Index: compiler-rt/trunk/include/sanitizer/msan_interface.h =================================================================== --- compiler-rt/trunk/include/sanitizer/msan_interface.h +++ compiler-rt/trunk/include/sanitizer/msan_interface.h @@ -104,6 +104,14 @@ copy. Source and destination regions can overlap. */ void __msan_copy_shadow(const volatile void *dst, const volatile void *src, size_t size); + + /* Disables uninitialized memory checks in interceptors. */ + void __msan_scoped_disable_interceptor_checks(void); + + /* Re-enables uninitialized memory checks in interceptors after a previous + call to __msan_scoped_disable_interceptor_checks. */ + void __msan_scoped_enable_interceptor_checks(void); + #ifdef __cplusplus } // extern "C" #endif Index: compiler-rt/trunk/lib/msan/msan_interceptors.cc =================================================================== --- compiler-rt/trunk/lib/msan/msan_interceptors.cc +++ compiler-rt/trunk/lib/msan/msan_interceptors.cc @@ -60,6 +60,9 @@ // True if this is a nested interceptor. static THREADLOCAL int in_interceptor_scope; +void __msan_scoped_disable_interceptor_checks() { ++in_interceptor_scope; } +void __msan_scoped_enable_interceptor_checks() { --in_interceptor_scope; } + struct InterceptorScope { InterceptorScope() { ++in_interceptor_scope; } ~InterceptorScope() { --in_interceptor_scope; } Index: compiler-rt/trunk/lib/msan/msan_interface_internal.h =================================================================== --- compiler-rt/trunk/lib/msan/msan_interface_internal.h +++ compiler-rt/trunk/lib/msan/msan_interface_internal.h @@ -174,6 +174,12 @@ SANITIZER_INTERFACE_ATTRIBUTE void __msan_copy_shadow(void *dst, const void *src, uptr size); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_scoped_disable_interceptor_checks(); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_scoped_enable_interceptor_checks(); } // extern "C" #endif // MSAN_INTERFACE_INTERNAL_H Index: compiler-rt/trunk/test/msan/scoped-interceptors.cc =================================================================== --- compiler-rt/trunk/test/msan/scoped-interceptors.cc +++ compiler-rt/trunk/test/msan/scoped-interceptors.cc @@ -0,0 +1,52 @@ +// RUN: %clangxx_msan %s -o %t +// RUN: %run %t --disable-checks 0 2>&1 | FileCheck --check-prefix=DISABLED --allow-empty %s +// RUN: %run %t --disable-checks 1 2>&1 | FileCheck --check-prefix=DISABLED --allow-empty %s +// RUN: %run %t --disable-checks 2 2>&1 | FileCheck --check-prefix=DISABLED --allow-empty %s +// RUN: %run %t --disable-checks 3 2>&1 | FileCheck --check-prefix=DISABLED --allow-empty %s +// RUN: not %run %t --reenable-checks 0 2>&1 | FileCheck --check-prefix=CASE-0 %s +// RUN: not %run %t --reenable-checks 1 2>&1 | FileCheck --check-prefix=CASE-1 %s +// RUN: not %run %t --reenable-checks 2 2>&1 | FileCheck --check-prefix=CASE-2 %s +// RUN: not %run %t --reenable-checks 3 2>&1 | FileCheck --check-prefix=CASE-3 %s + +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + assert(argc == 3); + __msan_scoped_disable_interceptor_checks(); + if (strcmp(argv[1], "--reenable-checks") == 0) + __msan_scoped_enable_interceptor_checks(); + + char uninit[7]; + switch (argv[2][0]) { + case '0': { + char *copy = strndup(uninit, sizeof(uninit)); // BOOM + free(copy); + break; + // CASE-0: Uninitialized bytes in __interceptor_strndup + } + case '1': { + puts(uninit); // BOOM + puts(uninit); // Ensure previous call did not enable interceptor checks. + break; + // CASE-1: Uninitialized bytes in __interceptor_puts + } + case '2': { + int cmp = memcmp(uninit, uninit, sizeof(uninit)); // BOOM + break; + // CASE-2: Uninitialized bytes in __interceptor_memcmp + } + case '3': { + size_t len = strlen(uninit); // BOOM + break; + // CASE-3: Uninitialized bytes in __interceptor_strlen + } + default: assert(0); + } + // DISABLED-NOT: Uninitialized bytes + return 0; +} +