| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This next example illustrates how the mpatrol library is able to check to see if anything has been written into free memory. The test is located in `tests/fail/test4.c' and simply writes a single byte into free memory.
23 /*
24 * Allocates a block of 16 bytes and then immediately frees it. A
25 * NULL character is written into the middle of the freed memory.
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[8] = '\0';
40 }
41 return EXIT_SUCCESS;
42 }
|
The following output was produced as part of `mpatrol.log'. Note that this
test was run using the same MPATROL_OPTIONS settings as the last example,
but make sure that `PRESERVE' is not set.
ERROR: [FRDCOR]: freed allocation 0x08062F54 has memory corruption at 0x08062F5C
0x08062F5C 00555555 55555555 .UUUUUUU
0x08062F54 (16 bytes) {free:52:0} [main|test4.c|38]
0x08049456 main+70
0x4007C9CB __libc_start_main+255
0x08049381 _start+33
|
The library was able to detect that something had been written into free memory
and could report on the memory allocation that was overwritten. However, these
checks are only performed whenever a function in the mpatrol library is called
if the `CHECK' option is used, or at the end of program execution. In
the example above, the code which wrote into free memory could have been miles
away from where the library detected the error since we were not using the
`CHECK' option. However, adding `CHECK=-' to the
MPATROL_OPTIONS environment variable doesn't really help much since the
next mpatrol function that is called is the one to terminate the library anyway.
Note that using the `CHECK' option is equivalent to calling
__mp_check() when each mpatrol library function is called, or at the
range and frequency specified in the values passed to the `CHECK' option.
If you suspect that heap corruption is occurring in a part of your code where
there is a large gap between mpatrol library calls, you can try to narrow the
problem down by adding a few calls to __mp_check().
On platforms that support memory protection, the library also supports the `PAGEALLOC' option. This option instructs the library to force every single memory allocation to have a size which is a multiple of the system page size. Although the library still stores the original requested size, it effectively means that no two memory allocations occupy the same page of memory. It can then use page protection (which only operates on pages of memory) to protect all free memory from being read from or written to, and uses similar features to install a page of overflow buffer on either side of the allocation.
However, if the requested size for the memory allocation was not a multiple of the page size this means that there will still be unused space left over in the allocated pages. This problem is solved by turning the unused space into overflow buffers that will be checked in the normal way. The positioning of the allocation within its pages is also important. If you want to check for illegal reads from the borders of the memory allocation, unless it fits exactly into its pages then there is a chance that a program could illegally read the right-most overflow buffer if the allocation was left-aligned, or vice-versa. Two settings therefore exist for the `PAGEALLOC' option: `LOWER' and `UPPER'. They refer to the placement of every memory allocation within its constituent pages.
The following diagram illustrates the `PAGEALLOC' option. In the diagram, the system page size is assumed to be 16 bytes (very unlikely, but will serve for this example) and each character represents 1 byte.
x = allocated memory
o = overflow buffer (filled with the overflow byte)
. = overflow buffer page (read and write protected)
PAGEALLOC=LOWER, allocation size is 16 bytes or
PAGEALLOC=UPPER, allocation size is 16 bytes:
................xxxxxxxxxxxxxxxx................
PAGEALLOC=LOWER, allocation size is 8 bytes:
................xxxxxxxxoooooooo................
PAGEALLOC=UPPER, allocation size is 8 bytes:
................ooooooooxxxxxxxx................
|
In our original example, if the `PAGEALLOC=LOWER' option is added to the
MPATROL_OPTIONS environment variable then the following error will be
produced instead of the original error.
ERROR: [ILLMEM]: illegal memory access at address 0x081C6008
0x081C6000 (16 bytes) {free:52:0} [main|test4.c|38]
0x08049456 main+70
0x4007C9CB __libc_start_main+255
0x08049381 _start+33
call stack
0x0804945F main+79
0x4007C9CB __libc_start_main+255
0x08049381 _start+33
|
On systems that support memory protection, the mpatrol library has a built-in signal handler which catches illegal memory accesses and terminates the program. In the above case, the freed memory was made write-protected and so could not be written to. The underlying virtual memory system in the operating system noticed this and signaled this to the library immediately after it happened.
Along with the details of the freed memory allocation that was being written to, the library also attempts to display the function call stack for the location in the program that caused the illegal memory access, although this can be quite unreliable. A better solution would be to run the program in a debugger to catch the illegal memory access.
Note that the `PAGEALLOC' option also modifies the behaviour of the `NOFREE' and `PRESERVE' options when used together. The memory allocation being freed will always be made write-protected when the `PRESERVE' option is used, otherwise it will also be made read-protected to prevent further accesses.
Note also that the `PAGEALLOC=UPPER' option is potentially much less efficient at catching illegal memory accesses than the `PAGEALLOC=LOWER' option. This is due to alignment requirements, since an allocation of 1 byte requiring an alignment of 16 bytes cannot be placed at the very end of a page of size 4096 bytes. The following diagram illustrates this, using the same page size as the last diagram.
x = allocated memory
o = overflow buffer (filled with the overflow byte)
. = overflow buffer page (read and write protected)
PAGEALLOC=UPPER, allocation size is 16 bytes, alignment is 8 bytes:
................xxxxxxxxxxxxxxxx................
PAGEALLOC=UPPER, allocation size is 3 bytes, alignment is 1 byte:
................oooooooooooooxxx................
PAGEALLOC=UPPER, allocation size is 3 bytes, alignment is 8 bytes:
................ooooooooxxxooooo................
|
Everything is OK until the last allocation, where the alignment requirement means that there must be two overflow buffers. This slows down program execution since the library must check an additional overflow buffer, and also means that the program would have to read six bytes beyond the end of the allocation before the illegal memory access would be detected.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |