xref: /llvm-project/libcxxabi/src/cxa_default_handlers.cpp (revision 59890c13343af9e308281b3c76bac425087f4f8a)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //
8 // This file implements the default terminate_handler, unexpected_handler and
9 // new_handler.
10 //===----------------------------------------------------------------------===//
11 
12 #include <exception>
13 #include <new>
14 #include "abort_message.h"
15 #include "cxxabi.h"
16 #include "cxa_handlers.h"
17 #include "cxa_exception.h"
18 #include "private_typeinfo.h"
19 #include "include/atomic_support.h" // from libc++
20 
21 #if !defined(LIBCXXABI_SILENT_TERMINATE)
22 
23 static constinit const char* cause = "uncaught";
24 
25 #  ifndef _LIBCXXABI_NO_EXCEPTIONS
26 __attribute__((noreturn))
27 static void demangling_terminate_handler()
28 {
29     using namespace __cxxabiv1;
30     __cxa_eh_globals* globals = __cxa_get_globals_fast();
31 
32     // If there is no uncaught exception, just note that we're terminating
33     if (!globals)
34         __abort_message("terminating");
35 
36     __cxa_exception* exception_header = globals->caughtExceptions;
37     if (!exception_header)
38         __abort_message("terminating");
39 
40     _Unwind_Exception* unwind_exception =
41         reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
42 
43     // If we're terminating due to a foreign exception
44     if (!__isOurExceptionClass(unwind_exception))
45         __abort_message("terminating due to %s foreign exception", cause);
46 
47     void* thrown_object =
48         __getExceptionClass(unwind_exception) == kOurDependentExceptionClass ?
49             ((__cxa_dependent_exception*)exception_header)->primaryException :
50             exception_header + 1;
51     const __shim_type_info* thrown_type =
52         static_cast<const __shim_type_info*>(exception_header->exceptionType);
53 
54     auto name = [str = thrown_type->name()] {
55 #    ifndef LIBCXXABI_NON_DEMANGLING_TERMINATE
56       if (const char* result = __cxxabiv1::__cxa_demangle(str, nullptr, nullptr, nullptr))
57         // We're about to abort(), this memory can never be freed; so it's fine
58         // to just return a raw pointer
59         return result;
60 #    endif
61       return str;
62     }();
63 
64     // If the uncaught exception can be caught with std::exception&
65     const __shim_type_info* catch_type =
66         static_cast<const __shim_type_info*>(&typeid(std::exception));
67     if (catch_type->can_catch(thrown_type, thrown_object))
68     {
69         // Include the what() message from the exception
70         const std::exception* e = static_cast<const std::exception*>(thrown_object);
71         __abort_message("terminating due to %s exception of type %s: %s", cause, name, e->what());
72     }
73     else
74     {
75         // Else just note that we're terminating due to an exception
76         __abort_message("terminating due to %s exception of type %s", cause, name);
77     }
78 }
79 #else // !_LIBCXXABI_NO_EXCEPTIONS
80 __attribute__((noreturn))
81 static void demangling_terminate_handler()
82 {
83     __abort_message("terminating");
84 }
85 #endif // !_LIBCXXABI_NO_EXCEPTIONS
86 
87 __attribute__((noreturn))
88 static void demangling_unexpected_handler()
89 {
90     cause = "unexpected";
91     std::terminate();
92 }
93 
94 static constexpr std::terminate_handler default_terminate_handler = demangling_terminate_handler;
95 static constexpr std::terminate_handler default_unexpected_handler = demangling_unexpected_handler;
96 #else // !LIBCXXABI_SILENT_TERMINATE
97 static constexpr std::terminate_handler default_terminate_handler = ::abort;
98 static constexpr std::terminate_handler default_unexpected_handler = std::terminate;
99 #endif // !LIBCXXABI_SILENT_TERMINATE
100 
101 //
102 // Global variables that hold the pointers to the current handler
103 //
104 _LIBCXXABI_DATA_VIS
105 constinit std::terminate_handler __cxa_terminate_handler = default_terminate_handler;
106 
107 _LIBCXXABI_DATA_VIS
108 constinit std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;
109 
110 _LIBCXXABI_DATA_VIS
111 constinit std::new_handler __cxa_new_handler = nullptr;
112 
113 namespace std
114 {
115 
116 unexpected_handler
117 set_unexpected(unexpected_handler func) noexcept
118 {
119     if (func == 0)
120         func = default_unexpected_handler;
121     return __libcpp_atomic_exchange(&__cxa_unexpected_handler, func,
122                                     _AO_Acq_Rel);
123 }
124 
125 terminate_handler
126 set_terminate(terminate_handler func) noexcept
127 {
128     if (func == 0)
129         func = default_terminate_handler;
130     return __libcpp_atomic_exchange(&__cxa_terminate_handler, func,
131                                     _AO_Acq_Rel);
132 }
133 
134 new_handler
135 set_new_handler(new_handler handler) noexcept
136 {
137     return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel);
138 }
139 
140 }
141