Для получения триального ключа
заполните форму ниже
Team License (базовая версия)
Enterprise License (расширенная версия)
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
GBP
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

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

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

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

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Ваше сообщение отправлено.

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


Если вы так и не получили ответ, пожалуйста, проверьте папку
Spam/Junk и нажмите на письме кнопку "Не спам".
Так Вы не пропустите ответы от нашей команды.

>
>
>
Магические константы и функция malloc()

Магические константы и функция malloc()

07 Сен 2009

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

Приведем классический пример ошибки:

size_t nCount = 10;
int **poinerArray = (int **)malloc(nCount * 4);

Код некорректен, но в рамках одной 32-битной системы он будет стабильно работать. Ошибка может проявить себя при адаптации программы к другой программной/аппаратной среде. Важность обнаружения подобного кода стала по настоящему актуальна в связи с массовым переносом программного обеспечения на 64-битные системы. Изменение размеров ряда базовых типов делает код, аналогичный выше приведенному, крайне опасным.

На приведенный выше код статический анализатор Viva64, входящий в состав PVS-Studio, выдаст предупреждение об использование магической константы "4″ и ошибка будет обнаружена в ходе просмотра диагностических сообщений. Но код может быть более запутан:

#define N_COUNT 100
#define POINTER_SIZE 4
#define NSIZE (N_COUNT * POINTER_SIZE)
int **pArray = (int **)malloc(NSIZE);

Ошибку в подобном коде, написанном в стиле языка Си с использованием #define, диагностировать сложнее. Хотя в коде присутствует константа 4, заданная через макрос, в анализаторе Viva64 сознательно заблокирован вывод предупреждения на подобные конструкции. Анализатор игнорирует магические константы, задаваемые макросами (#define) по двум причинам. Во-первых, если программист задает константы через макросы, то, скорее всего, он знает, что делает и очень высока вероятность ложного срабатывания. Во-вторых, если реагировать на опасные с точки зрения 64-битности константы (4, 8, 32 и т.д.), то возникнет лавина ложных срабатываний связанная с использованием Windows API. В качестве примера приведем безобиднейший код:

MessageBox("Are you sure ?",
           "Some question",
           MB_YESNO | MB_ICONQUESTION);

Если анализировать магические числа, скрывающиеся за макросами MB_YESNO и MB_ICONQUESTION, то на приведенную строчку необходимо выдать два предупреждения об использовании магических констант 4 и 32. Естественно это будет неприемлемо высоким уровнем ложных срабатываний.

Можно при анализе функции malloc() выводить информацию о всех опасных магических константах, независимо, макрос это или нет. Но и этого будет недостаточно для следующего случая:

int **pArray = (int **)malloc(400);

Если пойти дальше и считать любое число, используемое в выражении для функции malloc() опасным, то это тоже повлечет к ложным срабатываниям на корректном коде:

int **pArray = (int **)malloc(400 * sizeof(int *));

Проанализировав ситуацию, мы решили реализовать новое правило, для верификации выражений, результат которых передается в функцию malloc(). На данный момент правило сформулировано следующим образом:

Опасным следует считать использование числовых литералов в выражении, передаваемом в функцию malloc().

Исключения:

1) В выражении присутствует оператор sizeof()

2) Все числовые литералы делятся на 4 c остатком

Благодаря данному правилу мы сможем предупредить об ошибке в следующем коде:

1) Первый пример:

void *p = malloc(nCount * 4);

2) Второй пример:

#define N_COUNT 100
#define POINTER_SIZE 4
#define NSIZE (N_COUNT * POINTER_SIZE)
int **pArray = (int **)malloc(NSIZE);

А также не выдать ложное предупреждение на код вида:

1) Первый пример:

void *p = malloc(sizeof(double) * 4);

2) Второй пример:

#define N_COUNT 100
#define POINTER_SIZE sizeof(int *)
#define NSIZE (N_COUNT * POINTER_SIZE)
int **pArray = (int **)malloc(NSIZE);

Скорее всего, это новое диагностическое правило появится в следующей версии PVS-Studio 3.30.

Рассмотрим теперь другую ситуацию, также связанную с функцией malloc() и неверным предположением о выравнивании данных. Это не совсем связано с магическими числами, но проблема очень родственная. Рассмотрим пример кода:

struct MyBigStruct {
  unsigned m_numberOfPointers;
  void *m_Pointers[1];
};
unsigned n = 10000;
void *ptr = malloc(sizeof(unsigned) +
                   n * sizeof(void *));

Хотя в данном коде не используется магических чисел, размер типов определяется через sizeof(), код все равно не корректен. В нем неучтено изменение способа выравнивания данных, различного для 32-битных и 64-битных систем. Корректным будет следующий код:

void *ptr = malloc(
  offsetof(MyBigStruct, m_Pointers) +
  n * sizeof(void *));

Чтобы предупредить пользователя о возможной допущенной ошибке мы планируем реализовать еще одно правило:

Опасным следует считать использование более одного оператора sizeof() в выражении, передаваемом в функцию malloc. Возможно, при вычислении размера структуры не учитывается изменение выравнивания.

В ряде случаев такое правило будет давать ложные срабатывания, но подобные места в любом случае стоит тщательно проверить.

Описанные выше опасные выражения с участием магических констант актуальны не только для функции malloc(), но и для класса таких функций как fread, fwrite и так далее. Но эти функции требуют отдельного изучения, и к их анализу мы приступим позже, когда отработаем диагностику, связанную с malloc().

Популярные статьи по теме
Главный вопрос программирования, рефакторинга и всего такого

Дата: 14 Апр 2016

Автор: Андрей Карпов

Вы угадали, ответ - "42". Здесь приводится 42 рекомендации по программированию, которые помогут избежать множества ошибок, сэкономить время и нервы. Автором рекомендаций выступает Андрей Карпов - тех…
Зло живёт в функциях сравнения

Дата: 19 Май 2017

Автор: Андрей Карпов

Возможно, читатели помнят мою статью под названием "Эффект последней строки". В ней идёт речь о замеченной мной закономерности: ошибка чаще всего допускается в последней строке однотипных блоков текс…
Технологии, используемые в анализаторе кода PVS-Studio для поиска ошибок и потенциальных уязвимостей

Дата: 21 Ноя 2018

Автор: Андрей Карпов

Краткое описание технологий, используемых в инструменте PVS-Studio, которые позволяют эффективно обнаруживать большое количество паттернов ошибок и потенциальных уязвимостей. Статья описывает реализа…
Статический анализ как часть процесса разработки Unreal Engine

Дата: 27 Июн 2017

Автор: Андрей Карпов

Проект Unreal Engine развивается - добавляется новый код и изменятся уже написанный. Неизбежное следствие развития проекта - появление в коде новых ошибок, которые желательно выявлять как можно раньш…
Как PVS-Studio оказался внимательнее, чем три с половиной программиста

Дата: 22 Окт 2018

Автор: Андрей Карпов

PVS-Studio, как и другие статические анализаторы кода, часто выдаёт ложные срабатывания. Но не стоит спешить считать странные срабатывания ложными. Это короткая история о том, как PVS-Studio вновь ок…
Бесплатный PVS-Studio для тех, кто развивает открытые проекты

Дата: 22 Дек 2018

Автор: Андрей Карпов

В канун празднования нового 2019 года команда PVS-Studio решила сделать приятный подарок всем контрибьюторам open-source проектов, хостящихся на GitHub, GitLab или Bitbucket. Им предоставляется возмо…
Как и почему статические анализаторы борются с ложными срабатываниями

Дата: 20 Мар 2017

Автор: Андрей Карпов

В своей предыдущей статье я писал, что мне не нравится подход, при котором статические анализаторы кода оцениваются с помощью синтетических тестов. В статье приводился пример, воспринимаемый анализат…
PVS-Studio для Java

Дата: 17 Янв 2019

Автор: Андрей Карпов

В седьмой версии статического анализатора PVS-Studio мы добавили поддержку языка Java. Пришло время немного рассказать, как мы начинали делать поддержку языка Java, что у нас получилось и какие дальн…
PVS-Studio ROI

Дата: 30 Янв 2019

Автор: Андрей Карпов

Время от времени нам задают вопрос, какую пользу в денежном эквиваленте получит компания от использования анализатора PVS-Studio. Мы решили оформить ответ в виде статьи и привести таблицы, которые по…
Эффект последней строки

Дата: 31 Май 2014

Автор: Андрей Карпов

Я изучил множество ошибок, возникающих в результате копирования кода. И утверждаю, что чаще всего ошибки допускают в последнем фрагменте однотипного кода. Ранее я не встречал в книгах описания этого …

Комментарии (0)

Следующие комментарии

На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Этот сайт использует куки и другие технологии, чтобы предоставить вам более персонализированный опыт. Продолжая просмотр страниц нашего веб-сайта, вы принимаете условия использования этих файлов. Если вы не хотите, чтобы ваши данные обрабатывались, пожалуйста, покиньте данный сайт. Подробнее →
Принять