Skip to content

Commit

Permalink
Fuzzer: Generate ThrowRef, and avoid unneeded traps with it (#7279)
Browse files Browse the repository at this point in the history
We generate a `throw_ref` by generating an exnref for it to throw. To
avoid that causing lots of traps due to not having an exnref, add some logic to
generate an exnref (by making a try that throws and catches).
  • Loading branch information
kripken authored Feb 6, 2025
1 parent 8878eb5 commit a019ec8
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/tools/fuzzing.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
26 changes: 20 additions & 6 deletions src/tools/fuzzing/fuzzing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit a019ec8

Please sign in to comment.