Patrick Collins
Patrick Collins

Reputation: 10574

Filtering out junk from valgrind output

I'm trying to fix a memory leak in a very large project. Benchmarks have confirmed that memory leaks are a significant problem, and I'm working on finding the source of them.

Running the project on a very simple case, I get ~850 potential memory leaks reported. All but about 5 of them look like:

==83597== 768 bytes in 3 blocks are possibly lost in loss record 743 of 864
==83597==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==83597==    by 0x548EF93: myproject_malloc (mysourcefile.c:48)
==83597==    by 0x4F13FD5: ??? (in /path/to/project/library-version.so)
==83597==    by 0x1101: ???
==83597==    by 0xF7: ???
==83597==    by 0x64D4D87: ???
==83597==    by 0xFFFFFFFFFFFFFFFD: ???
==83597==    by 0x6: ???
==83597==    by 0x4F03BB0: ??? (in /path/to/project/library-version.so)
==83597==    by 0xFFFFFFFFFFFFFFFD: ???
==83597==    by 0x64D4D87: ???


==83597== 920 bytes in 1 blocks are possibly lost in loss record 750 of 864
==83597==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==83597==    by 0x548EF93: myproject_malloc (mysourcefile.c:48)
==83597==    by 0x4F13FD5: ??? (in /path/to/project/library-version.so)
==83597==    by 0xFFEFFFD5F: ???
==83597==    by 0x38F: ???
==83597==    by 0xFFEFFFE5F: ???
==83597==    by 0xF: ???
==83597==    by 0x54542FF: ??? (in /path/to/project/library-version.so)
==83597==    by 0x4F536CA: ??? (in /path/to/project/library-version.so)
==83597==    by 0x64B981F: ???
==83597==    by 0xF: ???
==83597==    by 0x54542FF: ??? (in /path/to/project/library-version.so)


==83597== 1,360 bytes in 1 blocks are possibly lost in loss record 789 of 864
==83597==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==83597==    by 0x548EF93: myproject_malloc (mysourcefile.c:48)
==83597==    by 0x4F13FD5: ??? (in /path/to/project/library-version.so)
==83597==    by 0x1101: ???
==83597==    by 0x547: ???
==83597==    by 0x1F: ???
==83597==    by 0x6584267: ???
==83597==    by 0x547: ???
==83597==    by 0x4F13808: ??? (in /path/to/project/library-version.so)
==83597==    by 0x6584267: ???
==83597==    by 0x6584527: ???
==83597==    by 0x65805FF: ???

I'm working on getting valgrind to give real, useful output rather than ???, but it may not be possible, and I'd like to be able to get useful output from memcheck until that happens.

A useful report has > 1 function call reported from a real source file rather than a .so file (because every output reports myproject_malloc as a potential leak source). What's the simplest way I can cut out all of the junk from the output and still display it as plain text in my emacs compilation buffer?

I know I could write a Python script that would be a few dozen lines long to do the job by checking every time I enter a new error report and counting the number of times I see ".c:\d+", but I'd prefer something simpler.

Is there a nice way to do this with commandline tools? Or an option to valgrind that I'm not aware of?

Upvotes: 3

Views: 2834

Answers (2)

Patrick Collins
Patrick Collins

Reputation: 10574

As I said in the comments, suppressing based on origin isn't an appropriate technique here because of strange properties of the library I'm working with (almost every stack trace passes through the "bad" library library-version.so and compiling with -g doesn't fix it). I ended up just writing a python script, which I'll post here for future users:

#!/usr/bin/python

import fileinput
import re

START = re.compile("in loss record")
STOP = re.compile("^==\d+== $")
GOOD = re.compile(r"\.c:\d+", re.M)

def main():
  in_line = False
  current = []
  for line in fileinput.input():
    if in_line:
      in_line = not STOP.search(line)
    else:
      in_line = START.search(line)

    if in_line:
      current.append(line)
    else:
      match = GOOD.findall("".join(current))
      if len(match) > 2:
        print "".join(current)
      current = []

if __name__ == "__main__":
  main()

Now you can either save your valgrind output to a file or pipe it directly to this script and it cuts down on the cruft. Adjust the len(match) > FOO line to control how many results you keep.

Upvotes: 0

Thomas Dickey
Thomas Dickey

Reputation: 54475

Not an option, but a configuration feature: valgrind can be configured with suppression files which tell it to ignore certain stack traces.

For information,

Yes! Use the --gen-suppressions=yes feature to spit out suppressions automatically for you. You can then edit them if you like, eg. combining similar automatically generated suppressions using wildcards like '*'.

If you really want to write suppressions by hand, read the manual carefully. Note particularly that C++ function names must be mangled (that is, not demangled).

Valgrind relies upon symbols. Those ??? are for missing symbols (and some do not appear likely addresses). As I recall it, valgrind supplies those after checking for symbols, so (even if there were a suitable wildcard to work around ? as a meta character), you could not explicitly suppress those.

Your stack traces lack line-numbers for the project library. If you compile with debugging (-g) and design a suitable frame-level suppression, that seems to be an improvement.

Upvotes: 3

Related Questions