In this section:
Overview
This error is generated when a dynamic memory block has become corrupt. Usually, the corruption is the result of a WRITE_OVERFLOW or WRITE_BAD_INDEX. This error is most often detected as the memory is being returned to the system.
Insure++ uses guard zones around dynamically allocated memory to help detect heap corruption that is otherwise difficult or impossible to discover. This feature can be turned on or off in the .psrc file. Dynamic memory heap is corruptCode Description Enabled Reported Platform HEAP_CORRUPT Runtime Windows/Unix
Problem
The following code will generate a WRITE_BAD_INDEX and a subsequent HEAP_CORRUPT:
/* *File: heapcrpt.c */ void scribble(char* p) { *p = ‘a’; } int main() { char* string = (char*) malloc(10); scribble(string+10); free(string); return 0; }
Diagnosis at Runtime
[heapcrpt.c:14] **HEAP_CORRUPT** >> free(string); The heap is corrupt. ---- Associated Common Weakness Enumerations ---- CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer CWE-122: Heap-based buffer overflow CWE-415: Double free CWE-416: Use after free CWE-590: Free of memory not on the heap CWE-786: Access of memory before start of buffer CWE-787: Out-of-bounds write CWE-788: Access of memory location after end of buffer CWE-805: IBuffer access with incorrect length value bbbbbb | 10 | 16 | xggggggg Guardzone : 0x0804b022 thru 0x0804b031 (16 bytes) Expected (g) : fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Found (x) : 61 fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa a . . . . . . . . . . . . . . . Near Block (b) : 0x0804b018 thru 0x0804b021 (10 bytes) string, allocated at heapcrpt.c, 12 malloc() (interface) main() heapcrpt.c, 12 Stack trace where memory was freed: free() (interface) main() heapcrpt.c, 14 Stack trace where error was detected: free() (interface) main() heapcrpt.c, 14 **Memory corrupted. Program may crash!!**
- Line 2: Source line at which the problem was detected.
- Line 3: Description of the problem.
- Line 5-14: CWEs associated with this problem.
- Line 16: Schematic showing the relative layout in memory of the block and the corrupted guard zone.
- Line 19: Range of corrupted memory showing the guard zone, the expected memory pattern, and the pattern that was found instead.
- Line 23: The memory block that is most likely the one that has been corrupted and the stack trace of its allocation.
- Line 27: The stack trace where the memory was freed, (may or may not be present).
- Line 30: The stack trace showing the call sequence to the error.
- Line 33: Informational message indicating that a serious error has occurred, which may cause the program to crash.
Repair
Look for previous WRITE_OVERFLOW or WRITE_BAD_INDEX errors—they might lead you to this particular error. If there aren't any, that means that the heap became corrupt in some uninstrumented code. Carefully examine all functions in all of the stack back traces to try to find the source of the problem.
Use a debugger to set a break point at the allocation location, then a watchpoint on the guardzone area which became corrupt. For example, in the sample code above, a watchpoint could be set on the memory at address 0x804b022
. When the breakpoint "fires", you've found the bug.
The following example uses Linux's gcc and gdb:
$ insure gcc -g -Zoi 'function_ignore scribble' heapcrpt.c -o heapcrpt /"-Zoi 'function_ignore scribble'", causes the function "scribble()" to be ignored -- ie: no instrumentation will be generated for it./ $ ./heapcrpt [heapcrpt.c:14] **HEAP_CORRUPT** >> free(string); The heap is corrupt. bbbbbb | 10 | 16 | xggggggg Guardzone : 0x0804b022 thru 0x0804b031 (16 bytes) Expected (g) : fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Found (x) : 61 fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa a . . . . . . . . . . . . . . . Near Block (b) : 0x0804b018 thru 0x0804b021 (10 bytes) string, allocated at heapcrpt.c, 12 malloc() (interface) main() heapcrpt.c, 12 stack trace where memory was freed: free() (interface) main() heapcrpt.c, 14 Stack trace where error was detected: free() (interface) main() heapcrpt.c, 14 **Memory corrupted. Program may crash!!** $
To figure out what happened, look at GDB:
$ gdb heapcrpt (gdb) b heapcrpt.c:12 (gdb) r Breakpoint 1, main () at heapcrpt.c:12 12 char* string = (char*) malloc(10);
The memory is about to be allocated. Be sure that it's getting allocated correctly:
(gdb) n 13 scribble(string+10); (gdb) p/x *(char*)0x0804b022 $1 = 0xfa
If the guard zone has the right pattern in it (as shown above), set a watchpoint on this memory location:
(gdb) watch *(int*)0x0804b022 Hardware watchpoint 1: *(int *) 134524962 (gdb) c Hardware watchpoint 1: *(int *) 134524962 Old value = -84215046 New value = -84215199 scribble (p=0x804b022 "a", 'ú' <repeats 15 times>) at heapcrpt.c:8 8 }
If you examine the source code immediately before the location where the watchpoint stopped, you can see the following:
(gdb) list */ void scribble(char* p) { *p = 'a'; }
The code shows that the memory became corrupt on line 7. To examine the backtrace to see how you got there:
(gdb) bt #0 scribble (p=0x804b022 "a", 'ú' <repeats 15 times>) at heapcrpt.c:8 #1 0x08049008 in main () at heapcrpt.c:13
Careful examination of line 13 of the file heapcrpt shows the problem: Wrong string offset sent down to function scribble()
.
References
The table below shows Common Weakness Enumerations associated with this error.
CWE | Description |
---|---|
CWE-119 | Improper Restriction of Operations within the Bounds of a Memory Buffer |
CWE-122 | Heap-based buffer overflow |
CWE-415 | Double free |
CWE-416 | Use after free |
CWE-590 | Free of memory not on the heap |
CWE-786 | Access of memory before start of buffer |
CWE-787 | Out-of-bounds write |
CWE-788 | Access of memory location after end of buffer |
CWE-805 | IBuffer access with incorrect length value |