Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting - #126717

Merged
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification
Apr 15, 2026
Merged

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting#126717
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification

Conversation

@tommcdon

Copy link
Copy Markdown
Member

For certain runtime async frames this resulted in the ICorDebugManagedCallback2::Exception to return a null ICorDebugFrame for DEBUG_EXCEPTION_CATCH_HANDLER_FOUND notifications. The fix addresses this by adjusting GetSpForDiagnosticReporting to account for runtime async variant method stack layout differences on x86.

…orting
Adjust GetSpForDiagnosticReporting to correctly handle runtime async variant method stack layout on x86.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdontommcdon added this to the 11.0.0 milestone Apr 9, 2026
@tommcdontommcdon self-assigned this Apr 9, 2026
CopilotAI review requested due to automatic review settings April 9, 2026 16:18
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts the stack pointer reported to the debugger on x86 for runtime “async call” frames so that ICorDebugManagedCallback2::Exception callbacks (notably DEBUG_EXCEPTION_CATCH_HANDLER_FOUND) can resolve a non-null ICorDebugFrame.

Changes:

  • Extends GetSpForDiagnosticReporting to optionally accept a MethodDesc* and apply an extra x86 adjustment for runtime async methods (IsAsyncMethod()).
  • Updates exception/debugger callback sites to pass the current MethodDesc* into GetSpForDiagnosticReporting.
Comments suppressed due to low confidence (1)

src/coreclr/vm/exceptionhandling.cpp:2968

  • pMD is only referenced under ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP + TARGET_X86. In other builds (e.g., x64 Unix where -Wall is enabled, often with -Werror), this new parameter can become unused and may trigger an unused-parameter warning. Consider adding UNREFERENCED_PARAMETER(pMD); in the #else path and/or in the non-x86 path to keep all configurations warning-free.
static TADDR GetSpForDiagnosticReporting(REGDISPLAY *pRD, MethodDesc *pMD = NULL)
{
#ifdef ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP
TADDR sp = CallerStackFrame::FromRegDisplay(pRD).SP;
#if defined(TARGET_X86)
sp -= sizeof(TADDR);
// On x86, runtime async methods have stack parameters that cause CallerSP
// to sit above the parameter area. The DBI uses PCTAddr as the frame
// pointer, which is at the return address (below the parameters).
// Subtract an extra sizeof(TADDR) to account for the stack parameter.
if (pMD != NULL && pMD->IsAsyncMethod())
{
sp -= sizeof(TADDR);
}
#endif
return sp;
#else
return GetSP(pRD->pCurrentContext);
#endif

Comment threadsrc/coreclr/vm/exceptionhandling.cpp Outdated
@janvorli

Copy link
Copy Markdown
Member

@tommcdon I wonder - was this always a problem? I am asking since there was a change in the ifdef in this code in January (#122833) from

#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)
sp -= sizeof(TADDR); // For X86 with funclets we want the address 1 pointer into the callee.
#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)

I wonder if the ifdef really meant to be for Linux x86 only (which was previously the only one with defined(FEATURE_EH_FUNCLETS)) and was unrelated to the funclets per se.

tommcdonand others added 2 commits April 10, 2026 20:44
On x86, the runtime sends CallerSP - sizeof(TADDR) as the frame pointer for
exception notifications (see GetSpForDiagnosticReporting). Since this does not
account for the stack parameter size, the DBI's IsContainedInFrame now queries
the DAC for stackParamSize and adjusts the frame pointer before matching.
Also switches FindFrame to use TARGET_X86 instead of HOST_64BIT for the
ifdef guard, using exact FramePointer comparison on all non-x86 platforms.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdon

Copy link
Copy Markdown
MemberAuthor

@tommcdon I wonder - was this always a problem?

Yes I think you are correct. A previous fix for this was on #115630.

@tommcdon
tommcdon merged commit bd5a164 into dotnet:mainApr 15, 2026
100 of 111 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 16, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@tommcdon@janvorli@noahfalk@jakobbotsch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting - #126717

Merged
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification
Apr 15, 2026
Merged

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting#126717
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification

Conversation

@tommcdon

Copy link
Copy Markdown
Member

For certain runtime async frames this resulted in the ICorDebugManagedCallback2::Exception to return a null ICorDebugFrame for DEBUG_EXCEPTION_CATCH_HANDLER_FOUND notifications. The fix addresses this by adjusting GetSpForDiagnosticReporting to account for runtime async variant method stack layout differences on x86.

…orting
Adjust GetSpForDiagnosticReporting to correctly handle runtime async variant method stack layout on x86.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdontommcdon added this to the 11.0.0 milestone Apr 9, 2026
@tommcdontommcdon self-assigned this Apr 9, 2026
CopilotAI review requested due to automatic review settings April 9, 2026 16:18
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts the stack pointer reported to the debugger on x86 for runtime “async call” frames so that ICorDebugManagedCallback2::Exception callbacks (notably DEBUG_EXCEPTION_CATCH_HANDLER_FOUND) can resolve a non-null ICorDebugFrame.

Changes:

  • Extends GetSpForDiagnosticReporting to optionally accept a MethodDesc* and apply an extra x86 adjustment for runtime async methods (IsAsyncMethod()).
  • Updates exception/debugger callback sites to pass the current MethodDesc* into GetSpForDiagnosticReporting.
Comments suppressed due to low confidence (1)

src/coreclr/vm/exceptionhandling.cpp:2968

  • pMD is only referenced under ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP + TARGET_X86. In other builds (e.g., x64 Unix where -Wall is enabled, often with -Werror), this new parameter can become unused and may trigger an unused-parameter warning. Consider adding UNREFERENCED_PARAMETER(pMD); in the #else path and/or in the non-x86 path to keep all configurations warning-free.
static TADDR GetSpForDiagnosticReporting(REGDISPLAY *pRD, MethodDesc *pMD = NULL)
{
#ifdef ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP
TADDR sp = CallerStackFrame::FromRegDisplay(pRD).SP;
#if defined(TARGET_X86)
sp -= sizeof(TADDR);
// On x86, runtime async methods have stack parameters that cause CallerSP
// to sit above the parameter area. The DBI uses PCTAddr as the frame
// pointer, which is at the return address (below the parameters).
// Subtract an extra sizeof(TADDR) to account for the stack parameter.
if (pMD != NULL && pMD->IsAsyncMethod())
{
sp -= sizeof(TADDR);
}
#endif
return sp;
#else
return GetSP(pRD->pCurrentContext);
#endif

Comment threadsrc/coreclr/vm/exceptionhandling.cpp Outdated
@janvorli

Copy link
Copy Markdown
Member

@tommcdon I wonder - was this always a problem? I am asking since there was a change in the ifdef in this code in January (#122833) from

#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)
sp -= sizeof(TADDR); // For X86 with funclets we want the address 1 pointer into the callee.
#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)

I wonder if the ifdef really meant to be for Linux x86 only (which was previously the only one with defined(FEATURE_EH_FUNCLETS)) and was unrelated to the funclets per se.

tommcdonand others added 2 commits April 10, 2026 20:44
On x86, the runtime sends CallerSP - sizeof(TADDR) as the frame pointer for
exception notifications (see GetSpForDiagnosticReporting). Since this does not
account for the stack parameter size, the DBI's IsContainedInFrame now queries
the DAC for stackParamSize and adjusts the frame pointer before matching.
Also switches FindFrame to use TARGET_X86 instead of HOST_64BIT for the
ifdef guard, using exact FramePointer comparison on all non-x86 platforms.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdon

Copy link
Copy Markdown
MemberAuthor

@tommcdon I wonder - was this always a problem?

Yes I think you are correct. A previous fix for this was on #115630.

@tommcdon
tommcdon merged commit bd5a164 into dotnet:mainApr 15, 2026
100 of 111 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 16, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@tommcdon@janvorli@noahfalk@jakobbotsch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting - #126717

Merged
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification
Apr 15, 2026
Merged

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting#126717
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification

Conversation

@tommcdon

Copy link
Copy Markdown
Member

For certain runtime async frames this resulted in the ICorDebugManagedCallback2::Exception to return a null ICorDebugFrame for DEBUG_EXCEPTION_CATCH_HANDLER_FOUND notifications. The fix addresses this by adjusting GetSpForDiagnosticReporting to account for runtime async variant method stack layout differences on x86.

…orting
Adjust GetSpForDiagnosticReporting to correctly handle runtime async variant method stack layout on x86.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdontommcdon added this to the 11.0.0 milestone Apr 9, 2026
@tommcdontommcdon self-assigned this Apr 9, 2026
CopilotAI review requested due to automatic review settings April 9, 2026 16:18
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts the stack pointer reported to the debugger on x86 for runtime “async call” frames so that ICorDebugManagedCallback2::Exception callbacks (notably DEBUG_EXCEPTION_CATCH_HANDLER_FOUND) can resolve a non-null ICorDebugFrame.

Changes:

  • Extends GetSpForDiagnosticReporting to optionally accept a MethodDesc* and apply an extra x86 adjustment for runtime async methods (IsAsyncMethod()).
  • Updates exception/debugger callback sites to pass the current MethodDesc* into GetSpForDiagnosticReporting.
Comments suppressed due to low confidence (1)

src/coreclr/vm/exceptionhandling.cpp:2968

  • pMD is only referenced under ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP + TARGET_X86. In other builds (e.g., x64 Unix where -Wall is enabled, often with -Werror), this new parameter can become unused and may trigger an unused-parameter warning. Consider adding UNREFERENCED_PARAMETER(pMD); in the #else path and/or in the non-x86 path to keep all configurations warning-free.
static TADDR GetSpForDiagnosticReporting(REGDISPLAY *pRD, MethodDesc *pMD = NULL)
{
#ifdef ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP
TADDR sp = CallerStackFrame::FromRegDisplay(pRD).SP;
#if defined(TARGET_X86)
sp -= sizeof(TADDR);
// On x86, runtime async methods have stack parameters that cause CallerSP
// to sit above the parameter area. The DBI uses PCTAddr as the frame
// pointer, which is at the return address (below the parameters).
// Subtract an extra sizeof(TADDR) to account for the stack parameter.
if (pMD != NULL && pMD->IsAsyncMethod())
{
sp -= sizeof(TADDR);
}
#endif
return sp;
#else
return GetSP(pRD->pCurrentContext);
#endif

Comment threadsrc/coreclr/vm/exceptionhandling.cpp Outdated
@janvorli

Copy link
Copy Markdown
Member

@tommcdon I wonder - was this always a problem? I am asking since there was a change in the ifdef in this code in January (#122833) from

#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)
sp -= sizeof(TADDR); // For X86 with funclets we want the address 1 pointer into the callee.
#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)

I wonder if the ifdef really meant to be for Linux x86 only (which was previously the only one with defined(FEATURE_EH_FUNCLETS)) and was unrelated to the funclets per se.

tommcdonand others added 2 commits April 10, 2026 20:44
On x86, the runtime sends CallerSP - sizeof(TADDR) as the frame pointer for
exception notifications (see GetSpForDiagnosticReporting). Since this does not
account for the stack parameter size, the DBI's IsContainedInFrame now queries
the DAC for stackParamSize and adjusts the frame pointer before matching.
Also switches FindFrame to use TARGET_X86 instead of HOST_64BIT for the
ifdef guard, using exact FramePointer comparison on all non-x86 platforms.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdon

Copy link
Copy Markdown
MemberAuthor

@tommcdon I wonder - was this always a problem?

Yes I think you are correct. A previous fix for this was on #115630.

@tommcdon
tommcdon merged commit bd5a164 into dotnet:mainApr 15, 2026
100 of 111 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 16, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@tommcdon@janvorli@noahfalk@jakobbotsch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting - #126717

Merged
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification
Apr 15, 2026
Merged

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting#126717
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification

Conversation

@tommcdon

Copy link
Copy Markdown
Member

For certain runtime async frames this resulted in the ICorDebugManagedCallback2::Exception to return a null ICorDebugFrame for DEBUG_EXCEPTION_CATCH_HANDLER_FOUND notifications. The fix addresses this by adjusting GetSpForDiagnosticReporting to account for runtime async variant method stack layout differences on x86.

…orting
Adjust GetSpForDiagnosticReporting to correctly handle runtime async variant method stack layout on x86.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdontommcdon added this to the 11.0.0 milestone Apr 9, 2026
@tommcdontommcdon self-assigned this Apr 9, 2026
CopilotAI review requested due to automatic review settings April 9, 2026 16:18
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts the stack pointer reported to the debugger on x86 for runtime “async call” frames so that ICorDebugManagedCallback2::Exception callbacks (notably DEBUG_EXCEPTION_CATCH_HANDLER_FOUND) can resolve a non-null ICorDebugFrame.

Changes:

  • Extends GetSpForDiagnosticReporting to optionally accept a MethodDesc* and apply an extra x86 adjustment for runtime async methods (IsAsyncMethod()).
  • Updates exception/debugger callback sites to pass the current MethodDesc* into GetSpForDiagnosticReporting.
Comments suppressed due to low confidence (1)

src/coreclr/vm/exceptionhandling.cpp:2968

  • pMD is only referenced under ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP + TARGET_X86. In other builds (e.g., x64 Unix where -Wall is enabled, often with -Werror), this new parameter can become unused and may trigger an unused-parameter warning. Consider adding UNREFERENCED_PARAMETER(pMD); in the #else path and/or in the non-x86 path to keep all configurations warning-free.
static TADDR GetSpForDiagnosticReporting(REGDISPLAY *pRD, MethodDesc *pMD = NULL)
{
#ifdef ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP
TADDR sp = CallerStackFrame::FromRegDisplay(pRD).SP;
#if defined(TARGET_X86)
sp -= sizeof(TADDR);
// On x86, runtime async methods have stack parameters that cause CallerSP
// to sit above the parameter area. The DBI uses PCTAddr as the frame
// pointer, which is at the return address (below the parameters).
// Subtract an extra sizeof(TADDR) to account for the stack parameter.
if (pMD != NULL && pMD->IsAsyncMethod())
{
sp -= sizeof(TADDR);
}
#endif
return sp;
#else
return GetSP(pRD->pCurrentContext);
#endif

Comment threadsrc/coreclr/vm/exceptionhandling.cpp Outdated
@janvorli

Copy link
Copy Markdown
Member

@tommcdon I wonder - was this always a problem? I am asking since there was a change in the ifdef in this code in January (#122833) from

#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)
sp -= sizeof(TADDR); // For X86 with funclets we want the address 1 pointer into the callee.
#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)

I wonder if the ifdef really meant to be for Linux x86 only (which was previously the only one with defined(FEATURE_EH_FUNCLETS)) and was unrelated to the funclets per se.

tommcdonand others added 2 commits April 10, 2026 20:44
On x86, the runtime sends CallerSP - sizeof(TADDR) as the frame pointer for
exception notifications (see GetSpForDiagnosticReporting). Since this does not
account for the stack parameter size, the DBI's IsContainedInFrame now queries
the DAC for stackParamSize and adjusts the frame pointer before matching.
Also switches FindFrame to use TARGET_X86 instead of HOST_64BIT for the
ifdef guard, using exact FramePointer comparison on all non-x86 platforms.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdon

Copy link
Copy Markdown
MemberAuthor

@tommcdon I wonder - was this always a problem?

Yes I think you are correct. A previous fix for this was on #115630.

@tommcdon
tommcdon merged commit bd5a164 into dotnet:mainApr 15, 2026
100 of 111 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 16, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@tommcdon@janvorli@noahfalk@jakobbotsch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting - #126717

Merged
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification
Apr 15, 2026
Merged

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting#126717
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification

Conversation

@tommcdon

Copy link
Copy Markdown
Member

For certain runtime async frames this resulted in the ICorDebugManagedCallback2::Exception to return a null ICorDebugFrame for DEBUG_EXCEPTION_CATCH_HANDLER_FOUND notifications. The fix addresses this by adjusting GetSpForDiagnosticReporting to account for runtime async variant method stack layout differences on x86.

…orting
Adjust GetSpForDiagnosticReporting to correctly handle runtime async variant method stack layout on x86.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdontommcdon added this to the 11.0.0 milestone Apr 9, 2026
@tommcdontommcdon self-assigned this Apr 9, 2026
CopilotAI review requested due to automatic review settings April 9, 2026 16:18
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts the stack pointer reported to the debugger on x86 for runtime “async call” frames so that ICorDebugManagedCallback2::Exception callbacks (notably DEBUG_EXCEPTION_CATCH_HANDLER_FOUND) can resolve a non-null ICorDebugFrame.

Changes:

  • Extends GetSpForDiagnosticReporting to optionally accept a MethodDesc* and apply an extra x86 adjustment for runtime async methods (IsAsyncMethod()).
  • Updates exception/debugger callback sites to pass the current MethodDesc* into GetSpForDiagnosticReporting.
Comments suppressed due to low confidence (1)

src/coreclr/vm/exceptionhandling.cpp:2968

  • pMD is only referenced under ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP + TARGET_X86. In other builds (e.g., x64 Unix where -Wall is enabled, often with -Werror), this new parameter can become unused and may trigger an unused-parameter warning. Consider adding UNREFERENCED_PARAMETER(pMD); in the #else path and/or in the non-x86 path to keep all configurations warning-free.
static TADDR GetSpForDiagnosticReporting(REGDISPLAY *pRD, MethodDesc *pMD = NULL)
{
#ifdef ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP
TADDR sp = CallerStackFrame::FromRegDisplay(pRD).SP;
#if defined(TARGET_X86)
sp -= sizeof(TADDR);
// On x86, runtime async methods have stack parameters that cause CallerSP
// to sit above the parameter area. The DBI uses PCTAddr as the frame
// pointer, which is at the return address (below the parameters).
// Subtract an extra sizeof(TADDR) to account for the stack parameter.
if (pMD != NULL && pMD->IsAsyncMethod())
{
sp -= sizeof(TADDR);
}
#endif
return sp;
#else
return GetSP(pRD->pCurrentContext);
#endif

Comment threadsrc/coreclr/vm/exceptionhandling.cpp Outdated
@janvorli

Copy link
Copy Markdown
Member

@tommcdon I wonder - was this always a problem? I am asking since there was a change in the ifdef in this code in January (#122833) from

#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)
sp -= sizeof(TADDR); // For X86 with funclets we want the address 1 pointer into the callee.
#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)

I wonder if the ifdef really meant to be for Linux x86 only (which was previously the only one with defined(FEATURE_EH_FUNCLETS)) and was unrelated to the funclets per se.

tommcdonand others added 2 commits April 10, 2026 20:44
On x86, the runtime sends CallerSP - sizeof(TADDR) as the frame pointer for
exception notifications (see GetSpForDiagnosticReporting). Since this does not
account for the stack parameter size, the DBI's IsContainedInFrame now queries
the DAC for stackParamSize and adjusts the frame pointer before matching.
Also switches FindFrame to use TARGET_X86 instead of HOST_64BIT for the
ifdef guard, using exact FramePointer comparison on all non-x86 platforms.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdon

Copy link
Copy Markdown
MemberAuthor

@tommcdon I wonder - was this always a problem?

Yes I think you are correct. A previous fix for this was on #115630.

@tommcdon
tommcdon merged commit bd5a164 into dotnet:mainApr 15, 2026
100 of 111 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 16, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@tommcdon@janvorli@noahfalk@jakobbotsch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting - #126717

Merged
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification
Apr 15, 2026
Merged

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting#126717
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification

Conversation

@tommcdon

Copy link
Copy Markdown
Member

For certain runtime async frames this resulted in the ICorDebugManagedCallback2::Exception to return a null ICorDebugFrame for DEBUG_EXCEPTION_CATCH_HANDLER_FOUND notifications. The fix addresses this by adjusting GetSpForDiagnosticReporting to account for runtime async variant method stack layout differences on x86.

…orting
Adjust GetSpForDiagnosticReporting to correctly handle runtime async variant method stack layout on x86.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdontommcdon added this to the 11.0.0 milestone Apr 9, 2026
@tommcdontommcdon self-assigned this Apr 9, 2026
CopilotAI review requested due to automatic review settings April 9, 2026 16:18
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts the stack pointer reported to the debugger on x86 for runtime “async call” frames so that ICorDebugManagedCallback2::Exception callbacks (notably DEBUG_EXCEPTION_CATCH_HANDLER_FOUND) can resolve a non-null ICorDebugFrame.

Changes:

  • Extends GetSpForDiagnosticReporting to optionally accept a MethodDesc* and apply an extra x86 adjustment for runtime async methods (IsAsyncMethod()).
  • Updates exception/debugger callback sites to pass the current MethodDesc* into GetSpForDiagnosticReporting.
Comments suppressed due to low confidence (1)

src/coreclr/vm/exceptionhandling.cpp:2968

  • pMD is only referenced under ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP + TARGET_X86. In other builds (e.g., x64 Unix where -Wall is enabled, often with -Werror), this new parameter can become unused and may trigger an unused-parameter warning. Consider adding UNREFERENCED_PARAMETER(pMD); in the #else path and/or in the non-x86 path to keep all configurations warning-free.
static TADDR GetSpForDiagnosticReporting(REGDISPLAY *pRD, MethodDesc *pMD = NULL)
{
#ifdef ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP
TADDR sp = CallerStackFrame::FromRegDisplay(pRD).SP;
#if defined(TARGET_X86)
sp -= sizeof(TADDR);
// On x86, runtime async methods have stack parameters that cause CallerSP
// to sit above the parameter area. The DBI uses PCTAddr as the frame
// pointer, which is at the return address (below the parameters).
// Subtract an extra sizeof(TADDR) to account for the stack parameter.
if (pMD != NULL && pMD->IsAsyncMethod())
{
sp -= sizeof(TADDR);
}
#endif
return sp;
#else
return GetSP(pRD->pCurrentContext);
#endif

Comment threadsrc/coreclr/vm/exceptionhandling.cpp Outdated
@janvorli

Copy link
Copy Markdown
Member

@tommcdon I wonder - was this always a problem? I am asking since there was a change in the ifdef in this code in January (#122833) from

#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)
sp -= sizeof(TADDR); // For X86 with funclets we want the address 1 pointer into the callee.
#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)

I wonder if the ifdef really meant to be for Linux x86 only (which was previously the only one with defined(FEATURE_EH_FUNCLETS)) and was unrelated to the funclets per se.

tommcdonand others added 2 commits April 10, 2026 20:44
On x86, the runtime sends CallerSP - sizeof(TADDR) as the frame pointer for
exception notifications (see GetSpForDiagnosticReporting). Since this does not
account for the stack parameter size, the DBI's IsContainedInFrame now queries
the DAC for stackParamSize and adjusts the frame pointer before matching.
Also switches FindFrame to use TARGET_X86 instead of HOST_64BIT for the
ifdef guard, using exact FramePointer comparison on all non-x86 platforms.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdon

Copy link
Copy Markdown
MemberAuthor

@tommcdon I wonder - was this always a problem?

Yes I think you are correct. A previous fix for this was on #115630.

@tommcdon
tommcdon merged commit bd5a164 into dotnet:mainApr 15, 2026
100 of 111 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 16, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@tommcdon@janvorli@noahfalk@jakobbotsch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting - #126717

Merged
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification
Apr 15, 2026
Merged

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting#126717
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification

Conversation

@tommcdon

Copy link
Copy Markdown
Member

For certain runtime async frames this resulted in the ICorDebugManagedCallback2::Exception to return a null ICorDebugFrame for DEBUG_EXCEPTION_CATCH_HANDLER_FOUND notifications. The fix addresses this by adjusting GetSpForDiagnosticReporting to account for runtime async variant method stack layout differences on x86.

…orting
Adjust GetSpForDiagnosticReporting to correctly handle runtime async variant method stack layout on x86.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdontommcdon added this to the 11.0.0 milestone Apr 9, 2026
@tommcdontommcdon self-assigned this Apr 9, 2026
CopilotAI review requested due to automatic review settings April 9, 2026 16:18
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts the stack pointer reported to the debugger on x86 for runtime “async call” frames so that ICorDebugManagedCallback2::Exception callbacks (notably DEBUG_EXCEPTION_CATCH_HANDLER_FOUND) can resolve a non-null ICorDebugFrame.

Changes:

  • Extends GetSpForDiagnosticReporting to optionally accept a MethodDesc* and apply an extra x86 adjustment for runtime async methods (IsAsyncMethod()).
  • Updates exception/debugger callback sites to pass the current MethodDesc* into GetSpForDiagnosticReporting.
Comments suppressed due to low confidence (1)

src/coreclr/vm/exceptionhandling.cpp:2968

  • pMD is only referenced under ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP + TARGET_X86. In other builds (e.g., x64 Unix where -Wall is enabled, often with -Werror), this new parameter can become unused and may trigger an unused-parameter warning. Consider adding UNREFERENCED_PARAMETER(pMD); in the #else path and/or in the non-x86 path to keep all configurations warning-free.
static TADDR GetSpForDiagnosticReporting(REGDISPLAY *pRD, MethodDesc *pMD = NULL)
{
#ifdef ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP
TADDR sp = CallerStackFrame::FromRegDisplay(pRD).SP;
#if defined(TARGET_X86)
sp -= sizeof(TADDR);
// On x86, runtime async methods have stack parameters that cause CallerSP
// to sit above the parameter area. The DBI uses PCTAddr as the frame
// pointer, which is at the return address (below the parameters).
// Subtract an extra sizeof(TADDR) to account for the stack parameter.
if (pMD != NULL && pMD->IsAsyncMethod())
{
sp -= sizeof(TADDR);
}
#endif
return sp;
#else
return GetSP(pRD->pCurrentContext);
#endif

Comment threadsrc/coreclr/vm/exceptionhandling.cpp Outdated
@janvorli

Copy link
Copy Markdown
Member

@tommcdon I wonder - was this always a problem? I am asking since there was a change in the ifdef in this code in January (#122833) from

#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)
sp -= sizeof(TADDR); // For X86 with funclets we want the address 1 pointer into the callee.
#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)

I wonder if the ifdef really meant to be for Linux x86 only (which was previously the only one with defined(FEATURE_EH_FUNCLETS)) and was unrelated to the funclets per se.

tommcdonand others added 2 commits April 10, 2026 20:44
On x86, the runtime sends CallerSP - sizeof(TADDR) as the frame pointer for
exception notifications (see GetSpForDiagnosticReporting). Since this does not
account for the stack parameter size, the DBI's IsContainedInFrame now queries
the DAC for stackParamSize and adjusts the frame pointer before matching.
Also switches FindFrame to use TARGET_X86 instead of HOST_64BIT for the
ifdef guard, using exact FramePointer comparison on all non-x86 platforms.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdon

Copy link
Copy Markdown
MemberAuthor

@tommcdon I wonder - was this always a problem?

Yes I think you are correct. A previous fix for this was on #115630.

@tommcdon
tommcdon merged commit bd5a164 into dotnet:mainApr 15, 2026
100 of 111 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 16, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@tommcdon@janvorli@noahfalk@jakobbotsch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting - #126717

Merged
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification
Apr 15, 2026
Merged

Fix x86 runtime async frame pointer mismatch in GetSpForDiagnosticReporting#126717
tommcdon merged 3 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/fixx86debuggernotification

Conversation

@tommcdon

Copy link
Copy Markdown
Member

For certain runtime async frames this resulted in the ICorDebugManagedCallback2::Exception to return a null ICorDebugFrame for DEBUG_EXCEPTION_CATCH_HANDLER_FOUND notifications. The fix addresses this by adjusting GetSpForDiagnosticReporting to account for runtime async variant method stack layout differences on x86.

…orting
Adjust GetSpForDiagnosticReporting to correctly handle runtime async variant method stack layout on x86.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdontommcdon added this to the 11.0.0 milestone Apr 9, 2026
@tommcdontommcdon self-assigned this Apr 9, 2026
CopilotAI review requested due to automatic review settings April 9, 2026 16:18
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts the stack pointer reported to the debugger on x86 for runtime “async call” frames so that ICorDebugManagedCallback2::Exception callbacks (notably DEBUG_EXCEPTION_CATCH_HANDLER_FOUND) can resolve a non-null ICorDebugFrame.

Changes:

  • Extends GetSpForDiagnosticReporting to optionally accept a MethodDesc* and apply an extra x86 adjustment for runtime async methods (IsAsyncMethod()).
  • Updates exception/debugger callback sites to pass the current MethodDesc* into GetSpForDiagnosticReporting.
Comments suppressed due to low confidence (1)

src/coreclr/vm/exceptionhandling.cpp:2968

  • pMD is only referenced under ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP + TARGET_X86. In other builds (e.g., x64 Unix where -Wall is enabled, often with -Werror), this new parameter can become unused and may trigger an unused-parameter warning. Consider adding UNREFERENCED_PARAMETER(pMD); in the #else path and/or in the non-x86 path to keep all configurations warning-free.
static TADDR GetSpForDiagnosticReporting(REGDISPLAY *pRD, MethodDesc *pMD = NULL)
{
#ifdef ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP
TADDR sp = CallerStackFrame::FromRegDisplay(pRD).SP;
#if defined(TARGET_X86)
sp -= sizeof(TADDR);
// On x86, runtime async methods have stack parameters that cause CallerSP
// to sit above the parameter area. The DBI uses PCTAddr as the frame
// pointer, which is at the return address (below the parameters).
// Subtract an extra sizeof(TADDR) to account for the stack parameter.
if (pMD != NULL && pMD->IsAsyncMethod())
{
sp -= sizeof(TADDR);
}
#endif
return sp;
#else
return GetSP(pRD->pCurrentContext);
#endif

Comment threadsrc/coreclr/vm/exceptionhandling.cpp Outdated
@janvorli

Copy link
Copy Markdown
Member

@tommcdon I wonder - was this always a problem? I am asking since there was a change in the ifdef in this code in January (#122833) from

#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)
sp -= sizeof(TADDR); // For X86 with funclets we want the address 1 pointer into the callee.
#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86)

I wonder if the ifdef really meant to be for Linux x86 only (which was previously the only one with defined(FEATURE_EH_FUNCLETS)) and was unrelated to the funclets per se.

tommcdonand others added 2 commits April 10, 2026 20:44
On x86, the runtime sends CallerSP - sizeof(TADDR) as the frame pointer for
exception notifications (see GetSpForDiagnosticReporting). Since this does not
account for the stack parameter size, the DBI's IsContainedInFrame now queries
the DAC for stackParamSize and adjusts the frame pointer before matching.
Also switches FindFrame to use TARGET_X86 instead of HOST_64BIT for the
ifdef guard, using exact FramePointer comparison on all non-x86 platforms.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdon

Copy link
Copy Markdown
MemberAuthor

@tommcdon I wonder - was this always a problem?

Yes I think you are correct. A previous fix for this was on #115630.

@tommcdon
tommcdon merged commit bd5a164 into dotnet:mainApr 15, 2026
100 of 111 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 16, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@tommcdon@janvorli@noahfalk@jakobbotsch