Enabling the Malloc Debugging Features
Debugging memory-related bugs can be time consuming if you do not know where to start looking. This is usually compounded by the problem that many memory bugs occur well after the memory in question was manipulated by the code. Fortunately, Xcode includes options for identifying memory problems closer to when those problems actually happen.
Enabling Guard Malloc
Guard Malloc is a special version of the malloc library that replaces the standard library during debugging. Guard Malloc uses several techniques to try and crash your application at the specific point where a memory error occurs. For example, it places separate memory allocations on different virtual memory pages and then deletes the entire page when the memory is freed. Subsequent attempts to access the deallocated memory cause an immediate memory exception rather than a blind access into memory that might now hold other data. When the crash occurs, you can then go and inspect the point of failure in the debugger to identify the problem.
To enable debugging using Guard Malloc, configure your project to run with Guard Malloc in Xcode’s scheme editor. You can use this option for Mac apps and iOS apps running in the simulator.
For more information about the types of memory problems that Guard Malloc can help you track down, see the
libgmalloc man page in OS X Man Pages.
Configuring the Malloc Environment Variables
The malloc library provides debugging features to help you track down memory smashing bugs, heap corruption, references to freed memory, and buffer overruns. You enable these debugging options through a set of environment variables. With the exception of
MallocCheckHeapEach, the value for most of these environment variables is ignored. To disable a variable from Terminal, use the
unset command. Table 1 lists some of the key environment variables and describes their basic function. For a complete list of variables, see the
malloc man page.
The following example enables stack logging and heap checking in the current shell before running an application. The value for
MallocCheckHeapStart is set to 1 but is irrelevant and can be set to any value you want. You could also set these variables from your shell’s startup file, although if you do be sure to
export each variable.
If you want to run your program in
gdb, you can set environment variables from the Xcode debugging console using the command
set env, as shown in the following example:
(gdb) set env MallocStackLogging 1
Some of the performance tools require these options to be set in order to gather their data. For example, the
malloc_history tool can identify the allocation site of specific blocks if the
MallocStackLogging flag is set. This tool can also describe the blocks previously allocated at an address if the
MallocStackLoggingNoCompact environment variable is set. The
leaks command line tool will name the allocation site of a leaked buffer if
MallocStackLogging is set. See the man pages for
malloc_history for more details.
Detecting Double Freed Memory
The malloc library reports attempts to call
free on a buffer that has already been freed. If you have enabled the
MallocStackLoggingNoCompact option, you can use the logged stack information to find out where in your code the second
free call was made. You can then use this information to set up an appropriate breakpoint in the debugger and track down the problem.
The malloc library reports information to
Detecting Heap Corruption
To enable heap checking, assign values to the
MallocCheckHeapEach environment variables. You must set both of these variables to enable heap checking. The
MallocCheckHeapStart variable tells the malloc library how many
malloc calls to process before initiating the first heap check. Set the second to the number of
malloc calls to process between heap checks.
MallocCheckHeapStart variable is useful when the heap corruption occurs at a predictable time. Once it hits the appropriate start point, the malloc library starts logging allocation messages to the Terminal window. You can watch the number of allocations and use that information to determine approximately where the heap is being corrupted. Adjust the values for
MallocCheckHeapEach as necessary to narrow down the actual point of corruption.
Detecting Memory Smashing Bugs
To find memory smashing bugs, enable the
MallocScribble variable. This variable writes invalid data to freed memory blocks, the execution of which causes an exception to occur. When using this variable, you should also set the
MallocStackLoggingNoCompact variables to log the location of the exception. When the exception occurs, you can then use the
malloc_history command to track down the code that allocated the memory block. You can then use this information to track through your code and look for any lingering pointers to this block.