Valgrind is one of the great tools in the long list of freely available applications for development. Beside several profiling tools it also contains a memory checker. Leaking memory is one of the more common errors a programmer could step into. Basically it means to forget freeing memory (or in a more general sense: any resource) a program has acquired. If you are a perfect developer, this will never happen to you. If you are a good developer it may happen and that’s where Valgrind will save you some trouble. As most of the developers out there are more or less good developers, their programs produce memory leaks, too ;). The right solution for this, is of course to write a bug report. But there are times where this isn’t possible or you are in hurry and don’t want to see all the errors of a third-party library you link against.
In the following post, I will show how to suppress such unwanted error messages to make it much more easier to analyze the output of Valgrind for your own application.
Installing Valgrind
On Mac OS X you can use MacPorts to install Valgrind. You have to use valgrind-devel if you are on Snow Leopard, because Snow Leopard is supported in the current development version only. It’s as simply as typing sudo port install valgrind-devel
.
On Gentoo it can become a bit harder. The current stable version is 3.5 (like in MacPorts). If you try this version (at least on an unstable Gentoo like mine) with valgrind ls
, you will get the following error:
valgrind: Fatal error at startup: a function redirection valgrind: which is mandatory for this platform-tool combination valgrind: cannot be set up. Details of the redirection are: valgrind: valgrind: A must-be-redirected function valgrind: whose name matches the pattern: strlen valgrind: in an object with soname matching: ld-linux-x86-64.so.2 valgrind: was not found whilst processing valgrind: symbols from the object with soname: ld-linux-x86-64.so.2 valgrind: valgrind: Possible fixes: (1, short term): install glibc's debuginfo valgrind: package on this machine. (2, longer term): ask the packagers valgrind: for your Linux distribution to please in future ship a non- valgrind: stripped ld.so (or whatever the dynamic linker .so is called) valgrind: that exports the above-named function using the standard valgrind: calling conventions for this platform. valgrind: valgrind: Cannot continue -- exiting now. Sorry.
The reason is a striped glibc. To work properly, Valgrind needs to overwrite some of the system functions the glibc provide. It does this by getting the symbols by name out of this library. This is of course not possible if all the symbol names are removed. You can prove this by executing nm /lib/ld-linux-x86-64.so.2
. Gentoo provides a FEATURE=splitdebug, which adds debug libraries to the installation. Unfortunately setting this feature in /etc/make.conf
, means setting it global. Gentoo is known as being configurable as no other distribution out there and of course we can set a feature for one program only. To do so, create a file called glibc
in /etc/portage/env/sys-libs/
and add the following content to it.
FEATURES="splitdebug"
After a rebuild of glibc by executing emerge --oneshot glibc
, we have a working Valgrind.
As all programs, Valgrind isn’t perfect. Version 3.5 shows many false/positive hits on my system, but fortunately the development goes on. Currently there is no newer version available in the Gentoo tree. Anyway it is not necessary to build one yourself, to get a more recent version. Using layman and the overlay tree of Flameeyes will let you integrate the development version of Valgrind seamlessly into your system. For a general How-to of layman check out this Users’ guide. In short, something like the following should be sufficient:
layman -a flameeyes-overlay layman -s flameeyes-overlay echo "=dev-util/valgrind-9999 **" >> /etc/portage/package.keywords emerge valgrind
Installing the development version of Valgrind is optional of course.
Know your tools
One usage of Valgrind could be look like this:
valgrind --leak-check=full --leak-resolution=high ./VirtualBox
Beside other errors it also shows this error message on my system:
==27174== at 0x4C26C09: memalign (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==27174== by 0x4C26CB9: posix_memalign (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==27174== by 0xBA8967F: ??? (in /usr/lib64/libglib-2.0.so.0.2400.2) ==27174== by 0xBA89E9D: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2400.2) ==27174== by 0xBA89F86: g_slice_alloc0 (in /usr/lib64/libglib-2.0.so.0.2400.2) ==27174== by 0xC204847: g_type_create_instance (in /usr/lib64/libgobject-2.0.so.0.2400.2) ==27174== by 0xC1EB8A5: ??? (in /usr/lib64/libgobject-2.0.so.0.2400.2) ==27174== by 0xC1ECE5D: g_object_newv (in /usr/lib64/libgobject-2.0.so.0.2400.2) ==27174== by 0xC1ED494: g_object_new (in /usr/lib64/libgobject-2.0.so.0.2400.2) ==27174== by 0x72A495F: ??? (in /usr/lib64/qt4/libQtGui.so.4.6.3) ==27174== by 0x72A0D4F: ??? (in /usr/lib64/qt4/libQtGui.so.4.6.3) ==27174== by 0x7289264: QGtkStyle::QGtkStyle() (in /usr/lib64/qt4/libQtGui.so.4.6.3) ==27174== by 0x7215DB6: QStyleFactory::create(QString const&) (in /usr/lib64/qt4/libQtGui.so.4.6.3) ==27174== by 0x6F5B7FC: QApplication::style() (in /usr/lib64/qt4/libQtGui.so.4.6.3) ==27174== by 0x6F61DFF: QApplicationPrivate::initialize() (in /usr/lib64/qt4/libQtGui.so.4.6.3) ==27174== by 0x6F61E88: QApplicationPrivate::construct(_XDisplay*, unsigned long, unsigned long) (in /usr/lib64/qt4/libQtGui.so.4.6.3) ==27174== by 0x6F61FF3: QApplication::QApplication(_XDisplay*, int&, char**, unsigned long, unsigned long, int) (in /usr/lib64/qt4/libQtGui.so.4.6.3) ==27174== by 0x44BC38: TrustedMain (main.cpp:371) ==27174== by 0x44C649: main (main.cpp:651)
If you analyze the backtrace, you see that something in libQtGui is leaking memory. I don’t want to blame someone for it or make a statement if this is right or wrong, I just want to get rid of it, to be able to easily spot errors VirtualBox itself produce. To do so, add --gen-suppressions=all
to the Valgrind call. This will produce something similar like this:
{ Memcheck:Leak fun:memalign fun:posix_memalign obj:/usr/lib64/libglib-2.0.so.0.2400.2 fun:g_slice_alloc fun:g_slice_alloc0 fun:g_type_create_instance obj:/usr/lib64/libgobject-2.0.so.0.2400.2 fun:g_object_newv fun:g_object_new obj:/usr/lib64/qt4/libQtGui.so.4.6.3 obj:/usr/lib64/qt4/libQtGui.so.4.6.3 fun:_ZN9QGtkStyleC1Ev fun:_ZN13QStyleFactory6createERK7QString fun:_ZN12QApplication5styleEv fun:_ZN19QApplicationPrivate10initializeEv fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm fun:_ZN12QApplicationC1EP9_XDisplayRiPPcmmi fun:TrustedMain fun:main }
To let Valgrind ignore this error in the future, copy the text into a file vbox.supp and start Valgrind with --suppressions=vbox.supp
. Viola, this specific error isn’t shown anymore. The format used there is easy to understand and you can of course tweak this much more. E.g. you could replace some of the fun:
entries by “...
“. This is a placeholder for one or more functions calls with any name. Beside making suppression rules more general you can of course add as much as you like. Adding a name at the top make it easy to identify the different rules. For all the possibilities have a look at the documentation. Just for the curious, Valgrind is using such a file itself. Have a look at /usr/lib/valgrind/default.supp. You may also have noted that the function names in the normal error message differ from the one in the suppression list. The former is in the demangled form and the later in the saved form. You could force Valgrind to print mangled function names by adding the --demangle=no
parameter to the call. This becomes handy if you manually create suppression lists.
Conclusion
By using suppression rules for the own application, unimportant errors could be eliminated in the output of Valgrind. With this is in mind there is no excuse anymore for memory leaks in the self developed applications. Beside memory leaks, Valgrind also finds places where uninitialized variables are in use or where memory is used which isn’t allocated by the application. Also these tests could be filtered out by suppression rules.