cxa_handlers.cpp revision 7da9b96afc66c4496eb8809897c1b707b574a5c4
1//===------------------------- cxa_handlers.cpp ---------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//
9// This file implements the functionality associated with the terminate_handler,
10//   unexpected_handler, and new_handler.
11//===----------------------------------------------------------------------===//
12
13#include <stdexcept>
14#include <new>
15#include <exception>
16#include "abort_message.h"
17#include "cxxabi.h"
18#include "cxa_handlers.hpp"
19#include "cxa_exception.hpp"
20#include "private_typeinfo.h"
21
22namespace std
23{
24
25static const char* cause = "uncaught";
26
27static void default_terminate_handler()
28{
29    // If there might be an uncaught exception
30    using namespace __cxxabiv1;
31    __cxa_eh_globals* globals = __cxa_get_globals_fast();
32    if (globals)
33    {
34        __cxa_exception* exception_header = globals->caughtExceptions;
35        // If there is an uncaught exception
36        if (exception_header)
37        {
38            _Unwind_Exception* unwind_exception =
39                reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
40            bool native_exception = (unwind_exception->exception_class   & get_language) ==
41                                                     (kOurExceptionClass & get_language);
42            if (native_exception)
43            {
44                void* thrown_object =
45                    unwind_exception->exception_class == kOurDependentExceptionClass ?
46                        ((__cxa_dependent_exception*)exception_header)->primaryException :
47                        exception_header + 1;
48                const __shim_type_info* thrown_type =
49                    static_cast<const __shim_type_info*>(exception_header->exceptionType);
50                const __shim_type_info* catch_type =
51                    static_cast<const __shim_type_info*>(&typeid(exception));
52                // If the uncaught exception can be caught with std::exception&
53                if (catch_type->can_catch(thrown_type, thrown_object))
54                {
55                    // Include the what() message from the exception
56                    const exception* e = static_cast<const exception*>(thrown_object);
57                    abort_message("terminating with %s exception of type %s: %s",
58                                  cause, thrown_type->name(), e->what());
59                }
60                else
61                    // Else just note that we're terminating with an exception
62                    abort_message("terminating with %s exception of type %s",
63                                   cause, thrown_type->name());
64            }
65            else
66                // Else we're terminating with a foreign exception
67                abort_message("terminating with %s foreign exception", cause);
68        }
69    }
70    // Else just note that we're terminating
71    abort_message("terminating");
72}
73
74static void default_unexpected_handler()
75{
76    cause = "unexpected";
77    terminate();
78}
79
80static terminate_handler  __terminate_handler = default_terminate_handler;
81static unexpected_handler __unexpected_handler = default_unexpected_handler;
82static new_handler __new_handler = 0;
83
84unexpected_handler
85set_unexpected(unexpected_handler func) _NOEXCEPT
86{
87    if (func == 0)
88        func = default_unexpected_handler;
89    return __sync_lock_test_and_set(&__unexpected_handler, func);
90}
91
92unexpected_handler
93get_unexpected() _NOEXCEPT
94{
95    return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
96}
97
98__attribute__((visibility("hidden"), noreturn))
99void
100__unexpected(unexpected_handler func)
101{
102    func();
103    // unexpected handler should not return
104    abort_message("unexpected_handler unexpectedly returned");
105}
106
107__attribute__((noreturn))
108void
109unexpected()
110{
111    __unexpected(get_unexpected());
112}
113
114terminate_handler
115set_terminate(terminate_handler func) _NOEXCEPT
116{
117    if (func == 0)
118        func = default_terminate_handler;
119    return __sync_lock_test_and_set(&__terminate_handler, func);
120}
121
122terminate_handler
123get_terminate() _NOEXCEPT
124{
125    return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
126}
127
128__attribute__((visibility("hidden"), noreturn))
129void
130__terminate(terminate_handler func) _NOEXCEPT
131{
132#if __has_feature(cxx_exceptions)
133    try
134    {
135#endif  // __has_feature(cxx_exceptions)
136        func();
137        // handler should not return
138        abort_message("terminate_handler unexpectedly returned");
139#if __has_feature(cxx_exceptions)
140    }
141    catch (...)
142    {
143        // handler should not throw exception
144        abort_message("terminate_handler unexpectedly threw an exception");
145    }
146#endif  // #if __has_feature(cxx_exceptions)
147}
148
149__attribute__((noreturn))
150void
151terminate() _NOEXCEPT
152{
153    __terminate(get_terminate());
154}
155
156new_handler
157set_new_handler(new_handler handler) _NOEXCEPT
158{
159    return __sync_lock_test_and_set(&__new_handler, handler);
160}
161
162new_handler
163get_new_handler() _NOEXCEPT
164{
165    return __sync_fetch_and_add(&__new_handler, (new_handler)0);
166}
167
168}  // std
169