manual: Improved chapter about library configurations
This commit is contained in:
parent
d2493fa3cb
commit
56ff1269d4
|
@ -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><?xml version="1.0"?>
|
<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><?xml version="1.0"?>
|
||||||
<def>
|
<def>
|
||||||
</def></programlisting>
|
|
||||||
|
|
||||||
<para>This configuration file is filled up with various options:</para>
|
|
||||||
|
|
||||||
<programlisting><?xml version="1.0"?>
|
|
||||||
<def>
|
|
||||||
<memory>
|
|
||||||
<alloc>CreateFred</alloc>
|
|
||||||
<dealloc>CloseFred</dealloc>
|
|
||||||
|
|
||||||
<use>AppendFred</use>
|
|
||||||
</memory>
|
|
||||||
|
|
||||||
<memory>
|
|
||||||
<alloc init="false">AllocWilma</alloc>
|
|
||||||
<alloc init="true">CAllocWilma</alloc>
|
|
||||||
<dealloc>CloseWilma</dealloc>
|
|
||||||
</memory>
|
|
||||||
|
|
||||||
<resource>
|
<resource>
|
||||||
<alloc>Lock</alloc>
|
<alloc>CreatePen</alloc>
|
||||||
<dealloc>Unlock</dealloc>
|
<dealloc>DeleteObject</dealloc>
|
||||||
</resource>
|
</resource>
|
||||||
|
</def></programlisting>
|
||||||
|
</section>
|
||||||
|
|
||||||
<function name="IsEqual">
|
<section>
|
||||||
<leak-ignore/>
|
<title>Uninitialized memory</title>
|
||||||
</function>
|
|
||||||
|
|
||||||
<function name="AssignFred">
|
<para>Here is an example program:</para>
|
||||||
<noreturn>false</noreturn>
|
|
||||||
<arg nr="1">
|
<programlisting>void test()
|
||||||
<not-null/>
|
{
|
||||||
</arg>
|
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><?xml version="1.0"?>
|
||||||
|
<def>
|
||||||
|
<function name="CopyMemory">
|
||||||
<arg nr="2">
|
<arg nr="2">
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
<arg nr="3">
|
</function>
|
||||||
<strz/>
|
</def></programlisting></para>
|
||||||
</arg>
|
</section>
|
||||||
<arg nr="4">
|
|
||||||
<formatstr/>
|
<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><?xml version="1.0"?>
|
||||||
|
<def>
|
||||||
|
<function name="CopyMemory">
|
||||||
|
<arg nr="1">
|
||||||
|
<not-null/>
|
||||||
</arg>
|
</arg>
|
||||||
</function>
|
</function>
|
||||||
</def></programlisting>
|
</def></programlisting>
|
||||||
|
</section>
|
||||||
<para>In the <literal><memory></literal> and
|
|
||||||
<literal><resource></literal> the allocation and deallocation
|
|
||||||
functions are configured. Putting allocation and deallocation functions in
|
|
||||||
different <literal><memory></literal> and
|
|
||||||
<literal><resource></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><use></literal> and
|
|
||||||
<literal><leak-ignore></literal> elements are used to control the
|
|
||||||
leaks checking. If it should be ignored that a function is called, use
|
|
||||||
<literal><leak-ignore></literal>. If there is no leak whenever the
|
|
||||||
memory is passed to a function, use <literal><use></literal>.</para>
|
|
||||||
|
|
||||||
<para>In the <literal><function></literal> block some useful info is
|
|
||||||
added about function behaviour. The <literal><noreturn></literal>
|
|
||||||
tells <literal>Cppcheck</literal> if the function is a no return function.
|
|
||||||
The <literal><arg></literal> is used to validate arguments. If it's
|
|
||||||
invalid to pass NULL, use <literal><not-null></literal>. If it's
|
|
||||||
invalid to pass uninitialized data, use
|
|
||||||
<literal><not-uninit></literal>. If the argument is a
|
|
||||||
zero-terminated string, use <literal><strz></literal>. If the
|
|
||||||
argument is a formatstring, use
|
|
||||||
<literal><formatstr></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; // <- 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 <noreturn> 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><?xml version="1.0"?>
|
||||||
|
<def>
|
||||||
|
<function name="ZeroMemory">
|
||||||
|
<noreturn>false</noreturn>
|
||||||
|
</function>
|
||||||
|
</def></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...
|
||||||
</arg>
|
</arg>
|
||||||
</function></programlisting>
|
</function></programlisting>
|
||||||
|
|
||||||
<para>The <literal><leak-ignore/></literal> is optional and it
|
<para>The <literal><leak-ignore/></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><noreturn></literal> is optional. But it's
|
<para>The <literal><noreturn></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><not-null></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><not-null></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
|
||||||
|
|
Loading…
Reference in New Issue