Skip to content

Add runtime async tests for catching non-Exception throws#131112

Merged
VSadov merged 2 commits into
copilot/runtime-async-tests-for-non-exceptionsfrom
copilot/add-runtime-async-tests
Jul 21, 2026
Merged

Add runtime async tests for catching non-Exception throws#131112
VSadov merged 2 commits into
copilot/runtime-async-tests-for-non-exceptionsfrom
copilot/add-runtime-async-tests

Conversation

Copilot AI commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

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), where RuntimeCompatibilityAttribute(WrapNonExceptionThrows) governs whether the object surfaces as a RuntimeWrappedException. 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-Exception object (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 a RuntimeWrappedException wrapping the thrown object, for throws both before and after a suspension point, under both WrapNonExceptionThrows settings.

Observed behavior:

  • WrapNonExceptionThrows = true (C#/CoreLib default): async1 and async2 match — caller sees RuntimeWrappedException in 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 the Task with a RuntimeWrappedException, while async1 lets the raw object escape onto the thread pool and crash the process.

The divergent (crashing) case, CatchAfterYield_NoWrap_Async1, is not exercised as a test: this reflects the older async1 behavior that is terminal to the process and is not something we plan to change, so it is left blocked with an explanatory comment rather than an [ActiveIssue] link. The remaining tests run.

On NativeAOT a non-Exception thrown after a suspension point is not surfaced as a RuntimeWrappedException and terminates the process instead of faulting the Task, so the test project is blocked on NativeAOT (DisableProjectBuild when TestBuildMode == nativeaot), pending the follow-up #131111.

// async1 (state machine) vs async2 (runtime async) — same body, different generation
public static async Task ThrowAfterYieldAsync2()
{
    await Task.Yield();
    NonExceptionThrower.ThrowNonException(); // throws a string (IL)
}

[RuntimeAsyncMethodGeneration(false)]
public static async Task ThrowAfterYieldAsync1()
{
    await Task.Yield();
    NonExceptionThrower.ThrowNonException();
}

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
16 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
@github-actions github-actions Bot added the area-ExceptionHandling-coreclr only use for closed issues label Jul 20, 2026
Copilot AI changed the title [WIP] Add runtime async tests for catching non-Exception throws Add runtime async tests for catching non-Exception throws Jul 20, 2026
Copilot AI requested a review from VSadov July 20, 2026 22:36
@VSadov
VSadov marked this pull request as ready for review July 21, 2026 19:25
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
15 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@VSadov
VSadov merged commit 457430a into copilot/runtime-async-tests-for-non-exceptions Jul 21, 2026
71 of 74 checks passed
@VSadov
VSadov deleted the copilot/add-runtime-async-tests branch July 21, 2026 19:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-ExceptionHandling-coreclr only use for closed issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants