>
>
>
Explanation on Diagnostic V595

Andrey Karpov
Articles: 674

Explanation on Diagnostic V595

Among others, PVS-Studio has diagnostic V595 "The pointer was utilized before it was verified against nullptr". I get lots of questions from our users regarding this diagnostic, so I decided to prepare a detailed answer in advance to help explain the principle behind it to future users.

See the description of diagnostic V595 in the documentation: The pointer was utilized before it was verified against nullptr.

Note. Since 2015 (when the article was published), a lot has changed. The V595 diagnostic has become smarter. Now the analyzer can look into the bodies of functions, including those located in different files. Thanks to this, this diagnostic can detect more complex errors. See the "PVS-Studio: static code analysis technology" section.

A typical question regarding V595 sounds like this:

I have the following code:

void MyClass::Do()
{
  m_ptr->Foo(1, 2, 3);
  Process(1, 2, 3, 4, 5);
}

The 'm_ptr' member can sometimes get zero values. When it happens, the program crashes. I expected the PVS-Studio analyzer to warn me that the 'm_ptr' pointer should have been checked before use. I want to get the V595 warning but it's not displayed. Please explain why.

I'll try to give a detailed answer.

In general, the PVS-Studio analyzer cannot diagnose issues when a pointer can be null and must be checked before use.

If we made a "straightforward" diagnostic to warn you whenever a pointer is used without a check, it wouldn't do any good because you'd be getting such a huge amount of false positives that a real bug, if any, would get lost among false positives and never be discovered. That's why it wouldn't make sense doing it that way.

Ideally, we should try to figure out if the pointer can be null. But it's an incredibly difficult task. We'd need to analyze the call graph and find out what values the variables can have. It's just impossible in practice. Different analyzers, including PVS-Studio, try to partly solve this task for simple cases, but in general they are far from success. Many bugs would stay unnoticed by user; many others would be missed by the analyzer.

The PVS-Studio analyzer can find that kind of bug only in simple cases, for example:

void Foo(int *p)
{
  if (!p)
  {
    p[1] = 2; //V522
  }
}

It detects that the program enters the if-statement's body if the pointer equals 0; therefore, dereferencing it will cause an error. But it's a very simple example. In complex ones, like that discussed in the beginning, the analyzer is just helpless. It can't figure out what is currently stored in 'm_ptr'.

Since the analyzer is obviously bad at solving tasks like that in a straightforward fashion, we use some roundabout ways to look for errors of this type. One of these ways is to use the V595 diagnostic. The idea behind it is: output a warning when a pointer is first used and then checked.

Here's an example. PVS-Studio doesn't know the contents of 'p', so it keeps silent:

void Foo()
{
  int *p = Get();
  p[0] = 1;
  ....
}

But at some point later, the programmer recalled that the pointer could be equal to null and implemented a check for it:

void Foo()
{
  int *p = Get();
  p[0] = 1; // V595
  ....
  if (p == NULL)
    Zzz();
}

Here's when PVS-Studio outputs the V595 warning. It can't evaluate the Get() function's return result, but it doesn't actually need that. It just "sees" that the pointer is checked for being null a bit later in the code, and infers from it that this pointer can be null on certain occasions and can't be dereferenced without being checked first.

Hopefully I have managed to clarify on how the analyzer handles this kind of bugs and why it doesn't display the warning for the code sample discussed in the beginning. There is no check of the 'm_ptr' variable for 0 later in the code, so there is no warning. The analyzer is helpless here, unfortunately.