Add runtime async tests for catching non-Exception throws#130506
Conversation
|
Tagging subscribers to this area: @agocke |
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
| // * async1 lets the raw non-Exception escape the resumed state machine onto | ||
| // the thread pool where it becomes an unhandled exception and crashes the | ||
| // process, so it can never be observed by the caller. |
There was a problem hiding this comment.
async1 lets the raw non-Exception escape the resumed state machine onto
the thread pool where it becomes an unhandled exception and crashes the
process
async2 behavior makes more sense.
This is a corner case though. Not a lot of value in changing async1 behavior here.
There was a problem hiding this comment.
@copilot let's
- keep the async2 behavior expectations as-is,
- keep the comment on differences,
- keep the async 1 scenario blocked, but not on an issue since we are not going to fix, block on some short comment like "async1 behavior is terminal to the process, thus we will not test it".
There was a problem hiding this comment.
Done in 8fef2c4. Kept the async2 expectations and the difference comment as-is, and the async1 divergent case stays blocked — now via the comment "async1 behavior here is terminal to the process, thus we will not test it" instead of the [ActiveIssue] link.
Note
This comment was generated by GitHub Copilot.
There was a problem hiding this comment.
Correction: the change is in commit 362e9c2 (not 8fef2c4).
Note
This comment was generated by GitHub Copilot.
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Runtime async (async2) is meant to match compiler state-machine async (async1). No coverage existed for catching objects that don't derive from
System.Exception(only throwable via IL), whereRuntimeCompatibilityAttribute(WrapNonExceptionThrows)governs whether the object surfaces as aRuntimeWrappedException. These tests close that hole and pin down where the two forms agree and diverge.Description
New tests under
src/tests/async/runtime-wrapped-exception/:NonExceptionThrower.il— IL helper that throws a non-Exceptionobject (a string), since C# can't express this.NoWrapThrowers.cs— helper assembly marked[assembly: RuntimeCompatibility(WrapNonExceptionThrows = false)]with async1/async2 throwers. The attribute is assembly-scoped, so an opt-out variant requires its own assembly.runtime-wrapped-exception.cs— awaits each thrower (async1 via[RuntimeAsyncMethodGeneration(false)], async2 by default) and asserts the caller observes aRuntimeWrappedExceptionwrapping the thrown object, for throws both before and after a suspension point, under bothWrapNonExceptionThrowssettings.Observed behavior:
WrapNonExceptionThrows = true(C#/CoreLib default): async1 and async2 match — caller seesRuntimeWrappedExceptionin all cases.WrapNonExceptionThrows = false: they match for a synchronous (pre-yield) throw and for async2 after a yield. They diverge for a non-Exception thrown after a suspension point — async2 faults theTaskwith aRuntimeWrappedException, while async1 lets the raw object escape onto the thread pool and crash the process.The divergent (crashing) case,
CatchAfterYield_NoWrap_Async1, is disabled with[ActiveIssue("https://github.com/dotnet/runtime/issues/123194")], which unconditionally skips it and keeps it out of the merged runner so it can't abort the process. The remaining 7 tests run.