diff options
author | Heejin Ahn <aheejin@gmail.com> | 2022-01-04 12:39:38 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-04 12:39:38 -0800 |
commit | 16ac2eb73a57eb530f78b632cffacac97c6b8fdd (patch) | |
tree | 81e0945bbb828b880f8292647c21318c600b783c | |
parent | 28665b1d8f0632216ceb2de475560c64dc260b9d (diff) | |
download | binaryen-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-x | scripts/fuzz_opt.py | 13 | ||||
-rw-r--r-- | src/ir/eh-utils.cpp | 2 | ||||
-rw-r--r-- | src/ir/eh-utils.h | 2 | ||||
-rw-r--r-- | src/tools/fuzzing.h | 7 | ||||
-rw-r--r-- | src/tools/fuzzing/fuzzing.cpp | 8 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 3 | ||||
-rw-r--r-- | test/passes/fuzz_metrics_noprint.bin.txt | 51 | ||||
-rw-r--r-- | test/passes/translate-to-fuzz_all-features_metrics_noprint.txt | 70 |
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 |