Фильтрация и обработка вывода анализатора при помощи файлов конфигурации диагностик (.pvsconfig)
- Добавление/использование файлов конфигурации в IDE и других инструментах анализа
- Использование .pvsconfig в Visual Studio
- Использование .pvsconfig файла в Rider
- Использование .pvsconfig в PVS-Studio_Cmd.exe и pvs-studio-dotnet
- Использование .pvsconfig в CLMonitor.exe
- Использование .pvsconfig в CompilerCommandsAnalyzer.exe
- Использование .pvsconfig в Standalone.exe
- Использование глобального файла .pvsconfig
- Общий функционал файлов конфигурации
- Дополнительные возможности для C++ анализатора
Файл конфигурации служит для отображения и фильтрации сообщений анализатора. Также в нём можно задать дополнительные настройки анализа. Использование данных файлов возможно только для проектов, написанных на C, C++ или C#.
Файлы конфигурации поддерживаются плагинами для следующих IDE:
- Visual Studio;
- Rider.
Утилиты, поддерживающие файлы конфигурации:
- PVS-Studio_Cmd.exe;
- CLMonitor.exe (только в режиме analyze или analyzeFromDump);
- C and C++ Compiler Monitoring UI (Standalone.exe);
- CompileCommandsAnalyzer.exe (в режиме analyze).
Добавление/использование файлов конфигурации в IDE и других инструментах анализа
Использование .pvsconfig в Visual Studio
Для использования файла конфигурации в Visual Studio необходимо добавить его на уровне проекта или решения. Для этого выделите интересующий проект или решение в окне Solution Explorer среды Visual Studio. Выберите пункт контекстного меню 'Add New Item...'. В появившемся окне выберите тип файла 'PVS-Studio Filters File'.

Если шаблона нет, то вы можете просто добавить в проект или решение обычный текстовый файл с расширением ".pvsconfig".
Для каждого проекта/решения можно добавить несколько файлов конфигурации.
Файлы конфигурации, добавленные на уровне проекта, действуют на все файлы данного проекта. Файлы конфигурации, добавленные на уровне решения, будут действовать на все файлы всех проектов в этом решении.
Использование .pvsconfig файла в Rider
Специального шаблона для добавления файла конфигурации для Rider нет.
Добавить файл конфигурации для Rider можно только на уровне проекта. Чтобы использовать файл конфигурации диагностик в Rider, добавьте в проект новый файл с расширением '.pvsconfig' через Solution Explorer.

Использование .pvsconfig в PVS-Studio_Cmd.exe и pvs-studio-dotnet
При анализе через PVS-Studio_Cmd.exe или pvs-studio-dotnet автоматически используются файлы конфигурации из анализируемого проекта или решения. Также можно передать путь к дополнительному файлу .pvsconfig с помощью параметра --rulesConfig (-C):
PVS-Studio_Cmd.exe -t ProjName.sln -C \path\to\.pvsconfig
pvs-studio-dotnet -t ProjName.sln -C /path/to/.pvsconfig
В этом случае при анализе учитываются настройки и из файлов в проекте/решении, и из файла, переданного в качестве аргумента.
Использование .pvsconfig в CLMonitor.exe
Путь к файлу конфигурации необходимо передать в качестве аргумента командной строки (параметр -c):
CLMonitor.exe analyzeFromDump -d /path/to/compileDump.gz -c /path/to/.pvsconfig
Использование .pvsconfig в CompilerCommandsAnalyzer.exe
Если вы используете утилиту CompilerCommandsAnalyzer.exe, то можете передать путь до .pvsconfig-файла через параметр -R:
CompilerCommandsAnalyzer.exe analyze ... -R /path/to/.pvsconfig
Использование .pvsconfig в Standalone.exe
В Standalone.exe вы можете указать путь к файлу при запуске мониторинга.

Использование глобального файла .pvsconfig
Глобальный файл конфигурации диагностик используется при проверке всех проектов. Таких файлов конфигурации .pvsconfig может быть несколько и все они будут использованы инструментами PVS-Studio.
Для добавления глобального файла конфигурации создайте файл с расширением pvsconfig в папке:
- Для Windows – '%APPDATA%\PVS-Studio'
- Для Linux и macOS – '~/.config/PVS-Studio'
Общий функционал файлов конфигурации
Добавление записей в файл конфигурации
Задание настроек в файлах конфигурации производится при помощи специальных директив, начинающихся с символов '//'. Каждая директива пишется с новой строки.
Пример:
//-V::122
//-V::123
Также существует возможность добавлять комментарии. Для этого необходимо написать символ '#' в начало строки.
Пример:
# I am a comment
Фильтрация срабатываний анализатора
Отключение отдельных диагностик
Для полного отключения определённой диагностики используется запись:
//-V::number
'number' – номер диагностики, которую нужно выключить (например, 3022).
Пример использования:
//-V::3022
В данном случае будут игнорироваться срабатывания диагностики V3022.
Для отключения нескольких диагностик перечислите номера через запятую:
//-V::number1,number2,...,numberN
Пример:
//-V::3022,3080
При использовании этой директивы будут полностью отключены диагностики V3022 и V3080.
Отключение диагностик из определённых категорий
Для отключения диагностик некоторой категории используются следующие директивы:
//-V::GA
//-V::X64
//-V::OP
//-V::CS
//-V::MISRA
//-V::OWASP
Пояснение для каждой из категорий:
- GA (General Analysis) – диагностики общего плана. Основной набор диагностических правил PVS-Studio;
- OP (Optimization) – диагностики оптимизации. Указания по повышению эффективности;
- X64 (64-bit) – диагностики, позволяющие выявлять специфические ошибки, связанные с разработкой 64-битных приложений, а также переносом кода с 32-битной на 64-битную платформу;
- CS (Customers' Specific) – узкоспециализированные диагностики, разработанные по просьбам пользователей. По умолчанию этот набор диагностик отключен;
- MISRA – диагностики, разработанные в соответствии со стандартом MISRA (Motor Industry Software Reliability Association). По умолчанию этот набор диагностик отключен;
- OWASP – диагностики, направленные на поиск проблем с безопасностью и проверяющие соответствие кода стандарту OWASP ASVS. По умолчанию отключено.
Можно комбинировать фильтры категорий, перечисляя их через запятую.
Пример комбинации:
//-V::GA,MISRA
Отключение всех C++ или C# диагностик
Для отключения всех диагностик C++ или C# анализатора используются директивы:
//-V::C++
//-V::C#
Исключение предупреждений определённого уровня
Если требуется исключить срабатывания определённого уровня, используйте запись вида:
//-V::number1,number2,...,numberN:level
- 'number1', 'number2' и т.д. – номера диагностик, срабатывания которых нужно исключить (например, 3022).
- 'level' – уровень предупреждения (1, 2 или 3).
Цифре 1 соответствуют срабатывания уровня 'High', цифре 2 – 'Medium', цифре 3 – 'Low'.
Можно исключать предупреждения сразу нескольких уровней. Для этого нужно написать уровни через запятую.
Пример:
//-V::3022,5623:1,3
Эта запись позволит исключить срабатывания диагностик V3022 и V5623 уровня 'High' и 'Low'.
Исключение предупреждений по подстроке в сообщении
Анализатор поддерживает возможность исключения предупреждений по номеру диагностики и подстроке, содержащейся в сообщении.
Запись для подавления:
//-V::number::{substring}
- 'number' – номер диагностики, сообщение которой нужно подавить (например, 3080).
- 'substring' – подстрока, содержащаяся в сообщении анализатор.
При использовании такого шаблона будут игнорироваться срабатывания диагностик с номером 'number', сообщения которых содержат подстроку 'substring'.
Пример подавления по подстроке:
//-V::3022::{always true}
В данном случае будут отключены срабатывания V3022, в сообщении которых есть подстрока 'always true'.
Исключение предупреждений по уровню и подстроке в сообщении
Также можно добавить фильтрацию по уровню и подстроке. Такая запись будет иметь вид:
//-V::number1,number2,...,numberN:level:{substring}
- 'number1', 'number2' и т.д. – номера диагностик, срабатывания которых нужно исключить (например, 3022).
- 'level' – уровень предупреждения (1, 2 или 3).
- 'substring' – подстрока, содержащаяся в сообщении анализатора.
Цифре 1 соответствуют срабатывания уровня 'High', цифре 2 – 'Medium', цифре 3 – 'Low'.
Можно исключать предупреждения диагностик сразу нескольких уровней. Для этого нужно написать уровни через запятую.
Пример:
//-V::3022,5623:1:{always true}
Будут исключены срабатывания уровня 'High' и 'Low' диагностик V3022, V5623, в сообщении которых есть подстрока 'always true'.
Добавление метки False Alarm для срабатываний на строки, содержащие указанный фрагмент
Добавление FA-метки для предупреждений на строки с некоторым фрагментом производится с помощью следующей директивы:
//-V:substring:number
- 'substring' – подстрока, содержащаяся в строке, на которую указывает анализатор;
- 'number' – номер диагностики, сообщение которой нужно подавить (например, 3080).
Примечание 1. Искомая подстрока ('substring') не должна содержать пробелов.
Примечание 2. Сообщения, отфильтрованные данным способом, не будут удалены из отчёта. Они будут отмечены, как False Alarm (FA).
Пример использования:
public string GetNull()
{
return null;
}
public void Foo()
{
string nullStr = GetNull();
Console.WriteLine(nullStr.Length);
}
На данный код анализатор выдаст предупреждение: "V3080 Possible null dereference. Consider inspecting 'nullStr'.".
Для добавления FA-метки для срабатываний на такой код используйте в .pvsconfig следующую запись:
//-V:Console:3080
Такая директива добавит отметку False Alarm на все предупреждения V3080, указывающие на строку кода, в которой есть 'Console'.
Аналогичным образом можно добавлять отметку False Alarm на срабатывания сразу нескольких диагностик. Для этого перечислите их номера через запятую:
//-V:substring:number1,number2,...,number
Пример:
//-V:str:3080,3022,3175
Сообщения диагностик V3080, V3082, V3175 будут помечены как False Alarm, если в строке, на которую указывает анализатор, есть подстрока 'str'.
Исключение файлов из анализа
Для исключения из анализа файла или группы файлов используйте шаблон:
//V_EXCLUDE_PATH fileMask
'fileMask' – маска файла.
Пример использования некоторых масок:
//V_EXCLUDE_PATH C:\TheBestProject\thirdParty
//V_EXCLUDE_PATH *\UE4\Engine\*
//V_EXCLUDE_PATH *.autogen.cs
С синтаксисом формирования масок можно ознакомится в документации.
Игнорирование глобальных файлов конфигурации
Перед запуском анализа 'PVS-Studio_Cmd' формирует конфигурацию диагностических правил из:
- глобальных файлов конфигурации (в папке '%APPDATA%\PVS-Studio' для Windows и в папке '~/.config/PVS-Studio' для Linux и macOS);
- файла, переданного через опцию --rulesConfig (-C);
- файлов, добавленных в решение;
- файлов, добавленных в проект.
Может возникнуть ситуация, когда глобальная конфигурация не должна применяться при анализе каких-либо проектов или решений. Для её отключения добавьте в соответствующий файл конфигурации следующий флаг:
//IGNORE_GLOBAL_PVSCONFIG
Указание timeout-а анализа файлов для проекта/solution/системы
При запуске анализа через интерфейс плагинов (Visual Studio, Rider и CLion) или в C and C++ Compiler Monitoring UI (Standalone.exe) имеется возможность указания timeout-а по истечению которого анализ файла будет прерван. При превышении timeout-а анализа в результаты анализа будет добавлено предупреждение V009 с информацией, о том на каком файле был превышен timeout.
Настройки timeout-а анализа файлов можно указать и в .pvsconfig. Например, этой строчкой указывается timeout в 10 минут (600 секунд):
//V_ANALYSIS_TIMEOUT 600
Если в .pvsconfig указана строка с timeout-ом равным 0, то файлы будут анализироваться без ограничения по времени.
Благодаря настройке timeout-ов через .pvsconfig файлы разных уровней, можно ограничить время анализа файлов в определенных проектах, solution-ах или во всей системе.:
- аргумент --rulesConfig (-c) PVS-Studio_Cmd.exe (переопределяет timeout анализа файлов для текущего анализа solution/проекта);
- системный (%AppData% в Windows, ~/.config в Linux, macOS);
- solution (.sln);
- уровень проекта (.csproj, .vcxproj).
Изменение уровня срабатываний диагностики
Для изменения уровня используйте директиву следующего вида:
//V_LEVEL_1::number
'number' – номер диагностики (например, 3022).
Чтобы изменить уровень предупреждений для диагностики V3176 на третий, используйте запись:
//V_LEVEL_3::3176
Директивы, меняющие уровень:
- Директива '//V_LEVEL_1' изменяет уровень срабатываний на 'High';
- Директива '//V_LEVEL_2' изменяет уровень срабатываний на 'Medium';
- Директива '//V_LEVEL_3' изменяет уровень срабатываний на 'Low'.
Изменения текста сообщений анализатора
Для изменения подстроки в сообщении анализатора используйте следующий синтаксис:
//+diagnosticName:RENAME:{originalString:replacementString}, ...
- 'diagnosticName' – название диагностики, сообщение которой необходимо модифицировать (например, V624);
- 'originalString' – исходная подстрока;
- 'replacementString' – строка на которую нужно заменить.
Разберём работу директивы на примере. Диагностика V624, встречая в коде число 3.1415, предлагает заменить его на 'M_PI' из библиотеки '<math.h>'. Но в проекте используется специальная математическая библиотека, и нужно использовать математические константы именно из неё. Для корректной работы следует добавить директиву в файл конфигурации.
Эта директива будет иметь следующий вид:
//+V624:RENAME:{M_PI:OUR_PI},{<math.h>:"math/MMath.h"}
Теперь анализатор сообщит, что нужно использовать константу 'OUR_PI' из заголовочного файла 'math/MMath.h'.
Существует возможность добавить строку к сообщению.
Директива, позволяющая сделать это, имеет следующий вид:
//+diagnosticName:ADD:{message}
- 'diagnosticName' – название диагностики, сообщение которой необходимо модифицировать (например, V2003);
- 'message' – строка для добавления;
Разберём пример. Для этого рассмотрим сообщение диагностики V2003: "Explicit conversion from 'float/double' type to signed integer type.".
Чтобы добавить дополнительную информацию в это сообщение, нужно использовать директиву следующего вида:
//+V2003:ADD:{ Consider using boost::numeric_cast instead.}
Теперь анализатор будет выдавать модифицированное сообщение: "Explicit conversion from 'float/double' type to signed integer type. Consider using boost::numeric_cast instead.".
Дополнительные возможности для C++ анализатора
В данном разделе представлен функционал только для C++ анализатора. При анализе проектов, написанных на других языках, описанные здесь директивы будут игнорироваться.
Указать анализатору, что функция возвращает или не возвращает nullptr
Существует множество системных функций, которые при определённых условиях возвращает нулевой указатель. Хорошими примерами являются такие функции, как 'malloc', 'realloc', 'calloc'. Они возвращают 'NULL' в случае, когда невозможно выделить буфер памяти указанного размера.
Может возникнуть желание изменить поведение анализатора и заставить его считать, что, допустим, функция 'malloc' не может вернуть 'NULL'. Например, пользователь может использовать системные библиотеки, в которых ситуации нехватки памяти обрабатываются особым образом.
Также возможна обратная ситуация. Пользователь может помочь анализатору, подсказав ему, что определённая системная или его собственная функция может вернуть нулевой указатель.
Если функция не возвращает 'nullptr', директива имеет следующий формат:
//V_RET_NOT_NULL, namespace: n, class:c, function:f
Чтобы указать анализатору, что функция возвращает 'nullptr', добавьте запись вида:
//V_RET_NULL, namespace: n, class: c, function: f
Для обоих случаев:
- Ключ 'namespace' – имя пространства имен. Может отсутствовать;
- Ключ 'class' – имя класса. Может отсутствовать;
- Ключ 'function' – задаёт имя функции, которая может/не может возвратить нулевой указатель.
Рассмотрим примеры использования.
Функция не возвращает нулевой указатель:
//V_RET_NOT_NULL, function:malloc
Теперь анализатор имеет информацию о том, что результат выполнения функции 'malloc', не возвращает 'nullptr'.
Функция возвращает нулевой указатель:
//V_RET_NULL, namesapce:Memory, function:QuickAlloc
При анализе будет учитываться, что функция 'QuickAlloc', находящейся в пространстве имён 'Memory' может вернуть 'nullptr'.
Настройка обработки макроса assert
По умолчанию анализатор одинаково проверяет код, в котором присутствует макрос assert(), независимо от конфигурации проекта. А именно – не учитывает, что при ложном условии в макросе выполнение кода прерывается. Чтобы задать иное поведение анализатора, нужно добавить следующую директиву:
//V_ASSERT_CONTRACT
Обратите внимание, что в таком режиме результаты анализа могут отличаться в зависимости от того, как раскрывается макрос в проверяемой конфигурации проекта.
Для пояснения, рассмотрим следующий код:
MyClass *p = dynamic_cast<MyClass *>(x);
assert(p);
p->foo();
Оператор 'dynamic_cast' может вернуть значение 'nullptr'. Поэтому, в стандартном режиме анализатор выдаст предупреждение, что при вызове функции 'foo' может произойти разыменовывание нулевого указателя.
При добавлении директивы предупреждение исчезнет.
Можно указать имя макроса, который анализатор будет обрабатывать так же, как 'assert'. Для этого используйте следующую директиву:
//V_ASSERT_CONTRACT, assertMacro:macroName
Ключ 'assetMacro' – имя макроса, который анализатор будет обрабатывать, как 'assert';
Пример:
//V_ASSERT_CONTRACT, assertMacro:MY_CUSTOM_MACRO_NAME
Теперь анализатор будет обрабатывать макрос 'MY_CUSTOM_MACRO_NAME', как 'assert'.
Если необходимо указать несколько имен макросов, для каждого из них следует добавить отдельную директиву 'V_ASSERT_CONTRACT'.
Указание псевдонима системной функции
Иногда в проектах используются собственные реализации разных системных функций, например, 'memcpy', 'malloc' и т.п. В этом случае анализатор не будет понимать, что поведение таких функций идентично стандартным аналогам. Существует возможность ставить имена своих функций в соответствие системным.
Формат записи:
//V_FUNC_ALIAS, implementation:imp, function:f, namespace:n, class:c
- Ключ 'implementation' – имя стандартной функции, для которой определяется псевдоним;
- Ключ 'function' – имя псевдонима. Сигнатура функции, имя которой указано в этом ключе, должна совпадать с сигнатурой функции, указанной в ключе 'implementation';
- Ключ 'class' – имя класса. Может отсутствовать;
- Ключ 'namespace' – имя пространства имен. Может отсутствовать.
Пример использования:
//V_FUNC_ALIAS, implementation:memcpy, function:MyMemCpy
Теперь анализатор будет обрабатывать вызовы функции 'MyMemCpy' так же, как вызовы 'memcpy'.