205 lines
5.5 KiB
Plaintext
205 lines
5.5 KiB
Plaintext
|
<?xml version="1.0" encoding="UTF-8"?>
|
||
|
<article version="5.0" xmlns="http://docbook.org/ns/docbook"
|
||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||
|
xmlns:m="http://www.w3.org/1998/Math/MathML"
|
||
|
xmlns:html="http://www.w3.org/1999/xhtml"
|
||
|
xmlns:db="http://docbook.org/ns/docbook">
|
||
|
<info>
|
||
|
<title>Cppcheck Design Overview</title>
|
||
|
|
||
|
<author>
|
||
|
<personname><firstname>Daniel</firstname><surname>Marjamäki</surname></personname>
|
||
|
|
||
|
<affiliation>
|
||
|
<orgname>Cppcheck</orgname>
|
||
|
</affiliation>
|
||
|
</author>
|
||
|
|
||
|
<pubdate>2010</pubdate>
|
||
|
</info>
|
||
|
|
||
|
<section>
|
||
|
<title>Introduction</title>
|
||
|
|
||
|
<para>This article is an overview of the design of Cppcheck.</para>
|
||
|
|
||
|
<para>The design of Cppcheck are based on:</para>
|
||
|
|
||
|
<itemizedlist>
|
||
|
<listitem>
|
||
|
<para>Cppcheck will never be perfectly clever</para>
|
||
|
</listitem>
|
||
|
|
||
|
<listitem>
|
||
|
<para>No false warnings are allowed</para>
|
||
|
</listitem>
|
||
|
</itemizedlist>
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Limitations of static analysis</title>
|
||
|
|
||
|
<para>It is not very reasonable to think that a static analysis tool will
|
||
|
detect all bugs in your code.</para>
|
||
|
|
||
|
<para>There are many bugs in programs that is really hard to detect for
|
||
|
tools.</para>
|
||
|
|
||
|
<para>Many bugs are caused by wrong calculations. Here is an
|
||
|
example:</para>
|
||
|
|
||
|
<programlisting>// calculate number of days
|
||
|
int days(int hours)
|
||
|
{
|
||
|
return hours / 23;
|
||
|
}</programlisting>
|
||
|
|
||
|
<para>A human programmer can see the error in that code because he knows
|
||
|
that there are 24 hours in a day.</para>
|
||
|
|
||
|
<para>Tools will probably not know that there are 24 hours in a
|
||
|
day.</para>
|
||
|
|
||
|
<para>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.</para>
|
||
|
|
||
|
<para>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.</para>
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Buffer overflows</title>
|
||
|
|
||
|
<para>This is a simple description of the buffer overflows checking in
|
||
|
Cppcheck.</para>
|
||
|
|
||
|
<para>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.</para>
|
||
|
|
||
|
<para>An example code:</para>
|
||
|
|
||
|
<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>
|
||
|
|
||
|
<para>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>
|
||
|
|
||
|
<para>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:</para>
|
||
|
|
||
|
<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
|
||
|
prove that "x+y==2" can be true when the function is called from
|
||
|
"f2".</para>
|
||
|
|
||
|
<para>No error message is reported for this code:</para>
|
||
|
|
||
|
<para><programlisting>void f1(char *s)
|
||
|
{
|
||
|
if (x + y == 2) {
|
||
|
s[20] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void f2()
|
||
|
{
|
||
|
char a[10];
|
||
|
f1();
|
||
|
}</programlisting></para>
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Memory leaks</title>
|
||
|
|
||
|
<para>Simple control-flow analysis is made. The assumtion is that all
|
||
|
conditions can always be either true or false.</para>
|
||
|
|
||
|
<para>It is assumed that all statements are reachable.</para>
|
||
|
|
||
|
<para>Here is an example:</para>
|
||
|
|
||
|
<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>
|
||
|
|
||
|
<para>This lack of advanced control-flow analysis means that many bugs are
|
||
|
not detected:</para>
|
||
|
|
||
|
<programlisting>void f(int x)
|
||
|
{
|
||
|
char *a = 0;
|
||
|
|
||
|
if (x == 10)
|
||
|
a = malloc(10);
|
||
|
|
||
|
if (x == 20)
|
||
|
free(a);
|
||
|
}</programlisting>
|
||
|
|
||
|
<para>Many other static analysis tools will probably detect that.</para>
|
||
|
|
||
|
<para>Many memory leaks are caused by:</para>
|
||
|
|
||
|
<itemizedlist>
|
||
|
<listitem>
|
||
|
<para>Completely forgetting to deallocate</para>
|
||
|
</listitem>
|
||
|
|
||
|
<listitem>
|
||
|
<para>Forgetting to deallocate in a bailout path</para>
|
||
|
</listitem>
|
||
|
</itemizedlist>
|
||
|
|
||
|
<para>These types of leaks should be detected by Cppcheck.</para>
|
||
|
</section>
|
||
|
</article>
|