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 <memory> 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" 20 #include "include/atomic_support.h" // from libc++ 21 22 #if !defined(LIBCXXABI_SILENT_TERMINATE) 23 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 } 36 37 __attribute__((noreturn)) 38 static void demangling_terminate_handler() 39 { 40 using namespace __cxxabiv1; 41 __cxa_eh_globals* globals = __cxa_get_globals_fast(); 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)) 69 { 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()); 73 } 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 { 84 abort_message("terminating"); 85 } 86 #endif // !_LIBCXXABI_NO_EXCEPTIONS 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; 97 #else // !LIBCXXABI_SILENT_TERMINATE 98 static constexpr std::terminate_handler default_terminate_handler = ::abort; 99 static constexpr std::terminate_handler default_unexpected_handler = std::terminate; 100 #endif // !LIBCXXABI_SILENT_TERMINATE 101 102 // 103 // Global variables that hold the pointers to the current handler 104 // 105 _LIBCXXABI_DATA_VIS 106 constinit std::terminate_handler __cxa_terminate_handler = default_terminate_handler; 107 108 _LIBCXXABI_DATA_VIS 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; 113 114 namespace std 115 { 116 117 unexpected_handler 118 set_unexpected(unexpected_handler func) noexcept 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 127 set_terminate(terminate_handler func) noexcept 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 135 new_handler 136 set_new_handler(new_handler handler) noexcept 137 { 138 return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel); 139 } 140 141 } 142