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

> Configure ThreadSanitizer (TSAN) for Abseil. Learn essential compiler flags and build settings for robust thread safety analysis with your C++ code.

- Repository: [Abseil/abseil-cpp](https://github.com/abseil/abseil-cpp)
- Tags: how-to-guide
- Published: 2026-07-14

---

**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`](https://github.com/abseil/abseil-cpp/blob/main/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:

```bash
--copt=-fsanitize=thread

```

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

```bash
--linkopt=-fsanitize=thread

```

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

```bash
--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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/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:

```bash
--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:

```bash
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:

```bash
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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/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.