master
  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 <cstdlib> // std::abort
 13#include <exception>
 14#include <new>
 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
 24static constinit const char* cause = "uncaught";
 25
 26#  ifndef _LIBCXXABI_NO_EXCEPTIONS
 27__attribute__((noreturn))
 28static void demangling_terminate_handler()
 29{
 30    using namespace __cxxabiv1;
 31    __cxa_eh_globals* globals = __cxa_get_globals_fast();
 32
 33    // If there is no uncaught exception, just note that we're terminating
 34    if (!globals)
 35        __abort_message("terminating");
 36
 37    __cxa_exception* exception_header = globals->caughtExceptions;
 38    if (!exception_header)
 39        __abort_message("terminating");
 40
 41    _Unwind_Exception* unwind_exception =
 42        reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
 43
 44    // If we're terminating due to a foreign exception
 45    if (!__isOurExceptionClass(unwind_exception))
 46        __abort_message("terminating due to %s foreign exception", cause);
 47
 48    void* thrown_object =
 49        __getExceptionClass(unwind_exception) == kOurDependentExceptionClass ?
 50            ((__cxa_dependent_exception*)exception_header)->primaryException :
 51            exception_header + 1;
 52    const __shim_type_info* thrown_type =
 53        static_cast<const __shim_type_info*>(exception_header->exceptionType);
 54
 55    auto name = [str = thrown_type->name()] {
 56#    ifndef LIBCXXABI_NON_DEMANGLING_TERMINATE
 57      if (const char* result = __cxxabiv1::__cxa_demangle(str, nullptr, nullptr, nullptr))
 58        // We're about to abort(), this memory can never be freed; so it's fine
 59        // to just return a raw pointer
 60        return result;
 61#    endif
 62      return str;
 63    }();
 64
 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, 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);
 78    }
 79}
 80#else // !_LIBCXXABI_NO_EXCEPTIONS
 81__attribute__((noreturn))
 82static void demangling_terminate_handler()
 83{
 84    __abort_message("terminating");
 85}
 86#endif // !_LIBCXXABI_NO_EXCEPTIONS
 87
 88__attribute__((noreturn))
 89static void demangling_unexpected_handler()
 90{
 91    cause = "unexpected";
 92    std::terminate();
 93}
 94
 95static constexpr std::terminate_handler default_terminate_handler = demangling_terminate_handler;
 96static constexpr std::terminate_handler default_unexpected_handler = demangling_unexpected_handler;
 97#else // !LIBCXXABI_SILENT_TERMINATE
 98static constexpr std::terminate_handler default_terminate_handler = std::abort;
 99static 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
106constinit std::terminate_handler __cxa_terminate_handler = default_terminate_handler;
107
108_LIBCXXABI_DATA_VIS
109constinit std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;
110
111_LIBCXXABI_DATA_VIS
112constinit std::new_handler __cxa_new_handler = nullptr;
113
114namespace std
115{
116
117unexpected_handler
118set_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
126terminate_handler
127set_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
135new_handler
136set_new_handler(new_handler handler) noexcept
137{
138    return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel);
139}
140
141}