This thread will discuss the solutions to buggy code!
1: #include <stdlib.h>
2: #include <stdio.h>
3:
4: char global[5];
5:
6: int main (void) {
7: char * dyn;
8: char local[5];
9:
10: /* First, overwrite a buffer just a little bit */
11: dyn = malloc(5);
12: strcpy(dyn, "12345");
13: printf("1: %s\n", dyn);
14: free(dyn);
15:
16: /* Now overwrite the buffer a lot */
17: dyn = malloc(5);
18: strcpy(dyn, "12345678");
19: printf("2: %s\n", dyn);
20:
21: /* Walk past the beginning of the malloc()ed buffer */
22: *(dyn -1) = '\0';
23: printf("3: %s\n", dyn);
24: /* We did not free()d the pointer */
25:
26: /* Now some local variable */
27: strcpy(local, "12345");
28: printf("4: %s\n", local);
29: local[-1]='\0';
30: printf("5: %s\n", local);
31:
32: /* Finally the Global Space */
33: strcpy(global, "12345");
34: printf("6: %s\n", global);
35:
36: /* Walk past the begining of global buffer */
37: global[-1]='\0';
38: printf("7: %s\n", global);
39:
40: return 0;
41: }
The above code corrupts three types of memory regions:
1. memory from dynamic memory pool via malloc()
2. local variables from program stack
3. global variables from seperate memory area in memory
$ gcc -Wall -o memleak memleak.c
$ ./memleak
1: 12345
2: 12345678
3: 12345678
4: 12345
5: 12345
6: 12345
7: 12345
When we run the code, it runs fine, while we have corrupted the
memory!!!
Lets start using some debuggers - Memory Debugging Tools
Electric Fence
Electric Fence does not find memory leaks, but help to isolate buffer
overruns. As linux, like every modern operating system provides
hardware memory protection to isolate programs from each other.
Electric Fence replaces C libraries malloc() function with a version
that allocates the requested memory and usually allocates a section of
memory immideately after this, which the process is not allowed to
access!
When the process tries to access the memory block pass the allocated
one, kernel traps and halts the process with a segmentation fault! Most
of us might have struggled with this error while working with pointer.
This way Electric Fence manages to get the program killed when it
passes the allocated space.
libefence.a is the library for Electric Fence!
Now compile the code against Electric Fence library...
$ gcc -ggdb -Wall -o memleak memleak.c -lefence
-ggdb generates debugging information in the code.
$ ./memleak
Electric Fence ... Copyright ...
1: 12345
Segmentation Fault (core dumped)
Although Electric Fence did not tell where the exact problem is, but it
tolw the problem exists.
Now lets run the code in Debugger to trace the problem...
$ gdb memleak
GDB .....
....
...
...
(gdb) run
Starting program: /home/achindrab/memleak
Electric Fence... Copyright ...
1: 12345
Program received signal SIGSEGV, segmentation fault.
...
...
(gdb) where
...
.... in main() at memleak.c:18
...
(gdb)
So now we know the error is at line number 18!!!
(gdb) is the debuggers prompt, gdb is a debugger, and supports command
line control
Most modern computers require multibyte objects to start at particular
offsets in memory (RAM), eg: a 32-bit system requires all 32-bit (4
byte) objects start at memory location evenly divisible by 4, and
64-bit(8 byte) at locatons evenly divisible by 8.
Due to this consideration, malloc() implementations normally return
memory whose first byte is alligned according to the processor word
size.
Electric Fence simulates this behavior by providing a malloc() that
returns only address that are an even multiple of sozeof(int).
In most programs, such allignment is not required as memory allocation
is done in incremental order which is based on machines word size or
simple character strings whose elements are already 1byte long.
In the program, malloc() allocates 5 bytes. for Electric Fence to meet
the allignment requirements, it must treat the allocation as a request
for 8bytes. And set up memory with extra 3 bytes on accesible space
after malloc()ed region. Now small buffer overruns in the region are
not cought because of this!!!
As malloc() allignment concerns can normally be ignored and the
allignment can allow buffer overruns to remain undetected, EF_ALIGNMENT
environment variable can be used to control how Electric Fence controls
the allignment.
If set, all malloc() results are alligned accordingly to its value.
eg:. if malloc()ed region is set to 5, all locations will be alligned
to a multiple of 5.
Set EF_ALIGNMENT to turn the feature off.
Although Linux kernel handles improper alligned accesses.
EF_PROTECT_BELOW environment variable is set to 1, Electric Fence will
trap any buffer underruns. Although Electric Fence will not be able to
do buffer overrun checks. Due to memory allignment concerns. It will
pad the inaccessible memory regions to the starting of the memory.
EF_PROTECT_FREE when set to 1, and free() is called, the memory is
returned to the inaccessible pool of memory, thus no access and kernel
traps the illegal move!!!
Topics to be handled in further discussion are
1. Finding Overruns with checker
2. Finding Memory Leaks with checker and mpr
3. Finding Memory Corruptions with mcheck
4. Any other tools in use.