Skip to content

Commit f0ad1a7

Browse files
[release/8.0] Fix stack_limit handling (#91095)
* Fix stack_limit handling There is a problem with computing stack_limit in the presence of inactive InlinedCallFrame. We were trying to call GetCallSiteSP on that frame to get the call site SP. But when the inlined call frame is not active (there is no call to native code in progress), that method returns random junk. But even if we checked for an active call before reading the value, it would not get correct stack limit on x86 windows when there was no active call with the inlined call frame being the topmost one. That can happen with hardware exception handling on Windows x86. On other targets, we always have other explicit frame on top of the explicit frames stack, but on windows x86, we don't use the FaultingExceptionFrame for hardware exceptions, so the inactive inlined call frame could be the topmost one when GC starts to scan stack roots. Since the stack_limit was introduced to fix a Unix specific problem, I have fixed that by disabling the stack_limit usage for x86 windows. Close #86265 * Add back the stack_limit field to keep contract unchanged * Reflect PR feedback - Minimalize the number of ifdefs * Reflect PR feedback --------- Co-authored-by: Jan Vorlicek <[email protected]>
1 parent ab22bc7 commit f0ad1a7

File tree

2 files changed

+15
-8
lines changed

2 files changed

+15
-8
lines changed

src/coreclr/vm/gcenv.ee.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,28 @@ static void ScanStackRoots(Thread * pThread, promote_func* fn, ScanContext* sc)
115115
IsGCSpecialThread() ||
116116
(GetThread() == ThreadSuspend::GetSuspensionThread() && ThreadStore::HoldingThreadStore()));
117117

118+
#if defined(FEATURE_CONSERVATIVE_GC) || defined(USE_FEF)
118119
Frame* pTopFrame = pThread->GetFrame();
119120
Object ** topStack = (Object **)pTopFrame;
120-
if ((pTopFrame != ((Frame*)-1))
121-
&& (pTopFrame->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr())) {
122-
// It is an InlinedCallFrame. Get SP from it.
121+
if (InlinedCallFrame::FrameHasActiveCall(pTopFrame))
122+
{
123+
// It is an InlinedCallFrame with active call. Get SP from it.
123124
InlinedCallFrame* pInlinedFrame = (InlinedCallFrame*)pTopFrame;
124125
topStack = (Object **)pInlinedFrame->GetCallSiteSP();
125126
}
127+
#endif // FEATURE_CONSERVATIVE_GC || USE_FEF
126128

129+
#ifdef USE_FEF
130+
// We only set the stack_limit when FEF (FaultingExceptionFrame) is enabled, because without the
131+
// FEF, the code above would have to check if hardware exception is being handled and get the limit
132+
// from the exception frame. Since the stack_limit is strictly necessary only on Unix and FEF is
133+
// not enabled on Window x86 only, it is sufficient to keep the stack_limit set to 0 in this case.
134+
// See the comment on the stack_limit usage in the PromoteCarefully function for more details.
127135
sc->stack_limit = (uintptr_t)topStack;
136+
#else // USE_FEF
137+
// It should be set to 0 in the ScanContext constructor
138+
_ASSERTE(sc->stack_limit == 0);
139+
#endif // USE_FEF
128140

129141
#ifdef FEATURE_CONSERVATIVE_GC
130142
if (g_pConfig->GetGCConservative())

src/coreclr/vm/siginfo.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4962,11 +4962,6 @@ void PromoteCarefully(promote_func fn,
49624962

49634963
#if !defined(DACCESS_COMPILE)
49644964

4965-
//
4966-
// Sanity check the stack scan limit
4967-
//
4968-
assert(sc->stack_limit != 0);
4969-
49704965
// Note that the base is at a higher address than the limit, since the stack
49714966
// grows downwards.
49724967
// To check whether the object is in the stack or not, we also need to check the sc->stack_limit.

0 commit comments

Comments
 (0)