diff options
author | Alon Zakai <azakai@google.com> | 2022-10-03 12:42:03 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-03 12:42:03 -0700 |
commit | fda3cf94fe778cfc93c322c4e31e316ecc2dd80c (patch) | |
tree | ac267653cbd818d6787802a04bc12738bdceff21 /src | |
parent | d9a57f8bac6e8dfd366a12f5ff97f58ceb242b91 (diff) | |
download | binaryen-fda3cf94fe778cfc93c322c4e31e316ecc2dd80c.tar.gz binaryen-fda3cf94fe778cfc93c322c4e31e316ecc2dd80c.tar.bz2 binaryen-fda3cf94fe778cfc93c322c4e31e316ecc2dd80c.zip |
[Fuzzing] Allow recombine() to replace with a subtype (#5101)
Previously it would randomly replace an expression with another one with the
exact same type. Allowing a subtype may give us more coverage.
Diffstat (limited to 'src')
-rw-r--r-- | src/tools/fuzzing/fuzzing.cpp | 47 |
1 files changed, 43 insertions, 4 deletions
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 3d84af26a..2b368a4e8 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -623,8 +623,39 @@ void TranslateToFuzzReader::recombine(Function* func) { void visitExpression(Expression* curr) { if (parent.canBeArbitrarilyReplaced(curr)) { - exprsByType[curr->type].push_back(curr); + for (auto type : getRelevantTypes(curr->type)) { + exprsByType[type].push_back(curr); + } + } + } + + std::vector<Type> getRelevantTypes(Type type) { + // Given an expression of a type, we can replace not only other + // expressions with the same type, but also supertypes - since then we'd + // be replacing with a subtype, which is valid. + if (!type.isRef()) { + return {type}; + } + + std::vector<Type> ret; + auto heapType = type.getHeapType(); + auto nullability = type.getNullability(); + + if (nullability == NonNullable) { + ret = getRelevantTypes(Type(heapType, Nullable)); + } + + while (1) { + ret.push_back(Type(heapType, nullability)); + // TODO: handle basic supertypes too + auto super = heapType.getSuperType(); + if (!super) { + break; + } + heapType = *super; } + + return ret; } }; Scanner scanner(*this); @@ -653,12 +684,13 @@ void TranslateToFuzzReader::recombine(Function* func) { } } // Second, with some probability replace an item with another item having - // the same type. (This is not always valid due to nesting of labels, but + // a proper type. (This is not always valid due to nesting of labels, but // we'll fix that up later.) struct Modder : public PostWalker<Modder, UnifiedExpressionVisitor<Modder>> { Module& wasm; Scanner& scanner; TranslateToFuzzReader& parent; + bool needRefinalize = false; Modder(Module& wasm, Scanner& scanner, TranslateToFuzzReader& parent) : wasm(wasm), scanner(scanner), parent(parent) {} @@ -668,13 +700,20 @@ void TranslateToFuzzReader::recombine(Function* func) { // Replace it! auto& candidates = scanner.exprsByType[curr->type]; assert(!candidates.empty()); // this expression itself must be there - replaceCurrent( - ExpressionManipulator::copy(parent.pick(candidates), wasm)); + auto* rep = parent.pick(candidates); + replaceCurrent(ExpressionManipulator::copy(rep, wasm)); + if (rep->type != curr->type) { + // Subtyping changes require us to finalize later. + needRefinalize = true; + } } } }; Modder modder(wasm, scanner, *this); modder.walk(func->body); + if (modder.needRefinalize) { + ReFinalize().walkFunctionInModule(func, &wasm); + } } void TranslateToFuzzReader::mutate(Function* func) { |