From 14de7d30063c2955523c1ff2ccb48e339977742b Mon Sep 17 00:00:00 2001 From: Gaurav Khanna Date: Wed, 16 Sep 2015 11:45:06 -0700 Subject: Fix for GH issue 410 - https://github.com/dotnet/coreclr/issues/410 Whenever a managed exception is thrown, the details about the thrown exception are also saved off the managed thread object (as LastThrownObject). The VM also has an exception tracker that tracks its dispatch across the managed frames and incase of nested exceptions, the trackers are collapsed correctly, when the nested exception is handled, and last thrown object is updated correctly. The VM works on the premise that the LastThrownObject is updated correctly. Incase of this bug, a method (M1)is invoked via Reflection and has an exception E1. During exception dispatch for E1, an IL filter is invoked that, in turn, has an exception (E2) that remains unhandled. While this is swallowed by the VM (as expected), the LastThrownObject is not updated to reflect the active exception to be E1. Thus, when the dispatch for original exception E1 completes and no managed handler is found, the exception is caught by Reflection subsystem that extracts the thrown exception using the GET_THROWABLE macro that uses the LastThrownObject to determine the thrown exception. Since the LTO was not updated, it still reflects E2. The fix is to update the managed exception state, if the filter has an unhandled exception, similar to how we do when a managed catch block successfully handles the exception. I have refactored the code to make the semantic cleaner. [tfs-changeset: 1525835] --- src/vm/i386/excepx86.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'src/vm/i386') diff --git a/src/vm/i386/excepx86.cpp b/src/vm/i386/excepx86.cpp index 6bf26a4790..7de7b43e0d 100644 --- a/src/vm/i386/excepx86.cpp +++ b/src/vm/i386/excepx86.cpp @@ -1890,18 +1890,11 @@ NOINLINE LPVOID COMPlusEndCatchWorker(Thread * pThread) pExInfo->UnwindExInfo(esp); - // This will set the last thrown to be either null if we have handled all the exceptions in the nested chain or - // to whatever the current exception is. + // Prepare to sync managed exception state // // In a case when we're nested inside another catch block, the domain in which we're executing may not be the // same as the one the domain of the throwable that was just made the current throwable above. Therefore, we // make a special effort to preserve the domain of the throwable as we update the the last thrown object. - pThread->SafeUpdateLastThrownObject(); - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Since the catch clause has successfully executed and we are exiting it, reset the corruption severity - // in the ThreadExceptionState for the last active exception. This will ensure that when the next exception - // gets thrown/raised, EH tracker wont pick up an invalid value. // // This function (COMPlusEndCatch) can also be called by the in-proc debugger helper thread on x86 when // an attempt to SetIP takes place to set IP outside the catch clause. In such a case, managed thread object @@ -1910,13 +1903,10 @@ NOINLINE LPVOID COMPlusEndCatchWorker(Thread * pThread) // This behaviour (of debugger doing SetIP) is not allowed on 64bit since the catch clauses are implemented // as a seperate funclet and it's just not allowed to set the IP across EH scopes, such as from inside a catch // clause to outside of the catch clause. - bool fIsDebuggerHelperThread = (g_pDebugInterface == NULL) ? false : g_pDebugInterface->ThisIsHelperThread(); - if (fIsDebuggerHelperThread == false) - { - CEHelper::ResetLastActiveCorruptionSeverityPostCatchHandler(); - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS + + // Sync managed exception state, for the managed thread, based upon any active exception tracker + pThread->SyncManagedExceptionState(fIsDebuggerHelperThread); LOG((LF_EH, LL_INFO1000, "COMPlusPEndCatch: esp=%p\n", esp)); @@ -2241,7 +2231,8 @@ int COMPlusThrowCallbackHelper(IJitManager *pJitManager, ThrowCallbackType* pData, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel, - OBJECTREF throwable + OBJECTREF throwable, + Thread *pThread ) { CONTRACTL @@ -2292,6 +2283,10 @@ int COMPlusThrowCallbackHelper(IJitManager *pJitManager, impersonating = FALSE; } + // We had an exception in filter invocation that remained unhandled. + // Sync managed exception state, for the managed thread, based upon the active exception tracker. + pThread->SyncManagedExceptionState(false); + // // Swallow exception. Treat as exception continue search. // @@ -2702,7 +2697,8 @@ StackWalkAction COMPlusThrowCallback( // SWA value pData, &EHClause, nestingLevel, - throwable); + throwable, + pThread); pExInfo->m_EHClauseInfo.SetManagedCodeEntered(FALSE); -- cgit v1.2.3