unsigned int __cxa_uncaught_exceptions() throw() { // This does not report foreign exceptions in flight __cxa_eh_globals* globals = __cxa_get_globals_fast(); if (globals == 0) return 0; return globals->uncaughtExceptions; }
bool __cxa_uncaught_exception() throw() { // This does not report foreign exceptions in flight __cxa_eh_globals* globals = __cxa_get_globals_fast(); if (globals == 0) return false; return globals->uncaughtExceptions != 0; }
// Note: exception_header may be masquerading as a __cxa_dependent_exception // and that's ok. exceptionType is there too. // However watch out for foreign exceptions. Return null for them. std::type_info * __cxa_current_exception_type() { // get the current exception __cxa_eh_globals *globals = __cxa_get_globals_fast(); if (NULL == globals) return NULL; // If there have never been any exceptions, there are none now. __cxa_exception *exception_header = globals->caughtExceptions; if (NULL == exception_header) return NULL; // No current exception if (!isOurExceptionClass(&exception_header->unwindHeader)) return NULL; return exception_header->exceptionType; }
__cxa_eh_globals * __cxa_get_globals () { // Try to get the globals for this thread __cxa_eh_globals* retVal = __cxa_get_globals_fast (); // If this is the first time we've been asked for these globals, create them if ( NULL == retVal ) { retVal = static_cast<__cxa_eh_globals*> (std::calloc (1, sizeof (__cxa_eh_globals))); if ( NULL == retVal ) abort_message("cannot allocate __cxa_eh_globals"); if ( 0 != pthread_setspecific ( key_, retVal ) ) abort_message("pthread_setspecific failure in __cxa_get_globals()"); } return retVal; }
void __cxa_end_catch() { if (!invalid) { __cxa_exception* top = __cxa_get_globals_fast()->caughtExceptions; // This is gcc specific and not specified in the ABI: // abs(handlerCount) is the number of active handlers, it's negative // for rethrown exceptions and positive (always 1) for regular exceptions. // In the rethrow case, we've already popped the exception off the // caught stack, so we don't do anything here. if (top->handlerCount == 1) { if (!caughtExceptions.pop()) { activeExceptions.clear(); invalid = true; } } } orig_cxa_end_catch(); }
/* Returns a pointer to the thrown object (if any) at the top of the caughtExceptions stack. Atomically increment the exception's referenceCount. If there is no such thrown object or if the thrown object is foreign, returns null. We can use __cxa_get_globals_fast here to get the globals because if there have been no exceptions thrown, ever, on this thread, we can return NULL without the need to allocate the exception-handling globals. */ void* __cxa_current_primary_exception() throw() { // get the current exception __cxa_eh_globals* globals = __cxa_get_globals_fast(); if (NULL == globals) return NULL; // If there are no globals, there is no exception __cxa_exception* exception_header = globals->caughtExceptions; if (NULL == exception_header) return NULL; // No current exception if (!isOurExceptionClass(&exception_header->unwindHeader)) return NULL; // Can't capture a foreign exception (no way to refcount it) if (isDependentException(&exception_header->unwindHeader)) { __cxa_dependent_exception* dep_exception_header = reinterpret_cast<__cxa_dependent_exception*>(exception_header); exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException); } void* thrown_object = thrown_object_from_cxa_exception(exception_header); __cxa_increment_exception_refcount(thrown_object); return thrown_object; }
/* Upon exit for any reason, a handler must call: void __cxa_end_catch (); This routine can be called for either a native or foreign exception. For a native exception: * Locates the most recently caught exception and decrements its handler count. * Removes the exception from the caught exception stack, if the handler count goes to zero. * If the handler count goes down to zero, and the exception was not re-thrown by throw, it locates the primary exception (which may be the same as the one it's handling) and decrements its reference count. If that reference count goes to zero, the function destroys the exception. In any case, if the current exception is a dependent exception, it destroys that. For a foreign exception: * If it has been rethrown, there is nothing to do. * Otherwise delete the exception and pop the catch stack to empty. */ void __cxa_end_catch() { static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception), "sizeof(__cxa_exception) must be equal to sizeof(__cxa_dependent_exception)"); __cxa_eh_globals* globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch __cxa_exception* exception_header = globals->caughtExceptions; // If we've rethrown a foreign exception, then globals->caughtExceptions // will have been made an empty stack by __cxa_rethrow() and there is // nothing more to be done. Do nothing! if (NULL != exception_header) { bool native_exception = isOurExceptionClass(&exception_header->unwindHeader); if (native_exception) { // This is a native exception if (exception_header->handlerCount < 0) { // The exception has been rethrown by __cxa_rethrow, so don't delete it if (0 == incrementHandlerCount(exception_header)) { // Remove from the chain of uncaught exceptions globals->caughtExceptions = exception_header->nextException; // but don't destroy } // Keep handlerCount negative in case there are nested catch's // that need to be told that this exception is rethrown. Don't // erase this rethrow flag until the exception is recaught. } else { // The native exception has not been rethrown if (0 == decrementHandlerCount(exception_header)) { // Remove from the chain of uncaught exceptions globals->caughtExceptions = exception_header->nextException; // Destroy this exception, being careful to distinguish // between dependent and primary exceptions if (isDependentException(&exception_header->unwindHeader)) { // Reset exception_header to primaryException and deallocate the dependent exception __cxa_dependent_exception* dep_exception_header = reinterpret_cast<__cxa_dependent_exception*>(exception_header); exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException); __cxa_free_dependent_exception(dep_exception_header); } // Destroy the primary exception only if its referenceCount goes to 0 // (this decrement must be atomic) __cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header)); } } } else { // The foreign exception has not been rethrown. Pop the stack // and delete it. If there are nested catch's and they try // to touch a foreign exception in any way, that is undefined // behavior. They likely can't since the only way to catch // a foreign exception is with catch (...)! _Unwind_DeleteException(&globals->caughtExceptions->unwindHeader); globals->caughtExceptions = 0; } } }
void __cxa_call_unexpected(void* arg) { _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg); if (unwind_exception == 0) call_terminate(false, unwind_exception); __cxa_begin_catch(unwind_exception); bool native_old_exception = (reinterpret_cast<uint64_t>(unwind_exception->exception_class) & get_vendor_and_language) == (kOurExceptionClass & get_vendor_and_language); std::unexpected_handler u_handler; std::terminate_handler t_handler; __cxa_exception* old_exception_header = 0; int64_t ttypeIndex; const uint8_t* lsda; if (native_old_exception) { old_exception_header = (__cxa_exception*)(unwind_exception+1) - 1; t_handler = old_exception_header->terminateHandler; u_handler = old_exception_header->unexpectedHandler; // If std::__unexpected(u_handler) rethrows the same exception, // these values get overwritten by the rethrow. So save them now: #ifndef __ARM_EABI_UNWINDER__ ttypeIndex = old_exception_header->handlerSwitchValue; lsda = old_exception_header->languageSpecificData; #endif } else { t_handler = std::get_terminate(); u_handler = std::get_unexpected(); } try { std::__unexpected(u_handler); } catch (...) { // If the old exception is foreign, then all we can do is terminate. // We have no way to recover the needed old exception spec. There's // no way to pass that information here. And the personality routine // can't call us directly and do anything but terminate() if we throw // from here. if (native_old_exception) { // Have: // old_exception_header->languageSpecificData // old_exception_header->actionRecord // Need // const uint8_t* classInfo // uint8_t ttypeEncoding uint8_t lpStartEncoding = *lsda++; const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding); (void)lpStart; // purposefully unused. Just needed to increment lsda. uint8_t ttypeEncoding = *lsda++; if (ttypeEncoding == DW_EH_PE_omit) std::__terminate(t_handler); uintptr_t classInfoOffset = readULEB128(&lsda); const uint8_t* classInfo = lsda + classInfoOffset; // Is this new exception catchable by the exception spec at ttypeIndex? // The answer is obviously yes if the new and old exceptions are the same exception // If no // throw; __cxa_eh_globals* globals = __cxa_get_globals_fast(); __cxa_exception* new_exception_header = globals->caughtExceptions; if (new_exception_header == 0) // This shouldn't be able to happen! std::__terminate(t_handler); bool native_new_exception = (reinterpret_cast<uint64_t>(new_exception_header->unwindHeader.exception_class) & get_vendor_and_language) == (kOurExceptionClass & get_vendor_and_language); void* adjustedPtr; if (native_new_exception && (new_exception_header != old_exception_header)) { const __shim_type_info* excpType = static_cast<const __shim_type_info*>(new_exception_header->exceptionType); adjustedPtr = reinterpret_cast<uint64_t>(new_exception_header->unwindHeader.exception_class) == kOurDependentExceptionClass ? ((__cxa_dependent_exception*)new_exception_header)->primaryException : new_exception_header + 1; if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, excpType, adjustedPtr, unwind_exception)) { // We need to __cxa_end_catch, but for the old exception, // not the new one. This is a little tricky ... // Disguise new_exception_header as a rethrown exception, but // don't actually rethrow it. This means you can temporarily // end the catch clause enclosing new_exception_header without // __cxa_end_catch destroying new_exception_header. new_exception_header->handlerCount = -new_exception_header->handlerCount; globals->uncaughtExceptions += 1; // Call __cxa_end_catch for new_exception_header __cxa_end_catch(); // Call __cxa_end_catch for old_exception_header __cxa_end_catch(); // Renter this catch clause with new_exception_header __cxa_begin_catch(&new_exception_header->unwindHeader); // Rethrow new_exception_header throw; } } // Will a std::bad_exception be catchable by the exception spec at // ttypeIndex? // If no // throw std::bad_exception(); const __shim_type_info* excpType = static_cast<const __shim_type_info*>(&typeid(std::bad_exception)); std::bad_exception be; adjustedPtr = &be; if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, excpType, adjustedPtr, unwind_exception)) { // We need to __cxa_end_catch for both the old exception and the // new exception. Technically we should do it in that order. // But it is expedient to do it in the opposite order: // Call __cxa_end_catch for new_exception_header __cxa_end_catch(); // Throw std::bad_exception will __cxa_end_catch for // old_exception_header throw be; } } } std::__terminate(t_handler); }