Valgrind Suppression File Howto

From WxWiki
Jump to: navigation, search

Introduction

Valgrind is (mostly) a memory error detector for Linux. It's very good at finding leaks and uninitialised variables; unfortunately it's too good, and usually produces a number of false positives. It comes with suppression files which automatically silence some of these; but not enough, and none specific to wxGTK.

This howto discusses suppression files and how to create your own. It includes a script to simplify the process.

Why I had to do this

I've used valgrind on apps running on wxGTK-2.4.2 upwards, in several distros. Each time there have been at least dozens of false positives, but never enough to be more than a nuisance. The last time was wxGTK-2.8.10 on debian lenny, where the 'minimal' sample gives 1200 errors. That's annoying, but just about manageable.

I'm now (August 2010) using debian testing, squeeze. The same sample gives 249,000 errors! and a real app many more. Presumably the valgrind/default.supp file doesn't match the squeeze libs too well.

So I've been forced to teach myself how to suppress these errors. Here are the results; but I don't claim to be an expert in any of this. Please correct any mistakes you find.


Valgrind and suppression files

When valgrind runs its default tool, Memcheck, it automatically tries to read a file called $PREFIX/lib/valgrind/default.supp ($PREFIX will normally be /usr). However you can make it use additional suppression files of your choice by adding --suppressions=<filename> to your command-line invocation. You can repeat this up to 100 times, which should be sufficient for most situations ;)

Rather than having to type this each time, it's more sensible to write it to an rc file. Each time it runs, valgrind looks for options in files called ~/.valgrindrc and ./.valgrindrc. I suggest that you put a general wxGTK suppression in the first, and one that's more specific to your current project in the second. Create the files if they don't already exist. So I now have a ~/.valgrindrc containing:

--memcheck:leak-check=full
--show-reachable=yes
--suppressions=/home/david/devel/wxGTK-2.8.12.supp
--suppressions=/home/david/devel/wxGTK-2.9.supp

To check that valgrind is actually using the suppression files, run it with the -v option. The list of suppression files read is near the beginning of the output.

How to make a suppression file

Run valgrind as usual, but with the extra option --gen-suppressions=all. This tells valgrind to print a suppression after every error it finds.

Example output:
==10977== Conditional jump or move depends on uninitialised value(s)
==10977==    at 0x9279BA4: __GI_strlen (strlen.S:37)
==10977==    by 0x97C27EB: ??? (in /usr/lib/libX11.so.6.3.0)
==10977==    by 0x97C2A8C: _XlcCreateLocaleDataBase (in /usr/lib/libX11.so.6.3.0)
==10977==    by 0x97C7B16: ??? (in /usr/lib/libX11.so.6.3.0)
==10977==    by 0x97C6EB2: ??? (in /usr/lib/libX11.so.6.3.0)
==10977==    by 0x97C7735: _XlcCreateLC (in /usr/lib/libX11.so.6.3.0)
==10977==    by 0x97EA8FF: _XlcUtf8Loader (in /usr/lib/libX11.so.6.3.0)
==10977==    by 0x97CF69A: _XOpenLC (in /usr/lib/libX11.so.6.3.0)
==10977==    by 0x97CF787: _XlcCurrentLC (in /usr/lib/libX11.so.6.3.0)
==10977==    by 0x97CFB78: XSupportsLocale (in /usr/lib/libX11.so.6.3.0)
==10977==    by 0x604B0B5: ??? (in /usr/lib/libgdk-x11-2.0.so.0.2000.1)
==10977==    by 0x604B1AE: gdk_set_locale (in /usr/lib/libgdk-x11-2.0.so.0.2000.1)
==10977== 
{
   <insert_a_suppression_name_here>
   Memcheck:Cond
   fun:__GI_strlen
   obj:/usr/lib/libX11.so.6.3.0
   fun:_XlcCreateLocaleDataBase
   obj:/usr/lib/libX11.so.6.3.0
   obj:/usr/lib/libX11.so.6.3.0
   fun:_XlcCreateLC
   fun:_XlcUtf8Loader
   fun:_XOpenLC
   fun:_XlcCurrentLC
   fun:XSupportsLocale
   obj:/usr/lib/libgdk-x11-2.0.so.0.2000.1
   fun:gdk_set_locale
}

Printing the suppressions inline like this means you have to cut/paste each to the suppression file by hand. Doing that would be fine for just a few errors. but 249k of them might take a while.

A more realistic solution is to save the output to a file. You can do this with a standard unix redirection, or by using the --log-file=<filename> option. With large numbers of errors, you also need to tell valgrind to process them all, with the option --error-limit=no. So, for the 'minimal' sample (which is a good place to start) you might write:

valgrind --leak-check=full --show-reachable=yes --error-limit=no --gen-suppressions=all --log-file=minimalraw.log ./minimal

When running the sample it's a good idea to use all its features: move the mouse, run the 'About' dialog, resize the sample etc, as these will often produce extra errors.


You now have a file containing the raw output, with the suppressions mingled with the errors and other stuff. Also, as errors are usually multiple, there'll usually be multiple instances of each suppression. So the next step is to pass minimalraw.log through this gawk script which removes the cruft.

cat ./minimalraw.log | ./parse_valgrind_suppressions.sh > minimal.supp

'minimal.supp' is now a valid suppression file, so you can live happily ever after, yes? Well, no. I found that the suppressions were too specific, so running the app again resulted in slightly different errors that weren't suppressed. The answer was to make them less specific by using wildcards. Unfortunately I don't think there's any way that this can be automated. I just went through the suppressions looking for:

  • libraries referred to in multiple suppressions, that are unlikely to be involved in 'real' errors. These can easily be filtered out with just one suppression, using the '...' frame-level wildcard.
  • near duplicates, that can be caught using a 'normal' wildcard.

During this process, I often found it helpful to refer to the error-message/suppression combination in the 'raw' file, especially as a side-effect of the awk script is to change the order of the suppressions. (It would have been much easier if similar suppressions were displayed adjacently, but I can't think of an easy way to do so. Anyone?)

Having done this, I put the 'wildcard' suppressions into a different file and used it to run 'minimal' and regenerate the suppression file. Then looked for more near duplicates... After several such iterations, I just appended the remaining suppressions, and ended up with a file that suppressed robustly all the 'minimal' false positives.

I've posted the resulting file here. The current one was created using wxGTK-2.8.12 on debian wheezy x86_64. If you don't want to write your own, try it. I don't know how well it'll work for you, but it should at least provide a start.

Update: It's now 2013 and many more people are using wx2.9 so I've also created an additional suppression file for wx2.9.5, though it also works for earlier 2.9 versions. It's designed to be used in addition to the 2.8 one, so either merge the two files or add both to your .valgrindrc.


The next step is to repeat the process (while using the 'minimal' suppression file) with the sample(s) most relevant to your app. This results in a second lot of suppressions which can either be added to the first file or used as a separate file, perhaps pointed to in ./.valgrindrc.

Now when you valgrind your app, the false positives should be reduced to reasonable levels. There will probably still be some though, as your app will make calls that the sample didn't. If you want to get rid of them, make yet another suppression file.


Aggressive use of wildcards in suppressions obviously risks filtering out true positives too. AFAICT I haven't done so, and valgrind still catches my mistakes (which of course are all intentional, just testing.. ;) ).

Suppression file syntax

This is described in [1] and [2]. Each suppression is surrounded with curly-braces, and starts with the line: <insert_a_suppression_name_here>. You can replace this with an informative name if you wish, but it's not necessary.

The second line will start with Memcheck:. Immediately following will be the type of error. See the links for all the possibilities, but I found mostly Cond, Addr8, Value8, and Leak. Unfortunately most false positives seem to produce most or all of these error types, and there's no way of combining the types in a single suppression; so each error needs 3 or 4 otherwise-identical suppressions.

The remaining lines start either with fun: for function calls, or obj: for the names of shared objects. Examples are fun:gdk_set_locale and obj:/usr/lib/libgdk-x11-2.0.so.0.2000.1.

Wildcards

The standard wildcard characters * and ? can be used e.g. obj:/usr/lib/libgdk-x11-* would be more generally applicable than the above line. However I found the frame-level wildcard '...' to be much more useful. This matches zero or more fun: or obj: lines. Using it results in a short, simple suppression that catches multiple similar errors.

So ideally a long suppression would end up as:
{
   <gdk_set_locale>
   Memcheck:Cond
   ...
   fun:gdk_set_locale
}
or
 {
   <libpango>
   Memcheck:Leak
   ...
   obj:/usr/*lib*/libpango*
}

As my programming errors are unlikely to involve calling libpango or similar, this should be both efficient and safe.

Step by step summary

  1. Check you have gawk and md5sum installed; you almost certainly already have.
  2. Open a terminal in the 'minimal' sample directory and run make.
  3. Copy the parse_valgrind_suppressions.sh script to this directory (ensure it has executable permission). Alternatively you could use its full filepath in 5.
  4. Create a raw suppression file: valgrind --leak-check=full --show-reachable=yes --error-limit=no --gen-suppressions=all --log-file=minimalraw.log ./minimal
  5. Process the raw data: cat ./minimalraw.log | ./parse_valgrind_suppressions.sh > minimal.supp
  6. Examine the resulting files. Select likely candidates for wildcarding, writing the resulting suppressions to another file e.g. wxGTK-2-8-12.supp.
  7. Rerun valgrind using that suppression file: valgrind --leak-check=full --show-reachable=yes --error-limit=no --suppressions=./wxGTK-2.8.12.supp --gen-suppressions=all --log-file=minimalraw.log ./minimal
  8. Goto 5.
  9. Once there aren't too many errors, or none that you dare wildcard, append the remaining unaltered suppressions to wxGTK-2-8-12.supp.
  10. Move wxGTK-2-8-12.supp to somewhere sensible and add its filepath to ~/.valgrindrc.
  11. If necessary, repeat using a different sample. Point to the resulting file either in ~/.valgrindrc or in ./.valgrindrc as appropriate.
  12. Optionally, repeat with wx2.9.? and either append the results to the 2.8 supp, or (as I do) create a separate 2.9 one and use both.

Links

valgrind

Valgrind: Core Command-line Options

Valgrind: Writing suppression files

Valgrind suppression file for wxgtk2.9.1