From cb16252ac1120da3c07b28926a77197780dfe9eb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 4 Oct 2024 11:55:50 -0700 Subject: [PATCH 01/11] start --- src/tools/fuzzing/fuzzing.cpp | 61 +++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index a8b8f7855ef..471955b494d 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1366,6 +1366,7 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) { &Self::makeCall, &Self::makeCallIndirect) .add(FeatureSet::ExceptionHandling, &Self::makeTry) + .add(FeatureSet::ExceptionHandling, &Self::makeTryTable) .add(FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeCallRef); } if (type.isSingle()) { @@ -1451,6 +1452,8 @@ Expression* TranslateToFuzzReader::_makenone() { &Self::makeGlobalSet) .add(FeatureSet::BulkMemory, &Self::makeBulkMemory) .add(FeatureSet::Atomics, &Self::makeAtomic) + .add(FeatureSet::ExceptionHandling, &Self::makeTry) + .add(FeatureSet::ExceptionHandling, &Self::makeTryTable) .add(FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeCallRef) .add(FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeStructSet) .add(FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeArraySet) @@ -1688,6 +1691,64 @@ Expression* TranslateToFuzzReader::makeTry(Type type) { return builder.makeTry(body, catchTags, catchBodies); } +Expression* TranslateToFuzzReader::makeTryTable(Type type) { + if (funcContext->breakableStack.empty()) { + return makeTrivial(type); + } + if (wasm.tags.empty()) { + addTag(); + } + + // Add catches of specific tags, and possible a catch_all at the end. We use + // the last iteration of the loop for that. + std::vector catchTags; + std::vector catchDests; + std::vector catchRefs; + auto numTags = upTo(MAX_TRY_CATCHES); + for (Index i = 0; i <= numTags; i++) { + Tag* tag; + auto tagType; + if (i < numTags) { + // Look for a specific tag. + tag = pick(wasm.tags).get(); + tagType = tag->sig.params; + } else { + // Look for a catch_all at the end. + tag = nullptr; + tagType = Type::none; + } + + // We need to find a proper target to break to, which means a target that + // has the type of the tag, or the tag + an exnref at the end. + std::vector vec; + for (auto t : tagType) { + vec.push_back(t); + } + vec.push_back(Type(HeapType::exn, Nullable)); // TODO: NonNullable? + auto tagTypeWithExn = Type(vec); + int tries = TRIES; + while (tries-- > 0) { + auto* target = pick(funcContext->breakableStack); + auto name = getTargetName(target); + auto valueType = getTargetType(target); + if (valueType == tagType || valueType == tagTypeWithExn) { + catchTags.push_back(tag->name); + catchDests.push_back(name); + catchRefs.push_back(valueType == tagTypeWithExn); + break; + } + } + } + + // If we found nothing, give up. + if (catchTags.empty()) { + return makeTrivial(type); + } + + auto* body = make(type); + return builder.makeTryTable(body, catchTags, catchDests, catchRefs); +} + Expression* TranslateToFuzzReader::makeBreak(Type type) { if (funcContext->breakableStack.empty()) { return makeTrivial(type); From f7424a9feb8f5e7f92156259210c48b803b0ae05 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 4 Oct 2024 12:00:32 -0700 Subject: [PATCH 02/11] builds --- src/tools/fuzzing.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 75e3a2a9a4e..f4400e39ec9 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -293,6 +293,7 @@ class TranslateToFuzzReader { Expression* buildIf(const struct ThreeArgs& args, Type type); Expression* makeIf(Type type); Expression* makeTry(Type type); + Expression* makeTryTable(Type type); Expression* makeBreak(Type type); Expression* makeCall(Type type); Expression* makeCallIndirect(Type type); From 1d4e1b33a3035237a49958f7164573f8afcef35c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 4 Oct 2024 12:00:54 -0700 Subject: [PATCH 03/11] builds.for.real --- 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 471955b494d..5664613dc4e 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1707,7 +1707,7 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) { auto numTags = upTo(MAX_TRY_CATCHES); for (Index i = 0; i <= numTags; i++) { Tag* tag; - auto tagType; + Type tagType; if (i < numTags) { // Look for a specific tag. tag = pick(wasm.tags).get(); From a0aa6fe5f058fedff4b5acfa6f5ee79df70e50c6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 4 Oct 2024 12:02:32 -0700 Subject: [PATCH 04/11] update --- ...e-to-fuzz_all-features_metrics_noprint.txt | 71 ++++++++----------- 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt index 07afaa7ebf4..633e73d33e1 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,53 +1,42 @@ Metrics total - [exports] : 5 - [funcs] : 9 + [exports] : 8 + [funcs] : 14 [globals] : 26 [imports] : 5 [memories] : 1 [memory-data] : 20 - [table-data] : 3 + [table-data] : 6 [tables] : 1 [tags] : 2 - [total] : 669 - [vars] : 27 - ArrayNew : 16 + [total] : 499 + [vars] : 30 + ArrayNew : 13 ArrayNewFixed : 3 AtomicCmpxchg : 1 - AtomicFence : 1 - Binary : 75 - Block : 70 - Break : 7 - Call : 26 - CallRef : 1 - Const : 143 - Drop : 3 - GlobalGet : 37 - GlobalSet : 27 - I31Get : 1 - If : 20 - Load : 21 - LocalGet : 55 - LocalSet : 40 - Loop : 6 - Nop : 5 - Pop : 5 - RefAs : 2 - RefEq : 2 - RefFunc : 5 + Binary : 62 + Block : 52 + Call : 10 + Const : 126 + Drop : 6 + GlobalGet : 34 + GlobalSet : 24 + If : 12 + Load : 17 + LocalGet : 34 + LocalSet : 21 + Nop : 4 + Pop : 2 + RefAs : 1 + RefFunc : 7 RefI31 : 2 - RefNull : 11 - RefTest : 2 - Return : 6 - Select : 2 - StringConst : 6 + RefNull : 7 + Return : 4 + StringConst : 4 StringEq : 1 - StringMeasure : 1 - StringWTF16Get : 1 - StructNew : 17 - StructSet : 1 - Try : 4 - TupleExtract : 3 - TupleMake : 5 - Unary : 20 - Unreachable : 15 + StructNew : 12 + Try : 1 + TupleExtract : 2 + TupleMake : 10 + Unary : 13 + Unreachable : 14 From 10a2aa522214e7d80673e51537bf2fb9d6d91c1e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 4 Oct 2024 12:10:14 -0700 Subject: [PATCH 05/11] work --- src/tools/fuzzing/fuzzing.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 5664613dc4e..a618cb52698 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1706,15 +1706,15 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) { std::vector catchRefs; auto numTags = upTo(MAX_TRY_CATCHES); for (Index i = 0; i <= numTags; i++) { - Tag* tag; + Name tagName; Type tagType; if (i < numTags) { // Look for a specific tag. - tag = pick(wasm.tags).get(); + auto& tag = pick(wasm.tags); + tagName = tag->name; tagType = tag->sig.params; } else { // Look for a catch_all at the end. - tag = nullptr; tagType = Type::none; } @@ -1732,12 +1732,13 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) { auto name = getTargetName(target); auto valueType = getTargetType(target); if (valueType == tagType || valueType == tagTypeWithExn) { - catchTags.push_back(tag->name); + catchTags.push_back(tagName); catchDests.push_back(name); catchRefs.push_back(valueType == tagTypeWithExn); break; } } + // TODO: Perhaps generate a block wrapping us, if we fail to find a target? } // If we found nothing, give up. From 4bc447280358781d35d34ad8ea4eecd82c33ab27 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 4 Oct 2024 13:06:06 -0700 Subject: [PATCH 06/11] bettr --- src/tools/fuzzing/fuzzing.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index a618cb52698..ed8b9bacc2e 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1693,13 +1693,15 @@ Expression* TranslateToFuzzReader::makeTry(Type type) { Expression* TranslateToFuzzReader::makeTryTable(Type type) { if (funcContext->breakableStack.empty()) { + // Nothing to break to. + // TODO: Perhaps generate a block wrapping us? return makeTrivial(type); } if (wasm.tags.empty()) { addTag(); } - // Add catches of specific tags, and possible a catch_all at the end. We use + // Add catches of specific tags, and possibly a catch_all at the end. We use // the last iteration of the loop for that. std::vector catchTags; std::vector catchDests; @@ -1714,7 +1716,11 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) { tagName = tag->name; tagType = tag->sig.params; } else { - // Look for a catch_all at the end. + // Look for a catch_all at the end, some of the time (but all of the time + // if we have nothing else). + if (!catchTags.empty() && oneIn(2)) { + break; + } tagType = Type::none; } From 72ae2c123a2c66074a534ba00c5e6d69a6fdcff9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 4 Oct 2024 13:19:51 -0700 Subject: [PATCH 07/11] comment --- src/tools/fuzzing/fuzzing.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index ed8b9bacc2e..daf10c2f600 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1745,6 +1745,8 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) { } } // TODO: Perhaps generate a block wrapping us, if we fail to find a target? + // TODO: It takes a bit of luck to find a target with an exnref - perhaps + // generate those? } // If we found nothing, give up. From eb6e87281789f08ee3502fd9648a5b71cd118503 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 7 Oct 2024 12:48:15 -0700 Subject: [PATCH 08/11] feedback: emit trivial try_table --- src/tools/fuzzing/fuzzing.cpp | 13 ++-- ...e-to-fuzz_all-features_metrics_noprint.txt | 69 +++++++++++-------- 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index daf10c2f600..446bc630848 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1692,11 +1692,14 @@ Expression* TranslateToFuzzReader::makeTry(Type type) { } Expression* TranslateToFuzzReader::makeTryTable(Type type) { + auto* body = make(type); + if (funcContext->breakableStack.empty()) { - // Nothing to break to. + // Nothing to break to, emit a trivial TryTable. // TODO: Perhaps generate a block wrapping us? - return makeTrivial(type); + return builder.makeTryTable(body, {}, {}, {}); } + if (wasm.tags.empty()) { addTag(); } @@ -1749,12 +1752,6 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) { // generate those? } - // If we found nothing, give up. - if (catchTags.empty()) { - return makeTrivial(type); - } - - auto* body = make(type); return builder.makeTryTable(body, catchTags, catchDests, catchRefs); } 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 633e73d33e1..e58a508309c 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,42 +1,53 @@ Metrics total - [exports] : 8 - [funcs] : 14 + [exports] : 3 + [funcs] : 5 [globals] : 26 [imports] : 5 [memories] : 1 [memory-data] : 20 - [table-data] : 6 + [table-data] : 0 [tables] : 1 [tags] : 2 [total] : 499 - [vars] : 30 - ArrayNew : 13 - ArrayNewFixed : 3 + [vars] : 20 + ArrayNew : 14 + ArrayNewFixed : 2 AtomicCmpxchg : 1 - Binary : 62 - Block : 52 - Call : 10 + AtomicNotify : 1 + AtomicRMW : 1 + Binary : 69 + Block : 42 + Break : 8 + Call : 6 Const : 126 - Drop : 6 - GlobalGet : 34 - GlobalSet : 24 - If : 12 - Load : 17 - LocalGet : 34 - LocalSet : 21 - Nop : 4 - Pop : 2 - RefAs : 1 - RefFunc : 7 - RefI31 : 2 - RefNull : 7 - Return : 4 - StringConst : 4 - StringEq : 1 + Drop : 2 + GlobalGet : 27 + GlobalSet : 16 + I31Get : 1 + If : 10 + Load : 18 + LocalGet : 43 + LocalSet : 22 + Loop : 5 + Nop : 3 + Pop : 3 + RefAs : 2 + RefFunc : 2 + RefI31 : 1 + RefNull : 8 + RefTest : 1 + Return : 1 + Select : 1 + Store : 3 + StringConst : 9 + StringEncode : 1 + StringEq : 3 StructNew : 12 - Try : 1 - TupleExtract : 2 - TupleMake : 10 + StructSet : 1 + Try : 3 + TryTable : 2 + TupleExtract : 1 + TupleMake : 4 Unary : 13 - Unreachable : 14 + Unreachable : 11 From b835be206897d18da07fce4376018eb66051f865 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 7 Oct 2024 12:49:46 -0700 Subject: [PATCH 09/11] feedback: numCatches --- src/tools/fuzzing/fuzzing.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 446bc630848..0021c7c4234 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1709,11 +1709,11 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) { std::vector catchTags; std::vector catchDests; std::vector catchRefs; - auto numTags = upTo(MAX_TRY_CATCHES); - for (Index i = 0; i <= numTags; i++) { + auto numCatches = upTo(MAX_TRY_CATCHES); + for (Index i = 0; i <= numCatches; i++) { Name tagName; Type tagType; - if (i < numTags) { + if (i < numCatches) { // Look for a specific tag. auto& tag = pick(wasm.tags); tagName = tag->name; From b49982ecc8f991f87459cb2601748c0c8100254c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 7 Oct 2024 12:51:04 -0700 Subject: [PATCH 10/11] feedback: dest --- src/tools/fuzzing/fuzzing.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 0021c7c4234..b24e012f393 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1719,8 +1719,8 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) { tagName = tag->name; tagType = tag->sig.params; } else { - // Look for a catch_all at the end, some of the time (but all of the time - // if we have nothing else). + // Add a catch_all at the end, some of the time (but all of the time if we + // have nothing else). if (!catchTags.empty() && oneIn(2)) { break; } @@ -1738,11 +1738,11 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) { int tries = TRIES; while (tries-- > 0) { auto* target = pick(funcContext->breakableStack); - auto name = getTargetName(target); + auto dest = getTargetName(target); auto valueType = getTargetType(target); if (valueType == tagType || valueType == tagTypeWithExn) { catchTags.push_back(tagName); - catchDests.push_back(name); + catchDests.push_back(dest); catchRefs.push_back(valueType == tagTypeWithExn); break; } From 091b67852b4d0213fe1c3475f0acef06354e4ee1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 7 Oct 2024 16:01:22 -0700 Subject: [PATCH 11/11] generalize to non-nullable too --- src/tools/fuzzing/fuzzing.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index b24e012f393..abc6a63d530 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1729,21 +1729,22 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) { // We need to find a proper target to break to, which means a target that // has the type of the tag, or the tag + an exnref at the end. - std::vector vec; - for (auto t : tagType) { - vec.push_back(t); - } - vec.push_back(Type(HeapType::exn, Nullable)); // TODO: NonNullable? + std::vector vec(tagType.begin(), tagType.end()); + // Use a non-nullable exnref here, and then the subtyping check below will + // also accept a target that is nullable. + vec.push_back(Type(HeapType::exn, NonNullable)); auto tagTypeWithExn = Type(vec); int tries = TRIES; while (tries-- > 0) { auto* target = pick(funcContext->breakableStack); auto dest = getTargetName(target); auto valueType = getTargetType(target); - if (valueType == tagType || valueType == tagTypeWithExn) { + auto subOfTagType = Type::isSubType(tagType, valueType); + auto subOfTagTypeWithExn = Type::isSubType(tagTypeWithExn, valueType); + if (subOfTagType || subOfTagTypeWithExn) { catchTags.push_back(tagName); catchDests.push_back(dest); - catchRefs.push_back(valueType == tagTypeWithExn); + catchRefs.push_back(subOfTagTypeWithExn); break; } }