2010-12-28 17:41:56 +01:00
|
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
2011-06-27 23:36:23 +02:00
|
|
|
<appendix>
|
2010-12-28 17:41:56 +01:00
|
|
|
<info>
|
2010-12-28 19:47:56 +01:00
|
|
|
<title>Cppcheck Design</title>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
|
|
|
<author>
|
|
|
|
<personname><firstname>Daniel</firstname><surname>Marjamäki</surname></personname>
|
|
|
|
|
|
|
|
<affiliation>
|
|
|
|
<orgname>Cppcheck</orgname>
|
|
|
|
</affiliation>
|
|
|
|
</author>
|
|
|
|
|
|
|
|
<pubdate>2010</pubdate>
|
|
|
|
</info>
|
|
|
|
|
|
|
|
<section>
|
|
|
|
<title>Introduction</title>
|
|
|
|
|
2010-12-29 18:03:57 +01:00
|
|
|
<para>The goal with this article is to give users an idea of how Cppcheck
|
|
|
|
works.</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
2010-12-29 18:03:57 +01:00
|
|
|
<para>Cppcheck is a static analysis tool that tries to completely avoid
|
|
|
|
false warnings. A false warning is when the tool reports that there is an
|
|
|
|
error even though there is no error.</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
2010-12-29 18:03:57 +01:00
|
|
|
<para>Cppcheck is a relatively simple tool. I hope that this article will
|
2010-12-30 10:17:17 +01:00
|
|
|
highlight that it is possible to avoid false warnings even with simple
|
2010-12-29 18:03:57 +01:00
|
|
|
analysis.</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
</section>
|
|
|
|
|
|
|
|
<section>
|
|
|
|
<title>Limitations of static analysis</title>
|
|
|
|
|
2010-12-28 19:47:56 +01:00
|
|
|
<para>There are many bugs in programs that are really hard to detect for
|
|
|
|
tools. Here is an example:</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
2010-12-30 10:17:17 +01:00
|
|
|
<programlisting> // calculate the number of days
|
|
|
|
int days = hours / 23;</programlisting>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
2010-12-28 19:47:56 +01:00
|
|
|
<para>A human programmer knows that there are 24 hours in a day and
|
|
|
|
therefore he could see that "23" is wrong. A tool will probably not know
|
2010-12-28 17:41:56 +01:00
|
|
|
that there are 24 hours in a day.</para>
|
|
|
|
|
2010-12-29 18:03:57 +01:00
|
|
|
<para>A tool that tries to detect all bugs could write a warning message
|
|
|
|
for every calculation in the program. Then it will correctly report that
|
|
|
|
"hours / 23" is wrong but incorrectly warn about "hours / 24".</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
|
|
|
<para>Cppcheck will only write a warning message if it can determine that
|
2010-12-28 19:47:56 +01:00
|
|
|
the calculation is wrong. In this case, no error will be written.</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
</section>
|
|
|
|
|
2010-12-29 18:03:57 +01:00
|
|
|
<section>
|
|
|
|
<title>Control flow analysis</title>
|
|
|
|
|
|
|
|
<para>When you review code you will probably use "control flow analysis"
|
|
|
|
in your head to determine if there are bugs or not.</para>
|
|
|
|
|
2010-12-30 10:17:17 +01:00
|
|
|
<para>Control flow analysis is when you try to determine what the possible
|
|
|
|
execution paths are.</para>
|
|
|
|
|
2010-12-29 18:03:57 +01:00
|
|
|
<para>The control flow analysis in Cppcheck is quite simple.</para>
|
|
|
|
</section>
|
|
|
|
|
2010-12-28 17:41:56 +01:00
|
|
|
<section>
|
|
|
|
<title>Buffer overflows</title>
|
|
|
|
|
2010-12-28 19:47:56 +01:00
|
|
|
<para>This is a simple description of how buffer overflows are detected by
|
2010-12-28 17:41:56 +01:00
|
|
|
Cppcheck.</para>
|
|
|
|
|
2010-12-30 10:17:17 +01:00
|
|
|
<para>If an array is accessed out of bounds somewhere in its scope then an
|
|
|
|
error message will be written. An example code:</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
|
|
|
<programlisting>void f()
|
|
|
|
{
|
|
|
|
char a[10];
|
|
|
|
if (x + y == 2) {
|
|
|
|
a[20] = 0;
|
|
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
|
|
|
|
<para>Cppcheck will report this message:</para>
|
|
|
|
|
|
|
|
<programlisting>Array 'a[10]' index 20 out of bounds</programlisting>
|
|
|
|
|
2010-12-30 10:17:17 +01:00
|
|
|
<para>No control flow analysis is used. 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.</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
|
|
|
<para>Cppcheck will also investigate function calls. But then control flow
|
2010-12-30 10:17:17 +01:00
|
|
|
analysis can be needed to avoid false warnings. Here is an example that
|
2010-12-28 19:47:56 +01:00
|
|
|
logically is the same as the previous example:</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
|
|
|
<para><programlisting>void f1(char *s)
|
|
|
|
{
|
|
|
|
s[20] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void f2()
|
|
|
|
{
|
|
|
|
char a[10];
|
|
|
|
if (x + y == 2) {
|
|
|
|
f1(a);
|
|
|
|
}
|
|
|
|
}</programlisting>Cppcheck will report this message:</para>
|
|
|
|
|
|
|
|
<programlisting>Array 'a[10]' index 20 out of bounds</programlisting>
|
|
|
|
|
|
|
|
<para>If the execution reaches the function call then there will be an
|
|
|
|
error.</para>
|
|
|
|
|
|
|
|
<para>But if the condition is moved into "f1" then it will be necessary to
|
2010-12-30 10:17:17 +01:00
|
|
|
prove that "x+y==2" can be true when the function is called from "f2". No
|
|
|
|
error message is reported for this code:</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
|
|
|
<para><programlisting>void f1(char *s)
|
|
|
|
{
|
|
|
|
if (x + y == 2) {
|
|
|
|
s[20] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void f2()
|
|
|
|
{
|
|
|
|
char a[10];
|
2010-12-28 19:47:56 +01:00
|
|
|
f1(a);
|
2010-12-28 17:41:56 +01:00
|
|
|
}</programlisting></para>
|
|
|
|
</section>
|
|
|
|
|
|
|
|
<section>
|
|
|
|
<title>Memory leaks</title>
|
|
|
|
|
2010-12-30 10:17:17 +01:00
|
|
|
<para>The check uses simple control-flow analysis. The control flow
|
|
|
|
analysis assumes that all conditions can always be either true or false.
|
|
|
|
It is assumed that all statements are reachable. Here is an
|
|
|
|
example:</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
|
|
|
<programlisting>void f()
|
|
|
|
{
|
|
|
|
char *a = malloc(10);
|
|
|
|
if (x + y == 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
free(a);
|
|
|
|
}</programlisting>
|
|
|
|
|
|
|
|
<para>Cppcheck will determine that there is a leak at the "return;"
|
|
|
|
statement:</para>
|
|
|
|
|
|
|
|
<programlisting>Memory leak: a</programlisting>
|
|
|
|
|
|
|
|
<para>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.</para>
|
|
|
|
|
2010-12-28 19:47:56 +01:00
|
|
|
<para>Lack of advanced control-flow analysis means that many bugs are not
|
|
|
|
detected:</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
|
|
|
<programlisting>void f(int x)
|
|
|
|
{
|
|
|
|
char *a = 0;
|
|
|
|
|
|
|
|
if (x == 10)
|
|
|
|
a = malloc(10);
|
|
|
|
|
|
|
|
if (x == 20)
|
|
|
|
free(a);
|
|
|
|
}</programlisting>
|
|
|
|
|
2010-12-28 19:47:56 +01:00
|
|
|
<para>Cppcheck doesn't detect any error. The "all conditions can be either
|
2010-12-30 10:17:17 +01:00
|
|
|
true/false" means that cppcheck doesn't know that "if (x==20)" is always
|
|
|
|
false when "if (x==10)" is true. So Cppcheck can't establish that there is
|
|
|
|
a leak. Many other static analysis tools will probably detect that there
|
|
|
|
will be a leak if x is 10.</para>
|
2010-12-28 19:47:56 +01:00
|
|
|
</section>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
2010-12-28 19:47:56 +01:00
|
|
|
<section>
|
|
|
|
<title>Final thoughts</title>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
2010-12-28 19:47:56 +01:00
|
|
|
<para>You can not trust that Cppcheck will detect all bugs.</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
|
2010-12-28 19:47:56 +01:00
|
|
|
<para>Cppcheck will just find some bugs. It is likely that you won't find
|
2010-12-30 10:17:17 +01:00
|
|
|
these bugs unless you use Cppcheck.</para>
|
2010-12-28 17:41:56 +01:00
|
|
|
</section>
|
2011-06-27 23:36:23 +02:00
|
|
|
</appendix>
|