Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
>
>
>
V641. Buffer size is not a multiple of …
menu mobile close menu
Проверка проектов
Сообщения PVS-Studio
Диагностики общего назначения (General Analysis, C++)
Диагностики общего назначения (General Analysis, C#)
Диагностики общего назначения (General Analysis, Java)
Микрооптимизации (C++)
Диагностика 64-битных ошибок (Viva64, C++)
Реализовано по запросам пользователей (C++)
Cтандарт MISRA
Стандарт AUTOSAR
Стандарт OWASP (C++)
Стандарт OWASP (C#)
Проблемы при работе анализатора кода
Дополнительная информация
toggle menu Оглавление

V641. Buffer size is not a multiple of element size.

07 Июл 2017

Анализатор обнаружил потенциальную ошибку, связанную c приведением указателя на исходный буфер к указателю на другой тип, при этом размер исходного буфера некратен размеру одного элемента полученного типа. Рассмотрим два класса ошибок, допускаемых при приведениях типов.

Первый класс ошибок связан с выделением некорректного размера памяти для хранения элементов массива с помощью функций 'malloc', 'calloc', 'alloca', 'realloc' и т.д.

Как правило, такие ошибки возникают, если размер выделяемой памяти задается константой (константами в случае 'calloc'). Для правильного выделения памяти под 'N' элементов массива типа 'T' рекомендуется использовать оператор 'sizeof(T)'. В зависимости от функции, аллоцирующей память, конструкция может иметь следующий вид:

int *p = (int*)malloc(N * sizeof(int));

или

int *p = (int*)calloc(N, sizeof(int));

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

Рассмотрим пример некорректного кода с использованием функции 'malloc':

int *p = (int*)malloc(70);

В данном случае будет выделено 70 байт памяти. Обращение к элементу 'p[17]' приведет к неопределенному поведению, поскольку произойдет выход за границу (необходимо 72 байта для корректного чтения 18-го элемента). Корректный вариант кода будет следующим:

p = (int*)malloc(72);

Также возможен случай, когда требуется выделить память для хранения 70 элементов. Корректным будет такой вариант кода:

p = (int*)malloc(70 * sizeof(int));

Рассмотрим пример некорректного кода из реального проекта с использованием функции 'calloc':

int data16len = MultiByteToWideChar(CP_UTF8, 
                                    0, 
                                    data,
                                    datalen,
                                    NULL,
                                    0);
if (!data16) 
{
  data16 = (wchar_t*)calloc(data16len + 1, 1);
}
MultiByteToWideChar(CP_UTF8, 0, data, -1, data16, data16len);

В данном случае хотели создать буфер для сохранения широкой (wide) строки после конвертации из UTF-8 строки. Однако размер 'wchar_t' не равен 1 байту (Windows - 2 байта, Linux - 4 байта). Корректный вариант кода будет выглядеть следующим образом:

data16 = (wchar_t*)calloc(data16len + 1, sizeof(wchar_t));

Примечание к функции 'calloc'. Несмотря на то, что прототип функции выглядит следующим образом:

void* calloc(size_t num, size_t size );

некоторые программисты полагают, что размер выделяемой памяти равен num*size и часто меняют аргументы местами. Такой код может приводить к ошибкам. Цитата из документации: "Due to the alignment requirements, the number of allocated bytes is not necessarily equal to num*size.".

Второй класс ошибок связан с преобразованием указателя на объект типа 'A' к указателю на объект типа 'B'. Рассмотрим пример:

struct A
{
  int a, b;
  float c;
  unsigned char d;
};

struct B
{
  int a, b;
  float c;
  unsigned short d;
};

....
A obj1;
B *obj2 = (B*)&obj1; //V641
std::cout << obj2->d;
....

Как видно из примера, две структуры отличаются друг от друга последним полем. Поле 'd' у приведённых структур имеет разный размер типа. При преобразовании указателя 'A*' к 'B*' можно получить неопределенное поведение при обращении к полю 'd'. Отметим, что преобразование указателя 'B*' к 'A*' возможно (хотя это плохой код), и неопределенного поведения не будет.

Анализатор не будет выдавать предупреждения на преобразование указателя 'A*' к 'B*', если два класса (структуры) находятся в иерархии наследования.

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

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

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

close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

Шаг 2
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности
close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS‑Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте, отфильтровано ли письмо в одну из следующих стандартных папок:

  • Промоакции
  • Оповещения
  • Спам