Next: , Previous: Example 1, Up: Examples


16.2 Detecting incorrect reuse of freed memory

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.