One of the drawback of C is the hard memory management.
It is because of this aspect that Clang provides a way to detect, at runtime, memory errors. Called Address Sanitizer, it allows, while the program is running, to keep track of the memory and detect typical errors (out-of-bound accesses, use of a variable after a free, etc).
# With the following packages (version 3.2-1~exp3)
$ sudo apt-get install clang clang-3.2 compiler-rt -t experimental
Taking the simple following example, even if the errors are obvious, compilers will accept this code.
#include <stdlib.h>
int main() {
char *x = (char*)malloc(10 * sizeof(char*));
free(x);
return x[5];
}
Built and run with:
$ clang -O1 -g -fsanitize=address -fno-omit-frame-pointer foo.c -o foo
$ ./foo &> memoryDebug.log
The previous command will generate a log file. Log which can be post processed with the asan_symbolize command.
$ asan_symbolize memoryDebug.log
which will give:
=================================================================
==21368== ERROR: AddressSanitizer: heap-use-after-free on address 0x7fb22e547f45 at pc 0x408c44 bp 0x7ffff60c10b0 sp 0x7ffff60c10a8
READ of size 1 at 0x7fb22e547f45 thread T0
#0 0x408c43 in main /tmp/foo.c:5
#1 0x7fb22d99f6ac in __libc_start_main /home/adconrad/eglibc-2.16/csu/libc-start.c:227
0x7fb22e547f45 is located 5 bytes inside of 80-byte region [0x7fb22e547f40,0x7fb22e547f90)
freed by thread T0 here:
#0 0x408c90 in __interceptor_free ??:0
#1 0x408c0a in main /tmp/foo.c:4
#2 0x7fb22d99f6ac in __libc_start_main /home/adconrad/eglibc-2.16/csu/libc-start.c:227
previously allocated by thread T0 here:
#0 0x408d50 in __interceptor_malloc ??:0
#1 0x408bff in main /tmp/foo.c:3
#2 0x7fb22d99f6ac in __libc_start_main /home/adconrad/eglibc-2.16/csu/libc-start.c:227
Shadow byte and word:
0x1ff645ca8fe8: fd
0x1ff645ca8fe8: fd fd fd fd fd fd fd fd
More shadow bytes:
0x1ff645ca8fc8: fa fa fa fa fa fa fa fa
0x1ff645ca8fd0: fa fa fa fa fa fa fa fa
0x1ff645ca8fd8: fa fa fa fa fa fa fa fa
0x1ff645ca8fe0: fa fa fa fa fa fa fa fa
=>0x1ff645ca8fe8: fd fd fd fd fd fd fd fd
0x1ff645ca8ff0: fd fd fd fd fd fd fd fd
0x1ff645ca8ff8: fa fa fa fa fa fa fa fa
0x1ff645ca9000: fa fa fa fa fa fa fa fa
0x1ff645ca9008: fa fa fa fa fa fa fa fa
Stats: 0M malloced (0M for red zones) by 1 calls
Stats: 0M realloced by 0 calls
Stats: 0M freed by 1 calls
Stats: 0M really freed by 0 calls
Stats: 0M (128 full pages) mmaped in 1 calls
mmaps by size class: 8:2047;
mallocs by size class: 8:1;
frees by size class: 8:1;
rfrees by size class:
Stats: malloc large: 0 small slow: 1
==21368== ABORTING
The main advantage compare to valgrind is that asan is supposed to be way more faster.
Threads can be also tricking to develop.
With the following example from stolen from upstream:
#include <pthread.h>
int Global;
void *Thread1(void *x) {
Global = 42;
return x;
}
int main() {
pthread_t t;
pthread_create(&t, NULL, Thread1, NULL);
Global = 43;
pthread_join(t, NULL);
return Global;
}
$ clang -fsanitize=thread -g -O1 foo2.c -fPIE -pie -o foo
$ ./foo
==================
WARNING: ThreadSanitizer: data race (pid=21416)
Write of size 4 at 0x7f2f1a214a50 by thread 1:
#0 Thread1 /tmp/foo2.c:4 (exe+0x00000000f850)
Previous write of size 4 at 0x7f2f1a214a50 by main thread:
#0 main /tmp/foo2.c:10 (exe+0x00000000f8a4)
Thread 1 (tid=21417, running) created at:
#0 pthread_create ??:0 (exe+0x00000001267e)
#1 main /tmp/foo2.c:9 (exe+0x00000000f894)
==================
ThreadSanitizer: reported 1 warnings
Note that clang also provides scan-build, a static analyzer for memory issues. Not as powerful as the Address Sanitizer (it only works on a file), it provides some excellent reports. See the Wouter's blog post on this subject or the automatic report of scan-build on Scilab.