Repository navigation
Description
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.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
dotnet-policy-service commentedon Sep 10, 2026
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.
AndyAyersMS commentedon Sep 11, 2026
Root cause identified with high confidence from the thunk and
ArgIteratorlayouts: the wasm R2R transition swaps the generic-context and async-continuation slots for signatures containing both, including the failingiiaS8psignature.AsyncHelpers.AwaitAwaiter<TAwaiter>(TAwaiter)is[BypassReadyToRun], so the R2R-compiled marker calls its interpreted implementation. ForTaskAwaiter<Task>, the argument-area layouts are:0816WasmLowering.RaiseSignaturerepresents the encoded generic context as a synthetic explicitInt32parameter.WasmR2RToInterpreterThunkNodethen callsGCRefMapBuilder.BuildArgIteratorwithmethodIsAsyncCall: true, but notmethodRequiresInstArg: true.ArgIteratorconsequently allocates the continuation as the first hidden slot and the synthetic explicit parameter as the next slot. The thunk'sHasGenericContextBeforeAsynchandling 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 observedmemory access out of boundstrap.The same layout pattern is present in:
WasmR2RToInterpreterThunkNode.csWasmImportThunk.csWasmInterpreterToR2RThunkNode.csThe likely fix is to model the generic context as a hidden
ArgIteratorargument usingmethodRequiresInstArg: true, store/load it throughGetParamTypeArgOffset(), and handle the continuation independently throughGetAsyncContinuationArgOffset(), rather than treating the generic context as an explicit raised-signature parameter.This was verified statically against the managed
ArgIteratorimplementation 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.
AndyAyersMS commentedon Sep 11, 2026
@davidwrighton FYI
Happy to try and fix if you like.
dotnet-policy-service commentedon Sep 11, 2026
Tagging subscribers to this area: @dotnet/crossgen-contrib
See info in area-owners.md if you want to be subscribed.
davidwrighton commentedon Sep 12, 2026
@AndyAyersMS sure. Seems like a good idea.
dotnet-policy-service commentedon Sep 13, 2026
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.
Retain the known WebAssembly WhenAny quarantine
Retain the known WebAssembly WhenAny quarantine
[wasm][R2R] Fix generic context / async continuation order in Wasm in…