From 4aa396993cf71be17481e7aae6440c0ffb763611 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Nov 2024 11:54:37 -0800 Subject: [PATCH 01/48] work --- scripts/fuzz_shell.js | 89 ++++++++++++++++++++--------------- src/tools/fuzzing.h | 3 ++ src/tools/fuzzing/fuzzing.cpp | 50 +++++++++++++++----- 3 files changed, 94 insertions(+), 48 deletions(-) diff --git a/scripts/fuzz_shell.js b/scripts/fuzz_shell.js index 782040dac84..95176bbe65b 100644 --- a/scripts/fuzz_shell.js +++ b/scripts/fuzz_shell.js @@ -160,6 +160,49 @@ function callFunc(func) { return func.apply(null, args); } +// Calls a given function in a try-catch, swallowing JS exceptions, and return 1 +// if we did in fact swallow an exception. Wasm traps are not swallowed (see +// details below). +function tryCall(func) { + try { + func(); + return 0; + } catch (e) { + // We only want to catch exceptions, not wasm traps: traps should still + // halt execution. Handling this requires different code in wasm2js, so + // check for that first (wasm2js does not define RuntimeError, so use + // that for the check - when wasm2js is run, we override the entire + // WebAssembly object with a polyfill, so we know exactly what it + // contains). + var wasm2js = !WebAssembly.RuntimeError; + if (!wasm2js) { + // When running native wasm, we can detect wasm traps. + if (e instanceof WebAssembly.RuntimeError) { + throw e; + } + } + var text = e + ''; + // We must not swallow host limitations here: a host limitation is a + // problem that means we must not compare the outcome here to any other + // VM. + var hostIssues = ['requested new array is too large', + 'out of memory', + 'Maximum call stack size exceeded']; + if (wasm2js) { + // When wasm2js does trap, it just throws an "abort" error. + hostIssues.push('abort'); + } + for (var hostIssue of hostIssues) { + if (text.includes(hostIssue)) { + throw e; + } + } + // Otherwise, this is a normal exception we want to catch (a wasm + // exception, or a conversion error on the wasm/JS boundary, etc.). + return 1; + } +} + // Table get/set operations need a BigInt if the table has 64-bit indexes. This // adds a proper cast as needed. function toAddressType(table, index) { @@ -204,43 +247,15 @@ var imports = { callFunc(exportList[index].value); }, 'call-export-catch': (index) => { - try { - callFunc(exportList[index].value); - return 0; - } catch (e) { - // We only want to catch exceptions, not wasm traps: traps should still - // halt execution. Handling this requires different code in wasm2js, so - // check for that first (wasm2js does not define RuntimeError, so use - // that for the check - when wasm2js is run, we override the entire - // WebAssembly object with a polyfill, so we know exactly what it - // contains). - var wasm2js = !WebAssembly.RuntimeError; - if (!wasm2js) { - // When running native wasm, we can detect wasm traps. - if (e instanceof WebAssembly.RuntimeError) { - throw e; - } - } - var text = e + ''; - // We must not swallow host limitations here: a host limitation is a - // problem that means we must not compare the outcome here to any other - // VM. - var hostIssues = ['requested new array is too large', - 'out of memory', - 'Maximum call stack size exceeded']; - if (wasm2js) { - // When wasm2js does trap, it just throws an "abort" error. - hostIssues.push('abort'); - } - for (var hostIssue of hostIssues) { - if (text.includes(hostIssue)) { - throw e; - } - } - // Otherwise, this is a normal exception we want to catch (a wasm - // exception, or a conversion error on the wasm/JS boundary, etc.). - return 1; - } + return tryCall(() => callFunc(exportList[index].value)); + }, + + // Funcref operations. + 'call-ref': (ref) => { + callFunc(ref); + }, + 'call-ref-catch': (ref) => { + return tryCall(() => callFunc(ref)); }, }, // Emscripten support. diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 1afb4bf36f7..8bdbecc7072 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -109,6 +109,8 @@ class TranslateToFuzzReader { Name tableSetImportName; Name callExportImportName; Name callExportCatchImportName; + Name callRefImportName; + Name callRefCatchImportName; std::unordered_map> globalsByType; std::unordered_map> mutableGlobalsByType; @@ -239,6 +241,7 @@ class TranslateToFuzzReader { Expression* makeImportTableGet(); Expression* makeImportTableSet(Type type); Expression* makeImportCallExport(Type type); + Expression* makeImportCallRef(Type type); Expression* makeMemoryHashLogging(); // Function creation diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 7e87f4f5850..268f9ae2d5a 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -766,20 +766,13 @@ void TranslateToFuzzReader::addImportLoggingSupport() { void TranslateToFuzzReader::addImportCallingSupport() { // Only add these some of the time, as they inhibit some fuzzing (things like // wasm-ctor-eval and wasm-merge are sensitive to the wasm being able to call - // its own exports, and to care about the indexes of the exports): - // - // 0 - none - // 1 - call-export - // 2 - call-export-catch - // 3 - call-export & call-export-catch - // 4 - none - // 5 - none - // - auto choice = upTo(6); - if (choice >= 4) { + // its own exports, and to care about the indexes of the exports). + if (oneIn(2)) { return; } + auto choice = upTo(16); + if (choice & 1) { // Given an export index, call it from JS. callExportImportName = Names::getValidFunctionName(wasm, "call-export"); @@ -804,6 +797,30 @@ void TranslateToFuzzReader::addImportCallingSupport() { func->type = Signature(Type::i32, Type::i32); wasm.addFunction(std::move(func)); } + + if (choice & 4) { + // Given an funcref, call it from JS. + callRefImportName = Names::getValidFunctionName(wasm, "call-ref"); + auto func = std::make_unique(); + func->name = callRefImportName; + func->module = "fuzzing-support"; + func->base = "call-ref"; + func->type = Signature({Type(HeapType::func, Nullable)}, Type::none); + wasm.addFunction(std::move(func)); + } + + if (choice & 8) { + // Given an funcref, call it from JS and catch all exceptions (similar to + // callExportCatch), return 1 if we caught). + callRefCatchImportName = + Names::getValidFunctionName(wasm, "call-ref-catch"); + auto func = std::make_unique(); + func->name = callRefCatchImportName; + func->module = "fuzzing-support"; + func->base = "call-ref-catch"; + func->type = Signature(Type::i32, Type::i32); + wasm.addFunction(std::move(func)); + } } void TranslateToFuzzReader::addImportThrowingSupport() { @@ -1023,6 +1040,17 @@ Expression* TranslateToFuzzReader::makeImportCallExport(Type type) { return builder.makeCall(target, {index}, type); } +Expression* TranslateToFuzzReader::makeImportCallRef(Type type) { + // The none-returning variant just does the call. The i32-returning one + // catches any errors and returns 1 when it saw an error. Based on the + // variant, pick which to call. + auto target = type == Type::none ? callExportImportName : target = callExportCatchImportName; + + // Most of the time make a non-nullable funcref, to avoid trapping. + auto refType = Type(HeapType::func, oneIn(10) ? Nullable : NonNullable); + return builder.makeCall(target, {make(refType)}, type); +} + Expression* TranslateToFuzzReader::makeMemoryHashLogging() { auto* hash = builder.makeCall(std::string("hashMemory"), {}, Type::i32); return builder.makeCall(logImportNames[Type::i32], {hash}, Type::none); From 2c5d9f36d87cff46e8b5e2a1ae1ca8ce6285d659 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Nov 2024 12:42:35 -0800 Subject: [PATCH 02/48] work --- src/tools/fuzzing/fuzzing.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 268f9ae2d5a..42007c136dc 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1044,7 +1044,7 @@ Expression* TranslateToFuzzReader::makeImportCallRef(Type type) { // The none-returning variant just does the call. The i32-returning one // catches any errors and returns 1 when it saw an error. Based on the // variant, pick which to call. - auto target = type == Type::none ? callExportImportName : target = callExportCatchImportName; + auto target = type == Type::none ? callRefImportName : target = callRefCatchImportName; // Most of the time make a non-nullable funcref, to avoid trapping. auto refType = Type(HeapType::func, oneIn(10) ? Nullable : NonNullable); @@ -1729,6 +1729,9 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) { if (callExportCatchImportName) { options.add(FeatureSet::MVP, &Self::makeImportCallExport); } + if (callRefCatchImportName) { + options.add(FeatureSet::MVP, &Self::makeImportCallRef); + } options.add(FeatureSet::ReferenceTypes, &Self::makeRefIsNull); options.add(FeatureSet::ReferenceTypes | FeatureSet::GC, &Self::makeRefEq, @@ -1811,6 +1814,10 @@ Expression* TranslateToFuzzReader::_makenone() { if (callExportImportName) { options.add(FeatureSet::MVP, &Self::makeImportCallExport); } + if (callRefImportName) { + options.add(FeatureSet::ReferenceTypes | FeatureSet::GC, + &Self::makeImportCallRef); + } return (this->*pick(options))(Type::none); } From ab048db7fc225b5fb10873839373e58fcd8835b3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Nov 2024 12:48:21 -0800 Subject: [PATCH 03/48] work --- src/tools/execution-results.h | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 25d0c077237..95c2798b8c9 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -105,13 +105,25 @@ struct LoggingExternalInterface : public ShellExternalInterface { tableStore(exportedTable, index, arguments[1]); return {}; } else if (import->base == "call-export") { - callExport(arguments[0].geti32()); + callExportAsJS(arguments[0].geti32()); // Return nothing. If we wanted to return a value we'd need to have // multiple such functions, one for each signature. return {}; } else if (import->base == "call-export-catch") { try { - callExport(arguments[0].geti32()); + callExportAsJS(arguments[0].geti32()); + return {Literal(int32_t(0))}; + } catch (const WasmException& e) { + return {Literal(int32_t(1))}; + } + } else if (import->base == "call-ref") { + callRefAsJS(arguments[0]); + // Return nothing. If we wanted to return a value we'd need to have + // multiple such functions, one for each signature. + return {}; + } else if (import->base == "call-ref-catch") { + try { + callRefAsJS(arguments[0]); return {Literal(int32_t(0))}; } catch (const WasmException& e) { return {Literal(int32_t(1))}; @@ -145,7 +157,7 @@ struct LoggingExternalInterface : public ShellExternalInterface { throwException(WasmException{Literal(payload)}); } - Literals callExport(Index index) { + Literals callExportAsJS(Index index) { if (index >= wasm.exports.size()) { // No export. throwEmptyException(); @@ -155,7 +167,18 @@ struct LoggingExternalInterface : public ShellExternalInterface { // No callable export. throwEmptyException(); } - auto* func = wasm.getFunction(exp->value); + return callFunctionAsJS(exp->value); + } + + Literals callRefAsJS(Literal ref) { + assert(ref.isFunc()); + return callFunctionAsJS(ref.getFunc()); + } + + // Call a function in a "JS-ey" manner, adding arguments as needed, the same + // way JS does. + Literals callFunctionAsJS(Name name) { + auto* func = wasm.getFunction(name); // TODO JS traps on some types on the boundary, which we should behave the // same on. For now, this is not needed because the fuzzer will prune all From 3cdf7a453124de6a2f867fd01c450a5c00ce0f53 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Nov 2024 15:48:55 -0800 Subject: [PATCH 04/48] work --- src/tools/fuzzing/fuzzing.cpp | 46 ++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 42007c136dc..cb9e8c60749 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -798,28 +798,30 @@ void TranslateToFuzzReader::addImportCallingSupport() { wasm.addFunction(std::move(func)); } - if (choice & 4) { - // Given an funcref, call it from JS. - callRefImportName = Names::getValidFunctionName(wasm, "call-ref"); - auto func = std::make_unique(); - func->name = callRefImportName; - func->module = "fuzzing-support"; - func->base = "call-ref"; - func->type = Signature({Type(HeapType::func, Nullable)}, Type::none); - wasm.addFunction(std::move(func)); - } - - if (choice & 8) { - // Given an funcref, call it from JS and catch all exceptions (similar to - // callExportCatch), return 1 if we caught). - callRefCatchImportName = - Names::getValidFunctionName(wasm, "call-ref-catch"); - auto func = std::make_unique(); - func->name = callRefCatchImportName; - func->module = "fuzzing-support"; - func->base = "call-ref-catch"; - func->type = Signature(Type::i32, Type::i32); - wasm.addFunction(std::move(func)); + if (wasm.features.hasReferenceTypes()) { + if (choice & 4) { + // Given an funcref, call it from JS. + callRefImportName = Names::getValidFunctionName(wasm, "call-ref"); + auto func = std::make_unique(); + func->name = callRefImportName; + func->module = "fuzzing-support"; + func->base = "call-ref"; + func->type = Signature({Type(HeapType::func, Nullable)}, Type::none); + wasm.addFunction(std::move(func)); + } + + if (choice & 8) { + // Given an funcref, call it from JS and catch all exceptions (similar to + // callExportCatch), return 1 if we caught). + callRefCatchImportName = + Names::getValidFunctionName(wasm, "call-ref-catch"); + auto func = std::make_unique(); + func->name = callRefCatchImportName; + func->module = "fuzzing-support"; + func->base = "call-ref-catch"; + func->type = Signature(Type::i32, Type::i32); + wasm.addFunction(std::move(func)); + } } } From 5035476db9e98dbf0be12f9fdbde3dc1ae04ac66 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Nov 2024 15:50:15 -0800 Subject: [PATCH 05/48] work --- src/tools/execution-results.h | 2 +- src/tools/fuzzing/fuzzing.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 95c2798b8c9..79fdabde9ef 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -171,7 +171,7 @@ struct LoggingExternalInterface : public ShellExternalInterface { } Literals callRefAsJS(Literal ref) { - assert(ref.isFunc()); + assert(ref.isFunction()); return callFunctionAsJS(ref.getFunc()); } diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index cb9e8c60749..c9ff9691d0a 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1046,10 +1046,10 @@ Expression* TranslateToFuzzReader::makeImportCallRef(Type type) { // The none-returning variant just does the call. The i32-returning one // catches any errors and returns 1 when it saw an error. Based on the // variant, pick which to call. - auto target = type == Type::none ? callRefImportName : target = callRefCatchImportName; + auto target = type == Type::none ? callRefImportName : callRefCatchImportName; // Most of the time make a non-nullable funcref, to avoid trapping. - auto refType = Type(HeapType::func, oneIn(10) ? Nullable : NonNullable); + auto refType = Type(HeapType::func, oneIn(20) ? Nullable : NonNullable); return builder.makeCall(target, {make(refType)}, type); } From 5a879579790940c307e05b6ea03ca5f1bf14a337 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Nov 2024 15:56:08 -0800 Subject: [PATCH 06/48] test --- src/tools/execution-results.h | 5 +++- src/tools/fuzzing/fuzzing.cpp | 2 +- test/lit/exec/fuzzing-api.wast | 53 +++++++++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 79fdabde9ef..36bdca406ab 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -171,7 +171,10 @@ struct LoggingExternalInterface : public ShellExternalInterface { } Literals callRefAsJS(Literal ref) { - assert(ref.isFunction()); + if (!ref.isFunction()) { + // Not a callable ref. + throwEmptyException(); + } return callFunctionAsJS(ref.getFunc()); } diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index c9ff9691d0a..7b7599e10b1 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -819,7 +819,7 @@ void TranslateToFuzzReader::addImportCallingSupport() { func->name = callRefCatchImportName; func->module = "fuzzing-support"; func->base = "call-ref-catch"; - func->type = Signature(Type::i32, Type::i32); + func->type = Signature(Type(HeapType::func, Nullable), Type::i32); wasm.addFunction(std::move(func)); } } diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 38a8ce41bbe..7bff5125140 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -16,6 +16,9 @@ (import "fuzzing-support" "call-export" (func $call.export (param i32))) (import "fuzzing-support" "call-export-catch" (func $call.export.catch (param i32) (result i32))) + (import "fuzzing-support" "call-ref" (func $call.ref (param funcref))) + (import "fuzzing-support" "call-ref-catch" (func $call.ref.catch (param funcref) (result i32))) + (table $table 10 20 funcref) ;; Note that the exported table appears first here, but in the binary and in @@ -102,7 +105,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] - ;; CHECK-NEXT: warning: no passes specified, not doing any work (func $export.calling.catching (export "export.calling.catching") ;; At index 0 in the exports we have $logging, so we will do those loggings, ;; then log a 0 as no exception happens. @@ -118,6 +120,42 @@ ) ) ) + + ;; CHECK: [fuzz-exec] calling ref.calling + ;; CHECK-NEXT: [LoggingExternalInterface logging 42] + ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] + ;; CHECK-NEXT: [exception thrown: __private ()] + (func $ref.calling (export "ref.calling") + ;; This will emit some logging. + (call $call.ref + (ref.func $logging) + ) + ;; This will trap. + (call $call.ref + (ref.null func) + ) + ) + + ;; CHECK: [fuzz-exec] calling ref.calling.catching + ;; CHECK-NEXT: [LoggingExternalInterface logging 42] + ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] + ;; CHECK-NEXT: [LoggingExternalInterface logging 0] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1] + ;; CHECK-NEXT: warning: no passes specified, not doing any work + (func $ref.calling.catching (export "ref.calling.catching") + ;; This will emit some logging, then log 0 as we do not error. + (call $log-i32 + (call $call.ref.catch + (ref.func $logging) + ) + ) + ;; The trap here is caught, and we'll log 1. + (call $log-i32 + (call $call.ref.catch + (ref.null func) + ) + ) + ) ) ;; CHECK: [fuzz-exec] calling logging ;; CHECK-NEXT: [LoggingExternalInterface logging 42] @@ -144,9 +182,22 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] + +;; CHECK: [fuzz-exec] calling ref.calling +;; CHECK-NEXT: [LoggingExternalInterface logging 42] +;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] +;; CHECK-NEXT: [exception thrown: __private ()] + +;; CHECK: [fuzz-exec] calling ref.calling.catching +;; CHECK-NEXT: [LoggingExternalInterface logging 42] +;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] +;; CHECK-NEXT: [LoggingExternalInterface logging 0] +;; CHECK-NEXT: [LoggingExternalInterface logging 1] ;; CHECK-NEXT: [fuzz-exec] comparing export.calling ;; CHECK-NEXT: [fuzz-exec] comparing export.calling.catching ;; CHECK-NEXT: [fuzz-exec] comparing logging +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.catching ;; CHECK-NEXT: [fuzz-exec] comparing table.getting ;; CHECK-NEXT: [fuzz-exec] comparing table.setting ;; CHECK-NEXT: [fuzz-exec] comparing throwing From 283aa4d5fa89f596ba3125de9d5bf096016ea626 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Nov 2024 16:18:13 -0800 Subject: [PATCH 07/48] traps --- src/tools/execution-results.h | 13 ++++++++++--- test/lit/exec/fuzzing-api.wast | 35 +++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 36bdca406ab..7bbc7b7e2bb 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -183,9 +183,12 @@ struct LoggingExternalInterface : public ShellExternalInterface { Literals callFunctionAsJS(Name name) { auto* func = wasm.getFunction(name); - // TODO JS traps on some types on the boundary, which we should behave the - // same on. For now, this is not needed because the fuzzer will prune all - // non-JS-compatible exports anyhow. + // Some types trap on the JS boundary. + auto trapOnNonJSTypes = [&](Type type) { + if (type == Type::i64 || type == Type::v128) { + throwEmptyException(); + } + }; // Send default values as arguments, or trap if we need anything else. Literals arguments; @@ -193,8 +196,12 @@ struct LoggingExternalInterface : public ShellExternalInterface { if (!param.isDefaultable()) { throwEmptyException(); } + trapOnNonJSTypes(param); arguments.push_back(Literal::makeZero(param)); } + for (const auto& result : func->getResults()) { + trapOnNonJSTypes(result); + } return instance->callFunction(func->name, arguments); } diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 7bff5125140..7ee9a9311ce 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -141,7 +141,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] - ;; CHECK-NEXT: warning: no passes specified, not doing any work (func $ref.calling.catching (export "ref.calling.catching") ;; This will emit some logging, then log 0 as we do not error. (call $log-i32 @@ -156,6 +155,31 @@ ) ) ) + + ;; CHECK: [fuzz-exec] calling ref.calling.illegal + ;; CHECK-NEXT: [LoggingExternalInterface logging 1] + (func $ref.calling.illegal (export "ref.calling.illegal") (param $x i64) + ;; The i64 param causes an error here, so we will log 1 as a trap. + (call $log-i32 + (call $call.ref.catch + (ref.func $ref.calling.illegal) + ) + ) + ) + + ;; CHECK: [fuzz-exec] calling ref.calling.illegal2 + ;; CHECK-NEXT: [LoggingExternalInterface logging 1] + ;; CHECK-NEXT: [fuzz-exec] note result: ref.calling.illegal2 => i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + ;; CHECK-NEXT: warning: no passes specified, not doing any work + (func $ref.calling.illegal2 (export "ref.calling.illegal2") (result v128) + ;; The v128 result causes an error here, so we will log 1 as a trap. + (call $log-i32 + (call $call.ref.catch + (ref.func $ref.calling.illegal2) + ) + ) + (v128.const i32x4 1 2 3 4) + ) ) ;; CHECK: [fuzz-exec] calling logging ;; CHECK-NEXT: [LoggingExternalInterface logging 42] @@ -193,11 +217,20 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] + +;; CHECK: [fuzz-exec] calling ref.calling.illegal +;; CHECK-NEXT: [LoggingExternalInterface logging 1] + +;; CHECK: [fuzz-exec] calling ref.calling.illegal2 +;; CHECK-NEXT: [LoggingExternalInterface logging 1] +;; CHECK-NEXT: [fuzz-exec] note result: ref.calling.illegal2 => i32x4 0x00000001 0x00000002 0x00000003 0x00000004 ;; CHECK-NEXT: [fuzz-exec] comparing export.calling ;; CHECK-NEXT: [fuzz-exec] comparing export.calling.catching ;; CHECK-NEXT: [fuzz-exec] comparing logging ;; CHECK-NEXT: [fuzz-exec] comparing ref.calling ;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.catching +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal2 ;; CHECK-NEXT: [fuzz-exec] comparing table.getting ;; CHECK-NEXT: [fuzz-exec] comparing table.setting ;; CHECK-NEXT: [fuzz-exec] comparing throwing From 982152633abafa9f3dc0f7212c93154abb96d0ed Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Nov 2024 16:20:51 -0800 Subject: [PATCH 08/48] test --- test/lit/exec/fuzzing-api.wast | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 7ee9a9311ce..ae69646f8d5 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -156,6 +156,25 @@ ) ) + (func $legal (param $x i32) (result i32) + ;; Helper for the function below. + (call $log-i32 + (i32.const 1234) + ) + (i32.const 5678) + ) + + ;; CHECK: [fuzz-exec] calling ref.calling.legal + ;; CHECK-NEXT: [LoggingExternalInterface logging 1234] + (func $ref.calling.legal (export "ref.calling.legal") + ;; It is fine to call-ref a function with params and results. The params get + ;; default values, and the results are ignored. All we will see here is the + ;; logging from the function, "1234". + (call $call.ref + (ref.func $legal) + ) + ) + ;; CHECK: [fuzz-exec] calling ref.calling.illegal ;; CHECK-NEXT: [LoggingExternalInterface logging 1] (func $ref.calling.illegal (export "ref.calling.illegal") (param $x i64) @@ -218,6 +237,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] +;; CHECK: [fuzz-exec] calling ref.calling.legal +;; CHECK-NEXT: [LoggingExternalInterface logging 1234] + ;; CHECK: [fuzz-exec] calling ref.calling.illegal ;; CHECK-NEXT: [LoggingExternalInterface logging 1] @@ -231,6 +253,7 @@ ;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.catching ;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal ;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal2 +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.legal ;; CHECK-NEXT: [fuzz-exec] comparing table.getting ;; CHECK-NEXT: [fuzz-exec] comparing table.setting ;; CHECK-NEXT: [fuzz-exec] comparing throwing From bf76afd287e7e232063fc0513af3d5e4bd5917b8 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Nov 2024 16:56:23 -0800 Subject: [PATCH 09/48] fix --- src/tools/execution-results.h | 5 +- test/lit/exec/fuzzing-api.wast | 524 ++++++++++++++++++++++++++++++++- 2 files changed, 512 insertions(+), 17 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 7bbc7b7e2bb..db8cda6a5c4 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -199,10 +199,13 @@ struct LoggingExternalInterface : public ShellExternalInterface { trapOnNonJSTypes(param); arguments.push_back(Literal::makeZero(param)); } + + // Call the function, then check if the results force a trap. + auto ret = instance->callFunction(func->name, arguments); for (const auto& result : func->getResults()) { trapOnNonJSTypes(result); } - return instance->callFunction(func->name, arguments); + return ret; } void setModuleRunner(ModuleRunner* instance_) { instance = instance_; } diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index ae69646f8d5..0ae6be8cf78 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -187,11 +187,265 @@ ) ;; CHECK: [fuzz-exec] calling ref.calling.illegal2 - ;; CHECK-NEXT: [LoggingExternalInterface logging 1] - ;; CHECK-NEXT: [fuzz-exec] note result: ref.calling.illegal2 => i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] ;; CHECK-NEXT: warning: no passes specified, not doing any work (func $ref.calling.illegal2 (export "ref.calling.illegal2") (result v128) - ;; The v128 result causes an error here, so we will log 1 as a trap. + ;; The v128 result causes an error here, so we will log 1 as a trap. But the + ;; error happens *after* the call, so the first logging goes through. And + ;; since we call ourselves recursively, we end up logging a lot, until we + ;; trap on exhausting the stack. XXX a + (call $log-i32 + (i32.const 1000) + ) (call $log-i32 (call $call.ref.catch (ref.func $ref.calling.illegal2) @@ -244,16 +498,254 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging 1] ;; CHECK: [fuzz-exec] calling ref.calling.illegal2 -;; CHECK-NEXT: [LoggingExternalInterface logging 1] -;; CHECK-NEXT: [fuzz-exec] note result: ref.calling.illegal2 => i32x4 0x00000001 0x00000002 0x00000003 0x00000004 -;; CHECK-NEXT: [fuzz-exec] comparing export.calling -;; CHECK-NEXT: [fuzz-exec] comparing export.calling.catching -;; CHECK-NEXT: [fuzz-exec] comparing logging -;; CHECK-NEXT: [fuzz-exec] comparing ref.calling -;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.catching -;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal -;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal2 -;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.legal -;; CHECK-NEXT: [fuzz-exec] comparing table.getting -;; CHECK-NEXT: [fuzz-exec] comparing table.setting -;; CHECK-NEXT: [fuzz-exec] comparing throwing +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: [LoggingExternalInterface logging 1000] +;; CHECK-NEXT: ignoring comparison of ExecutionResults! From 555ce920749467161bec7dac9cb377ff7f6f0052 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Dec 2024 11:37:12 -0800 Subject: [PATCH 10/48] work --- test/lit/exec/fuzzing-api.wast | 557 +++------------------------------ 1 file changed, 40 insertions(+), 517 deletions(-) diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 0ae6be8cf78..1bf4396de9b 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -157,15 +157,15 @@ ) (func $legal (param $x i32) (result i32) - ;; Helper for the function below. + ;; Helper for the function below. All types here are legal for JS. (call $log-i32 - (i32.const 1234) + (i32.const 12) ) - (i32.const 5678) + (i32.const 34) ) ;; CHECK: [fuzz-exec] calling ref.calling.legal - ;; CHECK-NEXT: [LoggingExternalInterface logging 1234] + ;; CHECK-NEXT: [LoggingExternalInterface logging 12] (func $ref.calling.legal (export "ref.calling.legal") ;; It is fine to call-ref a function with params and results. The params get ;; default values, and the results are ignored. All we will see here is the @@ -175,283 +175,44 @@ ) ) + (func $illegal (param $x i64) + ;; Helper for the function below. The param, an i64, is illegal for JS. + (call $log-i32 + (i32.const 56) + ) + ) + ;; CHECK: [fuzz-exec] calling ref.calling.illegal ;; CHECK-NEXT: [LoggingExternalInterface logging 1] (func $ref.calling.illegal (export "ref.calling.illegal") (param $x i64) - ;; The i64 param causes an error here, so we will log 1 as a trap. + ;; The i64 param causes an error here, so we will only log 1 as a trap. (call $log-i32 (call $call.ref.catch - (ref.func $ref.calling.illegal) + (ref.func $illegal) ) ) ) + (func $illegal-result (result v128) + ;; Helper for the function below. The result is illegal for JS. + (call $log-i32 + (i32.const 910) + ) + (v128.const i32x4 1 2 3 4) + ) + ;; CHECK: [fuzz-exec] calling ref.calling.illegal2 - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] - ;; CHECK-NEXT: [LoggingExternalInterface logging 1000] + ;; CHECK-NEXT: [LoggingExternalInterface logging 910] + ;; CHECK-NEXT: [LoggingExternalInterface logging 1] ;; CHECK-NEXT: warning: no passes specified, not doing any work - (func $ref.calling.illegal2 (export "ref.calling.illegal2") (result v128) + (func $ref.calling.illegal2 (export "ref.calling.illegal2") ;; The v128 result causes an error here, so we will log 1 as a trap. But the - ;; error happens *after* the call, so the first logging goes through. And - ;; since we call ourselves recursively, we end up logging a lot, until we - ;; trap on exhausting the stack. XXX a - (call $log-i32 - (i32.const 1000) - ) + ;; error happens *after* the call, so the first logging (910) goes through. (call $log-i32 (call $call.ref.catch - (ref.func $ref.calling.illegal2) + (ref.func $illegal-result) ) ) - (v128.const i32x4 1 2 3 4) ) ) ;; CHECK: [fuzz-exec] calling logging @@ -492,260 +253,22 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging 1] ;; CHECK: [fuzz-exec] calling ref.calling.legal -;; CHECK-NEXT: [LoggingExternalInterface logging 1234] +;; CHECK-NEXT: [LoggingExternalInterface logging 12] ;; CHECK: [fuzz-exec] calling ref.calling.illegal ;; CHECK-NEXT: [LoggingExternalInterface logging 1] ;; CHECK: [fuzz-exec] calling ref.calling.illegal2 -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: [LoggingExternalInterface logging 1000] -;; CHECK-NEXT: ignoring comparison of ExecutionResults! +;; CHECK-NEXT: [LoggingExternalInterface logging 910] +;; CHECK-NEXT: [LoggingExternalInterface logging 1] +;; CHECK-NEXT: [fuzz-exec] comparing export.calling +;; CHECK-NEXT: [fuzz-exec] comparing export.calling.catching +;; CHECK-NEXT: [fuzz-exec] comparing logging +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.catching +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal2 +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.legal +;; CHECK-NEXT: [fuzz-exec] comparing table.getting +;; CHECK-NEXT: [fuzz-exec] comparing table.setting +;; CHECK-NEXT: [fuzz-exec] comparing throwing From 3c92b0e9df19b081318732a68629f917afa47df3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Dec 2024 11:45:13 -0800 Subject: [PATCH 11/48] work --- src/tools/fuzzing.h | 5 ++-- src/tools/fuzzing/fuzzing.cpp | 45 +++++++++++++++++------------------ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 8bdbecc7072..ccc870b8566 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -240,8 +240,9 @@ class TranslateToFuzzReader { Expression* makeImportThrowing(Type type); Expression* makeImportTableGet(); Expression* makeImportTableSet(Type type); - Expression* makeImportCallExport(Type type); - Expression* makeImportCallRef(Type type); + // Call either an export or a ref. We do this from a single function to better + // control the frequency of each. + Expression* makeImportCallCode(Type type); Expression* makeMemoryHashLogging(); // Function creation diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 7b7599e10b1..e8f729bcee6 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1010,7 +1010,24 @@ Expression* TranslateToFuzzReader::makeImportTableSet(Type type) { Type::none); } -Expression* TranslateToFuzzReader::makeImportCallExport(Type type) { +Expression* TranslateToFuzzReader::makeImportCallCode(Type type) { + // Call code: either an export or a ref. We want to call an export more often, + // as refs are more likely to trap. + if (oneIn(4)) { + // Try to do a call to a ref. + + // The none-returning variant just does the call. The i32-returning one + // catches any errors and returns 1 when it saw an error. Based on the + // variant, pick which to call. + auto target = type == Type::none ? callRefImportName : callRefCatchImportName; + + if (target) { + // Most of the time make a non-nullable funcref, to avoid trapping. + auto refType = Type(HeapType::func, oneIn(20) ? Nullable : NonNullable); + return builder.makeCall(target, {make(refType)}, type); + } + } + // The none-returning variant just does the call. The i32-returning one // catches any errors and returns 1 when it saw an error. Based on the // variant, pick which to call, and the maximum index to call. @@ -1042,17 +1059,6 @@ Expression* TranslateToFuzzReader::makeImportCallExport(Type type) { return builder.makeCall(target, {index}, type); } -Expression* TranslateToFuzzReader::makeImportCallRef(Type type) { - // The none-returning variant just does the call. The i32-returning one - // catches any errors and returns 1 when it saw an error. Based on the - // variant, pick which to call. - auto target = type == Type::none ? callRefImportName : callRefCatchImportName; - - // Most of the time make a non-nullable funcref, to avoid trapping. - auto refType = Type(HeapType::func, oneIn(20) ? Nullable : NonNullable); - return builder.makeCall(target, {make(refType)}, type); -} - Expression* TranslateToFuzzReader::makeMemoryHashLogging() { auto* hash = builder.makeCall(std::string("hashMemory"), {}, Type::i32); return builder.makeCall(logImportNames[Type::i32], {hash}, Type::none); @@ -1728,11 +1734,8 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) { options.add(FeatureSet::Atomics, &Self::makeAtomic); } if (type == Type::i32) { - if (callExportCatchImportName) { - options.add(FeatureSet::MVP, &Self::makeImportCallExport); - } - if (callRefCatchImportName) { - options.add(FeatureSet::MVP, &Self::makeImportCallRef); + if (callExportCatchImportName || callRefCatchImportName) { + options.add(FeatureSet::MVP, &Self::makeImportCallCode); } options.add(FeatureSet::ReferenceTypes, &Self::makeRefIsNull); options.add(FeatureSet::ReferenceTypes | FeatureSet::GC, @@ -1813,12 +1816,8 @@ Expression* TranslateToFuzzReader::_makenone() { if (tableSetImportName) { options.add(FeatureSet::ReferenceTypes, &Self::makeImportTableSet); } - if (callExportImportName) { - options.add(FeatureSet::MVP, &Self::makeImportCallExport); - } - if (callRefImportName) { - options.add(FeatureSet::ReferenceTypes | FeatureSet::GC, - &Self::makeImportCallRef); + if (callExportImportName || callRefImportName) { + options.add(FeatureSet::MVP, &Self::makeImportCallCode); } return (this->*pick(options))(Type::none); } From d9b4f061161aadbb97b1ce2cb6ddd6556295465f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Dec 2024 11:48:22 -0800 Subject: [PATCH 12/48] update --- test/passes/fuzz_metrics_noprint.bin.txt | 52 +++++------ .../fuzz_metrics_passes_noprint.bin.txt | 53 ++++++----- ...e-to-fuzz_all-features_metrics_noprint.txt | 87 ++++++++++--------- 3 files changed, 97 insertions(+), 95 deletions(-) diff --git a/test/passes/fuzz_metrics_noprint.bin.txt b/test/passes/fuzz_metrics_noprint.bin.txt index 0fa206e0a1f..a2f996bcb38 100644 --- a/test/passes/fuzz_metrics_noprint.bin.txt +++ b/test/passes/fuzz_metrics_noprint.bin.txt @@ -1,35 +1,35 @@ Metrics total - [exports] : 45 - [funcs] : 60 + [exports] : 49 + [funcs] : 74 [globals] : 18 - [imports] : 5 + [imports] : 4 [memories] : 1 [memory-data] : 24 - [table-data] : 15 + [table-data] : 19 [tables] : 1 [tags] : 0 - [total] : 5475 - [vars] : 222 - Binary : 410 - Block : 870 - Break : 148 - Call : 271 - CallIndirect : 30 - Const : 915 - Drop : 51 - GlobalGet : 458 - GlobalSet : 323 - If : 293 - Load : 96 - LocalGet : 442 - LocalSet : 284 - Loop : 99 - Nop : 76 - RefFunc : 15 - Return : 78 - Select : 47 - Store : 44 + [total] : 5695 + [vars] : 227 + Binary : 430 + Block : 976 + Break : 188 + Call : 272 + CallIndirect : 20 + Const : 876 + Drop : 99 + GlobalGet : 504 + GlobalSet : 373 + If : 299 + Load : 111 + LocalGet : 365 + LocalSet : 299 + Loop : 108 + Nop : 58 + RefFunc : 19 + Return : 74 + Select : 40 + Store : 34 Switch : 2 Unary : 365 - Unreachable : 158 + Unreachable : 183 diff --git a/test/passes/fuzz_metrics_passes_noprint.bin.txt b/test/passes/fuzz_metrics_passes_noprint.bin.txt index 9c8c25c1279..c3881104d0d 100644 --- a/test/passes/fuzz_metrics_passes_noprint.bin.txt +++ b/test/passes/fuzz_metrics_passes_noprint.bin.txt @@ -1,35 +1,34 @@ Metrics total - [exports] : 54 - [funcs] : 84 + [exports] : 30 + [funcs] : 47 [globals] : 17 [imports] : 4 [memories] : 1 [memory-data] : 11 - [table-data] : 22 + [table-data] : 18 [tables] : 1 [tags] : 0 - [total] : 8343 - [vars] : 264 - Binary : 597 - Block : 1335 - Break : 226 - Call : 346 - CallIndirect : 65 - Const : 1375 - Drop : 107 - GlobalGet : 719 - GlobalSet : 522 - If : 458 - Load : 139 - LocalGet : 650 - LocalSet : 441 - Loop : 165 - Nop : 97 - RefFunc : 22 - Return : 120 - Select : 71 - Store : 56 - Switch : 2 - Unary : 574 - Unreachable : 256 + [total] : 4738 + [vars] : 133 + Binary : 338 + Block : 781 + Break : 122 + Call : 249 + CallIndirect : 27 + Const : 780 + Drop : 105 + GlobalGet : 378 + GlobalSet : 288 + If : 216 + Load : 79 + LocalGet : 396 + LocalSet : 252 + Loop : 89 + Nop : 43 + RefFunc : 18 + Return : 70 + Select : 37 + Store : 36 + Unary : 294 + Unreachable : 140 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 8df9d033cc0..e2e9b8053df 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,54 +1,57 @@ Metrics total - [exports] : 9 - [funcs] : 10 + [exports] : 6 + [funcs] : 6 [globals] : 4 [imports] : 8 [memories] : 1 [memory-data] : 112 - [table-data] : 2 + [table-data] : 1 [tables] : 1 [tags] : 1 - [total] : 682 - [vars] : 37 - ArrayLen : 1 - ArrayNew : 7 - ArrayNewFixed : 5 + [total] : 592 + [vars] : 38 + ArrayGet : 2 + ArrayLen : 2 + ArrayNew : 6 + ArrayNewFixed : 4 ArraySet : 1 - AtomicNotify : 1 - Binary : 79 - Block : 72 - BrOn : 4 - Break : 7 - Call : 19 - Const : 149 - Drop : 15 - GlobalGet : 35 - GlobalSet : 32 - If : 20 - Load : 20 - LocalGet : 55 - LocalSet : 26 - Loop : 7 - MemoryFill : 1 - Nop : 9 - Pop : 1 + AtomicCmpxchg : 1 + AtomicFence : 1 + AtomicRMW : 2 + Binary : 81 + Block : 62 + BrOn : 1 + Break : 11 + Call : 13 + CallIndirect : 2 + Const : 123 + Drop : 2 + GlobalGet : 22 + GlobalSet : 22 + If : 17 + Load : 25 + LocalGet : 63 + LocalSet : 35 + Loop : 6 + Nop : 8 + Pop : 3 RefAs : 1 - RefCast : 1 RefEq : 1 - RefFunc : 17 - RefI31 : 2 - RefIsNull : 2 - RefNull : 8 - Return : 5 - SIMDExtract : 3 - Store : 1 - StringConst : 3 + RefFunc : 6 + RefNull : 3 + Return : 4 + SIMDExtract : 2 + Select : 2 + StringConst : 5 + StringEncode : 1 + StringEq : 2 StringMeasure : 1 - StringWTF16Get : 1 - StructNew : 23 - Try : 1 - TupleExtract : 3 - TupleMake : 4 - Unary : 23 - Unreachable : 16 + StringWTF16Get : 2 + StructNew : 9 + Try : 3 + TryTable : 3 + TupleExtract : 1 + TupleMake : 2 + Unary : 18 + Unreachable : 11 From 6c141a880638fb85fcd3d8a101b4d8d89ab430fc Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Dec 2024 11:48:38 -0800 Subject: [PATCH 13/48] formt --- src/tools/fuzzing/fuzzing.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index e8f729bcee6..cd549cd423d 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1019,7 +1019,8 @@ Expression* TranslateToFuzzReader::makeImportCallCode(Type type) { // The none-returning variant just does the call. The i32-returning one // catches any errors and returns 1 when it saw an error. Based on the // variant, pick which to call. - auto target = type == Type::none ? callRefImportName : callRefCatchImportName; + auto target = + type == Type::none ? callRefImportName : callRefCatchImportName; if (target) { // Most of the time make a non-nullable funcref, to avoid trapping. From c3fe50c0ee0381bd3b3a7f71d3626ccf475ff656 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Dec 2024 12:14:16 -0800 Subject: [PATCH 14/48] fix --- src/tools/fuzzing/fuzzing.cpp | 46 ++++++++++++++--------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index cd549cd423d..3f7089844df 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1011,44 +1011,34 @@ Expression* TranslateToFuzzReader::makeImportTableSet(Type type) { } Expression* TranslateToFuzzReader::makeImportCallCode(Type type) { - // Call code: either an export or a ref. We want to call an export more often, - // as refs are more likely to trap. - if (oneIn(4)) { - // Try to do a call to a ref. + // Call code: either an export or a ref. Each has a catching and non-catching + // variant. The catching variants return i32, the others none. + assert(type == Type::none || type == Type::i32); + auto exportTarget = + type == Type::none ? callExportImportName : callExportCatchImportName; + auto refTarget = + type == Type::none ? callRefImportName : callRefCatchImportName; - // The none-returning variant just does the call. The i32-returning one - // catches any errors and returns 1 when it saw an error. Based on the - // variant, pick which to call. - auto target = - type == Type::none ? callRefImportName : callRefCatchImportName; - - if (target) { - // Most of the time make a non-nullable funcref, to avoid trapping. - auto refType = Type(HeapType::func, oneIn(20) ? Nullable : NonNullable); - return builder.makeCall(target, {make(refType)}, type); - } + // We want to call a ref rarely, as refs are more likely to trap. + if (refTarget && (!exportTarget || oneIn(4))) { + // Most of the time make a non-nullable funcref, to avoid trapping. + auto refType = Type(HeapType::func, oneIn(10) ? Nullable : NonNullable); + return builder.makeCall(refTarget, {make(refType)}, type); } - // The none-returning variant just does the call. The i32-returning one - // catches any errors and returns 1 when it saw an error. Based on the - // variant, pick which to call, and the maximum index to call. - Name target; + // Call an export. + assert(exportTarget); + + // Pick the maximum export index to call. Index maxIndex = wasm.exports.size(); - if (type == Type::none) { - target = callExportImportName; - } else if (type == Type::i32) { - target = callExportCatchImportName; + if (type == Type::i32) { // This never traps, so we can be less careful, but we do still want to // avoid trapping a lot as executing code is more interesting. (Note that // even though we double here, the risk is not that great: we are still // adding functions as we go, so the first half of functions/exports can // double here and still end up in bounds by the time we've added them all.) maxIndex = (maxIndex + 1) * 2; - } else { - WASM_UNREACHABLE("bad import.call"); } - // We must have set up the target function. - assert(target); // Most of the time, call a valid export index in the range we picked, but // sometimes allow anything at all. @@ -1057,7 +1047,7 @@ Expression* TranslateToFuzzReader::makeImportCallCode(Type type) { index = builder.makeBinary( RemUInt32, index, builder.makeConst(int32_t(maxIndex))); } - return builder.makeCall(target, {index}, type); + return builder.makeCall(exportTarget, {index}, type); } Expression* TranslateToFuzzReader::makeMemoryHashLogging() { From 3970db3271592a9e860a1e0ab41756535a1a2ac1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Dec 2024 12:59:52 -0800 Subject: [PATCH 15/48] fix --- src/tools/execution-results.h | 8 +++++--- test/lit/exec/fuzzing-api.wast | 7 +++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index db8cda6a5c4..161c73a5486 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -200,12 +200,14 @@ struct LoggingExternalInterface : public ShellExternalInterface { arguments.push_back(Literal::makeZero(param)); } - // Call the function, then check if the results force a trap. - auto ret = instance->callFunction(func->name, arguments); + // Trap on illegal results. Note that this happens, as per JS semantics, + // *before* the call. for (const auto& result : func->getResults()) { trapOnNonJSTypes(result); } - return ret; + + // Call the function. + return instance->callFunction(func->name, arguments); } void setModuleRunner(ModuleRunner* instance_) { instance = instance_; } diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 1bf4396de9b..3e2f6772218 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -202,12 +202,12 @@ ) ;; CHECK: [fuzz-exec] calling ref.calling.illegal2 - ;; CHECK-NEXT: [LoggingExternalInterface logging 910] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] ;; CHECK-NEXT: warning: no passes specified, not doing any work (func $ref.calling.illegal2 (export "ref.calling.illegal2") - ;; The v128 result causes an error here, so we will log 1 as a trap. But the - ;; error happens *after* the call, so the first logging (910) goes through. + ;; The v128 result causes an error here, so we will log 1 as a trap. The JS + ;; semantics determine that we do that check *before* the call, so the logging + ;; of 910 does not go through. (call $log-i32 (call $call.ref.catch (ref.func $illegal-result) @@ -259,7 +259,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging 1] ;; CHECK: [fuzz-exec] calling ref.calling.illegal2 -;; CHECK-NEXT: [LoggingExternalInterface logging 910] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] ;; CHECK-NEXT: [fuzz-exec] comparing export.calling ;; CHECK-NEXT: [fuzz-exec] comparing export.calling.catching From 45f6cb88081a729d8a8719f5616352d2b177c9d0 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Dec 2024 14:10:29 -0800 Subject: [PATCH 16/48] fix --- scripts/fuzz_opt.py | 10 ++++++---- src/tools/fuzzing.h | 6 ++++-- src/tools/fuzzing/fuzzing.cpp | 21 +++++++++++++++------ src/tools/wasm-opt.cpp | 2 +- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index 29940383751..b60a3e29ad8 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -225,10 +225,12 @@ def randomize_fuzz_settings(): # optimizations we use to create any other wasm file. FUZZ_OPTS += ['--dce'] - # Enclose the world much of the time when fuzzing closed-world, so that many - # types are private and hence optimizable. - if CLOSED_WORLD and random.random() < 0.5: - GEN_ARGS += ['--enclose-world'] + if CLOSED_WORLD: + GEN_ARGS += [CLOSED_WORLD_FLAG] + # Enclose the world much of the time when fuzzing closed-world, so that + # many types are private and hence optimizable. + if random.random() < 0.5: + GEN_ARGS += ['--enclose-world'] print('randomized settings (NaNs, OOB, legalize):', NANS, OOB, LEGALIZE) diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index ccc870b8566..d2d6c79a2c2 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -65,8 +65,8 @@ struct BinaryArgs { class TranslateToFuzzReader { public: - TranslateToFuzzReader(Module& wasm, std::vector&& input); - TranslateToFuzzReader(Module& wasm, std::string& filename); + TranslateToFuzzReader(Module& wasm, std::vector&& input, bool closedWorld = false); + TranslateToFuzzReader(Module& wasm, std::string& filename, bool closedWorld = false); void pickPasses(OptimizationOptions& options); void setAllowMemory(bool allowMemory_) { allowMemory = allowMemory_; } @@ -77,6 +77,8 @@ class TranslateToFuzzReader { Module& wasm; private: + // Whether the module will be tested in a closed-world environment. + bool closedWorld; Builder builder; Random random; diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 3f7089844df..dc1f833691b 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -32,8 +32,9 @@ namespace { } // anonymous namespace TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, - std::vector&& input) - : wasm(wasm), builder(wasm), random(std::move(input), wasm.features) { + std::vector&& input, + bool closedWorld) + : wasm(wasm), closedWorld(closedWorld), builder(wasm), random(std::move(input), wasm.features) { // Half the time add no unreachable code so that we'll execute the most code // as possible with no early exits. @@ -50,9 +51,10 @@ TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, } TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, - std::string& filename) + std::string& filename, + bool closedWorld) : TranslateToFuzzReader( - wasm, read_file>(filename, Flags::Binary)) {} + wasm, read_file>(filename, Flags::Binary), closedWorld) {} void TranslateToFuzzReader::pickPasses(OptimizationOptions& options) { // Pick random passes to further shape the wasm. This is similar to how we @@ -197,8 +199,11 @@ void TranslateToFuzzReader::pickPasses(OptimizationOptions& options) { case 41: // GC specific passes. if (wasm.features.hasGC()) { - // Most of these depend on closed world, so just set that. + // Most of these depend on closed world, so just set that. Set it both + // on the global pass options, and in the internal state of this + // TranslateToFuzzReader instance. options.passOptions.closedWorld = true; + closedWorld = true; switch (upTo(16)) { case 0: @@ -798,7 +803,11 @@ void TranslateToFuzzReader::addImportCallingSupport() { wasm.addFunction(std::move(func)); } - if (wasm.features.hasReferenceTypes()) { + // If the wasm will be used for closed-world testing, we cannot use the + // call-ref variants: calling a function reference outside is disallowed in + // that mode (optimizations can change the reference in ways that would be + // noticeable, and look like breakage). + if (wasm.features.hasReferenceTypes() && !closedWorld) { if (choice & 4) { // Given an funcref, call it from JS. callRefImportName = Names::getValidFunctionName(wasm, "call-ref"); diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index 3e429a976fd..aab6e138459 100644 --- a/src/tools/wasm-opt.cpp +++ b/src/tools/wasm-opt.cpp @@ -303,7 +303,7 @@ int main(int argc, const char* argv[]) { } } if (translateToFuzz) { - TranslateToFuzzReader reader(wasm, options.extra["infile"]); + TranslateToFuzzReader reader(wasm, options.extra["infile"], options.passOptions.closedWorld); if (fuzzPasses) { reader.pickPasses(options); } From b5ab044b158e4c164085545953384771e978d910 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Dec 2024 15:45:05 -0800 Subject: [PATCH 17/48] fix --- src/tools/execution-results.h | 18 +++++----- test/lit/exec/fuzzing-api.wast | 62 ++++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 161c73a5486..7c82dfa6437 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -183,27 +183,27 @@ struct LoggingExternalInterface : public ShellExternalInterface { Literals callFunctionAsJS(Name name) { auto* func = wasm.getFunction(name); - // Some types trap on the JS boundary. - auto trapOnNonJSTypes = [&](Type type) { - if (type == Type::i64 || type == Type::v128) { - throwEmptyException(); - } - }; - // Send default values as arguments, or trap if we need anything else. Literals arguments; for (const auto& param : func->getParams()) { + // An i64 param can work from JS, but fuzz_shell provides 0, which traps + // on attempts to convert it to BigInt. v128 cannot work at all. + if (param == Type::i64 || param == Type::v128) { + throwEmptyException(); + } if (!param.isDefaultable()) { throwEmptyException(); } - trapOnNonJSTypes(param); arguments.push_back(Literal::makeZero(param)); } // Trap on illegal results. Note that this happens, as per JS semantics, // *before* the call. for (const auto& result : func->getResults()) { - trapOnNonJSTypes(result); + // An i64 result is fine: a BigInt will be provided. But v128 still traps. + if (result == Type::v128) { + throwEmptyException(); + } } // Call the function. diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 3e2f6772218..3317955ca71 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -176,7 +176,8 @@ ) (func $illegal (param $x i64) - ;; Helper for the function below. The param, an i64, is illegal for JS. + ;; Helper for the function below. The param, an i64, causes a problem: when we + ;; call from JS we provide 0, but 0 traps when it tries to convert to BigInt. (call $log-i32 (i32.const 56) ) @@ -184,7 +185,7 @@ ;; CHECK: [fuzz-exec] calling ref.calling.illegal ;; CHECK-NEXT: [LoggingExternalInterface logging 1] - (func $ref.calling.illegal (export "ref.calling.illegal") (param $x i64) + (func $ref.calling.illegal (export "ref.calling.illegal") ;; The i64 param causes an error here, so we will only log 1 as a trap. (call $log-i32 (call $call.ref.catch @@ -193,6 +194,24 @@ ) ) + (func $illegal-v128 (param $x v128) + ;; Helper for the function below. + (call $log-i32 + (i32.const 56) + ) + ) + + ;; CHECK: [fuzz-exec] calling ref.calling.illegal-v128 + ;; CHECK-NEXT: [LoggingExternalInterface logging 1] + (func $ref.calling.illegal-v128 (export "ref.calling.illegal-v128") + ;; As above, we trap on the v128 param, and log 1. + (call $log-i32 + (call $call.ref.catch + (ref.func $illegal-v128) + ) + ) + ) + (func $illegal-result (result v128) ;; Helper for the function below. The result is illegal for JS. (call $log-i32 @@ -201,10 +220,9 @@ (v128.const i32x4 1 2 3 4) ) - ;; CHECK: [fuzz-exec] calling ref.calling.illegal2 + ;; CHECK: [fuzz-exec] calling ref.calling.illegal-result ;; CHECK-NEXT: [LoggingExternalInterface logging 1] - ;; CHECK-NEXT: warning: no passes specified, not doing any work - (func $ref.calling.illegal2 (export "ref.calling.illegal2") + (func $ref.calling.illegal-result (export "ref.calling.illegal-result") ;; The v128 result causes an error here, so we will log 1 as a trap. The JS ;; semantics determine that we do that check *before* the call, so the logging ;; of 910 does not go through. @@ -214,6 +232,27 @@ ) ) ) + + (func $legal-result (result i64) + ;; Helper for the function below. + (call $log-i32 + (i32.const 910) + ) + (i64.const 90) + ) + + ;; CHECK: [fuzz-exec] calling ref.calling.legal-result + ;; CHECK-NEXT: [LoggingExternalInterface logging 910] + ;; CHECK-NEXT: [LoggingExternalInterface logging 0] + ;; CHECK-NEXT: warning: no passes specified, not doing any work + (func $ref.calling.legal-result (export "ref.calling.legal-result") + ;; Unlike v128, i64 is legal in a result. The JS VM just returns a BigInt. + (call $log-i32 + (call $call.ref.catch + (ref.func $legal-result) + ) + ) + ) ) ;; CHECK: [fuzz-exec] calling logging ;; CHECK-NEXT: [LoggingExternalInterface logging 42] @@ -258,16 +297,25 @@ ;; CHECK: [fuzz-exec] calling ref.calling.illegal ;; CHECK-NEXT: [LoggingExternalInterface logging 1] -;; CHECK: [fuzz-exec] calling ref.calling.illegal2 +;; CHECK: [fuzz-exec] calling ref.calling.illegal-v128 ;; CHECK-NEXT: [LoggingExternalInterface logging 1] + +;; CHECK: [fuzz-exec] calling ref.calling.illegal-result +;; CHECK-NEXT: [LoggingExternalInterface logging 1] + +;; CHECK: [fuzz-exec] calling ref.calling.legal-result +;; CHECK-NEXT: [LoggingExternalInterface logging 910] +;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [fuzz-exec] comparing export.calling ;; CHECK-NEXT: [fuzz-exec] comparing export.calling.catching ;; CHECK-NEXT: [fuzz-exec] comparing logging ;; CHECK-NEXT: [fuzz-exec] comparing ref.calling ;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.catching ;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal -;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal2 +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-result +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-v128 ;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.legal +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.legal-result ;; CHECK-NEXT: [fuzz-exec] comparing table.getting ;; CHECK-NEXT: [fuzz-exec] comparing table.setting ;; CHECK-NEXT: [fuzz-exec] comparing throwing From 6a52eea2a40fcafd81d25131ca9f595c9afad75e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Dec 2024 16:23:56 -0800 Subject: [PATCH 18/48] gufa+closed --- scripts/fuzz_opt.py | 6 +++--- src/passes/GUFA.cpp | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index b60a3e29ad8..fbe451cc07a 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -1821,9 +1821,6 @@ def write_commands(commands, filename): ("--global-refining",), ("--gsi",), ("--gto",), - ("--gufa",), - ("--gufa-cast-all",), - ("--gufa-optimizing",), ("--local-cse",), ("--heap2local",), ("--remove-unused-names", "--heap2local",), @@ -1887,6 +1884,9 @@ def write_commands(commands, filename): ("--signature-pruning",), ("--signature-refining",), ("--gto",), + ("--gufa",), + ("--gufa-cast-all",), + ("--gufa-optimizing",), ("--remove-unused-types",), ("--abstract-type-refining",), ("--cfp",), diff --git a/src/passes/GUFA.cpp b/src/passes/GUFA.cpp index 513b2cf3dc2..9bb6c2df356 100644 --- a/src/passes/GUFA.cpp +++ b/src/passes/GUFA.cpp @@ -409,6 +409,10 @@ struct GUFAPass : public Pass { : optimizing(optimizing), castAll(castAll) {} void run(Module* module) override { + if (!getPassOptions().closedWorld) { + Fatal() << "GUFA requires --closed-world"; + } + ContentOracle oracle(*module, getPassOptions()); GUFAOptimizer(oracle, optimizing, castAll).run(getPassRunner(), module); } From bae2347322a31db8bc4d3d21a15248a4adc465e4 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Dec 2024 16:41:18 -0800 Subject: [PATCH 19/48] Revert "gufa+closed" This reverts commit 6a52eea2a40fcafd81d25131ca9f595c9afad75e. --- scripts/fuzz_opt.py | 6 +++--- src/passes/GUFA.cpp | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index fbe451cc07a..b60a3e29ad8 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -1821,6 +1821,9 @@ def write_commands(commands, filename): ("--global-refining",), ("--gsi",), ("--gto",), + ("--gufa",), + ("--gufa-cast-all",), + ("--gufa-optimizing",), ("--local-cse",), ("--heap2local",), ("--remove-unused-names", "--heap2local",), @@ -1884,9 +1887,6 @@ def write_commands(commands, filename): ("--signature-pruning",), ("--signature-refining",), ("--gto",), - ("--gufa",), - ("--gufa-cast-all",), - ("--gufa-optimizing",), ("--remove-unused-types",), ("--abstract-type-refining",), ("--cfp",), diff --git a/src/passes/GUFA.cpp b/src/passes/GUFA.cpp index 9bb6c2df356..513b2cf3dc2 100644 --- a/src/passes/GUFA.cpp +++ b/src/passes/GUFA.cpp @@ -409,10 +409,6 @@ struct GUFAPass : public Pass { : optimizing(optimizing), castAll(castAll) {} void run(Module* module) override { - if (!getPassOptions().closedWorld) { - Fatal() << "GUFA requires --closed-world"; - } - ContentOracle oracle(*module, getPassOptions()); GUFAOptimizer(oracle, optimizing, castAll).run(getPassRunner(), module); } From dd65b44324bbc1dde2ced5d8b584863b87950251 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 4 Dec 2024 09:57:36 -0800 Subject: [PATCH 20/48] work --- src/ir/possible-contents.cpp | 40 ++++++++++++++++++--------- test/lit/passes/gufa-closed-open.wast | 25 +++++++++++++++++ 2 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 test/lit/passes/gufa-closed-open.wast diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 17e40f1d805..2a066703794 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -501,6 +501,10 @@ struct CollectedFuncInfo { // when we update the child we can find the parent and handle any special // behavior we need there. std::unordered_map childParents; + + // All functions that might be called from the outside. And RefFunc suggests + // that, in open world. + std::unordered_set calledFromOutside; }; // Does a walk while maintaining a map of names of branch targets to those @@ -528,8 +532,9 @@ struct BreakTargetWalker : public PostWalker { struct InfoCollector : public BreakTargetWalker> { CollectedFuncInfo& info; + const PassOptions& options; - InfoCollector(CollectedFuncInfo& info) : info(info) {} + InfoCollector(CollectedFuncInfo& info, const PassOptions& options) : info(info), options(options) {} // Check if a type is relevant for us. If not, we can ignore it entirely. bool isRelevant(Type type) { @@ -665,6 +670,10 @@ struct InfoCollector info.links.push_back( {ResultLocation{func, i}, SignatureResultLocation{func->type, i}}); } + + if (!options.closedWorld) { + info.calledFromOutside.insert(curr->func); + } } void visitRefEq(RefEq* curr) { addRoot(curr); @@ -2092,7 +2101,7 @@ Flower::Flower(Module& wasm, const PassOptions& options) // First, collect information from each function. ModuleUtils::ParallelFunctionAnalysis analysis( wasm, [&](Function* func, CollectedFuncInfo& info) { - InfoCollector finder(info); + InfoCollector finder(info, options); if (func->imported()) { // Imports return unknown values. @@ -2114,7 +2123,7 @@ Flower::Flower(Module& wasm, const PassOptions& options) // Also walk the global module code (for simplicity, also add it to the // function map, using a "function" key of nullptr). auto& globalInfo = analysis.map[nullptr]; - InfoCollector finder(globalInfo); + InfoCollector finder(globalInfo, options); finder.walkModuleCode(&wasm); #ifdef POSSIBLE_CONTENTS_DEBUG @@ -2153,6 +2162,16 @@ Flower::Flower(Module& wasm, const PassOptions& options) // above. InsertOrderedMap roots; + // Any function that may be called from the outside, like an export, is a + // root, since they can be called with unknown parameters. + auto calledFromOutside = [&](Name funcName) { + auto* func = wasm.getFunction(funcName); + auto params = func->getParams(); + for (Index i = 0; i < func->getParams().size(); i++) { + roots[ParamLocation{func, i}] = PossibleContents::fromType(params[i]); + } + }; + for (auto& [func, info] : analysis.map) { for (auto& link : info.links) { links.insert(getIndexes(link)); @@ -2171,6 +2190,10 @@ Flower::Flower(Module& wasm, const PassOptions& options) childParents[getIndex(ExpressionLocation{child, 0})] = getIndex(ExpressionLocation{parent, 0}); } + + for (auto func : info.calledFromOutside) { + calledFromOutside(func); + } } // We no longer need the function-level info. @@ -2180,16 +2203,7 @@ Flower::Flower(Module& wasm, const PassOptions& options) std::cout << "external phase\n"; #endif - // Parameters of exported functions are roots, since exports can have callers - // that we can't see, so anything might arrive there. - auto calledFromOutside = [&](Name funcName) { - auto* func = wasm.getFunction(funcName); - auto params = func->getParams(); - for (Index i = 0; i < func->getParams().size(); i++) { - roots[ParamLocation{func, i}] = PossibleContents::fromType(params[i]); - } - }; - + // Exports can be modified from the outside. for (auto& ex : wasm.exports) { if (ex->kind == ExternalKind::Function) { calledFromOutside(ex->value); diff --git a/test/lit/passes/gufa-closed-open.wast b/test/lit/passes/gufa-closed-open.wast new file mode 100644 index 00000000000..b9475a13f70 --- /dev/null +++ b/test/lit/passes/gufa-closed-open.wast @@ -0,0 +1,25 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; RUN: foreach %s %t wasm-opt -all --gufa -S -o - | filecheck %s --check-prefix OPEND +;; RUN: foreach %s %t wasm-opt -all --gufa --closed-world -S -o - | filecheck %s --check-prefix CLOSE + +;; Compare behavior on closed and open world. In open world we must assume that +;; funcrefs, for example, can be called from outside. + +(module + (import "fuzzing-support" "call-ref-catch" (func $external-caller (param funcref))) + + (func $call-import (export "call-import") + ;; Send a reference to $func to the outside, which may call it. + (call $external-caller + (ref.func $func) + ) + ) + + (func $func (param $0 i32) + ;; This is called from the outside, so this is not dead code, and nothing + ;; should change here. + (drop + (local.get $0) + ) + ) +) From 9cc1332bf382c92b1d001e47b7a87a15f475072f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 4 Dec 2024 09:59:04 -0800 Subject: [PATCH 21/48] test --- test/lit/passes/gufa-closed-open.wast | 45 ++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/test/lit/passes/gufa-closed-open.wast b/test/lit/passes/gufa-closed-open.wast index b9475a13f70..47add9df53b 100644 --- a/test/lit/passes/gufa-closed-open.wast +++ b/test/lit/passes/gufa-closed-open.wast @@ -6,8 +6,40 @@ ;; funcrefs, for example, can be called from outside. (module + ;; OPEND: (type $0 (func (param funcref))) + + ;; OPEND: (type $1 (func)) + + ;; OPEND: (type $2 (func (param i32))) + + ;; OPEND: (import "fuzzing-support" "call-ref-catch" (func $external-caller (type $0) (param funcref))) + ;; CLOSE: (type $0 (func (param funcref))) + + ;; CLOSE: (type $1 (func)) + + ;; CLOSE: (type $2 (func (param i32))) + + ;; CLOSE: (import "fuzzing-support" "call-ref-catch" (func $external-caller (type $0) (param funcref))) (import "fuzzing-support" "call-ref-catch" (func $external-caller (param funcref))) + ;; OPEND: (elem declare func $func) + + ;; OPEND: (export "call-import" (func $call-import)) + + ;; OPEND: (func $call-import (type $1) + ;; OPEND-NEXT: (call $external-caller + ;; OPEND-NEXT: (ref.func $func) + ;; OPEND-NEXT: ) + ;; OPEND-NEXT: ) + ;; CLOSE: (elem declare func $func) + + ;; CLOSE: (export "call-import" (func $call-import)) + + ;; CLOSE: (func $call-import (type $1) + ;; CLOSE-NEXT: (call $external-caller + ;; CLOSE-NEXT: (ref.func $func) + ;; CLOSE-NEXT: ) + ;; CLOSE-NEXT: ) (func $call-import (export "call-import") ;; Send a reference to $func to the outside, which may call it. (call $external-caller @@ -15,9 +47,20 @@ ) ) + ;; OPEND: (func $func (type $2) (param $0 i32) + ;; OPEND-NEXT: (drop + ;; OPEND-NEXT: (local.get $0) + ;; OPEND-NEXT: ) + ;; OPEND-NEXT: ) + ;; CLOSE: (func $func (type $2) (param $0 i32) + ;; CLOSE-NEXT: (drop + ;; CLOSE-NEXT: (unreachable) + ;; CLOSE-NEXT: ) + ;; CLOSE-NEXT: ) (func $func (param $0 i32) ;; This is called from the outside, so this is not dead code, and nothing - ;; should change here. + ;; should change here in open world. In closed world, this can become an + ;; unreachable, since nothing can call it. (drop (local.get $0) ) From 039e0a1a77b99c394e6567baa49ad96e3df0f404 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 4 Dec 2024 10:01:05 -0800 Subject: [PATCH 22/48] test --- test/lit/passes/gufa-refs.wast | 5 ++++- test/lit/passes/gufa.wast | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast index 9772745bc28..80fd323869c 100644 --- a/test/lit/passes/gufa-refs.wast +++ b/test/lit/passes/gufa-refs.wast @@ -1,5 +1,8 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. -;; RUN: foreach %s %t wasm-opt -all --gufa -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt -all --gufa --closed-world -S -o - | filecheck %s + +;; Closed-world is applied here to avoid treating all ref.funcs as callable +;; from outside (and this is the more important mode to test on). (module ;; CHECK: (type $struct (struct)) diff --git a/test/lit/passes/gufa.wast b/test/lit/passes/gufa.wast index fcb60310ad4..721c27eeb66 100644 --- a/test/lit/passes/gufa.wast +++ b/test/lit/passes/gufa.wast @@ -1,5 +1,8 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. -;; RUN: foreach %s %t wasm-opt -all --gufa -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt -all --gufa --closed-world -S -o - | filecheck %s + +;; Closed-world is applied here to avoid treating all ref.funcs as callable +;; from outside (and this is the more important mode to test on). (module ;; CHECK: (type $0 (func (result i32))) From 768bde07b18a688db3060cb8297f360de9591b52 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 4 Dec 2024 10:01:22 -0800 Subject: [PATCH 23/48] format --- src/ir/possible-contents.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 2a066703794..62e80a185a8 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -534,7 +534,8 @@ struct InfoCollector CollectedFuncInfo& info; const PassOptions& options; - InfoCollector(CollectedFuncInfo& info, const PassOptions& options) : info(info), options(options) {} + InfoCollector(CollectedFuncInfo& info, const PassOptions& options) + : info(info), options(options) {} // Check if a type is relevant for us. If not, we can ignore it entirely. bool isRelevant(Type type) { From d2a142aac1c94974825060540e2673738a9a1152 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 4 Dec 2024 11:08:32 -0800 Subject: [PATCH 24/48] comment --- src/ir/possible-contents.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 62e80a185a8..00a2cb82500 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -502,8 +502,10 @@ struct CollectedFuncInfo { // behavior we need there. std::unordered_map childParents; - // All functions that might be called from the outside. And RefFunc suggests - // that, in open world. + // All functions that might be called from the outside. Any RefFunc suggests + // that, in open world. (We could be more precise and use our flow analysis to + // see which, in fact, flow outside, but it is unclear how useful that would + // be. Anyhow, closed-world is more important to optimize, and avoids this.) std::unordered_set calledFromOutside; }; From 1441b119b781ffff130a9007844eb78c12133529 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 4 Dec 2024 11:24:35 -0800 Subject: [PATCH 25/48] fix --- scripts/fuzz_opt.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index b60a3e29ad8..6a5cde1cbf1 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -363,6 +363,11 @@ def is_git_repo(): 'typed_continuations_suspend.wast', ] +INITIAL_CONTENTS_IGNORE_CLOSED_WORLD = [ + # call-ref* fuzzer APIs assume an open world + 'fuzzing-api.wast', +] + def pick_initial_contents(): # if we use an initial wasm file's contents as the basis for the @@ -386,14 +391,17 @@ def pick_initial_contents(): # no longer exist, and we should just skip it. if not os.path.exists(test_name): return - if os.path.basename(test_name) in INITIAL_CONTENTS_IGNORE: + basename = os.path.basename(test_name) + if basename in INITIAL_CONTENTS_IGNORE: + return + if CLOSED_WORLD and basename in INITIAL_CONTENTS_IGNORE_CLOSED_WORLD: return assert os.path.exists(test_name) # tests that check validation errors are not helpful for us if '.fail.' in test_name: print('initial contents is just a .fail test') return - if os.path.basename(test_name) in [ + if basename in [ # contains too many segments to run in a wasm VM 'limit-segments_disable-bulk-memory.wast', # https://github.com/WebAssembly/binaryen/issues/3203 From 00990f48a1e6cffaf7617070e156485822bcdeee Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 4 Dec 2024 11:45:56 -0800 Subject: [PATCH 26/48] Revert "fix" This reverts commit 1441b119b781ffff130a9007844eb78c12133529. --- scripts/fuzz_opt.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index 6a5cde1cbf1..b60a3e29ad8 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -363,11 +363,6 @@ def is_git_repo(): 'typed_continuations_suspend.wast', ] -INITIAL_CONTENTS_IGNORE_CLOSED_WORLD = [ - # call-ref* fuzzer APIs assume an open world - 'fuzzing-api.wast', -] - def pick_initial_contents(): # if we use an initial wasm file's contents as the basis for the @@ -391,17 +386,14 @@ def pick_initial_contents(): # no longer exist, and we should just skip it. if not os.path.exists(test_name): return - basename = os.path.basename(test_name) - if basename in INITIAL_CONTENTS_IGNORE: - return - if CLOSED_WORLD and basename in INITIAL_CONTENTS_IGNORE_CLOSED_WORLD: + if os.path.basename(test_name) in INITIAL_CONTENTS_IGNORE: return assert os.path.exists(test_name) # tests that check validation errors are not helpful for us if '.fail.' in test_name: print('initial contents is just a .fail test') return - if basename in [ + if os.path.basename(test_name) in [ # contains too many segments to run in a wasm VM 'limit-segments_disable-bulk-memory.wast', # https://github.com/WebAssembly/binaryen/issues/3203 From c092c81cd296d2de1f7562a37fe069b5c5127dcb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 4 Dec 2024 11:51:48 -0800 Subject: [PATCH 27/48] fix --- src/tools/fuzzing/fuzzing.cpp | 60 +++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index dc1f833691b..b0bdf764e8f 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -807,29 +807,43 @@ void TranslateToFuzzReader::addImportCallingSupport() { // call-ref variants: calling a function reference outside is disallowed in // that mode (optimizations can change the reference in ways that would be // noticeable, and look like breakage). - if (wasm.features.hasReferenceTypes() && !closedWorld) { - if (choice & 4) { - // Given an funcref, call it from JS. - callRefImportName = Names::getValidFunctionName(wasm, "call-ref"); - auto func = std::make_unique(); - func->name = callRefImportName; - func->module = "fuzzing-support"; - func->base = "call-ref"; - func->type = Signature({Type(HeapType::func, Nullable)}, Type::none); - wasm.addFunction(std::move(func)); - } - - if (choice & 8) { - // Given an funcref, call it from JS and catch all exceptions (similar to - // callExportCatch), return 1 if we caught). - callRefCatchImportName = - Names::getValidFunctionName(wasm, "call-ref-catch"); - auto func = std::make_unique(); - func->name = callRefCatchImportName; - func->module = "fuzzing-support"; - func->base = "call-ref-catch"; - func->type = Signature(Type(HeapType::func, Nullable), Type::i32); - wasm.addFunction(std::move(func)); + if (wasm.features.hasReferenceTypes()) { + if (closedWorld) { + // We are in closed world. Remove the call-ref* imports, if they exist. + for (auto& func : wasm.functions) { + if (func->imported() && func->module == "fuzzing-support" && + func->base.startsWith("call-ref")) { + // Make it non-imported, and with a simple body. + func->module = func->base = Name(); + auto results = func->getResults(); + func->body = results.isConcrete() ? makeConst(results) : makeNop(Type::none); + } + } + } else { + // We are in open world. Add the call-ref* imports, sometimes. + if (choice & 4) { + // Given an funcref, call it from JS. + callRefImportName = Names::getValidFunctionName(wasm, "call-ref"); + auto func = std::make_unique(); + func->name = callRefImportName; + func->module = "fuzzing-support"; + func->base = "call-ref"; + func->type = Signature({Type(HeapType::func, Nullable)}, Type::none); + wasm.addFunction(std::move(func)); + } + + if (choice & 8) { + // Given an funcref, call it from JS and catch all exceptions (similar + // to callExportCatch), return 1 if we caught). + callRefCatchImportName = + Names::getValidFunctionName(wasm, "call-ref-catch"); + auto func = std::make_unique(); + func->name = callRefCatchImportName; + func->module = "fuzzing-support"; + func->base = "call-ref-catch"; + func->type = Signature(Type(HeapType::func, Nullable), Type::i32); + wasm.addFunction(std::move(func)); + } } } } From 0c53f030ab9ec11216a93f0575f7bb09f48b841d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 4 Dec 2024 12:09:57 -0800 Subject: [PATCH 28/48] fix --- test/lit/passes/gufa-closed-open.wast | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/lit/passes/gufa-closed-open.wast b/test/lit/passes/gufa-closed-open.wast index 47add9df53b..689ee194f85 100644 --- a/test/lit/passes/gufa-closed-open.wast +++ b/test/lit/passes/gufa-closed-open.wast @@ -12,15 +12,15 @@ ;; OPEND: (type $2 (func (param i32))) - ;; OPEND: (import "fuzzing-support" "call-ref-catch" (func $external-caller (type $0) (param funcref))) + ;; OPEND: (import "outside" "call-ref-catch" (func $external-caller (type $0) (param funcref))) ;; CLOSE: (type $0 (func (param funcref))) ;; CLOSE: (type $1 (func)) ;; CLOSE: (type $2 (func (param i32))) - ;; CLOSE: (import "fuzzing-support" "call-ref-catch" (func $external-caller (type $0) (param funcref))) - (import "fuzzing-support" "call-ref-catch" (func $external-caller (param funcref))) + ;; CLOSE: (import "outside" "call-ref-catch" (func $external-caller (type $0) (param funcref))) + (import "outside" "call-ref-catch" (func $external-caller (param funcref))) ;; OPEND: (elem declare func $func) From c20343c3a8bbc3713fca0cc22b02fa1b15d364b9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 4 Dec 2024 12:50:42 -0800 Subject: [PATCH 29/48] format --- src/tools/fuzzing.h | 8 ++++++-- src/tools/fuzzing/fuzzing.cpp | 11 +++++++---- src/tools/wasm-opt.cpp | 3 ++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index d2d6c79a2c2..78219045c71 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -65,8 +65,12 @@ struct BinaryArgs { class TranslateToFuzzReader { public: - TranslateToFuzzReader(Module& wasm, std::vector&& input, bool closedWorld = false); - TranslateToFuzzReader(Module& wasm, std::string& filename, bool closedWorld = false); + TranslateToFuzzReader(Module& wasm, + std::vector&& input, + bool closedWorld = false); + TranslateToFuzzReader(Module& wasm, + std::string& filename, + bool closedWorld = false); void pickPasses(OptimizationOptions& options); void setAllowMemory(bool allowMemory_) { allowMemory = allowMemory_; } diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index b0bdf764e8f..a8f32d17ef1 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -34,7 +34,8 @@ namespace { TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, std::vector&& input, bool closedWorld) - : wasm(wasm), closedWorld(closedWorld), builder(wasm), random(std::move(input), wasm.features) { + : wasm(wasm), closedWorld(closedWorld), builder(wasm), + random(std::move(input), wasm.features) { // Half the time add no unreachable code so that we'll execute the most code // as possible with no early exits. @@ -53,8 +54,9 @@ TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, std::string& filename, bool closedWorld) - : TranslateToFuzzReader( - wasm, read_file>(filename, Flags::Binary), closedWorld) {} + : TranslateToFuzzReader(wasm, + read_file>(filename, Flags::Binary), + closedWorld) {} void TranslateToFuzzReader::pickPasses(OptimizationOptions& options) { // Pick random passes to further shape the wasm. This is similar to how we @@ -816,7 +818,8 @@ void TranslateToFuzzReader::addImportCallingSupport() { // Make it non-imported, and with a simple body. func->module = func->base = Name(); auto results = func->getResults(); - func->body = results.isConcrete() ? makeConst(results) : makeNop(Type::none); + func->body = + results.isConcrete() ? makeConst(results) : makeNop(Type::none); } } } else { diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index aab6e138459..2f8d225802b 100644 --- a/src/tools/wasm-opt.cpp +++ b/src/tools/wasm-opt.cpp @@ -303,7 +303,8 @@ int main(int argc, const char* argv[]) { } } if (translateToFuzz) { - TranslateToFuzzReader reader(wasm, options.extra["infile"], options.passOptions.closedWorld); + TranslateToFuzzReader reader( + wasm, options.extra["infile"], options.passOptions.closedWorld); if (fuzzPasses) { reader.pickPasses(options); } From dc002e1207e961dddb7c6cb5f04ff75df5886458 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 4 Dec 2024 12:54:34 -0800 Subject: [PATCH 30/48] [NFC] Send the closed-world flag to TranslateToFuzzReader --- scripts/fuzz_opt.py | 10 ++++++---- src/tools/fuzzing.h | 10 ++++++++-- src/tools/fuzzing/fuzzing.cpp | 19 +++++++++++++------ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index 29940383751..b60a3e29ad8 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -225,10 +225,12 @@ def randomize_fuzz_settings(): # optimizations we use to create any other wasm file. FUZZ_OPTS += ['--dce'] - # Enclose the world much of the time when fuzzing closed-world, so that many - # types are private and hence optimizable. - if CLOSED_WORLD and random.random() < 0.5: - GEN_ARGS += ['--enclose-world'] + if CLOSED_WORLD: + GEN_ARGS += [CLOSED_WORLD_FLAG] + # Enclose the world much of the time when fuzzing closed-world, so that + # many types are private and hence optimizable. + if random.random() < 0.5: + GEN_ARGS += ['--enclose-world'] print('randomized settings (NaNs, OOB, legalize):', NANS, OOB, LEGALIZE) diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 1afb4bf36f7..a3261ccbe59 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -65,8 +65,12 @@ struct BinaryArgs { class TranslateToFuzzReader { public: - TranslateToFuzzReader(Module& wasm, std::vector&& input); - TranslateToFuzzReader(Module& wasm, std::string& filename); + TranslateToFuzzReader(Module& wasm, + std::vector&& input, + bool closedWorld = false); + TranslateToFuzzReader(Module& wasm, + std::string& filename, + bool closedWorld = false); void pickPasses(OptimizationOptions& options); void setAllowMemory(bool allowMemory_) { allowMemory = allowMemory_; } @@ -77,6 +81,8 @@ class TranslateToFuzzReader { Module& wasm; private: + // Whether the module will be tested in a closed-world environment. + bool closedWorld; Builder builder; Random random; diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 7e87f4f5850..ab200a12635 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -32,8 +32,10 @@ namespace { } // anonymous namespace TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, - std::vector&& input) - : wasm(wasm), builder(wasm), random(std::move(input), wasm.features) { + std::vector&& input, + bool closedWorld) + : wasm(wasm), closedWorld(closedWorld), builder(wasm), + random(std::move(input), wasm.features) { // Half the time add no unreachable code so that we'll execute the most code // as possible with no early exits. @@ -50,9 +52,11 @@ TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, } TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, - std::string& filename) - : TranslateToFuzzReader( - wasm, read_file>(filename, Flags::Binary)) {} + std::string& filename, + bool closedWorld) + : TranslateToFuzzReader(wasm, + read_file>(filename, Flags::Binary), + closedWorld) {} void TranslateToFuzzReader::pickPasses(OptimizationOptions& options) { // Pick random passes to further shape the wasm. This is similar to how we @@ -197,8 +201,11 @@ void TranslateToFuzzReader::pickPasses(OptimizationOptions& options) { case 41: // GC specific passes. if (wasm.features.hasGC()) { - // Most of these depend on closed world, so just set that. + // Most of these depend on closed world, so just set that. Set it both + // on the global pass options, and in the internal state of this + // TranslateToFuzzReader instance. options.passOptions.closedWorld = true; + closedWorld = true; switch (upTo(16)) { case 0: From 23e67392688b301d3c23da694593e023e1254375 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 4 Dec 2024 13:21:30 -0800 Subject: [PATCH 31/48] refine --- src/tools/fuzzing/fuzzing.cpp | 38 ++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index a8f32d17ef1..b258885e937 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1040,21 +1040,35 @@ Expression* TranslateToFuzzReader::makeImportCallCode(Type type) { // Call code: either an export or a ref. Each has a catching and non-catching // variant. The catching variants return i32, the others none. assert(type == Type::none || type == Type::i32); + auto catching = type == Type::i32; auto exportTarget = - type == Type::none ? callExportImportName : callExportCatchImportName; - auto refTarget = - type == Type::none ? callRefImportName : callRefCatchImportName; - - // We want to call a ref rarely, as refs are more likely to trap. - if (refTarget && (!exportTarget || oneIn(4))) { - // Most of the time make a non-nullable funcref, to avoid trapping. - auto refType = Type(HeapType::func, oneIn(10) ? Nullable : NonNullable); - return builder.makeCall(refTarget, {make(refType)}, type); + catching ? callExportCatchImportName : callExportImportName; + auto refTarget = catching ? callRefCatchImportName : callRefImportName; + + // We want to call a ref less often, as refs are more likely to trap (a + // function reference can have arbitrary params and results, including things + // that trap on the JS boundary; an export is already filtered for such + // things in some cases - when we legalize the boundary - and even if not, we + // emit lots of void(void) functions - all the invoke_foo functions - that are + // safe to call). + if (refTarget) { + // This matters a lot more in the variants that do *not* catch (in the + // catching ones, we just get a result of 1, but when not caught it halts + // execution). + if ((catching && (!exportTarget || oneIn(2)) || + (!catching && oneIn(4))) { + // Most of the time make a non-nullable funcref, to avoid trapping. + auto refType = Type(HeapType::func, oneIn(10) ? Nullable : NonNullable); + return builder.makeCall(refTarget, {make(refType)}, type); + } + } + + if (!exportTarget) { + // We decided not to emit a call-ref here, due to fear of trapping, and + // there is no call-export, so just emit something trivial. + return makeTrivial(type); } - // Call an export. - assert(exportTarget); - // Pick the maximum export index to call. Index maxIndex = wasm.exports.size(); if (type == Type::i32) { From d50b97fbd2326c5cd49c23aa257f9abc16b97805 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 4 Dec 2024 13:21:55 -0800 Subject: [PATCH 32/48] refine --- 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 b258885e937..bec87436114 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1055,7 +1055,7 @@ Expression* TranslateToFuzzReader::makeImportCallCode(Type type) { // This matters a lot more in the variants that do *not* catch (in the // catching ones, we just get a result of 1, but when not caught it halts // execution). - if ((catching && (!exportTarget || oneIn(2)) || + if ((catching && (!exportTarget || oneIn(2))) || (!catching && oneIn(4))) { // Most of the time make a non-nullable funcref, to avoid trapping. auto refType = Type(HeapType::func, oneIn(10) ? Nullable : NonNullable); From 886c15b4890c77c44de7506b2f80beabde876990 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 08:54:25 -0800 Subject: [PATCH 33/48] fix --- src/tools/fuzzing/fuzzing.cpp | 78 ++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index bec87436114..c7eec3e22cf 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -771,6 +771,24 @@ void TranslateToFuzzReader::addImportLoggingSupport() { } void TranslateToFuzzReader::addImportCallingSupport() { + if (wasm.features.hasReferenceTypes() && closedWorld) { + // In closed world mode we must *remove* the call-ref* imports, if they + // exist in the initial content. These are not valid to call in closed-world + // mode as they call function references. (Another solution here would be to + // make closed-world issue validation errors on these imports, but that + // would require changes to the general-purpose validator.) + for (auto& func : wasm.functions) { + if (func->imported() && func->module == "fuzzing-support" && + func->base.startsWith("call-ref")) { + // Make it non-imported, and with a simple body. + func->module = func->base = Name(); + auto results = func->getResults(); + func->body = + results.isConcrete() ? makeConst(results) : makeNop(Type::none); + } + } + } + // Only add these some of the time, as they inhibit some fuzzing (things like // wasm-ctor-eval and wasm-merge are sensitive to the wasm being able to call // its own exports, and to care about the indexes of the exports). @@ -810,43 +828,29 @@ void TranslateToFuzzReader::addImportCallingSupport() { // that mode (optimizations can change the reference in ways that would be // noticeable, and look like breakage). if (wasm.features.hasReferenceTypes()) { - if (closedWorld) { - // We are in closed world. Remove the call-ref* imports, if they exist. - for (auto& func : wasm.functions) { - if (func->imported() && func->module == "fuzzing-support" && - func->base.startsWith("call-ref")) { - // Make it non-imported, and with a simple body. - func->module = func->base = Name(); - auto results = func->getResults(); - func->body = - results.isConcrete() ? makeConst(results) : makeNop(Type::none); - } - } - } else { - // We are in open world. Add the call-ref* imports, sometimes. - if (choice & 4) { - // Given an funcref, call it from JS. - callRefImportName = Names::getValidFunctionName(wasm, "call-ref"); - auto func = std::make_unique(); - func->name = callRefImportName; - func->module = "fuzzing-support"; - func->base = "call-ref"; - func->type = Signature({Type(HeapType::func, Nullable)}, Type::none); - wasm.addFunction(std::move(func)); - } - - if (choice & 8) { - // Given an funcref, call it from JS and catch all exceptions (similar - // to callExportCatch), return 1 if we caught). - callRefCatchImportName = - Names::getValidFunctionName(wasm, "call-ref-catch"); - auto func = std::make_unique(); - func->name = callRefCatchImportName; - func->module = "fuzzing-support"; - func->base = "call-ref-catch"; - func->type = Signature(Type(HeapType::func, Nullable), Type::i32); - wasm.addFunction(std::move(func)); - } + // We are in open world. Add the call-ref* imports, sometimes. + if (choice & 4) { + // Given an funcref, call it from JS. + callRefImportName = Names::getValidFunctionName(wasm, "call-ref"); + auto func = std::make_unique(); + func->name = callRefImportName; + func->module = "fuzzing-support"; + func->base = "call-ref"; + func->type = Signature({Type(HeapType::func, Nullable)}, Type::none); + wasm.addFunction(std::move(func)); + } + + if (choice & 8) { + // Given an funcref, call it from JS and catch all exceptions (similar + // to callExportCatch), return 1 if we caught). + callRefCatchImportName = + Names::getValidFunctionName(wasm, "call-ref-catch"); + auto func = std::make_unique(); + func->name = callRefCatchImportName; + func->module = "fuzzing-support"; + func->base = "call-ref-catch"; + func->type = Signature(Type(HeapType::func, Nullable), Type::i32); + wasm.addFunction(std::move(func)); } } } From a872081f4f83b62427d9caf21ef845419d9898cb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 09:00:18 -0800 Subject: [PATCH 34/48] Send closed-world to the fuzzer from wasm-opt --- src/tools/wasm-opt.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index 3e429a976fd..2f8d225802b 100644 --- a/src/tools/wasm-opt.cpp +++ b/src/tools/wasm-opt.cpp @@ -303,7 +303,8 @@ int main(int argc, const char* argv[]) { } } if (translateToFuzz) { - TranslateToFuzzReader reader(wasm, options.extra["infile"]); + TranslateToFuzzReader reader( + wasm, options.extra["infile"], options.passOptions.closedWorld); if (fuzzPasses) { reader.pickPasses(options); } From 12088b8c7489b177e5f32e6ffe6a406e75c86fd7 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 09:54:35 -0800 Subject: [PATCH 35/48] fix --- src/tools/fuzzing/fuzzing.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index c7eec3e22cf..d1df1a85b22 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -827,8 +827,7 @@ void TranslateToFuzzReader::addImportCallingSupport() { // call-ref variants: calling a function reference outside is disallowed in // that mode (optimizations can change the reference in ways that would be // noticeable, and look like breakage). - if (wasm.features.hasReferenceTypes()) { - // We are in open world. Add the call-ref* imports, sometimes. + if (wasm.features.hasReferenceTypes() && !closedWorld) { if (choice & 4) { // Given an funcref, call it from JS. callRefImportName = Names::getValidFunctionName(wasm, "call-ref"); From 28cc035bf469595901d6713a51f550885088781a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 11:08:03 -0800 Subject: [PATCH 36/48] fixes --- src/tools/fuzzing/fuzzing.cpp | 4 +--- test/lit/exec/fuzzing-api.wast | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index d1df1a85b22..5c9783df0eb 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -824,9 +824,7 @@ void TranslateToFuzzReader::addImportCallingSupport() { } // If the wasm will be used for closed-world testing, we cannot use the - // call-ref variants: calling a function reference outside is disallowed in - // that mode (optimizations can change the reference in ways that would be - // noticeable, and look like breakage). + // call-ref variants, as mentioned before. if (wasm.features.hasReferenceTypes() && !closedWorld) { if (choice & 4) { // Given an funcref, call it from JS. diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 3317955ca71..7e5ed8747dd 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -169,7 +169,7 @@ (func $ref.calling.legal (export "ref.calling.legal") ;; It is fine to call-ref a function with params and results. The params get ;; default values, and the results are ignored. All we will see here is the - ;; logging from the function, "1234". + ;; logging from the function, "12". (call $call.ref (ref.func $legal) ) From cda78bfd6c28d4e085ecbf4f2daa18d68ebc181a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 11:12:52 -0800 Subject: [PATCH 37/48] format --- src/tools/fuzzing/fuzzing.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 5c9783df0eb..f6c249cf2d0 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1056,8 +1056,7 @@ Expression* TranslateToFuzzReader::makeImportCallCode(Type type) { // This matters a lot more in the variants that do *not* catch (in the // catching ones, we just get a result of 1, but when not caught it halts // execution). - if ((catching && (!exportTarget || oneIn(2))) || - (!catching && oneIn(4))) { + if ((catching && (!exportTarget || oneIn(2))) || (!catching && oneIn(4))) { // Most of the time make a non-nullable funcref, to avoid trapping. auto refType = Type(HeapType::func, oneIn(10) ? Nullable : NonNullable); return builder.makeCall(refTarget, {make(refType)}, type); From 79158a045a0afeabfead072450e22bdb34de2c83 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 16:16:52 -0800 Subject: [PATCH 38/48] clarify comment --- src/tools/fuzzing/fuzzing.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index f6c249cf2d0..4c5ddcb9ae6 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1072,8 +1072,8 @@ Expression* TranslateToFuzzReader::makeImportCallCode(Type type) { // Pick the maximum export index to call. Index maxIndex = wasm.exports.size(); if (type == Type::i32) { - // This never traps, so we can be less careful, but we do still want to - // avoid trapping a lot as executing code is more interesting. (Note that + // This swallows traps, so we can be less careful, but we do still want to + // avoid swallowing a lot as executing code is more interesting. (Note that // even though we double here, the risk is not that great: we are still // adding functions as we go, so the first half of functions/exports can // double here and still end up in bounds by the time we've added them all.) From 8540938cf139ba31ad26b0cc87308d14b9465d64 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 16:19:47 -0800 Subject: [PATCH 39/48] Update test/lit/exec/fuzzing-api.wast Co-authored-by: Thomas Lively --- test/lit/exec/fuzzing-api.wast | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 7e5ed8747dd..4247ef6bab4 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -148,7 +148,7 @@ (ref.func $logging) ) ) - ;; The trap here is caught, and we'll log 1. + ;; The exception here is caught, and we'll log 1. (call $log-i32 (call $call.ref.catch (ref.null func) From 035b6bf27daecdb3005eabf49ae7daa1ebb734d5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 16:22:14 -0800 Subject: [PATCH 40/48] add logging --- test/lit/exec/fuzzing-api.wast | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 4247ef6bab4..08112a8f3c2 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -130,7 +130,7 @@ (call $call.ref (ref.func $logging) ) - ;; This will trap. + ;; This will throw. (call $call.ref (ref.null func) ) @@ -161,11 +161,17 @@ (call $log-i32 (i32.const 12) ) + ;; Also log the param to show it is 0, which is what $call.ref does for all + ;; params. + (call $log-i32 + (local.get $x) + ) (i32.const 34) ) ;; CHECK: [fuzz-exec] calling ref.calling.legal ;; CHECK-NEXT: [LoggingExternalInterface logging 12] + ;; CHECK-NEXT: [LoggingExternalInterface logging 0] (func $ref.calling.legal (export "ref.calling.legal") ;; It is fine to call-ref a function with params and results. The params get ;; default values, and the results are ignored. All we will see here is the @@ -293,6 +299,7 @@ ;; CHECK: [fuzz-exec] calling ref.calling.legal ;; CHECK-NEXT: [LoggingExternalInterface logging 12] +;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK: [fuzz-exec] calling ref.calling.illegal ;; CHECK-NEXT: [LoggingExternalInterface logging 1] From a05dcd59622ab171fb5630e2db3eccc479595114 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 16:23:16 -0800 Subject: [PATCH 41/48] Update test/lit/exec/fuzzing-api.wast Co-authored-by: Thomas Lively --- test/lit/exec/fuzzing-api.wast | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 08112a8f3c2..5f486ed4c31 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -183,7 +183,7 @@ (func $illegal (param $x i64) ;; Helper for the function below. The param, an i64, causes a problem: when we - ;; call from JS we provide 0, but 0 traps when it tries to convert to BigInt. + ;; call from JS we provide 0, but 0 throws when it tries to convert to BigInt. (call $log-i32 (i32.const 56) ) From 2ff869845af03615ec190dfaf65e82a40f94dd5d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 16:23:36 -0800 Subject: [PATCH 42/48] Update test/lit/exec/fuzzing-api.wast Co-authored-by: Thomas Lively --- test/lit/exec/fuzzing-api.wast | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 5f486ed4c31..5ab51f0eec1 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -192,7 +192,7 @@ ;; CHECK: [fuzz-exec] calling ref.calling.illegal ;; CHECK-NEXT: [LoggingExternalInterface logging 1] (func $ref.calling.illegal (export "ref.calling.illegal") - ;; The i64 param causes an error here, so we will only log 1 as a trap. + ;; The i64 param causes an error here, so we will only log 1 because we catch an exception. (call $log-i32 (call $call.ref.catch (ref.func $illegal) From 1d33abead3f00cf2e3adc6a9743af68d4fd166f5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 16:23:50 -0800 Subject: [PATCH 43/48] Update test/lit/exec/fuzzing-api.wast Co-authored-by: Thomas Lively --- test/lit/exec/fuzzing-api.wast | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 5ab51f0eec1..38ea08a4b2f 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -210,7 +210,7 @@ ;; CHECK: [fuzz-exec] calling ref.calling.illegal-v128 ;; CHECK-NEXT: [LoggingExternalInterface logging 1] (func $ref.calling.illegal-v128 (export "ref.calling.illegal-v128") - ;; As above, we trap on the v128 param, and log 1. + ;; As above, we throw on the v128 param, and log 1. (call $log-i32 (call $call.ref.catch (ref.func $illegal-v128) From 72b144f9549ceda3d86e8ba124b346b055362065 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 16:25:43 -0800 Subject: [PATCH 44/48] add trapping test --- test/lit/exec/fuzzing-api.wast | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 38ea08a4b2f..348daa3db4c 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -250,7 +250,6 @@ ;; CHECK: [fuzz-exec] calling ref.calling.legal-result ;; CHECK-NEXT: [LoggingExternalInterface logging 910] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] - ;; CHECK-NEXT: warning: no passes specified, not doing any work (func $ref.calling.legal-result (export "ref.calling.legal-result") ;; Unlike v128, i64 is legal in a result. The JS VM just returns a BigInt. (call $log-i32 @@ -259,6 +258,24 @@ ) ) ) + + (func $trap + ;; Helper for the function below. + (unreachable) + ) + + ;; CHECK: [fuzz-exec] calling ref.calling.trap + ;; CHECK-NEXT: [trap unreachable] + ;; CHECK-NEXT: warning: no passes specified, not doing any work + (func $ref.calling.trap (export "ref.calling.trap") + ;; We try to catch an exception here, but the target function traps, which is + ;; not something we can catch. We will trap here, and not log at all. + (call $log-i32 + (call $call.ref.catch + (ref.func $trap) + ) + ) + ) ) ;; CHECK: [fuzz-exec] calling logging ;; CHECK-NEXT: [LoggingExternalInterface logging 42] @@ -313,6 +330,9 @@ ;; CHECK: [fuzz-exec] calling ref.calling.legal-result ;; CHECK-NEXT: [LoggingExternalInterface logging 910] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] + +;; CHECK: [fuzz-exec] calling ref.calling.trap +;; CHECK-NEXT: [trap unreachable] ;; CHECK-NEXT: [fuzz-exec] comparing export.calling ;; CHECK-NEXT: [fuzz-exec] comparing export.calling.catching ;; CHECK-NEXT: [fuzz-exec] comparing logging @@ -323,6 +343,7 @@ ;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-v128 ;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.legal ;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.legal-result +;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.trap ;; CHECK-NEXT: [fuzz-exec] comparing table.getting ;; CHECK-NEXT: [fuzz-exec] comparing table.setting ;; CHECK-NEXT: [fuzz-exec] comparing throwing From a0abc0773a9fb622c31d5d877c85f71dedc3a5b9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 16:46:54 -0800 Subject: [PATCH 45/48] fix some trap mentions --- src/tools/fuzzing/fuzzing.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 4c5ddcb9ae6..a7f5e0d018f 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1046,9 +1046,9 @@ Expression* TranslateToFuzzReader::makeImportCallCode(Type type) { catching ? callExportCatchImportName : callExportImportName; auto refTarget = catching ? callRefCatchImportName : callRefImportName; - // We want to call a ref less often, as refs are more likely to trap (a + // We want to call a ref less often, as refs are more likely to error (a // function reference can have arbitrary params and results, including things - // that trap on the JS boundary; an export is already filtered for such + // that error on the JS boundary; an export is already filtered for such // things in some cases - when we legalize the boundary - and even if not, we // emit lots of void(void) functions - all the invoke_foo functions - that are // safe to call). @@ -1057,14 +1057,14 @@ Expression* TranslateToFuzzReader::makeImportCallCode(Type type) { // catching ones, we just get a result of 1, but when not caught it halts // execution). if ((catching && (!exportTarget || oneIn(2))) || (!catching && oneIn(4))) { - // Most of the time make a non-nullable funcref, to avoid trapping. + // Most of the time make a non-nullable funcref, to avoid errors. auto refType = Type(HeapType::func, oneIn(10) ? Nullable : NonNullable); return builder.makeCall(refTarget, {make(refType)}, type); } } if (!exportTarget) { - // We decided not to emit a call-ref here, due to fear of trapping, and + // We decided not to emit a call-ref here, due to fear of erroring, and // there is no call-export, so just emit something trivial. return makeTrivial(type); } @@ -1072,7 +1072,7 @@ Expression* TranslateToFuzzReader::makeImportCallCode(Type type) { // Pick the maximum export index to call. Index maxIndex = wasm.exports.size(); if (type == Type::i32) { - // This swallows traps, so we can be less careful, but we do still want to + // This swallows errors, so we can be less careful, but we do still want to // avoid swallowing a lot as executing code is more interesting. (Note that // even though we double here, the risk is not that great: we are still // adding functions as we go, so the first half of functions/exports can From 5d78cd87d080c2ed2af8c67d53f51b6a2f5bec58 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 16:49:45 -0800 Subject: [PATCH 46/48] another --- 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 7c82dfa6437..3633d1e2cca 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -186,7 +186,7 @@ struct LoggingExternalInterface : public ShellExternalInterface { // Send default values as arguments, or trap if we need anything else. Literals arguments; for (const auto& param : func->getParams()) { - // An i64 param can work from JS, but fuzz_shell provides 0, which traps + // An i64 param can work from JS, but fuzz_shell provides 0, which errors // on attempts to convert it to BigInt. v128 cannot work at all. if (param == Type::i64 || param == Type::v128) { throwEmptyException(); From 0a31791b0d980480a4341482dab291852bcc4847 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 16:50:37 -0800 Subject: [PATCH 47/48] more --- src/tools/execution-results.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 3633d1e2cca..bffc4e8f2b2 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -178,12 +178,12 @@ struct LoggingExternalInterface : public ShellExternalInterface { return callFunctionAsJS(ref.getFunc()); } - // Call a function in a "JS-ey" manner, adding arguments as needed, the same - // way JS does. + // Call a function in a "JS-ey" manner, adding arguments as needed, and + // throwing if necessary, the same way JS does. Literals callFunctionAsJS(Name name) { auto* func = wasm.getFunction(name); - // Send default values as arguments, or trap if we need anything else. + // Send default values as arguments, or error if we need anything else. Literals arguments; for (const auto& param : func->getParams()) { // An i64 param can work from JS, but fuzz_shell provides 0, which errors @@ -197,10 +197,11 @@ struct LoggingExternalInterface : public ShellExternalInterface { arguments.push_back(Literal::makeZero(param)); } - // Trap on illegal results. Note that this happens, as per JS semantics, + // Error on illegal results. Note that this happens, as per JS semantics, // *before* the call. for (const auto& result : func->getResults()) { - // An i64 result is fine: a BigInt will be provided. But v128 still traps. + // An i64 result is fine: a BigInt will be provided. But v128 still + // errors. if (result == Type::v128) { throwEmptyException(); } From 94a280c53b6e8c0960eff79fd0a6bc2487677678 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 5 Dec 2024 16:51:35 -0800 Subject: [PATCH 48/48] Update test/lit/exec/fuzzing-api.wast Co-authored-by: Thomas Lively --- test/lit/exec/fuzzing-api.wast | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 348daa3db4c..eae95fc0a87 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -229,7 +229,7 @@ ;; CHECK: [fuzz-exec] calling ref.calling.illegal-result ;; CHECK-NEXT: [LoggingExternalInterface logging 1] (func $ref.calling.illegal-result (export "ref.calling.illegal-result") - ;; The v128 result causes an error here, so we will log 1 as a trap. The JS + ;; The v128 result causes an error here, so we will log 1 as an exception. The JS ;; semantics determine that we do that check *before* the call, so the logging ;; of 910 does not go through. (call $log-i32