V2656. MISRA. Standard Library function 'memcmp' should not be used to compare null-terminated strings.
Диагностическое правило основано на руководстве MISRA (Motor Industry Software Reliability Association) по разработке программного обеспечения.
Правило актуально только для языка C.
Функция стандартной библиотеки memcmp не должна быть использована для сравнения null-терминированных строк.
В рамках текущего правила null-терминированные строки – это:
- строковые литералы;
- массивы сущностно-символьного типа, содержащие терминальный ноль (
\0).
Функция memcmp выполняет побайтовое сравнение двух последовательных участков памяти. При сравнении строк возможна ситуация, когда фактический размер каждой строки (все символы до терминального нуля) меньше, чем выделенный буфер. Полное сравнение таких буферов через функцию memcmp может привести к неожиданным результатам. Например, две логически одинаковые строки могут считаться различными. Это происходит из-за того, что символы после терминального нуля будут участвовать в сравнении, даже если они не являются частью строки.
Рассмотрим пример:
static _Bool FilesHaveSameContent(const FILE *lhs,
const FILE *rhs)
{
if (!lhs || !rhs) return false;
char l_buf[256];
char r_buf[256];
while (fgets(l_buf, sizeof(l_buf), lhs)
&& fgets(r_buf, sizeof(r_buf), rhs))
{
if (memcmp(l_buf, r_buf, sizeof(l_buf)) != 0) // <=
{
return false;
}
}
return feof(lhs) && feof(rhs);
}
Функция FilesHaveSameContent используется для построчного сравнения файлов. Содержимое из файлов считывается в соответствующие буферы l_buf и r_buf, размером 256 байтов каждый, с помощью функции fgets. Затем с помощью функции memcmp происходит их побайтовое сравнение.
Функция fgets читает указанное количество символов и сохраняет их в буфер. Чтение останавливается, если встречается символ переноса строки или конец файла. Если чтение прошло успешно, то за последним прочитанным символом из файла в буфере будет записан терминальный ноль.
Таким образом, если из двух одинаковых файлов считались строки размером менее 255 байт, то их сравнение может дать неправильный результат, поскольку символы после терминального нуля будут не инициализированы.
Для исправления проблемы следует заменить функцию memcmp на strcmp или strncmp:
if (strcmp(l_buf, r_buf) != 0)
{
return false;
}
Данная диагностика классифицируется как:
|