manual: Improved chapter about library configurations

This commit is contained in:
Daniel Marjamäki 2013-12-12 19:49:39 +01:00
parent d2493fa3cb
commit 56ff1269d4
1 changed files with 157 additions and 92 deletions

View File

@ -704,107 +704,176 @@ Checking test.c...
<chapter> <chapter>
<title>Library configuration</title> <title>Library configuration</title>
<para><literal>Cppcheck</literal> has internal knowledge about how <para>When external libraries are used, such as windows/posix/gtk/qt/etc,
standard C/C++ functions work. There is no internal knowledge about how <literal>Cppcheck</literal> doesn't know how the external functions
all libraries and environments work, and there can't be. behave. <literal>Cppcheck</literal> then fails to detect various problems
<literal>Cppcheck</literal> can be told how libraries and environments such as leaks, buffer overflows, possible null pointer dereferences, etc.
work by using configuration files.</para> But this can be fixed with configuration files.</para>
<para>The idea is that users will be able to download library <para>If you create a configuration file for a popular library, we would
configuration files for all popular libraries and environments appreciate if you upload it to us.</para>
here:</para>
<para><uri>http://cppcheck.sourceforge.net/archive</uri></para> <section>
<title>Memory/resource leaks</title>
<para>Ideally, all you need to do is choose and download the configuration <para>Here is an example program:</para>
files you need.</para>
<para>The archive is not complete however. If you can't find the <para><programlisting>void test()
configuration file you need in the archive, you can wait - maybe somebody {
else will write it and share it. Or you can write your own configuration HPEN pen = CreatePen(PS_SOLID, 1, RGB(255,0,0));
file (and then it's possible to share your configuration file with }</programlisting></para>
others).</para>
<para>A minimal configuration file looks like this:</para> <para>The code example above has a resource leak -
<literal>CreatePen()</literal> is a windows function that creates a pen.
However Cppcheck doesn't assume that return values from functions must
be freed. There is no error message:</para>
<programlisting>&lt;?xml version="1.0"?&gt; <programlisting># cppcheck pen1.c
Checking pen1.c...</programlisting>
<para>If you provide a windows configuration file then
<literal>Cppcheck</literal> detects the bug:</para>
<programlisting># cppcheck --library=windows.cfg pen1.c
Checking pen1.c...
[pen1.c:3]: (error) Resource leak: pen</programlisting>
<para>Here is a minimal <literal>windows.cfg</literal> file:</para>
<programlisting>&lt;?xml version="1.0"?&gt;
&lt;def&gt; &lt;def&gt;
&lt;/def&gt;</programlisting>
<para>This configuration file is filled up with various options:</para>
<programlisting>&lt;?xml version="1.0"?&gt;
&lt;def&gt;
&lt;memory&gt;
&lt;alloc&gt;CreateFred&lt;/alloc&gt;
&lt;dealloc&gt;CloseFred&lt;/dealloc&gt;
&lt;use&gt;AppendFred&lt;/use&gt;
&lt;/memory&gt;
&lt;memory&gt;
&lt;alloc init="false"&gt;AllocWilma&lt;/alloc&gt;
&lt;alloc init="true"&gt;CAllocWilma&lt;/alloc&gt;
&lt;dealloc&gt;CloseWilma&lt;/dealloc&gt;
&lt;/memory&gt;
&lt;resource&gt; &lt;resource&gt;
&lt;alloc&gt;Lock&lt;/alloc&gt; &lt;alloc&gt;CreatePen&lt;/alloc&gt;
&lt;dealloc&gt;Unlock&lt;/dealloc&gt; &lt;dealloc&gt;DeleteObject&lt;/dealloc&gt;
&lt;/resource&gt; &lt;/resource&gt;
&lt;/def&gt;</programlisting>
</section>
&lt;function name="IsEqual"&gt; <section>
&lt;leak-ignore/&gt; <title>Uninitialized memory</title>
&lt;/function&gt;
&lt;function name="AssignFred"&gt; <para>Here is an example program:</para>
&lt;noreturn&gt;false&lt;/noreturn&gt;
&lt;arg nr="1"&gt; <programlisting>void test()
&lt;not-null/&gt; {
&lt;/arg&gt; char buffer1[1024];
char buffer2[1024];
CopyMemory(buffer1, buffer2, 1024);
}</programlisting>
<para>The bug here is that buffer2 is uninitialized. The second argument
for CopyMemory needs to be initialized. However
<literal>Cppcheck</literal> assumes that it is fine to pass
uninitialized variables to functions:</para>
<programlisting># cppcheck uninit.c
Checking uninit.c...</programlisting>
<para>If you provide a windows configuration file then Cppcheck detects
the bug:</para>
<programlisting># cppcheck --library=windows.cfg uninit.c
Checking uninit.c...
[uninit.c:5]: (error) Uninitialized variable: buffer2</programlisting>
<para>Here is the minimal <literal>windows.cfg</literal>:</para>
<para><programlisting>&lt;?xml version="1.0"?&gt;
&lt;def&gt;
&lt;function name="CopyMemory"&gt;
&lt;arg nr="2"&gt; &lt;arg nr="2"&gt;
&lt;not-uninit/&gt; &lt;not-uninit/&gt;
&lt;/arg&gt; &lt;/arg&gt;
&lt;arg nr="3"&gt; &lt;/function&gt;
&lt;strz/&gt; &lt;/def&gt;</programlisting></para>
&lt;/arg&gt; </section>
&lt;arg nr="4"&gt;
&lt;formatstr/&gt; <section>
<title>Null pointers</title>
<para>Cppcheck assumes it's ok to pass NULL pointers to functions. Here
is an example program:</para>
<programlisting>void test()
{
CopyMemory(NULL, NULL, 1024);
}</programlisting>
<para>The MSDN documentation is not clear if that is ok or not. But
let's assume it's bad. Cppcheck assumes that it's ok to pass NULL to
functions so no error is reported:</para>
<programlisting># cppcheck null.c
Checking null.c...</programlisting>
<para>If you provide a windows configuration file then
<literal>Cppcheck</literal> detects the bug:</para>
<programlisting>cppcheck --library=windows.cfg null.c
Checking null.c...
[null.c:3]: (error) Null pointer dereference</programlisting>
<para>Here is a minimal <literal>windows.cfg</literal> file:</para>
<programlisting>&lt;?xml version="1.0"?&gt;
&lt;def&gt;
&lt;function name="CopyMemory"&gt;
&lt;arg nr="1"&gt;
&lt;not-null/&gt;
&lt;/arg&gt; &lt;/arg&gt;
&lt;/function&gt; &lt;/function&gt;
&lt;/def&gt;</programlisting> &lt;/def&gt;</programlisting>
</section>
<para>In the <literal>&lt;memory&gt;</literal> and
<literal>&lt;resource&gt;</literal> the allocation and deallocation
functions are configured. Putting allocation and deallocation functions in
different <literal>&lt;memory&gt;</literal> and
<literal>&lt;resource&gt;</literal> blocks means they are mismatching -
you'll get a warning message if you allocate memory with
<literal>CreateFred</literal> and try to close it with
<literal>CloseWilma</literal>.</para>
<para>The <literal>&lt;use&gt;</literal> and
<literal>&lt;leak-ignore&gt;</literal> elements are used to control the
leaks checking. If it should be ignored that a function is called, use
<literal>&lt;leak-ignore&gt;</literal>. If there is no leak whenever the
memory is passed to a function, use <literal>&lt;use&gt;</literal>.</para>
<para>In the <literal>&lt;function&gt;</literal> block some useful info is
added about function behaviour. The <literal>&lt;noreturn&gt;</literal>
tells <literal>Cppcheck</literal> if the function is a no return function.
The <literal>&lt;arg&gt;</literal> is used to validate arguments. If it's
invalid to pass NULL, use <literal>&lt;not-null&gt;</literal>. If it's
invalid to pass uninitialized data, use
<literal>&lt;not-uninit&gt;</literal>. If the argument is a
zero-terminated string, use <literal>&lt;strz&gt;</literal>. If the
argument is a formatstring, use
<literal>&lt;formatstr&gt;</literal>.</para>
<section> <section>
<title>Example: strcpy()</title> <title>noreturn</title>
<para>The strcpy() was chosen in this example for demonstration purposes <para>Cppcheck doesn't assume that functions always return. Here is an
because its behaviour is well-known.</para> example code:</para>
<programlisting>void test(int x)
{
int data, buffer[1024];
if (x == 1)
data = 123;
else
ZeroMemory(buffer, sizeof(buffer));
buffer[0] = data; // &lt;- error: data is uninitialized if x is not 1
}</programlisting>
<para>In theory, if <literal>ZeroMemory</literal> terminates the program
then there is no bug. Cppcheck therefore reports no error:</para>
<programlisting># cppcheck noreturn.c
Checking noreturn.c...</programlisting>
<para>However if you use <literal>--check-library</literal> and
<literal>--enable=information</literal> you'll get this:</para>
<programlisting># cppcheck --check-library --enable=information noreturn.c
Checking noreturn.c...
[noreturn.c:7]: (information) --check-library: Function ZeroMemory() should have &lt;noreturn&gt; configuration
</programlisting>
<para>If a proper <literal>windows.cfg</literal> is provided, the bug is
detected:</para>
<programlisting># cppcheck --library=windows.cfg noreturn.c
Checking noreturn.c...
[noreturn.c:8]: (error) Uninitialized variable: data</programlisting>
<para>Here is a minimal <literal>windows.cfg</literal> file:</para>
<programlisting>&lt;?xml version="1.0"?&gt;
&lt;def&gt;
&lt;function name="ZeroMemory"&gt;
&lt;noreturn&gt;false&lt;/noreturn&gt;
&lt;/function&gt;
&lt;/def&gt;</programlisting>
</section>
<section>
<title>Example configuration for strcpy()</title>
<para>The proper configuration for the standard strcpy() function would <para>The proper configuration for the standard strcpy() function would
be:</para> be:</para>
@ -821,20 +890,16 @@ Checking test.c...
&lt;/arg&gt; &lt;/arg&gt;
&lt;/function&gt;</programlisting> &lt;/function&gt;</programlisting>
<para>The <literal>&lt;leak-ignore/&gt;</literal> is optional and it <para>The <literal>&lt;leak-ignore/&gt;</literal> tells Cppcheck to
tells Cppcheck to ignore this function call in the leaks checking. ignore this function call in the leaks checking. Passing allocated
Passing allocated memory to this function won't mean it will be memory to this function won't mean it will be deallocated.</para>
deallocated.</para>
<para>The <literal>&lt;noreturn&gt;</literal> is optional. But it's <para>The <literal>&lt;noreturn&gt;</literal> tells Cppcheck if this
recommended.</para> function returns or not.</para>
<para>The first argument that the function takes is a pointer. It must <para>The first argument that the function takes is a pointer. It must
not be a null pointer, a uninitialized pointer nor a dead pointer. It not be a null pointer, therefore <literal>&lt;not-null&gt;</literal> is
must point at some data, this data can be initialized but it is not used.</para>
wrong if it isn't. Using <literal>&lt;not-null&gt;</literal> is correct.
<literal>Cppcheck</literal> will check by default that the pointer is
not uninitialized nor dead.</para>
<para>The second argument the function takes is a pointer. It must not <para>The second argument the function takes is a pointer. It must not
be null. And it must point at initialized data. Using be null. And it must point at initialized data. Using