Repository: bytecodealliance/wasmtime
Pull request #9374 (2024-10-04 17:09:00)

Fix type interning during Wasm-to-CLIF translation
We were handling the case where we had fewer rec groups than types, in the case where a rec group defines multiple types, but were failing to handle the case when we have more rec groups than types due to empty rec groups.

The fix is to bound the loop by the number of types, not the number of rec groups.

<!--
Please make sure you include the following information:

- If this work has been discussed elsewhere, please include a link to that
  conversation. If it was discussed in an issue, just mention "issue #...".

- Explain why this change is needed. If the details are in an issue already,
  this can be brief.

Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.html

Please ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->



Patch:
diff --git a/crates/environ/src/compile/module_environ.rs b/crates/environ/src/compile/module_environ.rs
index 9bfcc1ff8..416384b04 100644
--- a/crates/environ/src/compile/module_environ.rs
+++ b/crates/environ/src/compile/module_environ.rs
@@ -239,7 +239,9 @@ impl<'a, 'data> ModuleEnvironment<'a, 'data> {
             Payload::TypeSection(types) => {
                 self.validator.type_section(&types)?;
 
-                let count = types.count();
+                let count = self.validator.types(0).unwrap().core_type_count();
+                log::trace!("interning {count} Wasm types");
+
                 let capacity = usize::try_from(count).unwrap();
                 self.result.module.types.reserve(capacity);
                 self.types.reserve_wasm_signatures(capacity);
@@ -254,15 +256,16 @@ impl<'a, 'data> ModuleEnvironment<'a, 'data> {
                 // groups, we need copy the duplicates over (shallowly) as well,
                 // so that our types index space doesn't have holes.
                 let mut type_index = 0;
-                for _ in 0..count {
+                while type_index < count {
                     let validator_types = self.validator.types(0).unwrap();
 
                     // Get the rec group for the current type index, which is
                     // always the first type defined in a rec group.
+                    log::trace!("looking up wasmparser type for index {type_index}");
                     let core_type_id = validator_types.core_type_at(type_index).unwrap_sub();
                     log::trace!(
-                        "about to intern rec group for {core_type_id:?} = {:?}",
-                        validator_types[core_type_id]
+                        "  --> {core_type_id:?} = {:?}",
+                        validator_types[core_type_id],
                     );
                     let rec_group_id = validator_types.rec_group_id_of(core_type_id);
                     debug_assert_eq!(


Test patch:
diff --git a/tests/misc_testsuite/gc/more-rec-groups-than-types.wast b/tests/misc_testsuite/gc/more-rec-groups-than-types.wast
new file mode 100644
index 000000000..5f3644de0
--- /dev/null
+++ b/tests/misc_testsuite/gc/more-rec-groups-than-types.wast
@@ -0,0 +1,18 @@
+;; Test that we properly handle empty rec groups and when we have more rec
+;; groups defined in the type section than actual types (and therefore the
+;; length that the type section reports is greater than the length of the types
+;; index space).
+
+(module
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (rec)
+  (type (func (param i32) (result i32)))
+)