Writing Cppcheck rules Daniel Marjamäki Cppcheck 2010
Introduction This is a short guide for developers who want to write Cppcheck rules. There are two ways to write rules. Regular expressions Simple rules can be created by using regular expressions. No compilation is required. C++ Advanced rules must be created with C++. These rules must be compiled and linked statically with Cppcheck. 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.
Data representation of the source code The data used by the rules are not the raw source code. Cppcheck will read the source code and process it before the rules are used. 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. Between each token in the code there is always a space. For instance the raw code "1+f()" is processed into "1 + f ( )". The code is simplified in many ways. For example: The templates are instantiated The typedefs are handled There is no "else if". These are converted into "else { if.." The bodies of "if", "else", "while", "do" and "for" are always enclosed in "{" and "}" A declaration of multiple variables is split up into multiple variable declarations. "int a,b;" => "int a; int b;" There is no sizeof NULL is replaced with 0 Static value flow analysis is made. Known values are inserted into the code. .. and many more The simplifications are made in the Cppcheck Tokenizer. For more information see: http://cppcheck.sourceforge.net/doxyoutput/classTokenizer.html
Regular expressions Simple rules can be defined through regular expressions.
Creating regular expression Let's create a regular expression that checks for: if (p) free(p); The condition is often redundant, it is valid to free a NULL pointer. It is important to write the regular expression so it matches the simplified code. Create a source file that has the bad code: void f() { if (p) free(p); } I intentionally put the whole pattern on a single line. The simplified code is written on a single line of code. To see the simplified code I use cppcheck --debug file.cpp. ##file dealloc.cpp 1: void f ( ) { 2: if ( p ) { free ( p ) ; } 3: } I save that in a file test.txt. Now we can use grep to develop a regular expression. grep "if [(] p [)] { free [(] p [)] ; }" test.txt Feel free to improve the pattern.
Create rule file A rule consist of: a pattern to search for. an optional error message that is reported when pattern is found Here is a simple example: <?xml version="1.0"?> <rule version="1"> <pattern>if [(] p [)] { free [(] p [)] ; }</pattern> <message> <id>redundantCondition</id> <severity>style</severity> <summary>Redundant condition. It is valid to free a NULL pointer.</summary> </message> </rule> The message, id, severity and summary elements are optional. If they are not written default values are used. Now you can test this rule. Use the cppcheck --rule-file=dealloc.rule test.cpp command.