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