AddressSanitizer and UndefinedBehaviorSanitizer in C
The C programming language provides developers with low-level memory access and high performance, but it lacks inherent runtime guardrails, often leading to subtle bugs and security vulnerabilities. AddressSanitizer (ASan) and UndefinedBehaviorSanitizer (UBSan) are compiler-based instrumentation tools that modernize C development by detecting critical memory corruption and undefined behaviors during runtime. This article examines the specific error-detection capabilities that both tools introduce to the C development lifecycle.
AddressSanitizer (ASan) Runtime Detection
AddressSanitizer is designed primarily to locate memory access
violations. It works by instrumenting memory accesses and utilizing
"shadow memory" to track the validity of every byte in application
memory. When compiled with -fsanitize=address, ASan
intercepts memory operations to detect the following errors:
- Out-of-Bounds Accesses: Detects reads and writes outside the allocated boundaries of heap buffers, stack variables, and global arrays (buffer overflows and underflows).
- Use-After-Free: Flags attempts to read or write
memory that has already been deallocated using
free(). - Use-After-Scope: Catches accesses to local variables after their containing lexical scope (such as a block or loop) has terminated.
- Use-After-Return: Detects pointers referencing stack frames that have already returned.
- Double Free and Invalid Free: Intercepts redundant
calls to
free()on the same pointer, as well as attempts to free pointers not allocated bymalloc()orcalloc(). - Memory Leaks: Through its integrated component, LeakSanitizer (LSan), it identifies allocated heap memory that remains unreachable at program termination.
UndefinedBehaviorSanitizer (UBSan) Runtime Detection
Undefined behavior in C can lead to unpredictable application states,
security exploits, or compiler optimizations that eliminate critical
logic. UndefinedBehaviorSanitizer inserts dynamic checks with minimal
overhead when compiled with -fsanitize=undefined. UBSan
identifies:
- Signed Integer Overflow: Catches arithmetic calculations where the result exceeds the minimum or maximum representable value of a signed integer type.
- Misaligned Pointer Dereference: Flags attempts to load or store data through pointers that do not satisfy the target architecture's alignment requirements.
- Null Pointer Dereference: Intercepts operations
that attempt to read or write through a
NULLpointer, as well as passing null pointers into function arguments markednonnull. - Invalid Bitwise Shifts: Detects bitwise shifts by negative amounts, shifts greater than or equal to the bit width of the value, and shifts that overflow signed integers.
- Division by Zero: Catches integer or floating-point division and modulus operations where the divisor is zero.
- Unreachable Code Execution: Alerts when execution
enters code paths explicitly marked unreachable by the compiler (e.g.,
__builtin_unreachable()). - Variable-Length Array (VLA) Bound Errors: Detects when a runtime-sized array is declared with a non-positive bound.
Practical Impact on C Software
Together, ASan and UBSan transform bug detection from static post-mortem analysis (like inspecting core dumps) into immediate, detailed error reporting. When a violation occurs, the sanitizers halt execution or log the incident, outputting a descriptive error message complete with a stack trace, file name, exact line number, and a breakdown of the involved memory regions. This immediate feedback substantially reduces debugging time and prevents common C vulnerabilities from reaching production systems.