From b7f38e45a68e7e2d94373c0417a2f176a9062ffe Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Fri, 8 May 2026 15:27:58 -0700 Subject: [PATCH] Fix crash in MinimizeRecGroups We previously did not store type indices for public types. This caused a crash when the logic for comparing rec groups came across references to public types and assumed there would be indices to compare them by. --- src/passes/MinimizeRecGroups.cpp | 2 +- test/lit/passes/minimize-rec-groups.wast | 40 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/passes/MinimizeRecGroups.cpp b/src/passes/MinimizeRecGroups.cpp index 306426af5b9..a4d5e8211ac 100644 --- a/src/passes/MinimizeRecGroups.cpp +++ b/src/passes/MinimizeRecGroups.cpp @@ -311,10 +311,10 @@ struct MinimizeRecGroups : Pass { // generate new groups with the same shape. std::unordered_set publicGroups; for (auto& [type, info] : typeInfo) { + typeIndices.insert({type, typeIndices.size()}); if (info.visibility == ModuleUtils::Visibility::Private) { // We can optimize private types. types.push_back(type); - typeIndices.insert({type, typeIndices.size()}); } else { publicGroups.insert(type.getRecGroup()); } diff --git a/test/lit/passes/minimize-rec-groups.wast b/test/lit/passes/minimize-rec-groups.wast index 3483d1c9de3..963f655f20d 100644 --- a/test/lit/passes/minimize-rec-groups.wast +++ b/test/lit/passes/minimize-rec-groups.wast @@ -563,4 +563,44 @@ ;; CHECK: (global $privateB (ref null $privateB) (ref.null none)) (global $privateB (ref null $privateB) (ref.null none)) ) + +;; Regression test for a bug where we crashed when comparing rec groups with +;; references to public types because we did not store type indices for public +;; types. ;; CHECK: (export "g" (global $public)) +(module + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $public (sub (descriptor $desc) (struct))) + (type $public (sub (descriptor $desc) (struct))) + ;; CHECK: (type $desc (sub (describes $public) (struct))) + (type $desc (sub (describes $public) (struct))) + ) + + ;; We should not crash when comparing these identical connected components. + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $private1 (sub $public (descriptor $desc1) (struct))) + (type $private1 (sub $public (descriptor $desc1) (struct))) + ;; CHECK: (type $desc1 (sub $desc (describes $private1) (struct))) + + ;; CHECK: (rec + ;; CHECK-NEXT: (type $4 (struct)) + + ;; CHECK: (type $private2 (sub $public (descriptor $desc2) (struct))) + (type $private2 (sub $public (descriptor $desc2) (struct))) + (type $desc1 (sub $desc (describes $private1) (struct))) + ;; CHECK: (type $desc2 (sub $desc (describes $private2) (struct))) + (type $desc2 (sub $desc (describes $private2) (struct))) + ) + + ;; CHECK: (global $use1 (ref null $private1) (ref.null none)) + (global $use1 (ref null $private1) (ref.null none)) + ;; CHECK: (global $use2 (ref null $private2) (ref.null none)) + (global $use2 (ref null $private2) (ref.null none)) + ;; CHECK: (global $public (ref null $public) (ref.null none)) + (global $public (ref null $public) (ref.null none)) + ;; CHECK: (export "public" (global $public)) + (export "public" (global $public)) +) +