1673dc3d4SNico Weber // Regression test for
2673dc3d4SNico Weber // https://bugs.llvm.org/show_bug.cgi?id=32434
3673dc3d4SNico Weber 
4ac191bccSLeonard Chan // REQUIRES: shared_cxxabi
5ac191bccSLeonard Chan 
6673dc3d4SNico Weber // RUN: %clangxx_asan -fexceptions -O0 %s -o %t
7*4b4437c0SVitaly Buka // RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t
8673dc3d4SNico Weber 
9673dc3d4SNico Weber // The current implementation of this functionality requires special
10673dc3d4SNico Weber // combination of libraries that are not used by default on NetBSD
11673dc3d4SNico Weber // XFAIL: netbsd
12673dc3d4SNico Weber // FIXME: Bug 42703
13673dc3d4SNico Weber // XFAIL: solaris
14673dc3d4SNico Weber 
1591f0a6adSVitaly Buka // https://reviews.llvm.org/D111703 made compiler incompatible with released NDK.
1691f0a6adSVitaly Buka // UNSUPPORTED: android && arm-target-arch
1791f0a6adSVitaly Buka 
18673dc3d4SNico Weber #include <assert.h>
19673dc3d4SNico Weber #include <exception>
20673dc3d4SNico Weber #include <sanitizer/asan_interface.h>
21673dc3d4SNico Weber 
22673dc3d4SNico Weber namespace {
23673dc3d4SNico Weber 
24673dc3d4SNico Weber // Not instrumented because std::rethrow_exception is a [[noreturn]] function,
25673dc3d4SNico Weber // for which the compiler would emit a call to __asan_handle_no_return which
26673dc3d4SNico Weber // unpoisons the stack.
27673dc3d4SNico Weber // We emulate here some code not compiled with asan. This function is not
28673dc3d4SNico Weber // [[noreturn]] because the scenario we're emulating doesn't always throw. If it
29673dc3d4SNico Weber // were [[noreturn]], the calling code would emit a call to
30673dc3d4SNico Weber // __asan_handle_no_return.
31673dc3d4SNico Weber void __attribute__((no_sanitize("address")))
uninstrumented_rethrow_exception(std::exception_ptr const & exc_ptr)32673dc3d4SNico Weber uninstrumented_rethrow_exception(std::exception_ptr const &exc_ptr) {
33673dc3d4SNico Weber   std::rethrow_exception(exc_ptr);
34673dc3d4SNico Weber }
35673dc3d4SNico Weber 
36673dc3d4SNico Weber char *poisoned1;
37673dc3d4SNico Weber char *poisoned2;
38673dc3d4SNico Weber 
39673dc3d4SNico Weber // Create redzones for stack variables in shadow memory and call
40673dc3d4SNico Weber // std::rethrow_exception which should unpoison the entire stack.
create_redzones_and_throw(std::exception_ptr const & exc_ptr)41673dc3d4SNico Weber void create_redzones_and_throw(std::exception_ptr const &exc_ptr) {
42673dc3d4SNico Weber   char a[100];
43673dc3d4SNico Weber   poisoned1 = a - 1;
44673dc3d4SNico Weber   poisoned2 = a + sizeof(a);
45673dc3d4SNico Weber   assert(__asan_address_is_poisoned(poisoned1));
46673dc3d4SNico Weber   assert(__asan_address_is_poisoned(poisoned2));
47673dc3d4SNico Weber   uninstrumented_rethrow_exception(exc_ptr);
48673dc3d4SNico Weber }
49673dc3d4SNico Weber 
50673dc3d4SNico Weber } // namespace
51673dc3d4SNico Weber 
52673dc3d4SNico Weber // Check that std::rethrow_exception is intercepted by asan and the interception
53673dc3d4SNico Weber // unpoisons the stack.
54673dc3d4SNico Weber // If std::rethrow_exception is NOT intercepted, then calls to this function
55673dc3d4SNico Weber // from instrumented code will still unpoison the stack because
56673dc3d4SNico Weber // std::rethrow_exception is a [[noreturn]] function and any [[noreturn]]
57673dc3d4SNico Weber // function call will be instrumented with __asan_handle_no_return.
58673dc3d4SNico Weber // However, calls to std::rethrow_exception from UNinstrumented code will not
59673dc3d4SNico Weber // unpoison the stack, so we need to intercept std::rethrow_exception to
60673dc3d4SNico Weber // unpoison the stack.
main()61673dc3d4SNico Weber int main() {
62673dc3d4SNico Weber   // In some implementations of std::make_exception_ptr, e.g. libstdc++ prior to
63673dc3d4SNico Weber   // gcc 7, this function calls __cxa_throw. The __cxa_throw is intercepted by
64673dc3d4SNico Weber   // asan to unpoison the entire stack; since this test essentially tests that
65673dc3d4SNico Weber   // the stack is unpoisoned by a call to std::rethrow_exception, we need to
66673dc3d4SNico Weber   // generate the exception_ptr BEFORE we have the local variables poison the
67673dc3d4SNico Weber   // stack.
68673dc3d4SNico Weber   std::exception_ptr my_exception_ptr = std::make_exception_ptr("up");
69673dc3d4SNico Weber 
70673dc3d4SNico Weber   try {
71673dc3d4SNico Weber     create_redzones_and_throw(my_exception_ptr);
72673dc3d4SNico Weber   } catch(char const *) {
73673dc3d4SNico Weber     assert(!__asan_region_is_poisoned(poisoned1, poisoned2 - poisoned1 + 1));
74673dc3d4SNico Weber   }
75673dc3d4SNico Weber }
76