Beispiel #1
0
LONG PAL_RunFilters(PEXCEPTION_POINTERS pException) {
    PPAL_EXCEPTION_REGISTRATION pRegistration = PAL_GetBottommostRegistration();
    LONG filterResult = EXCEPTION_CONTINUE_SEARCH;
    BOOL foundHandler= FALSE;

    while ((pRegistration != NULL) && !foundHandler) {
        char *thrownTypeStr = NULL;

        switch (pRegistration->typeOfHandler) {
            case PALExceptFilter:
                filterResult = (pRegistration->Handler)
                    (pException, pRegistration->pvFilterParameter);

                switch (filterResult) {
                    case EXCEPTION_EXECUTE_HANDLER:
                        pRegistration->dwFlags |= PAL_EXCEPTION_FLAGS_UNWINDTARGET;
                        foundHandler = TRUE;
                        break;

                    case EXCEPTION_CONTINUE_SEARCH:
                        pRegistration->dwFlags &= ~PAL_EXCEPTION_FLAGS_UNWINDTARGET;
                        break;

                    case EXCEPTION_CONTINUE_EXECUTION:
			foundHandler = true;
			break;
                }
                break;

            case PALExcept:
		filterResult = (LONG)(SIZE_T)pRegistration->Handler;

                switch (filterResult) {
                    case EXCEPTION_EXECUTE_HANDLER:
                        pRegistration->dwFlags |= PAL_EXCEPTION_FLAGS_UNWINDTARGET;
                        foundHandler = TRUE;
                        break;

                    case EXCEPTION_CONTINUE_SEARCH:
                        pRegistration->dwFlags &= ~PAL_EXCEPTION_FLAGS_UNWINDTARGET;
                        break;

                    case EXCEPTION_CONTINUE_EXECUTION:
			foundHandler = TRUE;
			break;
                 }
                break;

            case PALFinally:
                break;

            case CatchTyped:
	        // The exception code must be right
		if (pException->ExceptionRecord->ExceptionCode != PAL_CPP_EXCEPTION_CODE)
		    break;

                // Type thrown must end in "Exception *"
                thrownTypeStr = (char *) pException->ExceptionRecord->ExceptionInformation[0];
                
                if (strcmp(thrownTypeStr + strlen(thrownTypeStr) - strlen("Exception *"),
                           "Exception *") != 0) {
                    pRegistration->dwFlags &= ~PAL_EXCEPTION_FLAGS_UNWINDTARGET;
                    break;
                }

                // fallthru

            case CatchAll:
                pRegistration->dwFlags |= PAL_EXCEPTION_FLAGS_UNWINDTARGET;
                foundHandler = TRUE;
		filterResult = EXCEPTION_EXECUTE_HANDLER;
                break;
        }

        if (!foundHandler)
            pRegistration = pRegistration->Next;
    }

    return filterResult;
};
Beispiel #2
0
/*++
Function:
  PAL_EndTryHelper

Abstract:
  Clean up the SEH stack when leaving a try block, and jump to the next
  exception frame if we're unwinding

Parameters :
    PPAL_EXCEPTION_REGISTRATION pRegistration : current exception frame
    int ExceptionCode : 0 if no exception occurred, nonzero if an exception
                        occurred and this is a stack unwind

    Always returns 0 that can be used to prevent compiler optimizations
    on setjmp/longjmp
--*/
int
PALAPI
PAL_EndTryHelper(
    IN OUT PPAL_EXCEPTION_REGISTRATION pRegistration,
    IN int ExceptionCode)
{
#if !DISABLE_EXCEPTIONS

    if( ExceptionCode == 0 )
    {
        /* If ExceptionCode is zero, there was no exception, so we
           only need to pop the exception frame. */
        SEH_TLS_INFO *seh_info = pthread_getspecific((DWORD) pSEHInfo);

        if( seh_info == NULL && (seh_info=SEHCreateThreadInfo()) == NULL)
        {
            ERROR("Cannot get thread info\n");
            goto done;
        }
 
        if( (pRegistration == NULL) ||
            (pRegistration != seh_info->bottom_frame) )
        {
            ASSERT("Exception registration pointers don't match!\n");
            goto done;
        }
        seh_info->bottom_frame = pRegistration->Next;
        
    }
    else if( pRegistration->dwFlags & PAL_EXCEPTION_FLAGS_UNWINDTARGET )
    {
        /* Stop unwinding if this is the target frame */
        
        /* If there was an exception, the current frame has already been popped 
           before the longjmp */

        if( (pRegistration == NULL) ||
            (pRegistration->Next != PAL_GetBottommostRegistration()) )
        {                 
            ASSERT("Exception registration pointers don't match!\n");
            goto done;
        }

        TRACE("Exception handled by frame %p. Lowest frame is now %p\n", 
              pRegistration, pRegistration->Next);
    }
    else
    {
        SEH_TLS_INFO *seh_info;

        TRACE("Unwinding in progress; looking for next frame\n");
        
        /* If there was an exception, the current frame has already been popped 
           before the longjmp */

        if( (pRegistration == NULL) ||
            (pRegistration->Next != PAL_GetBottommostRegistration()) )
        {
            ASSERT("Exception registration pointers don't match!\n");
            goto done;
        }
        
        SEHUnwind();
        
        TRACE("Reached top of exception stack! Exception was not "
              "handled, terminating the process.\n");

        if(!PALIsInitialized())
        {
            /* The only way we can get here is if PAL_Terminate is currently 
               running, but we haven't yet restored the default signal handlers. 
               This isn't a problem if an exception handler accepts the 
               exception, but if we reach here,TerminateProcess will have to use 
               the "non-initialized" code path : save status and exit, without 
               cleaning up shared memory etc. Not good, but no choice, so we 
               indicate the problem but proceed anyway. */
            WARN("Exception was raised during PAL termination!\n");
        }

        seh_info = SEHGetThreadInfo();

        /* exit code is exception code */
        if(NULL == seh_info)
        {
            WARN("SEH thread data not available, no exception code available! "
                 "using fake exit code\n");
            TerminateProcess(GetCurrentProcess(), -1);
        }
        TerminateProcess(GetCurrentProcess(),
                         seh_info->current_exception.ExceptionCode);
    }

done:
#endif // !DISABLE_EXCEPTIONS
    return 0;
}
Beispiel #3
0
/*++
Function :
    SEHRaiseException

    Raise an exception given a specified exception information.

Parameters :
    PEXCEPTION_POINTERS lpExceptionPointers : specification of exception
    to raise.
    int signal_code : signal that caused the exception, if applicable; 
                      0 otherwise

(no return value)
--*/
void SEHRaiseException( PEXCEPTION_POINTERS lpExceptionPointers, 
                        int signal_code )
{
    PPAL_EXCEPTION_REGISTRATION frame;
    LPTOP_LEVEL_EXCEPTION_FILTER top_filter;
    LONG default_action;
    SEH_TLS_INFO *seh_info;
    LONG handler_retval;

    if(!lpExceptionPointers)
    {
        ASSERT("Invalid exception record!\n");
        return;
    }

    TRACE("Raising exception %#x (record is %p)\n",
          lpExceptionPointers->ExceptionRecord->ExceptionCode,
          lpExceptionPointers);

    seh_info = SEHGetThreadInfo();
    if(NULL == seh_info)
    {
        ASSERT("Couldn't get SEH thread data!\n");
    }
    else
    {
        /* save copy of exception record for access after longjmp */
        memcpy(&seh_info->current_exception,
               lpExceptionPointers->ExceptionRecord, 
               sizeof seh_info->current_exception);
    }

    seh_info->signal_code = signal_code;
    
    /* Call exception filters until one returns EXCEPTION_EXECUTE_HANDLER */

    TRACE("Looking for exception handler...\n");

    frame = PAL_GetBottommostRegistration();

    while( frame )
    {
        if (frame->Handler == NULL )
        {
            TRACE("Exception frame %p is a try/finally block; skipping.\n",
                  frame);
            frame = frame->Next;
            continue;
        }

        if((LONG_PTR)frame->Handler != EXCEPTION_EXECUTE_HANDLER)
        {
/* reset ENTRY nesting level back to zero while inside the callback... */
#if !_NO_DEBUG_MESSAGES_
            {
            int old_level;
            old_level = DBG_change_entrylevel(0);
#endif /* !_NO_DEBUG_MESSAGES_ */

            /* since we're calling the application handler,
               let's reset to safe state so exception in
               the filter could be handled properly */
            SEHSetSafeState(TRUE);
            
            handler_retval = frame->Handler(lpExceptionPointers, 
                                            frame->pvFilterParameter);

            SEHSetSafeState(FALSE);

/* ...and set nesting level back to what it was */
#if !_NO_DEBUG_MESSAGES_
            DBG_change_entrylevel(old_level);
            }
#endif /* !_NO_DEBUG_MESSAGES_ */
        }
        else
        {
            handler_retval = (LONG)frame->Handler;
        }

        if (frame->dwFlags & PAL_EXCEPTION_FLAGS_UNWINDTARGET)
        {
            ASSERT("PAL_EXCEPTION_FLAGS_UNWINDTARGET is set\n");
        }

        switch(handler_retval)
        {
        case EXCEPTION_EXECUTE_HANDLER:
            frame->dwFlags |= PAL_EXCEPTION_FLAGS_UNWINDTARGET;
            break;
        case EXCEPTION_CONTINUE_SEARCH:
            frame->dwFlags &= ~PAL_EXCEPTION_FLAGS_UNWINDTARGET;
            break;
        case EXCEPTION_CONTINUE_EXECUTION:
            TRACE("Filter returned EXCEPTION_CONTINUE_EXECUTION");
            return;
        default:
            /* Filter has returned an invalid value */
            ASSERT("Filter for frame %p has returned an invalid value!\n",
                  frame);
            break;
        }

        if( frame->dwFlags & PAL_EXCEPTION_FLAGS_UNWINDONLY)
        {
            memcpy(frame->ReservedForPAL, lpExceptionPointers->ExceptionRecord,
                min(sizeof(EXCEPTION_RECORD), PAL_TRY_LOCAL_SIZE));
        }

        if( frame->dwFlags & PAL_EXCEPTION_FLAGS_UNWINDTARGET)
        {
            TRACE("Filter for frame %p has accepted the exception.\n", frame);
            break;
        }
        TRACE("Filter for frame %p has refused the exception.\n", frame);
        frame = frame->Next;
    }

    /* once we get here we can assume the exception stack is (reasonably) 
       valid, so we can allow signals to be handled again */
    SEHSetSafeState(TRUE);

    /* If a handler is found, begin unwinding by longjmp()ing to the first
       termination handler */
    if( frame )
    {
        SEHUnwind();
        ASSERT("SEHUnwind returned, even though an exception handler had "
              "accepted the exception!\n");
    }

    /* No handler found : start default handling */

    TRACE("No handler found for exception. Using default behavior.\n");

    /* Call application-defined top-level filter. */
    top_filter = pTopFilter;

    if(top_filter)
    {
        TRACE("Calling application-defined top-level filter\n");

/* reset ENTRY nesting level back to zero while inside the callback... */
#if !_NO_DEBUG_MESSAGES_
    {
        int old_level;
        old_level = DBG_change_entrylevel(0);
#endif /* !_NO_DEBUG_MESSAGES_ */

        default_action = top_filter(lpExceptionPointers);

/* ...and set nesting level back to what it was */
#if !_NO_DEBUG_MESSAGES_
        DBG_change_entrylevel(old_level);
    }
#endif /* !_NO_DEBUG_MESSAGES_ */

        switch( default_action )
        {
        case EXCEPTION_CONTINUE_SEARCH:
            break;
        case EXCEPTION_EXECUTE_HANDLER:
            break;
        default:
            ASSERT("Application-defined top-level exception filter returned "
                  "invalid value %d\n", default_action);
            default_action = EXCEPTION_CONTINUE_SEARCH;
            break;
        }
    }
    else
    {
        default_action = EXCEPTION_CONTINUE_SEARCH;
    }

    WARN("Exception %08x not handled; process will be terminated.\n",
          lpExceptionPointers->ExceptionRecord->ExceptionCode);

    SEHUnwind();

    /* Exception not handled, no termination handlers to execute : terminate */

    TRACE("Reached top of exception stack! Exception was not handled, "
          "terminating the process.\n");

    if(!PALIsInitialized())
    {
        /* The only way we can get here is if PAL_Terminate is currently 
           running, but we haven't yet restored the default signal handlers. 
           This isn't a problem if an exception handler accepts the exception, 
           but if we reach here, TerminateProcess will have to use the 
           "non-initialized" code path : save status and exit, wihtout cleaning 
           up shared memory etc. Not good, but no choice, so we indicate the 
           problem but proceed anyway. */
        WARN("Exception was raised during PAL termination!\n");
    } 
    else if(0 != signal_code)
    {
        // Terminate unconditionally. The application is not in
        // a safe state.
        PROCCleanupProcess(TRUE);
#if HAVE_MACH_EXCEPTIONS
        SEHCleanupExceptionPort();
#else
        SEHCleanupSignals();
#endif
        /* signal handlers uninstalled : let the signal be raised again */
        return;                                                         
    }                                                                   

    /* exit code is exception code */
    TerminateProcess(GetCurrentProcess(),
                     lpExceptionPointers->ExceptionRecord->ExceptionCode);
    ASSERT("TerminateProcess() returned!\n");
}
Beispiel #4
0
static void SEHUnwind()
{
    PAL_EXCEPTION_REGISTRATION *jmp_frame;
    EXCEPTION_POINTERS ep;
    LONG retval;
    SEH_TLS_INFO *seh_info;

    jmp_frame = PAL_GetBottommostRegistration();
    while(NULL != jmp_frame)
    {
        /* finally blocks have no filter */
        if( jmp_frame->Handler == NULL )
        {
            TRACE("Found termination handler frame (%p)\n", jmp_frame);
            break;
        }

        if(jmp_frame->dwFlags & PAL_EXCEPTION_FLAGS_UNWINDONLY)
        {
            jmp_frame->dwFlags &= ~PAL_EXCEPTION_FLAGS_UNWINDTARGET;

            PAL_SetBottommostRegistration(jmp_frame);

            ep.ExceptionRecord = (PEXCEPTION_RECORD) jmp_frame->ReservedForPAL;
            ep.ExceptionRecord->ExceptionFlags |= EXCEPTION_UNWINDING;
            ep.ContextRecord = NULL;

/* reset ENTRY nesting level back to zero while inside the callback... */
#if !_NO_DEBUG_MESSAGES_
            {
                int old_level;
                old_level = DBG_change_entrylevel(0);
#endif /* !_NO_DEBUG_MESSAGES_ */

                retval = jmp_frame->Handler(&ep, 
                                            jmp_frame->pvFilterParameter);
                
/* ...and set nesting level back to what it was, (if callback returned) */
#if !_NO_DEBUG_MESSAGES_
                DBG_change_entrylevel(old_level);
            }
#endif /* !_NO_DEBUG_MESSAGES_ */

            if(EXCEPTION_CONTINUE_SEARCH!=retval)
            {
                ASSERT("Win32 EH filter returned %d instead of "
                       "EXCEPTION_CONTINUE_SEARCH (%d)!\n", 
                       retval, EXCEPTION_CONTINUE_SEARCH);
                break; /* because what else can we do? */
            }

            if (jmp_frame->dwFlags & PAL_EXCEPTION_FLAGS_UNWINDTARGET)
            {
                ASSERT("PAL_EXCEPTION_FLAGS_UNWINDTARGET is set\n");
            }
        }           
        else if( jmp_frame->dwFlags & PAL_EXCEPTION_FLAGS_UNWINDTARGET )
        {
            TRACE("Found unwind target frame (%p)\n", jmp_frame);
            break;
        }

        jmp_frame = jmp_frame->Next;
    }
            
    if (jmp_frame)
    {
        TRACE("Jumping to exception frame %p\n", jmp_frame);

        /* remove the target frame from the chain : if there's an exception 
            within the handler, we don't want it to be sent back to the same
            handler */
        PAL_SetBottommostRegistration(jmp_frame->Next);

/* reset ENTRY nesting level back to zero before longjmping */
#if !_NO_DEBUG_MESSAGES_
        {
            int old_level;
            old_level = DBG_change_entrylevel(0);
#endif /* !_NO_DEBUG_MESSAGES_ */
                
            siglongjmp((LPVOID)jmp_frame->ReservedForPAL,1);

#if !_NO_DEBUG_MESSAGES_
        }
#endif /* !_NO_DEBUG_MESSAGES_ */
    }

    PAL_SetBottommostRegistration(NULL);

    seh_info = SEHGetThreadInfo();

    /* exit code is exception code */
    if(NULL == seh_info)
    {
        WARN("SEH thread data not available, no exception code available! "
             "using fake exit code\n");
        TerminateProcess(GetCurrentProcess(),-1);
    }
    if(0 == seh_info->signal_code)
    {   
        TerminateProcess(GetCurrentProcess(),
                         seh_info->current_exception.ExceptionCode);
    }
    else
    {
        int signal_code;

        TRACE("unhandled signal : shutting down the PAL and re-raising the "
              "signal\n");
        signal_code = seh_info->signal_code;
        // Terminate unconditionally. The application is not in a
        // safe state.
        PROCCleanupProcess(TRUE);
#if HAVE_MACH_EXCEPTIONS
        SEHCleanupExceptionPort();
#else
        SEHCleanupSignals();    
#endif

        /* signal handlers now uninstalled : raise the signal again */
        kill(gPID, signal_code);
    }
}