From e11f7ae6a73ac724d72f619ff05c818f547541ee Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 21 Oct 2024 15:42:00 -0700 Subject: [PATCH 01/25] start --- scripts/fuzz_shell.js | 7 +++++ src/tools/execution-results.h | 51 ++++++++++++++++++++++------------- src/tools/fuzzing.h | 3 +++ src/tools/fuzzing/fuzzing.cpp | 14 ++++++++++ 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/scripts/fuzz_shell.js b/scripts/fuzz_shell.js index 3d29b197ce8..dad9d920361 100644 --- a/scripts/fuzz_shell.js +++ b/scripts/fuzz_shell.js @@ -138,6 +138,7 @@ function logValue(x, y) { var tempRet0; var imports = { 'fuzzing-support': { + // Logging. 'log-i32': logValue, 'log-i64': logValue, 'log-f32': logValue, @@ -147,7 +148,13 @@ var imports = { // we could avoid running JS on code with SIMD in it, but it is useful to // fuzz such code as much as we can.) 'log-v128': logValue, + + // Throw an exception from JS. + 'throw': { + throw 'some JS error'; + } }, + // Emscripten support. 'env': { 'setTempRet0': function(x) { tempRet0 = x }, 'getTempRet0': function() { return tempRet0 }, diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 920bb200ac6..53e78884d3d 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -27,8 +27,12 @@ using Loggings = std::vector; // Logs every relevant import call parameter. struct LoggingExternalInterface : public ShellExternalInterface { +private: Loggings& loggings; + // A tag used for fuzzing support throwing. + Tag privateTag; + struct State { // Legalization for JS emits get/setTempRet0 calls ("temp ret 0" means a // temporary return value of 32 bits; "0" is the only important value for @@ -37,30 +41,39 @@ struct LoggingExternalInterface : public ShellExternalInterface { uint32_t tempRet0 = 0; } state; - LoggingExternalInterface(Loggings& loggings) : loggings(loggings) {} +public: + LoggingExternalInterface(Loggings& loggings) : loggings(loggings), privateTag(Signature(Type::none, Type::none)) {} Literals callImport(Function* import, const Literals& arguments) override { if (import->module == "fuzzing-support") { - std::cout << "[LoggingExternalInterface logging"; - loggings.push_back(Literal()); // buffer with a None between calls - for (auto argument : arguments) { - if (argument.type == Type::i64) { - // To avoid JS legalization changing logging results, treat a logging - // of an i64 as two i32s (which is what legalization would turn us - // into). - auto low = Literal(int32_t(argument.getInteger())); - auto high = Literal(int32_t(argument.getInteger() >> int32_t(32))); - std::cout << ' ' << low; - loggings.push_back(low); - std::cout << ' ' << high; - loggings.push_back(high); - } else { - std::cout << ' ' << argument; - loggings.push_back(argument); + if (import->base.startsWith("log-")) { + // This is a logging function like log-i32 or log-f64 + std::cout << "[LoggingExternalInterface logging"; + loggings.push_back(Literal()); // buffer with a None between calls + for (auto argument : arguments) { + if (argument.type == Type::i64) { + // To avoid JS legalization changing logging results, treat a + // logging of an i64 as two i32s (which is what legalization would + // turn us into). + auto low = Literal(int32_t(argument.getInteger())); + auto high = Literal(int32_t(argument.getInteger() >> int32_t(32))); + std::cout << ' ' << low; + loggings.push_back(low); + std::cout << ' ' << high; + loggings.push_back(high); + } else { + std::cout << ' ' << argument; + loggings.push_back(argument); + } } + std::cout << "]\n"; + return {}; + } else if (import->base == "throw") { + // Throw something. We create a new Tag here, unrelated to those in the + // wasm. + auto payload = std::make_shared(privateTag, payload); + throwException(WasmException{payload}); } - std::cout << "]\n"; - return {}; } else if (import->module == ENV) { if (import->base == "log_execution") { std::cout << "[LoggingExternalInterface log-execution"; diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 92e99791341..30eb2c22025 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -220,7 +220,10 @@ class TranslateToFuzzReader { void finalizeTable(); void prepareHangLimitSupport(); void addHangLimitSupport(); + // Imports that we call to log out values. void addImportLoggingSupport(); + // An import that we call to throw a wasm exception from outside. + void addImportThrowingSupport(); void addHashMemorySupport(); // Special expression makers diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index d3f52d3b0ec..37549fc47de 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -179,6 +179,7 @@ void TranslateToFuzzReader::build() { } modifyInitialFunctions(); addImportLoggingSupport(); + addImportThrowingSupport(); // keep adding functions until we run out of input while (!random.finished()) { auto* func = addFunction(); @@ -593,6 +594,19 @@ void TranslateToFuzzReader::addImportLoggingSupport() { } } +void TranslateToFuzzReader::addImportThrowingSupport() { + // Throw some kind of exception from JS. + // TODO: Send an index, which is which exported wasm Tag we should throw, or + // something not exported if out of bounds. First we must also export + // tags sometimes. + auto* func = new Function; + func->name = "throw"; + func->module = "fuzzing-support"; + func->base = name; + func->type = Signature(Type::none, Type::none); + wasm.addFunction(func); +} + void TranslateToFuzzReader::addHashMemorySupport() { // Add memory hasher helper (for the hash, see hash.h). The function looks // like: From a494c2af2cc4393e1cdff04b8c5f5870e1573556 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 21 Oct 2024 15:44:07 -0700 Subject: [PATCH 02/25] buildz --- src/tools/execution-results.h | 4 +++- src/tools/fuzzing/fuzzing.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 53e78884d3d..a32145e2467 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -42,7 +42,9 @@ struct LoggingExternalInterface : public ShellExternalInterface { } state; public: - LoggingExternalInterface(Loggings& loggings) : loggings(loggings), privateTag(Signature(Type::none, Type::none)) {} + LoggingExternalInterface(Loggings& loggings) : loggings(loggings) { + privateTag.sig = Signature(Type::none, Type::none); + } Literals callImport(Function* import, const Literals& arguments) override { if (import->module == "fuzzing-support") { diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 37549fc47de..7cf48736822 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -602,7 +602,7 @@ void TranslateToFuzzReader::addImportThrowingSupport() { auto* func = new Function; func->name = "throw"; func->module = "fuzzing-support"; - func->base = name; + func->base = func->name; func->type = Signature(Type::none, Type::none); wasm.addFunction(func); } From b3759d974b96c4b12c0a35ad7a1042615521935a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 21 Oct 2024 15:49:00 -0700 Subject: [PATCH 03/25] buildz.for.real --- src/tools/execution-results.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index a32145e2467..c635e8dd5e6 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -72,9 +72,11 @@ struct LoggingExternalInterface : public ShellExternalInterface { return {}; } else if (import->base == "throw") { // Throw something. We create a new Tag here, unrelated to those in the - // wasm. - auto payload = std::make_shared(privateTag, payload); - throwException(WasmException{payload}); + // wasm. XXX no need for tag, just name + Name name("private-tag"); + Literals empty; + auto payload = std::make_shared(name, empty); + throwException(WasmException{Literal(payload)}); } } else if (import->module == ENV) { if (import->base == "log_execution") { From d8c300df1debdbb7359e3ccd66b1e3717de8aacd Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 21 Oct 2024 15:53:28 -0700 Subject: [PATCH 04/25] call --- src/tools/fuzzing.h | 3 ++- src/tools/fuzzing/fuzzing.cpp | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 30eb2c22025..3905fdff43f 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -228,7 +228,8 @@ class TranslateToFuzzReader { // Special expression makers Expression* makeHangLimitCheck(); - Expression* makeLogging(); + Expression* makeImportLogging(); + Expression* makeImportThrowing(Type type); Expression* makeMemoryHashLogging(); // Function creation diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 7cf48736822..60746fd856e 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -706,12 +706,19 @@ Expression* TranslateToFuzzReader::makeHangLimitCheck() { builder.makeConst(int32_t(1))))); } -Expression* TranslateToFuzzReader::makeLogging() { +Expression* TranslateToFuzzReader::makeImportLogging() { auto type = getLoggableType(); return builder.makeCall( std::string("log-") + type.toString(), {make(type)}, Type::none); } +Expression* TranslateToFuzzReader::makeImportThrowing(Type type) { + // We throw from the import, so this call appears to be none and not + // unreachable. + assert(type == Type::none); + return builder.makeCall("throw", {}, Type::none); +} + Expression* TranslateToFuzzReader::makeMemoryHashLogging() { auto* hash = builder.makeCall(std::string("hashMemory"), {}, Type::i32); return builder.makeCall(std::string("log-i32"), {hash}, Type::none); @@ -1444,7 +1451,7 @@ Expression* TranslateToFuzzReader::_makenone() { auto choice = upTo(100); if (choice < LOGGING_PERCENT) { if (choice < LOGGING_PERCENT / 2) { - return makeLogging(); + return makeImportLogging(); } else { return makeMemoryHashLogging(); } @@ -1469,6 +1476,7 @@ Expression* TranslateToFuzzReader::_makenone() { .add(FeatureSet::Atomics, &Self::makeAtomic) .add(FeatureSet::ExceptionHandling, &Self::makeTry) .add(FeatureSet::ExceptionHandling, &Self::makeTryTable) + .add(FeatureSet::ExceptionHandling, &Self::makeImportThrowing) .add(FeatureSet::ReferenceTypes | FeatureSet::GC, &Self::makeCallRef) .add(FeatureSet::ReferenceTypes | FeatureSet::GC, &Self::makeStructSet) .add(FeatureSet::ReferenceTypes | FeatureSet::GC, &Self::makeArraySet) From c002b78d5bd6bae7b3c2a0ef679d4099900a7af7 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 21 Oct 2024 15:55:20 -0700 Subject: [PATCH 05/25] oops --- scripts/fuzz_shell.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/fuzz_shell.js b/scripts/fuzz_shell.js index dad9d920361..4cf3ba35866 100644 --- a/scripts/fuzz_shell.js +++ b/scripts/fuzz_shell.js @@ -150,7 +150,7 @@ var imports = { 'log-v128': logValue, // Throw an exception from JS. - 'throw': { + 'throw': () => { throw 'some JS error'; } }, From bcbae0d60f701971e60d47a25db0508445872856 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 21 Oct 2024 16:14:37 -0700 Subject: [PATCH 06/25] fix --- src/tools/fuzzing.h | 2 ++ src/tools/fuzzing/fuzzing.cpp | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 3905fdff43f..77214ab573e 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -104,6 +104,8 @@ class TranslateToFuzzReader { Name funcrefTableName; + Name throwImportName; + std::unordered_map> globalsByType; std::unordered_map> mutableGlobalsByType; std::unordered_map> immutableGlobalsByType; diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 60746fd856e..cd055a8c739 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -599,10 +599,11 @@ void TranslateToFuzzReader::addImportThrowingSupport() { // TODO: Send an index, which is which exported wasm Tag we should throw, or // something not exported if out of bounds. First we must also export // tags sometimes. + throwImportName = Names::getValidFunctionName(wasm, "throw"); auto* func = new Function; - func->name = "throw"; + func->name = throwImportName; func->module = "fuzzing-support"; - func->base = func->name; + func->base = "throw"; func->type = Signature(Type::none, Type::none); wasm.addFunction(func); } @@ -716,7 +717,9 @@ Expression* TranslateToFuzzReader::makeImportThrowing(Type type) { // We throw from the import, so this call appears to be none and not // unreachable. assert(type == Type::none); - return builder.makeCall("throw", {}, Type::none); + + // TODO: This and makeThrow should probably be rare, as they halt the program. + return builder.makeCall(throwImportName, {}, Type::none); } Expression* TranslateToFuzzReader::makeMemoryHashLogging() { From 33d473245243a2c4ce89db32f9390d425ed57872 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 21 Oct 2024 16:21:33 -0700 Subject: [PATCH 07/25] simpl --- src/tools/execution-results.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index c635e8dd5e6..989b3c7c421 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -71,11 +71,8 @@ struct LoggingExternalInterface : public ShellExternalInterface { std::cout << "]\n"; return {}; } else if (import->base == "throw") { - // Throw something. We create a new Tag here, unrelated to those in the - // wasm. XXX no need for tag, just name - Name name("private-tag"); - Literals empty; - auto payload = std::make_shared(name, empty); + // Throw something. We use a (hopefully) private name here. + auto payload = std::make_shared("__private", Literals{}); throwException(WasmException{Literal(payload)}); } } else if (import->module == ENV) { From 631a20f7fbf68d9b9809e0c513a333eee48765d6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 21 Oct 2024 16:25:26 -0700 Subject: [PATCH 08/25] fix --- src/tools/fuzzing/fuzzing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index cd055a8c739..d15f2cbd887 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -176,10 +176,10 @@ void TranslateToFuzzReader::build() { setupGlobals(); if (wasm.features.hasExceptionHandling()) { setupTags(); + addImportThrowingSupport(); } modifyInitialFunctions(); addImportLoggingSupport(); - addImportThrowingSupport(); // keep adding functions until we run out of input while (!random.finished()) { auto* func = addFunction(); From 13e8e0c5affab9065ac4db6f5b297b8ce663ff61 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 09:39:30 -0700 Subject: [PATCH 09/25] fix --- src/tools/fuzzing/fuzzing.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index d15f2cbd887..1e15a9977a0 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1239,15 +1239,18 @@ void TranslateToFuzzReader::modifyInitialFunctions() { // the end (currently that is not needed atm, but it might in the future). for (Index i = 0; i < wasm.functions.size(); i++) { auto* func = wasm.functions[i].get(); - FunctionCreationContext context(*this, func); if (func->imported()) { // We can't allow extra imports, as the fuzzing infrastructure wouldn't - // know what to provide. + // know what to provide. Keep only our own fuzzer imports. + if (func->module == "fuzzing-support") { + continue; + } func->module = func->base = Name(); func->body = make(func->getResults()); } // Optionally, fuzz the function contents. if (upTo(RESOLUTION) >= chance) { + FunctionCreationContext context(*this, func); dropToLog(func); // Notice params as well as any locals generated above. // TODO add some locals? and the rest of addFunction's operations? From 77c879dcff7f6fae98ce4c828e3b3d7ff1dcd7e9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 09:48:48 -0700 Subject: [PATCH 10/25] fix --- src/tools/fuzzing/fuzzing.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 1e15a9977a0..e9c0acca030 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1239,18 +1239,18 @@ void TranslateToFuzzReader::modifyInitialFunctions() { // the end (currently that is not needed atm, but it might in the future). for (Index i = 0; i < wasm.functions.size(); i++) { auto* func = wasm.functions[i].get(); + // We can't allow extra imports, as the fuzzing infrastructure wouldn't + // know what to provide. Keep only our own fuzzer imports. + if (func->imported() && func->module == "fuzzing-support") { + continue; + } + FunctionCreationContext context(*this, func); if (func->imported()) { - // We can't allow extra imports, as the fuzzing infrastructure wouldn't - // know what to provide. Keep only our own fuzzer imports. - if (func->module == "fuzzing-support") { - continue; - } func->module = func->base = Name(); func->body = make(func->getResults()); } // Optionally, fuzz the function contents. if (upTo(RESOLUTION) >= chance) { - FunctionCreationContext context(*this, func); dropToLog(func); // Notice params as well as any locals generated above. // TODO add some locals? and the rest of addFunction's operations? From fc34b327f10aa7b6f01c29d39a221d9a7aae2307 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 11:32:29 -0700 Subject: [PATCH 11/25] update --- ...e-to-fuzz_all-features_metrics_noprint.txt | 83 ++++++++++--------- 1 file changed, 45 insertions(+), 38 deletions(-) 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 3cc84161097..c17c9cd1eea 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,58 @@ Metrics total - [exports] : 4 - [funcs] : 7 + [exports] : 3 + [funcs] : 4 [globals] : 26 - [imports] : 5 + [imports] : 6 [memories] : 1 [memory-data] : 20 - [table-data] : 2 + [table-data] : 0 [tables] : 1 [tags] : 2 - [total] : 510 - [vars] : 15 - ArrayNew : 14 - ArrayNewFixed : 2 - AtomicFence : 1 - Binary : 64 - Block : 45 - Break : 2 - Call : 8 + [total] : 665 + [vars] : 20 + ArrayGet : 2 + ArrayLen : 2 + ArrayNew : 15 + ArrayNewFixed : 3 + AtomicCmpxchg : 1 + AtomicRMW : 1 + Binary : 71 + Block : 63 + BrOn : 4 + Break : 7 + Call : 18 CallRef : 2 - Const : 127 - Drop : 5 - GlobalGet : 28 + Const : 142 + Drop : 10 + GlobalGet : 33 GlobalSet : 16 - If : 12 - Load : 18 - LocalGet : 46 - LocalSet : 29 - Loop : 3 - MemoryCopy : 1 + I31Get : 1 + If : 21 + Load : 20 + LocalGet : 61 + LocalSet : 52 + Loop : 6 + MemoryFill : 1 MemoryInit : 1 - Nop : 4 - Pop : 2 - RefCast : 1 - RefFunc : 7 - RefNull : 6 - Return : 9 + Nop : 7 + Pop : 1 + RefAs : 11 + RefEq : 1 + RefFunc : 3 + RefI31 : 1 + RefNull : 14 + Return : 5 SIMDExtract : 1 - Store : 1 - StringConst : 7 - StringEq : 1 - StringMeasure : 1 - StringSliceWTF : 1 - StructNew : 14 - Try : 2 + Select : 2 + StringConst : 5 + StringEncode : 1 + StructGet : 4 + StructNew : 16 + StructSet : 1 + Try : 1 TryTable : 1 - TupleExtract : 3 + TupleExtract : 2 TupleMake : 6 - Unary : 9 - Unreachable : 10 + Unary : 20 + Unreachable : 9 From 1a0ae632dcd55db6124b1adea0fec13ed120cad8 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 11:33:18 -0700 Subject: [PATCH 12/25] work --- src/tools/execution-results.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 989b3c7c421..38231365231 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -30,9 +30,6 @@ struct LoggingExternalInterface : public ShellExternalInterface { private: Loggings& loggings; - // A tag used for fuzzing support throwing. - Tag privateTag; - struct State { // Legalization for JS emits get/setTempRet0 calls ("temp ret 0" means a // temporary return value of 32 bits; "0" is the only important value for From 73117d22d79ac576215cd74a2f00d3fc8929d374 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 11:33:44 -0700 Subject: [PATCH 13/25] work --- src/tools/execution-results.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 38231365231..85e0b1aafe7 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -39,9 +39,7 @@ struct LoggingExternalInterface : public ShellExternalInterface { } state; public: - LoggingExternalInterface(Loggings& loggings) : loggings(loggings) { - privateTag.sig = Signature(Type::none, Type::none); - } + LoggingExternalInterface(Loggings& loggings) : loggings(loggings) {} Literals callImport(Function* import, const Literals& arguments) override { if (import->module == "fuzzing-support") { From 383059aa6b0a91aa4ee6c4d3d9f1d430cc229f25 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 11:35:54 -0700 Subject: [PATCH 14/25] text --- src/tools/fuzzing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 77214ab573e..65cbb3122a1 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -224,7 +224,7 @@ class TranslateToFuzzReader { void addHangLimitSupport(); // Imports that we call to log out values. void addImportLoggingSupport(); - // An import that we call to throw a wasm exception from outside. + // An import that we call to throw an exception from outside. void addImportThrowingSupport(); void addHashMemorySupport(); From c9689df49e359c26121dc278f3ab8f2a722fa5f5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 11:54:41 -0700 Subject: [PATCH 15/25] update existing test: we now differentiate between imports from fuzzing-support, and logging funcs must start with 'log-' --- test/lit/exec/host-limit.wast | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lit/exec/host-limit.wast b/test/lit/exec/host-limit.wast index e64a47d8a3f..ba5087f6942 100644 --- a/test/lit/exec/host-limit.wast +++ b/test/lit/exec/host-limit.wast @@ -9,7 +9,7 @@ (module (type $type$0 (array i8)) - (import "fuzzing-support" "log" (func $log (param i32))) + (import "fuzzing-support" "log-i32" (func $log (param i32))) (global $global (mut (ref $type$0)) (array.new_default $type$0 (i32.const -1) From ea1f8ee5911f920735179423aed4bd94b1f009c1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 12:53:23 -0700 Subject: [PATCH 16/25] feedback --- src/tools/execution-results.h | 2 ++ src/tools/fuzzing/fuzzing.cpp | 13 +++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 85e0b1aafe7..74d72dd8c13 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -69,6 +69,8 @@ struct LoggingExternalInterface : public ShellExternalInterface { // Throw something. We use a (hopefully) private name here. auto payload = std::make_shared("__private", Literals{}); throwException(WasmException{Literal(payload)}); + } else { + WASM_UNREACHABLE("unknown fuzzer import"); } } else if (import->module == ENV) { if (import->base == "log_execution") { diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index e9c0acca030..45019817c58 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -584,13 +584,13 @@ void TranslateToFuzzReader::addHangLimitSupport() { void TranslateToFuzzReader::addImportLoggingSupport() { for (auto type : loggableTypes) { - auto* func = new Function; + auto func = std::make_unique(); Name name = std::string("log-") + type.toString(); func->name = name; func->module = "fuzzing-support"; func->base = name; func->type = Signature(type, Type::none); - wasm.addFunction(func); + wasm.addFunction(std::move(func)); } } @@ -600,12 +600,12 @@ void TranslateToFuzzReader::addImportThrowingSupport() { // something not exported if out of bounds. First we must also export // tags sometimes. throwImportName = Names::getValidFunctionName(wasm, "throw"); - auto* func = new Function; + auto func = std::make_unique(); func->name = throwImportName; func->module = "fuzzing-support"; func->base = "throw"; func->type = Signature(Type::none, Type::none); - wasm.addFunction(func); + wasm.addFunction(std::move(func)); } void TranslateToFuzzReader::addHashMemorySupport() { @@ -730,7 +730,8 @@ Expression* TranslateToFuzzReader::makeMemoryHashLogging() { // TODO: return std::unique_ptr Function* TranslateToFuzzReader::addFunction() { LOGGING_PERCENT = upToSquared(100); - auto* func = new Function; + auto allocation = std::make_unique(); + auto* func = allocation.get(); func->name = Names::getValidFunctionName(wasm, "func"); FunctionCreationContext context(*this, func); assert(funcContext->typeLocals.empty()); @@ -789,7 +790,7 @@ Function* TranslateToFuzzReader::addFunction() { } // Add hang limit checks after all other operations on the function body. - wasm.addFunction(func); + wasm.addFunction(std::move(allocation)); // Export some functions, but not all (to allow inlining etc.). Try to export // at least one, though, to keep each testcase interesting. Only functions // with valid params and returns can be exported because the trap fuzzer From cd292a826f0ed88abf8d8313e813765591f1483d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 12:53:26 -0700 Subject: [PATCH 17/25] test --- test/lit/exec/fuzzing-api.wast | 39 ++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 test/lit/exec/fuzzing-api.wast diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast new file mode 100644 index 00000000000..d37d7ef4a35 --- /dev/null +++ b/test/lit/exec/fuzzing-api.wast @@ -0,0 +1,39 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --output=fuzz-exec and should not be edited. + +;; RUN: wasm-opt %s -all --fuzz-exec -o /dev/null 2>&1 | filecheck %s + +;; Test the fuzzing-support module imports. + +(module + (import "fuzzing-support" "log-i32" (func $log-i32 (param i32))) + (import "fuzzing-support" "log-f64" (func $log-f64 (param f64))) + + (import "fuzzing-support" "throw" (func $throw)) + + ;; CHECK: [fuzz-exec] calling logging + ;; CHECK-NEXT: [LoggingExternalInterface logging 42] + ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] + (func $logging (export "logging") + (call $log-i32 + (i32.const 42) + ) + (call $log-f64 + (f64.const 3.14159) + ) + ) + + ;; CHECK: [fuzz-exec] calling throwing + ;; CHECK-NEXT: [exception thrown: __private ()] + ;; CHECK-NEXT: warning: no passes specified, not doing any work + (func $throwing (export "throwing") + (call $throw) + ) +) +;; CHECK: [fuzz-exec] calling logging +;; CHECK-NEXT: [LoggingExternalInterface logging 42] +;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] + +;; CHECK: [fuzz-exec] calling throwing +;; CHECK-NEXT: [exception thrown: __private ()] +;; CHECK-NEXT: [fuzz-exec] comparing logging +;; CHECK-NEXT: [fuzz-exec] comparing throwing From 3bbec24398e1a142641b6fe57ea0509eb5402e79 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 13:02:10 -0700 Subject: [PATCH 18/25] avoid hardcoded logging import names --- src/tools/fuzzing.h | 2 ++ src/tools/fuzzing/fuzzing.cpp | 16 ++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 65cbb3122a1..69fee656c07 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -104,6 +104,8 @@ class TranslateToFuzzReader { Name funcrefTableName; + std::unordered_map logImportNames; + Name throwImportName; std::unordered_map> globalsByType; diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 45019817c58..c05a67a2298 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -585,10 +585,11 @@ void TranslateToFuzzReader::addHangLimitSupport() { void TranslateToFuzzReader::addImportLoggingSupport() { for (auto type : loggableTypes) { auto func = std::make_unique(); - Name name = std::string("log-") + type.toString(); - func->name = name; + Name baseName = std::string("log-") + type.toString(); + func->name = Names::getValidFunctionName(wasm, baseName); + logImportNames[type] = func->name; func->module = "fuzzing-support"; - func->base = name; + func->base = baseName; func->type = Signature(type, Type::none); wasm.addFunction(std::move(func)); } @@ -709,8 +710,7 @@ Expression* TranslateToFuzzReader::makeHangLimitCheck() { Expression* TranslateToFuzzReader::makeImportLogging() { auto type = getLoggableType(); - return builder.makeCall( - std::string("log-") + type.toString(), {make(type)}, Type::none); + return builder.makeCall(logImportNames[type], {make(type)}, Type::none); } Expression* TranslateToFuzzReader::makeImportThrowing(Type type) { @@ -724,7 +724,7 @@ Expression* TranslateToFuzzReader::makeImportThrowing(Type type) { Expression* TranslateToFuzzReader::makeMemoryHashLogging() { auto* hash = builder.makeCall(std::string("hashMemory"), {}, Type::i32); - return builder.makeCall(std::string("log-i32"), {hash}, Type::none); + return builder.makeCall(logImportNames[Type::i32], {hash}, Type::none); } // TODO: return std::unique_ptr @@ -1289,8 +1289,8 @@ void TranslateToFuzzReader::dropToLog(Function* func) { void visitDrop(Drop* curr) { if (parent.isLoggableType(curr->value->type) && parent.oneIn(2)) { - replaceCurrent(parent.builder.makeCall(std::string("log-") + - curr->value->type.toString(), + auto target = parent.logImportNames[curr->value->type]; + replaceCurrent(parent.builder.makeCall(target, {curr->value}, Type::none)); } From b6fa6bcbb1e37d27f48083970d170026b183f1e2 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 13:02:39 -0700 Subject: [PATCH 19/25] format --- src/tools/fuzzing/fuzzing.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index c05a67a2298..a284b71e3f5 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1290,9 +1290,8 @@ void TranslateToFuzzReader::dropToLog(Function* func) { void visitDrop(Drop* curr) { if (parent.isLoggableType(curr->value->type) && parent.oneIn(2)) { auto target = parent.logImportNames[curr->value->type]; - replaceCurrent(parent.builder.makeCall(target, - {curr->value}, - Type::none)); + replaceCurrent( + parent.builder.makeCall(target, {curr->value}, Type::none)); } } }; From be58b10f5feeda0ec135651a59a08ae26970fdbb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 13:04:55 -0700 Subject: [PATCH 20/25] fix --- src/tools/fuzzing/fuzzing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index a284b71e3f5..b7d075dccfb 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -178,8 +178,8 @@ void TranslateToFuzzReader::build() { setupTags(); addImportThrowingSupport(); } - modifyInitialFunctions(); addImportLoggingSupport(); + modifyInitialFunctions(); // keep adding functions until we run out of input while (!random.finished()) { auto* func = addFunction(); From 2b266df083573d77df424a6466041ab7f2cd12ef Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 13:38:35 -0700 Subject: [PATCH 21/25] update --- test/passes/fuzz_metrics_noprint.bin.txt | 52 ++++++++++++------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/test/passes/fuzz_metrics_noprint.bin.txt b/test/passes/fuzz_metrics_noprint.bin.txt index 2f1719633b8..fab2ccc9d63 100644 --- a/test/passes/fuzz_metrics_noprint.bin.txt +++ b/test/passes/fuzz_metrics_noprint.bin.txt @@ -1,35 +1,35 @@ Metrics total - [exports] : 23 - [funcs] : 34 + [exports] : 50 + [funcs] : 72 [globals] : 9 [imports] : 4 [memories] : 1 [memory-data] : 2 - [table-data] : 6 + [table-data] : 25 [tables] : 1 [tags] : 0 - [total] : 4303 - [vars] : 100 - Binary : 355 - Block : 684 - Break : 149 - Call : 219 + [total] : 4381 + [vars] : 218 + Binary : 335 + Block : 725 + Break : 120 + Call : 210 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 + Const : 692 + Drop : 64 + GlobalGet : 391 + GlobalSet : 298 + If : 236 + Load : 71 + LocalGet : 285 + LocalSet : 209 + Loop : 76 + Nop : 63 + RefFunc : 25 + Return : 60 + Select : 23 + Store : 29 + Switch : 2 + Unary : 293 + Unreachable : 151 From d6cbcc9db1fc51125270899e6c1806a0f3c64298 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 14:37:35 -0700 Subject: [PATCH 22/25] be more flexible --- src/tools/execution-results.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 74d72dd8c13..d9fefc44ec7 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -43,7 +43,7 @@ struct LoggingExternalInterface : public ShellExternalInterface { Literals callImport(Function* import, const Literals& arguments) override { if (import->module == "fuzzing-support") { - if (import->base.startsWith("log-")) { + if (import->base.startsWith("log")) { // This is a logging function like log-i32 or log-f64 std::cout << "[LoggingExternalInterface logging"; loggings.push_back(Literal()); // buffer with a None between calls From 043a76a5abb0e5f63bceeac606a4122cb0053561 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 14:41:01 -0700 Subject: [PATCH 23/25] fix some tests, which misused logging --- test/passes/simplify-locals_all-features.wast | 2 +- ...simplify-locals_all-features_disable-exception-handling.wast | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/passes/simplify-locals_all-features.wast b/test/passes/simplify-locals_all-features.wast index 47bb7f1b588..ae4d0336b8d 100644 --- a/test/passes/simplify-locals_all-features.wast +++ b/test/passes/simplify-locals_all-features.wast @@ -1194,7 +1194,7 @@ (type $4 (func (param i32))) (type $5 (func (param i32) (result i32))) (type $6 (func (param i32 i32 i32 i32 i32 i32))) - (import "fuzzing-support" "log1" (func $fimport$0 (result i32))) + (import "env" "get1" (func $fimport$0 (result i32))) (import "fuzzing-support" "log2" (func $fimport$1 (param i32))) (import "fuzzing-support" "log3" (func $fimport$2 (param f32))) (memory 256 256 shared) diff --git a/test/passes/simplify-locals_all-features_disable-exception-handling.wast b/test/passes/simplify-locals_all-features_disable-exception-handling.wast index 0fc11069693..49bc29c0729 100644 --- a/test/passes/simplify-locals_all-features_disable-exception-handling.wast +++ b/test/passes/simplify-locals_all-features_disable-exception-handling.wast @@ -1194,7 +1194,7 @@ (type $4 (func (param i32))) (type $5 (func (param i32) (result i32))) (type $6 (func (param i32 i32 i32 i32 i32 i32))) - (import "fuzzing-support" "log1" (func $fimport$0 (result i32))) + (import "env" "get1" (func $fimport$0 (result i32))) (import "fuzzing-support" "log2" (func $fimport$1 (param i32))) (import "fuzzing-support" "log3" (func $fimport$2 (param f32))) (memory 256 256 shared) From e983c3abd2b303b65c60c81f20261a3df5762e69 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 14:41:22 -0700 Subject: [PATCH 24/25] update outputs --- test/passes/simplify-locals_all-features.txt | 2 +- .../simplify-locals_all-features_disable-exception-handling.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/passes/simplify-locals_all-features.txt b/test/passes/simplify-locals_all-features.txt index befbe33efb7..978dfc62f86 100644 --- a/test/passes/simplify-locals_all-features.txt +++ b/test/passes/simplify-locals_all-features.txt @@ -1220,7 +1220,7 @@ (type $9 (func (result f64))) (type $10 (func (param i32 i32) (result f64))) (type $11 (func (param i32 i32) (result i32))) - (import "fuzzing-support" "log1" (func $fimport$0 (type $FUNCSIG$i) (result i32))) + (import "env" "get1" (func $fimport$0 (type $FUNCSIG$i) (result i32))) (import "fuzzing-support" "log2" (func $fimport$1 (type $4) (param i32))) (import "fuzzing-support" "log3" (func $fimport$2 (type $7) (param f32))) (global $global$0 (mut i32) (i32.const 10)) diff --git a/test/passes/simplify-locals_all-features_disable-exception-handling.txt b/test/passes/simplify-locals_all-features_disable-exception-handling.txt index 111223c49c5..2cd4e68246d 100644 --- a/test/passes/simplify-locals_all-features_disable-exception-handling.txt +++ b/test/passes/simplify-locals_all-features_disable-exception-handling.txt @@ -1214,7 +1214,7 @@ (type $9 (func (result f64))) (type $10 (func (param i32 i32) (result f64))) (type $11 (func (param i32 i32) (result i32))) - (import "fuzzing-support" "log1" (func $fimport$0 (type $FUNCSIG$i) (result i32))) + (import "env" "get1" (func $fimport$0 (type $FUNCSIG$i) (result i32))) (import "fuzzing-support" "log2" (func $fimport$1 (type $4) (param i32))) (import "fuzzing-support" "log3" (func $fimport$2 (type $7) (param f32))) (global $global$0 (mut i32) (i32.const 10)) From 3b0bb3f03a1cb71ebdd7c601d25f84280418efe5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Oct 2024 15:42:21 -0700 Subject: [PATCH 25/25] use proper log-i32/f32 names in tests --- test/passes/simplify-locals_all-features.txt | 4 ++-- test/passes/simplify-locals_all-features.wast | 4 ++-- ...implify-locals_all-features_disable-exception-handling.txt | 4 ++-- ...mplify-locals_all-features_disable-exception-handling.wast | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/passes/simplify-locals_all-features.txt b/test/passes/simplify-locals_all-features.txt index 978dfc62f86..9daee90a264 100644 --- a/test/passes/simplify-locals_all-features.txt +++ b/test/passes/simplify-locals_all-features.txt @@ -1221,8 +1221,8 @@ (type $10 (func (param i32 i32) (result f64))) (type $11 (func (param i32 i32) (result i32))) (import "env" "get1" (func $fimport$0 (type $FUNCSIG$i) (result i32))) - (import "fuzzing-support" "log2" (func $fimport$1 (type $4) (param i32))) - (import "fuzzing-support" "log3" (func $fimport$2 (type $7) (param f32))) + (import "fuzzing-support" "log-i32" (func $fimport$1 (type $4) (param i32))) + (import "fuzzing-support" "log-f32" (func $fimport$2 (type $7) (param f32))) (global $global$0 (mut i32) (i32.const 10)) (memory $0 256 256 shared) (func $nonatomics (type $FUNCSIG$i) (result i32) diff --git a/test/passes/simplify-locals_all-features.wast b/test/passes/simplify-locals_all-features.wast index ae4d0336b8d..0c296e378b4 100644 --- a/test/passes/simplify-locals_all-features.wast +++ b/test/passes/simplify-locals_all-features.wast @@ -1195,8 +1195,8 @@ (type $5 (func (param i32) (result i32))) (type $6 (func (param i32 i32 i32 i32 i32 i32))) (import "env" "get1" (func $fimport$0 (result i32))) - (import "fuzzing-support" "log2" (func $fimport$1 (param i32))) - (import "fuzzing-support" "log3" (func $fimport$2 (param f32))) + (import "fuzzing-support" "log-i32" (func $fimport$1 (param i32))) + (import "fuzzing-support" "log-f32" (func $fimport$2 (param f32))) (memory 256 256 shared) (global $global$0 (mut i32) (i32.const 10)) (func $nonatomics (result i32) ;; loads are reordered diff --git a/test/passes/simplify-locals_all-features_disable-exception-handling.txt b/test/passes/simplify-locals_all-features_disable-exception-handling.txt index 2cd4e68246d..92356286763 100644 --- a/test/passes/simplify-locals_all-features_disable-exception-handling.txt +++ b/test/passes/simplify-locals_all-features_disable-exception-handling.txt @@ -1215,8 +1215,8 @@ (type $10 (func (param i32 i32) (result f64))) (type $11 (func (param i32 i32) (result i32))) (import "env" "get1" (func $fimport$0 (type $FUNCSIG$i) (result i32))) - (import "fuzzing-support" "log2" (func $fimport$1 (type $4) (param i32))) - (import "fuzzing-support" "log3" (func $fimport$2 (type $7) (param f32))) + (import "fuzzing-support" "log-i32" (func $fimport$1 (type $4) (param i32))) + (import "fuzzing-support" "log-f32" (func $fimport$2 (type $7) (param f32))) (global $global$0 (mut i32) (i32.const 10)) (memory $0 256 256 shared) (func $nonatomics (type $FUNCSIG$i) (result i32) diff --git a/test/passes/simplify-locals_all-features_disable-exception-handling.wast b/test/passes/simplify-locals_all-features_disable-exception-handling.wast index 49bc29c0729..44c31e344b3 100644 --- a/test/passes/simplify-locals_all-features_disable-exception-handling.wast +++ b/test/passes/simplify-locals_all-features_disable-exception-handling.wast @@ -1195,8 +1195,8 @@ (type $5 (func (param i32) (result i32))) (type $6 (func (param i32 i32 i32 i32 i32 i32))) (import "env" "get1" (func $fimport$0 (result i32))) - (import "fuzzing-support" "log2" (func $fimport$1 (param i32))) - (import "fuzzing-support" "log3" (func $fimport$2 (param f32))) + (import "fuzzing-support" "log-i32" (func $fimport$1 (param i32))) + (import "fuzzing-support" "log-f32" (func $fimport$2 (param f32))) (memory 256 256 shared) (global $global$0 (mut i32) (i32.const 10)) (func $nonatomics (result i32) ;; loads are reordered