Coverage Report

Created: 2025-08-11 07:06

/src/llvm-project-18.1.8.src/libcxxabi/src/cxa_default_handlers.cpp
Line
Count
Source (jump to first uncovered line)
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
0
{
30
0
#if !defined(LIBCXXABI_NON_DEMANGLING_TERMINATE)
31
0
    if (const char* result = __cxxabiv1::__cxa_demangle(str, nullptr, nullptr, nullptr))
32
0
        return {result, [](char const* p) { std::free(const_cast<char*>(p)); }};
33
0
#endif
34
0
    return {str, [](char const*) { /* nothing to free */ }};
35
0
}
36
37
__attribute__((noreturn))
38
static void demangling_terminate_handler()
39
0
{
40
0
    using namespace __cxxabiv1;
41
0
    __cxa_eh_globals* globals = __cxa_get_globals_fast();
42
43
    // If there is no uncaught exception, just note that we're terminating
44
0
    if (!globals)
45
0
        abort_message("terminating");
46
47
0
    __cxa_exception* exception_header = globals->caughtExceptions;
48
0
    if (!exception_header)
49
0
        abort_message("terminating");
50
51
0
    _Unwind_Exception* unwind_exception =
52
0
        reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
53
54
    // If we're terminating due to a foreign exception
55
0
    if (!__isOurExceptionClass(unwind_exception))
56
0
        abort_message("terminating due to %s foreign exception", cause);
57
58
0
    void* thrown_object =
59
0
        __getExceptionClass(unwind_exception) == kOurDependentExceptionClass ?
60
0
            ((__cxa_dependent_exception*)exception_header)->primaryException :
61
0
            exception_header + 1;
62
0
    const __shim_type_info* thrown_type =
63
0
        static_cast<const __shim_type_info*>(exception_header->exceptionType);
64
0
    auto name = demangle(thrown_type->name());
65
    // If the uncaught exception can be caught with std::exception&
66
0
    const __shim_type_info* catch_type =
67
0
        static_cast<const __shim_type_info*>(&typeid(std::exception));
68
0
    if (catch_type->can_catch(thrown_type, thrown_object))
69
0
    {
70
        // Include the what() message from the exception
71
0
        const std::exception* e = static_cast<const std::exception*>(thrown_object);
72
0
        abort_message("terminating due to %s exception of type %s: %s", cause, name.get(), e->what());
73
0
    }
74
0
    else
75
0
    {
76
        // Else just note that we're terminating due to an exception
77
0
        abort_message("terminating due to %s exception of type %s", cause, name.get());
78
0
    }
79
0
}
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
0
{
91
0
    cause = "unexpected";
92
0
    std::terminate();
93
0
}
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
0
{
120
0
    if (func == 0)
121
0
        func = default_unexpected_handler;
122
0
    return __libcpp_atomic_exchange(&__cxa_unexpected_handler, func,
123
0
                                    _AO_Acq_Rel);
124
0
}
125
126
terminate_handler
127
set_terminate(terminate_handler func) noexcept
128
0
{
129
0
    if (func == 0)
130
0
        func = default_terminate_handler;
131
0
    return __libcpp_atomic_exchange(&__cxa_terminate_handler, func,
132
0
                                    _AO_Acq_Rel);
133
0
}
134
135
new_handler
136
set_new_handler(new_handler handler) noexcept
137
0
{
138
0
    return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel);
139
0
}
140
141
}