_FINDING RUN-TIME MEMORY ERRORS_ by Taed Nelson Figure 2: Test.c, a sample program with two errors. 1 #include 2 #include 3 4 const char *Hello = "Hello, world!"; 5 6 int main (int argc, char *argv[]) 7 { 8 char *string; 9 10 /* Allocate memory, but we forgot the null character. */ 11 string = (char *) malloc (strlen (Hello)); 12 13 /* Copy, but it will copy the last byte into unallocated memory. */ 14 strcpy (string, Hello); 15 16 /* Leave, but we didn't free() string. */ 17 return (0); 18 } [LISTING ONE] /* Copy the entire string from source to destination. */ /* Return the number of characters copied. */ unsigned int stringCopy (char *destination, const char *source) { unsigned int length; while ((*(destination++) = *(source++)) != '\0') { length++; } return (length); } int main () { char *string; stringCopy (string, "Hello world!"); exit (0); } [LISTING TWO] Purify'd string (pid 12837) Purify 2 (C) 1990-93 Pure Software Inc. Patents Pending. Contact us at: support@pure.com or (408) 720 1600. In Europe: support@pts.co.uk or (+44) 61 776 4499. Purify checking enabled. **** Purify'd string (pid 12837) **** Purify (umr): uninitialized memory read: * This is occurring while in: main [line 19, ~nelson/Papers/string1.c, pc=0x19ad4] start [crt0.o, pc=0x2064] * Reading 4 bytes from 0xf7fff8a4 on the stack This is local variable "string" in function main. **** Purify'd string (pid 12837) **** Purify (cor): Received signal 11 SIGSEGV (segmentation violation, signal bit = 0x00000400), may dump core: * This is occurring while in: etext [/n/share/src/gnu/gcc/gcc-2.3.2/libgcc2.c, pc=0x85720] main [line 19, ~nelson/Papers/string1.c, pc=0x19ae8] start [crt0.o, pc=0x2064] * Handler function: SIG_DFL * Current signals: 0x00000400 (SIGSEGV) * Pending signals: 0x00000000 [LISTING THREE] int main (void) { char *string; string = (char *) malloc (20); stringCopy (string, "Hello world!"); exit (0); } [LISTING FOUR] Purify (umr): uninitialized memory read: * This is occurring while in: stringCopy [line 8, ~nelson/Papers/string2.c, pc=0x21744] main [line 21, ~nelson/Papers/string2.c, pc=0x217dc] start [crt0.o, pc=0x2064] * Reading 4 bytes from 0xf7fff814 on the stack This is local variable "length" in function stringCopy. **** Purify'd string (pid 12878) **** * 1 access error. * Basic memory usage: 262136 code 273000 data/bss 16392 heap 1864 stack * Shared library memory usage: 696320 libc_pure_200.so.1.8 (shared code) 16384 libc_pure_200.so.1.8 (private data) 8192 libinternal_stubs.so.1.0 (shared code) 8192 libinternal_stubs.so.1.0 (private data) [LISTING FIVE] #include /* Copy the entire string from source to destination. */ /* Return the number of characters copied. */ unsigned int stringCopy (char *destination, const char *source) { unsigned int length = 0; while ((*(destination++) = *(source++)) != '\0') { length++; } return (length); } int main (void) { char *string; string = (char *) malloc (20); stringCopy (string, "Hello world!"); stringCopy (string, "supercalifragilisticexpialidocious"); stringCopy (string, ""); stringCopy (NULL, NULL); exit (0); } [LISTING SIX] **** Purify'd string (pid 13077) **** Purify (abw): array bounds write (15 times): * This is occurring while in: stringCopy [line 9, ~nelson/Papers/string3.c, pc=0x21730] main [line 24, ~nelson/Papers/string3.c, pc=0x21824] start [crt0.o, pc=0x2064] ==== At first occurrence: ==== * Writing 1 byte to 0x85774 in the heap 1 byte past end of a malloc'd block at 0x85760 of 20 bytes * This block was allocated by malloc called from: main [line 21, ~nelson/Papers/string3.c, pc=0x217e8] start [crt0.o, pc=0x2064] **** Purify'd string (pid 13077) **** Purify (npr): null pointer read: reading 1 byte from 0x0 * This is occurring while in: stringCopy [line 9, ~nelson/Papers/string3.c, pc=0x21724] main [line 26, ~nelson/Papers/string3.c, pc=0x21850] start [crt0.o, pc=0x2064] **** Purify'd string (pid 13077) **** Purify (cor): Received signal 11 SIGSEGV (segmentation violation, signal bit = 0x00000400), may dump core: * This is occurring while in: etext [~nelson/Papers/string3.c, pc=0x85778] main [line 26, ~nelson/Papers/string3.c, pc=0x21850] start [crt0.o, pc=0x2064] [LISTING SEVEN] #include #define MAX_STRING 100 const char *StringList[] = { "Hello world!", "supercalifragilisticexpialidocious", "", NULL }; /* Copy the entire string from source to destination. */ /* Return the number of characters copied. */ unsigned int stringCopy (char *destination, const char *source, unsigned int size) { unsigned int length = 0; if ((source == NULL) || (destination == NULL)) { return (0); } while ((length < size) && ((*(destination++) = *(source++)) != '\0')) { length++; } return (length); } int main (void) { const char **example; char *string; /* Test all of the example strings in StringList. */ for (example = StringList; *example != NULL; example++) { string = (char *) malloc (MAX_STRING); stringCopy (string, *example, MAX_STRING); printf ("The copied string is \"%s\".\n", string); } exit (0); } [LISTING EIGHT] Purify: Searching for all memory leaks... There are 200 leaked bytes (44.6% of the 448 allocated bytes in the heap) 100 bytes (2 times). Last memory leak at 0x858d0 Report (mlk): 200 total bytes lost, malloc called from: main [line 38, ~nelson/Papers/string4.c, pc=0x218a0] start [crt0.o, pc=0x2064] Purify Heap Analysis (combining suppressed and unsuppressed chunks) Chunks Bytes Leaked 2 200 Potentially Leaked 0 0 In-Use 3 248 ---------------------------------------- Total Allocated 5 448 [LISTING NINE] void tzload (void) { ... sp->chars = (char *) calloc ((unsigned) sp->charcnt, ... for (i = 0; i < sp->charcnt; i++) sp->chars[i] = *p++; sp->chars[i] = '\0'; ... } [LISTING TEN] int main () { unsigned int data; data |= 0x01; printf ("%u\n", data); exit (0); } [LISTING ELEVEN] Purify'd test (pid 11557 at Sat Aug 14 09:53:44 1993) Purify 2.1.0 SunOS 4.1, Copyright 1992, 1993 Pure Software Inc. For contact information type: "purify -help" Purify licensed to Pure Software Central **** Purify'd test (pid 11557) **** Purify (abw): array bounds write: * This is occurring while in: strcpy [p9.o, pc=0xcf0c] main [line 14, test.c, pc=0x1b394] start [interface.c, pc=0x2064] * Writing 14 bytes to 0xc2ff0 in the heap (1 byte at 0xc2ffd illegal). * This is at the beginning of a malloc'd block of 13 bytes. * This block was allocated from: malloc [p6.o, pc=0x46d4] main [line 11, test.c, pc=0x1b36c] start [interface.c, pc=0x2064] **** Purify'd test (pid 11557) **** Purify: Searching for all memory leaks... There are 13 leaked bytes (100% of the 13 allocated bytes in the heap) Purify (mlk): 13 bytes at 0xc2ff0 lost, allocated from: malloc [p6.o, pc=0x46d4] main [line 11, test.c, pc=0x1b36c] start [interface.c, pc=0x2064] Purify Heap Analysis (combining suppressed and unsuppressed chunks) Chunks Bytes Leaked 1 13 Potentially Leaked 0 0 In-Use 0 0 ---------------------------------------- Total Allocated 1 13 **** Purify'd test (pid 11557) **** * Program exited with status code 1. * 1 access error. * Basic memory usage: 311288 code 475976 data/bss 16392 heap 2888 stack * Shared library memory usage: 696320 libc_pure_210.so.1.8 (shared code) 16384 libc_pure_210.so.1.8 (private data) 8192 libinternal_stubs.so.1.0 (shared code) 8192 libinternal_stubs.so.1.0 (private data) [LISTING TWELVE] The SENTINEL Debugging Environment, Version 1.4.0.10 (c) Copyright 1992,1993 Virtual Technologies, Inc. Error Output from: /t/cpcahil/./test Running on: rama SENTINEL: Warning [14]: An attempt was made to access data beyond the end of an allocated data section. The program attempted to write 14 bytes to location 0x896A8. That address is at offset 0 in the 13 byte data area that starts at location 0x896A8 (there is only room to write 13 bytes). Reading symbol table...Sun format...................Done This problem was detected at the following location: strcpy() [string.c:744] main() [test.c:14] This problem is *probably* associated with a 13 byte data area allocated on the 5th call to malloc() which returned 0x896A8. The context of the call to malloc() was as follows: malloc() [allocext.c:150] main() [test.c:11] *********************** SENTINEL: LIST OF MEMORY LEAKS ********************** POINTER STAT LOCATION ALLOC NUMBER TOTAL DATA TO DATA WHERE ALLOCATED FUNCT LEAKS LEAKED -------- ---- --------------------------------- -------------- ------ ---------- 0x0896A8 **** main() [test.c:11] malloc(5) 1 13 [LISTING THIRTEEN] **WRITE_OVERFLOW** [orig.c:15] >> strcpy (string, Hello); Writing overflows memory: string bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | 13 | 1 | wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww Writing (w) : 0x0002eca0 thru 0x0002ecad (14 bytes) To block (b) : 0x0002eca0 thru 0x0002ecac (13 bytes, 3 elements) string, allocated at orig.c, 12 main() orig.c, 15 **Memory corrupted. Program may crash!!** ************************* INSIGHT SUMMARY ********************************* * Program : orig * * Arguments : * * Directory : /home/elephant2/whicken/D * * Compiled on : Aug 13, 1993 13:01:32 * * Run on : Aug 13, 1993 13:02:20 * * Elapsed time : 00:00:00 * *************************************************************************** PROBLEM SUMMARY - by type =============== Problem Detected Suppressed ------------------------------------------------- WRITE_OVERFLOW 1 0 ------------------------------------------------- TOTAL 1 0 ------------------------------------------------- PROBLEM SUMMARY - by location =============== WRITE_OVERFLOW: Writing overflows memory, 1 occurrence 1 at orig.c, 15 MEMORY LEAK SUMMARY =================== 1 outstanding memory reference for 13 bytes. Outstanding allocated memory ---------------------------- 13 bytes 1 chunk allocated at orig.c, 12 [LISTING FOURTEEN] MemCheck V3.0 Active (License: StratosWare Corporation) Strcpy at ddjtest.c(16),len=14: overwrites destination... destination is _fmalloc at ddjtest.c(13), size=13, #1 mc_endcheck after ddjtest.c(16): buffer overwritten before call... buffer is _fmalloc at ddjtest.c(13), size=13, #1 mc_endcheck: no free for _fmalloc at ddjtest.c(13), size=13, #1 [LISTING FIFTEEN] ---------------------------------------------------------------------------- F:\DDJ\WINTEST.EXE loaded 02:45 PM Thursday August 19 ---------- 03:05 PM Thursday August 19 ---------- ***** Error, Source will overrun destination **** Procedure: WINMAIN (00038H) Module: WINTEST Source File: WINTEST.C Line Number: 00018 Trying to copy 00014 bytes to an area allocated by: WINTEST.C LINE # 00015 starting offset within buffer 00000 The destination buffer is only 00013 bytes long. CALL STACK ---------- #WINTEST!WINMAIN(hInstance,PrevInstance,lpszCmdLine,nCmdShow) (1AAE,0000,1A87:0080,0001) *************************************************************************** YOUR PROGRAM'S data usage *************************************************************************** Stack Usage: stack space available stack space used --------------------- ---------------- 04908 01018 WINTEST Memory used (in bytes): Local Heap Global Heap ---------- ----------- 00525 00000 Local leaks: Function Name Size Program location ------------- ---- ---------------- _malloc 00013 WINTEST.C LINE # 00015 *************************************************************************** GDI data usage on your program's behalf *************************************************************************** Memory used (in bytes): Local Heap Global Heap ---------- ----------- 00000 00000 *************************************************************************** USER data usage on your program's behalf *************************************************************************** Memory used (in bytes): Local Heap Global Heap ---------- ----------- 00000 00480