diff options
-rw-r--r-- | src/tools/fuzzing.h | 5 | ||||
-rw-r--r-- | src/tools/fuzzing/fuzzing.cpp | 31 | ||||
-rw-r--r-- | test/passes/fuzz_metrics_noprint.bin.txt | 53 | ||||
-rw-r--r-- | test/passes/translate-to-fuzz_all-features_metrics_noprint.txt | 65 |
4 files changed, 82 insertions, 72 deletions
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index aff2a0aa3..bdadaba5a 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -193,9 +193,8 @@ private: } void recombine(Function* func); void mutate(Function* func); - // Fix up changes that may have broken validation - types are correct in our - // modding, but not necessarily labels. - void fixLabels(Function* func); + // Fix up the IR after recombination and mutation. + void fixAfterChanges(Function* func); void modifyInitialFunctions(); // Initial wasm contents may have come from a test that uses the drop pattern: diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index d91266d49..af2a34078 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -544,7 +544,7 @@ Function* TranslateToFuzzReader::addFunction() { // with more possible sets. // Recombination, mutation, etc. can break validation; fix things up // after. - fixLabels(func); + fixAfterChanges(func); } // Add hang limit checks after all other operations on the function body. wasm.addFunction(func); @@ -690,7 +690,6 @@ void TranslateToFuzzReader::recombine(Function* func) { Module& wasm; Scanner& scanner; TranslateToFuzzReader& parent; - bool needRefinalize = false; Modder(Module& wasm, Scanner& scanner, TranslateToFuzzReader& parent) : wasm(wasm), scanner(scanner), parent(parent) {} @@ -702,18 +701,11 @@ void TranslateToFuzzReader::recombine(Function* func) { assert(!candidates.empty()); // this expression itself must be there 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) { @@ -721,15 +713,28 @@ void TranslateToFuzzReader::mutate(Function* func) { if (oneIn(2)) { return; } + struct Modder : public PostWalker<Modder, UnifiedExpressionVisitor<Modder>> { Module& wasm; TranslateToFuzzReader& parent; + // Whether to replace with unreachable. This can lead to less code getting + // executed, so we don't want to do it all the time even in a big function. + bool allowUnreachable; + Modder(Module& wasm, TranslateToFuzzReader& parent) - : wasm(wasm), parent(parent) {} + : wasm(wasm), parent(parent) { + // Half the time, never replace with an unreachable. The other half, do it + // sometimes (but even so, only rarely, see below). + allowUnreachable = parent.oneIn(2); + } void visitExpression(Expression* curr) { if (parent.oneIn(10) && parent.canBeArbitrarilyReplaced(curr)) { + if (allowUnreachable && parent.oneIn(10)) { + replaceCurrent(parent.make(Type::unreachable)); + return; + } // For constants, perform only a small tweaking in some cases. if (auto* c = curr->dynCast<Const>()) { if (parent.oneIn(2)) { @@ -749,7 +754,7 @@ void TranslateToFuzzReader::mutate(Function* func) { modder.walk(func->body); } -void TranslateToFuzzReader::fixLabels(Function* func) { +void TranslateToFuzzReader::fixAfterChanges(Function* func) { struct Fixer : public ControlFlowWalker<Fixer, UnifiedExpressionVisitor<Fixer>> { Module& wasm; @@ -818,6 +823,8 @@ void TranslateToFuzzReader::fixLabels(Function* func) { }; Fixer fixer(wasm, *this); fixer.walk(func->body); + + // Refinalize at the end, after labels are all fixed up. ReFinalize().walkFunctionInModule(func, &wasm); } @@ -855,7 +862,7 @@ void TranslateToFuzzReader::modifyInitialFunctions() { // check variations on initial testcases even at the risk of OOB. recombine(func); mutate(func); - fixLabels(func); + fixAfterChanges(func); } } // Remove a start function - the fuzzing harness expects code to run only diff --git a/test/passes/fuzz_metrics_noprint.bin.txt b/test/passes/fuzz_metrics_noprint.bin.txt index cf94c2f3d..b7d64cee2 100644 --- a/test/passes/fuzz_metrics_noprint.bin.txt +++ b/test/passes/fuzz_metrics_noprint.bin.txt @@ -1,33 +1,34 @@ total - [exports] : 15 - [funcs] : 21 + [exports] : 41 + [funcs] : 52 [globals] : 7 [imports] : 4 [memories] : 1 [memory-data] : 4 - [table-data] : 7 + [table-data] : 21 [tables] : 1 [tags] : 0 - [total] : 2012 - [vars] : 60 - Binary : 195 - Block : 269 - Break : 80 - Call : 67 - CallIndirect : 14 - Const : 373 - Drop : 12 - GlobalGet : 164 - GlobalSet : 65 - If : 110 - Load : 47 - LocalGet : 176 - LocalSet : 116 - Loop : 39 - Nop : 24 - RefFunc : 7 - Return : 74 - Select : 18 - Store : 26 - Unary : 135 - Unreachable : 1 + [total] : 8251 + [vars] : 153 + Binary : 661 + Block : 1232 + Break : 320 + Call : 303 + CallIndirect : 86 + Const : 1458 + Drop : 57 + GlobalGet : 646 + GlobalSet : 295 + If : 479 + Load : 157 + LocalGet : 617 + LocalSet : 473 + Loop : 208 + Nop : 137 + RefFunc : 21 + Return : 338 + Select : 58 + Store : 91 + Switch : 1 + Unary : 611 + Unreachable : 2 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 97d1b637d..3f725452b 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,6 +1,6 @@ total - [exports] : 10 - [funcs] : 14 + [exports] : 15 + [funcs] : 18 [globals] : 6 [imports] : 5 [memories] : 1 @@ -8,35 +8,38 @@ total [table-data] : 6 [tables] : 1 [tags] : 0 - [total] : 610 - [vars] : 52 - ArrayInit : 5 - AtomicFence : 4 - AtomicRMW : 2 - Binary : 66 - Block : 78 - Break : 9 - Call : 21 + [total] : 541 + [vars] : 31 + ArrayInit : 7 + AtomicFence : 1 + AtomicNotify : 1 + Binary : 68 + Block : 64 + Break : 3 + Call : 14 + CallIndirect : 1 CallRef : 1 - Const : 146 + Const : 119 + DataDrop : 1 Drop : 9 - GlobalGet : 46 - GlobalSet : 22 - I31New : 3 - If : 28 - Load : 13 - LocalGet : 20 - LocalSet : 17 - Loop : 8 - Nop : 16 - RefFunc : 8 - RefIsNull : 2 - RefNull : 5 - Return : 28 - SIMDExtract : 1 - Select : 1 - Store : 4 - StructNew : 6 + GlobalGet : 49 + GlobalSet : 23 + I31Get : 1 + I31New : 4 + If : 24 + Load : 16 + LocalGet : 26 + LocalSet : 18 + Loop : 5 + MemoryCopy : 1 + Nop : 6 + RefFunc : 7 + RefIsNull : 3 + RefNull : 3 + Return : 26 + SIMDTernary : 1 + Select : 2 + Store : 2 TupleExtract : 1 - TupleMake : 7 - Unary : 33 + TupleMake : 5 + Unary : 29 |