Use the Sparse Semantic Parser to Spot Problems With Your Code

During my LinuxCon EU talk last year I briefly touched on the sparse semantic parser tool started by Linus Torvalds in 2003 (slide 7). While it might not be as powerful as other static analyzers I described, it still might be worthwhile to run on your code. Many distributions ship a sparse package already, which makes it easy to test. If not you might want to grab the latest tarball and build it yourself.

Once you have sparse installed, running it on your code should be easy as it provides a build wrapper around the CC environment variable. If you do not have any special requirements for CC in your build setup you should be able to run sparse like this:

make CC=cgcc

Use Filters to Find What Matters

Depending on your code, you might be overwhelmed by the amount of warnings and maybe errors sparse is producing. While you should have a look at all of them it helps on the practical side to filter out some warning classes to make sure you do not miss others. Sparse allows filtering with -Wsomething and -Wno-something command line options to enable or disable specific checks. To pass these options to sparse while using the build-wrapper we can put them into our CFLAGS.

CFLAGS="$CFLAGS -Wno-decl"

After this you need to make sure that the new CFLAGS are picked up by your build system, and after that a new sparse run should act accordingly to your newly set options.

For example a run in the EFL codebase showed a lot warnings about functions that should be static.

warning: symbol 'XXX' was not declared. Should it be static?

It was hard to find other warnings due to the sheer amount of those. After adding -Wno-decl to the CFLAGS for this run it was easier to spot others and allowing me to re-visit the functions which might need to be static later on.

Some Examples of Warnings You Might Find

When I ran this on EFL, one warning I hit was “Using plain integer as NULL pointer” which pointed me to two cases in our code where we used the integer 0 as the address we pointed mmap to.

mmap(0, ...)

instead of

mmap(NULL, ...)

I have not checked the mmap() internals about how such a case would be handled, but we should use it as intended. Interestingly these cases have been 2 out of 31 actual uses of mmap() from our code.

Another warning we saw in our code base was:

warning: non-ANSI function declaration of function

It points out that we declared functions without parameters in some cases:

foobar();

instead of

foobar(void);

For a definition this would mean that the function takes no parameters, but for a declaration this has a different meaning. The former one takes an unspecified number of parameters. You could, for example, have something like this:

foobar();

foobar(int param) { };

If you want to make sure your function really takes no parameters. you need to make sure to use the (void) syntax for declaration. In C++ the meaning is different, but my examples here refer to plain C code.

Make the Sparse Semantic Parser Work for You

While it’s possible to filter warnings with the compiler options, not all warnings can be disabled like this. The sparse man page covers warning options that are available. The signal to noise ratio is still a bit too much on the noise side for my own taste, but at least some things can be filtered out. Given the output is plain text, some shell magic could be used to filter the output to find the bits you are interested in.

In one of the next installations of this tools series I will look into the smatch tool, which uses sparse and was also developed for the Linux Kernel but can be used on other projects as well. Stay tuned and I hope you enjoyed this one and maybe even found some bugs in your code you could fix now.

Author: Stefan Schmidt

Stefan Schmidt has been a FOSS contributor for over 10 years and currently works on Enlightenment Foundations Libraries, Wayland and the IEEE 802.15.4 and 6LoWPAN Linux stack.