Next: , Previous: Example 5, Up: Examples


16.6 Bad memory operations

In C there are several basic memory operation functions that are often called to perform tasks such as clearing memory, copying memory, etc. The mpatrol library contains replacements for these which allow for better checking of their arguments to prevent reading and writing past the boundaries of existing memory allocations. The following source can be found in tests/fail/test9.c.

     23  /*
     24   * Allocates a block of 16 bytes and then attempts to zero the contents of
     25   * the block.  However, a zero byte is also written 1 byte before and 1
     26   * byte after the allocated block, resulting in an error in the log file.
     27   */
     
     
     30  #include "mpatrol.h"
     
     
     33  int main(void)
     34  {
     35      char *p;
     
     37      if (p = (char *) malloc(16))
     38      {
     39          memset(p - 1, 0, 18);
     40          free(p);
     41      }
     42      return EXIT_SUCCESS;
     43  }

When this is compiled and run, the following should appear in the log file.

     ERROR: [RNGOVF]: memset: range [0x08062FB7,0x08062FC8] overflows
                      [0x08062FB8,0x08062FC7]
         0x08062FB8 (16 bytes) {malloc:52:0} [main|test9.c|37]
             0x0804942F main+31
             0x4007C9CB __libc_start_main+255
             0x08049381 _start+33

As you can see, the library detected that the memset() function would have written past the boundaries of the memory allocation and reported this to you. It then proceeded to ignore the request to copy the memory and continued with the execution of the program1. Note that this will only be done for known memory allocations. Reading and writing past the boundaries of static and stack memory allocations cannot be detected in this way.

If the LOGMEMORY option is added to the MPATROL_OPTIONS environment variable then it is possible to see a log of all the mpatrol library memory operation functions that were called during program execution. For example, adding this option and running the above program again will produce something similar to the following.

     MEMSET: memset (0x08062FB7, 18 bytes, 0x00) [main|test9.c|39]
             0x0804945B main+75
             0x4007C9CB __libc_start_main+255
             0x08049381 _start+33

This is similar to the tracing produced for memory allocation functions, except that the arguments in parentheses mean different things. For `MEMSET', the first argument represents the start of the memory block to set, the second argument represents the number of bytes to set and the third argument represents the actual byte to set.

For `MEMCOPY', the first argument represents the source memory block, the second argument represents the destination memory block, the third argument represents the number of bytes to copy and the fourth argument represents a byte to copy up to if memccpy() is being called. This is similar for `MEMCMP'.

For `MEMFIND', the first and second arguments represent the source memory block and its length, while the third and fourth arguments represent the memory block to search for and its length. In the implementation for memchr(), the byte to search for is copied to a one byte buffer and the address of that buffer is used as the memory block to search for.

Note that as with the memory allocation functions, `MEMCMP', `MEMFIND', `MEMCOPY' and `MEMSET' are used to generalise the types of operations being performed and are followed by the names of the actual functions being used. In some cases the functions may use a different ordering of parameters than that shown.


Footnotes

[1] The error can be turned into a warning with the ALLOWOFLOW option which will also force the operation to be performed.