YSTest: exception.cpp 源文件

YSTest PreAlpha_b900_20201012 The YSLib Test Project

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