Sylvestre Ledru: Some more cool stuff with LLVM/Clang
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 example from stolen from upstream:
# With the following packages (version 3.2-1~exp3)Taking the simple following example, even if the errors are obvious, compilers will accept this code.
$ sudo apt-get install clang clang-3.2 compiler-rt -t experimental
#include <stdlib.h>Built and run with:
int main()
char *x = (char*)malloc(10 * sizeof(char*));
free(x);
return x[5];
$ clang -O1 -g -fsanitize=address -fno-omit-frame-pointer foo.c -o fooThe previous command will generate a log file. Log which can be post processed with the asan_symbolize command.
$ ./foo &> memoryDebug.log
$ asan_symbolize memoryDebug.logwhich 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== ABORTINGThe 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 warningsNote 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.