summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-10-03 12:42:03 -0700
committerGitHub <noreply@github.com>2022-10-03 12:42:03 -0700
commitfda3cf94fe778cfc93c322c4e31e316ecc2dd80c (patch)
treeac267653cbd818d6787802a04bc12738bdceff21 /src
parentd9a57f8bac6e8dfd366a12f5ff97f58ceb242b91 (diff)
downloadbinaryen-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.cpp47
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) {