Over the past few months I've been using static code analysis tools such as cppcheck, Coverity Scan and also smatch on various open source projects. I've generally found that most open source code is fairly well written, however, most suffer a common pattern of bugs on the error handling paths. Typically, these are not free'ing up memory or freeing up memory incorrectly. Other frequent bugs are not initialising variables and overly complex code paths that introduce subtle bugs when certain rare conditions are occur. Most of these bugs are small and very rarely hit; some of these just silently do things wrong while others can potentially trigger segmentation faults.
The --force option in cppcheck to force the checking of every build configuration has been very useful in finding code paths that are rarely built, executed or tested and hence are likely to contain bugs.
I'm coming to the conclusion that whenever I have to look at some new code I should take 5 minutes or so throwing it at various static code analysis tools to see what pops out and being a good citizen and fixing these and sending these upstream. It's not too much effort and helps reduce some of those more obscure bugs that rarely bite but do linger around in code.
Friday, 28 February 2014
Friday, 10 January 2014
cppcheck - another very useful static code analysis tool
Over the past months I have been using static code analysis tools such as smatch and Coverity Scan on various open source projects that I am involved with. These, combined with using gcc's -Wall -Wextra have proved useful in tracking down and eliminating various bugs.
Recently I stumbled on cppcheck and gave it a spin on several larger projects. One of the cppcheck project aims is to find errors that the compiler won't spot and also try to keep the number of false positives found to a minimum.
cppcheck is very easy to use, the default settings just work out of the box. However, for extra checking I enabled the --force option to check of all configurations and the --enable=all to report on checks to be totally thorough and pedantic.
The --enable option is especially useful. It allows one to select different types of checking, for example, coding style, execution performance, portability, unused functions and missing include files.
Even though my code has been through smatch and Coverity Scan, cppcheck still managed to find a few issues using --enable=all
1. unused functions
2. a potential memory leak with realloc(), for example:
buf = realloc(buf, new_size);
if (!buf)
return NULL;
if realloc() fails, buf can be leaked. A potential fix is:
tmp = realloc(buf, new_size);
if (!tmp) {
free(buf);
return NULL;
} else
buf = tmp;
3. some potential sscanf buffer overflows
4. some coding style improvements, for example, local auto variables could be moved to a deeper scope
So cppcheck worked well for me. I recommend referring to the cppcheck project wiki to check out the features and then subjecting your code to it and seeing if it can find any bugs.
Recently I stumbled on cppcheck and gave it a spin on several larger projects. One of the cppcheck project aims is to find errors that the compiler won't spot and also try to keep the number of false positives found to a minimum.
cppcheck is very easy to use, the default settings just work out of the box. However, for extra checking I enabled the --force option to check of all configurations and the --enable=all to report on checks to be totally thorough and pedantic.
The --enable option is especially useful. It allows one to select different types of checking, for example, coding style, execution performance, portability, unused functions and missing include files.
Even though my code has been through smatch and Coverity Scan, cppcheck still managed to find a few issues using --enable=all
1. unused functions
2. a potential memory leak with realloc(), for example:
buf = realloc(buf, new_size);
if (!buf)
return NULL;
if realloc() fails, buf can be leaked. A potential fix is:
tmp = realloc(buf, new_size);
if (!tmp) {
free(buf);
return NULL;
} else
buf = tmp;
3. some potential sscanf buffer overflows
4. some coding style improvements, for example, local auto variables could be moved to a deeper scope
So cppcheck worked well for me. I recommend referring to the cppcheck project wiki to check out the features and then subjecting your code to it and seeing if it can find any bugs.
Tuesday, 17 December 2013
Infinite Snowflake
So it's close to the Christmas Holiday season, so I thought I would spend some time writing something seasonal. My daughter, who is rather mathematically minded, was asking me about finding reoccurring digits in reciprocals of primes, for example 1/7, 1/11, 1/13 etc., and somehow this got me looking at the binary digits of Pi, and after a little more browsing around Wikipedia onto the Thue-Morse binary sequence.
The Thue-Morse binary sequence starts with zero and one successively appends to the existing sequence the boolean compliment of the sequence so far. One interesting feature is that a turtle graphics program can be written to control the turtle by feeding it the successive digits from the sequence so that:
The original source code can be found here. It contains a 512 x 512 turtle graphics plotter, a Thue-Morse binary sequence generator and a PPM output backend. Anyway, have fun figuring out how it works (it is only mildly obfuscated) and have a great Christmas!
The Thue-Morse binary sequence starts with zero and one successively appends to the existing sequence the boolean compliment of the sequence so far. One interesting feature is that a turtle graphics program can be written to control the turtle by feeding it the successive digits from the sequence so that:
- A zero moves the cursor forward by a step
- A one turns the cursor anti-clockwise by 60 degress (or pi/3 radians)
#include<stdio.h>
#include <math.h>
#define Q (1<<9)
#define M /**/for
#define E(b,a) {\
J q=1^(X+b)[3+Q*\
a];printf("%c%c%\
c",q,q,q);/*//*/}
int /*/*/ typedef
#define W double
#define z (Q<<5)
J;J X[3+(Q *Q)]
,t[z ] ;J main(
){ W o= Q >>1,V=
o/5, a=0; M (1 [X
]=1; X[1] <z;X
[1 ] *=2) for(
X[2] =0;X [2]<
X[1] ;X[2 ]++,
t[X[ 2]+X [1]]
=1^t [X[2 ]]);
for( 0[X] =0;X
[0]< 3;0[ X]++
)for (X[2] =0;X
[2]< z;X[ 2]++
)if( t[X[ 2]])
a-=( M_PI /3.0
);else{o+= cos(a ); V+=
sin(a);X[3+( int)o+Q*(int)V]|=1;}printf(
"P6 %d %d 1 ",Q,Q);M(1[X] =0;X[1]<Q;X[1]
++)M(2[X]=0;X[ 2]<Q;X[2]++)E(2[X],X[1]);
return 0;} /* Colin Ian King 2013 */
To build and run:gcc koch-binary.c -lm -o koch-binary
./koch-binary | ppmtojpeg > koch-binary.jpg
And the result is a koch-snowflake:The original source code can be found here. It contains a 512 x 512 turtle graphics plotter, a Thue-Morse binary sequence generator and a PPM output backend. Anyway, have fun figuring out how it works (it is only mildly obfuscated) and have a great Christmas!
Sunday, 15 December 2013
Detecting System Management Interrupts
System Management Mode (SMM) is a special operating mode on x86 processors that temporarily jumps from normal execution and executes specialised firmware code in a high privilege before returning back. SMM is entered via the System Management Interrupt (SMI) and is intented to work transparently to the operating system.
For example, SMM can be used to handle shutdown if CPU temperature is too high, perform transparent fan control, handle special system events (e.g. chipset errors), emulate hardware (non existing or buggy hardware) and a lot more besides.
SMM in theory cannot be disabled by the operating system and have been known to interfere with the operating system even though is it meant to be transparent. SMIs steal CPU cycles from the system - CPU state has to be stored and restored and there are side effects because of flushing out of the write back cache. This CPU cycle stealing can impact real time behaviour and in the past it has been hard to determine how frequently SMIs occur and hence how much potential disruption they bring to a system.
When the CPU enters SMM the output pin SMIACT# is asserted (and all further memory cycles are redirected to a protected memory for SMM). Hence one could use a logic analyser on SMIACT# to count SMIs. An alternative is to have a non-interruptible thread on a CPU checking time skips by constantly monitoring the Time Stamp Counter (TSC) but this is a CPU expensive operation.
Fortunately, modern Intel CPUs (such as Ivybridge and Haswell) have a special SMI counter in a Model Specific Register. MSR_SMI_COUNT (0x00000034) is incremented when SMIs occur, allowing easy detection of SMIs.
As a quick test, I hacked up smistat that polls MSR_SMI_COUNT every second. For example, pressing the backlight brightness keys on my Lenovo laptop bumps the counter and this is easy to see with smistat. So this MSR provides some indication of the frequency of SMIs, however, it of course cannot inform us how many CPU cycles are stolen in SMM. Now that would be a very useful MSR to add to the next revision of the Intel silicon...
For example, SMM can be used to handle shutdown if CPU temperature is too high, perform transparent fan control, handle special system events (e.g. chipset errors), emulate hardware (non existing or buggy hardware) and a lot more besides.
SMM in theory cannot be disabled by the operating system and have been known to interfere with the operating system even though is it meant to be transparent. SMIs steal CPU cycles from the system - CPU state has to be stored and restored and there are side effects because of flushing out of the write back cache. This CPU cycle stealing can impact real time behaviour and in the past it has been hard to determine how frequently SMIs occur and hence how much potential disruption they bring to a system.
When the CPU enters SMM the output pin SMIACT# is asserted (and all further memory cycles are redirected to a protected memory for SMM). Hence one could use a logic analyser on SMIACT# to count SMIs. An alternative is to have a non-interruptible thread on a CPU checking time skips by constantly monitoring the Time Stamp Counter (TSC) but this is a CPU expensive operation.
Fortunately, modern Intel CPUs (such as Ivybridge and Haswell) have a special SMI counter in a Model Specific Register. MSR_SMI_COUNT (0x00000034) is incremented when SMIs occur, allowing easy detection of SMIs.
As a quick test, I hacked up smistat that polls MSR_SMI_COUNT every second. For example, pressing the backlight brightness keys on my Lenovo laptop bumps the counter and this is easy to see with smistat. So this MSR provides some indication of the frequency of SMIs, however, it of course cannot inform us how many CPU cycles are stolen in SMM. Now that would be a very useful MSR to add to the next revision of the Intel silicon...
Subscribe to:
Posts (Atom)
