Дополнительная настройка диагностик


Как указать анализатору, что функция может или не может возвращать nullptr

Существует множество системных функций, которые при определённых условиях возвращают нулевой указатель. Хорошими примерами являются такие функции, как malloc, realloc, calloc. Эти функции возвращают NULL в случае, когда невозможно выделить буфер памяти указанного размера.

Иногда возникает желание изменить поведение анализатора и заставить его считать, что, например, функция malloc не может вернуть NULL. Например, пользователь может использовать системные библиотеки, в которых ситуации нехватки памяти обрабатываются особым образом.

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

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

  • V_RET_NULL - функция может вернуть нулевой указатель
  • V_RET_NOT_NULL - функция не может вернуть нулевой указатель

Формат комментария:

//V_RET_[NOT]_NULL, namespace:Space, class:Memory, function:my_malloc
  • Ключ function - Задаёт имя функции, которая может/не может возвратить нулевой указатель.
  • Ключ class - Имя класса. Может отсутствовать.
  • Ключ namespace - Имя пространства имён. Может отсутствовать.

Управляющий комментарий может быть написан рядом с объявлением функции.

В случае таких функций, как malloc, это невозможно. Плохая идея вносить изменения в системные заголовочные файлы.

Одним из решений является написание комментария в одном из глобальных заголовочных файлов, который используется во всех единицах трансляции. Для проекта, разрабатываемого с помощью Visual Studio, хорошим кандидатом на такую роль является stdafx.h.

Ещё один вариант - использование файла конфигурации диагностик pvsconfig. См. "Подавление ложных предупреждений" (раздел "Массовое подавление ложных предупреждений с помощью файлов конфигурации диагностик pvsconfig").

Для наглядности рассмотрим два примера.

Функция не возвращает нулевой указатель:

//V_RET_NOT_NULL, function:malloc

Теперь анализатор считает, что функция malloc не может вернуть NULL и не будет выдавать предупреждение V522 для следующего фрагмента кода:

int *p = (int *)malloc(sizeof(int) * 100);
p[0] = 12345; // ok

Функция возвращает потенциально нулевой указатель:

//V_RET_NULL, namesapce:Memory, function:QuickAlloc

После добавления этого комментария анализатор начнёт выдавать предупреждение для следующего кода:

char *p = Memory::QuickAlloc(strlen(src) + 1);
strcpy(p, src); // Warning!

Как задать свой уровень для конкретной диагностики

Предупреждения анализатора имеют три уровня достоверности: High, Medium, Low. В зависимости от используемых в коде конструкций, анализатор оценивает достоверность предупреждений и присваивает им соответствующий уровень в отчёте. Некоторые предупреждения могут быть выданы одновременно на нескольких уровнях.

В некоторых проектах поиск определённых типов ошибок может быть очень важен, независимо от степени достоверности предупреждения. Бывает и обратная ситуация, когда сообщения малополезны, но совсем их отключать не хочется. В таких случаях для диагностик можно вручную задать уровень High/Medium/Low. Для этого следует использовать специальные комментарии, которые можно добавить в код или файл конфигурации диагностик. Примеры комментариев:

//V_LEVEL_1::501,502
//V_LEVEL_2::522,783,579
//V_LEVEL_3::773

Найдя подобные комментарии, анализатор будет выдавать предупреждения на указанном уровне.

Изменение текста выводимого сообщения

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

//+Vnnn:RENAME:{Aaaa:Bbbb},{<foo.h>:<myfoo.h>},{100:200},......

Во всех сообщениях с номером Vnnn будут произведены замены:

  • Aaaa заменится на Bbbb.
  • <foo.h> заменится на <myfoo.h>.
  • Число 100 заменится на 200.

Проще всего использование этого механизма будет пояснить на примере.

Диагностика V624, встречая в коде число 3.1415, предлагает заменить его на M_PI из библиотеки <math.h>. Но в проекте используется специальная математическая библиотека и нужно использовать математические константы именно из неё. Поэтому программист может сделать в глобальном файле (например, в StdAfx.h) следующий комментарий:

//+V624:RENAME:{M_PI:OUR_PI},{<math.h>:"math/MMath.h"}

Теперь анализатор будет сообщать, что следует использовать константу OUR_PI из заголовочного файла "math/MMath.h".

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

//+Vnnn:ADD:{ Message}

В конец всех сообщений с номером Vnnn будет добавлена строка, заданная программистом.

Например, возьмем диагностику V2003. Выдаваемое сообщение будет выглядеть следующим образом: "V2003 - Explicit conversion from 'float/double' type to signed integer type.". Программист может учесть особенности проекта и расширить сообщение об ошибке, для чего можно сделать следующий комментарий:

//+V2003:ADD:{ Consider using boost::numeric_cast instead.}

Теперь анализатор будет выдавать модифицированное сообщение: "V2003 - Explicit conversion from 'float/double' type to signed integer type. Consider using boost::numeric_cast instead.".


А ты совершаешь ошибки в коде?

Проверь с помощью
PVS-Studio

Статический анализ
кода для C, C++ и C#

goto PVS-Studio;
Мы используем cookie-файлы для анализа событий на нашем веб-сайте, что позволяет улучшить наш контент и сделать взаимодействие с пользователем более удобным. Продолжая просмотр страниц нашего веб-сайта, вы принимаете условия использования этих файлов. Узнайте подробнее о cookie-файлах и политике конфиденциальности или скройте это уведомление, нажав на кнопку. Подробнее →
Не показывать