You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When crossgen2 compiles managed methods to WebAssembly (wasm32) R2R, CodeGen::findTargetDepth can fail to locate a branch's target block in the active wasm control-flow stack. In that case it falls through to a checked-only assert and then return ~0;. Because the assert is compiled out of release/optimized crossgen2, the sentinel ~0 (0xFFFFFFFF) is emitted as the branch depth of a br / br_if / br_table instruction, producing an invalid wasm module. Validators reject it — V8 reports invalid branch depth: 4294967295.
codegenwasm.cpp:3969 — findTargetDepth(tgtBlock) + wasmExtraControlFlowDepth for an emitted br/br_if.
So a ~0 return does not merely misbehave in one spot — it is written into the module's branch encoding.
Observed on the exception-handling funclet System.Threading.Tasks.Parallel.Invoke (mangled Invoke_0, funclet 1) during a full framework wasm R2R crossgen. It is not SIMD-related (the funclet contains no 0xfd-prefixed opcodes).
This is a distinct root cause from the terminal-end drop fixed in #131251 (that fix addresses funclet end-emission; this is funclet branch-target resolution), but it is the same family of defect: an EH-funclet wasm-codegen gap guarded only by a checked-only assert, so in release the malformed wasm ships silently instead of failing the build.
Reproduction Steps
Build a wasm R2R crossgen2 (release) and a browser-wasm framework pack.
Crossgen a framework assembly (or composite) containing System.Threading.Tasks.Parallel for wasm:
wasm-tools validate out.wasm # or load it in V8 / a browser
The malformed function is the Parallel.Invoke EH funclet; V8 rejects the whole module with invalid branch depth: 4294967295.
Expected behavior
crossgen2 emits a valid wasm module: every emitted br / br_if / br_table carries a real, in-range control-stack depth for its target block. If a target genuinely cannot be resolved on the control-flow stack, crossgen2 should fail the compilation (or mark the method R2R-unsupported) rather than silently emit a ~0 branch depth into shipping wasm.
Actual behavior
findTargetDepth fails to find the target block on the wasm control-flow stack for certain EH-funclet shapes. In release the DEBUG assert is gone, so it returns ~0 and that value is encoded as the branch depth. The resulting module fails validation:
invalid branch depth: 4294967295
(V8; wasm-tools/other validators reject it equivalently.)
Regression?
Not a regression from a shipping release — wasm R2R (wasm32 crossgen2) is in-development. This is within the same wasm EH-funclet codegen area as #129335, #129449, and #131251.
Known Workarounds
None at the module level once emitted — unlike the terminal-end drop (#131251), the missing/incorrect data is a branch-target depth that cannot be repaired by appending a byte. Avoiding the affected funclet shape (e.g. excluding the offending method from R2R) sidesteps it.
Host: macOS/arm64; reproduced against a browser-wasm framework pack.
Not specific to SIMD codegen (the funclet has no SIMD opcodes).
Other information
Root cause locus (relative to main, subject to drift): CodeGen::findTargetDepth (src/coreclr/jit/codegenwasm.cpp:517); DEBUG assert assert(!"Can't find target in control stack") at :568; release fallback return ~0; at :570. Callers at :1120 (br_table) and :3969 (br/br_if). To locate it independent of line drift, search for the assert string Can't find target in control stack.
Suggested direction: either (a) resolve the target correctly for this funclet's control-flow shape so it is present on the stack when the branch is emitted, or (b) make the "target not found" case a hard compilation failure in all build flavors (not just checked) so malformed wasm can never ship.
Note
This issue was authored with the help of GitHub Copilot.
Description
When crossgen2 compiles managed methods to WebAssembly (wasm32) R2R,
CodeGen::findTargetDepthcan fail to locate a branch's target block in the active wasm control-flow stack. In that case it falls through to a checked-onlyassertand thenreturn ~0;. Because the assert is compiled out of release/optimized crossgen2, the sentinel~0(0xFFFFFFFF) is emitted as the branch depth of abr/br_if/br_tableinstruction, producing an invalid wasm module. Validators reject it — V8 reportsinvalid branch depth: 4294967295.Relevant source (
src/coreclr/jit/codegenwasm.cpp); line numbers are relative tomainand will drift:The two callers feed this depth straight into emitted branch instructions:
codegenwasm.cpp:1120—br_tablecase-target depth (BBJ_SWITCH).codegenwasm.cpp:3969—findTargetDepth(tgtBlock) + wasmExtraControlFlowDepthfor an emittedbr/br_if.So a
~0return does not merely misbehave in one spot — it is written into the module's branch encoding.Observed on the exception-handling funclet
System.Threading.Tasks.Parallel.Invoke(mangledInvoke_0, funclet 1) during a full framework wasm R2R crossgen. It is not SIMD-related (the funclet contains no0xfd-prefixed opcodes).This is a distinct root cause from the terminal-
enddrop fixed in #131251 (that fix addresses funclet end-emission; this is funclet branch-target resolution), but it is the same family of defect: an EH-funclet wasm-codegen gap guarded only by a checked-only assert, so in release the malformed wasm ships silently instead of failing the build.Reproduction Steps
browser-wasmframework pack.System.Threading.Tasks.Parallelfor wasm:The malformed function is the
Parallel.InvokeEH funclet; V8 rejects the whole module withinvalid branch depth: 4294967295.Expected behavior
crossgen2 emits a valid wasm module: every emitted
br/br_if/br_tablecarries a real, in-range control-stack depth for its target block. If a target genuinely cannot be resolved on the control-flow stack, crossgen2 should fail the compilation (or mark the method R2R-unsupported) rather than silently emit a~0branch depth into shipping wasm.Actual behavior
findTargetDepthfails to find the target block on the wasm control-flow stack for certain EH-funclet shapes. In release the DEBUGassertis gone, so it returns~0and that value is encoded as the branch depth. The resulting module fails validation:(V8;
wasm-tools/other validators reject it equivalently.)Regression?
Not a regression from a shipping release — wasm R2R (wasm32 crossgen2) is in-development. This is within the same wasm EH-funclet codegen area as #129335, #129449, and #131251.
Known Workarounds
None at the module level once emitted — unlike the terminal-
enddrop (#131251), the missing/incorrect data is a branch-target depth that cannot be repaired by appending a byte. Avoiding the affected funclet shape (e.g. excluding the offending method from R2R) sidesteps it.Configuration
main), CoreCLR wasm R2R (crossgen2), targetwasm32/--targetos:browser.browser-wasmframework pack.Other information
main, subject to drift):CodeGen::findTargetDepth(src/coreclr/jit/codegenwasm.cpp:517); DEBUG assertassert(!"Can't find target in control stack")at:568; release fallbackreturn ~0;at:570. Callers at:1120(br_table) and:3969(br/br_if). To locate it independent of line drift, search for the assert stringCan't find target in control stack.endfor EH funclets ending in a no-return call #131251 (sibling wasm EH-funclet defect — terminalenddropped; different root cause, fixed separately), Wasm / R2R: malformed wasm (missing function-body end opcode) for try / throwing-finally pattern in b51875 #129335 and Wasm R2R: emit trailing end after retless BBJ_CALLFINALLY #129449 (prior wasm EH-funclet codegen work in the same area).Note
This issue was authored with the help of GitHub Copilot.