Fix exception handling issue (#633)
authorJan Vorlicek <janvorli@microsoft.com>
Tue, 7 Apr 2015 22:27:21 +0000 (00:27 +0200)
committerJan Vorlicek <janvorli@microsoft.com>
Tue, 7 Apr 2015 22:27:21 +0000 (00:27 +0200)
This change fixes exception handling issue #633. The problem was caused by the
fact that in interleaved exception handling (when exception propagates over
one or more native / managed stack frame boundaries), we were preserving the
m_ScannedStackRange and m_sfResumeStackFrame members of the exception tracker
after unwinding a sequence of native frames and moving on into next block of
managed ones. The m_ScannedStackRange in that case contained addresses of
frames that were already unwound and in case of a rethrown exception, there
could have been new frames in that range. That lead to improper detection
of already processed frames in some cases.
The proper solution is to start with an empty scanned stack range after the
partial unwind that unwinds managed and the adjacent native frames.

src/vm/exceptionhandling.cpp
src/vm/exceptionhandling.h

index 4012a62..2937dc7 100644 (file)
@@ -3521,8 +3521,6 @@ void ExceptionTracker::PopTrackers(
 // Save the state of the source exception tracker
 void ExceptionTracker::PartialTrackerState::Save(const ExceptionTracker* pSourceTracker)
 {
-    m_sfResumeStackFrame = pSourceTracker->m_sfResumeStackFrame;
-    m_ScannedStackRange = pSourceTracker->m_ScannedStackRange;
     m_uCatchToCallPC = pSourceTracker->m_uCatchToCallPC;
     m_pClauseForCatchToken = pSourceTracker->m_pClauseForCatchToken;
     m_ClauseForCatch = pSourceTracker->m_ClauseForCatch;
@@ -3536,8 +3534,6 @@ void ExceptionTracker::PartialTrackerState::Save(const ExceptionTracker* pSource
 // Restore the state into the target exception tracker
 void ExceptionTracker::PartialTrackerState::Restore(ExceptionTracker* pTargetTracker)
 {
-    pTargetTracker->m_sfResumeStackFrame = m_sfResumeStackFrame;
-    pTargetTracker->m_ScannedStackRange = m_ScannedStackRange;
     pTargetTracker->m_uCatchToCallPC = m_uCatchToCallPC;
     pTargetTracker->m_pClauseForCatchToken = m_pClauseForCatchToken;
     pTargetTracker->m_ClauseForCatch = m_ClauseForCatch;
@@ -3718,9 +3714,6 @@ ExceptionTracker* ExceptionTracker::GetOrCreateTracker(
             previousTrackerPartialState.Restore(pNewTracker);
             // Reset the 'unwind has started' flag to indicate we are in the first pass again
             pNewTracker->m_ExceptionFlags.ResetUnwindHasStarted();
-            // Remember the current scanned stack range so that we can restore it after
-            // switching to the 2nd pass.
-            pNewTracker->m_secondPassInitialScannedStackRange = pNewTracker->m_ScannedStackRange;
         }
 
         CONSISTENCY_CHECK(pNewTracker->IsValid());
@@ -3873,7 +3866,7 @@ ExceptionTracker* ExceptionTracker::GetOrCreateTracker(
                 // We have to detect this transition because otherwise we break when unmanaged code
                 // catches our exceptions.
                 EH_LOG((LL_INFO100, ">>tracker transitioned to second pass\n"));
-                pTracker->m_ScannedStackRange = pTracker->m_secondPassInitialScannedStackRange;
+                pTracker->m_ScannedStackRange.Reset();
 
                 pTracker->m_ExceptionFlags.SetUnwindHasStarted();
                 if (pTracker->m_ExceptionFlags.UnwindingToFindResumeFrame())
index 9362fa4..820f0d3 100644 (file)
@@ -669,8 +669,6 @@ private: ;
     // is propagated to the new tracker instance.
     class PartialTrackerState
     {
-        StackFrame m_sfResumeStackFrame;
-        StackRange m_ScannedStackRange;
         UINT_PTR m_uCatchToCallPC;
         PTR_EXCEPTION_CLAUSE_TOKEN m_pClauseForCatchToken;
         EE_ILEXCEPTION_CLAUSE m_ClauseForCatch;
@@ -692,12 +690,6 @@ private: ;
                                                 // reuse its memory, if it's non-NULL, it better be a valid thread pointer
 
     StackRange              m_ScannedStackRange;
-    // Range used to initialize the m_ScannedStackRange at start of the 2nd pass.
-    // This is: 
-    // 1) null range for non-interleaved exception handling and the very first
-    //    2nd pass of the interleaved handling and
-    // 2) non-null for the other 2nd passes of the interleaved handling.
-    StackRange              m_secondPassInitialScannedStackRange;
     DAC_EXCEPTION_POINTERS  m_ptrs;
     OBJECTHANDLE            m_hThrowable;
     StackTraceInfo          m_StackTraceInfo;