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>
Add Condition="'$(Language)' == 'C#'" to the RuntimeAsyncMethodGenerationAttribute.cs Compile Include in src/tests/async/Directory.Build.props so it is not injected into .ilproj projects. Remove the now-unnecessary <Compile Remove> workarounds from async-versions.ilproj and NonExceptionThrower.ilproj. Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
|
@copilot per suggestion from @MichalStrehovsky, please use #69919 for blocking the test on NativeAOT. (the issue already covers general scenarios with non-Exception throws on NativeAOT) |
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Updated in the latest commit — the NativeAOT blocking comment now references #69919. |
|
@copilot there is |
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Removed in the latest commit. |
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
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.