TSan instrumentation using LLVM opt and TSan passes

My goal is to instrument my initial IR with proper calls to TSan runtime library functions using LLVM opt and TSan passes. In other words, I want to end up with similar TSan instrumentation as when using clang -fsanitize=thread -S -emit-llvm but by directly using opt and TSan passes instead.

As far as I know, LLVM has two passes for TSan instrumentation: tsan-module (a module pass) and tsan (a function pass). Both passes seem to be available by default in opt, i.e. are included in opt -print-passes report.

I choose tiny_race.c as my sample program, where the main thread and the thread it spawns (Thread1) form a data race while accessing a global variable Global.

Here are the two steps I take to instrument the code my way:

  1. Generating the initial LLVM IR for tiny_race.c:
    clang -S -emit-llvm tiny_race.c -o tiny_race.ll

  2. Using LLVM opt to instrument tiny_race.ll with the two TSan passes:
    opt -passes=‘tsan-module,tsan’ tiny_race.ll -S -o myInstrumented.ll

The above pass pipeline executes fine but the resulting myInstrumented.ll lacks most TSan instrumentations. More specifically:

  • Thread1 (child thread) is left completely un-instrumented.

  • main thread only has @__tsan_func_entry and @__tsan_func_exit instrumentations and its accesses to Global are not instrumented.

It might be interesting to mention that my output IR does contain TSan function declarations as expected.

I am using LLVM 16 and I have not modified the two mentioned TSan passes.

Does anyone know why my approach produces a partially-instrumented IR? Am I supposed to use some other passes alongside the two TSan passes I mentioned? Any suggestion is greatly appreciated.

See llvm-project/ThreadSanitizer.cpp at main · llvm/llvm-project · GitHub, if a function ihas no Attribute::SanitizeThread, it won’t be instrumented.
You can write a pass, which manually calls Fn->addFnAttr(llvm::Attribute::SanitizeThread); for each function before you call tsan instrumentation pass.
Also see llvm-project/CodeGenFunction.cpp at main · llvm/llvm-project · GitHub and llvm-project/CGDeclCXX.cpp at main · llvm/llvm-project · GitHub, Attribute::SanitizeThread is added by clang when -fsanitize=thread is enabled.

1 Like

Here is an another way:
1, clang -S -emit-llvm -fsanitize=thread -Xclang -disable-llvm-passes -Xclang -disable-O0-optnone tiny_race.c -o tiny_race.ll
2. opt -passes=‘tsan-module,tsan’ tiny_race.ll -S -o myInstrumented.ll

1 Like