Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top

Вебинар: Понять себя как тимлида: привычки, роли и стили управления - 21.10

menu mobile close menu
Проверка проектов
Дополнительная информация
toggle menu Оглавление

V557. Possible array overrun.

13 Июн 2012

Анализатор обнаружил потенциально возможный доступ к памяти за границами массива. Самым распространённым случаем является ошибка при записи символа \0 после последнего элемента массива.

Рассмотрим соответствующий пример:

struct IT_SAMPLE
{
  unsigned char filename[14];
  ...
};

static int it_riff_dsmf_process_sample(
  IT_SAMPLE * sample, const unsigned char * data)
{
  memcpy( sample->filename, data, 13 );
  sample->filename[ 14 ] = 0;
  ...
}

Последний элемент массива имеет индекс 13, а не 14. Поэтому корректный код должен иметь вид:

sample->filename[13] = 0;

В подобных случаях лучше использовать не явное значение индекса, а выражение, использующее оператор sizeof(). Однако следует помнить, что и в этом случае можно допустить ошибку. Рассмотрим пример:

typedef wchar_t letter;
letter    name[30];
...
name[sizeof(name) - 1] = L'\0';

На первый взгляд выражение sizeof(name) – 1 верно. Но здесь программист забыл, что он работает с типом wchar_t, а не char. В результате символ \0 будет записан далеко за пределами массива.

Корректный вариант:

name[sizeof(name) / sizeof(*name) - 1] = L'\0';

Для упрощения записи таких конструкций можно использовать специальный макрос:

#define str_len(arg) ((sizeof(arg) / sizeof(arg[0])) - 1)
name[str_len(name)] = L'\0';

Анализатор выявляет некоторые ошибки, когда индексом является переменная, значение которой может выйти за пределы массива.

Пример:

int buff[25];
for (int i=0; i <= 25; i++)
  buff[i] = 10;

Корректный вариант:

int buff[25];
for (int i=0; i < 25; i++)
  buff[i] = 10;

Следует учитывать, что при работе с подобными диапазонами значений анализатор может ошибаться и выдавать ложные срабатывания.

Проверка верхней границы массива

Анализатор также может выявлять потенциальный выход за границы массива в ситуациях, когда проверяется только нижняя граница индекса, а верхняя — нет.

Рассмотрим пример:

int arr[6];

void foo(int i)
{
  if (i >= 0) 
  {
    arr[i] = 0; // <= V557
  }
}

Условие i >= 0 лишь гарантирует, что индекс массива неотрицателен, но не защищает от переполнения буфера. Если переменная i будет иметь значение больше 5, то произойдёт выход за границу массива arr.

Корректный код:

int arr[6];

void foo(int i)
{
  if (i >= 0 && i < 6) 
  {
    arr[i] = 0; //ok
  }
}

По умолчанию проверка верхней границы массива отключена. Чтобы её включить, добавьте комментарий в файл конфигурации(.pvsconfig) или в файл с исходным кодом:

//+V557 CHECK_UPPER_BOUND:ON

Для её отключения используйте комментарий:

//+V557 CHECK_UPPER_BOUND:OFF

Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки переполнения буфера (записи или чтения за пределами выделенной для буфера памяти), Ошибки непроверенного использования чувствительных данных (ввода пользователя, файлов, сети и пр.).

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

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