From f7923baf3c80529a096320353a6f7e57228e623e Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Fri, 2 Oct 2026 11:56:45 +0200 Subject: [PATCH 1/2] [cDAC][wasm] Filter unexpected register slots in non-active frames Treat unexpected Wasm register slots as scratch, with a concise rationale and matching contract clarification. Preserve active-frame behavior and all encoding constants. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- docs/design/datacontracts/GCInfo.md | 2 ++ .../Contracts/GCInfo/PlatformTraits/WasmGCInfoTraits.cs | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/design/datacontracts/GCInfo.md b/docs/design/datacontracts/GCInfo.md index 7ba3cfbc90ab9d..2e7792d0c48f92 100644 --- a/docs/design/datacontracts/GCInfo.md +++ b/docs/design/datacontracts/GCInfo.md @@ -665,6 +665,8 @@ For encodings without interruptible ranges (`HAS_INTERRUPTIBLE_RANGES` is false, **Slot filtering**: Before reporting any slot, the algorithm checks: - **Scratch registers**: Only reported for the active/leaf frame (`ActiveStackFrame` flag). + The WebAssembly platform decoder treats every register as scratch because + valid Wasm GC info does not encode register slots. - **Scratch stack slots**: Only reported for the active/leaf frame (slots in the outgoing/scratch area). - **FP-based-only mode** (`ReportFPBasedSlotsOnly`): Only frame-register-relative stack slots are reported; all register slots and non-frame-relative stack slots are skipped. diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/WasmGCInfoTraits.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/WasmGCInfoTraits.cs index 60fa8fe8f3894b..63c0f5fb3c3945 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/WasmGCInfoTraits.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/WasmGCInfoTraits.cs @@ -37,5 +37,8 @@ internal sealed class WasmGCInfoTraits : IGCInfoTraits public static int NUM_INTERRUPTIBLE_RANGES_ENCBASE => 1; public static bool HAS_FIXED_STACK_PARAMETER_SCRATCH_AREA => false; public static bool HAS_INTERRUPTIBLE_RANGES => false; - public static bool IsScratchRegister(uint regNum) => false; + + // Valid Wasm GC info has no register slots. Treat unexpected ones as scratch + // so they are omitted from non-active frames. + public static bool IsScratchRegister(uint regNum) => true; } From 1608fcafe3ca732326add48eb59e7ea915a98d27 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Sun, 4 Oct 2026 12:56:39 +0200 Subject: [PATCH 2/2] [cDAC][wasm] Match native fallback for unexpected register slots Jan Kotas noted that returning true from IsScratchRegister diverges from the native unknown-platform fallback, which asserts and returns false (gcinfodecoder.cpp PORTABILITY_ASSERT). Mirror that: Debug.Fail to flag the unreachable call in debug builds, then return false like the native helper and other unimplemented platforms. Update the matching contract-spec sentence. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- docs/design/datacontracts/GCInfo.md | 5 +++-- .../GCInfo/PlatformTraits/WasmGCInfoTraits.cs | 13 ++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/docs/design/datacontracts/GCInfo.md b/docs/design/datacontracts/GCInfo.md index 2e7792d0c48f92..a136cffdac2dbc 100644 --- a/docs/design/datacontracts/GCInfo.md +++ b/docs/design/datacontracts/GCInfo.md @@ -665,8 +665,9 @@ For encodings without interruptible ranges (`HAS_INTERRUPTIBLE_RANGES` is false, **Slot filtering**: Before reporting any slot, the algorithm checks: - **Scratch registers**: Only reported for the active/leaf frame (`ActiveStackFrame` flag). - The WebAssembly platform decoder treats every register as scratch because - valid Wasm GC info does not encode register slots. + Valid Wasm GC info never contains register slots, so the WebAssembly platform + decoder's scratch-register predicate always returns false and asserts in debug + builds if called, mirroring the native unsupported-platform fallback. - **Scratch stack slots**: Only reported for the active/leaf frame (slots in the outgoing/scratch area). - **FP-based-only mode** (`ReportFPBasedSlotsOnly`): Only frame-register-relative stack slots are reported; all register slots and non-frame-relative stack slots are skipped. diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/WasmGCInfoTraits.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/WasmGCInfoTraits.cs index 63c0f5fb3c3945..6097373872693b 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/WasmGCInfoTraits.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/GCInfo/PlatformTraits/WasmGCInfoTraits.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; + namespace Microsoft.Diagnostics.DataContractReader.Contracts.GCInfoHelpers; // Mirrors Wasm32GcInfoEncoding in src/coreclr/inc/gcinfotypes.h. @@ -38,7 +40,12 @@ internal sealed class WasmGCInfoTraits : IGCInfoTraits public static bool HAS_FIXED_STACK_PARAMETER_SCRATCH_AREA => false; public static bool HAS_INTERRUPTIBLE_RANGES => false; - // Valid Wasm GC info has no register slots. Treat unexpected ones as scratch - // so they are omitted from non-active frames. - public static bool IsScratchRegister(uint regNum) => true; + // Valid Wasm GC info has no register slots; RyuJIT never emits one. Mirror the + // native fallback (gcinfodecoder.cpp PORTABILITY_ASSERT): flag the unexpected + // call in debug builds and otherwise return false, like other unimplemented platforms. + public static bool IsScratchRegister(uint regNum) + { + Debug.Fail("Wasm GC info must not contain register slots."); + return false; + } }