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" ))) |
32 | uninstrumented_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. |
41 | void 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. |
61 | int 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 | |