Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
>
>
>
V505. The 'alloca' function is used ins…
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 Оглавление

V505. The 'alloca' function is used inside the loop. This can quickly overflow stack.

26 Апр 2023

Анализатор обнаружил использование функции 'alloca' внутри цикла.

Функция 'alloca' выделяет память для заданного буфера внутри фрейма вызывающей функции. Эта область памяти будет очищена только вместе с уничтожением этого фрейма в момент её завершения.

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

void foo ()
{
  char *buffer = nullptr;
  buffer = (char *) alloca(256); // <= (1)

  // using buffer
  ....
} // <= (2)

Пример синтетический, но на нём можно увидеть принцип работы функция 'alloca'. На строчке, помеченной как (1), происходит выделение блока памяти размеров в 256 байт на фрейме стека функции 'foo', который будет создан при её вызове. Фрейм функции будет уничтожен на строчке (2), когда она вернёт поток управления вызывающему коду. Это освободит всю выделенную под него память на стеке и позволит избежать утечек памяти.

Однако неаккуратное использование этой функции может привести к проблеме. Память стека исполняемой программы ограничена, и нужно следить за её переполнением.

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

void bar(int n)
{
  for (size_t i = 0; i < n; ++i)
  {
    char *buffer = nullptr;
    if (buffer = (char*) alloca(256)) // <=
    { 
      // using buffer
      ....
    }
  }
}

Функция 'alloca' вызывается в цикле. Проблема заключается в том, что между его итерациями выделенная память не будет освобождена. При этом, если количество итераций 'n' будет достаточно большим, то стек программы может переполниться.

Исправить некорректный код в данном случае достаточно просто. Для этого можно перенести вызов функции 'alloca' за пределы цикла и использовать 'buffer' повторно на каждой итерации:

void bar(int n)
{
  char *buffer = (char*)alloca(256);

  for (size_t i = 0; i < n; ++i)
  {
    // using buffer
    ....
  }
}

Ещё один пример опасного кода:

// A2W defined in ATL using alloca
#define A2W(lpa) .... 

void AtlExample()
{
  ....

  size_t n = ....;
  wchar_t** strings = { '\0' };
  LPCSTR* pszSrc = { '\0' };

  for (size_t i = 0; i < n; ++i)
  {
    if (wcscmp(strings[i], A2W(pszSrc[i])) == 0) // <=
    { 
      ....
    }
  }
}

Макрос 'A2W' определён в библиотеке 'ATL' версии 3.0. Внутри него используется функция 'alloca'. Приведёт ли данный код к ошибке или нет, будет зависеть от длины обрабатываемых строк, их количества и размера доступного стека. Исправить опасный код можно использовав класс 'CA2W', определённый в библиотеке 'ATL' версии 7.0. В отличии от макроса, он выделяет память на стеке только для маленьких строк. Для длинных она выделяется через 'malloc'. Кроме того, память, выделенная на стеке, будет освобождена при выходе из области видимости объявления переменной. Следовательно, будет освобождаться после сравнения с 'strings[i]'.

Исправленный пример:

// using ATL 7.0
....
for (size_t i = 0; i < n; ++i)
{
  if (wcscmp(strings[i], CA2W(pszSrc[i])) == 0) // <=
  { 
    ....
  }
}

Подробнее про функции библиотеки ATL можно почитать в документации.

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

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

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
Ваше сообщение отправлено.

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


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

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