GWPSan: Sampling-Based Sanitizer Framework


GWPSan is a framework for low-overhead sampling-based dynamic binary instrumentation, designed for implementing various bug detectors (also called "sanitizers") suitable for production uses. GWPSan does not modify the executed code, but instead performs dynamic analysis from signal handlers.


To use GWPSan, you have to build GWPSan and link it (statically or dynamically) into a binary of interest. For most GWPSan "tools", the target binary must be compiled with additional compiler flags, to add required metadata sections. GWPSan currently requires Clang 18 or later, and Linux kernel 6.4 or later (details); support for the x86-64 and arm64 architectures is currently implemented. Bazel is required to build GWPSan.

To build GWPSan static and dynamic runtime libraries:

CC=<path to clang-18 or later>
CXX=<path to clang++-18 or later>
bazel build --action_env=CC="$CC" --action_env=CXX="$CXX" -c opt \
		$( [[ $(uname -m) == "x86_64" ]] && echo --config=x86_64 ) \
		//gwpsan/ //gwpsan/unified:gwpsan_archive
If the clang and clang++ binaries in your PATH are already version 18 or later, you may omit explicitly setting CC and CXX. Some combinations of the GNU C++ Library (libstdc++) and Clang versions may be incompatible; if you run into problems, try with the LLVM C++ Library (libc++) by additionally passing --config=libc++ to the Bazel command.

To build the target binary with statically linked runtime (adapt to your build system):

clang++ $GWPSAN_CFLAGS -c example.cpp -o example.o
clang++ -o example example.o ... \
        -Wl,--whole-archive "${GWPSAN_ROOT}/bazel-bin/gwpsan/unified/libgwpsan.a" -Wl,--no-whole-archive

To use the dynamically linked GWPSan runtime with a binary that has been build with GWPSAN_CFLAGS but does not link the runtime statically:

clang++ $GWPSAN_CFLAGS -c example.cpp -o example.o
clang++ -o example example.o ...
LD_PRELOAD="${GWPSAN_ROOT}/bazel-bin/gwpsan/unified/" ./example

Tunable flags

GWPSan has several tunable flags with reasonable defaults. If necessary, the flags can be tuned with the GWPSAN_OPTIONS environment variable. To see all available flags, set GWPSAN_OPTIONS=help and run a binary with the GWPSan runtime linked in; this will show help for all flags and immediately exit without running the main program. Multiple flags can be separated by :.

Note: Boolean flags can be enabled with either GWPSAN_OPTIONS=foobar or GWPSAN_OPTIONS=foobar=1; to explicitly disable, GWPSAN_OPTIONS=foobar=0.

Enabling sampling and tools

By default, GWPSan is completely disabled and none of its bug detectors (also called tools) are enabled. To enable GWPSan sampling, and crash on errors (in production you may not always want to set halt_on_error):

# Sample once per second, and crash on detected errors:

export GWPSAN_OPTIONS=sample_interval_usec=1000000:halt_on_error

With that, GWPSan only enables periodic sampling, but no tools are enabled yet.

The following tools are available:

  • tsan detects data races. Enabled/disabled with GWPSAN_OPTIONS=tsan=0/1.
  • uar detects use-after-return bugs. Enabled/disabled with GWPSAN_OPTIONS=uar=0/1.
  • lmsan detects uses of uninit values (experimental). Enabled/disabled with GWPSAN_OPTIONS=lmsan=0/1.