Our website uses cookies to enhance your browsing experience.
Accept
to the top
close form

Fill out the form in 2 simple steps below:

Your contact information:

Step 1
Congratulations! This is your promo code!

Desired license type:

Step 2
Team license
Enterprise license
** By clicking this button you agree to our Privacy Policy statement
close form
Request our prices
New License
License Renewal
--Select currency--
USD
EUR
* By clicking this button you agree to our Privacy Policy statement

close form
Free PVS‑Studio license for Microsoft MVP specialists
* By clicking this button you agree to our Privacy Policy statement

close form
To get the licence for your open-source project, please fill out this form
* By clicking this button you agree to our Privacy Policy statement

close form
I am interested to try it on the platforms:
* By clicking this button you agree to our Privacy Policy statement

close form
check circle
Message submitted.

Your message has been sent. We will email you at


If you do not see the email in your inbox, please check if it is filtered to one of the following folders:

  • Promotion
  • Updates
  • Spam

Webinar: Evaluation - 05.12

>
>
>
Special case of error

Special case of error

Jul 29 2024

Static analysis cannot detect some types of program errors in a "general" way, or these errors may be extremely difficult to find. In this case, you may be better off learning how to identify many individual error patterns of the same type. In other words, one should look for special cases of errors. The easiest way to understand this concept is to illustrate it.

Both C and C++ have errors related to undefined behavior (UB) in code. So, static analyzers should detect code that causes UB. However, it is easier said than done.

Undefined behavior is not a specific type of a bug or typo. The C and C++ standards describe a wide variety of cases that lead to UB. Undefined behavior has been the subject of many articles and books. New language constructs appear as new C and C++ standards get released. If used incorrectly, they tend to cause undefined behavior in new ways.

So, in reality, the detection of undefined behavior is the creation of many separate diagnostic rules, each looking for its own patterns (cases) of errors. Here is an example:

  • the argument of the operator delete is the void * pointer (V772);
  • a macro whose name overrides a keyword or reserved identifier (V1059) is declared;
  • incorrect shift operations (V610);
  • and so on.

Let's take a look at another example, which is a null pointer dereference. By the way, this is also a special case of undefined behavior, but everyone considers this error type separately.

The analyzer can find a lot of such errors by performing data flow and control flow analysis. Here's the simplest yet real-world example:

ViewProviderPage* vpp = getViewProviderPage(dView);
if (!vpp) {
  return vpp->getQGVPage();

PVS-Studio warns (V522) that if we go into the if statement, a null pointer is dereferenced.

Unfortunately, the high computational complexity makes it impossible for static analyzers to trace all the paths of program execution and data transfer in general. That's why analyzers often can't determine whether a pointer can be null or not.

Warning a programmer about the use of pointers for which there is no information and "just in case" is a bad idea. It may lead to numerous false positives and render the analyzer useless. Helpful warnings may drown in an endless flood of useless ones, and the programmer will stop looking at them. So, at PVS-Studio, we stick to this philosophy: warn users only when there is a reason to suspect an error.

Is there something we can do if even the analyzer was unable to calculate whether a pointer can be null or not? Yes, there is. For example, PVS-Studio provides the following model for searching errors:

Ms::Segment* startSegment = score()->selection().startSegment();

startSegment->measure()->firstEnabled();  // <= (1)

if (!startSegment) {                      // <= (2)
  return nullptr;
}

Let's assume that in this case, the analyzer failed to determine whether the startSegment pointer can be null or not. However, indirectly, we can certainly say that the code contains an error.

Note that the pointer is first dereferenced (1) and then checked (2). Since the pointer is checked, it can be equal to nullptr. So, a null pointer can be dereferenced here.

The PVS-Studio analyzer identifies such an erroneous pattern and issues the V595 warning. By the way, this is a very common antipattern, and we have already collected a large list of such bugs.

This is a very clear example. Theoretically, we may find the use of all null pointers by analyzing the data flow. However, the computational complexity of the task limits the capabilities of analyzers. The special case of an error detection—one of which we have just discussed—comes to the rescue. There are also other ways, such as the V757 diagnostic rule. By complementing each other, the diagnostic rules are generally good at finding null pointers.

Additional links:

Popular related articles


Comments (0)

Next comments next comments
close comment form