LAL  7.5.0.1-08ee4f4

Detailed Description

Provides standard LAL memory allocation/deallocation routines.

Synopsis

#include <lal/LALMalloc.h>

This header covers routines that replace the standard malloc(), calloc(), realloc(), and free(). All memory allocation and deallocation in LAL should use these replacement functions. If the LAL_MEMORY_FUNCTIONS_DISABLED flag is set in LALConfig.h, the LAL routines are #defined to be the same as the standard C routines.

Macros

#ifdef LAL_MEMORY_FUNCTIONS_DISABLED
#define LALMalloc malloc
#define LALMallocShort malloc
#define LALMallocLong( n, file, line ) malloc( n )
#define LALCalloc calloc
#define LALCallocShort calloc
#define LALCallocLong( m, n, file, line ) calloc( m, n )
#define LALRealloc realloc
#define LALReallocShort realloc
#define LALReallocLong( p, n, file, line ) realloc( p, n )
#define LALFree free
#define LALCheckMemoryLeaks()
#else
#define LALMalloc( n ) LALMallocLong( n, __FILE__, __LINE__ )
#define LALCalloc( m, n ) LALCallocLong( m, n, __FILE__, __LINE__ )
#define LALRealloc( p, n ) LALReallocLong( p, n, __FILE__, __LINE__ )
#endif

Description

Note:
As the LALxxx() interface is deprecated, it is recommended to use the corresponding XLALxxx() functions instead, which follow exactly the same API as the functions described in the following.

These functions are the LAL replacements for malloc(), calloc(), realloc(), and free(), with extra functionality to check for memory leaks (i.e. unfreed memory and segmentation violations). The LALMallocLong(), LALCallocLong(), and LALReallocLong() functions have two extra arguments giving the file name and line number of the calling statement; LALMallocShort(), LALCallocShort(), and LALReallocShort() do not have these extra arguments, and are merely call the corresponding long alloc functions with a file name of "unknown" and a line number of -1 (they are useful if you want to replace hooks to malloc(), calloc(), and realloc() of an external package that provides suitable hooks). LALMalloc(), LALCalloc(), and LALRealloc() are actually macros which call the functions LALMallocLong(), LALCallocLong(), and LALReallocLong with the appropriate file name and line number information. In practice, it is almost sufficient to use LALMalloc(), LALCalloc(), and LALRealloc() as you would malloc(), calloc(), and realloc().

Any time an object is freed, LALFree() checks to make sure that the memory bounds were not over-written, and that the memory address is valid. The function LALCheckMemoryLeaks() is to be called at the end of a program when all the allocated memory is expected to have been freed. If there is memory that has been allocated but not freed then this routine reports an error. Whenever a memory leak is detected, the routines raise a segmentation violation signal SIGSEGV. (The signal is raised using the signal raising hook lalRaiseHook, which can be reset to a different handler if desired.)

Memory leak detection adds significant computational overhead to a program. It also requires the use of static memory, making the code non-thread-safe (but it can be made posix-thread-safe using the –enable-pthread-lock configure option). Production code should suppress memory leak detection at runtime by setting the global lalDebugLevel equal to zero or by setting the LALNMEMDBG bit of lalDebugLevel. In addition, you can turn off individual components of the memory debugging tools. Setting the LALNMEMPAD bit of lalDebugLevel prevents the allocation routines from "padding out" the arrays in an effort to detect buffer overflows. Setting the LALNMEMTRK bit of lalDebugLevel prevents tracking the allocations/frees. Setting the LALMEMINFO bit of lalDebugLevel produces copious output describing each memory allocation and deallocation.

If one wishes to completely disable the LAL routines, one can configure LAL with the –disable-memory-functions option, which sets the LAL_MEMORY_FUNCTIONS_DISABLED flag in LALConfig.h. This causes LALCheckMemoryLeaks() to do nothing, and the other functions to revert to their standard C counterparts.

Algorithm

When buffer overflow detection is active, LALMalloc() allocates, in addition to the requested memory, storage at the beginning of the object where a magic number and the size of the object is recorded, and padding at the end of the object. The number of allocations and the total size of allocated memory are stored in static memory. When LALFree() is executed, the padding at the end of the object and the magic number are examined to see if the bounds of the object were over-written. The total number of allocations and the total memory allocated are decreased. LALCheckMemoryLeaks() is called when all memory should have been freed. If the number of allocations or the total memory allocated is not zero, this routine reports an error.

When memory tracking is active, LALMalloc() keeps a linked list containing information about each allocation: the memory address, the size of the allocation, and the file name and line number of the calling statement. Subsequent calls to LALFree() make sure that the address to be freed was correctly allocated. In addition, in the case of a memory leak in which some memory that was allocated was not freed, LALCheckMemoryLeaks() prints a list of all allocations and the information about the allocations.

When any of these routines encounter an error, they will issue an error message using LALPrintError() and will raise a SIGSEGV signal, which will normally cause execution to terminate. The signal is raised using the hook lalRaiseHook, which can be set to perform a different action if desired.

These routines also issue status messages indicating how much memory is being allocated or freed with each function call. These memory information messages are considered a distinct class of status message, and can be activated or suppressed independently of other status messages. See the discussion in LALStatusMacros.h.

When lalDebugLevel is set to zero or the LALNMEMDBG bit is set, or when compiled with the LAL_MEMORY_FUNCTIONS_DISABLED flag set, these functions revert to their standard system versions, and LALCheckMemoryLeaks() does nothing.

Notes

Memory leak detection only occurs when lalDebugLevel \(\neq0\). To turn on leak detection independent of error reporting, simply switch on the most-significant bit of lalDebugLevel, which is reserved not to be associated with any type of status message. See the discussion in LALStatusMacros.h for more information about lalDebugLevel.

It is assumed that pointers of type size_t * have the most restrictive alignment. If this is not true, then this code may not work except in non-debugging mode. (It will probably produce bus errors.)

Debugging memory leak tips

Programs should end by calling LALCheckMemoryLeaks(). This will ensure that all memory that has been allocated has been freed. Making sure that all memory allocated is freed is a good idea in order to make sure (i) that memory isn't being "lost" (which may mean that the computer will run out of memory when the program is run under more extensive use), (ii) that array bounds are not being exceeded (since this will usually overwrite the pad area at the end of the array, and this overwrite is detected when the array is freed). LALCheckMemoryLeaks() should pass silently—if it doesn't, then there is probably some memory that has not been freed; LALCheckMemoryLeaks() will give information about where this memory was allocated.

The most common problem (after forgetting to free some memory) is overwriting of array bounds. When this is detected, LALFree() reports the memory address that was overwritten, as well as the address of the array that LALFree() attempted to free. In order to find out where the overwrite occurs, run the program in the debugger and stop the execution as soon as the array that is being overwritten has been allocated. The LALMalloc module has some secret memory debugging tools (for use in debugging only!). One is the global variable lalMemDbgUsrPtr, which is of type char *. Set this variable to be equal to the memory address where the overwrite occurs. Then watch the contents of the variable to find out where the overwrite occurs. This is done in gdb using the commands:

set var lalMemDbgUsrPtr=0x20f530
watch *lalMemDgbUsrPtr
cont
char * lalMemDbgUsrPtr
Definition: LALMalloc.c:248

where 0x20f530 is the corrupted memory address. The program will run until the value of this address is changed, thereby allowing you to find out where in the program the overwrite occurs.

If you don't know where the memory was allocated, you can locate this too. To do so, set lalMemDbgUsrPtr to be the address of the array. Then, every time LALMalloc() is called, it sets the value of the global variable lalIsMemDbgRetPtr to be one zero if the array address produced by LALMalloc() is not the address in lalMemDbgUsrPtr, and one if it is. Then you can watch the value of lalIsMemDbgRetPtr in a debugger until it changes to one, which stops execution at that point. (Note: it is possible that a given address is allocated, then freed, the allocated again—you may need to watch lalIsMemDbgRetPtr for a while.)

Here's an example debugging session: first we run the program, identify the address of the array whose bounds are being overwritten, and find out where that array is allocated.

(gdb) run
LALFree error: array bounds overwritten
Byte 4 past end of array has changed
Corrupted address: 0x1cf530
Array address: 0x1cf528
Program received signal SIGSEGV, Segmentation fault.
0x9001b46c in kill ()
(gdb) list 1,11
1 #include <lal/LALStdlib.h>
2 int main( void )
3 {
4 char *s;
6 s = LALMalloc( 5 );
7 s[8] = 'x';
8 LALFree( s );
10 return 0;
11 }
(gdb) break 5
Breakpoint 1 at 0x1b60: file bad.c, line 5.
(gdb) run
Breakpoint 1, main () at bad.c:5
(gdb) set var lalMemDbgUsrPtr = 0x1cf528
(gdb) watch lalIsMemDbgRetPtr
Hardware watchpoint 2: lalIsMemDbgRetPtr
(gdb) cont
Continuing.
Hardware watchpoint 2: lalIsMemDbgRetPtr
Old value = 0
New value = 1
0x0088d63c in LALMallocLong (n=5, file=0x1ff8 "bad.c", line=6) at LALMalloc.c:575
(gdb) up
#1 0x00001b84 in main () at bad.c:6
6 s = LALMalloc( 5 );
int lalIsMemDbgRetPtr
Definition: LALMalloc.c:251
char * lalMemDbgRetPtr
Definition: LALMalloc.c:246
int lalIsMemDbgPtr
Definition: LALMalloc.c:252
void LALCheckMemoryLeaks(void)
Definition: LALMalloc.c:784
#define LALMalloc(n)
Definition: LALMalloc.h:93
#define LALFree(p)
Definition: LALMalloc.h:96
static REAL8TimeSeries * error(const REAL8TimeSeries *s1, const REAL8TimeSeries *s0)
int main(int argc, char *argv[])
Definition: cache.c:25
void * LALMallocLong(size_t n, const char *file, int line)
Definition: LALMalloc.c:624

So here is where the memory is allocated. We want to find out where the memory is being corrupted.

(gdb) set var lalMemDbgUsrPtr = 0x1cf530
(gdb) watch *lalMemDbgUsrPtr
Hardware watchpoint 3: *lalMemDbgUsrPtr
(gdb) cont
Continuing.
Hardware watchpoint 3: *lalMemDbgUsrPtr
Old value = -25
New value = 120 'x'
main () at bad.c:8
8 LALFree( s );
(gdb) list
3 {
4 char *s;
6 s = LALMalloc( 5 );
7 s[8] = 'x';
8 LALFree( s );
10 return 0;
11 }

Notice that the program has stopped just after the line in which the array bounds were overwritten.

Prototypes

void * XLALMalloc (size_t n)
 
void * XLALMallocLong (size_t n, const char *file, int line)
 
void * XLALCalloc (size_t m, size_t n)
 
void * XLALCallocLong (size_t m, size_t n, const char *file, int line)
 
void * XLALRealloc (void *p, size_t n)
 
void * XLALReallocLong (void *p, size_t n, const char *file, int line)
 
void XLALFree (void *p)
 
void XLALFreeLong (void *p, const char *file, const int line)
 
void * LALMallocShort (size_t n)
 
void * LALMallocLong (size_t n, const char *file, int line)
 
void * LALCallocShort (size_t m, size_t n)
 
void * LALCallocLong (size_t m, size_t n, const char *file, int line)
 
void * LALReallocShort (void *p, size_t n)
 
void * LALReallocLong (void *p, size_t n, const char *file, int line)
 
void LALFreeShort (void *p)
 
void LALFreeLong (void *p, const char *file, int line)
 

Macros

#define XLALMalloc(n)   XLALMallocLong( n, __FILE__, __LINE__ )
 
#define XLALCalloc(m, n)   XLALCallocLong( m, n, __FILE__, __LINE__ )
 
#define XLALRealloc(p, n)   XLALReallocLong( p, n, __FILE__, __LINE__ )
 
#define XLALFree(p)   XLALFreeLong( p, __FILE__, __LINE__ )
 

Files

file  LALMallocPerf.c
 Tests the performance of the routines in Header LALMalloc.h.
 
file  LALMallocTest.c
 Tests the routines in Header LALMalloc.h.
 

Variables

size_t lalMallocTotal
 current amount of memory allocated by process More...
 
size_t lalMallocTotalPeak
 peak amount of memory allocated so far More...
 

Function Documentation

◆ XLALMalloc()

void* XLALMalloc ( size_t  n)

Definition at line 70 of file LALMalloc.c.

◆ XLALMallocLong()

void* XLALMallocLong ( size_t  n,
const char *  file,
int  line 
)

Definition at line 77 of file LALMalloc.c.

◆ XLALCalloc()

void* XLALCalloc ( size_t  m,
size_t  n 
)

Definition at line 85 of file LALMalloc.c.

◆ XLALCallocLong()

void* XLALCallocLong ( size_t  m,
size_t  n,
const char *  file,
int  line 
)

Definition at line 92 of file LALMalloc.c.

◆ XLALRealloc()

void* XLALRealloc ( void *  p,
size_t  n 
)

Definition at line 100 of file LALMalloc.c.

◆ XLALReallocLong()

void* XLALReallocLong ( void *  p,
size_t  n,
const char *  file,
int  line 
)

Definition at line 106 of file LALMalloc.c.

◆ XLALFree()

void XLALFree ( void *  p)

Definition at line 113 of file LALMalloc.c.

◆ XLALFreeLong()

void XLALFreeLong ( void *  p,
const char *  file,
const int  line 
)

◆ LALMallocShort()

void* LALMallocShort ( size_t  n)

Definition at line 617 of file LALMalloc.c.

◆ LALMallocLong()

void* LALMallocLong ( size_t  n,
const char *  file,
int  line 
)

Definition at line 624 of file LALMalloc.c.

◆ LALCallocShort()

void* LALCallocShort ( size_t  m,
size_t  n 
)

Definition at line 652 of file LALMalloc.c.

◆ LALCallocLong()

void* LALCallocLong ( size_t  m,
size_t  n,
const char *  file,
int  line 
)

Definition at line 660 of file LALMalloc.c.

◆ LALReallocShort()

void* LALReallocShort ( void *  p,
size_t  n 
)

Definition at line 690 of file LALMalloc.c.

◆ LALReallocLong()

void* LALReallocLong ( void *  p,
size_t  n,
const char *  file,
int  line 
)

Definition at line 697 of file LALMalloc.c.

◆ LALFreeShort()

void LALFreeShort ( void *  p)

Definition at line 758 of file LALMalloc.c.

◆ LALFreeLong()

void LALFreeLong ( void *  p,
const char *  file,
int  line 
)

Definition at line 764 of file LALMalloc.c.

Macro Definition Documentation

◆ XLALMalloc

#define XLALMalloc (   n)    XLALMallocLong( n, __FILE__, __LINE__ )

Definition at line 44 of file LALMalloc.h.

◆ XLALCalloc

#define XLALCalloc (   m,
 
)    XLALCallocLong( m, n, __FILE__, __LINE__ )

Definition at line 45 of file LALMalloc.h.

◆ XLALRealloc

#define XLALRealloc (   p,
 
)    XLALReallocLong( p, n, __FILE__, __LINE__ )

Definition at line 46 of file LALMalloc.h.

◆ XLALFree

#define XLALFree (   p)    XLALFreeLong( p, __FILE__, __LINE__ )

Definition at line 47 of file LALMalloc.h.

Variable Documentation

◆ lalMallocTotal

size_t lalMallocTotal
extern

current amount of memory allocated by process

Definition at line 38 of file LALMalloc.c.

◆ lalMallocTotalPeak

size_t lalMallocTotalPeak
extern

peak amount of memory allocated so far

Definition at line 39 of file LALMalloc.c.