1// -*- C++ -*- Implement the members of exception_ptr. 2// Copyright (C) 2008-2015 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 <bits/atomic_lockfree_defines.h> 27 28#if ATOMIC_INT_LOCK_FREE > 1 29 30#define _GLIBCXX_EH_PTR_COMPAT 31 32#include <exception> 33#include <bits/exception_ptr.h> 34#include "unwind-cxx.h" 35 36using namespace __cxxabiv1; 37 38// Verify assumptions about member layout in exception types 39namespace 40{ 41template<typename Ex> 42 constexpr std::size_t unwindhdr() 43 { return offsetof(Ex, unwindHeader); } 44 45template<typename Ex> 46 constexpr std::size_t termHandler() 47 { return unwindhdr<Ex>() - offsetof(Ex, terminateHandler); } 48 49static_assert( termHandler<__cxa_exception>() 50 == termHandler<__cxa_dependent_exception>(), 51 "__cxa_dependent_exception::termHandler layout must be" 52 " consistent with __cxa_exception::termHandler" ); 53 54#ifndef __ARM_EABI_UNWINDER__ 55template<typename Ex> 56 constexpr std::ptrdiff_t adjptr() 57 { return unwindhdr<Ex>() - offsetof(Ex, adjustedPtr); } 58 59static_assert( adjptr<__cxa_exception>() 60 == adjptr<__cxa_dependent_exception>(), 61 "__cxa_dependent_exception::adjustedPtr layout must be" 62 " consistent with __cxa_exception::adjustedPtr" ); 63#endif 64} 65 66std::__exception_ptr::exception_ptr::exception_ptr() _GLIBCXX_USE_NOEXCEPT 67: _M_exception_object(0) { } 68 69 70std::__exception_ptr::exception_ptr::exception_ptr(void* obj) 71_GLIBCXX_USE_NOEXCEPT 72: _M_exception_object(obj) { _M_addref(); } 73 74 75std::__exception_ptr::exception_ptr::exception_ptr(__safe_bool) 76_GLIBCXX_USE_NOEXCEPT 77: _M_exception_object(0) { } 78 79 80std::__exception_ptr:: 81exception_ptr::exception_ptr(const exception_ptr& other) _GLIBCXX_USE_NOEXCEPT 82: _M_exception_object(other._M_exception_object) 83{ _M_addref(); } 84 85 86std::__exception_ptr::exception_ptr::~exception_ptr() _GLIBCXX_USE_NOEXCEPT 87{ _M_release(); } 88 89 90std::__exception_ptr::exception_ptr& 91std::__exception_ptr:: 92exception_ptr::operator=(const exception_ptr& other) _GLIBCXX_USE_NOEXCEPT 93{ 94 exception_ptr(other).swap(*this); 95 return *this; 96} 97 98 99void 100std::__exception_ptr::exception_ptr::_M_addref() _GLIBCXX_USE_NOEXCEPT 101{ 102 if (_M_exception_object) 103 { 104 __cxa_refcounted_exception *eh = 105 __get_refcounted_exception_header_from_obj (_M_exception_object); 106 __atomic_add_fetch (&eh->referenceCount, 1, __ATOMIC_ACQ_REL); 107 } 108} 109 110 111void 112std::__exception_ptr::exception_ptr::_M_release() _GLIBCXX_USE_NOEXCEPT 113{ 114 if (_M_exception_object) 115 { 116 __cxa_refcounted_exception *eh = 117 __get_refcounted_exception_header_from_obj (_M_exception_object); 118 if (__atomic_sub_fetch (&eh->referenceCount, 1, __ATOMIC_ACQ_REL) == 0) 119 { 120 if (eh->exc.exceptionDestructor) 121 eh->exc.exceptionDestructor (_M_exception_object); 122 123 __cxa_free_exception (_M_exception_object); 124 _M_exception_object = 0; 125 } 126 } 127} 128 129 130void* 131std::__exception_ptr::exception_ptr::_M_get() const _GLIBCXX_USE_NOEXCEPT 132{ return _M_exception_object; } 133 134 135void 136std::__exception_ptr::exception_ptr::swap(exception_ptr &other) 137 _GLIBCXX_USE_NOEXCEPT 138{ 139 void *tmp = _M_exception_object; 140 _M_exception_object = other._M_exception_object; 141 other._M_exception_object = tmp; 142} 143 144 145// Retained for compatibility with CXXABI_1.3. 146void 147std::__exception_ptr::exception_ptr::_M_safe_bool_dummy() 148 _GLIBCXX_USE_NOEXCEPT { } 149 150 151// Retained for compatibility with CXXABI_1.3. 152bool 153std::__exception_ptr::exception_ptr::operator!() const _GLIBCXX_USE_NOEXCEPT 154{ return _M_exception_object == 0; } 155 156 157// Retained for compatibility with CXXABI_1.3. 158std::__exception_ptr::exception_ptr::operator __safe_bool() const 159_GLIBCXX_USE_NOEXCEPT 160{ 161 return _M_exception_object ? &exception_ptr::_M_safe_bool_dummy : 0; 162} 163 164 165const std::type_info* 166std::__exception_ptr::exception_ptr::__cxa_exception_type() const 167 _GLIBCXX_USE_NOEXCEPT 168{ 169 __cxa_exception *eh = __get_exception_header_from_obj (_M_exception_object); 170 return eh->exceptionType; 171} 172 173 174bool std::__exception_ptr::operator==(const exception_ptr& lhs, 175 const exception_ptr& rhs) 176 _GLIBCXX_USE_NOEXCEPT 177{ return lhs._M_exception_object == rhs._M_exception_object; } 178 179 180bool std::__exception_ptr::operator!=(const exception_ptr& lhs, 181 const exception_ptr& rhs) 182 _GLIBCXX_USE_NOEXCEPT 183{ return !(lhs == rhs);} 184 185 186std::exception_ptr 187std::current_exception() _GLIBCXX_USE_NOEXCEPT 188{ 189 __cxa_eh_globals *globals = __cxa_get_globals (); 190 __cxa_exception *header = globals->caughtExceptions; 191 192 if (!header) 193 return std::exception_ptr(); 194 195 // Since foreign exceptions can't be counted, we can't return them. 196 if (!__is_gxx_exception_class (header->unwindHeader.exception_class)) 197 return std::exception_ptr(); 198 199 return std::exception_ptr( 200 __get_object_from_ambiguous_exception (header)); 201} 202 203 204static void 205__gxx_dependent_exception_cleanup(_Unwind_Reason_Code code, 206 _Unwind_Exception *exc) 207{ 208 // This cleanup is set only for dependents. 209 __cxa_dependent_exception *dep = __get_dependent_exception_from_ue (exc); 210 __cxa_refcounted_exception *header = 211 __get_refcounted_exception_header_from_obj (dep->primaryException); 212 213 // We only want to be called through _Unwind_DeleteException. 214 // _Unwind_DeleteException in the HP-UX IA64 libunwind library 215 // returns _URC_NO_REASON and not _URC_FOREIGN_EXCEPTION_CAUGHT 216 // like the GCC _Unwind_DeleteException function does. 217 if (code != _URC_FOREIGN_EXCEPTION_CAUGHT && code != _URC_NO_REASON) 218 __terminate (header->exc.terminateHandler); 219 220 __cxa_free_dependent_exception (dep); 221 222 if (__atomic_sub_fetch (&header->referenceCount, 1, __ATOMIC_ACQ_REL) == 0) 223 { 224 if (header->exc.exceptionDestructor) 225 header->exc.exceptionDestructor (header + 1); 226 227 __cxa_free_exception (header + 1); 228 } 229} 230 231 232void 233std::rethrow_exception(std::exception_ptr ep) 234{ 235 void *obj = ep._M_get(); 236 __cxa_refcounted_exception *eh 237 = __get_refcounted_exception_header_from_obj (obj); 238 239 __cxa_dependent_exception *dep = __cxa_allocate_dependent_exception (); 240 dep->primaryException = obj; 241 __atomic_add_fetch (&eh->referenceCount, 1, __ATOMIC_ACQ_REL); 242 243 dep->unexpectedHandler = get_unexpected (); 244 dep->terminateHandler = get_terminate (); 245 __GXX_INIT_DEPENDENT_EXCEPTION_CLASS(dep->unwindHeader.exception_class); 246 dep->unwindHeader.exception_cleanup = __gxx_dependent_exception_cleanup; 247 248 __cxa_eh_globals *globals = __cxa_get_globals (); 249 globals->uncaughtExceptions += 1; 250 251#ifdef _GLIBCXX_SJLJ_EXCEPTIONS 252 _Unwind_SjLj_RaiseException (&dep->unwindHeader); 253#else 254 _Unwind_RaiseException (&dep->unwindHeader); 255#endif 256 257 // Some sort of unwinding error. Note that terminate is a handler. 258 __cxa_begin_catch (&dep->unwindHeader); 259 std::terminate(); 260} 261 262#undef _GLIBCXX_EH_PTR_COMPAT 263 264#endif 265