A Brief Overview of the PVS-Studio Static Code Analyzer

Contents[Show]

During one of C++Russia conferences, I got acquainted with the team, developing the PVS-Studio code analyzer. Right now, I'd like to hand it over to them. They will make a small overview of this amazing tool, give a few useful links. In addition, they promised to provide you with a small bonus.

 

null pointer

Hello, everyone. Thanks to Rainer Grimm for letting us make a guest post and let's start.

Static analyzers issue messages are similar to compiler warnings. The difference is that static analyzers are not subject to the same stringent performance limits as compilers. They aren't aimed at code optimization. Analyzers can use more memory and work longer, allowing them to use deeper and higher-level error-finding algorithms. For example, they can follow the interconnections of functions and detect memory leaks and null pointer dereference in the following code:

int *GetPtr()
{
  int *a = (rand() % 2) ? new int : nullptr;
  return a;
}

void foo()
{
  int *p = GetPtr();
  *p = 123;       // potential null pointer dereference
}                 // memory leak

These errors are detected by the PVS-Studio analyzer:

  • V522 [CWE-690] There might be dereferencing of a potential null pointer 'p'. test.cpp 35
  • V773 [CWE-401] Visibility scope of the 'p' pointer was exited without releasing the memory. A memory leak is possible. test.cpp 36

PVS-Studio is positioned as a B2B product, however, there are several options of free usage. It can be used for free by many open project developers. More interestingly, there is a free option for small, closed commercial projects. To get it, you have to add special comments to the code. Read more: "Ways to Get a Free PVS-Studio License".

The natural way to try the analyzer on commercial code is to get the trial version. Here comes the bonus promised to readers. With the hashtag #modernescpp in the request form, the license key will be generated not for a week, but for a month.

The following question may arise: does all this make sense? Today's compilers are very good at finding many potential bugs and are developing rapidly.

Back to the above question - it definitely makes sense to try the static analyzer. First, the PVS-Studio team also doesn't sit idly by and is very active in developing algorithms for detecting defects. This enables them to post articles each and every year on errors that PVS-Studio can find even in well-tested compilers:

Secondly, PVS-Studio integrates with various third-party solutions and has interesting auxiliary subsystems. One of these subsystems allows you to seamlessly implement the analyzer in large legacy projects. The general idea is the following. The team runs the analyzer on a large codebase and gets many warnings. If the project is alive, then the critical bugs have somehow been corrected in more expensive ways. Everything that the analyzer now finds can be considered a technical debt, which is impractical to try to eliminate immediately.

You can tell PVS-Studio to consider all these warnings as irrelevant so far (to postpone the technical debt for later), and not to show them any more. The analyzer creates a special file where it stores information about uninteresting errors. From now on, PVS-Studio will issue warnings only for new or modified code. If an empty line is added at the beginning of a .cpp file, the analyzer will size up a situation that nothing has really changed and will remain quiet. You can put the file containing information on suppressed warnings into the version control system. Even though the file is large, it's not a problem, as there's no need to upload it very often.

Developers will see only warnings related to newly written and modified code. So you can start using the analyzer, as they say, from the next day. You can get back to technical debt later and gradually correct errors and tweak the analyzer.

Seems like all this doesn't directly relate to the analysis itself or to errors search. But still, these features have a pivotal role in implementing and regular usage of static analysis in a complex project. At the same time, high-quality support should not go unspoken here. By the way, one of PVS-Studio developers had a very nice talk about support: "Don't take on C++ programmers support" :). 26mb string literal - holy molly!

Let's get back to diagnostic capabilities.

PVS-Studio is good at finding typos. Use the analyzer as an additional helper when reviewing code that is not lazy to check boring code. It will help to find bugs in code, which, at first glance, seems uninteresting to study, because "how can you ever make a mistake here..." For example, let's look at comparison functions:

bool FaceTypedBSpline::isEqual(const TopoDS_Face &faceOne,
                               const TopoDS_Face &faceTwo) const
{
  ....
  if (surfaceOne->IsURational() != 
      surfaceTwo->IsURational())
    return false;
  if (surfaceTwo->IsVRational() != 
      surfaceTwo->IsVRational())
    return false;
  if (surfaceOne->IsUPeriodic() != 
      surfaceTwo->IsUPeriodic())
    return false;
  if (surfaceOne->IsVPeriodic() != 
      surfaceTwo->IsVPeriodic())
    return false;
  if (surfaceOne->IsUClosed() != 
      surfaceTwo->IsUClosed())
    return false;
  if (surfaceOne->IsVClosed() != 
      surfaceTwo->IsVClosed())
    return false;
  if (surfaceOne->UDegree() != 
      surfaceTwo->UDegree())
    return false;
  if (surfaceOne->VDegree() != 
      surfaceTwo->VDegree())
    return false;
  ....
}

What a boring thing is it to review such code, isn't it? The program pointing at the following issue is here to help:

if (surfaceTwo->IsVRational() != 
    surfaceTwo->IsVRational())

Seems like the problem is contrived? The PVS-Studio team wrote a funny (or disappointing) article "The Evil within the Comparison Functions". It cites a lot of similar bugs found in projects such as Chromium, MongoDB, Qt, FreeBSD, Unreal Engine 4, GDB, GCC and others. Well, unfortunately, it actually feels like crying.

Ok, let's move on to the last example. PVS-Studio creators monitor the main trends of the C++ language development and make diagnostics for new, recently non-existent patterns of errors. For instance, the analyzer will detect the iterator invalidation in the for range-based loop. A real example from the ClickHouse project:

using Strings = std::vector<std::string>;
....
Strings input_files;
....
for (const String filename : input_files)
{
  ....
  if (FS::is_directory(file))
  {
    input_files.erase(
      std::remove(input_files.begin(),
                  input_files.end(),
                  filename) ,
      input_files.end() );

    getFilesFromDir(file, input_files, recursive);
  }
  ....
}

The analyzer will issue the V789 warning here, indicating the change inside the loop of the input_files container.

So that's all I have to say on this matter. The size and complexity of projects are growing. Static analysis tools can be good helpers to maintain high-level code quality, and reduce the cost of finding bugs and zero-day vulnerabilities. Therefore, try PVS-Studio and other code analyzers. Don't forget that these tools are meant to be used on a regular basis, not just once.

Thank you all for your attention. Yours sincerely, PVS-Studio team.

Additional links

  1. Download PVS-Studio (don't forget about #modernescpp)
  2. Error base. You're welcome to use the above information when preparing for talks and articles on the topic of code writing ;)
  3. PVS-Studio internals

My Newest E-Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code

Visitors

Today 6486

Yesterday 5047

Week 6486

Month 146247

All 4596339

Currently are 143 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments