Suppression of false-positive warnings
- Watch, don't read (YouTube)
- Suppression of individual false positives (Mark as False Alarm)
- Manual false positive suppression
- How to Suppress false positives using the plugin context menu
- Suppressing false positives located within C/C++ macro statements (#define) and for other code fragments
- How to enable and disable certain diagnostics for a block of code
- Suppression of false positives through diagnostic configuration files (.pvsconfig)
- Other means of filtering messages in the PVS-Studio analyzer (Detectable Errors, Don't Check Files, Keyword Message Filtering)
- Mass suppression of analyzer messages (baselining)
- Possible issues
This section describes the analyzer's false positive suppression features. It provides ways to control both the separate analyzer messages under specific source code lines and whole groups of messages related, for example, to the use of C/C++ macros. The described method, by using comments of a special format, allows disabling individual analyzer rules or modifying text of analyzer's messages.
Features described in the following section are applicable to both C/C++ and C# PVS-Studio analyzers, if the contrary is not stated explicitly.
Watch, don't read (YouTube)
Suppression of individual false positives (Mark as False Alarm)
Any code analyzer always produces a lot of the so called "false alarms" besides helpful messages. These are situations when it is absolutely obvious to the programmer that the code does not have an error but it is not obvious to the analyzer. Such messages are called false alarms. Consider a sample of code:
obj.specialFunc(obj);
The analyzer finds it suspicious that a method is called from an object, in which as an argument the same object is passed, so it will issue a warning V678 for this code. The programmer can also know that the use of the 'specialFunc' method in this way is conceivable, therefore, in this case the analyzer warning is a false positive. You can notify the analyzer that the warning V678 issued on this code is a false positive.
It can be done either manually or using context menu command. After marking a message as a false alarm, the message will disappear from error list. You may enable the display of messages marked as 'False Alarms' in PVS-Studio error list by changing the value of 'PVS-Studio -> Options... -> Specific Analyzer Settings -> DisplayFalseAlarms' settings option.
We don't recommend marking warning as false positives without preliminary review of corresponding code, because such approach contradicts static analysis ideology. Only a developer can determine if an error message is false or not.
Manual false positive suppression
'#pragma' directives are usually used in compilers to suppress individual warnings. Here's an example of code:
unsigned arraySize = n * sizeof(float);
The compiler issues a warning:
warning C4267: 'initializing' : conversion from 'size_t' to 'unsigned int', possible loss of data x64Sample.cpp 151
This message can be suppressed by using the following construction:
#pragma warning (disable:4267)
Or rather to suppress this specific warning, write the code as follows:
#pragma warning(push)
#pragma warning (disable:4267)
unsigned arraySize = n * sizeof(float);
#pragma warning(pop)
The PVS-Studio analyzer uses special mark-up comments. For the same line of code, suppress the PVS-Studio warning as follows:
unsigned arraySize = n * sizeof(INT_PTR); //-V103
The analyzer will now mark the V103 warning issued on this line as false. We chose this approach to increase the clarity of the end code. The point is that PVS-Studio can report problems in the middle of multiline expressions, such as here:
size_t n = 100;
for (unsigned i = 0;
i < n; // <= the analyzer will report the problem here
i++)
{
// ...
}
To suppress this message when using a comment, it is enough to write:
size_t n = 100;
for (unsigned i = 0;
i < n; //-V104
i++)
{
// ...
}
If you had to add a '#pragma' directive to this expression, the code would look much less clear.
Markup is saved in source code. This helps to modify code and be sure the information about error-ridden lines won't be lost.
If you need to suppress more than one warning on one line, you should add a separate comment for each of them. Here are some examples:
1) the suppression of warnings of different diagnostics:
struct Small { int *pointer; };
struct Big { int *array[20]; };
int Add(const Small &a, Big b) //-V835 //-V813
{
return *a.pointer + *b.array[10];
}
2) the suppression of warnings of one diagnostic:
struct Small { int *pointer; };
int Add(const Small &a, const Small &b) //-V835 //-V835
{
return *a.pointer + *b.pointer;
}
You can also use a separate base and store the information as follows: error code, file name, line number. This approach is separately implemented in PVS-Studio and called "Mass Suppression".
How to Suppress false positives using the plugin context menu
The user is provided with two commands available from the PVS-Studio's context menu (figure 1).
Figure 1 – Commands to work with the mechanism of false alarm suppression
Let's study the commands concerning False Alarm suppression:
1. Mark selected messages as False Alarms. You may choose one or more false alarms in the list (figure 2) and use this command to mark the corresponding code as safe.
Figure 2 - Choosing warnings before executing the "Mark selected messages as False Alarms" command
2. Remove False Alarm marks from selected messages. This command removes the comment that marks code as safe. This function might be helpful if, for instance, you were in a hurry and marked some code fragment as safe by mistake. Like in the previous case, you must choose the required messages from the list.
Suppressing false positives located within C/C++ macro statements (#define) and for other code fragments
It goes without saying that the analyzer can locate potential problems within macro statements (#define) and produce diagnostic messages accordingly. But at the same time these messages will be produced by analyzer at such positions where the macro is being used, i.e. where placement of macro's body into the code is actually happening. An example:
#define TEST_MACRO \
int a = 0; \
size_t b = 0; \
b = a;
void func1()
{
TEST_MACRO // V1001 here
}
void func2()
{
TEST_MACRO // V1001 here
}
To suppress these messages, you can use the "Mark as False Alarm" command. Then the code containing suppression commands will look like this:
#define TEST_MACRO \
int a = 0; \
size_t b = 0; \
b = a;
void func1()
{
TEST_MACRO //-V1001
}
void func2()
{
TEST_MACRO //-V1001
}
But in case the macro is being utilized quite frequently, marking it everywhere as False Alarm is quite inconvenient. It is possible to add a special marking to the code manually to make the analyzer mark the diagnostics inside this macro as False Alarms automatically. With this marking the code will look like this:
//-V:TEST_MACRO:1001
#define TEST_MACRO \
int a = 0; \
size_t b = 0; \
b = a;
void func1()
{
TEST_MACRO
}
void func2()
{
TEST_MACRO
}
During the verification of such a code the messages concerning issues within macro will be immediately marked as False Alarms. Also, it is possible to select several diagnostics at once, separating them by comma:
//-V:TEST_MACRO:1001, 105, 201
Please note that if the macro contains another nested macro inside it then the name of top level macro should be specified for automated marking.
#define NO_ERROR 0
#define VB_NODATA ((long)(77))
size_t stat;
#define CHECK_ERROR_STAT \
if( stat != NO_ERROR && stat != VB_NODATA ) \
return stat;
size_t testFunc()
{
{
CHECK_ERROR_STAT // #1
}
{
CHECK_ERROR_STAT // #2
}
return VB_NODATA; // #3
}
In the example mentioned above the V126 diagnostics appears at three positions. To automatically mark it as False Alarm one should add the following code at positions #1 and #2:
//-V:CHECK_ERROR_STAT:126
To make it work at #3 you should additionally specify this:
//-V:VB_NODATA:126
Unfortunately to simply specify "to mark V126 inside VB_NODATA macro" and not to specify anything for CHECK_ERROR_STAT macro is impossible because of technical specifics of preprocessing mechanism.
Everything that is written in this section about macros is also true for any code fragment. For example, if you want to suppress all the warnings of the V103 diagnostic for the call of the function 'MyFunction', you should add such a string:
//-V:MyFunction:103
How to enable and disable certain diagnostics for a block of code
This section is only relevant to C and C++ analyzer.
In some cases, you may need to disable a rule for a certain part of the code, not for the entire project. For example, you need to disable diagnostics for a specific file or part of a file. In doing so, other diagnostics must remain enabled. And the analyzer must continue to issue the suppressed warning for the rest of the code.
To do this, the tool provides the suppression mechanism that uses special 'pragma' directives. This method is similar to the one used in a compiler to manage warnings.
The analyzer uses the following directives:
- #pragma pvs(push) – saves current enable/disable diagnostic warnings;
- #pragma pvs(disable: XXXX, YYYY, ...) – disables diagnostics with numbers from the list;
- #pragma pvs(enable: XXXX, YYYY, ...) – enables diagnostics with numbers from the list;
- #pragma pvs(pop) – restores previously saved settings.
Just as with '#pragma warning', nesting is supported.
Example:
void func(int* p1, int* p2, int* p3)
{
if (!p1 || !p2 || !p3)
return;
#pragma pvs(push)
#pragma pvs(disable: 547)
if (p1) // V547 off
do_something();
#pragma pvs(push)
#pragma pvs(enable: 547)
if (p2) // V547 Expression 'p2' is always true.
do_something_else();
#pragma pvs(pop)
if (p3) // V547 off
do_other();
#pragma pvs(pop)
}
Note. Compilers ignore unknown 'pragma' directives. Depending on settings, however, they may issue warnings about such directives. In this case, disable the warning by passing a special parameter to the compiler command line:
- for GCC and Clang: -Wno-unknown-pragmas
- for MSVC: -wd4068
Suppression of false positives through diagnostic configuration files (.pvsconfig)
Analyzer messages can be manipulated and filtered through the comments of as special format. Such comments can be placed either in the special diagnostic configuration files (.pvsconfig) for all analyzers, or directly inside the source code (but only for C/C++ analyzer).
The diagnostic configuration files are plain text files which are added to any Visual Studio project or solution. To add the configuration file, select the project or solution in question in the Solution Explorer window inside Visual Studio IDE, and select a context menu item 'Add New Item...'. In the following window, select the 'PVS-Studio Filters File' template (figure 3):
Figure 3 - Adding diagnostic configuration file to a solution.
Because of the specifics of some Visual Studio versions, the 'PVS-Studio Filters File' file template may be absent in some versions and editions of Visual Studio for projects and\or solutions. In such a case, it is possible to use add diagnostic configuration file as a simple text file by specifying the 'pvsconfig' extension manually. Make sure that after the file is added, it is set as non-buildable in its' compilation properties.
When a configuration file is added to a project, it will be valid for all the source files in this project. A solution configuration file will affect all the source files in all of the projects added to that solution.
In addition, .pvsconfig file can be placed in the user data folder (%AppData%\PVS-Studio\) - this file will be automatically used by analyzer, without the need to modify any of your project\solution files.
Note. '%AppData%\PVS-Studio\' may contain several '.pvsconfig' files. The analyzer will use them all. One should also take into account that the configuration from '%AppData%\PVS-Studio\' will be global for the analyzer and will certainly be used at each run.
When using the PVS-Studio_Cmd command-line tool, you can specify the path to the .pvsconfig configuration file using the ‑‑rulesConfig (-C) parameter, for example, as follows:
PVS-Studio_Cmd.exe -t D:\project\project.sln
-C D:\project\rules.pvsconfig
The '.pvsconfig' files utilize quite a simple syntax. Any line starting with the '#' character is considered a comment and ignored. The filters themselves are written as one-line C++/C# comments, i.e. every filter should start with '//' characters.
In case of C/C++ code, the filters can also be specified directly in the source code. Please note, that this is not supported for C# projects!
Next, let's review different variants of diagnostic configurations and filters.
Filtering analyzer messages by a fragment of source code (for example, macro, variable and function names)
Let us assume that the following structure exists:
struct MYRGBA
{
unsigned data;
};
Also there are several functions that are utilizing it:
void f1(const struct MYRGBA aaa)
{
}
long int f2(int b, const struct MYRGBA aaa)
{
return int();
}
long int f3(float b, const struct MYRGBA aaa, char c)
{
return int();
}
The analyzer produces three V801: "Decreased performance. It is better to redefine the N function argument as a reference" messages concerning these functions. Such a message will be a false one for the source code in question, as the compiler will optimize the code by itself, thus negating the issue. Of course it is possible to mark every single message as a False Alarm using the "Mark As False Alarm" option. But there is a better way. Adding this line into the sources will suffice:
//-V:MYRGBA:801
For C/C++ projects, we advise you to add such a line into .h file near the declaration of the structure, but if this is somehow impossible (for example the structure is located within the system file) you could add this line into the stdafx.h as well.
And then, every one of these V801 messages will be automatically marked as false alarm after re-verification.
Note: if you use comments of the //-V:MY_STRING:Vxxx form, PVS-Studio suppresses all Vxxx messages issued for strings that have the MY_STRING substring.
It's not only single words that the described mechanism of warning suppression can be applied. That's why it may be very useful sometimes.
Let's examine a few examples:
//-V:<<:128
This comment will suppress the V128 warning in all the lines which contain the << operator.
buf << my_vector.size();
If you want the V128 warning to be suppressed only when writing data into the 'log' object, you can use the following comment:
//-V:log<<:128
buf << my_vector.size(); // Warning untouched
log << my_vector.size(); // Warning suppressed
Note. Notice that the comment text string must not contain spaces.
Correct: //-V:log<<:128
Incorrect: //-V:log <<:128
When searching for the substring, spaces are ignored. But don't worry: a comment like the following one will be treated correctly:
//-V:ABC:501
AB C = x == x; // Warning untouched
AB y = ABC == ABC; // Warning suppressed
Complete warning disabling
Our analyzer allows the user to completely disable output of any warning through a special comment. In this case, you should specify the number of the diagnostic you want to turn off, after a double colon. The syntax pattern is as follows:
//-V::(number)
For example, if you want to ignore warning V122, you insert the following comment in the beginning of a file:
//-V::122
To disable a number of diagnostics, you can list their numbers separating them by commas. The syntax pattern is the following:
//-V::(number1),(number2),...,(numberN)
If you want to disable V502, V507, and V525 warnings, then the comment will look like this:
//-V::502,507,525
You can disable warnings for certain diagnostics at specific levels. The syntax pattern is the following:
//-V::(number1),(number2),...,(numberN):1,2,3
For example, if you need to disable V3161 and V3165 warnings at the 'Medium' and 'Low' levels, the comment will look like this:
//-V::3161,3165:2,3
In addition, the analyzer allows the user to filter warnings by their number and substring. The syntax pattern is as follows:
//-V::(number1),(number2),...,(numberN)::{substring}
For example, you can disable all V3022 and V3063 warnings that contain the "always true" substring:
//-V::3022,3063::{always true}
You can filter warnings by diagnostic number, level and substring simultaneously:
//-V::(number1),(number2),...,(numberN):1,2,3:{substring}
For example, you can disable all V5625 warnings at the second level that contain the "Google.Protobuf 3.6.1" substring:
//-V::5625:2:{Google.Protobuf 3.6.1}
There is also an option to disable a group of diagnostics. The syntax pattern is the following:
//-V::GA
//-V::X64
//-V::OP
//-V::CS
//-V::MISRA
To disable several groups of diagnostics, you can list them separating by commas. The syntax pattern is the following:
//-V::X64,CS,...
To turn off all the diagnostics of C++ or C# analyzer use the following form:
//-V::C++
//-V::C#
Since the analyzer won't output the warnings you have specified, this might significantly reduce the size of the analysis log when too many false positives are generated for some diagnostic.
Excluding files from the analysis by masks
You can set the exclusion from the analysis of files / directories that correspond to specified masks. It might be convenient, for example, when it's needed to exclude the code of third-party libraries or automatically generated files from the analysis.
Several examples of masks:
//V_EXCLUDE_PATH C:\TheBestProject\thirdParty
//V_EXCLUDE_PATH *\UE4\Engine\*
//V_EXCLUDE_PATH *.autogen.cs
Syntax of masks is the same as the one for the options 'FileNameMasks' and 'PathMasks', described in the document "Settings: Don't Check Files".
Ignoring global configuration files
Before running the analysis, 'PVS-Studio_Cmd' generates the configuration of diagnostic rules from:
- global files in '%AppData%\PVS-Studio\';
- the file passed through the ‑‑rulesConfig (-C) option;
- files added to the solution;
- files added to the project.
You may have a large number of projects and the configuration for these projects can be generated in various ways. In this case, configuration from global files sometimes may lead to confusion in the resulting configuration. The reason is the following: the configuration from the global files always applies to whatever project you are working on. In other words, settings that are specific only to the X project will also be applied to other projects as well.
So if you need to ignore global configuration files, you need to add a special flag to the corresponding '.pvsconfig' file:
//IGNORE_GLOBAL_PVSCONFIG
The flag works as follows:
- if the flag is set in one of the global files, the global configuration will always be ignored.
- if the flag is set at the solution level, the global configuration is ignored for a specific solution;
- if the flag is set at the project level, the global configuration is ignored for a specific project.
The usage of the flag will allow you to flexibly disable the global settings for certain cases.
Other means of filtering messages in the PVS-Studio analyzer (Detectable Errors, Don't Check Files, Keyword Message Filtering)
There may be situations in which a certain type of diagnostics is not relevant for the analyzed project, or one of the diagnostics produces warnings for the source code which, you have no doubt in it, is correct. In this case, you can use the group messages suppression based on the filtering of the gained analysis results. The list of available filtering modes can be accessed through the 'PVS-Studio -> Options' menu item.
The suppression of multiple messages through filters does not require restarting of the analysis, the filtering results will appear in PVS-Studio output window immediately.
First, you may disable diagnosis of some errors by their code. You may do this using the "Settings: Detectable Errors" tab. On the tab of detected errors, you may specify the numbers of errors that must not be shown in the analysis report. Sometimes it is reasonable to remove errors with particular codes from the report. For instance, if you are sure that errors related to explicit type conversion (codes V201, V202, V203) are not relevant for your project, you may hide them. A display of errors of a certain type can be disabled using the context menu command "Hide all Vxxx errors". Accordingly, in case you need to enable a display back, you can configure it on the section "Detectable Errors", mentioned above.
Second, you may disable analysis of some project's parts (some folders or project files). This is the "Settings: Don't Check Files" tab. On this tab, you may insert information about libraries whose files' inclusions (through the #include directive) must not be analyzed. This might be needed to reduce the number of unnecessary diagnostic messages. Suppose your project employs the Boost library. Although the analyzer generates diagnostic messages on some code from this library, you are sure that it is rather safe and well written. So, perhaps there is no need to get warnings concerning its code. In this case, you may disable analysis of the library's files by specifying the path to it on the settings page. Besides, you may add file masks to exclude some files from analysis. The analyzer will not check files meeting the mask conditions. For instance, you may use this method to exclude autogenerated files from analysis.
Path masks for files which are mentioned in the latest generated PVS-Studio report in the output window could be appended to the 'Don't Check Files' list using the "Don't check files and hide all messages from..." context menu command for the currently selected message (figure 4).
Figure 4 - Appending path masks through the context menu
This command allows the appending either of a single selected file or of the whole directory mask containing such a file.
Third, you may suppress separate messages by their text. On the "Settings: Keyword Message Filtering" tab, you may set filtering of errors by their text and not their code. If necessary, you may hide error messages containing particular words or phrases in the report. For instance, if the report contains errors that refer to the names of the functions printf and scanf and you think that there cannot be any errors related to them, you should simply add these two words using the editor of suppressed messages.
Mass suppression of analyzer messages (baselining)
Sometimes, especially on the stage of stage of implementation of static analysis in large projects, you may need to 'suppress' all warnings of code base, since the developers may not have the necessary resources to fix the errors found by the analyzer in the old code. In such a case, it can be useful to 'hide' all warnings issued for existing code to track it only when errors occur again. This can be achieved by using the "mass suppression of analyzer messages" mechanism. The use of the appropriate mechanism in Windows environment is described in the document "Mass suppression of analyzer messages", in Linux environment - in the relevant section of document "How to run PVS-Studio on Linux".
Possible issues
In rare cases markers arranged automatically might sometimes appear in false places. In this case, the analyzer will again produce the same error warnings because it will fail to find the markers. This is the issue of the preprocessor refers to multi-line #pragma-directives of a particular type that also cause confusion with line numbering. To solve this issue, you should mark messages you experience troubles with manually. PVS-Studio always informs about such errors with the message "V002. Some diagnostic messages may contain incorrect line number".
Like in case of any other procedure involving mass processing of files, you must remember about possible access conflicts when marking messages as false alarms. Since some files might be opened in an external editor and modified there during file marking, the result of joint processing of such files cannot be predicted. That is why we recommend you either to have copies of source code or use version control systems.