MSAN, ASAN, & TSAN

Testing Skia with memory, address, and thread santizers.

Compiling Skia with ASAN, UBSAN, or TSAN can be done with the latest version of Clang.

  • UBSAN works on Linux, Mac, Android, and Windows, though some checks are platform-specific.
  • ASAN works on Linux, Mac, Android, and Windows.
  • TSAN works on Linux and Mac.
  • MSAN works on Linux[1].

We find that testing sanitizer builds with libc++ uncovers more issues than with the system-provided C++ standard library, which is usually libstdc++. libc++ proactively hooks into sanitizers to help their analyses. We ship a copy of libc++ with our Linux toolchain in /lib.

[1]To compile and run with MSAN, an MSAN-instrumented version of libc++ is needed. It’s generally easiest to run one of the following 2 steps to build/download a recent version of Clang and the instrumented libc++, located in /msan.

Downloading Clang binaries (Googlers Only)

This requires gsutil, part of the gcloud sdk.

gcloud auth application-default login
CLANGDIR="${HOME}/clang"
./bin/sk asset download clang_linux $CLANGDIR

Building Clang binaries from scratch (Other users)

CLANGDIR="${HOME}/clang"

python3 tools/git-sync-deps
CC= CXX= infra/bots/assets/clang_linux/create.py -t "$CLANGDIR"

Configure and Compile Skia with MSAN

CLANGDIR="${HOME}/clang"
mkdir -p out/msan
cat > out/msan/args.gn <<- EOF
    cc = "${CLANGDIR}/bin/clang"
    cxx = "${CLANGDIR}/bin/clang++"
    extra_cflags = [ "-B${CLANGDIR}/bin" ]
    extra_ldflags = [
        "-B${CLANGDIR}/bin",
        "-fuse-ld=lld",
        "-L${CLANGDIR}/msan",
        "-Wl,-rpath,${CLANGDIR}/msan" ]
    sanitize = "MSAN"
    skia_use_fontconfig = false
EOF
python3 tools/git-sync-deps
bin/gn gen out/msan
ninja -C out/msan

When running dm under MSAN, you’ll want to include --nogpu because MSAN won’t have instrumented driver memory and such and will flag unrelated issues.

Symbolizing MSAN Traces

By default, MSan will print hexadecimal addresses in stack traces. To see function names and line numbers, you must provide the path to llvm-symbolizer via an environment variable.

CLANGDIR="${HOME}/clang"
export MSAN_SYMBOLIZER_PATH="${CLANGDIR}/bin/llvm-symbolizer"
./out/msan/dm ...

Stack Overflow during MSAN Reporting

If you encounter a stack overflow (segfault) while MSAN is trying to report an error, it is likely because libunwind was itself instrumented with MSAN. This causes infinite recursion during stack unwinding.

While our toolchain build script has been updated to fix this, you may need to apply a workaround to an existing toolchain:

  1. Locate the msan directory in your clang asset (e.g., ~/clang/msan).
  2. Delete the instrumented unwinder files: rm ~/clang/msan/libunwind.so* ~/clang/msan/libunwind.a
  3. Force a relink of your binary (e.g., rm out/msan/dm && ninja -C out/msan dm).

This will force the loader to use the system’s uninstrumented libunwind.

Configure and Compile Skia with ASAN

CLANGDIR="${HOME}/clang"
mkdir -p out/asan
cat > out/asan/args.gn <<- EOF
    cc = "${CLANGDIR}/bin/clang"
    cxx = "${CLANGDIR}/bin/clang++"
    sanitize = "ASAN"
    extra_ldflags = [ "-fuse-ld=lld", "-Wl,-rpath,${CLANGDIR}/lib/x86_64-unknown-linux-gnu" ]
EOF
python3 tools/git-sync-deps
bin/gn gen out/asan
ninja -C out/asan

Configure and Compile Skia with TSAN

CLANGDIR="${HOME}/clang"
mkdir -p out/tsan
cat > out/tsan/args.gn <<- EOF
    cc = "${CLANGDIR}/bin/clang"
    cxx = "${CLANGDIR}/bin/clang++"
    sanitize = "TSAN"
    is_debug = false
    extra_ldflags = [ "-Wl,-rpath,${CLANGDIR}/lib" ]
EOF
python3 tools/git-sync-deps
bin/gn gen out/tsan
ninja -C out/tsan