Cppcheck Design Overview
DanielMarjamäki
Cppcheck
2010
Introduction
This article is an overview of the design of Cppcheck.
The design of Cppcheck are based on:
Cppcheck will never be perfectly clever
No false warnings are allowed
Limitations of static analysis
It is not very reasonable to think that a static analysis tool will
detect all bugs in your code.
There are many bugs in programs that is really hard to detect for
tools.
Many bugs are caused by wrong calculations. Here is an
example:
// calculate number of days
int days(int hours)
{
return hours / 23;
}
A human programmer can see the error in that code because he knows
that there are 24 hours in a day.
Tools will probably not know that there are 24 hours in a
day.
A tool that tries to guarantee that all bugs are found could write a
warning message for every calculation in the program. In my humble opinion
it wouldn't be usable to do that.
Cppcheck will only write a warning message if it can determine that
the calculation is wrong. This approach means that many bugs will not be
detected.
Buffer overflows
This is a simple description of the buffer overflows checking in
Cppcheck.
For simple cases, no sophisticated control flow analysis is used. If
an array is accessed out of bounds somewhere in its scope then an error
message will be written.
An example code:
void f()
{
char a[10];
if (x + y == 2) {
a[20] = 0;
}
}
Cppcheck will report this message:
Array 'a[10]' index 20 out of bounds
Cppcheck will not try to determine how execution can reach the
"a[20] = 0;" statement. It is assumed that all statements are reachable.
Cppcheck will detect the error even if it is really impossible that "x + y
== 2" is true. I still claim that this is a correct warning because the
statement is there and it has the error.
Cppcheck will also investigate function calls. But then control flow
is needed to avoid false warnings. Here is an example that logically is
the same as the previous example:
void f1(char *s)
{
s[20] = 0;
}
void f2()
{
char a[10];
if (x + y == 2) {
f1(a);
}
}Cppcheck will report this message:
Array 'a[10]' index 20 out of bounds
If the execution reaches the function call then there will be an
error.
But if the condition is moved into "f1" then it will be necessary to
prove that "x+y==2" can be true when the function is called from
"f2".
No error message is reported for this code:
void f1(char *s)
{
if (x + y == 2) {
s[20] = 0;
}
}
void f2()
{
char a[10];
f1();
}
Memory leaks
Simple control-flow analysis is made. The assumtion is that all
conditions can always be either true or false.
It is assumed that all statements are reachable.
Here is an example:
void f()
{
char *a = malloc(10);
if (x + y == 2) {
return;
}
free(a);
}
Cppcheck will determine that there is a leak at the "return;"
statement:
Memory leak: a
Cppcheck doesn't try to determine how the execution reaches the
"return;" statement. It will only see that if the execution reaches the
"return;" then there will be a memory leak.
This lack of advanced control-flow analysis means that many bugs are
not detected:
void f(int x)
{
char *a = 0;
if (x == 10)
a = malloc(10);
if (x == 20)
free(a);
}
Many other static analysis tools will probably detect that.
Many memory leaks are caused by:
Completely forgetting to deallocate
Forgetting to deallocate in a bailout path
These types of leaks should be detected by Cppcheck.