How to Configure ThreadSanitizer (TSAN) Compatibility with Abseil: Compiler Flags and Build Guide

Building Abseil with ThreadSanitizer requires passing -fsanitize=thread to both the compiler and linker, configuring CPLUS_INCLUDE_PATH and BAZEL_LINKOPTS to point to a TSAN-instrumented libc++, and setting TSAN_SYMBOLIZER_PATH for readable stack traces.

Abseil-cpp provides built-in support for ThreadSanitizer through automated detection macros and specialized mutex wrappers. To achieve full TSAN compatibility with Abseil, you must configure specific compiler flags, library paths, and Bazel build options that align with the sanitizer's instrumentation requirements.

Essential Compiler and Linker Flags

The foundation of TSAN compatibility with Abseil relies on the -fsanitize=thread flag applied at both compile and link time. According to ci/linux_clang-latest_libcxx_tsan_bazel.sh, you must pass this flag via Bazel's --copt and --linkopt options.

At line 89, the compiler instrumentation is enabled:

--copt=-fsanitize=thread

At line 96, the linker flag ensures the TSAN runtime is embedded in the final binary:

--linkopt=-fsanitize=thread

Additionally, lines 90-91 specify -fno-sanitize-blacklist to disable user-supplied blacklists and maintain complete instrumentation coverage:

--copt=-fno-sanitize-blacklist

Include Paths and Library Configuration

ThreadSanitizer requires a specially instrumented C++ standard library. The Abseil CI demonstrates this using a custom-built libc++ located at /opt/llvm-tsan/.

TSAN-Compatible Standard Library Setup

Set these environment variables before invoking Bazel to point to the TSAN-compatible toolchain:

  • CPLUS_INCLUDE_PATH=/opt/llvm-tsan/include/c++/v1 (line 76): Gives the compiler access to libc++ headers built for the TSAN ABI.
  • BAZEL_LINKOPTS="-L/opt/llvm-tsan/lib ..." (line 75): Ensures the linker finds TSAN-compatible libc++ and libstdc++ libraries. The CI script uses -L/opt/llvm-tsan/lib -lc++ -lc++abi -lgcc_s -lm -Wl,-rpath=/opt/llvm-tsan/lib.
  • TSAN_SYMBOLIZER_PATH=/opt/llvm/bin/llvm-symbolizer (line 99): Provides symbolization for TSAN reports when tests are executed.

Source-Level TSAN Integration in Abseil

Abseil detects TSAN automatically through the ABSL_INTERNAL_HAVE_TSAN_INTERFACE macro, which the compiler defines when -fsanitize=thread is active. This macro enables TSAN-specific wrappers in absl/base/internal/tsan_mutex_interface.h.

Mutex Wrapper Implementation

These wrappers (using the ABSL_TSAN_MUTEX_* macros) forward lock and unlock events to the TSAN runtime, preventing false positives for Abseil's internal synchronization primitives. The implementation is used throughout absl/synchronization/mutex.h and absl/synchronization/mutex.cc. Test coverage includes absl/synchronization/mutex_test.cc, which specifically validates TSAN reports for locked-mutex destruction, and absl/flags/internal/sequence_lock_test.cc, which demonstrates atomic contention scenarios only enabled under TSAN.

Bazel Build Configuration

Filtering TSAN-Incompatible Tests

Abseil marks tests that are incompatible with ThreadSanitizer using the notsan tag. Lines 84-86 and 102-103 of the CI script demonstrate the required filters:

--build_tag_filters="-notsan"
--test_tag_filters="-benchmark,-notsan"

The -benchmark exclusion prevents long-running benchmark tests from generating excessive TSAN output during CI runs.

Complete Build Examples

Minimal Bazel command for TSAN testing:

bazel test ... \
  --copt=-fsanitize=thread \
  --copt=-fno-sanitize-blacklist \
  --linkopt=-fsanitize=thread \
  --build_tag_filters="-notsan" \
  --test_tag_filters="-benchmark,-notsan" \
  --test_env=TSAN_SYMBOLIZER_PATH=/opt/llvm/bin/llvm-symbolizer

Docker-based environment matching the Abseil CI configuration:

docker run -v "$PWD":/abseil-cpp:ro \
  -e CPLUS_INCLUDE_PATH=/opt/llvm-tsan/include/c++/v1 \
  -e BAZEL_LINKOPTS="-L/opt/llvm-tsan/lib -lc++ -lc++abi -lgcc_s -lm -Wl,-rpath=/opt/llvm-tsan/lib" \
  -e TSAN_SYMBOLIZER_PATH=/opt/llvm/bin/llvm-symbolizer \
  --cap-add=SYS_PTRACE \
  clang:latest \
  /bin/bash -c '
    bazel test ... \
      --copt=-fsanitize=thread \
      --copt=-fno-sanitize-blacklist \
      --linkopt=-fsanitize=thread \
      --build_tag_filters="-notsan" \
      --test_tag_filters="-benchmark,-notsan"
  '

Summary

  • Pass -fsanitize=thread via both --copt and --linkopt in your Bazel configuration.
  • Configure CPLUS_INCLUDE_PATH and BAZEL_LINKOPTS to use a TSAN-instrumented libc++, typically located at /opt/llvm-tsan/.
  • Set TSAN_SYMBOLIZER_PATH to enable readable stack traces in sanitizer reports.
  • Exclude notsan tagged tests using --build_tag_filters="-notsan" and --test_tag_filters="-benchmark,-notsan".
  • Include -fno-sanitize-blacklist to ensure complete instrumentation without source-based exclusions.
  • Abseil automatically activates ABSL_INTERNAL_HAVE_TSAN_INTERFACE and mutex wrappers in absl/base/internal/tsan_mutex_interface.h when TSAN is detected.

Frequently Asked Questions

Do I need a special version of the C++ standard library for TSAN compatibility with Abseil?

Yes. ThreadSanitizer requires that the C++ standard library be compiled with TSAN instrumentation. The Abseil CI script uses a custom-built libc++ located at /opt/llvm-tsan/, setting CPLUS_INCLUDE_PATH to /opt/llvm-tsan/include/c++/v1 and adding -L/opt/llvm-tsan/lib via BAZEL_LINKOPTS (lines 75-76) to ensure ABI compatibility between the sanitizer runtime and standard library containers.

What Bazel tags should I use when running TSAN tests on Abseil?

Use --build_tag_filters="-notsan" and --test_tag_filters="-benchmark,-notsan". The Abseil repository marks tests that are incompatible with ThreadSanitizer with the notsan tag, while benchmarks are excluded to prevent excessive execution time. This configuration is documented in ci/linux_clang-latest_libcxx_tsan_bazel.sh at lines 84-86.

How does Abseil prevent false positives in TSAN reports?

Abseil provides TSAN-aware mutex wrappers in absl/base/internal/tsan_mutex_interface.h. When the preprocessor detects -fsanitize=thread (defining ABSL_INTERNAL_HAVE_TSAN_INTERFACE), these wrappers forward lock and unlock operations to the TSAN runtime. This integration prevents the sanitizer from reporting false data races on Abseil's internal synchronization primitives implemented in absl/synchronization/mutex.cc.

Can I use TSAN with any Bazel compilation mode?

Yes. According to the CI configuration in linux_clang-latest_libcxx_tsan_bazel.sh at lines 90-91, any Bazel compilation mode (fastbuild, opt, or dbg) works with TSAN. The only additional requirement beyond the standard -fsanitize=thread flags is including -fno-sanitize-blacklist to disable source-based blacklists and ensure complete instrumentation coverage.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →