Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.NET 9: Unhandled exceptions in background threads reported with empty managed frames #101729

Closed
gregg-miskelly opened this issue Apr 30, 2024 · 3 comments
Assignees
Milestone

Comments

@gregg-miskelly
Copy link
Contributor

gregg-miskelly commented Apr 30, 2024

Description

In .NET 9 preview 3, there is a regression where the target process stops at a point where the ICorDebug stack walk interfaces report a single native chain with reason CHAIN_THREAD_START (0x00000040). Previously these exceptions would go unhandled with the managed code still on the stack.

Reproduction Steps

  1. dotnet new console
  2. Replace program.cs with the following code
  3. Run it under a managed debugger that is NOT configured to stop when NotImplementedException is thrown
  4. The debugger will stop when the exception goes unhandled

Program.cs:

Thread thread = new Thread(() => {
    throw new NotImplementedException(); // should crash here
});
thread.Start();
thread.Join();

Expected behavior

Call stack should have a managed frame

Actual behavior

No managed frames

Regression?

Definitely a regression from .NET 8. I believe it first appeared in preview 3.

Known Workarounds

None

Configuration

Problem appears on Windows, Mac and Linux

Other information

No response

@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Apr 30, 2024
Copy link
Contributor

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

@tommcdon
Copy link
Member

tommcdon commented May 6, 2024

Verified setting the DOTNET_LegacyExceptionHandling=1 environment variable reverts to correct behavior, so this seems to be caused by the new EH in .NET 9. Adding @janvorli

@janvorli janvorli self-assigned this May 6, 2024
@tommcdon tommcdon added this to the 9.0.0 milestone May 7, 2024
@tommcdon tommcdon removed the untriaged New issue has not been triaged by the area owner label May 7, 2024
janvorli added a commit to janvorli/runtime that referenced this issue May 20, 2024
The VS team has recently reported two issues with the new exception
handling in Visual Studio debugger.
The first issue was that an unhandled exception on a secondary managed
thread wasn't showing any stack trace when the exception occured and the
debugger has broken in.
The other issue was that when an exception occured during a funceval
invoked from the immediate window, the debugger would not highlight the
source line where the exception occured and it would not display a
dialog with the exception details.
Both problems were caused by the same underlying problem. In both cases,
the "catch handler found" notification was to be sent at a point when
the managed stack frames were already gone - in native code in catch / filter.
In the funceval case, there was even a check that prevented sending the
notification at all when there was no exception info present.

The fix is to move the notification to the point where the managed stack
frames are still present - when we detect in the EH code that there is
no managed frame left and either the DebuggerU2MCatchHandler frame or
FuncEvalFrame is the explicit frame we've encountered as the next one to
process. The FuncEvalFrame case is a bit more involved, as we always
push ProtectValueClassFrame after the FuncEvalFrame, so we need to skip
that one in the check. The debugger actually needs to get a pointer to
the FuncEvalFrame in the notification to do the right thing.

Close dotnet#102178 and dotnet#101729
janvorli added a commit to janvorli/runtime that referenced this issue May 20, 2024
The VS team has recently reported two issues with the new exception
handling in Visual Studio debugger.
The first issue was that an unhandled exception on a secondary managed
thread wasn't showing any stack trace when the exception occured and the
debugger has broken in.
The other issue was that when an exception occured during a funceval
invoked from the immediate window, the debugger would not highlight the
source line where the exception occured and it would not display a
dialog with the exception details.
Both problems were caused by the same underlying problem. In both cases,
the "catch handler found" notification was to be sent at a point when
the managed stack frames were already gone - in native code in catch / filter.
In the funceval case, there was even a check that prevented sending the
notification at all when there was no exception info present.

The fix is to move the notification to the point where the managed stack
frames are still present - when we detect in the EH code that there is
no managed frame left and either the DebuggerU2MCatchHandler frame or
FuncEvalFrame is the explicit frame we've encountered as the next one to
process. The FuncEvalFrame case is a bit more involved, as we always
push ProtectValueClassFrame after the FuncEvalFrame, so we need to skip
that one in the check. The debugger actually needs to get a pointer to
the FuncEvalFrame in the notification to do the right thing.

Close dotnet#102178 and dotnet#101729
janvorli added a commit that referenced this issue May 21, 2024
* Fix VS debugger issues with funceval and secondary threads

The VS team has recently reported two issues with the new exception
handling in Visual Studio debugger.
The first issue was that an unhandled exception on a secondary managed
thread wasn't showing any stack trace when the exception occured and the
debugger has broken in.
The other issue was that when an exception occured during a funceval
invoked from the immediate window, the debugger would not highlight the
source line where the exception occured and it would not display a
dialog with the exception details.
Both problems were caused by the same underlying problem. In both cases,
the "catch handler found" notification was to be sent at a point when
the managed stack frames were already gone - in native code in catch / filter.
In the funceval case, there was even a check that prevented sending the
notification at all when there was no exception info present.

The fix is to move the notification to the point where the managed stack
frames are still present - when we detect in the EH code that there is
no managed frame left and either the DebuggerU2MCatchHandler frame or
FuncEvalFrame is the explicit frame we've encountered as the next one to
process. The FuncEvalFrame case is a bit more involved, as we always
push ProtectValueClassFrame after the FuncEvalFrame, so we need to skip
that one in the check. The debugger actually needs to get a pointer to
the FuncEvalFrame in the notification to do the right thing.

Close #102178 and #101729

* Fix too strong assert

The ProtectValueClassFrame can also occur without FuncEvalFrame in the
reflection invocation.
@tommcdon
Copy link
Member

Closing via #102470

Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this issue May 30, 2024
…2470)

* Fix VS debugger issues with funceval and secondary threads

The VS team has recently reported two issues with the new exception
handling in Visual Studio debugger.
The first issue was that an unhandled exception on a secondary managed
thread wasn't showing any stack trace when the exception occured and the
debugger has broken in.
The other issue was that when an exception occured during a funceval
invoked from the immediate window, the debugger would not highlight the
source line where the exception occured and it would not display a
dialog with the exception details.
Both problems were caused by the same underlying problem. In both cases,
the "catch handler found" notification was to be sent at a point when
the managed stack frames were already gone - in native code in catch / filter.
In the funceval case, there was even a check that prevented sending the
notification at all when there was no exception info present.

The fix is to move the notification to the point where the managed stack
frames are still present - when we detect in the EH code that there is
no managed frame left and either the DebuggerU2MCatchHandler frame or
FuncEvalFrame is the explicit frame we've encountered as the next one to
process. The FuncEvalFrame case is a bit more involved, as we always
push ProtectValueClassFrame after the FuncEvalFrame, so we need to skip
that one in the check. The debugger actually needs to get a pointer to
the FuncEvalFrame in the notification to do the right thing.

Close dotnet#102178 and dotnet#101729

* Fix too strong assert

The ProtectValueClassFrame can also occur without FuncEvalFrame in the
reflection invocation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants