Repository navigation
[wasm/R2R] TypeIntrinsics_r/_ro: GC reports uninitialized frame slots during throw-helper calls (pMT->Validate assert) #135966
Description
Build Information
Build: https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1637640
Build error leg or test failing: R2R-CG2 browser wasm Checked - JIT_r.WorkItemExecution (JIT/Intrinsics/TypeIntrinsics_r)
Pull request: #135899
Error Details
Running test: JIT/Intrinsics/TypeIntrinsics_r/TypeIntrinsics_r.dll
ASSERT FAILED
Expression: !CREATE_CHECK_STRING(pMT && pMT->Validate())
Location: /__w/1/s/src/coreclr/vm/object.cpp:509
Function: ValidateInner
Frame (InlinedCallFrame): 0x4fe6b4
Frame (SoftwareExceptionFrame): 0x4feb08
Frame (PrestubMethodFrame): 0x4fed48
Frame (PrestubMethodFrame): 0x4ff238
ASSERT FAILED
Expression: IsExecutingOnAltStack() || (curSP <= m_pFrame && m_pFrame < m_CacheStackBase) || m_pFrame == (Frame*) -1
Location: /__w/1/s/src/coreclr/vm/threads.h:1179
Function: GetFrame
(repeated 3x)
Aborted(native code called abort())
RuntimeError: unreachable
Both runs of this lane for #135899 (Helix jobs c34772cf-9b4e-4ed1-bf2a-3762ec6112ec and 49de35bc-09c7-4794-ad81-140e84941c6e) failed this way.
Investigation
This is a pre-existing wasm JIT bug, not caused by #135899. Fix: #135970. It reproduces on code without that PR under DOTNET_GCStress=1.
Repro (Linux x64, Node 23.11.1, CI's Helix correlation and work-item payloads, Checked browser-wasm runtime):
node --experimental-wasm-exnref --stack-size=8192 $CORE_ROOT/corerun.js -c $CORE_ROOT \
-p System.Reflection.Metadata.MetadataUpdater.IsSupported=false \
-p System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization=true <workitem>/JIT/JIT_r/JIT_r.dll
| Configuration | Result |
|---|---|
| #135899 payload, no stress | crashes 20/20 with fixed paths/env (1/3 through JIT_r.sh); passes on macOS |
| Same, CoreLib recompiled without #135899 | 0/10 |
Same, CoreLib recompiled without #135899, DOTNET_GCStress=1 |
same pMT->Validate() assert |
Unrelated PR #135962's payload (no #135899 code), DOTNET_GCStress=1 |
same assert |
Without stress the crash depends on GC timing. Paths, environment size and logging all change whether it fires. #135899 removes box allocations from CoreLib, which moves the first GC onto the bad window.
Root cause (see #135970): on wasm, optRemoveRedundantZeroInits skipped prolog zeroing for GC locals stored after a throwing tree, because IsPotentialGCSafePoint didn't treat GTF_EXCEPT trees as safe points. Wasm has no hardware exceptions, so a null or bounds check is a call to a throw helper, during which a GC can run. Wasm frames report GC locals as untracked slots, so that GC reports whatever an earlier call left in them. Here, Object.GetType's null check on this calls ThrowNullReferenceException before its temps (sp+0x10..0x18) are stored, and the leftover value fails pMT->Validate().
An earlier version of this issue blamed a stale DynamicHelperFrame. That frame is live: it belongs to the delay-load call made from ThrowNullReferenceException.
Related, but different signatures:
- [wasm] Report untracked GC slots for aborted Wasm R2R frames #134769: a GC hole for untracked slots in aborted wasm R2R frames during dispatch. Merged before this build.
- [wasm/R2R] JitTest_Directed fails with GC hole assert #135313: a wasi R2R
Directed_dGC-hole assert viaResolveVirtualFunctionPointer.
Error Message
{
"ErrorMessage": "",
"ErrorPattern": [
"Running test: JIT/Intrinsics/TypeIntrinsics_ro?/TypeIntrinsics_ro?\\.dll",
"Expression: !CREATE_CHECK_STRING\\(pMT && pMT->Validate\\(\\)\\)"
],
"BuildRetry": false,
"ExcludeConsoleLog": false
}Verified against the Helix console logs: each element matches once (the GetFrame assert 3 times) in both failing JIT_r logs. A passing JIT_r log from the same lane (PR #135962) contains only the first line.
Note
This issue was drafted with GitHub Copilot.
Known issue validation
Build: 🔎 https://dev.azure.com/dnceng-public/public/_build/results?buildId=1637640
Error message validated: [Running test: JIT/Intrinsics/TypeIntrinsics_r/TypeIntrinsics_r.dll Expression: !CREATE_CHECK_STRING(pMT && pMT->Validate()) Expression: IsExecutingOnAltStack() || (curSP <= m_pFrame && m_pFrame < m_CacheStackBase) || m_pFrame == (Frame*) -1]
Result validation: ✅ Known issue matched with the provided build.
Validation performed at: 10/16/2026 6:07:11 PM UTC
Metadata
Metadata
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
dotnet-policy-service commentedon Oct 16, 2026
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.
dotnet-policy-service commentedon Oct 16, 2026
Tagging subscribers to this area: @agocke
See info in area-owners.md if you want to be subscribed.
[-][wasm/R2R] TypeIntrinsics_r: stale DynamicHelperFrame after caught NullReferenceException (pMT->Validate assert)[/-][+][wasm/R2R] TypeIntrinsics_r: GC reports uninitialized frame slots during throw-helper calls (pMT->Validate assert)[/+]lewing commentedon Oct 16, 2026
It turns our this is an xplat problem #135970
[-][wasm/R2R] TypeIntrinsics_r: GC reports uninitialized frame slots during throw-helper calls (pMT->Validate assert)[/-][+][wasm/R2R] TypeIntrinsics_r/_ro: GC reports uninitialized frame slots during throw-helper calls (pMT->Validate assert)[/+]