Skip to content

Wasm: don't zero-pad the caller's return buffer in the interp-to-R2R thunk - #132257

Merged
AndyAyersMS merged 3 commits into
dotnet:mainfrom
AndyAyersMS:wasm-r2r-retbuf-overflow
Aug 13, 2026
Merged

Wasm: don't zero-pad the caller's return buffer in the interp-to-R2R thunk#132257
AndyAyersMS merged 3 commits into
dotnet:mainfrom
AndyAyersMS:wasm-r2r-retbuf-overflow

Conversation

@AndyAyersMS

Copy link
Copy Markdown
Member

WasmInterpreterToR2RThunkNode zero-padded pRet out to an aligned size after calling the R2R body. pRet is the interpreter's own return slot only when the interpreter made the call; it is the compiled caller's return buffer when we arrive via WasmR2RToInterpreterThunkNode, and CallDescrData::pRetBuffArg when we arrive via CallDescrWorkerInternal. In those cases the buffer is exactly as large as the struct, so the padding wrote past its end.

For a 12-byte struct that is four bytes into the next frame slot. In JsonDocument.Parse it zeroed the reference field of a live ReadOnlySpan and left its length intact, so the first Parse threw NullReferenceException from Utf8JsonReader.ReadSingleSegment.

Fixes #131640

…thunk

WasmInterpreterToR2RThunkNode zero-padded pRet out to an aligned size after
calling the R2R body. pRet is the interpreter's own return slot only when the
interpreter made the call; it is the compiled caller's return buffer when we
arrive via WasmR2RToInterpreterThunkNode, and CallDescrData::pRetBuffArg when
we arrive via CallDescrWorkerInternal. In those cases the buffer is exactly as
large as the struct, so the padding wrote past its end.

For a 12-byte struct that is four bytes into the next frame slot. In
JsonDocument.Parse it zeroed the reference field of a live ReadOnlySpan and
left its length intact, so the first Parse threw NullReferenceException from
Utf8JsonReader.ReadSingleSegment.

Fixes dotnet#131640

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings August 13, 2026 01:49
@AndyAyersMS

Copy link
Copy Markdown
Member Author

@davidwrighton PTAL
fyi @dotnet/wasm-contrib

@azure-pipelines

Copy link
Copy Markdown
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.

@jkotas jkotas added the arch-wasm WebAssembly architecture label Aug 13, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrighton davidwrighton left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Jan on the comment, but the rest of the fix looks correct to me.

…yAnalysis/ReadyToRun/WasmInterpreterToR2RThunkNode.cs
Copilot AI lite review requested due to automatic review settings August 13, 2026 18:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a WebAssembly ReadyToRun thunk correctness issue where the interpreter-to-R2R thunk could zero-pad a caller-owned struct return buffer past its actual size, corrupting adjacent stack data (observed as a spurious NullReferenceException in JsonDocument.Parse under wasm R2R).

Changes:

  • Remove post-call zero-padding of pRet in WasmInterpreterToR2RThunkNode for retbuf-based struct returns to avoid writing past the caller’s buffer.
  • Add a wasm R2R-focused JIT regression test that keeps byref-like values live across a struct-returning call, catching the historical overwrite pattern.
  • Add per-test project settings to force crossgen2 on the browser leg and run the test in process-isolated mode.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/WasmInterpreterToR2RThunkNode.cs Removes retbuf padding logic so the thunk never writes beyond the caller-provided return buffer.
src/tests/JIT/Regression/JitBlue/Runtime_131640/Runtime_131640.cs Adds a regression test that detects stack corruption from overrunning retbuf padding in wasm R2R thunking scenarios.
src/tests/JIT/Regression/JitBlue/Runtime_131640/Runtime_131640.csproj Forces crossgen2 on TargetOS=browser and uses process isolation so the repro runs under wasm R2R as intended.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 13, 2026 19:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/tests/JIT/Regression/JitBlue/Runtime_131640/Runtime_131640.csproj:8

  • The csproj comment claims AlwaysUseCrossGen2 “only takes effect through the project's own run script, which requires process isolation”, but other wasm R2R regression tests in the same directory rely on AlwaysUseCrossGen2 without RequiresProcessIsolation (e.g. Runtime_131285/Runtime_131373). This makes the comment misleading and RequiresProcessIsolation looks unnecessary here. Consider dropping RequiresProcessIsolation and simplifying the comment to match the established pattern so future readers don’t infer a harness constraint that doesn’t exist.
    <!-- The bug only reproduces when the caller is optimized R2R code, so force crossgen on
         the browser leg. AlwaysUseCrossGen2 only takes effect through the project's own run
         script, which requires process isolation. -->
    <AlwaysUseCrossGen2 Condition="'$(TargetOS)' == 'browser'">true</AlwaysUseCrossGen2>
    <RequiresProcessIsolation>true</RequiresProcessIsolation>

@AndyAyersMS

Copy link
Copy Markdown
Member Author

/ba-g build timeouts

@AndyAyersMS
AndyAyersMS merged commit f6e73fc into dotnet:main Aug 13, 2026
104 of 108 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-ReadyToRun

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[wasm] R2R: JsonDocument.Parse throws spurious NullReferenceException in Utf8JsonReader.ReadSingleSegment

4 participants