aboutsummaryrefslogtreecommitdiff
path: root/contrib/libc++/src/exception.cpp
blob: f25041d83427689595fe8635fd9f7e157ce53e1c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
//===------------------------ exception.cpp -------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <stdlib.h>
#include <stdio.h>

#include "exception"
#include "new"

#if defined(_LIBCPP_ABI_MICROSOFT)
#include <eh.h>
#include <corecrt_terminate.h>
#elif defined(__APPLE__) && !defined(LIBCXXRT) && \
    !defined(_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY)
  #include <cxxabi.h>

  using namespace __cxxabiv1;
  #define HAVE_DEPENDENT_EH_ABI 1
  #ifndef _LIBCPPABI_VERSION
    using namespace __cxxabiapple;
    // On Darwin, there are two STL shared libraries and a lower level ABI
    // shared library.  The globals holding the current terminate handler and
    // current unexpected handler are in the ABI library.
    #define __terminate_handler  __cxxabiapple::__cxa_terminate_handler
    #define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler
  #endif  // _LIBCPPABI_VERSION
#elif defined(LIBCXXRT) || defined(LIBCXX_BUILDING_LIBCXXABI)
  #include <cxxabi.h>
  using namespace __cxxabiv1;
  #if defined(LIBCXXRT) || defined(_LIBCPPABI_VERSION)
    #define HAVE_DEPENDENT_EH_ABI 1
  #endif
#elif !defined(__GLIBCXX__) // defined(LIBCXX_BUILDING_LIBCXXABI)
  _LIBCPP_SAFE_STATIC static std::terminate_handler  __terminate_handler;
  _LIBCPP_SAFE_STATIC static std::unexpected_handler __unexpected_handler;
#endif // defined(LIBCXX_BUILDING_LIBCXXABI)

namespace std
{

#if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)

// libcxxrt provides implementations of these functions itself.
unexpected_handler
set_unexpected(unexpected_handler func) _NOEXCEPT
{
#if defined(_LIBCPP_ABI_MICROSOFT)
  return ::set_unexpected(func);
#else
  return __sync_lock_test_and_set(&__unexpected_handler, func);
#endif
}

unexpected_handler
get_unexpected() _NOEXCEPT
{
#if defined(_LIBCPP_ABI_MICROSOFT)
  return ::_get_unexpected();
#else
  return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
#endif
}

_LIBCPP_NORETURN
void
unexpected()
{
    (*get_unexpected())();
    // unexpected handler should not return
    terminate();
}

terminate_handler
set_terminate(terminate_handler func) _NOEXCEPT
{
#if defined(_LIBCPP_ABI_MICROSOFT)
  return ::set_terminate(func);
#else
  return __sync_lock_test_and_set(&__terminate_handler, func);
#endif
}

terminate_handler
get_terminate() _NOEXCEPT
{
#if defined(_LIBCPP_ABI_MICROSOFT)
  return ::_get_terminate();
#else
  return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
#endif
}

#ifndef __EMSCRIPTEN__ // We provide this in JS
_LIBCPP_NORETURN
void
terminate() _NOEXCEPT
{
#ifndef _LIBCPP_NO_EXCEPTIONS
    try
    {
#endif  // _LIBCPP_NO_EXCEPTIONS
        (*get_terminate())();
        // handler should not return
        fprintf(stderr, "terminate_handler unexpectedly returned\n");
        ::abort();
#ifndef _LIBCPP_NO_EXCEPTIONS
    }
    catch (...)
    {
        // handler should not throw exception
        fprintf(stderr, "terminate_handler unexpectedly threw an exception\n");
        ::abort();
    }
#endif  // _LIBCPP_NO_EXCEPTIONS
}
#endif // !__EMSCRIPTEN__
#endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)

#if !defined(LIBCXXRT) && !defined(__GLIBCXX__) && !defined(__EMSCRIPTEN__)

bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }

int uncaught_exceptions() _NOEXCEPT
{
#if !defined(_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY) && \
    (defined(__APPLE__) || defined(_LIBCPPABI_VERSION))
   // on Darwin, there is a helper function so __cxa_get_globals is private
# if _LIBCPPABI_VERSION > 1101
    return __cxa_uncaught_exceptions();
# else
    return __cxa_uncaught_exception() ? 1 : 0;
# endif
#elif defined(_LIBCPP_ABI_MICROSOFT)
    return __uncaught_exceptions();
#else
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("uncaught_exceptions not yet implemented")
#   else
#       warning uncaught_exception not yet implemented
#   endif
    fprintf(stderr, "uncaught_exceptions not yet implemented\n");
    ::abort();
#endif  // __APPLE__
}


#ifndef _LIBCPPABI_VERSION

exception::~exception() _NOEXCEPT
{
}

const char* exception::what() const _NOEXCEPT
{
  return "std::exception";
}

#endif  // _LIBCPPABI_VERSION
#endif //LIBCXXRT
#if !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)

bad_exception::~bad_exception() _NOEXCEPT
{
}

const char* bad_exception::what() const _NOEXCEPT
{
  return "std::bad_exception";
}

#endif

#if defined(__GLIBCXX__)

// libsupc++ does not implement the dependent EH ABI and the functionality
// it uses to implement std::exception_ptr (which it declares as an alias of
// std::__exception_ptr::exception_ptr) is not directly exported to clients. So
// we have little choice but to hijack std::__exception_ptr::exception_ptr's
// (which fortunately has the same layout as our std::exception_ptr) copy
// constructor, assignment operator and destructor (which are part of its
// stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr)
// function.

namespace __exception_ptr
{

struct exception_ptr
{
    void* __ptr_;

    exception_ptr(const exception_ptr&) _NOEXCEPT;
    exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
    ~exception_ptr() _NOEXCEPT;
};

}

_LIBCPP_NORETURN void rethrow_exception(__exception_ptr::exception_ptr);

#endif

exception_ptr::~exception_ptr() _NOEXCEPT
{
#if HAVE_DEPENDENT_EH_ABI
    __cxa_decrement_exception_refcount(__ptr_);
#elif defined(__GLIBCXX__)
    reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr();
#else
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("exception_ptr not yet implemented")
#   else
#       warning exception_ptr not yet implemented
#   endif
    fprintf(stderr, "exception_ptr not yet implemented\n");
    ::abort();
#endif
}

exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
    : __ptr_(other.__ptr_)
{
#if HAVE_DEPENDENT_EH_ABI
    __cxa_increment_exception_refcount(__ptr_);
#elif defined(__GLIBCXX__)
    new (reinterpret_cast<void*>(this)) __exception_ptr::exception_ptr(
        reinterpret_cast<const __exception_ptr::exception_ptr&>(other));
#else
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("exception_ptr not yet implemented")
#   else
#       warning exception_ptr not yet implemented
#   endif
    fprintf(stderr, "exception_ptr not yet implemented\n");
    ::abort();
#endif
}

exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
{
#if HAVE_DEPENDENT_EH_ABI
    if (__ptr_ != other.__ptr_)
    {
        __cxa_increment_exception_refcount(other.__ptr_);
        __cxa_decrement_exception_refcount(__ptr_);
        __ptr_ = other.__ptr_;
    }
    return *this;
#elif defined(__GLIBCXX__)
    *reinterpret_cast<__exception_ptr::exception_ptr*>(this) =
        reinterpret_cast<const __exception_ptr::exception_ptr&>(other);
    return *this;
#else
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("exception_ptr not yet implemented")
#   else
#       warning exception_ptr not yet implemented
#   endif
    fprintf(stderr, "exception_ptr not yet implemented\n");
    ::abort();
#endif
}

nested_exception::nested_exception() _NOEXCEPT
    : __ptr_(current_exception())
{
}

#if !defined(__GLIBCXX__)

nested_exception::~nested_exception() _NOEXCEPT
{
}

#endif

_LIBCPP_NORETURN
void
nested_exception::rethrow_nested() const
{
    if (__ptr_ == nullptr)
        terminate();
    rethrow_exception(__ptr_);
}

#if !defined(__GLIBCXX__)

exception_ptr current_exception() _NOEXCEPT
{
#if HAVE_DEPENDENT_EH_ABI
    // be nicer if there was a constructor that took a ptr, then
    // this whole function would be just:
    //    return exception_ptr(__cxa_current_primary_exception());
    exception_ptr ptr;
    ptr.__ptr_ = __cxa_current_primary_exception();
    return ptr;
#else
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING( "exception_ptr not yet implemented" )
#   else
#       warning exception_ptr not yet implemented
#   endif
    fprintf(stderr, "exception_ptr not yet implemented\n");
    ::abort();
#endif
}

#endif  // !__GLIBCXX__

_LIBCPP_NORETURN
void rethrow_exception(exception_ptr p)
{
#if HAVE_DEPENDENT_EH_ABI
    __cxa_rethrow_primary_exception(p.__ptr_);
    // if p.__ptr_ is NULL, above returns so we terminate
    terminate();
#elif defined(__GLIBCXX__)
    rethrow_exception(reinterpret_cast<__exception_ptr::exception_ptr&>(p));
#else
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("exception_ptr not yet implemented")
#   else
#       warning exception_ptr not yet implemented
#   endif
    fprintf(stderr, "exception_ptr not yet implemented\n");
    ::abort();
#endif
}
} // std