From 509c6c6ba00d807a912c9e9193ee70a4d3090d40 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 5 Dec 2025 21:17:23 +0100 Subject: [PATCH 1/2] Improve stack overflow stacktrace pretty print The current algorithm used for the stack overflow stactrace pretty printing isn't able to find repetitions that don't start at the first frame. That leads to huge stack traces when there are few non-repeated frames on the top of the stack, e.g. when a recursion in managed method calls to some common chain of methods and the stack overflow occurs down that chain and not in the recursive part. This change fixes that. When no repeated sequence is found at the top of the stack, it tries to search from the next frame and so on until a repeated sequence is identified. Close #118218 --- src/coreclr/vm/eepolicy.cpp | 107 ++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 42 deletions(-) diff --git a/src/coreclr/vm/eepolicy.cpp b/src/coreclr/vm/eepolicy.cpp index 0e22b1e39ad27e..1d3a14d0d50870 100644 --- a/src/coreclr/vm/eepolicy.cpp +++ b/src/coreclr/vm/eepolicy.cpp @@ -162,13 +162,6 @@ class CallStackLogger // MethodDescs of the stack frames, the TOS is at index 0 CDynArray m_frames; - // Index of a stack frame where a possible repetition of frames starts - int m_commonStartIndex = -1; - // Length of the largest found repeated sequence of frames - int m_largestCommonStartLength = 0; - // Number of repetitions of the largest repeated sequence of frames - int m_largestCommonStartRepeat = 0; - StackWalkAction LogCallstackForLogCallbackWorker(CrawlFrame *pCF) { WRAPPER_NO_CONTRACT; @@ -183,36 +176,6 @@ class CallStackLogger } } - MethodDesc *pMD = pCF->GetFunction(); - - if (m_commonStartIndex != -1) - { - // Some common frames were already found - - if (m_frames[m_frames.Count() - m_commonStartIndex] != pMD) - { - // The frame being added is not part of the repeated sequence - if (m_frames.Count() / m_commonStartIndex >= 2) - { - // A sequence repeated at least twice was found. It is the largest one that was found so far - m_largestCommonStartLength = m_commonStartIndex; - m_largestCommonStartRepeat = m_frames.Count() / m_commonStartIndex; - } - - m_commonStartIndex = -1; - } - } - - if (m_commonStartIndex == -1) - { - if ((m_frames.Count() != 0) && (pMD == m_frames[0])) - { - // We have found a frame with the same MethodDesc as the frame at the top of the stack, - // possibly a new repeated sequence is starting. - m_commonStartIndex = m_frames.Count(); - } - } - MethodDesc** itemPtr = m_frames.Append(); if (itemPtr == nullptr) { @@ -220,7 +183,7 @@ class CallStackLogger return SWA_ABORT; } - *itemPtr = pMD; + *itemPtr = pCF->GetFunction();; return SWA_CONTINUE; } @@ -260,22 +223,82 @@ class CallStackLogger { WRAPPER_NO_CONTRACT; - if (m_largestCommonStartLength != 0) + // Length of the largest found repeated sequence of frames + int largestCommonLength = 0; + // Number of repetitions of the largest repeated sequence of frames + int largestCommonRepeat = 0; + + // Start index of the repetition + int largestCommonStartOffset; + for (largestCommonStartOffset = 0; largestCommonStartOffset < m_frames.Count(); largestCommonStartOffset++) + { + // Index of a stack frame where a possible repetition of frames starts + int commonStartIndex = -1; + largestCommonLength = 0; + largestCommonRepeat = 0; + + for (int i = largestCommonStartOffset; i < m_frames.Count(); i++) + { + MethodDesc* pMD = m_frames[i]; + if (commonStartIndex != -1) + { + // Some common frames were already found + + int commonLength = commonStartIndex - largestCommonStartOffset; + if (m_frames[i - commonLength] != pMD) + { + // The frame being added is not part of the repeated sequence + int commonRepeat = (i - largestCommonStartOffset) / commonLength; + if (commonRepeat >= 2) + { + // A sequence repeated at least twice was found. It is the largest one that was found so far + largestCommonLength = commonLength; + largestCommonRepeat = commonRepeat; + } + + commonStartIndex = -1; + } + } + + if (commonStartIndex == -1) + { + if ((i != largestCommonStartOffset) && (pMD == m_frames[largestCommonStartOffset])) + { + // We have found a frame with the same MethodDesc as the frame at the top of the stack, + // possibly a new repeated sequence is starting. + commonStartIndex = i; + } + } + } + + if (largestCommonRepeat != 0) + { + // A repeated sequence of frames was identified + break; + } + } + + for (int i = 0; i < largestCommonStartOffset; i++) + { + PrintFrame(i, pWordAt); + } + + if (largestCommonLength != 0) { SmallStackSString repeatStr; - repeatStr.AppendPrintf("Repeated %d times:\n", m_largestCommonStartRepeat); + repeatStr.AppendPrintf("Repeated %d times:\n", largestCommonRepeat); PrintToStdErrW(repeatStr.GetUnicode()); PrintToStdErrA("--------------------------------\n"); - for (int i = 0; i < m_largestCommonStartLength; i++) + for (int i = largestCommonStartOffset; i < largestCommonStartOffset + largestCommonLength; i++) { PrintFrame(i, pWordAt); } PrintToStdErrA("--------------------------------\n"); } - for (int i = m_largestCommonStartLength * m_largestCommonStartRepeat; i < m_frames.Count(); i++) + for (int i = largestCommonLength * largestCommonRepeat + largestCommonStartOffset; i < m_frames.Count(); i++) { PrintFrame(i, pWordAt); } From 285750d237d137605b0521aa67ba978343fb99ae Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 5 Dec 2025 23:24:46 +0100 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/vm/eepolicy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/eepolicy.cpp b/src/coreclr/vm/eepolicy.cpp index 1d3a14d0d50870..317c1df1165fc9 100644 --- a/src/coreclr/vm/eepolicy.cpp +++ b/src/coreclr/vm/eepolicy.cpp @@ -183,7 +183,7 @@ class CallStackLogger return SWA_ABORT; } - *itemPtr = pCF->GetFunction();; + *itemPtr = pCF->GetFunction(); return SWA_CONTINUE; } @@ -264,7 +264,7 @@ class CallStackLogger { if ((i != largestCommonStartOffset) && (pMD == m_frames[largestCommonStartOffset])) { - // We have found a frame with the same MethodDesc as the frame at the top of the stack, + // We have found a frame with the same MethodDesc as the frame at the start of the repetition search (index largestCommonStartOffset), // possibly a new repeated sequence is starting. commonStartIndex = i; }