Cppcheck is an open-source static analysis tool for C++. In this post I'm going to describe how to install and run Cppcheck over your C++ code base.
Static Analysis
Static analysis is the analysis of code without executing it. It can be used to find common programming errors and enforce coding guidelines. Some common benefits of static analysis include:
- Prevent unexpected / undefined behaviour.
- Find security vulnerabilities and make code more secure.
- Make code more maintainable by enforcing coding standards.
The very first static analysis tool that programmers use is their compiler. In my previous blog posts, I've discussed how using multiple compilers can help catch errors and prevent undefined behaviour. Using multiple compilers is a great first step in detecting issues, however, dedicated static analysis tools can help to prevent more errors as they can look at more detailed and complex code paths to analyse issues.
Cppcheck
Cppcheck is a standalone static analysis tool that can perform the following checks:
- Undefined Behaviour
- Dead pointers
- Integer Overflow
- Null pointer dereferences
- Out of bounds checking
- Security checking including some common CVE errors
- Coding Standards
It is integrated into may common CI systems, IDEs and programming environments to allow it to be easily run over different code bases.
Installing
On Linux, most common package managers include a version of Cppcheck, however, this version is often older and out of date. As a result I recommended to install the latest version which can be found from the Cppcheck website.
For windows a binary installer is available.
For other platforms, it is easy to build the latest version from source. The only requirements are CMake and a C++11 compatible compiler. To build and install v1.85 (the latest at time or writing), you can run:
12345678$ wget https:
/
/
github.com
/
danmar
/
cppcheck
/
archive
/
1.85
.tar.gz
$ tar xvf
1.85
.tar.gz
$ cd cppcheck
-
1.85
$ mkdir build
$ cd build
$ cmake ..
$ make
$ sudo make install
You should then have cppcheck
available in your path:
12$ cppcheck
-
-
version
Cppcheck
1.85
Basic Usage
Single File
To run Cppcheck against a single cpp file you can run cppcheck filename.cpp
. For a simple example, take the following file.
12345678#include <array>
int
main() {
const
int
ex_sz
=
5
;
std::array<
int
, ex_sz> ex;
ex[ex_sz]
=
1
;
return
1
;
}
Under GCC and Clang this compiles without any warnings using -Wall
. However, with Cppcheck I see:
123$ cppcheck test.cpp
Checking test.cpp ...
[test.cpp:
6
]: (error) Array
'ex[5]'
accessed at index
5
, which
is
out of bounds.
This simple tests shows us how using Cppcheck as a static analysis tool can save us from an out of bounds error.
Header Files
If you have header files, you can use the -I
flag to tell cppcheck where to search for them.
1cppcheck
-
I inc
/
with_header.cpp
Recursive Checks
To recursively check all cpp files in a folder you can pass the folder name to Cppcheck.
1cppcheck
-
I inc
/
src
/
Enabling Checks
As mentioned, Cppcheck has a number of different checks available. You can enable or disable checks by using the --enable
flag.
1234567891011121314151617181920212223242526-
-
enable
=
<
id
> Enable additional checks. The available ids are:
*
all
Enable
all
checks. It
is
recommended to only
use
-
-
enable
=
all
when the whole program
is
scanned, because this enables unusedFunction.
*
warning
Enable warning messages
*
style
Enable
all
coding style checks.
All
messages
with the severities
'style'
,
'performance'
and
'portability'
are enabled.
*
performance
Enable performance messages
*
portability
Enable portability messages
*
information
Enable information messages
*
unusedFunction
Check
for
unused functions. It
is
recommend
to only enable this when the whole program
is
scanned.
*
missingInclude
Warn
if
there are missing includes. For
detailed information, use
'--check-config'
.
Several ids can be given
if
you separate them with
commas. See also
-
-
std
Usage for an existing project
As you can see from the above you have to pass details about your source code to Cppcheck in order for it to understand what files to analyse, how to find dependencies, and what compiler flags to use. The easiest way to do this is to use a compilation database.
If you are using CMake you can create a compilation database using the -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
flag, or by adding the following to your root CMakeLists.txt
.
1set
(CMAKE_EXPORT_COMPILE_COMMANDS ON)
After running CMake with this enabled a file compile_commands.json
will be created. This will look like:
123456789101112131415[
{
"directory"
:
"/home/user/development/project"
,
"command"
:
"/usr/bin/c++ -Iinc -std=c+11 ... -c ../foo/foo.cc"
,
"file"
:
"../foo/foo.cc"
},
...
{
"directory"
:
"/home/user/development/project"
,
"command"
:
"/usr/bin/c++ -Iinc -std=c+11 ... -c ../foo/bar.cc"
,
"file"
:
"../foo/bar.cc"
}
]
Once you have the compilation database available, you can then run Cppcheck as:
1cppcheck
-
-
enable
=
all
-
-
project
=
compile_commands.json
Conclusions
This post showed how to install and run Cppcheck over your project. It also showed a simple example of how using static analysis can help you to detect errors. In future posts, I hope to show more advanced features of Cppcheck and also some common errors that it can help detect.
No comments:
Post a Comment