Additional diagnostics configuration


How to tell the analyzer that a function can or cannot return nullptr

There are many system functions, such as malloc, realloc, and calloc, that return a null pointer in certain conditions. They return NULL when they fail to allocate a buffer of the specified size.

Sometimes you may want to change the analyzer's behavior and make it think, for example, that malloc cannot return NULL. This can be done by using the system libraries, where 'out of memory' errors are handled in a specific way.

An opposite scenario is also possible. You may want to help the analyzer by telling it that a certain system or user-made function can return a null pointer.

To help you with that, we added a mechanism that allows you to use special comments to tell the analyzer that a certain function can or cannot return NULL.

  • V_RET_NULL - the function can return a null pointer
  • V_RET_NOT_NULL - the function cannot return a null pointer

Comment format:

//V_RET_[NOT]_NULL, namespace:Space, class:Memory, function:my_malloc
  • function option - specifies the name of the function that can(not) return NULL.
  • class option - class name; optional.
  • namespace option - namespace name; optional.

The controlling comment can be written next to the function declaration.

However , you cannot do this for such functions as malloc because changing system header files is a bad idea.

A possible way out is to add the comment to one of the global headers included into each of the translation units. If you work in Visual Studio, the file stdafx.h would be a good choice.

Another solution is to use the diagnostic configuration file pvsconfig. See "Suppression of false alarms" (section "Mass suppression of false positives through diagnostic configuration files (pvsconfig)").

This is illustrated by the two examples below.

The function does not return NULL:

//V_RET_NOT_NULL, function:malloc

Now the analyzer thinks that the malloc function cannot return NULL and, therefore, will not issue the V522 warning for the following code:

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

The function returns a pointer that could be null:

//V_RET_NULL, namesapce:Memory, function:QuickAlloc

With this comment, the following code will be triggering the warning:

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

In projects with special quality requirements, you might need to find all functions, returning a pointer. To do this, you can use the following comment:

//V_RET_NULL_ALL

We don't recommend using this mode because of issuing a large number of warnings. But if it's really needed in your project, you can use this special comment to add in code a check of a returned pointer for all such functions.

How to Set Your Level for Specific Diagnostics

Analyzer warnings are of three levels of certainty: High, Medium, Low. Depending on the used constructs in code the analyzer estimates the certainty of warnings and assigns them an appropriate level in a report. Some warnings may be issued simultaneously on several levels.

In some projects, search for specific types of errors can be very important, regardless of the level of warning certainty. Sometimes there can be a reverse situation, when the error messages are of little use, but a programmer does not want to disable them at all. In such cases, you can manually set the diagnostics level of High/Medium/Low. To do this, you should use the special comments that can be added in code or the diagnostics configuration file. Examples of comments:

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

Finding such comments, the analyzer issue warnings at the specified level.

Changing an output message's text

You can specify that one or more entities should be replaced with some other one(s) in certain messages. This enables the analyzer to generate warnings taking into account the project's specifics. The control comment has the following format:

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

In all the messages Vnnn, the following replacements will be done:

  • Aaaa will be replaced with Bbbb.
  • <foo.h> will be replaced with <myfoo.h>.
  • The number 100 will be replaced with 200.

The working principle of this mechanism is best to be explained by an example.

When coming across the number 3.1415 in code, the V624 diagnostic suggests replacing it with M_PI from the <math.h> library. But suppose our project uses a special math library and it is this library that we should use mathematical constants from. So the programmer may add the following comment in a global file (for example StdAfx.h):

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

After that the analyzer will be warning that the OUR_PI constant from the header file "math/MMath.h" should be used.

You can also extend messages generated by PVS-Studio. The control comment has the following format:

//+Vnnn:ADD:{ Message}

The string specified by the programmer will be added to the end of every message with the number Vnnn.

Take diagnostic V2003, for example. The message associated with it is: "V2003 - Explicit conversion from 'float/double' type to signed integer type.". You can reflect some specifics of the project in the message and extend it by adding the following comment:

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

From now on, the analyzer will be generating a modified message: "V2003 - Explicit conversion from 'float/double' type to signed integer type. Consider using boost::numeric_cast instead.".

Configuration of the assert() macro handling

The analyzer equally checks the code where the assert() macro is presented regardless of the configuration of the project (Debug, Release, ...) and specifically doesn't take into account that the execution of the code is interrupted when having the false condition.

To set another analyzer behavior, use the following comment in code:

//V_ASSERT_CONTRACT

Note that in such a mode the analysis results may differ depending on the way the macro is expanded in the checked project configuration.

Let's look at this example to make it clear:

MyClass *p = dynamic_cast<MyClass *>(x);
assert(p);
p->foo();

The dynamic_cast operator can return the nullptr value. Thus, in the standard mode the analyzer will issue the warning that when calling the function foo(), null pointer dereference might occur.
But if we use the comment, the warning will be gone.


Do you make errors in the code?

Check your code
with PVS-Studio

Static code analysis
for C, C++, and C#

goto PVS-Studio;