Suppression of false alarms

04.06.2013

Abstract

The article describes the function "Mark as False Alarm" that appeared in PVS-Studio 3.40 and provides an example of how to use it. This function allows you to mark those PVS-Studio analyzer diagnostic messages which are "false alarms" so that you would not have to see them at the next launch of the analyzer.

Suppression of individual false positives.

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:

ptrdiff_t value;
fread(&value, 4, 1, f);
char RGBA[4];

There will be two V112 warnings generated for this code since the magic constant 4 is used here. In the first case, it is an error because the size of a variable of the ptrdiff_t type will not equal four bytes in the 64-bit system. In the second case, number 4 signifies the number of color components and is safe. In PVS-Studio, beginning with the version 3.40, we have implemented the capability to mark an error message generated by PVS-Studio as a false alarm. You may do this either manually or with the help of the corresponding context menu command. Appearance of the "Mark as False Alarm" option in PVS-Studio greatly extends the potential of integrating the code analyzer into the software development process at the stage of everyday permanent use, which allows you not only port applications to the 64-bit platform but also make sure that there are no dangerous issues in new code you have just developed.

To suppress a false alarm, you may add a special comment into the code:

char RGBA[4]; //-V112

Now the analyzer will not generate the V112 warning on this line.

You may type the comment suppressing warnings into the code by yourself. You may also use a special command provided by PVS-Studio. The user is provided with two commands available from the PVS-Studio's context menu (see Figure 1).

Figure 1 - Commands to work with the mechanism of false alarm suppression

Figure 1 - Commands to work with the mechanism of false alarm suppression

Let's study the available commands concerning False Alarm suppression:

1. Mark selected errors as False Alarm. You may choose one or more false alarms in the list (see Figure 2) and use this command to mark the corresponding code as safe.

Figure 2 - Choosing warnings before executing the Mark Selected errors as False Alarms command

Figure 2 - Choosing warnings before executing the Mark Selected errors as False Alarms command

2. Remove False Alarm marks from selected errors. 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.

Suppression of multiple false positives by using the group filtering mechanism

It is possible that certain kinds of diagnostics are not essential for the project being analyzed (For example, if you are not interested in the errors relating to explicit type casting — V201, V202, V203 codes, e.t.c.), or one of the diagnostics produces warnings for the source code which, you have no doubt in it, is correct. In such a situation one could utilize the group suppression mechanism, which is based on filtering the analysis output results. The list of available filtering modes can be accessed through the "Suppressions" toolstrip button, or through the common PVS-Studio -> Options menu (see figure 3)

Figure 3 - The group message filtering modes

Figure 3 - The group message filtering modes

The group filtering modes include Detectable Errors, Don't Check Files and Message Suppression.

Utilizing the "Hide all Vxxx errors" context menu command (see in figure 1) it is possible to disable the display of all the errors belonging to a certain code. To enable the display of these errors again you should select the "Detectable Errors" mode and check the required code as True.

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.

Demonstration of the Mark as False Alarm function using OmniSample project as example

Let's show how to use the Mark as False Alarm function with the demo project, which is included into the PVS-Studio distribution package, as example.

At first you need to unpack the demo project into any folder you like from menu Start\PVS-Studio\. (project samples, file Samples.zip) or through IDE 'PVS-Studio\Open Samples.zip examples' menu item and open it in the Microsoft Visual Studio environment.

After opening the project, let's launch analysis of the solution using the "Check Solution / Check Project Group" command (depending on the IDE you utilize). As the analysis is over, the list of detected issues will appear (Figure 4).

Figure 4 - The list of issues detected by PVS-Studio

Figure 4 - The list of issues detected by PVS-Studio

You need to review and study this message list.

Next, let's study the following message of the analyzer:

V547 Expression 'N >= 0' is always true. Unsigned type value is always >= 0. sample1.cpp 18

The source code corresponding to this message (and this line number) is:

if (TEST(N))
{
  data->num = N;
}

Certainly, it is possible to just simply rewrite this fragment for this message to disappear. The issue is that the macro expression, which is utilized here, can be correct on different platforms. So if you are completely confident that the code is correct, it is possible to "disable" the display of this particular type of messages (V547) in this particular line (18) of this file (sample1.cpp). To do this, you should select the corresponding error message in the PVS-Studio window and choose the "Mark Selected Errors as False Alarm" command in the PVS-Studio context menu (Figure 5).

Figure 5 - "Mark Selected Errors as False Alarm" command

Figure 5 - "Mark Selected Errors as False Alarm" command

After that, the " //-V547" comment will be automatically added into the code:

if (TEST(N))//-V547

This comment informs the code analyzer that it must not generate the message about this error in this line when analyzing the project next time.

You may add this comment manually as well without using the "Mark selected errors as False Alarms" command, but you must follow the note's format: two slashes, minus (without a space), error code.

After marking the message as a false alarm, you may use the "False Alarms" check-button (Figure 6) to refresh the list of error messages and hide the unnecessary message. After that the PVS-Studio window will contain one less item.

Figure 6 - The FA button controls the display of marked messages

Figure 6 - The FA button controls the display of marked messages

You may remove the comment using the "Remove False Alarm marks from selected errors" command, having chosen the error message in the PVS-Studio window beforehand. You may also remove the comment manually.

Figure 7 - "Remove False Alarm Marks from selected errors" command

Figure 7 - "Remove False Alarm Marks from selected errors" command

So, we have marked one error as a "false alarm". Let's relaunch the analysis and see that we get one less message. Note that the message we have marked as a "false alarm" is absent in the PVS-Studio window this time.

If you need to see all the messages in the PVS-Studio window (including the false alarms), you may enable their display once again using the "FA" check-button (Figure 8).

Figure 8 - Enabling the display of marked messages

Figure 8 - Enabling the display of marked messages

You may mark several messages at once. To do this, you should choose them in the PVS-Studio window (Figure 9).

Figure 9 - Choosing several messages to mark in the PVS-Studio window

Figure 9 - Choosing several messages to mark in the PVS-Studio window

We do not recommend you to mark messages as false alarms without preliminarily reviewing the corresponding code fragments since it contradicts the ideology of static analysis. Only the programmer can determine if a particular error message is false or not.

Implementation of the false alarm suppression function

Usually compilers employ #pragma-directives to suppress individual error messages. Consider a code sample:

unsigned arraySize = n * sizeof(float);

The compiler generates the following message:

warning C4267: 'initializing' : conversion from 'size_t' to 'unsigned
int', possible loss of data x64Sample.cpp 151

This message can be suppressed with the following construct:

#pragma warning (disable:4267)

To be more exact, it is better to arrange the code in the following way to suppress this particular message:

#pragma warning(push)
#pragma warning (disable:4267) 
  unsigned arraySize = n * sizeof(float);
#pragma warning(pop)

The PVS-Studio analyzer uses comments of a special kind. Suppression of the PVS-Studio's message for the same code line will look in the following way:

unsigned arraySize = n * sizeof(INT_PTR); //-V103

This approach was chosen to make the target code cleaner. The point is that PVS-Studio can inform about issues in the middle of multi-line expressions as, for instance, in this sample:

  size_t n = 100;
  for (unsigned i = 0;
       i < n; // the analyzer will inform of the issue here
       i++)
  {
      // ...
  }

To suppress this message using the comment, you just need to write:

  size_t n = 100;
  for (unsigned i = 0;
       i < n; //-V104
       i++)
  {
      // ...
  }

But if we had to add a #pragma-directive into this expression, the code would look much less clear.

Storage of the marking in source code lets you modify it without the risk to lose information about lines with errors.

Theoretically we may also use a separate base where we could store information in the following approximate pattern: error code, file name, line number. The disadvantage of this approach is that you risk losing information about numbers of lines with errors when modifying source files from outside. Storage of the marking in source code allows you to bring modifications into it without the risk to lose information about lines with errors.

Suppressing false positives located within macro statements (#define)

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 // V101 here
}

void func2()
{
  TEST_MACRO // V101 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 //-V101
}

void func2()
{
  TEST_MACRO //-V101
}

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:101

#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:101, 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.

Mass suppression of false positive alarms

Let us assume that the following structure exists:

struct EXRGBA
{
unsigned data;
};

Also there are several functions that are utilizing it:

void f1(const struct EXRGBA aaa)
{
}

long int f2(int b, const struct EXRGBA aaa)
{
  return int();
}

long int f3(float b, const struct EXRGBA 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:EXRGBA:801 

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.

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

You can use a comment to completely turn off the warning. In this case, the word that must be found in the code line is not specified. The comment's syntax:

//-V::(number) – to turn off one diagnostic

//-V::(number1),(number2),...,(numberN) – to turn off a number of diagnostics

If you need to ignore the V122 warning in a file, you can type in the following in the beginning of it:

//-V::122

If you need to globally turn off the diagnostic throughout the entire project, add the "//-V::122" comment into the stdafx.h file.

Other means of filtering messages in the PVS-Studio analyzer

The analyzer also provides three more methods of error messages filtering.

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.

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 10).

Figure 10 — Appending path masks through the context menu

Figure 10 — 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: Message Suppression" 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.

Possible issues

There might be some issues when using the "Mark as False Alarm" function. Sometimes the analyzer "misses" the number of a line with an error. For instance, the analyzer says that there is an error in line 57 while line 57 is empty at all. Then it is the code, for instance, one line above (line 56) that causes the error.

The reason is that the code analyzer uses the preprocessor from Visual C++ that experiences problems when dealing with multi-line macros (#define). These problems were eliminated in Visual Studio 2005 Service Pack 1 and later versions.

Another issue of the preprocessor refers to multi-line #pragma-directives of a particular type that also cause confusion with line numbering. Unfortunately, this error has not been fixed in any version of Visual Studio yet.

So, 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. 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.