YSTest: exception.cpp 源文件

YSTest PreAlpha_b800_20170810 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

libdefect/exception.cpp
浏览该文件的文档.
1 /*
2 © 2014-2017 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #include <cstddef> // for std::size_t and <bits/c++config.h> if using libstdc++.
29 #include <atomic> // for <bits/atomic_lockfree_defines.h> if using libstdc++.
30
31 #if defined(__GLIBCXX__) \
32 && (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) \
33 && (ATOMIC_INT_LOCK_FREE < 2 && __GNUC__ < 7)
34
35 # include "libdefect/exception.h"
36 # include <cxxabi.h> // for __cxxabiv1 and std::type_info;
37 # include <bits/atomic_word.h> // for ::_Atomic_word;
38 # include <unwind.h> // from libgcc, for __ARM_EABI_UNWINDER__, _Unwind_Ptr,
39 // etc;
40 # if defined(__CLANG_UNWIND_H) && !defined(__ARM_EABI_UNWINDER__) \
41 && defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) \
42 && !defined(__ARM_DWARF_EH__)
43 // NOTE: See https://reviews.llvm.org/D15883.
44 # define __ARM_EABI_UNWINDER__ 1
45 # endif
46
47 # pragma GCC visibility push(default)
48
49 namespace __cxxabiv1
50 {
51
52 struct __cxa_exception
53 {
54 std::type_info* exceptionType;
55 void(_GLIBCXX_CDTOR_CALLABI*exceptionDestructor)(void*);
56 std::unexpected_handler unexpectedHandler;
57 std::terminate_handler terminateHandler;
58 __cxa_exception* nextException;
59 int handlerCount;
60 # ifdef __ARM_EABI_UNWINDER__
61 __cxa_exception* nextPropagatingException;
62 int propagationCount;
63 # else
64 int handlerSwitchValue;
65 const unsigned char* actionRecord;
66 const unsigned char* languageSpecificData;
67 _Unwind_Ptr catchTemp;
68 void* adjustedPtr;
69 # endif
70 _Unwind_Exception unwindHeader;
71 };
72
73 struct __cxa_refcounted_exception
74 {
75 ::_Atomic_word referenceCount;
76 __cxa_exception exc;
77 };
78
79 struct __cxa_dependent_exception
80 {
81 void* primaryException;
82 # if __GNUC__ * 100 + __GNUC_MINOR__ >= 409
83 void(_GLIBCXX_CDTOR_CALLABI*__padding)(void*);
84 # endif
85 std::unexpected_handler unexpectedHandler;
86 std::terminate_handler terminateHandler;
87 __cxa_exception* nextException;
88 int handlerCount;
89 # ifdef __ARM_EABI_UNWINDER__
90 __cxa_exception* nextPropagatingException;
91 int propagationCount;
92 # else
93 int handlerSwitchValue;
94 const unsigned char* actionRecord;
95 const unsigned char* languageSpecificData;
96 _Unwind_Ptr catchTemp;
97 void* adjustedPtr;
98 # endif
99 _Unwind_Exception unwindHeader;
100 };
101
102 struct __cxa_eh_globals
103 {
104 __cxa_exception* caughtExceptions;
105 unsigned int uncaughtExceptions;
106 # ifdef __ARM_EABI_UNWINDER__
107 __cxa_exception* propagatingExceptions;
108 # endif
109 };
110
111 extern void
112 __terminate(std::terminate_handler) noexcept __attribute__((__noreturn__));
113
114
115 namespace
116 {
117
118 inline __cxa_exception*
119 __get_exception_header_from_obj(void* ptr)
120 {
121 return reinterpret_cast<__cxa_exception*>(ptr) - 1;
122 }
123
124 inline __cxa_refcounted_exception*
125 __get_refcounted_exception_header_from_obj(void* ptr)
126 {
127 return reinterpret_cast<__cxa_refcounted_exception*>(ptr) - 1;
128 }
129
131 inline __cxa_refcounted_exception*
132 __get_refcounted_exception_header_from_ue(_Unwind_Exception* exc)
133 {
134 return reinterpret_cast<__cxa_refcounted_exception*>(exc + 1) - 1;
135 }
136
137 inline __cxa_dependent_exception*
138 __get_dependent_exception_from_ue(_Unwind_Exception* exc)
139 {
140 return reinterpret_cast<__cxa_dependent_exception*>(exc + 1) - 1;
141 }
142
143 // NOTE: This should be safe when %_Unwind_Exception_Class is %::uint8_t.
144 # if defined(__ARM_EABI_UNWINDER__) && !defined(__CLANG_UNWIND_H)
145 inline bool
146 __is_gxx_exception_class(_Unwind_Exception_Class c)
147 {
148 // TODO: Deferred. Take advantage of the fact that 'c' will always be
149 // word-aligned.
150 return c[0] == 'G' && c[1] == 'N' && c[2] == 'U' && c[3] == 'C'
151 && c[4] == 'C' && c[5] == '+' && c[6] == '+'
152 && (c[7] == '\0' || c[7] == '\x01');
153 }
154
155 inline bool
156 __is_dependent_exception(_Unwind_Exception_Class c)
157 {
158 return c[7] == '\x01';
159 }
160
162 static inline void
163 __GXX_INIT_PRIMARY_EXCEPTION_CLASS(_Unwind_Exception_Class c)
164 {
165 c[0] = 'G';
166 c[1] = 'N';
167 c[2] = 'U';
168 c[3] = 'C';
169 c[4] = 'C';
170 c[5] = '+';
171 c[6] = '+';
172 c[7] = '\0';
173 }
174
175 inline void
176 __GXX_INIT_DEPENDENT_EXCEPTION_CLASS(_Unwind_Exception_Class c)
177 {
178 c[0] = 'G';
179 c[1] = 'N';
180 c[2] = 'U';
181 c[3] = 'C';
182 c[4] = 'C';
183 c[5] = '+';
184 c[6] = '+';
185 c[7] = '\x01';
186 }
187 # else
188 const _Unwind_Exception_Class __gxx_primary_exception_class
189 = (((((((_Unwind_Exception_Class('G')
190 << 8 | _Unwind_Exception_Class('N'))
191 << 8 | _Unwind_Exception_Class('U'))
192 << 8 | _Unwind_Exception_Class('C'))
193 << 8 | _Unwind_Exception_Class('C'))
194 << 8 | _Unwind_Exception_Class('+'))
195 << 8 | _Unwind_Exception_Class('+'))
196 << 8 | _Unwind_Exception_Class('\0'));
197
198 const _Unwind_Exception_Class __gxx_dependent_exception_class
199 = (((((((_Unwind_Exception_Class('G')
200 << 8 | _Unwind_Exception_Class('N'))
201 << 8 | _Unwind_Exception_Class('U'))
202 << 8 | _Unwind_Exception_Class('C'))
203 << 8 | _Unwind_Exception_Class('C'))
204 << 8 | _Unwind_Exception_Class('+'))
205 << 8 | _Unwind_Exception_Class('+'))
206 << 8 | _Unwind_Exception_Class('\x01'));
207
208 inline bool
209 __is_gxx_exception_class(_Unwind_Exception_Class c)
210 {
211 return c == __gxx_primary_exception_class
212 || c == __gxx_dependent_exception_class;
213 }
214
215 inline bool
216 __is_dependent_exception(_Unwind_Exception_Class c)
217 {
218 return c & 1;
219 }
220
222 # define __GXX_INIT_PRIMARY_EXCEPTION_CLASS(c) \
223 c = __gxx_primary_exception_class
224 # define __GXX_INIT_DEPENDENT_EXCEPTION_CLASS(c) \
225 c = __gxx_dependent_exception_class
226 # endif
227
228 inline void*
229 __get_object_from_ue(_Unwind_Exception* eo) noexcept
230 {
231 return __is_dependent_exception(eo->exception_class) ?
232 __get_dependent_exception_from_ue(eo)->primaryException : eo + 1;
233 }
234
235 inline void*
236 __get_object_from_ambiguous_exception(__cxa_exception* p_or_d) noexcept
237 {
238 return __get_object_from_ue(&p_or_d->unwindHeader);
239 }
240
241 template<typename Ex>
242 constexpr
243 std::size_t unwindhdr()
244 {
245 return offsetof(Ex, unwindHeader);
246 }
247
248 # if __GNUC__ * 100 + __GNUC_MINOR__ >= 409
249 template<typename Ex>
250 constexpr
251 std::size_t termHandler()
252 {
253 return unwindhdr<Ex>() - offsetof(Ex, terminateHandler);
254 }
255
256 static_assert(termHandler<__cxa_exception>()
257 == termHandler<__cxa_dependent_exception>(),
258 "__cxa_dependent_exception::termHandler layout must be"
259 " consistent with __cxa_exception::termHandler");
260 # endif
261
262 # ifndef __ARM_EABI_UNWINDER__
263 template<typename Ex>
264 constexpr std::ptrdiff_t adjptr()
265 {
266 return unwindhdr<Ex>() - offsetof(Ex, adjustedPtr);
267 }
268
269 static_assert(adjptr<__cxa_exception>()
270 == adjptr<__cxa_dependent_exception>(),
271 "__cxa_dependent_exception::adjustedPtr layout must be"
272 " consistent with __cxa_exception::adjustedPtr");
273 # endif
274
275 // FIXME: For platforms with threading but no atomic builtins, e.g. Android
276 // ARMv5.
277 # if !_GLIBCXX_HAS_GTHREADS || __clang__
278 template<typename _type>
279 inline _type
280 __atomic_add_fetch_(_type* ptr, _type val, int)
281 {
282 *ptr += val;
283 return *ptr;
284 }
285
286 template<typename _type>
287 inline _type
288 __atomic_sub_fetch_(_type* ptr, _type val, int)
289 {
290 *ptr -= val;
291 return *ptr;
292 }
293 # define __atomic_add_fetch __atomic_add_fetch_
294 # define __atomic_sub_fetch __atomic_sub_fetch_
295 # endif
296
297 void
298 __gxx_dependent_exception_cleanup(_Unwind_Reason_Code code,
299 _Unwind_Exception* exc)
300 {
301 const auto dep(__get_dependent_exception_from_ue(exc));
302 const auto header(
303 __get_refcounted_exception_header_from_obj(dep->primaryException));
304
305 if(code != _URC_FOREIGN_EXCEPTION_CAUGHT && code != _URC_NO_REASON)
306 __terminate(header->exc.terminateHandler);
307 __cxa_free_dependent_exception(dep);
308 if(__atomic_sub_fetch(&header->referenceCount, 1, __ATOMIC_ACQ_REL) == 0)
309 {
310 if(header->exc.exceptionDestructor)
311 header->exc.exceptionDestructor(header + 1);
312 __cxa_free_exception(header + 1);
313 }
314 }
315
317 void
318 __gxx_exception_cleanup(_Unwind_Reason_Code code, _Unwind_Exception* exc)
319 {
320 const auto header(__get_refcounted_exception_header_from_ue(exc));
321
322 if(code != _URC_FOREIGN_EXCEPTION_CAUGHT && code != _URC_NO_REASON)
323 __terminate(header->exc.terminateHandler);
324
325 if(__atomic_sub_fetch(&header->referenceCount, 1, __ATOMIC_ACQ_REL) == 0)
326 {
327 if(header->exc.exceptionDestructor)
328 header->exc.exceptionDestructor(header + 1);
329
330 __cxa_free_exception(header + 1);
331 }
332 }
333
334 } // unnamed namespace;
335
336 } // namespace __cxxabiv1;
337
338 using namespace __cxxabiv1;
339
340 # pragma GCC visibility pop
341
342 namespace std
343 {
344
345 namespace __exception_ptr
346 {
347
348 exception_ptr::exception_ptr() noexcept
349 : _M_exception_object()
350 {}
351 exception_ptr::exception_ptr(void* obj) noexcept
352 : _M_exception_object(obj)
353 {
354 // NOTE: Need to hack here because pre-built code in
355 // %__cxxabiv1::__cxa_throw or transactional memory extension
356 // may assume it is not reference-counted so it would crash on %_M_release
357 // or %std::rethrow_exception called after the reference has been cleanup.
358 const auto header(__get_refcounted_exception_header_from_obj(obj));
359
360 header->exc.unwindHeader.exception_cleanup = __gxx_exception_cleanup;
361 _M_addref();
362 }
363 # ifdef _GLIBCXX_EH_PTR_COMPAT
364 exception_ptr::exception_ptr(__safe_bool) noexcept
365 : _M_exception_object()
366 {}
367 # endif
368 exception_ptr::exception_ptr(const exception_ptr& other) noexcept
369 : _M_exception_object(other._M_exception_object)
370 {
371 _M_addref();
372 }
373 exception_ptr::~exception_ptr() noexcept
374 {
375 _M_release();
376 }
377
378 exception_ptr&
379 exception_ptr::operator=(const exception_ptr& other) noexcept
380 {
381 exception_ptr(other).swap(*this);
382 return *this;
383 }
384
385 void
386 exception_ptr::_M_addref() noexcept
387 {
388 if(_M_exception_object)
389 {
390 const auto
391 eh(__get_refcounted_exception_header_from_obj(_M_exception_object));
392
393 __atomic_add_fetch(&eh->referenceCount, 1, __ATOMIC_ACQ_REL);
394 }
395 }
396
397 void
398 exception_ptr::_M_release() noexcept
399 {
400 if(_M_exception_object)
401 {
402 const auto eh(
403 __get_refcounted_exception_header_from_obj(_M_exception_object));
404
405 if(__atomic_sub_fetch(&eh->referenceCount, 1, __ATOMIC_ACQ_REL) == 0)
406 {
407 if(eh->exc.exceptionDestructor)
408 eh->exc.exceptionDestructor(_M_exception_object);
409 __cxa_free_exception(_M_exception_object);
410 _M_exception_object = {};
411 }
412 }
413 }
414
415 void*
416 exception_ptr::_M_get() const noexcept
417 {
418 return _M_exception_object;
419 }
420
421 void
422 exception_ptr::swap(exception_ptr& other) noexcept
423 {
424 const auto tmp(_M_exception_object);
425
426 _M_exception_object = other._M_exception_object;
427 other._M_exception_object = tmp;
428 }
429
430
431 # ifdef _GLIBCXX_EH_PTR_COMPAT
432 void
433 exception_ptr::_M_safe_bool_dummy() noexcept
434 {}
435
436 bool
437 exception_ptr::operator!() const noexcept
438 {
439 return !_M_exception_object;
440 }
441
442 exception_ptr::operator __safe_bool() const noexcept
443 {
444 return _M_exception_object ? &exception_ptr::_M_safe_bool_dummy : nullptr;
445 }
446 # endif
447
448 const type_info*
449 exception_ptr::__cxa_exception_type() const noexcept
450 {
451 return __get_exception_header_from_obj(_M_exception_object)->exceptionType;
452 }
453
454 bool
455 operator==(const exception_ptr& lhs, const exception_ptr& rhs) noexcept
456 {
457 return lhs._M_exception_object == rhs._M_exception_object;
458 }
459
460 bool
461 operator!=(const exception_ptr& lhs, const exception_ptr& rhs) noexcept
462 {
463 return !(lhs == rhs);
464 }
465
466 } // namespace __exception_ptr;
467
468 exception_ptr
469 current_exception() noexcept
470 {
471 const auto header(__cxa_get_globals()->caughtExceptions);
472
473 return header && __is_gxx_exception_class(
474 header->unwindHeader.exception_class)
475 ? exception_ptr(__get_object_from_ambiguous_exception(header))
476 : exception_ptr();
477 }
478
479 void
480 rethrow_exception(exception_ptr ep)
481 {
482 void* obj(ep._M_get());
483 const auto eh(__get_refcounted_exception_header_from_obj(obj));
484 const auto dep(__cxa_allocate_dependent_exception());
485
486 dep->primaryException = obj;
487 __atomic_add_fetch(&eh->referenceCount, 1, __ATOMIC_ACQ_REL);
488 dep->unexpectedHandler = get_unexpected();
489 dep->terminateHandler = get_terminate();
490 __GXX_INIT_DEPENDENT_EXCEPTION_CLASS(dep->unwindHeader.exception_class);
491 dep->unwindHeader.exception_cleanup = __gxx_dependent_exception_cleanup;
492 #ifdef _GLIBCXX_SJLJ_EXCEPTIONS
493 _Unwind_SjLj_RaiseException(&dep->unwindHeader);
494 #else
495 _Unwind_RaiseException(&dep->unwindHeader);
496 #endif
497 __cxa_begin_catch(&dep->unwindHeader);
498 std::terminate();
499 }
500
501 } // namespace std;
502
503 #endif
504
505 #if defined(__GLIBCXX__) \
506 &&(defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) \
507 && __GNUC__ * 100 + __GNUC_MINOR__ < 409
508
509 # include <exception>
510 # if ATOMIC_POINTER_LOCK_FREE < 2
511 // XXX: Reordered to avoid include <exception> too early.
512 # include <ext/concurrence.h>
513 namespace
514 {
515
516 __gnu_cxx::__mutex mx;
517
518 } // unnamed namespace;
519 # endif
520
521 namespace __cxxabiv1
522 {
523
524 extern std::terminate_handler __terminate_handler;
525 extern std::unexpected_handler __unexpected_handler;
526
527 } // namespace __cxxabiv1;
528
529 using namespace __cxxabiv1;
530
531 namespace std
532 {
533
534 terminate_handler
535 get_terminate() noexcept
536 {
537 terminate_handler func;
538
539 # if ATOMIC_POINTER_LOCK_FREE > 1
540 __atomic_load(&__terminate_handler, &func, __ATOMIC_ACQUIRE);
541 # else
542 __gnu_cxx::__scoped_lock l(mx);
543
544 func = __terminate_handler;
545 # endif
546 return func;
547 }
548
549 unexpected_handler
550 get_unexpected() noexcept
551 {
552 unexpected_handler func;
553
554 # if ATOMIC_POINTER_LOCK_FREE > 1
555 __atomic_load(&__unexpected_handler, &func, __ATOMIC_ACQUIRE);
556 # else
557 __gnu_cxx::__scoped_lock l(mx);
558
559 func = __unexpected_handler;
560 # endif
561 return func;
562 }
563
564 } // namespace std;
565
566 #endif
567
platform::size_t
YF_API size_t
Definition: FileIO.h:1353
exception.h
ystdex::operator!=
bool operator!=(nullptr_t lhs, const _type &rhs)
Definition: ydef.h:908
platform_ex::operator==
PDefH(void, EnsureNonNull, void *p) ImplExpr(p?void() boo operator==)(const COMPtr< _iCOM1 > &x, const COMPtr< _iCOM2 > &y) ynothrow
检查指针值，若为空则抛出 COMException 。
Definition: COM.h:328
CHRLib::CharSet::other
Definition: Encoding.h:65
ystdex::swap
void swap(container_adaptor< _tSeqCon > &x, container_adaptor< _tSeqCon > &y)
Definition: container.hpp:179
std
Definition: memory.hpp:1183
platform::terminate
YB_NORETURN YF_API void terminate() ynothrow
异常终止函数。
Definition: YCommon.cpp:47
CHRLib::c
c
Definition: CharacterProcessing.h:81