From 075f13ac4c3d451afc038ba896f266c93c570ba6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 17 May 2024 10:48:58 -0700 Subject: [PATCH 01/10] fuzz --- src/support/topological_sort.h | 2 +- src/tools/fuzzing.h | 2 + src/tools/fuzzing/fuzzing.cpp | 72 +++++++++++-------- src/tools/fuzzing/parameters.h | 2 +- test/passes/fuzz_metrics_noprint.bin.txt | 54 +++++++------- ...e-to-fuzz_all-features_metrics_noprint.txt | 63 ++++++---------- 6 files changed, 97 insertions(+), 98 deletions(-) diff --git a/src/support/topological_sort.h b/src/support/topological_sort.h index 91353dd3727..3594617ebd5 100644 --- a/src/support/topological_sort.h +++ b/src/support/topological_sort.h @@ -27,7 +27,7 @@ namespace wasm { // CRTP utility that provides an iterator through arbitrary directed acyclic // graphs of data that will visit the data in a topologically sorted order // (https://en.wikipedia.org/wiki/Topological_sorting). In other words, the -// iterator will produce each item only after all that items predecessors have +// iterator will produce each item only after all that item's predecessors have // been produced. // // Subclasses should call `push` on all the root items in their constructors and diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 78652723627..75e3a2a9a4e 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -106,6 +106,8 @@ class TranslateToFuzzReader { std::unordered_map> globalsByType; std::unordered_map> mutableGlobalsByType; + std::unordered_map> immutableGlobalsByType; + std::unordered_map> importedImmutableGlobalsByType; std::vector loggableTypes; diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 1b1d2cb0172..ff8335c98a4 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -379,26 +379,53 @@ void TranslateToFuzzReader::setupGlobals() { } } + auto useGlobalLater = [&](Global* global) { + auto type = global->type; + auto name = global->name; + globalsByType[type].push_back(name); + if (global->mutable_) { + mutableGlobalsByType[type].push_back(name); + } else { + immutableGlobalsByType[type].push_back(name); + if (global->imported()) { + importedImmutableGlobalsByType[type].push_back(name); + } + } + }; + // Randomly assign some globals from initial content to be ignored for the // fuzzer to use. Such globals will only be used from initial content. This is // important to preserve some real-world patterns, like the "once" pattern in // which a global is used in one function only. (If we randomly emitted gets // and sets of such globals, we'd with very high probability end up breaking // that pattern, and not fuzzing it at all.) - // - // Pick a percentage of initial globals to ignore later down when we decide - // which to allow uses from. - auto numInitialGlobals = wasm.globals.size(); - unsigned percentIgnoredInitialGlobals = 0; - if (numInitialGlobals) { - // Only generate this random number if it will be used. - percentIgnoredInitialGlobals = upTo(100); + if (!wasm.globals.empty()) { + unsigned percentUsedInitialGlobals = upTo(100); + for (auto& global : wasm.globals) { + if (upTo(100) < percentUsedInitialGlobals) { + useGlobalLater(global.get()); + } + } } // Create new random globals. for (size_t index = upTo(MAX_GLOBALS); index > 0; --index) { auto type = getConcreteType(); - auto* init = makeConst(type); + if (type.isTuple()) { + // We disallow tuples in globals. + type = Type::i32; + } + auto mutability = oneIn(2) ? Builder::Mutable : Builder::Immutable; + + // Usually make a const, but sometimes make a global.get (which may fail to + // find a suitable global, and if so it will make a constant instead). + Expression* init; + if (oneIn(3)) { + init = makeConst(type); + } else { + init = makeGlobalGet(type); + } + if (!FindAll(init).list.empty()) { // When creating this initial value we ended up emitting a RefAs, which // means we had to stop in the middle of an overly-nested struct or array, @@ -408,26 +435,9 @@ void TranslateToFuzzReader::setupGlobals() { type = getMVPType(); init = makeConst(type); } - auto mutability = oneIn(2) ? Builder::Mutable : Builder::Immutable; auto global = builder.makeGlobal( Names::getValidGlobalName(wasm, "global$"), type, init, mutability); - wasm.addGlobal(std::move(global)); - } - - // Set up data structures for picking globals later for get/set operations. - for (Index i = 0; i < wasm.globals.size(); i++) { - auto& global = wasm.globals[i]; - - // Apply the chance for initial globals to be ignored, see above. - if (i < numInitialGlobals && upTo(100) < percentIgnoredInitialGlobals) { - continue; - } - - // This is a global we can use later, note it. - globalsByType[global->type].push_back(global->name); - if (global->mutable_) { - mutableGlobalsByType[global->type].push_back(global->name); - } + useGlobalLater(wasm.addGlobal(std::move(global))); } } @@ -1900,8 +1910,12 @@ Expression* TranslateToFuzzReader::makeLocalSet(Type type) { } Expression* TranslateToFuzzReader::makeGlobalGet(Type type) { - auto it = globalsByType.find(type); - if (it == globalsByType.end() || it->second.empty()) { + // In a non-function context, like in another global, we can only get from an + // immutable global, and whether GC is enabled (which allows getting non- + // imported globals). + auto& relevantGlobals = funcContext ? globalsByType : (wasm.features.hasGC() ? immutableGlobalsByType : importedImmutableGlobalsByType); + auto it = relevantGlobals.find(type); + if (it == relevantGlobals.end() || it->second.empty()) { return makeTrivial(type); } diff --git a/src/tools/fuzzing/parameters.h b/src/tools/fuzzing/parameters.h index 51531681b39..33ef2b9aeaf 100644 --- a/src/tools/fuzzing/parameters.h +++ b/src/tools/fuzzing/parameters.h @@ -30,7 +30,7 @@ constexpr int MAX_PARAMS = 10; constexpr int MAX_VARS = 20; // The maximum number of globals in a module. -constexpr int MAX_GLOBALS = 20; +constexpr int MAX_GLOBALS = 1000; // The maximum number of tuple elements. constexpr int MAX_TUPLE_SIZE = 6; diff --git a/test/passes/fuzz_metrics_noprint.bin.txt b/test/passes/fuzz_metrics_noprint.bin.txt index f6af82a5ad0..75ed3bba6f0 100644 --- a/test/passes/fuzz_metrics_noprint.bin.txt +++ b/test/passes/fuzz_metrics_noprint.bin.txt @@ -1,34 +1,34 @@ total - [exports] : 18 - [funcs] : 21 - [globals] : 9 + [exports] : 38 + [funcs] : 60 + [globals] : 108 [imports] : 4 [memories] : 1 [memory-data] : 2 - [table-data] : 7 + [table-data] : 18 [tables] : 1 [tags] : 0 - [total] : 11685 - [vars] : 64 - Binary : 848 - Block : 1846 - Break : 456 - Call : 275 - CallIndirect : 117 - Const : 1952 - Drop : 86 - GlobalGet : 844 - GlobalSet : 679 - If : 625 - Load : 236 - LocalGet : 1050 - LocalSet : 764 - Loop : 301 - Nop : 143 - RefFunc : 7 - Return : 103 - Select : 77 - Store : 111 + [total] : 7585 + [vars] : 173 + Binary : 527 + Block : 1247 + Break : 273 + Call : 322 + CallIndirect : 78 + Const : 1299 + Drop : 95 + GlobalGet : 586 + GlobalSet : 480 + If : 405 + Load : 114 + LocalGet : 600 + LocalSet : 367 + Loop : 169 + Nop : 59 + RefFunc : 18 + Return : 87 + Select : 52 + Store : 50 Switch : 3 - Unary : 835 - Unreachable : 327 + Unary : 519 + Unreachable : 235 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 4ead6265533..33494961f35 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,47 +1,30 @@ total - [exports] : 5 - [funcs] : 7 - [globals] : 14 + [exports] : 2 + [funcs] : 2 + [globals] : 250 [imports] : 5 [memories] : 1 [memory-data] : 20 - [table-data] : 2 + [table-data] : 0 [tables] : 1 - [tags] : 1 - [total] : 467 - [vars] : 40 - ArrayGet : 1 - ArrayLen : 1 - ArrayNew : 6 - ArrayNewFixed : 1 - Binary : 67 - Block : 44 - Break : 5 - Call : 21 - Const : 106 - Drop : 7 - GlobalGet : 20 - GlobalSet : 18 - If : 14 - Load : 17 - LocalGet : 45 - LocalSet : 28 - Loop : 3 - MemoryFill : 1 - Nop : 5 - RefAs : 1 - RefCast : 1 - RefEq : 1 + [tags] : 0 + [total] : 531 + [vars] : 1 + ArrayNew : 29 + ArrayNewFixed : 9 + Binary : 49 + Block : 4 + Const : 186 + GlobalGet : 117 + GlobalSet : 2 + If : 1 + Load : 16 + LocalGet : 33 + LocalSet : 17 RefFunc : 3 RefI31 : 4 - RefNull : 3 - Return : 3 - Select : 2 - Store : 1 - StringConst : 3 - StringEncode : 1 - StringEq : 1 - StructNew : 5 - TupleMake : 5 - Unary : 13 - Unreachable : 10 + RefNull : 28 + StringConst : 7 + StructNew : 23 + Unary : 1 + Unreachable : 2 From 5200682a889ca8b4c874fa6f1eda4bef8e231365 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 17 May 2024 14:39:17 -0700 Subject: [PATCH 02/10] moderation --- src/tools/fuzzing/parameters.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/fuzzing/parameters.h b/src/tools/fuzzing/parameters.h index 33ef2b9aeaf..72b5640b4ca 100644 --- a/src/tools/fuzzing/parameters.h +++ b/src/tools/fuzzing/parameters.h @@ -30,7 +30,7 @@ constexpr int MAX_PARAMS = 10; constexpr int MAX_VARS = 20; // The maximum number of globals in a module. -constexpr int MAX_GLOBALS = 1000; +constexpr int MAX_GLOBALS = 25; // The maximum number of tuple elements. constexpr int MAX_TUPLE_SIZE = 6; From 6c19dd519cbac712e24503a453f274c63d365134 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 17 May 2024 14:39:47 -0700 Subject: [PATCH 03/10] format --- src/tools/fuzzing/fuzzing.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index ff8335c98a4..df2552fdf27 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1913,7 +1913,10 @@ Expression* TranslateToFuzzReader::makeGlobalGet(Type type) { // In a non-function context, like in another global, we can only get from an // immutable global, and whether GC is enabled (which allows getting non- // imported globals). - auto& relevantGlobals = funcContext ? globalsByType : (wasm.features.hasGC() ? immutableGlobalsByType : importedImmutableGlobalsByType); + auto& relevantGlobals = + funcContext ? globalsByType + : (wasm.features.hasGC() ? immutableGlobalsByType + : importedImmutableGlobalsByType); auto it = relevantGlobals.find(type); if (it == relevantGlobals.end() || it->second.empty()) { return makeTrivial(type); From 3b8300452f329462d3903cfa0f43c28800b7af28 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 17 May 2024 14:42:52 -0700 Subject: [PATCH 04/10] fix --- src/tools/fuzzing/fuzzing.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index df2552fdf27..595294c24fd 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -411,16 +411,12 @@ void TranslateToFuzzReader::setupGlobals() { // Create new random globals. for (size_t index = upTo(MAX_GLOBALS); index > 0; --index) { auto type = getConcreteType(); - if (type.isTuple()) { - // We disallow tuples in globals. - type = Type::i32; - } auto mutability = oneIn(2) ? Builder::Mutable : Builder::Immutable; // Usually make a const, but sometimes make a global.get (which may fail to // find a suitable global, and if so it will make a constant instead). Expression* init; - if (oneIn(3)) { + if (!oneIn(3)) { init = makeConst(type); } else { init = makeGlobalGet(type); @@ -1911,8 +1907,8 @@ Expression* TranslateToFuzzReader::makeLocalSet(Type type) { Expression* TranslateToFuzzReader::makeGlobalGet(Type type) { // In a non-function context, like in another global, we can only get from an - // immutable global, and whether GC is enabled (which allows getting non- - // imported globals). + // immutable global. Whether GC is enabled also matters, as it allows getting + // from a non-import. auto& relevantGlobals = funcContext ? globalsByType : (wasm.features.hasGC() ? immutableGlobalsByType From 276cf342c23bbbda748ba79c572f05a7a60ca537 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 17 May 2024 14:43:14 -0700 Subject: [PATCH 05/10] fix --- test/passes/fuzz_metrics_noprint.bin.txt | 55 ++++++++-------- ...e-to-fuzz_all-features_metrics_noprint.txt | 64 ++++++++++++------- 2 files changed, 69 insertions(+), 50 deletions(-) diff --git a/test/passes/fuzz_metrics_noprint.bin.txt b/test/passes/fuzz_metrics_noprint.bin.txt index 75ed3bba6f0..71ba93839e9 100644 --- a/test/passes/fuzz_metrics_noprint.bin.txt +++ b/test/passes/fuzz_metrics_noprint.bin.txt @@ -1,34 +1,33 @@ total - [exports] : 38 - [funcs] : 60 - [globals] : 108 + [exports] : 50 + [funcs] : 72 + [globals] : 9 [imports] : 4 [memories] : 1 [memory-data] : 2 - [table-data] : 18 + [table-data] : 22 [tables] : 1 [tags] : 0 - [total] : 7585 - [vars] : 173 - Binary : 527 - Block : 1247 - Break : 273 - Call : 322 - CallIndirect : 78 - Const : 1299 - Drop : 95 - GlobalGet : 586 - GlobalSet : 480 - If : 405 - Load : 114 - LocalGet : 600 - LocalSet : 367 - Loop : 169 - Nop : 59 - RefFunc : 18 - Return : 87 - Select : 52 - Store : 50 - Switch : 3 - Unary : 519 - Unreachable : 235 + [total] : 8564 + [vars] : 237 + Binary : 632 + Block : 1451 + Break : 298 + Call : 318 + CallIndirect : 81 + Const : 1383 + Drop : 93 + GlobalGet : 681 + GlobalSet : 565 + If : 467 + Load : 142 + LocalGet : 606 + LocalSet : 484 + Loop : 198 + Nop : 96 + RefFunc : 22 + Return : 66 + Select : 57 + Store : 72 + Unary : 578 + Unreachable : 274 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 33494961f35..28eb9dc51c9 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,30 +1,50 @@ total [exports] : 2 [funcs] : 2 - [globals] : 250 + [globals] : 24 [imports] : 5 [memories] : 1 [memory-data] : 20 [table-data] : 0 [tables] : 1 - [tags] : 0 - [total] : 531 - [vars] : 1 - ArrayNew : 29 - ArrayNewFixed : 9 - Binary : 49 - Block : 4 - Const : 186 - GlobalGet : 117 - GlobalSet : 2 - If : 1 - Load : 16 - LocalGet : 33 - LocalSet : 17 - RefFunc : 3 - RefI31 : 4 - RefNull : 28 - StringConst : 7 - StructNew : 23 - Unary : 1 - Unreachable : 2 + [tags] : 1 + [total] : 524 + [vars] : 36 + ArrayCopy : 1 + ArrayFill : 1 + ArrayGet : 2 + ArrayLen : 4 + ArrayNew : 19 + AtomicNotify : 1 + Binary : 71 + Block : 30 + Break : 2 + Call : 5 + Const : 135 + Drop : 2 + GlobalGet : 12 + GlobalSet : 6 + If : 16 + Load : 18 + LocalGet : 66 + LocalSet : 41 + Loop : 2 + Nop : 5 + Pop : 3 + RefAs : 14 + RefCast : 1 + RefNull : 12 + RefTest : 2 + Return : 1 + Select : 1 + Store : 2 + StringConst : 4 + StringEncode : 1 + StringEq : 1 + StringMeasure : 1 + StructNew : 13 + Try : 4 + TupleExtract : 3 + TupleMake : 11 + Unary : 8 + Unreachable : 3 From 60332739ae0bdd46772dff6319231e4ffb04d75e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 17 May 2024 16:37:19 -0700 Subject: [PATCH 06/10] fix --- src/tools/fuzzing/fuzzing.cpp | 20 +++-- test/passes/fuzz_metrics_noprint.bin.txt | 52 ++++++------- ...e-to-fuzz_all-features_metrics_noprint.txt | 77 ++++++++++--------- 3 files changed, 74 insertions(+), 75 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 595294c24fd..e0b9b1d1911 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -413,14 +413,9 @@ void TranslateToFuzzReader::setupGlobals() { auto type = getConcreteType(); auto mutability = oneIn(2) ? Builder::Mutable : Builder::Immutable; - // Usually make a const, but sometimes make a global.get (which may fail to - // find a suitable global, and if so it will make a constant instead). - Expression* init; - if (!oneIn(3)) { - init = makeConst(type); - } else { - init = makeGlobalGet(type); - } + // We can only make something trivial (like a constant) in a global + // initializer. + auto* init = makeTrivial(type); if (!FindAll(init).list.empty()) { // When creating this initial value we ended up emitting a RefAs, which @@ -1483,9 +1478,12 @@ Expression* TranslateToFuzzReader::makeTrivial(Type type) { // using it before it was set, which would trap. if (funcContext && oneIn(type.isNonNullable() ? 10 : 2)) { return makeLocalGet(type); - } else { - return makeConst(type); } + + // Either make a const, or a global.get (which may fail to find a suitable + // global, especially in a non-function context, and if so it will make a + // constant instead). + return oneIn(2) ? makeConst(type) : makeGlobalGet(type); } else if (type == Type::none) { return makeNop(type); } @@ -1915,7 +1913,7 @@ Expression* TranslateToFuzzReader::makeGlobalGet(Type type) { : importedImmutableGlobalsByType); auto it = relevantGlobals.find(type); if (it == relevantGlobals.end() || it->second.empty()) { - return makeTrivial(type); + return makeConst(type); } auto name = pick(it->second); diff --git a/test/passes/fuzz_metrics_noprint.bin.txt b/test/passes/fuzz_metrics_noprint.bin.txt index 71ba93839e9..0fbc46028dc 100644 --- a/test/passes/fuzz_metrics_noprint.bin.txt +++ b/test/passes/fuzz_metrics_noprint.bin.txt @@ -1,33 +1,33 @@ total - [exports] : 50 - [funcs] : 72 + [exports] : 37 + [funcs] : 60 [globals] : 9 [imports] : 4 [memories] : 1 [memory-data] : 2 - [table-data] : 22 + [table-data] : 23 [tables] : 1 [tags] : 0 - [total] : 8564 - [vars] : 237 - Binary : 632 - Block : 1451 - Break : 298 - Call : 318 - CallIndirect : 81 - Const : 1383 - Drop : 93 - GlobalGet : 681 - GlobalSet : 565 - If : 467 - Load : 142 - LocalGet : 606 - LocalSet : 484 - Loop : 198 - Nop : 96 - RefFunc : 22 - Return : 66 - Select : 57 - Store : 72 - Unary : 578 - Unreachable : 274 + [total] : 6655 + [vars] : 169 + Binary : 504 + Block : 1108 + Break : 211 + Call : 209 + CallIndirect : 54 + Const : 1049 + Drop : 70 + GlobalGet : 562 + GlobalSet : 421 + If : 361 + Load : 126 + LocalGet : 482 + LocalSet : 377 + Loop : 145 + Nop : 107 + RefFunc : 23 + Return : 84 + Select : 40 + Store : 58 + Unary : 456 + Unreachable : 208 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 28eb9dc51c9..74a54355fd7 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,50 +1,51 @@ total - [exports] : 2 - [funcs] : 2 + [exports] : 6 + [funcs] : 16 [globals] : 24 [imports] : 5 [memories] : 1 [memory-data] : 20 - [table-data] : 0 + [table-data] : 2 [tables] : 1 [tags] : 1 - [total] : 524 - [vars] : 36 - ArrayCopy : 1 - ArrayFill : 1 - ArrayGet : 2 - ArrayLen : 4 - ArrayNew : 19 - AtomicNotify : 1 - Binary : 71 - Block : 30 - Break : 2 - Call : 5 - Const : 135 - Drop : 2 - GlobalGet : 12 - GlobalSet : 6 - If : 16 + [total] : 653 + [vars] : 75 + ArrayGet : 1 + ArrayLen : 1 + ArrayNew : 8 + ArrayNewFixed : 4 + Binary : 75 + Block : 83 + Break : 4 + Call : 15 + Const : 125 + Drop : 4 + GlobalGet : 52 + GlobalSet : 40 + If : 26 Load : 18 - LocalGet : 66 - LocalSet : 41 - Loop : 2 - Nop : 5 + LocalGet : 46 + LocalSet : 32 + Loop : 5 + Nop : 3 Pop : 3 - RefAs : 14 + RefAs : 6 RefCast : 1 - RefNull : 12 - RefTest : 2 - Return : 1 - Select : 1 - Store : 2 - StringConst : 4 - StringEncode : 1 + RefEq : 1 + RefFunc : 5 + RefI31 : 1 + RefIsNull : 1 + RefNull : 7 + RefTest : 1 + Return : 5 + Select : 3 + StringConst : 6 StringEq : 1 - StringMeasure : 1 - StructNew : 13 - Try : 4 - TupleExtract : 3 + StringWTF16Get : 1 + StructGet : 1 + StructNew : 8 + Try : 3 + TupleExtract : 2 TupleMake : 11 - Unary : 8 - Unreachable : 3 + Unary : 23 + Unreachable : 21 From 52a6d8d2645a50dd411212b02e88d5539576c838 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 17 May 2024 16:51:17 -0700 Subject: [PATCH 07/10] bettr --- src/tools/fuzzing/fuzzing.cpp | 4 +++- src/tools/fuzzing/parameters.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index e0b9b1d1911..238c7593167 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -411,7 +411,9 @@ void TranslateToFuzzReader::setupGlobals() { // Create new random globals. for (size_t index = upTo(MAX_GLOBALS); index > 0; --index) { auto type = getConcreteType(); - auto mutability = oneIn(2) ? Builder::Mutable : Builder::Immutable; + // Prefer immutable ones as they can be used in global.gets in other + // globals, for more interesting patterns. + auto mutability = oneIn(3) ? Builder::Mutable : Builder::Immutable; // We can only make something trivial (like a constant) in a global // initializer. diff --git a/src/tools/fuzzing/parameters.h b/src/tools/fuzzing/parameters.h index 72b5640b4ca..eede193a7f3 100644 --- a/src/tools/fuzzing/parameters.h +++ b/src/tools/fuzzing/parameters.h @@ -30,7 +30,7 @@ constexpr int MAX_PARAMS = 10; constexpr int MAX_VARS = 20; // The maximum number of globals in a module. -constexpr int MAX_GLOBALS = 25; +constexpr int MAX_GLOBALS = 30; // The maximum number of tuple elements. constexpr int MAX_TUPLE_SIZE = 6; From e6bd6f26551601d01d38ab6ad14db441764b67df Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 17 May 2024 16:52:45 -0700 Subject: [PATCH 08/10] bettr --- test/passes/fuzz_metrics_noprint.bin.txt | 53 ++++++------ ...e-to-fuzz_all-features_metrics_noprint.txt | 82 ++++++++++--------- 2 files changed, 72 insertions(+), 63 deletions(-) diff --git a/test/passes/fuzz_metrics_noprint.bin.txt b/test/passes/fuzz_metrics_noprint.bin.txt index 0fbc46028dc..c5dab17e75b 100644 --- a/test/passes/fuzz_metrics_noprint.bin.txt +++ b/test/passes/fuzz_metrics_noprint.bin.txt @@ -1,33 +1,34 @@ total - [exports] : 37 - [funcs] : 60 + [exports] : 23 + [funcs] : 34 [globals] : 9 [imports] : 4 [memories] : 1 [memory-data] : 2 - [table-data] : 23 + [table-data] : 6 [tables] : 1 [tags] : 0 - [total] : 6655 - [vars] : 169 - Binary : 504 - Block : 1108 - Break : 211 - Call : 209 - CallIndirect : 54 - Const : 1049 - Drop : 70 - GlobalGet : 562 - GlobalSet : 421 - If : 361 - Load : 126 - LocalGet : 482 - LocalSet : 377 - Loop : 145 - Nop : 107 - RefFunc : 23 - Return : 84 - Select : 40 - Store : 58 - Unary : 456 - Unreachable : 208 + [total] : 4303 + [vars] : 100 + Binary : 355 + Block : 684 + Break : 149 + Call : 219 + CallIndirect : 23 + Const : 643 + Drop : 50 + GlobalGet : 367 + GlobalSet : 258 + If : 206 + Load : 78 + LocalGet : 339 + LocalSet : 236 + Loop : 93 + Nop : 41 + RefFunc : 6 + Return : 45 + Select : 41 + Store : 36 + Switch : 1 + Unary : 304 + Unreachable : 129 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 74a54355fd7..57650cb2475 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,51 +1,59 @@ total - [exports] : 6 - [funcs] : 16 + [exports] : 3 + [funcs] : 4 [globals] : 24 [imports] : 5 [memories] : 1 [memory-data] : 20 - [table-data] : 2 + [table-data] : 3 [tables] : 1 [tags] : 1 - [total] : 653 - [vars] : 75 - ArrayGet : 1 - ArrayLen : 1 - ArrayNew : 8 - ArrayNewFixed : 4 - Binary : 75 - Block : 83 - Break : 4 - Call : 15 - Const : 125 - Drop : 4 - GlobalGet : 52 - GlobalSet : 40 - If : 26 - Load : 18 - LocalGet : 46 - LocalSet : 32 - Loop : 5 - Nop : 3 + [total] : 750 + [vars] : 30 + ArrayCopy : 1 + ArrayGet : 2 + ArrayLen : 5 + ArrayNew : 24 + ArrayNewFixed : 1 + ArraySet : 1 + AtomicCmpxchg : 1 + AtomicFence : 1 + AtomicRMW : 1 + Binary : 84 + Block : 58 + Break : 12 + Call : 13 + Const : 175 + Drop : 2 + GlobalGet : 45 + GlobalSet : 20 + I31Get : 2 + If : 21 + Load : 20 + LocalGet : 70 + LocalSet : 46 + Loop : 7 + MemoryCopy : 1 + Nop : 11 Pop : 3 - RefAs : 6 - RefCast : 1 + RefAs : 7 RefEq : 1 RefFunc : 5 - RefI31 : 1 - RefIsNull : 1 - RefNull : 7 - RefTest : 1 - Return : 5 + RefI31 : 7 + RefIsNull : 3 + RefNull : 19 + RefTest : 3 + Return : 2 + SIMDTernary : 1 Select : 3 - StringConst : 6 - StringEq : 1 + Store : 1 + StringConst : 8 + StringEncode : 1 + StringMeasure : 1 StringWTF16Get : 1 StructGet : 1 - StructNew : 8 + StructNew : 21 Try : 3 - TupleExtract : 2 - TupleMake : 11 - Unary : 23 - Unreachable : 21 + TupleMake : 6 + Unary : 19 + Unreachable : 10 From 36b86e4d0809092b5043c3794aac112f6501998f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 20 May 2024 12:44:24 -0700 Subject: [PATCH 09/10] fix --- src/tools/fuzzing/fuzzing.cpp | 8 +++++++- src/wasm/wasm-binary.cpp | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 238c7593167..248bab33030 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1914,7 +1914,13 @@ Expression* TranslateToFuzzReader::makeGlobalGet(Type type) { : (wasm.features.hasGC() ? immutableGlobalsByType : importedImmutableGlobalsByType); auto it = relevantGlobals.find(type); - if (it == relevantGlobals.end() || it->second.empty()) { + // If we have no such relevant globals give up and emit a constant instead. + // We also do so if this is a tuple type and we are not in a function, because + // atm tuple globals have only limited support, and in particular we do not + // support a global.get from one such global to another (a tuple global must + // contain a tuple.make instruction). + if (it == relevantGlobals.end() || it->second.empty() || + (type.isTuple() && !funcContext)) { return makeConst(type); } diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index befafde599f..4888310b831 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -572,8 +572,23 @@ void WasmBinaryWriter::writeGlobals() { o << U32LEB(global->mutable_); if (global->type.size() == 1) { writeExpression(global->init); + } else if (auto* make = global->init->dynCast()) { + // Emit the proper lane for this global. + writeExpression(make->operands[i]); } else { - writeExpression(global->init->cast()->operands[i]); + // For now tuple globals must contain tuple.make. We could perhaps + // support more operations, like global.get, but the code would need to + // look something like this: + // + // auto parentIndex = getGlobalIndex(get->name); + // o << int8_t(BinaryConsts::GlobalGet) << U32LEB(parentIndex + i); + // + // That is, we must emit the instruction here, and not defer to + // writeExpression, as writeExpression writes an entire expression at a + // time (and not just one of the lanes). As emitting an instruction here + // is less clean, and there is no important use case for global.get of + // one tuple global to another, we disallow this. + WASM_UNREACHABLE("unsupported tuple global operation"); } o << int8_t(BinaryConsts::End); ++i; From 3fb0381d0d203a4051a757107616dc359cc81a06 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 21 May 2024 10:34:02 -0700 Subject: [PATCH 10/10] refactor --- src/tools/fuzzing/fuzzing.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 248bab33030..f4f059deb43 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -427,6 +427,12 @@ void TranslateToFuzzReader::setupGlobals() { // validate in a global. Switch to something safe instead. type = getMVPType(); init = makeConst(type); + } else if (type.isTuple() && !init->is()) { + // For now we disallow anything but tuple.make at the top level of tuple + // globals (see details in wasm-binary.cpp). In the future we may allow + // global.get or other things here. + init = makeConst(type); + assert(init->is()); } auto global = builder.makeGlobal( Names::getValidGlobalName(wasm, "global$"), type, init, mutability); @@ -1915,12 +1921,7 @@ Expression* TranslateToFuzzReader::makeGlobalGet(Type type) { : importedImmutableGlobalsByType); auto it = relevantGlobals.find(type); // If we have no such relevant globals give up and emit a constant instead. - // We also do so if this is a tuple type and we are not in a function, because - // atm tuple globals have only limited support, and in particular we do not - // support a global.get from one such global to another (a tuple global must - // contain a tuple.make instruction). - if (it == relevantGlobals.end() || it->second.empty() || - (type.isTuple() && !funcContext)) { + if (it == relevantGlobals.end() || it->second.empty()) { return makeConst(type); }