summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeejin Ahn <aheejin@gmail.com>2022-01-04 12:39:38 -0800
committerGitHub <noreply@github.com>2022-01-04 12:39:38 -0800
commit16ac2eb73a57eb530f78b632cffacac97c6b8fdd (patch)
tree81e0945bbb828b880f8292647c21318c600b783c
parent28665b1d8f0632216ceb2de475560c64dc260b9d (diff)
downloadbinaryen-16ac2eb73a57eb530f78b632cffacac97c6b8fdd.tar.gz
binaryen-16ac2eb73a57eb530f78b632cffacac97c6b8fdd.tar.bz2
binaryen-16ac2eb73a57eb530f78b632cffacac97c6b8fdd.zip
[EH] Enable fuzzer with initial contents (#4409)
This enables fuzzing EH with initial contents. fuzzing.cpp/h does not yet support generation of EH instructions, but with this we can still fuzz EH based on initial contents. The fuzzer ran successfully for more than 1,900,000 iterations, with my local modification that always enables EH and lets the fuzzer select only EH tests for its initial contents.
-rwxr-xr-xscripts/fuzz_opt.py13
-rw-r--r--src/ir/eh-utils.cpp2
-rw-r--r--src/ir/eh-utils.h2
-rw-r--r--src/tools/fuzzing.h7
-rw-r--r--src/tools/fuzzing/fuzzing.cpp8
-rw-r--r--src/wasm/wasm-validator.cpp3
-rw-r--r--test/passes/fuzz_metrics_noprint.bin.txt51
-rw-r--r--test/passes/translate-to-fuzz_all-features_metrics_noprint.txt70
8 files changed, 85 insertions, 71 deletions
diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py
index d7c82e244..21d39853a 100755
--- a/scripts/fuzz_opt.py
+++ b/scripts/fuzz_opt.py
@@ -312,8 +312,6 @@ def pick_initial_contents():
global FEATURE_OPTS
FEATURE_OPTS += [
- # has not been enabled in the fuzzer yet
- '--disable-exception-handling',
# has not been fuzzed in general yet
'--disable-memory64',
# avoid multivalue for now due to bad interactions with gc rtts in
@@ -793,7 +791,7 @@ class CompareVMs(TestCaseHandler):
compare(before[vm], after[vm], 'CompareVMs between before and after: ' + vm.name)
def can_run_on_feature_opts(self, feature_opts):
- return all_disallowed(['simd', 'exception-handling', 'multivalue'])
+ return all_disallowed(['simd', 'multivalue'])
# Check for determinism - the same command must have the same output.
@@ -1184,9 +1182,6 @@ def randomize_opt_flags():
if has_flatten:
print('avoiding multiple --flatten in a single command, due to exponential overhead')
continue
- if '--enable-exception-handling' in FEATURE_OPTS:
- print('avoiding --flatten due to exception catching which does not support it yet')
- continue
if '--enable-multivalue' in FEATURE_OPTS and '--enable-reference-types' in FEATURE_OPTS:
print('avoiding --flatten due to multivalue + reference types not supporting it (spilling of non-nullable tuples)')
continue
@@ -1198,6 +1193,10 @@ def randomize_opt_flags():
continue
else:
has_flatten = True
+ if ('--rereloop' in choice or '--dfo' in choice) and \
+ '--enable-exception-handling' in FEATURE_OPTS:
+ print('avoiding --rereloop or --dfo due to exception-handling not supporting it')
+ continue
flag_groups.append(choice)
if len(flag_groups) > 20 or random.random() < 0.3:
break
@@ -1238,7 +1237,7 @@ print('POSSIBLE_FEATURE_OPTS:', POSSIBLE_FEATURE_OPTS)
# some features depend on other features, so if a required feature is
# disabled, its dependent features need to be disabled as well.
IMPLIED_FEATURE_OPTS = {
- '--disable-reference-types': ['--disable-exception-handling', '--disable-gc']
+ '--disable-reference-types': ['--disable-gc']
}
if __name__ == '__main__':
diff --git a/src/ir/eh-utils.cpp b/src/ir/eh-utils.cpp
index 31ddfe306..37af738ce 100644
--- a/src/ir/eh-utils.cpp
+++ b/src/ir/eh-utils.cpp
@@ -100,7 +100,7 @@ getFirstPop(Expression* catchBody, bool& isPopNested, Expression**& popPtr) {
}
}
-bool isPopValid(Expression* catchBody) {
+bool containsValidDanglingPop(Expression* catchBody) {
bool isPopNested = false;
Expression** popPtr = nullptr;
auto* pop = getFirstPop(catchBody, isPopNested, popPtr);
diff --git a/src/ir/eh-utils.h b/src/ir/eh-utils.h
index 733eedc67..c0d6e59ea 100644
--- a/src/ir/eh-utils.h
+++ b/src/ir/eh-utils.h
@@ -29,7 +29,7 @@ namespace EHUtils {
// whose tag type is void or a catch_all's body, this returns false.
// - This returns true even if there are more pops after the first one within a
// catch body, which is invalid. That will be taken care of in validation.
-bool isPopValid(Expression* catchBody);
+bool containsValidDanglingPop(Expression* catchBody);
// Fixes up 'pop's nested in blocks, which are currently not supported without
// block param types, by creating a new local, putting a (local.set $new (pop
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h
index a9cc9eec0..fe5191475 100644
--- a/src/tools/fuzzing.h
+++ b/src/tools/fuzzing.h
@@ -31,6 +31,7 @@ high chance for set at start of loop
#include "ir/memory-utils.h"
#include "support/insert_ordered.h"
#include "tools/fuzzing/random.h"
+#include <ir/eh-utils.h>
#include <ir/find_all.h>
#include <ir/literal-utils.h>
#include <ir/manipulation.h>
@@ -182,8 +183,12 @@ private:
// type, but should not do so for certain types that are dangerous. For
// example, it would be bad to add an RTT in a tuple, as that would force us
// to use temporary locals for the tuple, but RTTs are not defaultable.
+ // Also, 'pop' pseudo instruction for EH is supposed to exist only at the
+ // beginning of a 'catch' block, so it shouldn't be moved around or deleted
+ // freely.
bool canBeArbitrarilyReplaced(Expression* curr) {
- return curr->type.isDefaultable();
+ return curr->type.isDefaultable() &&
+ !EHUtils::containsValidDanglingPop(curr);
}
void recombine(Function* func);
void mutate(Function* func);
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index 8194c52d3..a41e6704e 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -581,14 +581,18 @@ void TranslateToFuzzReader::recombine(Function* func) {
// First, scan and group all expressions by type.
struct Scanner
: public PostWalker<Scanner, UnifiedExpressionVisitor<Scanner>> {
+ TranslateToFuzzReader& parent;
// A map of all expressions, categorized by type.
InsertOrderedMap<Type, std::vector<Expression*>> exprsByType;
+ Scanner(TranslateToFuzzReader& parent) : parent(parent) {}
void visitExpression(Expression* curr) {
- exprsByType[curr->type].push_back(curr);
+ if (parent.canBeArbitrarilyReplaced(curr)) {
+ exprsByType[curr->type].push_back(curr);
+ }
}
};
- Scanner scanner;
+ Scanner scanner(*this);
scanner.walk(func->body);
// Potentially trim the list of possible picks, so replacements are more
// likely to collide.
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index e7e1d7fd5..1ad1380c9 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -2202,7 +2202,8 @@ void FunctionValidator::visitTry(Try* curr) {
<< "catch's tag (" << tagName
<< ")'s pop doesn't have the same type as the tag's params";
}
- if (!shouldBeTrue(EHUtils::isPopValid(catchBody), curr, "")) {
+ if (!shouldBeTrue(
+ EHUtils::containsValidDanglingPop(catchBody), curr, "")) {
getStream() << "catch's body (" << tagName
<< ")'s pop's location is not valid";
}
diff --git a/test/passes/fuzz_metrics_noprint.bin.txt b/test/passes/fuzz_metrics_noprint.bin.txt
index d65d67831..4c481cd8f 100644
--- a/test/passes/fuzz_metrics_noprint.bin.txt
+++ b/test/passes/fuzz_metrics_noprint.bin.txt
@@ -1,31 +1,32 @@
total
- [exports] : 38
- [funcs] : 62
+ [exports] : 39
+ [funcs] : 50
[globals] : 7
[imports] : 4
[memory-data] : 4
- [table-data] : 22
+ [table-data] : 17
[tables] : 1
[tags] : 0
- [total] : 7561
- [vars] : 214
- Binary : 542
- Block : 1140
- Break : 287
- Call : 236
- CallIndirect : 94
- Const : 1510
- Drop : 66
- GlobalGet : 625
- GlobalSet : 266
- If : 487
- Load : 128
- LocalGet : 477
- LocalSet : 264
- Loop : 182
- Nop : 223
- RefFunc : 22
- Return : 301
- Select : 58
- Store : 91
- Unary : 562
+ [total] : 3442
+ [vars] : 108
+ Binary : 299
+ Block : 495
+ Break : 110
+ Call : 193
+ CallIndirect : 29
+ Const : 650
+ Drop : 48
+ GlobalGet : 295
+ GlobalSet : 131
+ If : 183
+ Load : 79
+ LocalGet : 199
+ LocalSet : 153
+ Loop : 71
+ Nop : 45
+ RefFunc : 17
+ Return : 155
+ Select : 25
+ Store : 29
+ Unary : 235
+ Unreachable : 1
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 853206211..a172095ef 100644
--- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
+++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
@@ -1,42 +1,46 @@
total
- [exports] : 8
- [funcs] : 9
+ [exports] : 13
+ [funcs] : 18
[globals] : 6
[imports] : 5
[memory-data] : 22
- [table-data] : 4
+ [table-data] : 14
[tables] : 1
[tags] : 1
- [total] : 465
- [vars] : 10
- ArrayInit : 1
- AtomicCmpxchg : 1
+ [total] : 728
+ [vars] : 41
+ ArrayInit : 6
+ AtomicFence : 1
AtomicNotify : 1
- Binary : 64
- Block : 51
- Break : 6
- Call : 19
- Const : 121
- DataDrop : 1
- Drop : 6
- GlobalGet : 22
- GlobalSet : 12
- If : 20
- Load : 13
- LocalGet : 22
- LocalSet : 18
- Loop : 3
+ AtomicRMW : 1
+ Binary : 80
+ Block : 83
+ Break : 13
+ Call : 33
+ CallIndirect : 1
+ CallRef : 1
+ Const : 162
+ Drop : 10
+ GlobalGet : 50
+ GlobalSet : 27
+ I31Get : 3
+ I31New : 5
+ If : 32
+ Load : 20
+ LocalGet : 35
+ LocalSet : 21
+ Loop : 8
MemoryFill : 1
- Nop : 20
+ MemoryInit : 1
+ Nop : 14
RefAs : 1
- RefFunc : 5
- RefIs : 3
- RefNull : 3
- Return : 18
- SIMDExtract : 3
- Select : 1
- Store : 3
- StructNew : 3
- TupleExtract : 2
- TupleMake : 4
- Unary : 17
+ RefFunc : 16
+ RefIs : 2
+ RefNull : 6
+ Return : 27
+ SIMDExtract : 1
+ Select : 8
+ Store : 2
+ StructNew : 7
+ TupleMake : 5
+ Unary : 44