diff options
author | Jan Vorlicek <janvorli@microsoft.com> | 2016-03-07 23:17:10 +0100 |
---|---|---|
committer | Jan Vorlicek <janvorli@microsoft.com> | 2016-03-08 22:02:08 +0100 |
commit | 76c2dfc6321bff28c90ac48b0f2ca5abb02abe72 (patch) | |
tree | 44661f96cd37868935b28216d60f5624f6f96091 | |
parent | dc64c3254c7c60d8b7965defa97db61f5fddfe87 (diff) | |
download | coreclr-76c2dfc6321bff28c90ac48b0f2ca5abb02abe72.tar.gz coreclr-76c2dfc6321bff28c90ac48b0f2ca5abb02abe72.tar.bz2 coreclr-76c2dfc6321bff28c90ac48b0f2ca5abb02abe72.zip |
Fix stack walking on Unix in case of finally
The issue is that the code in the StackFrameIterator::Filter that handles cases
when a funclet frame that was already removed from the stack due to native frames
unwinding works for catch funclets only and not for finally ones.
The ExceptionTracker::GetCallerOfActualHandlingFrame is set for catch funclets
only. To make it work for the finally funclets as well, we need to use information
from the ExceptionTracker::m_EnclosingClauseInfoForGCReporting instead.
There was also another problem in the Filter method that caused the function to
spin in an infinite loop when a parent of a funclet was also a funclet. In
such case, the code in the method rechecks the current frame but the special
functionality to check the exception trackers data needs to be skipped for
the recheck.
And finally, when we find that the current frame was a parent of an unwound
funclet from the evidence in the exception trackers, we also need to set
the fSkippingFunclet.
-rw-r--r-- | src/vm/exceptionhandling.h | 9 | ||||
-rw-r--r-- | src/vm/stackwalk.cpp | 13 |
2 files changed, 16 insertions, 6 deletions
diff --git a/src/vm/exceptionhandling.h b/src/vm/exceptionhandling.h index d5dd4807ce..2a8181b08b 100644 --- a/src/vm/exceptionhandling.h +++ b/src/vm/exceptionhandling.h @@ -558,7 +558,14 @@ public: return m_sfCallerOfActualHandlerFrame; } - StackFrame GetCallerOfCollapsedActualHandlingFrame() + StackFrame GetCallerOfEnclosingClause() + { + LIMITED_METHOD_CONTRACT; + + return m_EnclosingClauseInfoForGCReporting.GetEnclosingClauseCallerSP(); + } + + StackFrame GetCallerOfCollapsedEnclosingClause() { LIMITED_METHOD_CONTRACT; diff --git a/src/vm/stackwalk.cpp b/src/vm/stackwalk.cpp index ec9acfbac2..a2eb2895b0 100644 --- a/src/vm/stackwalk.cpp +++ b/src/vm/stackwalk.cpp @@ -1689,8 +1689,6 @@ StackWalkAction StackFrameIterator::Filter(void) ProcessFuncletsForGCReporting: do { - fRecheckCurrentFrame = false; - // When enumerating GC references for "liveness" reporting, depending upon the architecture, // the responsibility of who reports what varies: // @@ -1751,7 +1749,7 @@ ProcessFuncletsForGCReporting: // only source of evidence about it. // This is different from Windows where the full stack is preserved until an exception is fully handled // and so we can detect it just from walking the stack. - if (!fSkippingFunclet && (pTracker != NULL)) + if (!fRecheckCurrentFrame && !fSkippingFunclet && (pTracker != NULL)) { // The stack walker is not skipping frames now, which means it didn't find a funclet frame that // would require skipping the current frame. If we find a tracker with caller of actual handling @@ -1764,14 +1762,14 @@ ProcessFuncletsForGCReporting: { if (hasFuncletStarted) { - sfFuncletParent = pCurrTracker->GetCallerOfActualHandlingFrame(); + sfFuncletParent = pCurrTracker->GetCallerOfEnclosingClause(); if (!sfFuncletParent.IsNull() && ExceptionTracker::IsUnwoundToTargetParentFrame(&m_crawl, sfFuncletParent)) { break; } } - sfFuncletParent = pCurrTracker->GetCallerOfCollapsedActualHandlingFrame(); + sfFuncletParent = pCurrTracker->GetCallerOfCollapsedEnclosingClause(); if (!sfFuncletParent.IsNull() && ExceptionTracker::IsUnwoundToTargetParentFrame(&m_crawl, sfFuncletParent)) { break; @@ -1793,9 +1791,12 @@ ProcessFuncletsForGCReporting: m_sfFuncletParent = sfFuncletParent; m_fProcessNonFilterFunclet = true; m_fDidFuncletReportGCReferences = false; + fSkippingFunclet = true; } } #endif // FEATURE_PAL + + fRecheckCurrentFrame = false; // Do we already have a reference to a funclet parent? if (!m_sfFuncletParent.IsNull()) { @@ -2000,6 +2001,7 @@ ProcessFuncletsForGCReporting: // Since we are in GC reference reporting mode, // then avoid code duplication and go to // funclet processing. + fRecheckCurrentFrame = true; goto ProcessFuncletsForGCReporting; } } @@ -2105,6 +2107,7 @@ ProcessFuncletsForGCReporting: // If we are in GC reference reporting mode, // then avoid code duplication and go to // funclet processing. + fRecheckCurrentFrame = true; goto ProcessFuncletsForGCReporting; } else |