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
but nothing validates that the modeled type matches the helper's real signature. On register machines a "model a value-returning helper as void because the result is unused" shortcut is harmless, so these shortcuts are scattered through the JIT (importer.cpp, morph.cpp, objectalloc.cpp, ...) and are individually invisible until wasm traps at runtime — typically deep in a cold path, with a bare function signature mismatch and no attribution to the JIT site that caused it.
There is also no central table of helper return types in the JIT. HelperCallProperties (src/coreclr/jit/utils.cpp) tracks purity, allocation, no-GC, throw behavior — but not return arity. jithelpers.h knows the backing METHOD__* for DYNAMICJITHELPER entries, and corelib.h knows their signatures, but the JIT never cross-checks.
Proposal
Add a debug-only verification so these mismatches fail at JIT time with a clear message rather than as a wasm engine trap:
In a Checked/Debug wasm JIT, when building the call signature in genCallInstruction (or earlier, in gtNewHelperCallNode and after any gtCallMethHnd retarget), resolve the helper's real signature via eeGetMethodSig(eeFindHelper(helper)) and assert that the modeled return arity (void vs. non-void) matches.
Emit the helper name and the two conflicting types in the assert message so the failing site is immediately identifiable.
Optionally, a static table of expected return types per CorInfoHelpFunc (analogous to HelperCallProperties) would let this be checked on all targets and would make the intent explicit at each call site.
Given there is currently no wasm-R2R CI leg, an assert like this is the cheapest way to stop this class of bug from being found one production trap at a time.
Description
We have now hit the same bug three times, each found only by a runtime trap in a browser/WASI R2R run:
CORINFO_HELP_INITCLASS/CORINFO_HELP_INITINSTCLASSmodeledTYP_VOIDwhile the managed helpers returnvoid*.fa248fe58e8— the inline-unboxslow-pathCORINFO_HELP_UNBOXmodeledTYP_VOIDwhileCastHelpers.Unboxreturnsref byte.objectallocretargetingUNBOX→UNBOX_TYPETESTwithout retyping, andCORINFO_HELP_CHECK_OBJmodeledTYP_VOIDwhileJIT_CheckObjreturnsObject*.The root cause is structural. On wasm,
CodeGen::genCallInstructionderives the emittedcall_indirect/ call signature from the JIT-modeled node type:but nothing validates that the modeled type matches the helper's real signature. On register machines a "model a value-returning helper as void because the result is unused" shortcut is harmless, so these shortcuts are scattered through the JIT (
importer.cpp,morph.cpp,objectalloc.cpp, ...) and are individually invisible until wasm traps at runtime — typically deep in a cold path, with a barefunction signature mismatchand no attribution to the JIT site that caused it.There is also no central table of helper return types in the JIT.
HelperCallProperties(src/coreclr/jit/utils.cpp) tracks purity, allocation, no-GC, throw behavior — but not return arity.jithelpers.hknows the backingMETHOD__*forDYNAMICJITHELPERentries, andcorelib.hknows their signatures, but the JIT never cross-checks.Proposal
Add a debug-only verification so these mismatches fail at JIT time with a clear message rather than as a wasm engine trap:
genCallInstruction(or earlier, ingtNewHelperCallNodeand after anygtCallMethHndretarget), resolve the helper's real signature viaeeGetMethodSig(eeFindHelper(helper))and assert that the modeled return arity (void vs. non-void) matches.Optionally, a static table of expected return types per
CorInfoHelpFunc(analogous toHelperCallProperties) would let this be checked on all targets and would make the intent explicit at each call site.Given there is currently no wasm-R2R CI leg, an assert like this is the cheapest way to stop this class of bug from being found one production trap at a time.
Related: #129622, #130634, #130813, #131377, #131378
Note
This issue was created with assistance from GitHub Copilot (AI).