Анализатор обнаружил потенциально возможную ошибку, связанную с заполнением, копированием или сравнением буферов памяти. Ошибка может приводить к переполнению буфера (buffer overflow).
Примечание: ранее данная диагностика содержала в себе дополнительный функционал, но позже было решено вынести его в отдельную диагностику V1086. О причинах и последствиях такого решения можно прочитать в специальной заметке.
Это достаточно распространённый вид ошибки, возникающий из-за опечаток или невнимательности. В результате может произойти чтение или запись в область памяти, которая занята другими данными. Такой ошибкой могут воспользоваться злоумышленники для выполнения вредоносного программного кода, чтения чувствительной информации или вызова сбоев в работе операционной системы. Неприятность подобных ошибок заключается в том, что программа долгое время может работать стабильно.
Рассмотрим пример N1:
#define BYTES_COUNT 5
struct Example
{
unsigned char id[BYTES_COUNT];
unsigned char extended[BYTES_COUNT - 2];
unsigned char data[20];
};
void ClearID(Example *data)
{
memset(&data->id, 0, BYTES_COUNT);
memset(&data->extended, 0, BYTES_COUNT);
}
В данном примере в функцию 'ClearID' передаётся указатель на объект типа 'Example'. Внутри функции происходит очистка полей 'id' и 'extended' с помощью функции 'memset'. Из-за невнимательного использования макроса 'BYTES_COUNT' при очистке поля 'extended' произойдёт переполнение буфера, которое приведёт к перезаписи соседнего поля 'data'.
Также переполнение буфера можно получить при неправильном приведении типов, как в примере N2:
struct MyTime
{
int timestamp;
....
};
MyTime s;
time((time_t*)&s.timestamp);
Данный пример, на первый взгляд, не содержит в себе опасностей и даже будет корректно работать, пока совпадает размер типов 'int' и 'time_t'. Проблема проявится при использовании стандартной библиотеки, где тип 'time_t' может быть 64-битным. При этом переменная 'int' имеет размер 32 бита.
В таком случае при вызове функции 'time' произойдёт запись в переменную 'timestamp', а также в область памяти после неё. Корректный вариант:
struct MyTime
{
time_t time;
....
};
MyTime s;
time(&s.time);
Ранее диагностическое правило содержало в себе дополнительный функционал, который был перенесён в диагностику V1086. Новая диагностика выявляет случаи, когда буфер обработан не полностью.
До разделения была возможность тонко настроить поведение диагностики и отключить неактуальную часть с помощью специальных комментариев. В целях обеспечения обратной совместимости, осталась возможность отключить диагностику V512 с помощью специального комментария:
//-V512_OVERFLOW_OFF
Этот комментарий можно вписать в заголовочный файл, который включается во все другие файлы. Например, это может быть "stdafx.h". Если вписать этот комментарий в "*.cpp" файл, то он будет действовать только для этого файла.
Поскольку теперь диагностика V512 ищет только переполнение буфера, то этот комментарий стал эквивалентен полному отключению диагностики (//-V::512).
Иногда анализатор при работе с форматной строкой может не знать точное значение аргумента – к примеру, когда он пришёл из параметра функции:
void foo(int someVar)
{
char buf[2];
sprintf(buf, "%d", someVar);
....
}
По умолчанию здесь предупреждение выдаваться не будет. Чтобы включить его выдачу, добавьте следующий комментарий:
//V_512_WARN_ON_UNKNOWN_FORMAT_ARGS
В этом случае для работы анализатор будет использовать диапазон значений из типа аргумента.
Неоднократно к нам в поддержку обращались пользователи, считая, что анализатор выдаёт ложное предупреждение на подобный код:
char buf[5];
strncpy(buf, "X", 100);
На первый взгляд может показаться, что функция должна скопировать только 2 байта (символ 'X' и терминальный ноль). Но, на самом деле, здесь действительно произойдёт выход за пределы массива. Причиной тому является важное свойство функции 'strncpy':
Если требуемое количество символов (третий аргумент функции) больше длины исходной строки, то целевая строка будет дополнена нулевыми символами до требуемого размера.
Более подробно с этим или другими свойствами функции 'strncpy' можно ознакомиться на cppreference.
Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки переполнения буфера (записи или чтения за пределами выделенной для буфера памяти). |
Данная диагностика классифицируется как:
Взгляните на примеры ошибок, обнаруженных с помощью диагностики V512. |