Skip to content

JIT: don't fall through from a Wasm callfinally across a try_table end - #134758

Merged
lewing merged 4 commits into
mainfrom
lewing-fix-wasm-r2r-websocket-close-trap
Sep 29, 2026
Merged

lewing merged 4 commits into
mainfrom
lewing-fix-wasm-r2r-websocket-close-trap

Conversation

@lewing

@lewing lewing commented Sep 27, 2026

Copy link
Copy Markdown
Member

On Wasm, genCallFinally omitted the branch to the callfinally continuation whenever it was the lexically next block. When a try_table interval ends between the BBJ_CALLFINALLYRET and its continuation, codegen emits a validation unreachable after the try_table end, so the fall-through traps at runtime with RuntimeError: unreachable.

This hit ManagedWebSocket.<WaitForServerToCloseConnectionAsync>d__64.MoveNext under browser-wasm R2R. Disassembly showed the normal path calling the finally funclet and then falling into the try_table end, while other paths to the same continuation used call finally; br N.

Changes

  • genCallFinally now uses BasicBlock::CanRemoveJumpToTarget, which already refuses fall-through across a Try/ExnRefWrapper end for BBJ_ALWAYS and BBJ_COND (JIT: fix wasm conditional fallthrough #133528). Its assert is widened to accept BBJ_CALLFINALLYRET.
  • A DEBUG check in fgWasmControlFlow asserts that every adjacent forward edge that cannot fall through because a Try/ExnRefWrapper ends at its target has an enclosing Block interval, so the explicit branch has a label.
  • New regression test JIT/Regression_2/Runtime_134264. The bug needs an async method ending in a user try/catch/finally whose finally is too large to be cloned; a nested try/finally-in-try/catch variant is included.
  • Re-enable WebSocketReceiveErrorMessageTests on Wasm R2R.

Validation

  • System.Net.WebSockets.Tests, browser-wasm CoreCLR, trimmed R2R on Chrome: before the fix, reproduces the trap; after, 278 run, 0 failed, including the 4 re-enabled tests.
  • Runtime_134264 via src/tests/run.sh wasm --runcrossgen2tests (browser): passes with the fix; with the pre-fix JIT it traps with RuntimeError: unreachable in TryCatchFinallyAsync_d__2.MoveNext.
  • Checked cross-targeting Wasm JIT: crossgen2 of System.Private.CoreLib and 14 framework assemblies with no asserts. Temporarily disabling block creation for try/catch exits makes the new check fire on both test methods.
  • jitformat.py clean.

JIT/Regression_2 is not yet in the curated WASI runtime-test trees; #133265 adds the WASI R2R lane and should include -tree:JIT/Regression_2 to cover this test there.

Resolves #134264

Note

This PR description was generated with GitHub Copilot.

lewing and others added 3 commits September 27, 2026 17:11
genCallFinally omitted the branch to the continuation whenever it was the
lexically next block. On Wasm, closing a Try interval between the
BBJ_CALLFINALLYRET and its continuation emits a validation 'unreachable'
after the try_table 'end', so the fall-through trapped at runtime. Use
CanRemoveJumpToTarget, which already handles this for BBJ_ALWAYS/BBJ_COND.

Re-enable WebSocketReceiveErrorMessageTests on Wasm R2R.

Fixes #134264

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add a JIT regression test for the Wasm callfinally fall-through trap: an
async method ending in a user try/catch/finally whose finally is too large
to clone, plus a nested try/finally-in-try/catch variant.

Add a DEBUG check in fgWasmControlFlow that every adjacent forward edge
that cannot fall through because a Try/ExnRefWrapper ends at its target
has an enclosing Block interval to branch to.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Sep 27, 2026
@lewing
lewing requested a review from AndyAyersMS September 27, 2026 22:54
@azure-pipelines

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

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@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.

@lewing

lewing commented Sep 29, 2026

Copy link
Copy Markdown
Member Author

cc @dotnet/wasm-contrib

@lewing
lewing requested a review from janvorli September 29, 2026 18:41
Comment thread src/coreclr/jit/fgwasm.cpp
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@lewing
lewing enabled auto-merge (squash) September 29, 2026 22:39
@lewing
lewing merged commit 58f7fbc into main Sep 29, 2026
164 of 167 checks passed
@lewing
lewing deleted the lewing-fix-wasm-r2r-websocket-close-trap branch September 29, 2026 23:29
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 12.0-preview1 milestone Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[browser][CoreCLR][R2R] ManagedWebSocket async close path traps with unreachable

2 participants