# 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 как критические и относятся к типу: Ошибки переполнения буфера (записи или чтения за пределами выделенной для буфера памяти).

Данная диагностика классифицируется как:

CWE-129 CWE-20 CWE-789 CERT-API00-C CERT-CTR50-CPP CERT-MEM35-C

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V781.