summaryrefslogtreecommitdiff
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
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).
-rw-r--r--src/tools/fuzzing/fuzzing.cpp39
-rw-r--r--test/passes/translate-to-fuzz_all-features_metrics_noprint.txt83
2 files changed, 71 insertions, 51 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);
diff --git a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
index 3cd4228e9..6f5078909 100644
--- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
+++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
@@ -1,56 +1,55 @@
total
- [exports] : 5
- [funcs] : 8
+ [exports] : 3
+ [funcs] : 6
[globals] : 1
[imports] : 5
[memories] : 1
[memory-data] : 20
- [table-data] : 6
+ [table-data] : 1
[tables] : 1
[tags] : 2
- [total] : 807
- [vars] : 27
- ArrayLen : 1
+ [total] : 643
+ [vars] : 36
+ ArrayCopy : 1
+ ArrayFill : 1
+ ArrayGet : 1
+ ArrayLen : 5
ArrayNew : 7
- ArrayNewFixed : 3
ArraySet : 1
- AtomicCmpxchg : 1
- AtomicFence : 1
- Binary : 89
- Block : 102
- Break : 18
- Call : 21
- CallRef : 1
- Const : 154
- Drop : 5
- GlobalGet : 38
- GlobalSet : 38
+ AtomicNotify : 1
+ AtomicRMW : 1
+ Binary : 84
+ Block : 58
+ Break : 9
+ Call : 22
+ CallRef : 2
+ Const : 144
+ Drop : 2
+ GlobalGet : 16
+ GlobalSet : 16
I31Get : 2
- If : 27
- Load : 19
- LocalGet : 62
+ If : 20
+ Load : 20
+ LocalGet : 75
LocalSet : 48
- Loop : 12
- MemoryFill : 1
- Nop : 10
- Pop : 5
- RefAs : 19
- RefCast : 3
- RefEq : 2
- RefFunc : 7
- RefI31 : 4
- RefIsNull : 2
- RefNull : 14
- RefTest : 2
- Return : 2
+ Loop : 4
+ MemoryInit : 1
+ Nop : 4
+ Pop : 4
+ RefAs : 4
+ RefFunc : 6
+ RefI31 : 3
+ RefNull : 11
+ RefTest : 1
+ Return : 7
SIMDExtract : 1
Select : 5
- Store : 4
- StructGet : 6
- StructNew : 9
+ Store : 3
+ StructGet : 3
+ StructNew : 7
StructSet : 1
- Try : 5
- TupleExtract : 2
- TupleMake : 2
- Unary : 32
- Unreachable : 19
+ Try : 3
+ TupleExtract : 7
+ TupleMake : 10
+ Unary : 14
+ Unreachable : 8