From 38a155ab135bf5140aa8aeedc8490ceb4be6ccef Mon Sep 17 00:00:00 2001 From: Randolf Jung Date: Fri, 23 Oct 2026 16:21:59 -0700 Subject: [PATCH 1/2] Don't panic on empty core rec groups in components The component translator found each core rec group of a component from the type at the group's first index, which an empty rec group doesn't have, so `(component (core rec))` indexed out of bounds and `(component (core rec) (core type (module)))` used the module type instead. Empty rec groups define no types, so this skips them. --- crates/environ/src/component/translate.rs | 2 ++ tests/misc_testsuite/component-model/empty-rec-groups.wast | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100644 tests/misc_testsuite/component-model/empty-rec-groups.wast diff --git a/crates/environ/src/component/translate.rs b/crates/environ/src/component/translate.rs index baf49ccc5cf5..aabe2c079288 100644 --- a/crates/environ/src/component/translate.rs +++ b/crates/environ/src/component/translate.rs @@ -905,6 +905,8 @@ impl<'a, 'data> Translator<'a, 'data> { let types = self.validator.types(0).unwrap(); for ty in s { match ty? { + // An empty rec group defines no types to intern. + wasmparser::CoreType::Rec(group) if group.types().len() == 0 => {} wasmparser::CoreType::Rec(group) => { let id = types.core_type_at_in_component(index).unwrap_sub(); let group_id = types.rec_group_id_of(id); diff --git a/tests/misc_testsuite/component-model/empty-rec-groups.wast b/tests/misc_testsuite/component-model/empty-rec-groups.wast new file mode 100644 index 000000000000..f1a811aec0d9 --- /dev/null +++ b/tests/misc_testsuite/component-model/empty-rec-groups.wast @@ -0,0 +1,6 @@ +;;! gc = true + +;; Empty core rec groups define no types. +(component (core rec)) +(component (core rec) (core type (module))) +(component (core type (sub (array i8))) (core rec)) From a18d20335a46d542640c987fd6a8688f5a1db156 Mon Sep 17 00:00:00 2001 From: Randolf Jung Date: Mon, 26 Oct 2026 09:29:14 -0700 Subject: [PATCH 2/2] Intern component core types by type count instead of per rec group Like the type section in core modules, walk the core types that the validator added for this section rather than the section's rec groups, which handles empty rec groups without special-casing them. --- crates/environ/src/component/translate.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/crates/environ/src/component/translate.rs b/crates/environ/src/component/translate.rs index aabe2c079288..a1b57c07d416 100644 --- a/crates/environ/src/component/translate.rs +++ b/crates/environ/src/component/translate.rs @@ -14,8 +14,8 @@ use indexmap::IndexMap; use std::collections::{HashMap, HashSet}; use std::mem; use wasmparser::component_types::{ - AliasableResourceId, ComponentCoreModuleTypeId, ComponentDefinedTypeId, ComponentEntityType, - ComponentFuncTypeId, ComponentInstanceTypeId, ComponentValType, + AliasableResourceId, ComponentCoreModuleTypeId, ComponentCoreTypeId, ComponentDefinedTypeId, + ComponentEntityType, ComponentFuncTypeId, ComponentInstanceTypeId, ComponentValType, }; use wasmparser::types::Types; use wasmparser::{Chunk, ComponentExternName, Encoding, Parser, Payload, Validator}; @@ -903,19 +903,21 @@ impl<'a, 'data> Translator<'a, 'data> { .core_type_count_in_component(); self.validator.core_type_section(&s)?; let types = self.validator.types(0).unwrap(); - for ty in s { - match ty? { - // An empty rec group defines no types to intern. - wasmparser::CoreType::Rec(group) if group.types().len() == 0 => {} - wasmparser::CoreType::Rec(group) => { - let id = types.core_type_at_in_component(index).unwrap_sub(); + let count = types.core_type_count_in_component(); + while index < count { + match types.core_type_at_in_component(index) { + // The current type index is always the first type of + // its rec group, so intern the group and then skip + // past the rest of its types. + ComponentCoreTypeId::Sub(id) => { let group_id = types.rec_group_id_of(id); self.types .module_types_builder() .intern_rec_group(types, group_id)?; - index += u32::try_from(group.types().len()).unwrap(); + index += + u32::try_from(types.rec_group_elements(group_id).len()).unwrap(); } - wasmparser::CoreType::Module(_) => index += 1, + ComponentCoreTypeId::Module(_) => index += 1, } } }