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