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