Writing Cppcheck rules
Part 3 - Introduction to writing rules with C++
DanielMarjamäki
Cppcheck
2011
Introduction
The goal for this article is to introduce how
Cppcheck rules are written with C++. With C++ it is
possible to write more complex rules than is possible with regular
expressions.
Basics
A C++ rule is written in a C++ function.
Rules are organized into Check classes. For instance there is a
class with the name CheckStl that contains various stl
rules. The CheckOther can always be used if no other
class suits you.
When you have added your rule you must recompile Cppcheck before you
can test it.
Division by zero
This simple regular expression will check for division by
zero:
cppcheck --rule="/ 0"
Here is the corresponding C++ check:
// Detect division by zero
void CheckOther::divisionByZero()
{
// Loop through all tokens
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{
// check if there is a division by zero
if (Token::Match(tok, "/ 0"))
{
// report error
divisionByZeroError(tok);
}
}
}
// Report error
void CheckOther::divisionByZeroError()
{
reportError(tok, Severity::error, "divisionByZero", "Division by zero");
}
The Token::Match matches tokens against
expressions. A few rules about Token::Match expressions are:
tokens are either completely matched or not matched at all. The
token "abc" is not matched by "ab".
Spaces are used as separators.
With normal regular expressions there are special meanings for +
* ? ( ). These are just normal characters in
Token::Match patterns.
Condition before deallocation
In the first Writing rules article I described a
rule that looks for redundant conditions. Here is the regular expression
that was shown:
if \( p \) { free \( p \) ; }
The corresponding Token::Match expression
is:
if ( %var% ) { free ( %var% ) ; }
Any variable name is matched by %var%.
Here is a C++ function:
// Find redundant condition before deallocation
void CheckOther::dealloc()
{
// Loop through all tokens
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{
// Is there a condition and a deallocation?
if (Token::Match(tok, "if ( %var% ) { free ( %var% ) ; }"))
{
// Get variable name used in condition:
const std::string varname1 = tok->strAt(2);
// Get variable name used in deallocation:
const std::string varname2 = tok->strAt(7);
// Is the same variable used?
if (varname1 == varname2)
{
// report warning
deallocWarning(tok);
}
}
}
}
// Report warning
void CheckOther::deallocWarning()
{
reportError(tok, Severity::warning, "dealloc", "Redundant condition before deallocation");
}
The strAt function is used to fetch strings from the token list. The
parameter specifies the token offset.