From fbdeb1973f3f1c722d2aa5cf69b05228f6f429ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Hillerstr=C3=B6m?= Date: Thu, 6 Aug 2026 18:56:16 +0100 Subject: [PATCH] [stack-switching] Fix type index conflation in the translation of `switch` The translation of `switch` would erroneously decompose a `ModuleInternedTypeIndex` and use its `u32` representation to build a `TypeIndex`. The two index types map different spaces, consequently it is possible to cause a compiler crash (out of bounds on lookup) or worse a runtime crash (argument types mismatch). --- crates/cranelift/src/func_environ.rs | 9 +++++ .../src/translate/code_translator.rs | 4 +-- .../switch-type-index-conflation.wast | 35 +++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 tests/misc_testsuite/stack-switching/switch-type-index-conflation.wast diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 10d20e63b170..1e47b8c70de4 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -5584,6 +5584,15 @@ impl FuncEnvironment<'_> { ) } + pub fn continuation_arguments_from_interned( + &self, + index: ModuleInternedTypeIndex, + ) -> &[WasmValType] { + self.types[self.types[index].unwrap_cont().unwrap_module_type_index()] + .unwrap_func() + .params() + } + pub fn continuation_arguments(&self, index: TypeIndex) -> &[WasmValType] { let idx = self.module.types[index].unwrap_module_type_index(); self.types[self.types[idx].unwrap_cont().unwrap_module_type_index()] diff --git a/crates/cranelift/src/translate/code_translator.rs b/crates/cranelift/src/translate/code_translator.rs index 7de3ab3b4d62..6e1b49cb7070 100644 --- a/crates/cranelift/src/translate/code_translator.rs +++ b/crates/cranelift/src/translate/code_translator.rs @@ -3335,10 +3335,10 @@ pub fn translate_operator( WasmHeapType::ConcreteCont(index) => { let mti = index .as_module_type_index() - .expect("Only supporting module type indices on switch for now"); + .expect("expected module-local type index"); environ - .continuation_arguments(TypeIndex::from_u32(mti.as_u32())) + .continuation_arguments_from_interned(mti) .iter() .map(|ty| crate::value_type(environ.isa(), *ty)) .collect() diff --git a/tests/misc_testsuite/stack-switching/switch-type-index-conflation.wast b/tests/misc_testsuite/stack-switching/switch-type-index-conflation.wast new file mode 100644 index 000000000000..e5ae9747b7b6 --- /dev/null +++ b/tests/misc_testsuite/stack-switching/switch-type-index-conflation.wast @@ -0,0 +1,35 @@ +;;! bulk_memory = true +;;! function_references = true +;;! stack_switching = true + +;; Regression test for buggy module-local type index to declared type +;; index conversion. +(module + ;; These two function types canonicalize to the same module-interned type. + ;; As a result, subsequent TypeIndex and ModuleInternedTypeIndex values do + ;; not have the same numeric value. + (type $duplicate (func)) + (type $ft0 (func)) + + (type $ct0 (cont $ft0)) + + (type $ft1 (func (param (ref $ct0)))) + (type $ct1 (cont $ft1)) + + (tag $t) + + (func $f + (cont.new $ct1 (ref.func $g)) + (switch $ct1 $t)) + (elem declare func $f) + + (func $g (type $ft1)) + (elem declare func $g) + + (func (export "entry") (result i32) + (cont.new $ct0 (ref.func $f)) + (resume $ct0 (on $t switch)) + (i32.const 0)) +) + +(assert_return (invoke "entry") (i32.const 0))