>
>
>
V781. Value of a variable is checked af…


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.