V781. Value of a variable is checked after it is used. Possible error in program's logic. Check lines: N1, N2.
Анализатор заметил в коде следующую ситуацию. В начале, значение переменной используется в качестве размера или индекса массива. А уже затем это значение сравнивается с 0 или с размером массива. Это может указывать на наличие логической ошибки в коде или опечатку в одном из сравнений.
Рассмотрим пример
int idx = GetPos(buf);
buf[idx] = 42;
if (idx < 0) return -1;
Если значение 'idx' окажется меньше нуля, то выражение 'buf[idx] ' приведёт к ошибке. Анализатор выдаст предупреждение на этот код, указав 2 строки. Первая строка - это то место, где используется переменная. Вторая строка - это то место, где переменная сравнивается с другим значением.
Исправленный вариант кода:
int idx = GetPos(buf);
if (idx < 0) return -1;
buf[idx] = 42;
Точно также анализатор выдаёт предупреждение, если переменная сравнивается с размером массива:
int buf[10];
buf[idx] = 42;
if (idx < countof(buf)) return -1;
Правильный вариант кода:
int buf[10];
if (idx < countof(buf)) return -1;
buf[idx] = 42;
Помимо индексов, анализатор смотрит на использование переменных в качестве аргументов к функциям, которые принимают неотрицательные значения (memset, malloc и т.д.). Рассмотрим пример:
bool Foo(char *A, int size_A, char *B, int size_B)
{
if (size_A <= 0)
return false;
memset(A, 0, size_A);
....
if (size_A <= 0) // Error
return false;
memset(B, 0, size_B);
....
}
В коде допущена опечатка, которая будет выявлена косвенным образом. В коде всё хорошо с массивом 'A'. Однако, размер массива 'B' проверяется неправильно. В результате возникает ситуация, что 'size_A' проверяется уже после использования.
Корректный код:
bool Foo(char *A, int size_A, char *B, int size_B)
{
if (size_A <= 0)
return false;
memset(A, 0, size_A);
....
if (size_B <= 0) // FIX
return false;
memset(B, 0, size_B);
....
}
Так же анализатор может увидеть проблему, если использование переменной в качестве индекса массива и её проверка находятся в одном выражении:
void f(int *arr, const int size)
{
for (int i = 0; arr[i] < 10 && i < size; ++i)
arr[i] = 0;
}
В этом случае на последней итерации цикла мы будем проверять значение, взятое за границей массива, а это является неопределённым поведением.
Исправленный вариант:
void f(int *arr, const int size)
{
for (int i = 0; i < size && arr[i] < 10; ++i)
arr[i] = 0;
}
Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки переполнения буфера (записи или чтения за пределами выделенной для буфера памяти). |
Данная диагностика классифицируется как:
Взгляните на примеры ошибок, обнаруженных с помощью диагностики V781. |