[msan] Add support for disable_sanitizer_instrumentation attribute

Unlike __attribute__((no_sanitize("memory"))), this one will cause MSan
to skip the entire function during instrumentation.

Depends on https://reviews.llvm.org/D108029

Differential Revision: https://reviews.llvm.org/D108199
This commit is contained in:
Alexander Potapenko 2021-08-17 11:34:22 +02:00
parent 791d88f35f
commit 8dc7dcdca1
3 changed files with 70 additions and 0 deletions

View File

@ -85,6 +85,15 @@ particular function. MemorySanitizer may still instrument such functions to
avoid false positives. This attribute may not be supported by other compilers, avoid false positives. This attribute may not be supported by other compilers,
so we suggest to use it together with ``__has_feature(memory_sanitizer)``. so we suggest to use it together with ``__has_feature(memory_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 therefore 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("memory")``.
Ignorelist Ignorelist
---------- ----------

View File

@ -0,0 +1,58 @@
// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck -check-prefixes CHECK,WITHOUT %s
// RUN: %clang_cc1 -emit-llvm -o - %s -fsanitize=memory | FileCheck -check-prefixes CHECK,MSAN %s
// RUN: %clang_cc1 -emit-llvm -o - %s -fsanitize=kernel-memory | FileCheck -check-prefixes CHECK,KMSAN %s
// Instrumented function.
// MSan uses memset(addr, -1, size) to poison allocas and stores shadow of the return value in
// __msan_retval_tls. KMSAN uses __msan_poison_alloca() to poison allocas and calls
// __msan_get_context_state() at function prologue to access the task context struct (including the
// shadow of the return value).
//
// CHECK-LABEL: i32 @instrumented1
// KMSAN: __msan_get_context_state
// WITHOUT-NOT: __msan_poison_alloca
// WITHOUT-NOT: @llvm.memset
// MSAN: @llvm.memset{{.*}}({{.*}}, i8 -1
// KMSAN: __msan_poison_alloca
// WITHOUT-NOT: __msan_retval_tls
// MSAN: __msan_retval_tls
// CHECK: ret i32
int instrumented1(int *a) {
volatile char buf[8];
return *a;
}
// Function with no_sanitize("memory")/no_sanitize("kernel-memory"): no shadow propagation, but
// unpoisons memory to prevent false positives.
// MSan uses memset(addr, 0, size) to unpoison locals, KMSAN uses __msan_unpoison_alloca(). Both
// tools still access the retval shadow to write 0 to it.
//
// CHECK-LABEL: i32 @no_false_positives1
// KMSAN: __msan_get_context_state
// WITHOUT-NOT: __msan_unpoison_alloca
// WITHOUT-NOT: @llvm.memset
// MSAN: @llvm.memset{{.*}}({{.*}}, i8 0
// KMSAN: __msan_unpoison_alloca
// WITHOUT-NOT: __msan_retval_tls
// MSAN: __msan_retval_tls
// CHECK: ret i32
__attribute__((no_sanitize("memory"))) __attribute__((no_sanitize("kernel-memory"))) int no_false_positives1(int *a) {
volatile char buf[8];
return *a;
}
// Function with disable_sanitizer_instrumentation: no instrumentation at all.
//
// CHECK-LABEL: i32 @no_instrumentation1
// KMSAN-NOT: __msan_get_context_state
// WITHOUT-NOT: __msan_poison_alloca
// WITHOUT-NOT: @llvm.memset
// MSAN-NOT: @llvm.memset{{.*}}({{.*}}, i8 0
// KMSAN-NOT: __msan_unpoison_alloca
// WITHOUT-NOT: __msan_retval_tls
// MSAN-NOT: __msan_retval_tls
// CHECK: ret i32
__attribute__((disable_sanitizer_instrumentation)) int no_instrumentation1(int *a) {
volatile char buf[8];
return *a;
}

View File

@ -5330,6 +5330,9 @@ bool MemorySanitizer::sanitizeFunction(Function &F, TargetLibraryInfo &TLI) {
if (!CompileKernel && F.getName() == kMsanModuleCtorName) if (!CompileKernel && F.getName() == kMsanModuleCtorName)
return false; return false;
if (F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation))
return false;
MemorySanitizerVisitor Visitor(F, *this, TLI); MemorySanitizerVisitor Visitor(F, *this, TLI);
// Clear out readonly/readnone attributes. // Clear out readonly/readnone attributes.