1 // Regression test for 2 // https://bugs.llvm.org/show_bug.cgi?id=32434 3 4 // REQUIRES: shared_cxxabi 5 6 // RUN: %clangxx_asan -fexceptions -O0 %s -o %t 7 // RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t 8 9 // The current implementation of this functionality requires special 10 // combination of libraries that are not used by default on NetBSD 11 // XFAIL: target={{.*netbsd.*}} 12 // FIXME: Bug 42703 13 // XFAIL: target={{.*solaris.*}} 14 15 // https://reviews.llvm.org/D111703 made compiler incompatible with released NDK. 16 // UNSUPPORTED: android && arm-target-arch 17 18 #include <assert.h> 19 #include <exception> 20 #include <sanitizer/asan_interface.h> 21 22 namespace { 23 24 // Not instrumented because std::rethrow_exception is a [[noreturn]] function, 25 // for which the compiler would emit a call to __asan_handle_no_return which 26 // unpoisons the stack. 27 // We emulate here some code not compiled with asan. This function is not 28 // [[noreturn]] because the scenario we're emulating doesn't always throw. If it 29 // were [[noreturn]], the calling code would emit a call to 30 // __asan_handle_no_return. 31 void __attribute__((no_sanitize("address"))) uninstrumented_rethrow_exception(std::exception_ptr const & exc_ptr)32uninstrumented_rethrow_exception(std::exception_ptr const &exc_ptr) { 33 std::rethrow_exception(exc_ptr); 34 } 35 36 char *poisoned1; 37 char *poisoned2; 38 39 // Create redzones for stack variables in shadow memory and call 40 // std::rethrow_exception which should unpoison the entire stack. create_redzones_and_throw(std::exception_ptr const & exc_ptr)41void create_redzones_and_throw(std::exception_ptr const &exc_ptr) { 42 char a[100]; 43 poisoned1 = a - 1; 44 poisoned2 = a + sizeof(a); 45 assert(__asan_address_is_poisoned(poisoned1)); 46 assert(__asan_address_is_poisoned(poisoned2)); 47 uninstrumented_rethrow_exception(exc_ptr); 48 } 49 50 } // namespace 51 52 // Check that std::rethrow_exception is intercepted by asan and the interception 53 // unpoisons the stack. 54 // If std::rethrow_exception is NOT intercepted, then calls to this function 55 // from instrumented code will still unpoison the stack because 56 // std::rethrow_exception is a [[noreturn]] function and any [[noreturn]] 57 // function call will be instrumented with __asan_handle_no_return. 58 // However, calls to std::rethrow_exception from UNinstrumented code will not 59 // unpoison the stack, so we need to intercept std::rethrow_exception to 60 // unpoison the stack. main()61int main() { 62 // In some implementations of std::make_exception_ptr, e.g. libstdc++ prior to 63 // gcc 7, this function calls __cxa_throw. The __cxa_throw is intercepted by 64 // asan to unpoison the entire stack; since this test essentially tests that 65 // the stack is unpoisoned by a call to std::rethrow_exception, we need to 66 // generate the exception_ptr BEFORE we have the local variables poison the 67 // stack. 68 std::exception_ptr my_exception_ptr = std::make_exception_ptr("up"); 69 70 try { 71 create_redzones_and_throw(my_exception_ptr); 72 } catch(char const *) { 73 assert(!__asan_region_is_poisoned(poisoned1, poisoned2 - poisoned1 + 1)); 74 } 75 } 76