The next example uses tests/fail/test2.c to illustrate how the mpatrol library can detect whereabouts on the heap an address belongs.
23 /* 24 * Allocates a block of 16 bytes and then immediately frees it. An 25 * attempt is then made to double the size of the original block. 26 */ 29 #include "mpatrol.h" 32 int main(void) 33 { 34 char *p; 36 if (p = (char *) malloc(16)) 37 { 38 free(p); 39 p = (char *) realloc(p, 32); 40 } 41 return EXIT_SUCCESS; 42 }
The relevant excerpts from mpatrol.log appear below. The format of the log messages should be familiar to you now.
ALLOC: malloc (52, 16 bytes, 4 bytes) [main|test2.c|36] 0x0804942F main+31 0x4007C9CB __libc_start_main+255 0x08049381 _start+33 returns 0x080620E8 FREE: free (0x080620E8) [main|test2.c|38] 0x08049456 main+70 0x4007C9CB __libc_start_main+255 0x08049381 _start+33 0x080620E8 (16 bytes) {malloc:52:0} [main|test2.c|36] 0x0804942F main+31 0x4007C9CB __libc_start_main+255 0x08049381 _start+33 REALLOC: realloc (0x080620E8, 32 bytes, 4 bytes) [main|test2.c|39] 0x08049476 main+102 0x4007C9CB __libc_start_main+255 0x08049381 _start+33 ERROR: [NOTALL]: realloc: 0x080620E8 has not been allocated returns 0x00000000
The mpatrol library stores all of its information about allocated and free memory in tree structures so that it can quickly determine if an address belongs to allocated or free memory, or if it even exists in the heap that is managed by mpatrol. The above example should illustrate this since after the allocation had been freed, the library recognised this and reported an error. It was possible for the program to continue execution even after that error since mpatrol could recover from it and return `NULL'.
It is possible for mpatrol to give even more useful diagnostics in the above situation by using the NOFREE option. This prevents the library from returning any freed allocations to the free memory pool, by preserving any information about them and marking them as freed. If you add the NOFREE=1 option to the MPATROL_OPTIONS environment variable you should see the following entries in mpatrol.log instead.
ALLOC: malloc (52, 16 bytes, 4 bytes) [main|test2.c|36] 0x0804942F main+31 0x4007C9CB __libc_start_main+255 0x08049381 _start+33 returns 0x08062F54 FREE: free (0x08062F54) [main|test2.c|38] 0x08049456 main+70 0x4007C9CB __libc_start_main+255 0x08049381 _start+33 0x08062F54 (16 bytes) {malloc:52:0} [main|test2.c|36] 0x0804942F main+31 0x4007C9CB __libc_start_main+255 0x08049381 _start+33 REALLOC: realloc (0x08062F54, 32 bytes, 4 bytes) [main|test2.c|39] 0x08049476 main+102 0x4007C9CB __libc_start_main+255 0x08049381 _start+33 ERROR: [PRVFRD]: realloc: 0x08062F54 was freed with free 0x08062F54 (16 bytes) {free:52:0} [main|test2.c|38] 0x08049456 main+70 0x4007C9CB __libc_start_main+255 0x08049381 _start+33 returns 0x00000000
Note the extra information reported by realloc()
since the library knows
all of the details about the freed memory allocation and when it was freed.
The NOFREE option can potentially use up much more system memory than normal if it is given a large numerical argument since it effectively instructs the mpatrol library to allocate new memory for every single memory allocation or reallocation. It can also slow down program execution when overflow buffers are used, since with each new memory allocation the library needs to check more and more overflow buffers every time it is called. However, with a low numerical argument it can be quite useful for problems such as this one. The test in tests/fail/test3.c has a similar situation.
The numerical argument specified with the NOFREE option indicates the number of recently-freed memory allocations that are to be delayed from being returned to the free memory pool, with a value of zero meaning that all freed memory allocations will immediately be reused. Obviously, in an ideal world it would be nice to be able to specify NOFREE=huge-number all the time, but this will gradually use up more and more memory since no system heap memory will ever be reused. Supplying a smaller number to the NOFREE option allows you to make a compromise by storing the details of only the most recently-freed memory allocations. How many details you wish to store is up to you.
Normally, the NOFREE option will cause the library to fill all freed memory allocations with the free byte. However, the original contents of such allocations can be preserved with the PRESERVE option. This could help in situations when you need to determine exactly if a program is relying on the contents of freed memory.