UndefinedBehaviorSanitizer
Undefined Behavior Sanitizer or UBSAN is a compiler feature in GCC and Clang that is able to detect various forms of undefined behaviour (UB). It helps to both identify why an application is misbehaving and to help prevent future issues. Undefined Behavior Sanitizer is enabled with the compiler flag -fsanitize=undefined
.
Configuration
UBsan can only be configured via two methods:
- additional flags passed to the compiler at build time (see the relevant compiler's documentation for examples)
- UBSAN_OPTIONS if not using the minimal runtime, options are delimited by colon (:)
It may be useful to run the following when debugging to enable both stacktraces and immediate abort on error:
user $
export UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1"
Use
The compiler must be built with sanitizer support:
- For GCC, sanitize must be enabled on sys-devel/gcc
- For Clang, ubsan must be enabled on sys-libs/compiler-rt-sanitizers
Example
First, create the following incorrect C program:
#include <stdio.h>
int main() {
/* Overflows an unsigned integer by shifting it 32 times */
printf("%d", 1u >> 32);
}
Compile it:
user $
cc -O2 -g -fsanitize=undefined /tmp/overflow.c -o /tmp/overflow
Run it:
user $
UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1" /tmp/overflow
/tmp/overflow.c:4:21: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int' #0 0x5612d124209a in main /tmp/overflow.c:4 #1 0x7fae8909fd4f (/usr/lib64/libc.so.6+0x23d4f) #2 0x7fae8909fe08 in __libc_start_main (/usr/lib64/libc.so.6+0x23e08) #3 0x5612d12420e4 in _start (/tmp/foo+0x10e4)
UBsan has instrumented the shift operation and trapped the overflow at runtime, identifying the type of UB and where it occurred.
Per-package
The most sensible use of Undefined Behavior Sanitizer (or other sanitizers) is temporary and per-package using /etc/portage/package.env.
Create a file in /etc/portage/env as follows:
CFLAGS="${CFLAGS} -fsanitize=undefined"
CXXFLAGS="${CXXFLAGS} -fsanitize=undefined"
LDFLAGS="${LDFLAGS} -fsanitize=undefined"
# Only relevant if package uses Meson
# For Meson packages, it might be necessary to comment out the *FLAGS lines above
# and only set MYMESONARGS.
MYMESONARGS="-Db_sanitize=undefined"
Next, add an entry to package.env followed by the name of the file created in the previous step:
app-misc/hello ubsan.conf
Then re-emerge the relevant package(s):
root #
emerge --oneshot --usepkg=n app-misc/hello
See also
- AddressSanitizer — a compiler feature in GCC and Clang that is able to detect several memory access errors.
- Valgrind — dynamic analysis tool which detects memory errors and memory leaks.