Skip to content

Conversation

@janvorli
Copy link
Member

A recent fix that has moved 2nd pass of the exception handling to native
code has accidentally broken detectin of collided unwind, that means
detection of when exception escapes a catch or exceptionally called finally
funclets. Unfortunately none of our coreclr and libraries test exercise
the specific case when the problem occurs, which is as follows:

  • There is a try / catch inside of an outer catch
  • The try block contains try / finally and the non-exceptionally called
    finally throws.
    In this case, the stack walk out of the throwing finally funclet was
    incorrectly classifed as an exception collision and the catch was
    skipped.

The problem was that the last part of the condition to detect the collided
unwind was wrong. In fact, it was always true, so any unwind out of a
funclet was considered to be a collision even if the funclet was a
finally that was called non-exceptionally.

This change fixes it by identifying the collision by the fact that the
stack walker has moved from a funclet to native code, which is the only
case when the exception is really escaping an exceptionally called
funclet.

I have also added a regression test for the issue.

Close #121578

A recent fix that has moved 2nd pass of the exception handling to native
code has accidentally broken detectin of collided unwind, that means
detection of when exception escapes a catch or exceptionally called finally
funclets. Unfortunately none of our coreclr and libraries test exercise
the specific case when the problem occurs, which is as follows:
* There is a try / catch inside of an outer catch
* The try block contains try / finally and the non-exceptionally called
  finally throws.
In this case, the stack walk out of the throwing finally funclet was
incorrectly classifed as an exception collision and the catch was
skipped.

The problem was that the last part of the condition to detect the collided
unwind was wrong. In fact, it was always true, so any unwind out of a
funclet was considered to be a collision even if the funclet was a
finally that was called non-exceptionally.

This change fixes it by identifying the collision by the fact that the
stack walker has moved from a funclet to native code, which is the only
case when the exception is really escaping an exceptionally called
funclet.

I have also added a regression test for the issue.

Close dotnet#121578
@janvorli janvorli added this to the 10.0.x milestone Nov 14, 2025
@janvorli janvorli requested a review from jkotas November 14, 2025 13:02
@janvorli janvorli self-assigned this Nov 14, 2025
Copilot AI review requested due to automatic review settings November 14, 2025 13:02
Copilot finished reviewing on behalf of janvorli November 14, 2025 13:03
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes a bug in collided unwind detection during exception handling. A collided unwind occurs when an exception escapes from a catch or exceptionally-called finally funclet. The bug caused incorrect behavior when a non-exceptionally called finally throws an exception inside an outer catch block - the runtime incorrectly classified this as a collision and skipped the catch clause.

Key Changes:

  • Modified the collided unwind detection condition in exceptionhandling.cpp to correctly identify collisions only when transitioning from a funclet to native code
  • Added regression test test121578.cs that exercises the specific scenario: try/catch with nested try/finally where the non-exceptionally called finally throws

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/coreclr/vm/exceptionhandling.cpp Changed collided unwind detection condition to check frame state instead of stack pointer comparison
src/tests/Regressions/coreclr/GitHub_121578/test121578.csproj Project file for new regression test
src/tests/Regressions/coreclr/GitHub_121578/test121578.cs Regression test that reproduces the bug scenario

@janvorli
Copy link
Member Author

/backport to release/10.0

@github-actions
Copy link
Contributor

Started backporting to release/10.0 (link to workflow run)

@janvorli
Copy link
Member Author

/azp run runtime-coreclr outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@janvorli
Copy link
Member Author

/ba-g the failing outerloop tests are unrelated to the change - those are SVE numeric omputations failures - #121659

@janvorli janvorli merged commit 776e86a into dotnet:main Nov 15, 2025
145 of 156 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

.NET 10 changes the way nested try-finally are handled

2 participants