diff --git a/compiler-rt/include/sanitizer/asan_interface.h b/compiler-rt/include/sanitizer/asan_interface.h --- a/compiler-rt/include/sanitizer/asan_interface.h +++ b/compiler-rt/include/sanitizer/asan_interface.h @@ -323,4 +323,38 @@ } // extern "C" #endif +// Macro for declaring pointer types that should not be instrumented +// by ASan. Loads and stores on pointers of this type will not be +// instrumented. +// +// \note Macro is a no-op when ASan is disabled. +// \note This macro is only supported by Clang. +// +// \param TYPE A pointer type. +// +// Example: +// ASAN_NO_INSTR_PTR(int*) a = 0; +// int b = a[0]; // Not instrumented +// a[0] = 5; // Not instrumented +// +#ifdef __clang__ +# if defined(__has_feature) +# if __has_feature(address_sanitizer) +# define ASAN_NO_INSTR_PTR(TYPE) __attribute__((address_space(1))) TYPE +# else +# define ASAN_NO_INSTR_PTR(TYPE) TYPE +# endif +# else +# error Unreachable +# endif +#else + // Using macro on unsupported compilers should be an error +# ifdef __GNUC__ +# define ASAN_NO_INSTR_PTR(TYPE) _Pragma ("GCC error \"ASAN_NO_INSTR_PTR is only supported by Clang\"") +# else + // TODO(dliew): Support other compilers. For now avoid breaking compilation. +# define ASAN_NO_INSTR_PTR(TYPE) TYPE +# endif +#endif + #endif // SANITIZER_ASAN_INTERFACE_H diff --git a/compiler-rt/test/asan/TestCases/no_instrument_pointer.cpp b/compiler-rt/test/asan/TestCases/no_instrument_pointer.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/no_instrument_pointer.cpp @@ -0,0 +1,46 @@ +// REQUIRES: Clang +// Check non-instrumented binary using ASAN_NO_INSTR_PTR compiles and runs. +// RUN: %clangxx -O0 %s -DUSE_ASAN_MACRO -o %t.no_asan +// RUN: %run %t.no_asan + +// Check instrumented binary without ASAN_NO_INSTR_PTR detects the access to poisoned memory. +// RUN: %clangxx_asan -O0 %s -o %t.asan_find_poison +// RUN: not %run %t.asan_find_poison 2>&1 | FileCheck -check-prefix=CHECK-POISON %s + +// Check instrumented binary with ASAN_NO_INSTR_PTR does not detect access to poisoned memory. +// RUN: %clangxx_asan -O0 -DUSE_ASAN_MACRO %s -o %t.asan_no_find_poison +// RUN: %run %t.asan_no_find_poison +#include "sanitizer/asan_interface.h" +#include +#include +#include + + +#ifndef ASAN_NO_INSTR_PTR +#error ASAN_NO_INSTR_PTR macro is missing +#endif + +int *source() { + unsigned size = sizeof(int) * 32; + int *a = (int *)malloc(size); + memset(a, 0, size); +#if __has_feature(address_sanitizer) + __asan_poison_memory_region(a, size); +#endif + return a; +} + +int main() { +#ifdef USE_ASAN_MACRO + ASAN_NO_INSTR_PTR(int *) + ptr = (ASAN_NO_INSTR_PTR(int *))source(); +#else + int *ptr = source(); +#endif + + // CHECK-POISON: AddressSanitizer: use-after-poison + printf("READ: %d\n", ptr[0]); // Read + ptr[0] = 5; // Write + free((int *)ptr); + return 0; +} diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -1364,6 +1364,8 @@ // Do not instrument acesses from different address spaces; we cannot deal // with them. Type *PtrTy = cast(Ptr->getType()->getScalarType()); + // If this condition is ever changed the `ASAN_NO_INSTR_PTR` macro + // in `compiler-rt/include/sanitizer/asan_interface.h` must be updated. if (PtrTy->getPointerAddressSpace() != 0) return true;