Debug malloc tool
Debugging applications that are mismanaging memory allocated by the malloc subsystem can be difficult and tedious. This is because there is generally no synchronicity between the insertion of an error and the exposure of its resulting symptom.
Adding to the difficulty is the inherent complexity of memory allocation, with thousands of allocations being made, undone, and accessed (perhaps) asynchronously and simultaneously, all within a multithreaded context that necessitates robust and efficient synchronization.
It is for these reasons that the focus of our debugging tools is primarily to move the time of symptom detection closer to the time of error insertion. This helps the application developer to pinpoint more precisely which section of code is responsible for committing the error.
Many different debugging tools have been developed for use with malloc. Some can be used in combination with other debugging tools and with all allocation policies; others are more limited in their use. Many of the debugging tools consume resources additional to those required by the process. It is up to the application developer to provide adequate resources when necessary.
Performance Considerations
The debug malloc tools are not appropriate for full-time, constant, or system-wide use. Although
they are designed for minimal performance impact upon the application being debugged, significant
negative impact on overall system throughput can result if they are used widely throughout a system.
In particular, setting MALLOCDEBUG=catch_overflow
in the /etc/environment
file is not recommended, and will likely cause significant system problems, such as excessive use of
paging space. The debug malloc tools should only be used to debug single applications or small
groups of applications at the same time.
Because of the extra work involved in making various run-time checks, malloc subsystem performance will degrade variably with debug malloc tools enabled (depending on which tool is being used), but not to the point that applications will become unusable. After the problem is resolved, the debug malloc tools should be turned off to restore malloc subsystem performance.
Disk and memory considerations
With the catch_overflow
or Malloc Log tools enabled, the malloc subsystem
will consume significantly more memory.
For catch_overflow
, each malloc request is increased by 4096 + 2 times the size
of unsigned long, then rounded up to the next multiple of the PAGESIZE macro.
catch_overflow
might prove to be too memory-intensive to use for very large
applications, but for the majority of applications that need memory debugging, the extra use of
memory should not cause a problem. For large applications, the use of the debug_range and
functionset options to catch_overflow
can significantly lower memory usage,
allowing the program to be debugged piecemeal.
For Malloc Log, an allocation record is stored for every active allocation in the process. This memory overhead can be minimized by specifying a low number of saved stack pointers.
If the application being debugged frequently calls malloc subsystem allocation routines, it might encounter memory usage problems with debug malloc tools enabled that could prevent the application from executing properly in a single segment. If this occurs, it may be helpful to enable the application to access additional memory by using the ulimit command and the -bmaxdata option of the ld command.
ulimit -d unlimited
ulimit -s unlimited
To reserve the maximum of 8 segments for a 32-bit process, the -bmaxdata option should be
specified as -bmaxdata:0x80000000
.
When the debug malloc tools are turned off, the default values for ulimit and -bmaxdata can be restored.
For more information about the ulimit command and the -bmaxdata option, see Large Program Support.
The debug malloc tools are not appropriate for use in some debugging situations. Because some of the debug malloc tools require the overhead of a page or more per allocation, programs that issue many small allocation requests will see their memory usage increase dramatically. These programs might encounter new failures as memory allocation requests are denied due to a lack of memory or paging space. These failures are not necessarily errors in the program being debugged, and they are not errors in the debug malloc tool.
- Start the X server with catch_overflow turned off.
- Start a terminal window (for example, dtterm, xterm, aixterm).
- Set the appropriate environment variables within the terminal window session to enable catch_overflow.
- Invoke the X client program to be debugged from within the same window.
Enabling debug malloc
Debug Malloc is not enabled by default, but is enabled and configured by setting the MALLOCDEBUG environment variable to the appropriate option. If more than one option is required, options can be separated by a comma (,). Options requested in tandem must be compatible with each other.
Malloc debugging tools
Buffer overflow detection
Memory management errors are sometimes caused by the application program writing past the end of an allocated buffer. Because this often has no immediate consequence, symptoms do not arise until much later when the memory that was overwritten (usually belonging to another allocation) is referenced and no longer contains the data originally stored therein.
The catch_overflow
debug option exists to allow users to identify memory
overwrites, overreads, duplicate frees, and reuse of freed memory allocated by the malloc
subroutine. Memory problems detected by the catch_overflow tool result in an abort call or a
segmentation violation (SIGSEGV). In most cases, when an error is detected, the application
stops immediately and a core file is produced.
catch_overflow
option affects the allocations of the following allocation
policies and options: - Default Allocation Policy
- Watson Allocation Policy
- Malloc Multiheap Option
- Malloc Threadcache Option
- Malloc Disclaim Option
The catch_overflow
debug option is enabled by setting
MALLOCDEBUG=catch_overflow
. This will turn on identification of memory overwrites
and overreads.
- align
-
By default, the malloc subroutine returns a pointer aligned on a 2-word boundary. This is necessary for standards conformance and for programs which cannot accept unaligned memory accesses (e.g. programs using DCE components). However, due to a quirk in the implementation of the
catch_overflow
option, it is possible for a program to overwrite a buffer by an amount less than the alignment value without being detected bycatch_overflow
. Thealign
option can be used to tell the malloc subsystem to disregard this default alignment in order to decrease or eliminate the number of bytes by which a buffer can be overwritten without detection. A custom alignment can be specified for any power of two between 0 and 4096 inclusive (e.g. 0,1,2,4,...). The values 0 and 1 are treated as the same, that is, there is no memory alignment; therefore any memory accesses beyond the allocated area will cause a SEGFAULT.Thealign
option is part of thecatch_overflow
option and is only meaningful whencatch_overflow
is enabled. To enable a non-default alignment, set the MALLOCDEBUG environment variable as follows:
where n is the desired alignment.MALLOCDEBUG=catch_overflow,align:n
To calculate how many bytes of overreads or overwrites thecatch_overflow
option will allow for a given allocation request when n is the requested alignment and size is the number of bytes to be allocated, use the following formula:((((size / n) + 1) * n) - size) % n
The following example demonstrates the effect of the align option on the application's ability to perform overreads or overwrites with the catch_overflow option enabled. In this example, the align option is specified with a value of 2:MALLOCDEBUG=align:2,catch_overflow
Thecatch_overflow
option handles overreads and overwrites as follows:- When an even number of bytes is allocated, malloc allocates exactly the number of bytes requested, which will allow for 0 bytes of overreads or overwrites.
- When an odd number of bytes is allocated, malloc allocates the number of bytes requested, plus one additional byte to satisfy the required alignment. This allows for 1 byte of possible overreads or overwrites.
- override_signal_handling
-
The
catch_overflow
option reports errors in one of the following ways:- Memory access errors (such as trying to read or write past the end of allocated memory) cause a segmentation violation (SIGSEGV), resulting in a core dump.
- For other types of errors (such as trying to free space that was already freed), the
catch_overflow
option will output an error message, then call the abort function , which will send a SIGIOT signal to end the current process.
If the calling program is blocking or catching the SIGSEGV and the SIGIOT signals, the
catch_overflow
option will be prevented from reporting errors. Theoverride_signal_handling
option provides a means of bypassing this situation without recoding and rebuilding the application.If theoverride_signal_handling
option is specified, thecatch_overflow
option will perform the following actions upon each call to a malloc subsystem routine:- Disable any existing signal handlers set up by the application for SIGSEGV or SIGIOT.
- Set the action for both SIGIOT and SIGSEGV to the default (SIG_DFL).
- Unblock both SIGIOT and SIGSEGV.
If an application signal handler modifies the action for SIGSEGV between memory allocation routine calls and then attempts an invalid memory access, the catch_overflow option will be unable to report the error (the application will not exit and no core file will be produced).
Note:- The
override_signal_handling
option can be ineffective in a threaded application environment because thecatch_overflow
option uses the sigprocmask subroutine and many threaded processes use the pthread_sigmask subroutine. - If a thread calls the sigwait subroutine without including SIGSEGV and SIGIOT in the
signal set and the
catch_overflow
option subsequently detects an error, the thread will hang because thecatch_overflow
option can only generate SIGSEGV or SIGIOT. - If a pointer to invalid memory is passed to a kernel routine, the kernel routine will fail and usually return with errno set to EFAULT. If the application is not checking the return from the system call, this error might be undetected.
- debug_range
-
By default, if the
catch_overflow
option is enabled, buffer overflow detection is performed for every allocation in the program. If thedebug_range
option is specified, only allocation requests that fall between a user-defined minimum and maximum size will have buffer overflows detected by thecatch_overflow
option. Otherwise, no buffer overflow detection will be performed. This option allows the user to control the amount of extra memory resources consumed by thecatch_overflow
option by only using the tool in specific cases.Thedebug_range
option is only meaningful in the context of thecatch_overflow
option. It is enabled as follows:
where min is the lower bound and max is the upper bound of the range in which buffer overflow detection is to be performed. If 0 is specified as a minimum value, then anything that is less than the maximum value will have buffer overflow detection performed. If 0 is specified as a maximum value, then anything that is greater than the minimum value will have buffer overflow detection performed.MALLOCDEBUG=catch_overflow,debug_range:min:max
Limitation: Due to an internal implementation requirement, each allocation will still necessarily be at least a page size in length. Therefore the
debug_range
option merely reduces the overhead of thecatch_overflow
option rather than eliminating it.If the realloc subroutine is called with an allocation request that falls within the user-specified range , buffer overflow detection is performed even if the original allocation was not within the specified range. The reverse of this is also true.
Note: If theoverride_signal
option is set in conjunction with thedebug_range
option, the overriding of the SIGIOT and SIGSEGV signal behavior is performed for all allocations. - functionset
-
Due to an internal implementation requirement, each allocation will still necessarily be at least a page size in length. Therefore the
functionset
option merely reduces the overhead of thecatch_overflow
option rather than eliminating it.If the realloc subroutine is called from a function that is a member of the user-specified function list , buffer overflow detection is performed even if the original allocation was not made from a specified function. The reverse of this is also true.
Note: If theoverride_signal
option is set in conjunction with thefunctionset
option, the overriding of the SIGIOT and SIGSEGV signal behavior is performed for all allocations.The
functionset
option does not check the validity of the functions specified in the list. - allow_overreading
-
By default, when the
catch_overflow
debug option is enabled and the calling program attempts to read past the end of allocated memory, a segmentation violation will occur and the process will core dump. However, the user may not be interested in catching this type of error, and may have enabledcatch_overflow
in order to catch more dangerous overwrites. Specifying theallow_overreading
option will cause thecatch_overflow
option to ignore overreads so that other types of errors, which may be considered more serious, can be detected first.Theallow_overreading
option is only meaningful in the context of thecatch_overflow
option. It is enabled as follows:MALLOCDEBUG=catch_overflow,allow_overreading,
- postfree_checking
-
The
postfree_checking
option consumes a substantial amount of extra memory. Programs with very large memory requirements may not be able to use thepostfree_checking
option. - Malloc trace
-
Malloc Trace is a debugging option designed to allow tracing of all calls to the malloc subsystem API through the system trace facility.
- Mallow log
-
Malloc Log is a debugging option designed to provide the user with a runtime database of active allocations in the malloc subsystem.
- report_allocations
-
The
report_allocations
option is a tool for detecting memory leaks in an application program. Thereport_allocations
option uses the database constructed by Malloc Log to report a list of allocations currently held by the user. A record of each successful allocation is made at the time of the request by Malloc Log. When an allocation is deallocated, Malloc Log removes its record from the database. At process exit, the list of allocations still active is printed to stderr, giving a list of allocations that were never freed by their callers.Thereport_allocations
option requires the functionality of Malloc Log to work. Thus, Malloc Log is implicitly enabled whenreport_allocations
is enabled. Thereport_allocations
option is enabled as follows:MALLOCDEBUG=report_allocations
- validate_ptrs
-
By default, the malloc subsystem APIs do not validate their input pointers to ensure that they actually reference memory previously allocated. If one of these pointers is invalid, severe heap corruption can occur. Specifying the
validate_ptrs
option causes the malloc subsystem APIs to perform extensive validation on their input pointers. If a pointer is found to be invalid (that is, it does not reference memory previously allocated by a call to the malloc subsystem API), an error message stating why it is invalid is printed, the abort function is called, and a core file is produced. Thevalidate_ptrs
option is similar to theverbose
sub-option. Thevalidate_ptrs
option does not take effect if thepostfree_checking
option is enabled.Thevalidate_ptrs
option is enabled as follows:MALLOCDEBUG=validate_ptrs
- Malloc detect
-
Malloc Detect is a debugging option designed to detect and report corruption of the internal malloc subsystem data structures on every call to a malloc subsystem API.
- verbose
-
Sub-option of Malloc Detect.
- checkarena
-
Sub-option of Malloc Detect.
- output
-
By default, the malloc debugging options send their output to stderr. This may not be desired for all programs. The
output
option exists to provide an alternate destination for printed information. Output can be sent to either stderr, stdout, or to any file on the system.Theoutput
option is enabled as follows:MALLOCDEBUG=output:<filename>
- continue
-
Many malloc debugging options call abort() when they detect an error. This is not always the desired behavior for all programs. The
continue
option exists to instruct the malloc subsystem to continue after the detection of a synchronous error rather than to abort the process. Error messages will still be logged to the appropriate channels.Thecontinue
option is enabled as follows:MALLOCDEBUG=continue
- Malloc debug fill
-
Malloc debug fill is a debugging option designed to fill up the memory allocated through the malloc() calls with user specified pattern for debug purposes..
The pattern should be specified as a string (for example, export MALLOCDEBUG=fill:”abc” will set the memory allocated through malloc with the pattern “abc”) and a maximum of 128 characters is allowed. If the pattern is not specified, fill option is ignored.
The malloc debug fill option can be enabled as follows:
MALLOCDEBUG=fill:pattern
Pattern can be a octal or hexadecimal numbers specified in the form of a string. i.e the pattern “\101” , is treated as the octal notation for character ‘A’ and the pattern “\x41”, is treated as the hexadecimal notation for character ‘A’
If an invalid octal number is specified, for example \777 which cannot be contained within 1 byte, will be stored as \377, the maximum octal value that can be stored as 1 byte.