Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
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.