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 by malloc() or calloc().
  • 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 NULL pointer, as well as passing null pointers into function arguments marked nonnull.
  • 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.