Skip to content

Commit 661fe5e

Browse files
authored
Skip function references when detecting uninhabitable types (#5545)
Function references are always inhabitable because functions can be created with any function type, even types that refer to uninhabitable types. Take advantage of this by skipping function references when finding non-nullable reference cycles that cause uninhabitability.
1 parent 069aec9 commit 661fe5e

File tree

2 files changed

+28
-25
lines changed

2 files changed

+28
-25
lines changed

src/tools/fuzzing/heap-types.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -685,10 +685,8 @@ struct Inhabitator {
685685
//
686686
// An invariant field of a heaptype must have the same type in subtypes of
687687
// that heaptype. A covariant field of a heaptype must be typed with a subtype
688-
// of its original type in subtypes of the heaptype. A contravariant field of
689-
// a heap type must be typed with a supertype of its original type in subtypes
690-
// of the heaptype.
691-
enum Variance { Invariant, Covariant, Contravariant };
688+
// of its original type in subtypes of the heaptype.
689+
enum Variance { Invariant, Covariant };
692690

693691
// The input types.
694692
const std::vector<HeapType>& types;
@@ -712,7 +710,7 @@ struct Inhabitator {
712710

713711
Inhabitator::Variance Inhabitator::getVariance(FieldPos field) {
714712
auto [type, idx] = field;
715-
assert(!type.isBasic());
713+
assert(!type.isBasic() && !type.isSignature());
716714
if (type.isStruct()) {
717715
if (type.getStruct().fields[idx].mutable_ == Mutable) {
718716
return Invariant;
@@ -727,13 +725,6 @@ Inhabitator::Variance Inhabitator::getVariance(FieldPos field) {
727725
return Covariant;
728726
}
729727
}
730-
if (type.isSignature()) {
731-
if (idx < type.getSignature().params.size()) {
732-
return Contravariant;
733-
} else {
734-
return Covariant;
735-
}
736-
}
737728
WASM_UNREACHABLE("unexpected kind");
738729
}
739730

@@ -768,8 +759,6 @@ void Inhabitator::markNullable(FieldPos field) {
768759
curr = *super;
769760
}
770761
}
771-
[[fallthrough]];
772-
case Contravariant:
773762
// Mark the field nullable in all subtypes. If the subtype field is
774763
// already nullable, that's ok and this will have no effect. TODO: Remove
775764
// this extra `index` variable once we have C++20. It's a workaround for
@@ -784,6 +773,11 @@ void Inhabitator::markNullable(FieldPos field) {
784773

785774
void Inhabitator::markBottomRefsNullable() {
786775
for (auto type : types) {
776+
if (type.isSignature()) {
777+
// Functions can always be instantiated, even if their types refer to
778+
// uninhabitable types.
779+
continue;
780+
}
787781
auto children = type.getTypeChildren();
788782
for (size_t i = 0; i < children.size(); ++i) {
789783
auto child = children[i];
@@ -801,6 +795,11 @@ void Inhabitator::markExternRefsNullable() {
801795
// TODO: Remove this once the fuzzer imports externref globals or gets some
802796
// other way to instantiate externrefs.
803797
for (auto type : types) {
798+
if (type.isSignature()) {
799+
// Functions can always be instantiated, even if their types refer to
800+
// uninhabitable types.
801+
continue;
802+
}
804803
auto children = type.getTypeChildren();
805804
for (size_t i = 0; i < children.size(); ++i) {
806805
auto child = children[i];
@@ -863,6 +862,14 @@ void Inhabitator::breakNonNullableCycles() {
863862
++idx;
864863
continue;
865864
}
865+
// Skip references to function types. Functions types can always be
866+
// instantiated since functions can be created even with uninhabitable
867+
// params or results. Function references therefore break cycles that
868+
// would otherwise produce uninhabitability.
869+
if (heapType.isSignature()) {
870+
++idx;
871+
continue;
872+
}
866873
// If this ref forms a cycle, break the cycle by marking it nullable and
867874
// continue.
868875
if (auto it = visiting.find(heapType); it != visiting.end()) {

src/tools/wasm-fuzz-types.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -502,9 +502,14 @@ static std::optional<HeapType>
502502
findUninhabitable(HeapType type,
503503
std::unordered_set<HeapType>& visited,
504504
std::unordered_set<HeapType>& visiting) {
505-
if (type.isBasic() || visited.count(type)) {
505+
if (type.isBasic()) {
506506
return std::nullopt;
507-
} else if (type.isBasic()) {
507+
}
508+
if (type.isSignature()) {
509+
// Function types are always inhabitable.
510+
return std::nullopt;
511+
}
512+
if (visited.count(type)) {
508513
return std::nullopt;
509514
}
510515

@@ -523,15 +528,6 @@ findUninhabitable(HeapType type,
523528
type, type.getArray().element.type, visited, visiting)) {
524529
return t;
525530
}
526-
} else if (type.isSignature()) {
527-
auto sig = type.getSignature();
528-
for (auto types : {sig.params, sig.results}) {
529-
for (auto child : types) {
530-
if (auto t = findUninhabitable(type, child, visited, visiting)) {
531-
return t;
532-
}
533-
}
534-
}
535531
} else {
536532
WASM_UNREACHABLE("unexpected type kind");
537533
}

0 commit comments

Comments
 (0)