summaryrefslogtreecommitdiff
path: root/src/tools/fuzzing/fuzzing.cpp
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-10-18 10:10:58 -0700
committerGitHub <noreply@github.com>2023-10-18 17:10:58 +0000
commit89c02aad305474aea1d413e110aadd68278a13d6 (patch)
treef1185f1ffaa2d6f6b3691b21d81bbecb24440169 /src/tools/fuzzing/fuzzing.cpp
parentf2a556b1179fe4ee350728ad674bf723eb824768 (diff)
downloadbinaryen-89c02aad305474aea1d413e110aadd68278a13d6.tar.gz
binaryen-89c02aad305474aea1d413e110aadd68278a13d6.tar.bz2
binaryen-89c02aad305474aea1d413e110aadd68278a13d6.zip
Fuzzer: Allow non-nullable locals (#6019)
Remove the code that avoided such locals. To avoid much new trapping, add logic to set a value to such locals if they have accesses that are not dominated by a set already. Also in makeTrivial only rarely emit a local.get of a non-nullable local (prefer a constant).
Diffstat (limited to 'src/tools/fuzzing/fuzzing.cpp')
-rw-r--r--src/tools/fuzzing/fuzzing.cpp39
1 files changed, 30 insertions, 9 deletions
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index bdaf71e83..ef7b3a5b7 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -16,6 +16,7 @@
#include "tools/fuzzing.h"
#include "ir/gc-type-utils.h"
+#include "ir/local-structural-dominance.h"
#include "ir/module-utils.h"
#include "ir/subtypes.h"
#include "ir/type-updating.h"
@@ -559,15 +560,37 @@ void TranslateToFuzzReader::addHashMemorySupport() {
}
TranslateToFuzzReader::FunctionCreationContext::~FunctionCreationContext() {
+ // We must ensure non-nullable locals validate. Later down we'll run
+ // TypeUpdating::handleNonDefaultableLocals which will make them validate by
+ // turning them nullable + add ref.as_non_null to fix up types. That has the
+ // downside of making them trap at runtime, however, and also we lose the non-
+ // nullability in the type, so we prefer to do a manual fixup that avoids a
+ // trap, which we do by writing a non-nullable value into the local at the
+ // function entry.
+ // TODO: We could be more precise and use a LocalGraph here, at the cost of
+ // doing more work.
+ LocalStructuralDominance info(
+ func, parent.wasm, LocalStructuralDominance::NonNullableOnly);
+ for (auto index : info.nonDominatingIndices) {
+ // Do not always do this, but with high probability, to reduce the amount of
+ // traps.
+ if (!parent.oneIn(5)) {
+ auto* value = parent.makeTrivial(func->getLocalType(index));
+ func->body = parent.builder.makeSequence(
+ parent.builder.makeLocalSet(index, value), func->body);
+ }
+ }
+
+ // Then, to handle remaining cases we did not just fix up, do the general
+ // fixup to ensure we validate.
+ TypeUpdating::handleNonDefaultableLocals(func, parent.wasm);
+
if (HANG_LIMIT > 0) {
parent.addHangLimitChecks(func);
}
assert(breakableStack.empty());
assert(hangStack.empty());
parent.funcContext = nullptr;
-
- // We must ensure non-nullable locals validate.
- TypeUpdating::handleNonDefaultableLocals(func, parent.wasm);
}
Expression* TranslateToFuzzReader::makeHangLimitCheck() {
@@ -621,11 +644,6 @@ Function* TranslateToFuzzReader::addFunction() {
Index numVars = upToSquared(MAX_VARS);
for (Index i = 0; i < numVars; i++) {
auto type = getConcreteType();
- if (!type.isDefaultable()) {
- // We can't use a nondefaultable type as a var, as those must be
- // initialized to some default value.
- continue;
- }
funcContext->typeLocals[type].push_back(params.size() + func->vars.size());
func->vars.push_back(type);
}
@@ -1251,7 +1269,10 @@ Expression* TranslateToFuzzReader::makeTrivial(Type type) {
} nester(*this);
if (type.isConcrete()) {
- if (oneIn(2) && funcContext) {
+ // If we have a function context, use a local half the time. Use a local
+ // less often if the local is non-nullable, however, as then we might be
+ // using it before it was set, which would trap.
+ if (funcContext && oneIn(type.isNonNullable() ? 10 : 2)) {
return makeLocalGet(type);
} else {
return makeConst(type);