4

leaks command-line tool will report

  • the address of the leaked memory
  • the size of the leak (in bytes)
  • the contents of the leaked buffer

like the following:

Process:         checker [84357]
Path:            /path/to/program
Load Address:    0x104703000
Identifier:      checker
Version:         ???
Code Type:       X86-64
Parent Process:  zsh [64610]

Date/Time:       2019-11-30 18:43:06.864 -0800
Launch Time:     2019-11-30 18:42:58.593 -0800
OS Version:      Mac OS X 10.13.4 (17E199)
Report Version:  7
Analysis Tool:   /usr/bin/leaks

Physical footprint:         300K
Physical footprint (peak):  300K
----

leaks Report Version: 3.0
Process 84357: 161 nodes malloced for 17 KB
Process 84357: 3 leaks for 64 total leaked bytes.

Leak: 0x7fdf5b400350  size=16  zone: DefaultMallocZone_0x10470e000
Leak: 0x7fdf5b4027c0  size=16  zone: DefaultMallocZone_0x10470e000
Leak: 0x7fdf5b402810  size=32  zone: DefaultMallocZone_0x10470e000

My question is, how can I use these information to actually track down and find which malloc calls in my source code doesn’t have corresponding free() calls?
How can I find out which source file / where in the source file?
Do I need to change the value of some environment variables like MallocStackLogging or MallocStackLoggingNoCompact?

KIYZ
  • 412
  • 1
  • 5
  • 12
  • Try looking at the "man leaks" command documentation page in Terminal, explains some things. Type `man leaks`. https://www.unix.com/man-page/osx/1/leaks/ – ABC Dec 01 '19 at 04:57
  • @Raymond I already did, but still couldn't figure it out. – KIYZ Dec 01 '19 at 05:04

3 Answers3

7

It took me a while, but once I figured this all out it works great:

  • I used to use valgrind, until it couldn't run on my newer osx version. I was looking for a similarly convenient command-line approach to tracing memory leaks (could use Instruments instead, but it is heavyweight and UI-driven, both of which annoy me)
  • Using leaks -atExit tells me which leaks exist, but not where any leaked allocation came from
  • MallocStackLogging creates logs that can tell me where the leaked allocations came from, but the logs are automatically deleted when the program exits, and leaks -atExit runs, obviously, at exit

So you have to run MallocStackLogging, pause your program, then run leaks:

  1. Open a terminal and set MallocStackLogging: export MallocStackLogging=1

  2. At the end of the program, before it exists, add a line of code to pause it by reading from stdin, then recompile: fscanf(stdin, "c"); // wait for user to enter input from keyboard

  3. Run your program and wait for it to pause

  4. In a separate terminal, output the leak allocations by running leaks my_program_name (or alternatively, find your pid: ps aux | grep my_program_name and then run leaks <pid>).

Cheers

mwag
  • 3,557
  • 31
  • 38
3

Set environment variable MallocStackLogging to true, run program, then run leaks.
This will print a stack trace of where the leaked memory was allocated.

The way I did it is:

  1. export MallocStackLogging=1
  2. In the main function, add the following code right before returning.
    system("leaks executablename"); .
  3. Run program.
KIYZ
  • 412
  • 1
  • 5
  • 12
0

You can save memory graph file with the leaks command. If malloc stack logging is enabled the graph will include stack traces.

If your program is a long-running process chances are you want to compare memory usage at different point in time, which can be also done with the leaks commands.

  • in one terminal, run you program with stack logging: MallocStackLogging=1 ./myprogram
  • in another terminal, run leaks --outputGraph=g1 myprogram; this will save g1.memgraph file
  • (optional) after some time run leaks --outputGraph=g2 myprogram
  • you can now kill myprogram
  • view the results with either leaks g1.memgraph or leaks --diffFrom=g1.memgraph g2.memgraph