Skip to content

[browser][CoreCLR][R2R] RuntimeAsync_WhenAny_TracksAllBranches traps in an R2R-to-interpreter transition #133627

Closed

Description

@lewing

Description

Completing the browser CoreCLR R2R Tasks test investigation exposed a separate execution trap in AsyncProfilerTests.RuntimeAsync_WhenAny_TracksAllBranches. It reproduces both in a group and in isolation with aggressive trimming enabled and only TestUtilities.dll excluded from R2R. The same test passes with R2R disabled.

This is tracked separately from the missing profiler identities (#133626) and the resumed managed exception escape (#133625): the observed failure is a Wasm memory-access trap during an R2R-to-interpreter transition, not an assertion or InvalidOperationException.

Reproduction Steps

Using the browser CoreCLR library-test pipeline with Release runtime/host/packs and host crossgen2 built:

XHARNESS_COMMAND=test-browser ./dotnet.sh build /t:Test \
  src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/System.Threading.Tasks.Tests.csproj \
  /p:TargetOS=browser /p:TargetArchitecture=wasm /p:RuntimeFlavor=CoreCLR \
  /p:Configuration=Release /p:EnableAggressiveTrimming=true /p:PublishReadyToRun=true \
  /p:Scenario=WasmTestOnChrome /p:InstallChromeForTests=true /p:XunitShowProgress=true \
  /p:WasmXHarnessTestsTimeout=00:03:00 \
  /p:WasmTestAppArgs="-method System.Threading.Tasks.Tests.AsyncProfilerTests.RuntimeAsync_WhenAny_TracksAllBranches"

The pipeline sets TEST_READY_TO_RUN_MODE=1 and PublishReadyToRunExclude=TestUtilities.dll; the runtime libraries and Tasks assembly stay R2R. Remove only this method's temporary ActiveIssue annotation once applied. For the interpreter control, set PublishReadyToRun=false without changing aggressive trimming, forcing Tasks-only relinking to avoid stale incremental assets.

The runtime-async marker starts three runtime-async tasks (one yielding, two using Task.Delay), awaits Task.WhenAny(fast, slow1, slow2), then awaits Task.WhenAll(slow1, slow2).

Expected behavior

The method should complete without a Wasm trap. Any subsequent profiler-identity assertions are separately covered by #133626.

Actual behavior

The isolated ON run discovers and starts one case, then exits without final XML/results:

[STRT] System.Threading.Tasks.Tests.AsyncProfilerTests.RuntimeAsync_WhenAny_TracksAllBranches
DOTNET: Unhandled error: memory access out of bounds
RuntimeError: memory access out of bounds
    at InterpExecMethod(InterpreterFrame*, InterpMethodContextFrame*, InterpThreadContext*, ExceptionClauseArgs*)
    at ExecuteInterpretedMethod
    at ExecuteInterpretedMethodWithArgs_PortableEntryPoint(...)
    at WasmR2RToInterpreterThunk(iiaS8p)
    at WasmDelayLoadHelper->EagerImports->SignaturePointer_ReadyToRunHelper_DelayLoad_MethodCall(...Sig:iiaS8p)
    at ...RuntimeAsync_WhenAny_TracksAllBranches_Marker
    at WasmInterpreterToR2RThunk(vap)
WASM EXIT 1

The grouped run has the same trap at the same test. OFF baseline XML contains one passing result for this exact method. Both ON probes were bounded to three minutes and terminated promptly; this was not a timeout.

Regression?

Unknown. It is R2R-dependent in the controlled comparison; no earlier release or candidate runtime fix was tested.

Known Workarounds

PublishReadyToRun=false. A method-level ActiveIssue conditioned on PlatformDetection.IsBrowserReadyToRun can quarantine this case without disabling other tests or interpreter coverage.

Configuration

macOS arm64 host, single-threaded Chromium 153.0.8010.12, browser-wasm CoreCLR Release development runtime. Tests target net11.0; runtime startup banner reports 12.0.0. Full aggressive trimming remains enabled in both configurations. Reproduced after the #133615 CoreLib/packs rebuild and with TestUtilities interpreted.

Other information

The precise ABI/transition defect is unproven. The stack identifies the transition and marker, not which argument or frame is malformed. No runtime source changes or speculative prerequisite merges were made. This case was previously masked by earlier AsyncProfiler process aborts.

Note

This issue was generated by GitHub Copilot from locally reproduced test results.

Activity

  1. added
    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
    on Sep 10, 2026
  2. dotnet-policy-service commented on Sep 10, 2026

    @dotnet-policy-service
    Contributor

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

  3. AndyAyersMS commented on Sep 11, 2026

    @AndyAyersMS
    Member

    Root cause identified with high confidence from the thunk and ArgIterator layouts: the wasm R2R transition swaps the generic-context and async-continuation slots for signatures containing both, including the failing iiaS8p signature.

    AsyncHelpers.AwaitAwaiter<TAwaiter>(TAwaiter) is [BypassReadyToRun], so the R2R-compiled marker calls its interpreted implementation. For TaskAwaiter<Task>, the argument-area layouts are:

    Offset Interpreter expects Thunk currently writes
    0 generic context async continuation
    8 async continuation generic context
    16 8-byte awaiter 8-byte awaiter

    WasmLowering.RaiseSignature represents the encoded generic context as a synthetic explicit Int32 parameter. WasmR2RToInterpreterThunkNode then calls GCRefMapBuilder.BuildArgIterator with methodIsAsyncCall: true, but not methodRequiresInstArg: true. ArgIterator consequently allocates the continuation as the first hidden slot and the synthetic explicit parameter as the next slot. The thunk's HasGenericContextBeforeAsync handling adjusts the incoming wasm-local order, but it does not correct the calculated frame offsets.

    The interpreted AwaitAwaiter<TAwaiter> therefore receives the continuation object as its generic dictionary/method context. Generic awaiter operations then dereference this invalid context, leading to the observed memory access out of bounds trap.

    The same layout pattern is present in:

    • WasmR2RToInterpreterThunkNode.cs
    • WasmImportThunk.cs
    • WasmInterpreterToR2RThunkNode.cs

    The likely fix is to model the generic context as a hidden ArgIterator argument using methodRequiresInstArg: true, store/load it through GetParamTypeArgOffset(), and handle the continuation independently through GetAsyncContinuationArgOffset(), rather than treating the generic context as an explicit raised-signature parameter.

    This was verified statically against the managed ArgIterator implementation and the runtime signature encoder. I have not yet rerun the full browser-wasm reproduction with a fix.

    Note

    This analysis was generated with GitHub Copilot.

  4. added and removed
    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
    on Sep 11, 2026
  5. removed
    untriagedNew issue has not been triaged by the area owner
    on Sep 11, 2026
  6. AndyAyersMS commented on Sep 11, 2026

    @AndyAyersMS
    Member

    @davidwrighton FYI

    Happy to try and fix if you like.

  7. dotnet-policy-service commented on Sep 11, 2026

    @dotnet-policy-service
    Contributor

    Tagging subscribers to this area: @dotnet/crossgen-contrib
    See info in area-owners.md if you want to be subscribed.

  8. davidwrighton commented on Sep 12, 2026

    @davidwrighton
    Member

    @AndyAyersMS sure. Seems like a good idea.

  9. dotnet-policy-service commented on Sep 13, 2026

    @dotnet-policy-service
    Contributor

    Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
    See info in area-owners.md if you want to be subscribed.

  10. added
    disabled-testThe test is disabled in source code against the issue
    on Sep 17, 2026
  11. self-assigned this
    on Sep 28, 2026
  12. locked and limited conversation to collaborators on Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

arch-wasmWebAssembly architecturearea-ReadyToRundisabled-testThe test is disabled in source code against the issue

Type

No type

Projects

  • Status
    No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions