diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 63f399f949f..82a9f86b0a4 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -483,6 +483,7 @@ class TranslateToFuzzReader { Expression* makeArrayBulkMemoryOp(Type type); Expression* makeI31Get(Type type); Expression* makeThrow(Type type); + Expression* makeThrowRef(Type type); Expression* makeMemoryInit(); Expression* makeDataDrop(); diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 11fa12d5ba8..bc981a49f53 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1992,7 +1992,7 @@ Expression* TranslateToFuzzReader::_makeunreachable() { &Self::makeSwitch, &Self::makeDrop, &Self::makeReturn) - .add(FeatureSet::ExceptionHandling, &Self::makeThrow) + .add(FeatureSet::ExceptionHandling, &Self::makeThrow, &Self::makeThrowRef) .add(FeatureSet::ReferenceTypes | FeatureSet::GC, &Self::makeCallRef); return (this->*pick(options))(Type::unreachable); } @@ -3250,12 +3250,17 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) { return builder.makeArrayNewFixed(ht, {}); } case HeapType::exn: { - auto null = builder.makeRefNull(HeapTypes::exn.getBasic(share)); - if (!type.isNullable()) { - assert(funcContext); - return builder.makeRefAs(RefAsNonNull, null); + // If nullable, we can emit a null. If not, generate an exnref using a + // throw in a try_table. + if (type.isNullable() && oneIn(2)) { + return builder.makeRefNull(HeapTypes::exn.getBasic(share)); } - return null; + + // Make a catch_all_ref to a block. + auto* throww = makeThrow(Type::unreachable); + auto label = makeLabel(); + auto* tryy = builder.makeTryTable(throww, {Name()}, {label}, {true}); + return builder.makeBlock(label, tryy); } case HeapType::string: { // In non-function contexts all we can do is string.const. @@ -4809,6 +4814,15 @@ Expression* TranslateToFuzzReader::makeThrow(Type type) { return builder.makeThrow(tag, operands); } +Expression* TranslateToFuzzReader::makeThrowRef(Type type) { + assert(type == Type::unreachable); + // Use a nullable type here to avoid the risk of trapping (when we find no way + // to make a non-nullable ref, we end up fixing validation with + // ref.as_non_null of a null, which validates but traps). + auto* ref = make(Type(HeapType::exn, Nullable)); + return builder.makeThrowRef(ref); +} + Expression* TranslateToFuzzReader::makeMemoryInit() { if (!allowMemory) { return makeTrivial(Type::none);