1 // -*- C++ -*- Implement the members of exception_ptr. 2 // Copyright (C) 2008-2018 Free Software Foundation, Inc. 3 // 4 // This file is part of GCC. 5 // 6 // GCC is free software; you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 // 11 // GCC is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 #include <bits/c++config.h> 26 #include "eh_atomics.h" 27 28 #define _GLIBCXX_EH_PTR_COMPAT 29 30 #include <exception> 31 #include <bits/exception_ptr.h> 32 #include "unwind-cxx.h" 33 34 using namespace __cxxabiv1; 35 36 // Verify assumptions about member layout in exception types 37 namespace 38 { 39 template<typename Ex> 40 constexpr std::size_t unwindhdr() 41 { return offsetof(Ex, unwindHeader); } 42 43 template<typename Ex> 44 constexpr std::size_t termHandler() 45 { return unwindhdr<Ex>() - offsetof(Ex, terminateHandler); } 46 47 static_assert( termHandler<__cxa_exception>() 48 == termHandler<__cxa_dependent_exception>(), 49 "__cxa_dependent_exception::termHandler layout must be" 50 " consistent with __cxa_exception::termHandler" ); 51 52 #ifndef __ARM_EABI_UNWINDER__ 53 template<typename Ex> 54 constexpr std::ptrdiff_t adjptr() 55 { return unwindhdr<Ex>() - offsetof(Ex, adjustedPtr); } 56 57 static_assert( adjptr<__cxa_exception>() 58 == adjptr<__cxa_dependent_exception>(), 59 "__cxa_dependent_exception::adjustedPtr layout must be" 60 " consistent with __cxa_exception::adjustedPtr" ); 61 #endif 62 } 63 64 std::__exception_ptr::exception_ptr::exception_ptr() noexcept 65 : _M_exception_object(0) { } 66 67 68 std::__exception_ptr::exception_ptr::exception_ptr(void* obj) noexcept 69 : _M_exception_object(obj) { _M_addref(); } 70 71 72 std::__exception_ptr::exception_ptr::exception_ptr(__safe_bool) noexcept 73 : _M_exception_object(0) { } 74 75 76 std::__exception_ptr:: 77 exception_ptr::exception_ptr(const exception_ptr& other) noexcept 78 : _M_exception_object(other._M_exception_object) 79 { _M_addref(); } 80 81 82 std::__exception_ptr::exception_ptr::~exception_ptr() noexcept 83 { _M_release(); } 84 85 86 std::__exception_ptr::exception_ptr& 87 std::__exception_ptr:: 88 exception_ptr::operator=(const exception_ptr& other) noexcept 89 { 90 exception_ptr(other).swap(*this); 91 return *this; 92 } 93 94 95 void 96 std::__exception_ptr::exception_ptr::_M_addref() noexcept 97 { 98 if (_M_exception_object) 99 { 100 __cxa_refcounted_exception *eh = 101 __get_refcounted_exception_header_from_obj (_M_exception_object); 102 __gnu_cxx::__eh_atomic_inc (&eh->referenceCount); 103 } 104 } 105 106 107 void 108 std::__exception_ptr::exception_ptr::_M_release() noexcept 109 { 110 if (_M_exception_object) 111 { 112 __cxa_refcounted_exception *eh = 113 __get_refcounted_exception_header_from_obj (_M_exception_object); 114 if (__gnu_cxx::__eh_atomic_dec (&eh->referenceCount)) 115 { 116 if (eh->exc.exceptionDestructor) 117 eh->exc.exceptionDestructor (_M_exception_object); 118 119 __cxa_free_exception (_M_exception_object); 120 _M_exception_object = 0; 121 } 122 } 123 } 124 125 126 void* 127 std::__exception_ptr::exception_ptr::_M_get() const noexcept 128 { return _M_exception_object; } 129 130 131 void 132 std::__exception_ptr::exception_ptr::swap(exception_ptr &other) noexcept 133 { 134 void *tmp = _M_exception_object; 135 _M_exception_object = other._M_exception_object; 136 other._M_exception_object = tmp; 137 } 138 139 140 // Retained for compatibility with CXXABI_1.3. 141 void 142 std::__exception_ptr::exception_ptr::_M_safe_bool_dummy() noexcept { } 143 144 145 // Retained for compatibility with CXXABI_1.3. 146 bool 147 std::__exception_ptr::exception_ptr::operator!() const noexcept 148 { return _M_exception_object == 0; } 149 150 151 // Retained for compatibility with CXXABI_1.3. 152 std::__exception_ptr::exception_ptr::operator __safe_bool() const noexcept 153 { 154 return _M_exception_object ? &exception_ptr::_M_safe_bool_dummy : 0; 155 } 156 157 158 const std::type_info* 159 std::__exception_ptr::exception_ptr::__cxa_exception_type() const noexcept 160 { 161 __cxa_exception *eh = __get_exception_header_from_obj (_M_exception_object); 162 return eh->exceptionType; 163 } 164 165 166 bool std::__exception_ptr::operator==(const exception_ptr& lhs, 167 const exception_ptr& rhs) noexcept 168 { return lhs._M_exception_object == rhs._M_exception_object; } 169 170 171 bool std::__exception_ptr::operator!=(const exception_ptr& lhs, 172 const exception_ptr& rhs) noexcept 173 { return !(lhs == rhs);} 174 175 176 std::exception_ptr 177 std::current_exception() noexcept 178 { 179 __cxa_eh_globals *globals = __cxa_get_globals (); 180 __cxa_exception *header = globals->caughtExceptions; 181 182 if (!header) 183 return std::exception_ptr(); 184 185 // Since foreign exceptions can't be counted, we can't return them. 186 if (!__is_gxx_exception_class (header->unwindHeader.exception_class)) 187 return std::exception_ptr(); 188 189 return std::exception_ptr( 190 __get_object_from_ambiguous_exception (header)); 191 } 192 193 194 static void 195 __gxx_dependent_exception_cleanup(_Unwind_Reason_Code code, 196 _Unwind_Exception *exc) 197 { 198 // This cleanup is set only for dependents. 199 __cxa_dependent_exception *dep = __get_dependent_exception_from_ue (exc); 200 __cxa_refcounted_exception *header = 201 __get_refcounted_exception_header_from_obj (dep->primaryException); 202 203 // We only want to be called through _Unwind_DeleteException. 204 // _Unwind_DeleteException in the HP-UX IA64 libunwind library 205 // returns _URC_NO_REASON and not _URC_FOREIGN_EXCEPTION_CAUGHT 206 // like the GCC _Unwind_DeleteException function does. 207 if (code != _URC_FOREIGN_EXCEPTION_CAUGHT && code != _URC_NO_REASON) 208 __terminate (header->exc.terminateHandler); 209 210 __cxa_free_dependent_exception (dep); 211 212 if (__gnu_cxx::__eh_atomic_dec (&header->referenceCount)) 213 { 214 if (header->exc.exceptionDestructor) 215 header->exc.exceptionDestructor (header + 1); 216 217 __cxa_free_exception (header + 1); 218 } 219 } 220 221 222 void 223 std::rethrow_exception(std::exception_ptr ep) 224 { 225 void *obj = ep._M_get(); 226 __cxa_refcounted_exception *eh 227 = __get_refcounted_exception_header_from_obj (obj); 228 229 __cxa_dependent_exception *dep = __cxa_allocate_dependent_exception (); 230 dep->primaryException = obj; 231 __gnu_cxx::__eh_atomic_inc (&eh->referenceCount); 232 233 dep->unexpectedHandler = get_unexpected (); 234 dep->terminateHandler = get_terminate (); 235 __GXX_INIT_DEPENDENT_EXCEPTION_CLASS(dep->unwindHeader.exception_class); 236 dep->unwindHeader.exception_cleanup = __gxx_dependent_exception_cleanup; 237 238 __cxa_eh_globals *globals = __cxa_get_globals (); 239 globals->uncaughtExceptions += 1; 240 241 #ifdef __USING_SJLJ_EXCEPTIONS__ 242 _Unwind_SjLj_RaiseException (&dep->unwindHeader); 243 #else 244 _Unwind_RaiseException (&dep->unwindHeader); 245 #endif 246 247 // Some sort of unwinding error. Note that terminate is a handler. 248 __cxa_begin_catch (&dep->unwindHeader); 249 std::terminate(); 250 } 251 252 #undef _GLIBCXX_EH_PTR_COMPAT 253