Friday, 23 June 2023

Valgrind: noise reduction

Ensuring your delivered code is memory leak free is a standard concern for C/C++ developers and valgrind is a great tool to assist. One problem we can run into is extra noise from system/non project libraries masking your own issues. Refocussing is relatively straight forward: https://valgrind.org/docs/manual/manual-core.html#manual-core.suppress
$ valgrind --gen-suppressions=all ./audiotag ../tests/test.mp3 ==17943== Invalid read of size 32 ==17943== at 0x641D5D9: __wmemcmp_avx2_movbe (in /usr/lib64/libc.so.6) ==17943== by 0x48F1785: TagLib::String::operator<(TagLib::String const&) const (in /usr/lib64/libtag.so.1.18.0) ==17943== by 0x48E533B: ??? (in /usr/lib64/libtag.so.1.18.0) ==17943== by 0x48F7E81: TagLib::PropertyMap::operator[](TagLib::String const&) (in /usr/lib64/libtag.so.1.18.0) ==17943== by 0x492052E: TagLib::Tag::properties() const (in /usr/lib64/libtag.so.1.18.0) ==17943== by 0x40A5FA: _properties (Meta.h:366) ==17943== by 0x40A5FA: AudioTag::MetaMP3::properties(TagLib::Tag const&) const (Meta.cc:473) ==17943== by 0x41041F: AudioTag::MetaOutJson::out(std::ostream&, AudioTag::File const&) (MetaOut.cc:122) ==17943== by 0x410806: execute (Ops.h:32) ==17943== by 0x410806: AudioTag::Ops::execute(AudioTag::File&) const (Ops.cc:23) ==17943== by 0x40779E: main (audiotag.cc:570) ==17943== Address 0xf6ea210 is 0 bytes inside a block of size 28 alloc'd ==17943== at 0x4844FF5: operator new(unsigned long) (vg_replace_malloc.c:422) ==17943== by 0x48E9C79: TagLib::String::upper() const (in /usr/lib64/libtag.so.1.18.0) ==17943== by 0x48F7E69: TagLib::PropertyMap::operator[](TagLib::String const&) (in /usr/lib64/libtag.so.1.18.0) ==17943== by 0x49204DE: TagLib::Tag::properties() const (in /usr/lib64/libtag.so.1.18.0) ==17943== by 0x40A5FA: _properties (Meta.h:366) ==17943== by 0x40A5FA: AudioTag::MetaMP3::properties(TagLib::Tag const&) const (Meta.cc:473) ==17943== by 0x41041F: AudioTag::MetaOutJson::out(std::ostream&, AudioTag::File const&) (MetaOut.cc:122) ==17943== by 0x410806: execute (Ops.h:32) ==17943== by 0x410806: AudioTag::Ops::execute(AudioTag::File&) const (Ops.cc:23) ==17943== by 0x40779E: main (audiotag.cc:570) ==17943== { <<>insert_a_suppression_name_here<>> Memcheck:Addr32 fun:__wmemcmp_avx2_movbe fun:_ZNK6TagLib6StringltERKS0_ obj:/usr/lib64/libtag.so.1.18.0 fun:_ZN6TagLib11PropertyMapixERKNS_6StringE fun:_ZNK6TagLib3Tag10propertiesEv fun:_properties fun:_ZNK8AudioTag7MetaMP310propertiesERKN6TagLib3TagE fun:_ZN8AudioTag11MetaOutJson3outERSoRKNS_4FileE fun:execute fun:_ZNK8AudioTag3Ops7executeERNS_4FileE fun:main } ...
$ cat > valgrind.supress << EOF { rule_ignore_system_libs Memcheck:Leak obj:*/lib*/lib*.so.* } { rule_ignore_tablib_invalid_read Memcheck:Addr32 fun:__wmemcmp_avx2_movbe fun:_ZNK6TagLib6StringltERKS0_ obj:/usr/lib64/libtag.so.* } EOF $ valgrind --suppressions=valgrind.suppress ./audiotag ../tests/test.mp3
With suppressions enabled you should be able to concentrate on items related to your project. However if you need to dig further, there are advanced techniques to help narrowing down your memory issues: using gdb along with valgrindis a power combination:

You will need two terminals, one starting valgrind in paused start and then gdb in another terminal connecting to the former.
$ valgrind --vgdb-error=0 ./audiotag -d1A -l ../tests/test.mp3 ==40385== Memcheck, a memory error detector ==40385== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al. ==40385== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info ==40385== Command: ./audiotag -d1A -l ../tests/test.mp3 ==40385== ==40385== (action at startup) vgdb me ... ==40385== ==40385== TO DEBUG THIS PROCESS USING GDB: start GDB like this ==40385== /path/to/gdb ./audiotag ==40385== and then give GDB the following command ==40385== target remote | /usr/libexec/valgrind/../../bin/vgdb --pid=40385 ==40385== --pid is optional if only one valgrind process is running ==40385==
In second terminal:
$ gdb ./audiotag .. (gdb) target remote | /usr/libexec/valgrind/../../bin/vgdb --pid=40385 (gdb) monitor help (gdb) monitor leak_check full reachable any (gdb) br ... ... (gdb) mo l ==40385== LEAK SUMMARY: ==40385== definitely lost: 0 (+0) bytes in 0 (+0) blocks ==40385== indirectly lost: 0 (+0) bytes in 0 (+0) blocks ==40385== possibly lost: 0 (+0) bytes in 0 (+0) blocks ==40385== still reachable: 299,633 (+0) bytes in 1,109 (+0) blocks ==40385== suppressed: 0 (+0) bytes in 0 (+0) blocks ==40385== Reachable blocks (those to which a pointer was found) are not shown. ==40385== To see them, add 'reachable any' args to leak_check ==40385==
Once connected you can continue adding break points with the monitor commands evaluating specific execution paths where the memory errors occur.

No comments:

Post a Comment