“Sanitizers” is a project by Google (Sanitizers github project) where the compiler instruments your code to signal various errors. Most prominently (in my opinion) are the sanitizers for memory addressing and leakage errors, which are described below. Other sanitziers can detect undefined behavior and race conditions.
Just build the code with extra compiler (and linker) flag -fsanitize=address:
g++ -fsanitize=address -Og -ggdb -fno-omit-frame-pointer source.cpp -o my_executable
then run ./my_executable
. The flags -Og, -ggdb, and -fno-omit-frame-pointer are not necessary but should improve the debug output of the sanitizers (e.g. code files and line numbers).
Now, executing the code will terminate on addressing errors with debug information being printed. This happens on many errors that would go unnoticed otherwise.
For CMake, make sure to include the fsanitizer flag to compiler and linker. In CMakeLists.txt, this can be done as follows:
target_compile_options(<targetname> PRIVATE -fsanitize=address)
target_link_libraries (<targetname> PRIVATE -fsanitize=address)
The project page of the address sanitizer says
This tool is very fast. The average slowdown of the instrumented program is ~2x (see AddressSanitizerPerformanceNumberspage).
I like to have a core dump on crash, so I set
ASAN_OPTIONS="disable_coredump=0:unmap_shadow_on_exit=1:abort_on_error=1"
The cryptic second option avoids dumping the sanitizers house-keeping data, which would increase the size of the core dump.
asan.cpp
1 #include <iostream>
2 ///Built: g++ -g -fno-omit-frame-pointer -fsanitize=address asan.cpp -o asan
3
4 int main(int argc, char* argv[]) {
5 if(argc != 2) {
6 std::cout << "Usage: " << argv[0] << "<flag>\n";
7 std::cout << "where <flag> is one of\n";
9 std::cout << "'s' to trigger Stack Sanitizer\n";
9 std::cout << "'h' to trigger Heap Sanitizer\n";
10 std::cout << "'a' to trigger Address Sanitizer on SEGV\n";
11 std::cout << "'l' to trigger Leak Sanitizer (default)\n";
12 }
13 else {
14 char my_stack_array[10];
15 char* my_heap_array = new char[10];//triggers leak sanitizer
16
17 switch(argv[1][0]){
18 //triggers stack-buffer-overflow
19 case 's': std::cerr << "Stack: " << my_stack_array[12] << "\n"; break;
20 //triggers heap-buffer-overflow
21 case 'h': std::cerr << "Heap: " << my_heap_array[12] << "\n"; break;
22 //Triggers SEGV, sanitizer provides stack trace
23 case 'a': std::cerr << "Param 900:" << argv[900] << "\n"; break;
24 //Leak sanitizer is triggered automatically on leaving main
25 case 'l':
26 default: break;
27 }
28 }
29 return 0;
30 }
$ ./asan l ================================================================= ==15659==ERROR: LeakSanitizer: detected memory leaks Direct leak of 10 byte(s) in 1 object(s) allocated from: #0 0x7f9d77ae9608 in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe0608) #1 0x55804c0d7336 in main /home/user/code/asan.cpp:15 #2 0x7f9d772b0b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96) SUMMARY: AddressSanitizer: 10 byte(s) leaked in 1 allocation(s).Accessing heap array beyond end:
$ ./asan h Heap: ================================================================= ==15665==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000001c at pc 0x556be9267649 bp 0x7ffe8ab6c690 sp 0x7ffe8ab6c680 READ of size 1 at 0x60200000001c thread T0 #0 0x556be9267648 in main /home/user/code/asan.cpp:21 #1 0x7f0d62ed9b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96) #2 0x556be9267139 in _start (/home/user/code/asan+0x1139) 0x60200000001c is located 2 bytes to the right of 10-byte region [0x602000000010,0x60200000001a) allocated by thread T0 here: #0 0x7f0d63712608 in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe0608) #1 0x556be9267336 in main /home/user/code/asan.cpp:15 #2 0x7f0d62ed9b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96) SUMMARY: AddressSanitizer: heap-buffer-overflow /home/user/code/asan.cpp:21 in main Shadow bytes around the buggy address: 0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c047fff8000: fa fa 00[02]fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==15665==ABORTINGAccessing stack array beyond end:
$ ./asan s Stack: ================================================================= ==15718==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcd2bd5c6c at pc 0x55d9eda9d63f bp 0x7ffcd2bd5ba0 sp 0x7ffcd2bd5b90 READ of size 1 at 0x7ffcd2bd5c6c thread T0 #0 0x55d9eda9d63e in main /home/user/code/asan.cpp:19 #1 0x7f1ea1e41b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96) #2 0x55d9eda9d139 in _start (/home/user/code/asan+0x1139) Address 0x7ffcd2bd5c6c is located in stack of thread T0 at offset 172 in frame #0 0x55d9eda9d283 in main /home/user/code/asan.cpp:4 This frame has 3 object(s): [32, 33) '__c' [96, 97) '__c' [160, 170) 'my_stack_array' <== Memory access at offset 172 overflows this variable HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext (longjmp and C++ exceptions *are* supported) SUMMARY: AddressSanitizer: stack-buffer-overflow /home/user/code/asan.cpp:19 in main Shadow bytes around the buggy address: 0x10001a572b30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10001a572b40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10001a572b50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10001a572b60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10001a572b70: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 01 f2 f2 f2 =>0x10001a572b80: f2 f2 f2 f2 01 f2 f2 f2 f2 f2 f2 f2 00[02]f2 f2 0x10001a572b90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10001a572ba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10001a572bb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10001a572bc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10001a572bd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==15718==ABORTINGAccessing parameter array (which is usually stored on the stack) grossly beyond end:
Param 900:ASAN:DEADLYSIGNAL
=================================================================
==17283==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7f27e05785c7 bp 0x7ffd69376660 sp 0x7ffd69375dd8 T0)
==17283==The signal is caused by a READ memory access.
==17283==Hint: address points to the zero page.
#0 0x7f27e05785c6 (/lib/x86_64-linux-gnu/libc.so.6+0x18e5c6)
#1 0x7f27e0bb557b (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5157b)
#2 0x7f27e08eeee8 in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x113ee8)
#3 0x563735f1b3d6 in main /home/uic13796/Documents/CoP/memory-presentation/asan.cpp:23
#4 0x7f27e040bb96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
#5 0x563735f1b139 in _start (/home/uic13796/Documents/CoP/memory-presentation/asan+0x1139)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/lib/x86_64-linux-gnu/libc.so.6+0x18e5c6)
==17283==ABORTING