2010-12-04 09:18:57 +01:00
|
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
|
|
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
|
|
|
<article>
|
|
|
|
<articleinfo>
|
|
|
|
<title>Writing Cppcheck rules</title>
|
|
|
|
|
|
|
|
<author>
|
|
|
|
<firstname>Daniel</firstname>
|
|
|
|
|
|
|
|
<surname>Marjamäki</surname>
|
|
|
|
|
|
|
|
<affiliation>
|
|
|
|
<orgname>Cppcheck</orgname>
|
|
|
|
</affiliation>
|
|
|
|
</author>
|
|
|
|
|
|
|
|
<pubdate>2010</pubdate>
|
|
|
|
</articleinfo>
|
|
|
|
|
|
|
|
<section>
|
|
|
|
<title>Introduction</title>
|
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<para>This is a short guide for developers who want to write Cppcheck
|
|
|
|
rules.</para>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
|
|
|
<para>There are two ways to write rules.</para>
|
|
|
|
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry>
|
|
|
|
<term>Regular expressions</term>
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
<para>Simple rules can be created by using regular expressions. No
|
|
|
|
compilation is required.</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
|
|
|
|
<varlistentry>
|
|
|
|
<term>C++</term>
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
<para>Advanced rules must be created with C++. These rules must be
|
|
|
|
compiled and linked statically with Cppcheck.</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<para>It is a good first step to use regular expressions. It is easier.
|
|
|
|
You'll get results quicker. Therefore this guide will focus on regular
|
|
|
|
expressions.</para>
|
2010-12-04 09:18:57 +01:00
|
|
|
</section>
|
|
|
|
|
|
|
|
<section>
|
|
|
|
<title>Data representation of the source code</title>
|
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<para>The data used by the rules are not the raw source code.
|
|
|
|
<literal>Cppcheck</literal> will read the source code and process it
|
|
|
|
before the rules are used.</para>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<para>Cppcheck is designed to find bugs and dangerous code. Stylistic
|
|
|
|
information such as indentation, comments, etc are filtered out at an
|
|
|
|
early state. You don't need to worry about such stylistic information when
|
|
|
|
you write rules.</para>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<para>Between each token in the code there is always a space. For instance
|
|
|
|
the raw code "1+f()" is processed into "1 + f ( )".</para>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<para>The code is simplified in many ways. For example:</para>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para>The templates are instantiated</para>
|
|
|
|
</listitem>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<listitem>
|
|
|
|
<para>The typedefs are handled</para>
|
|
|
|
</listitem>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<listitem>
|
|
|
|
<para>There is no "else if". These are converted into "else {
|
|
|
|
if.."</para>
|
|
|
|
</listitem>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<listitem>
|
|
|
|
<para>The bodies of "if", "else", "while", "do" and "for" are always
|
|
|
|
enclosed in "{" and "}"</para>
|
|
|
|
</listitem>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<listitem>
|
|
|
|
<para>A declaration of multiple variables is split up into multiple
|
|
|
|
variable declarations. "int a,b;" => "int a; int b;"</para>
|
|
|
|
</listitem>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<listitem>
|
|
|
|
<para>There is no sizeof</para>
|
|
|
|
</listitem>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<listitem>
|
|
|
|
<para>NULL is replaced with 0</para>
|
|
|
|
</listitem>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<listitem>
|
|
|
|
<para>Static value flow analysis is made. Known values are inserted
|
|
|
|
into the code.</para>
|
|
|
|
</listitem>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<listitem>
|
|
|
|
<para>.. and many more</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-04 20:01:55 +01:00
|
|
|
<para>The simplifications are made in the <literal>Cppcheck</literal>
|
|
|
|
<literal>Tokenizer</literal>. For more information see:
|
|
|
|
<uri>http://cppcheck.sourceforge.net/doxyoutput/classTokenizer.html</uri></para>
|
2010-12-04 09:18:57 +01:00
|
|
|
</section>
|
|
|
|
|
|
|
|
<section>
|
|
|
|
<title>Regular expressions</title>
|
|
|
|
|
2010-12-05 13:19:30 +01:00
|
|
|
<para>Simple rules can be defined through regular expressions. Cppcheck
|
|
|
|
uses PCRE to handle regular expressions.</para>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-05 09:36:13 +01:00
|
|
|
<section>
|
|
|
|
<title>Creating regular expression</title>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-05 09:36:13 +01:00
|
|
|
<para>Let's create a regular expression that checks for:</para>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-05 09:36:13 +01:00
|
|
|
<programlisting>if (p)
|
|
|
|
free(p);</programlisting>
|
|
|
|
|
2010-12-05 13:19:30 +01:00
|
|
|
<para>The condition is often redundant, on most implementations it is
|
|
|
|
valid to free a NULL pointer.</para>
|
2010-12-05 09:36:13 +01:00
|
|
|
|
2010-12-05 13:19:30 +01:00
|
|
|
<para>The regular expression must match the simplified code. Create a
|
|
|
|
source file that has the bad code:</para>
|
2010-12-05 09:36:13 +01:00
|
|
|
|
|
|
|
<programlisting>void f() {
|
2010-12-05 13:19:30 +01:00
|
|
|
if (p)
|
|
|
|
free(p);
|
2010-12-05 09:36:13 +01:00
|
|
|
}</programlisting>
|
|
|
|
|
2010-12-05 13:19:30 +01:00
|
|
|
<para>To see the simplified code use <literal>cppcheck --debug
|
|
|
|
dealloc.cpp</literal>.</para>
|
2010-12-05 09:36:13 +01:00
|
|
|
|
|
|
|
<programlisting>##file dealloc.cpp
|
|
|
|
1: void f ( ) {
|
2010-12-05 13:19:30 +01:00
|
|
|
2: if ( p ) {
|
|
|
|
3: free ( p ) ; }
|
|
|
|
4: }</programlisting>
|
|
|
|
|
|
|
|
<para>In the <literal>--debug</literal> output there are line feeds and
|
|
|
|
line numbers. But the newlines and line numbers are only there to make
|
|
|
|
the output easier to read. The real simplified code is written on a
|
|
|
|
single line:</para>
|
2010-12-05 09:36:13 +01:00
|
|
|
|
2010-12-05 13:19:30 +01:00
|
|
|
<programlisting>void f ( ) { if ( p ) { free ( p ) ; } }</programlisting>
|
2010-12-05 09:36:13 +01:00
|
|
|
|
2010-12-05 13:19:30 +01:00
|
|
|
<para>Now we can use <literal>cppcheck --rule</literal> to develop a
|
|
|
|
regular expression.</para>
|
2010-12-05 09:36:13 +01:00
|
|
|
|
2010-12-05 13:19:30 +01:00
|
|
|
<programlisting>$ cppcheck --rule="if \( p \) { free \( p \) ; }" dealloc.cpp
|
|
|
|
Checking dealloc.cpp...
|
|
|
|
[dealloc.cpp:2]: (style) found 'if ( p ) { free ( p ) ; }'</programlisting>
|
2010-12-05 09:36:13 +01:00
|
|
|
|
2010-12-05 13:19:30 +01:00
|
|
|
<para>Feel free to improve the pattern. Above, the pointer name must be
|
|
|
|
"p" to get a match.</para>
|
2010-12-05 09:36:13 +01:00
|
|
|
</section>
|
|
|
|
|
|
|
|
<section>
|
|
|
|
<title>Create rule file</title>
|
|
|
|
|
|
|
|
<para>A rule consist of:</para>
|
|
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para>a pattern to search for.</para>
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
<listitem>
|
2010-12-05 13:19:30 +01:00
|
|
|
<para>an error message that is reported when pattern is found - this
|
|
|
|
is optional, if none is given a default message is written.</para>
|
2010-12-05 09:36:13 +01:00
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-05 09:36:13 +01:00
|
|
|
<para>Here is a simple example:</para>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-05 09:36:13 +01:00
|
|
|
<programlisting><?xml version="1.0"?>
|
2010-12-04 20:01:55 +01:00
|
|
|
<rule version="1">
|
2010-12-05 13:19:30 +01:00
|
|
|
<pattern>if \( p \) { free \( p \) ; }</pattern>
|
2010-12-04 09:18:57 +01:00
|
|
|
<message>
|
2010-12-05 09:36:13 +01:00
|
|
|
<id>redundantCondition</id>
|
|
|
|
<severity>style</severity>
|
|
|
|
<summary>Redundant condition. It is valid to free a NULL pointer.</summary>
|
2010-12-04 09:18:57 +01:00
|
|
|
</message>
|
|
|
|
</rule></programlisting>
|
|
|
|
|
2010-12-05 09:36:13 +01:00
|
|
|
<para>The <literal>message</literal>, <literal>id</literal>,
|
|
|
|
<literal>severity</literal> and <literal>summary</literal> elements are
|
2010-12-05 13:19:30 +01:00
|
|
|
optional. But highly recommended.</para>
|
|
|
|
|
|
|
|
<para>If you save that xml data in <literal>dealloc.rule</literal> you
|
|
|
|
can test this rule:</para>
|
2010-12-04 09:18:57 +01:00
|
|
|
|
2010-12-05 13:19:30 +01:00
|
|
|
<programlisting>$ cppcheck --rule-file=dealloc.rule dealloc.cpp
|
|
|
|
Checking dealloc.cpp...
|
|
|
|
[dealloc.cpp:2]: (style) Redundant condition. It is valid to free a NULL pointer.</programlisting>
|
2010-12-05 09:36:13 +01:00
|
|
|
</section>
|
2010-12-04 09:18:57 +01:00
|
|
|
</section>
|
|
|
|
</article>
|