From e5c089d55ca760198ab0f91447ce94baed3b602f Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Tue, 2 Jun 2026 00:35:00 +0000 Subject: [PATCH] [wasm-split] Fix infinite loop bug in table patching We should skip all active segments in the active table when creating trampolines for indirect references. Currently we only do it for the last active segment, in case there are multiple of them. --- src/ir/module-splitting.cpp | 8 ++--- .../trampoline-ignore-active-segments.wast | 34 +++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 test/lit/wasm-split/trampoline-ignore-active-segments.wast diff --git a/src/ir/module-splitting.cpp b/src/ir/module-splitting.cpp index 619b00d92b6..a3b6a11d24b 100644 --- a/src/ir/module-splitting.cpp +++ b/src/ir/module-splitting.cpp @@ -979,13 +979,13 @@ void ModuleSplitter::indirectReferencesToSecondaryFunctions() { gatherer.walkModule(secondaryPtr.get()); } - // Ignore references to secondary functions that occur in the active segment + // Ignore references to secondary functions that occur in the active segments // that will contain the imported placeholders. Indirect calls to table slots - // initialized by that segment will already go to the right place once the + // initialized by those segments will already go to the right place once the // secondary module has been loaded and the table has been patched. std::unordered_set ignore; - if (tableManager.activeSegment) { - for (auto* expr : tableManager.activeSegment->data) { + for (auto* segment : tableManager.activeTableSegments) { + for (auto* expr : segment->data) { if (auto* ref = expr->dynCast()) { ignore.insert(ref); } diff --git a/test/lit/wasm-split/trampoline-ignore-active-segments.wast b/test/lit/wasm-split/trampoline-ignore-active-segments.wast new file mode 100644 index 00000000000..35c1e6485e9 --- /dev/null +++ b/test/lit/wasm-split/trampoline-ignore-active-segments.wast @@ -0,0 +1,34 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-split %s --disable-reference-types --split-funcs=split -g -o1 %t.1.wasm -o2 %t.2.wasm +;; RUN: wasm-dis %t.1.wasm | filecheck %s --check-prefix PRIMARY + +;; Regression test for a bug that we incorrectly created a trampoline for +;; (elem $e0 (i32.const 0) $split) segment, even though it was one of active +;; segments. + +(module + ;; PRIMARY: (type $0 (func)) + (type $0 (func)) + ;; PRIMARY: (table $active_table 2 2 funcref) + (table $active_table 2 2 funcref) + ;; PRIMARY: (elem $e0 (i32.const 0) $placeholder_0) + + ;; PRIMARY: (elem $e1 (i32.const 1) $keep) + + ;; PRIMARY: (export "active_table" (table $active_table)) + (export "active_table" (table $active_table)) + + (elem $e0 (i32.const 0) $split) + (elem $e1 (i32.const 1) $keep) + + ;; PRIMARY: (func $keep + ;; PRIMARY-NEXT: (nop) + ;; PRIMARY-NEXT: ) + (func $keep (type $0) + (nop) + ) + + (func $split (type $0) + (nop) + ) +)