Ejemplo n.º 1
0
/*
    If thrown_object is not null, allocate, initialize and throw a dependent
    exception.
*/
void
__cxa_rethrow_primary_exception(void* thrown_object)
{
    if ( thrown_object != NULL )
    {
        // thrown_object guaranteed to be native because
        //   __cxa_current_primary_exception returns NULL for foreign exceptions
        __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
        __cxa_dependent_exception* dep_exception_header =
            static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception());
        dep_exception_header->primaryException = thrown_object;
        __cxa_increment_exception_refcount(thrown_object);
        dep_exception_header->exceptionType = exception_header->exceptionType;
        dep_exception_header->unexpectedHandler = std::get_unexpected();
        dep_exception_header->terminateHandler = std::get_terminate();
        setDependentExceptionClass(&dep_exception_header->unwindHeader);
        __cxa_get_globals()->uncaughtExceptions += 1;
        dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup;
#if __arm__
        _Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader);
#else
        _Unwind_RaiseException(&dep_exception_header->unwindHeader);
#endif
        // Some sort of unwinding error.  Note that terminate is a handler.
        __cxa_begin_catch(&dep_exception_header->unwindHeader);
    }
    // If we return client will call terminate()
}
Ejemplo n.º 2
0
/*
After constructing the exception object with the throw argument value,
the generated code calls the __cxa_throw runtime library routine. This
routine never returns.

The __cxa_throw routine will do the following:

* Obtain the __cxa_exception header from the thrown exception object address,
which can be computed as follows: 
 __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1); 
* Save the current unexpected_handler and terminate_handler in the __cxa_exception header.
* Save the tinfo and dest arguments in the __cxa_exception header. 
* Set the exception_class field in the unwind header. This is a 64-bit value
representing the ASCII string "XXXXC++\0", where "XXXX" is a
vendor-dependent string. That is, for implementations conforming to this
ABI, the low-order 4 bytes of this 64-bit value will be "C++\0".
* Increment the uncaught_exception flag. 
* Call _Unwind_RaiseException in the system unwind library, Its argument is the
pointer to the thrown exception, which __cxa_throw itself received as an argument.
__Unwind_RaiseException begins the process of stack unwinding, described
in Section 2.5. In special cases, such as an inability to find a
handler, _Unwind_RaiseException may return. In that case, __cxa_throw
will call terminate, assuming that there was no handler for the
exception.
*/
LIBCXXABI_NORETURN
void 
__cxa_throw(void* thrown_object, std::type_info* tinfo, void (*dest)(void*))
{
    __cxa_eh_globals *globals = __cxa_get_globals();
    __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);

    exception_header->unexpectedHandler = std::get_unexpected();
    exception_header->terminateHandler  = std::get_terminate();
    exception_header->exceptionType = tinfo;
    exception_header->exceptionDestructor = dest;
    setExceptionClass(&exception_header->unwindHeader);
    exception_header->referenceCount = 1;  // This is a newly allocated exception, no need for thread safety.
    globals->uncaughtExceptions += 1;   // Not atomically, since globals are thread-local

    exception_header->unwindHeader.exception_cleanup = exception_cleanup_func;
#if __arm__
    _Unwind_SjLj_RaiseException(&exception_header->unwindHeader);
#else
    _Unwind_RaiseException(&exception_header->unwindHeader);
#endif
    //  This only happens when there is no handler, or some unexpected unwinding
    //     error happens.
    failed_throw(exception_header);
}
Ejemplo n.º 3
0
/*
The routine to be called after the cleanup has been performed.  It will get the
propagating __cxa_exception from __cxa_eh_globals, and continue the stack
unwinding with _Unwind_Resume.

According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any
register, thus we have to write this function in assembly so that we can save
{r1, r2, r3}.  We don't have to save r0 because it is the return value and the
first argument to _Unwind_Resume().  In addition, we are saving r4 in order to
align the stack to 16 bytes, even though it is a callee-save register.
*/
__attribute__((used)) static _Unwind_Exception *
__cxa_end_cleanup_impl()
{
    __cxa_eh_globals* globals = __cxa_get_globals();
    __cxa_exception* exception_header = globals->propagatingExceptions;
    if (NULL == exception_header)
    {
        // It seems that __cxa_begin_cleanup() is not called properly.
        // We have no choice but terminate the program now.
        std::terminate();
    }

    if (isOurExceptionClass(&exception_header->unwindHeader))
    {
        --exception_header->propagationCount;
        if (0 == exception_header->propagationCount)
        {
            globals->propagatingExceptions = exception_header->nextPropagatingException;
            exception_header->nextPropagatingException = NULL;
        }
    }
    else
    {
        globals->propagatingExceptions = NULL;
    }
    return &exception_header->unwindHeader;
}
Ejemplo n.º 4
0
/*
The routine to be called before the cleanup.  This will save __cxa_exception in
__cxa_eh_globals, so that __cxa_end_cleanup() can recover later.
*/
bool
__cxa_begin_cleanup(void* unwind_arg) throw ()
{
    _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
    __cxa_eh_globals* globals = __cxa_get_globals();
    __cxa_exception* exception_header =
        cxa_exception_from_exception_unwind_exception(unwind_exception);

    if (isOurExceptionClass(unwind_exception))
    {
        if (0 == exception_header->propagationCount)
        {
            exception_header->nextPropagatingException = globals->propagatingExceptions;
            globals->propagatingExceptions = exception_header;
        }
        ++exception_header->propagationCount;
    }
    else
    {
        // If the propagatingExceptions stack is not empty, since we can't
        // chain the foreign exception, terminate it.
        if (NULL != globals->propagatingExceptions)
            std::terminate();
        globals->propagatingExceptions = exception_header;
    }
    return true;
}
Ejemplo n.º 5
0
void __cilkrts_save_exception_state(__cilkrts_worker *w, full_frame *ff)
{
    save_exception_info(w, __cxa_get_globals(), 0, false, "undo-detach");
    CILK_ASSERT(NULL == ff->pending_exception);
    ff->pending_exception = w->l->pending_exception;
    w->l->pending_exception = NULL;    
}
Ejemplo n.º 6
0
void __tdeh_init()
{
#if defined(__EXCEPTIONS)
    __cxa_get_globals();
#else
    return;
#endif
}
Ejemplo n.º 7
0
void __cilkrts_setup_for_execution_sysdep(__cilkrts_worker *w, full_frame *ff)
{
    // ASSERT: We own w->lock and ff->lock || P == 1

    __cxa_eh_globals *state = __cxa_get_globals ();
    struct pending_exception_info *info = w->l->pending_exception;

    if (info == NULL)
        return;

    w->l->pending_exception = 0;

#if DEBUG_EXCEPTIONS
    _Unwind_Exception *exc = info->active;
    if (exc) {
        fflush(stdout);
        fprintf(stderr, "__cilkrts_resume_except W%u %p->%p [%u %p]\n",
                w->self, exc,
                to_cxx(exc)->nextException,
                info->runtime_state.uncaughtExceptions,
                info->runtime_state.caughtExceptions);
        /*CILK_ASSERT(info->runtime_state.uncaughtExceptions > 0);*/
    }
#endif

    if (state->uncaughtExceptions || state->caughtExceptions)
        __cilkrts_bug("W%u: resuming with non-empty prior exception state %u %p\n", state->uncaughtExceptions, state->caughtExceptions);

    *state = info->runtime_state;
    info->runtime_state.caughtExceptions = 0;
    info->runtime_state.uncaughtExceptions = 0;

    if (info->rethrow) {
        info->rethrow = false;
        /* Resuming function will rethrow.  Runtime calls
           std::terminate if there is no caught exception. */
        ff->call_stack->flags |= CILK_FRAME_EXCEPTING;
    }
    if (info->active) {
        ff->call_stack->flags |= CILK_FRAME_EXCEPTING;
        ff->call_stack->except_data = info->active;
        info->active = 0;
    }

    if (info->empty()) {
        info->destruct();
        __cilkrts_frame_free(w, info, sizeof *info);
        w->l->pending_exception = NULL;
    }

#if CILK_LIB_DEBUG
    if (ff->call_stack->except_data)
        CILK_ASSERT(std::uncaught_exception());
#endif
}
Ejemplo n.º 8
0
/*
This routine can catch foreign or native exceptions.  If native, the exception
can be a primary or dependent variety.  This routine may remain blissfully
ignorant of whether the native exception is primary or dependent.

If the exception is native:
* Increment's the exception's handler count.
* Push the exception on the stack of currently-caught exceptions if it is not 
  already there (from a rethrow).
* Decrements the uncaught_exception count.
* Returns the adjusted pointer to the exception object, which is stored in
  the __cxa_exception by the personality routine.

If the exception is foreign, this means it did not originate from one of throw
routines.  The foreign exception does not necessarily have a __cxa_exception
header.  However we can catch it here with a catch (...), or with a call
to terminate or unexpected during unwinding.
* Do not try to increment the exception's handler count, we don't know where
  it is.
* Push the exception on the stack of currently-caught exceptions only if the
  stack is empty.  The foreign exception has no way to link to the current
  top of stack.  If the stack is not empty, call terminate.  Even with an
  empty stack, this is hacked in by pushing a pointer to an imaginary
  __cxa_exception block in front of the foreign exception.  It would be better
  if the __cxa_eh_globals structure had a stack of _Unwind_Exception, but it
  doesn't.  It has a stack of __cxa_exception (which has a next* in it).
* Do not decrement the uncaught_exception count because we didn't increment it
  in __cxa_throw (or one of our rethrow functions).
* If we haven't terminated, assume the exception object is just past the 
  _Unwind_Exception and return a pointer to that.
*/
void*
__cxa_begin_catch(void* unwind_arg) throw()
{
    _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
    bool native_exception = isOurExceptionClass(unwind_exception);
    __cxa_eh_globals* globals = __cxa_get_globals();
    // exception_header is a hackish offset from a foreign exception, but it
    //   works as long as we're careful not to try to access any __cxa_exception
    //   parts.
    __cxa_exception* exception_header =
            cxa_exception_from_exception_unwind_exception
            (
                static_cast<_Unwind_Exception*>(unwind_exception)
            );
    if (native_exception)
    {
        // Increment the handler count, removing the flag about being rethrown
        exception_header->handlerCount = exception_header->handlerCount < 0 ?
            -exception_header->handlerCount + 1 : exception_header->handlerCount + 1;
        //  place the exception on the top of the stack if it's not already
        //    there by a previous rethrow
        if (exception_header != globals->caughtExceptions)
        {
            exception_header->nextException = globals->caughtExceptions;
            globals->caughtExceptions = exception_header;
        }
        globals->uncaughtExceptions -= 1;   // Not atomically, since globals are thread-local
#if LIBCXXABI_ARM_EHABI
        return reinterpret_cast<void*>(exception_header->unwindHeader.barrier_cache.bitpattern[0]);
#else
        return exception_header->adjustedPtr;
#endif
    }
    // Else this is a foreign exception
    // If the caughtExceptions stack is not empty, terminate
    if (globals->caughtExceptions != 0)
        std::terminate();
    // Push the foreign exception on to the stack
    globals->caughtExceptions = exception_header;
    return unwind_exception + 1;
}
Ejemplo n.º 9
0
/*  This routine can rethrow native or foreign exceptions.
If the exception is native:
* marks the exception object on top of the caughtExceptions stack 
  (in an implementation-defined way) as being rethrown. 
* If the caughtExceptions stack is empty, it calls terminate() 
  (see [C++FDIS] [except.throw], 15.1.8). 
* It then calls _Unwind_RaiseException which should not return
   (terminate if it does).
  Note:  exception_header may be masquerading as a __cxa_dependent_exception
         and that's ok.
*/
LIBCXXABI_NORETURN
void
__cxa_rethrow()
{
    __cxa_eh_globals* globals = __cxa_get_globals();
    __cxa_exception* exception_header = globals->caughtExceptions;
    if (NULL == exception_header)
        std::terminate();      // throw; called outside of a exception handler
    bool native_exception = isOurExceptionClass(&exception_header->unwindHeader);
    if (native_exception)
    {
        //  Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch)
        exception_header->handlerCount = -exception_header->handlerCount;
        globals->uncaughtExceptions += 1;
        //  __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary
    }
    else  // this is a foreign exception
    {
        // The only way to communicate to __cxa_end_catch that we've rethrown
        //   a foreign exception, so don't delete us, is to pop the stack here
        //   which must be empty afterwards.  Then __cxa_end_catch will do
        //   nothing
        globals->caughtExceptions = 0;
    }
#if __arm__
    _Unwind_SjLj_RaiseException(&exception_header->unwindHeader);
#else
    _Unwind_RaiseException(&exception_header->unwindHeader);
#endif

    //  If we get here, some kind of unwinding error has occurred.
    //  There is some weird code generation bug happening with 
    //     Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn)
    //     If we call failed_throw here.  Turns up with -O2 or higher, and -Os.
    __cxa_begin_catch(&exception_header->unwindHeader);
    if (native_exception)
        std::__terminate(exception_header->terminateHandler);
    // Foreign exception: can't get exception_header->terminateHandler
    std::terminate();
}
Ejemplo n.º 10
0
NORETURN __cilkrts_c_sync_except (__cilkrts_worker *w, __cilkrts_stack_frame *sf)
{
    __cxa_eh_globals *state = __cxa_get_globals();
    _Unwind_Exception *exc = (_Unwind_Exception *)sf->except_data;

    CILK_ASSERT((sf->flags & (CILK_FRAME_UNSYNCHED|CILK_FRAME_EXCEPTING)) ==
                (CILK_FRAME_UNSYNCHED|CILK_FRAME_EXCEPTING));
    sf->flags &= ~CILK_FRAME_EXCEPTING;

#if DEBUG_EXCEPTIONS
    fflush(stdout);
    char decoded[9];
    decode_flags(sf->flags, decoded);
    if (exc)
        fprintf(stderr, "__cilkrts_sync_except W%u %p/%s %p->%p [%u %p]\n",
                w->self, sf, decoded, exc,
                to_cxx(exc)->nextException,
                state->uncaughtExceptions,
                state->caughtExceptions);
    else
        fprintf(stderr, "__cilkrts_sync_except W%d %p/%s none [%u %p]\n",
                w->self, sf, decoded,
                state->uncaughtExceptions,
                state->caughtExceptions);
#endif

    /* Here the identity of an rethrown exception is always known.
       If exc is NULL this call is only to preserve parent state. */
    save_exception_info(w, state, exc, false, "sync_except");
#if 0
    {
        full_frame *ff = w->l->frame_ff;
        CILK_ASSERT(NULL == ff->pending_exception);
        ff->pending_exception = w->l->pending_exception;
        w->l->pending_exception = NULL;    
    }
#endif
    CILK_ASSERT(!std::uncaught_exception());
    __cilkrts_c_sync(w, sf);
}
Ejemplo n.º 11
0
std::vector<ExceptionInfo> getCurrentExceptions() {
  struct Once {
    Once() {
      // See if linked in with us (getExceptionStackTraceStack is weak)
      getExceptionStackTraceStackFn = getExceptionStackTraceStack;

      if (!getExceptionStackTraceStackFn) {
        // Nope, see if it's in a shared library
        getExceptionStackTraceStackFn = (GetExceptionStackTraceStackType)dlsym(
            RTLD_NEXT, "getExceptionStackTraceStack");
      }
    }
  };
  static Once once;

  std::vector<ExceptionInfo> exceptions;
  auto currentException = __cxa_get_globals()->caughtExceptions;
  if (!currentException) {
    return exceptions;
  }

  StackTraceStack* traceStack = nullptr;
  if (!getExceptionStackTraceStackFn) {
    static bool logged = false;
    if (!logged) {
      LOG(WARNING)
          << "Exception tracer library not linked, stack traces not available";
      logged = true;
    }
  } else if ((traceStack = getExceptionStackTraceStackFn()) == nullptr) {
    static bool logged = false;
    if (!logged) {
      LOG(WARNING)
          << "Exception stack trace invalid, stack traces not available";
      logged = true;
    }
  }

  StackTrace* trace = traceStack ? traceStack->top() : nullptr;
  while (currentException) {
    ExceptionInfo info;
    // Dependent exceptions (thrown via std::rethrow_exception) aren't
    // standard ABI __cxa_exception objects, and are correctly labeled as
    // such in the exception_class field.  We could try to extract the
    // primary exception type in horribly hacky ways, but, for now, nullptr.
    info.type = isAbiCppException(currentException)
        ? currentException->exceptionType
        : nullptr;

    if (traceStack) {
      LOG_IF(DFATAL, !trace)
          << "Invalid trace stack for exception of type: "
          << (info.type ? folly::demangle(*info.type) : "null");

      if (!trace) {
        return {};
      }

      info.frames.assign(
          trace->addresses, trace->addresses + trace->frameCount);
      trace = traceStack->next(trace);
    }
    currentException = currentException->nextException;
    exceptions.push_back(std::move(info));
  }

  LOG_IF(DFATAL, trace) << "Invalid trace stack!";

  return exceptions;
}
Ejemplo n.º 12
0
CILK_ABI_THROWS_VOID
__cilkrts_return_exception(__cilkrts_stack_frame *sf)
{
    __cilkrts_worker *w = sf->worker;
    _Unwind_Exception *exc = (_Unwind_Exception *)sf->except_data;

    CILK_ASSERT(sf->flags & CILK_FRAME_DETACHED);
    sf->flags &= ~CILK_FRAME_DETACHED;

   /*
    * If we are in replay mode, and a steal occurred during the recording
    * phase, stall till a steal actually occurs.
    */
    replay_wait_for_steal_if_parent_was_stolen(w);

    /* If this is to be an abnormal return, save the active exception. */
    if (!__cilkrts_pop_tail(w)) {
        /* Write a record to the replay log for an attempt to return to a
           stolen parent.  This must be done before the exception handler
           invokes __cilkrts_leave_frame which will bump the pedigree so
           the replay_wait_for_steal_if_parent_was_stolen() above will match on
           replay */
        replay_record_orphaned(w);

        /* Now that the record/replay stuff is done, update the pedigree */
        update_pedigree_on_leave_frame(w, sf);

        /* Inline pop_frame; this may not be needed. */
        w->current_stack_frame = sf->call_parent;
        sf->call_parent = 0;
        __cxa_eh_globals *state = __cxa_get_globals();

#if DEBUG_EXCEPTIONS
        fflush(stdout);
        char decoded[9];
        decode_flags(sf->flags, decoded);
        fprintf(stderr, "__cilkrts_save_except W%u sf %p/%s exc %p [%u %p] suspend\n",
                w->self, sf, decoded, exc,
                state->uncaughtExceptions,
                state->caughtExceptions);
#endif

        /* Like __cilkrts_save_exception_state except for setting the
           rethrow flag. */
        save_exception_info(w, state, exc, exc == NULL, "save_except");
        {
            full_frame *ff = w->l->frame_ff;
            CILK_ASSERT(NULL == ff->pending_exception);
            ff->pending_exception = w->l->pending_exception;
            w->l->pending_exception = NULL;
        }
        __cilkrts_exception_from_spawn(w, sf); /* does not return */
    }
    /* This code path is taken when the parent is attached.  It is on
       the same stack and part of the same full frame.  The caller is
       cleaning up the Cilk frame during unwind and will reraise the
       exception */

    /* Now that the record/replay stuff is done, update the pedigree */
    update_pedigree_on_leave_frame(w, sf);

#if DEBUG_EXCEPTIONS /* DEBUG ONLY */
    {
        __cxa_eh_globals *state = __cxa_get_globals();

        fflush(stdout);
        char decoded[9];
        decode_flags(sf->flags, decoded);
        fprintf(stderr, "__cilkrts_save_except W%d %p/%s %p->%p [%u %p] escape\n",
                w->self, sf, decoded, exc,
                exc ? to_cxx(exc)->nextException : 0,
                state->uncaughtExceptions,
                state->caughtExceptions);

        /* XXX This is triggering in the user thread which gets an exception
           from somewhere but does not get the corresponding runtime exception
           state.
           XXX There might be two or more uncaught exceptions.  Test could be
           (uncaught != 0) == (exc != 0).  First, design tests to see if that
           case is otherwise handled correctly.  And what if there's an uncaught
           exception that does not belong to this function?  I.e. this is a return
           from spawn in a destructor. */
        if (exc)
            CILK_ASSERT((int)state->uncaughtExceptions > 0);
        /*CILK_ASSERT(state->uncaughtExceptions == (exc != 0));*/
    }
#endif
    
    /* The parent is attached so this exception can be propagated normally. */
    return;
}