Author: Alexander Potapenko Date: 2021-08-23T12:38:33+02:00 New Revision: 8300d52e8cbf757192d6b66efa537e15376bf756
URL: https://github.com/llvm/llvm-project/commit/8300d52e8cbf757192d6b66efa537e15376bf756 DIFF: https://github.com/llvm/llvm-project/commit/8300d52e8cbf757192d6b66efa537e15376bf756.diff LOG: [tsan] Add support for disable_sanitizer_instrumentation attribute Unlike __attribute__((no_sanitize("thread"))), this one will cause TSan to skip the entire function during instrumentation. Depends on https://reviews.llvm.org/D108029 Differential Revision: https://reviews.llvm.org/D108202 Added: clang/test/CodeGen/sanitize-thread-disable.c Modified: clang/docs/ThreadSanitizer.rst llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp Removed: ################################################################################ diff --git a/clang/docs/ThreadSanitizer.rst b/clang/docs/ThreadSanitizer.rst index 92cc9392955cc..98d5307d824f9 100644 --- a/clang/docs/ThreadSanitizer.rst +++ b/clang/docs/ThreadSanitizer.rst @@ -100,6 +100,16 @@ instruments such functions to avoid false positives and provide meaningful stack traces. This attribute may not be supported by other compilers, so we suggest to use it together with ``__has_feature(thread_sanitizer)``. +``__attribute__((disable_sanitizer_instrumentation))`` +-------------------------------------------------------- + +The ``disable_sanitizer_instrumentation`` attribute can be applied to functions +to prevent all kinds of instrumentation. As a result, it may introduce false +positives and incorrect stack traces. Therefore, it should be used with care, +and only if absolutely required; for example for certain code that cannot +tolerate any instrumentation and resulting side-effects. This attribute +overrides ``no_sanitize("thread")``. + Ignorelist ---------- diff --git a/clang/test/CodeGen/sanitize-thread-disable.c b/clang/test/CodeGen/sanitize-thread-disable.c new file mode 100644 index 0000000000000..d3ec1425e7821 --- /dev/null +++ b/clang/test/CodeGen/sanitize-thread-disable.c @@ -0,0 +1,57 @@ +// RUN: %clang -target x86_64-linux-gnu -S -emit-llvm -o - %s | FileCheck -check-prefixes CHECK,WITHOUT %s +// RUN: %clang -target x86_64-linux-gnu -S -emit-llvm -o - %s -fsanitize=thread | FileCheck -check-prefixes CHECK,TSAN %s + +#include <stdatomic.h> + +// Instrumented function. +// TSan inserts calls to __tsan_func_entry() and __tsan_func_exit() to prologue/epilogue. +// Non-atomic loads are instrumented with __tsan_readXXX(), atomic loads - with +// __tsan_atomicXXX_load(). +// +// CHECK-LABEL: @instrumented1 +// TSAN: call void @__tsan_func_entry +// WITHOUT-NOT: call void @__tsan_func_entry +// TSAN: call void @__tsan_read4 +// WITHOUT-NOT: call void @__tsan_read4 +// TSAN: call i32 @__tsan_atomic32_load +// WITHOUT-NOT: call i32 @__tsan_atomic32_load +// TSAN: call void @__tsan_func_exit +// WITHOUT-NOT: call void @__tsan_func_exit +// CHECK: ret i32 +int instrumented1(int *a, _Atomic int *b) { + return *a + atomic_load(b); +} + +// Function with no_sanitize("thread"). +// TSan only inserts instrumentation necessary to prevent false positives: calls are inserted for +// function entry/exit and atomics, but not plain memory accesses. +// +// CHECK-LABEL: @no_false_positives1 +// TSAN: call void @__tsan_func_entry +// WITHOUT-NOT: call void @__tsan_func_entry +// TSAN-NOT: call void @__tsan_read4 +// WITHOUT-NOT: call void @__tsan_read4 +// TSAN: call i32 @__tsan_atomic32_load +// WITHOUT-NOT: call i32 @__tsan_atomic32_load +// TSAN: call void @__tsan_func_exit +// WITHOUT-NOT: call void @__tsan_func_exit +// CHECK: ret i32 +__attribute__((no_sanitize("thread"))) int no_false_positives1(int *a, _Atomic int *b) { + return *a + atomic_load(b); +} + +// Function with disable_sanitizer_instrumentation: no instrumentation at all. +// +// CHECK-LABEL: @no_instrumentation1 +// TSAN-NOT: call void @__tsan_func_entry +// WITHOUT-NOT: call void @__tsan_func_entry +// TSAN-NOT: call void @__tsan_read4 +// WITHOUT-NOT: call void @__tsan_read4 +// TSAN-NOT: call i32 @__tsan_atomic32_load +// WITHOUT-NOT: call i32 @__tsan_atomic32_load +// TSAN-NOT: call void @__tsan_func_exit +// WITHOUT-NOT: call void @__tsan_func_exit +// CHECK: ret i32 +__attribute__((disable_sanitizer_instrumentation)) int no_instrumentation1(int *a, _Atomic int *b) { + return *a + atomic_load(b); +} diff --git a/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp index 87fdcc9114f44..714e21dc82bb4 100644 --- a/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp @@ -562,6 +562,12 @@ bool ThreadSanitizer::sanitizeFunction(Function &F, // all. if (F.hasFnAttribute(Attribute::Naked)) return false; + + // __attribute__(disable_sanitizer_instrumentation) prevents all kinds of + // instrumentation. + if (F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation)) + return false; + initialize(*F.getParent()); SmallVector<InstructionInfo, 8> AllLoadsAndStores; SmallVector<Instruction*, 8> LocalLoadsAndStores; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits