From db858492c40e2f28bbc767b6a1c26201c69f9995 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 19 Mar 2026 10:52:57 -0700 Subject: [PATCH 01/18] start --- src/tools/fuzzing/fuzzing.cpp | 62 ++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index aedcc1ac2de..5ef44302d9d 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5459,18 +5459,58 @@ Expression* TranslateToFuzzReader::makeBrOn(Type type) { Expression* TranslateToFuzzReader::makeContBind(Type type) { auto sig = type.getHeapType().getContinuation().type.getSignature(); - // Add a single param to be bound. TODO: Add multiple, and look in - // interestingHeapTypes. - std::vector newParams; - for (auto t : sig.params) { - newParams.push_back(t); - } - auto newParam = getSingleConcreteType(); - newParams.insert(newParams.begin(), newParam); - auto newSig = Signature(Type(newParams), sig.results); - auto newCont = Continuation(newSig); + auto numOldParams = sig.params.size(); + + // Look for a compatible signature, one who we are a suffix of. For example, + // with params [x,y,z] we'd want a signature like [a,b,x,y,z] so that we can + // bind a and b. + int tries = fuzzParams->TRIES; + auto& funcTypes = interestingHeapSubTypes[HeapTypes::func]; + Index numAddedParams; + std::optional newSig; + while (tries-- > 0) { + auto pickedSig = pick(funcTypes).getSignature(); + auto numNewParams = pickedSig.params.size(); + if (numNewParams < numOldParams) { + // Too short. + continue; + } + // Ignoring the new params at the start, compare the tails. + numAddedParams = numNewParams - numOldParams; + bool bad = false; + for (Index i = 0; i < numOldParams; i++) { + if (pickedSig.params[numAddedParams + i] != sig.params[i]) { + bad = true; + break; + } + } + if (!bad) { + newSig = pickedSig; + break; + } + } + + // If we failed to find a signature, either use the current one (binding no + // new params) or invent a new one, adding one param. + if (!newSig) { + if (oneIn(2)) { + newSig = sig; + } else { + std::vector newParams; + for (auto t : sig.params) { + newParams.push_back(t); + } + auto newParam = getSingleConcreteType(); + newParams.insert(newParams.begin(), newParam); + newSig = Signature(Type(newParams), sig.results); + } + } + auto newCont = Continuation(*newSig); // TODO: use interestingHeapType oneIn2 auto newType = Type(newCont, NonNullable, Exact); - std::vector newArgs{make(newParam)}; + std::vector newArgs; + for (Index i = 0; i < numAddedParams; i++) { + newArgs.push_back(make(newSig->params[i])); + } return builder.makeContBind(type.getHeapType(), newArgs, make(newType)); } From 3c40ad270a760fdc2b54b99d2db82e1cfed33052 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 19 Mar 2026 11:02:07 -0700 Subject: [PATCH 02/18] start --- src/tools/fuzzing.h | 3 +++ src/tools/fuzzing/fuzzing.cpp | 32 +++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 97bbea7a77d..eea080256a6 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -217,6 +217,9 @@ class TranslateToFuzzReader { // All arrays that are mutable. std::vector mutableArrays; + // Mapping of signatures to the continuations they are used by. + std::unordered_map> sigConts; + // All tags that are valid as exception tags (which cannot have results). std::vector exceptionTags; diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 5ef44302d9d..c013533cbe1 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -574,6 +574,7 @@ void TranslateToFuzzReader::setupHeapTypes() { break; case HeapTypeKind::Cont: interestingHeapSubTypes[cont].push_back(type); + sigConts[type.getContinuation().type].push_back(type); break; case HeapTypeKind::Basic: WASM_UNREACHABLE("unexpected kind"); @@ -5467,9 +5468,10 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { int tries = fuzzParams->TRIES; auto& funcTypes = interestingHeapSubTypes[HeapTypes::func]; Index numAddedParams; - std::optional newSig; + std::optional newSigType; while (tries-- > 0) { - auto pickedSig = pick(funcTypes).getSignature(); + auto pickedSigType = pick(funcTypes); + auto pickedSig = pickedSigType.getSignature(); auto numNewParams = pickedSig.params.size(); if (numNewParams < numOldParams) { // Too short. @@ -5485,16 +5487,16 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { } } if (!bad) { - newSig = pickedSig; + newSigType = pickedSigType; break; } } // If we failed to find a signature, either use the current one (binding no // new params) or invent a new one, adding one param. - if (!newSig) { + if (!newSigType) { if (oneIn(2)) { - newSig = sig; + newSigType = sig; } else { std::vector newParams; for (auto t : sig.params) { @@ -5502,14 +5504,26 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { } auto newParam = getSingleConcreteType(); newParams.insert(newParams.begin(), newParam); - newSig = Signature(Type(newParams), sig.results); + newSigType = Signature(Type(newParams), sig.results); } } - auto newCont = Continuation(*newSig); // TODO: use interestingHeapType oneIn2 - auto newType = Type(newCont, NonNullable, Exact); + auto newSig = newSigType->getSignature(); + + // Pick a continuation type for the signature. If existing continuations use + // it, usually pick one of them. + auto& newSigConts = sigConts[*newSigType]; + HeapType newCont; + if (!newSigConts.empty() && !oneIn(5)) { + newCont = pick(newSigConts); + } else { + newCont = Continuation(*newSig); + } + Type newType = Type(newCont, NonNullable, Exact); + + // Generate the new args and the cont.bind. std::vector newArgs; for (Index i = 0; i < numAddedParams; i++) { - newArgs.push_back(make(newSig->params[i])); + newArgs.push_back(make(newSig.params[i])); } return builder.makeContBind(type.getHeapType(), newArgs, make(newType)); } From 53b3b8fa4e175e7f3894ef1d219315d46dc261c9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 19 Mar 2026 11:09:38 -0700 Subject: [PATCH 03/18] start --- 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 c013533cbe1..315550aa18a 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5516,7 +5516,7 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { if (!newSigConts.empty() && !oneIn(5)) { newCont = pick(newSigConts); } else { - newCont = Continuation(*newSig); + newCont = Continuation(newSig); } Type newType = Type(newCont, NonNullable, Exact); From 6f6c62e6e7354c62d578814533b276d4b52c52cd Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 19 Mar 2026 11:10:43 -0700 Subject: [PATCH 04/18] start --- 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 315550aa18a..d1f2d8448aa 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5467,7 +5467,7 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { // bind a and b. int tries = fuzzParams->TRIES; auto& funcTypes = interestingHeapSubTypes[HeapTypes::func]; - Index numAddedParams; + Index numAddedParams = -1; std::optional newSigType; while (tries-- > 0) { auto pickedSigType = pick(funcTypes); From 4793820e18bb53ba7b6aa6475f253e88c3df0f6c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 19 Mar 2026 11:21:55 -0700 Subject: [PATCH 05/18] go --- src/tools/fuzzing/fuzzing.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index d1f2d8448aa..ba1a50aa9e7 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5472,6 +5472,10 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { while (tries-- > 0) { auto pickedSigType = pick(funcTypes); auto pickedSig = pickedSigType.getSignature(); + if (pickedSig.results != sig.results) { + // Results must match. + continue; + } auto numNewParams = pickedSig.params.size(); if (numNewParams < numOldParams) { // Too short. From 7a925ef34fcf516f58470f52c04809a862faea45 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 19 Mar 2026 11:30:43 -0700 Subject: [PATCH 06/18] go --- src/tools/fuzzing/fuzzing.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index ba1a50aa9e7..1413db0057f 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5467,7 +5467,6 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { // bind a and b. int tries = fuzzParams->TRIES; auto& funcTypes = interestingHeapSubTypes[HeapTypes::func]; - Index numAddedParams = -1; std::optional newSigType; while (tries-- > 0) { auto pickedSigType = pick(funcTypes); @@ -5482,25 +5481,34 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { continue; } // Ignoring the new params at the start, compare the tails. - numAddedParams = numNewParams - numOldParams; + auto numAddedParams = numNewParams - numOldParams; +std::cout << "compar " << sig << " to " << pickedSig << " with num added " << numAddedParams << '\n'; bool bad = false; for (Index i = 0; i < numOldParams; i++) { +std::cout << "a1\n"; if (pickedSig.params[numAddedParams + i] != sig.params[i]) { +std::cout << "a2\n"; bad = true; break; } +std::cout << "a3\n"; } if (!bad) { newSigType = pickedSigType; break; } } +std::cout << "a4\n"; - // If we failed to find a signature, either use the current one (binding no - // new params) or invent a new one, adding one param. - if (!newSigType) { + Index numAddedParams; + if (newSigType) { + numAddedParams = newSigType->getSignature().params.size() - numOldParams; + } else { + // We failed to find a signature, either use the current one (binding no + // new params) or invent a new one, adding one param. if (oneIn(2)) { newSigType = sig; + numAddedParams = 0; } else { std::vector newParams; for (auto t : sig.params) { @@ -5509,13 +5517,16 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { auto newParam = getSingleConcreteType(); newParams.insert(newParams.begin(), newParam); newSigType = Signature(Type(newParams), sig.results); + numAddedParams = 1; } } auto newSig = newSigType->getSignature(); // Pick a continuation type for the signature. If existing continuations use // it, usually pick one of them. +std::cout << "a5\n"; auto& newSigConts = sigConts[*newSigType]; +std::cout << "a6\n"; HeapType newCont; if (!newSigConts.empty() && !oneIn(5)) { newCont = pick(newSigConts); @@ -5526,9 +5537,11 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { // Generate the new args and the cont.bind. std::vector newArgs; +std::cout << "a7 " << numAddedParams << " : " << newSig << "\n"; for (Index i = 0; i < numAddedParams; i++) { newArgs.push_back(make(newSig.params[i])); } +std::cout << "a9\n"; return builder.makeContBind(type.getHeapType(), newArgs, make(newType)); } From 5fa9ca8b6f8433e4f3e2dfb8189276a03d6aef31 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 19 Mar 2026 16:41:24 -0700 Subject: [PATCH 07/18] clean --- src/tools/fuzzing/fuzzing.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 1413db0057f..5555f5af496 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5482,23 +5482,18 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { } // Ignoring the new params at the start, compare the tails. auto numAddedParams = numNewParams - numOldParams; -std::cout << "compar " << sig << " to " << pickedSig << " with num added " << numAddedParams << '\n'; bool bad = false; for (Index i = 0; i < numOldParams; i++) { -std::cout << "a1\n"; if (pickedSig.params[numAddedParams + i] != sig.params[i]) { -std::cout << "a2\n"; bad = true; break; } -std::cout << "a3\n"; } if (!bad) { newSigType = pickedSigType; break; } } -std::cout << "a4\n"; Index numAddedParams; if (newSigType) { @@ -5524,9 +5519,7 @@ std::cout << "a4\n"; // Pick a continuation type for the signature. If existing continuations use // it, usually pick one of them. -std::cout << "a5\n"; auto& newSigConts = sigConts[*newSigType]; -std::cout << "a6\n"; HeapType newCont; if (!newSigConts.empty() && !oneIn(5)) { newCont = pick(newSigConts); @@ -5537,11 +5530,9 @@ std::cout << "a6\n"; // Generate the new args and the cont.bind. std::vector newArgs; -std::cout << "a7 " << numAddedParams << " : " << newSig << "\n"; for (Index i = 0; i < numAddedParams; i++) { newArgs.push_back(make(newSig.params[i])); } -std::cout << "a9\n"; return builder.makeContBind(type.getHeapType(), newArgs, make(newType)); } From e7bac6ebf40d2122399ef08285681045d426e47d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 20 Mar 2026 09:40:14 -0700 Subject: [PATCH 08/18] rename old/new to input/output --- src/tools/fuzzing/fuzzing.cpp | 58 ++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 5555f5af496..fd223db055b 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5459,15 +5459,17 @@ Expression* TranslateToFuzzReader::makeBrOn(Type type) { } Expression* TranslateToFuzzReader::makeContBind(Type type) { - auto sig = type.getHeapType().getContinuation().type.getSignature(); - auto numOldParams = sig.params.size(); + // We must output a signature that corresponds to the type we were given. + auto outputSig = type.getHeapType().getContinuation().type.getSignature(); + auto numOutputParams = sig.params.size(); // Look for a compatible signature, one who we are a suffix of. For example, // with params [x,y,z] we'd want a signature like [a,b,x,y,z] so that we can - // bind a and b. + // bind a and b. That will be the input signature, which is longer, and after + // cont.bind it becomes the output signature. int tries = fuzzParams->TRIES; auto& funcTypes = interestingHeapSubTypes[HeapTypes::func]; - std::optional newSigType; + std::optional inputSigType; while (tries-- > 0) { auto pickedSigType = pick(funcTypes); auto pickedSig = pickedSigType.getSignature(); @@ -5475,65 +5477,65 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { // Results must match. continue; } - auto numNewParams = pickedSig.params.size(); - if (numNewParams < numOldParams) { + auto numinputParams = pickedSig.params.size(); + if (numinputParams < numOutputParams) { // Too short. continue; } - // Ignoring the new params at the start, compare the tails. - auto numAddedParams = numNewParams - numOldParams; + // Ignoring the input params at the start, compare the tails. + auto numAddedParams = numinputParams - numOutputParams; bool bad = false; - for (Index i = 0; i < numOldParams; i++) { + for (Index i = 0; i < numOutputParams; i++) { if (pickedSig.params[numAddedParams + i] != sig.params[i]) { bad = true; break; } } if (!bad) { - newSigType = pickedSigType; + inputSigType = pickedSigType; break; } } Index numAddedParams; - if (newSigType) { - numAddedParams = newSigType->getSignature().params.size() - numOldParams; + if (inputSigType) { + numAddedParams = inputSigType->getSignature().params.size() - numOutputParams; } else { // We failed to find a signature, either use the current one (binding no - // new params) or invent a new one, adding one param. + // input params) or invent a input one, adding one param. if (oneIn(2)) { - newSigType = sig; + inputSigType = sig; numAddedParams = 0; } else { - std::vector newParams; + std::vector inputParams; for (auto t : sig.params) { - newParams.push_back(t); + inputParams.push_back(t); } - auto newParam = getSingleConcreteType(); - newParams.insert(newParams.begin(), newParam); - newSigType = Signature(Type(newParams), sig.results); + auto inputParam = getSingleConcreteType(); + inputParams.insert(inputParams.begin(), inputParam); + inputSigType = Signature(Type(inputParams), sig.results); numAddedParams = 1; } } - auto newSig = newSigType->getSignature(); + auto inputSig = inputSigType->getSignature(); // Pick a continuation type for the signature. If existing continuations use // it, usually pick one of them. - auto& newSigConts = sigConts[*newSigType]; - HeapType newCont; - if (!newSigConts.empty() && !oneIn(5)) { - newCont = pick(newSigConts); + auto& inputSigConts = sigConts[*inputSigType]; + HeapType inputCont; + if (!inputSigConts.empty() && !oneIn(5)) { + inputCont = pick(inputSigConts); } else { - newCont = Continuation(newSig); + inputCont = Continuation(inputSig); } - Type newType = Type(newCont, NonNullable, Exact); + Type inputType = Type(inputCont, NonNullable, Exact); // Generate the new args and the cont.bind. std::vector newArgs; for (Index i = 0; i < numAddedParams; i++) { - newArgs.push_back(make(newSig.params[i])); + newArgs.push_back(make(inputSig.params[i])); } - return builder.makeContBind(type.getHeapType(), newArgs, make(newType)); + return builder.makeContBind(type.getHeapType(), newArgs, make(inputType)); } bool TranslateToFuzzReader::maybeSignedGet(const Field& field) { From 813f40723f190c89c79742ae7b45ca1e41c81bf3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 20 Mar 2026 09:43:28 -0700 Subject: [PATCH 09/18] filter sigs for result compatibility --- src/tools/fuzzing/fuzzing.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index fd223db055b..f188a1b2145 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5467,16 +5467,20 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { // with params [x,y,z] we'd want a signature like [a,b,x,y,z] so that we can // bind a and b. That will be the input signature, which is longer, and after // cont.bind it becomes the output signature. - int tries = fuzzParams->TRIES; auto& funcTypes = interestingHeapSubTypes[HeapTypes::func]; + // Filter out signatures with incompatible results. + std::vector relevantFuncTypes; + for (auto funcType : funcTypes) { + if (funcType.getSignature().results == outputSig.results) { + relevantFuncTypes.push_back(funcType); + } + } std::optional inputSigType; + int tries = fuzzParams->TRIES; while (tries-- > 0) { - auto pickedSigType = pick(funcTypes); + auto pickedSigType = pick(relevantFuncTypes); auto pickedSig = pickedSigType.getSignature(); - if (pickedSig.results != sig.results) { - // Results must match. - continue; - } + assert(pickedSig.results == outputSig.results); auto numinputParams = pickedSig.params.size(); if (numinputParams < numOutputParams) { // Too short. @@ -5493,6 +5497,7 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { } if (!bad) { inputSigType = pickedSigType; + abort(); break; } } From f4456d1837c3b8be4c62207c8d86d2db26b1285e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 20 Mar 2026 09:45:29 -0700 Subject: [PATCH 10/18] subtyping --- 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 f188a1b2145..0dc45dce5e7 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5490,14 +5490,14 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { auto numAddedParams = numinputParams - numOutputParams; bool bad = false; for (Index i = 0; i < numOutputParams; i++) { - if (pickedSig.params[numAddedParams + i] != sig.params[i]) { + if (!Type::isSubType(pickedSig.params[numAddedParams + i], outputSig.params[i])) { bad = true; break; } } if (!bad) { inputSigType = pickedSigType; - abort(); + Fatal() << "picked"; break; } } @@ -5513,12 +5513,12 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { numAddedParams = 0; } else { std::vector inputParams; - for (auto t : sig.params) { + for (auto t : outputSig.params) { inputParams.push_back(t); } auto inputParam = getSingleConcreteType(); inputParams.insert(inputParams.begin(), inputParam); - inputSigType = Signature(Type(inputParams), sig.results); + inputSigType = Signature(Type(inputParams), outputSig.results); numAddedParams = 1; } } From c55e795c79944a58ffa8ef89ccade181211efa71 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 20 Mar 2026 09:45:38 -0700 Subject: [PATCH 11/18] format --- src/tools/fuzzing/fuzzing.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 0dc45dce5e7..6ced72f9ea8 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5490,7 +5490,8 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { auto numAddedParams = numinputParams - numOutputParams; bool bad = false; for (Index i = 0; i < numOutputParams; i++) { - if (!Type::isSubType(pickedSig.params[numAddedParams + i], outputSig.params[i])) { + if (!Type::isSubType(pickedSig.params[numAddedParams + i], + outputSig.params[i])) { bad = true; break; } @@ -5504,7 +5505,8 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { Index numAddedParams; if (inputSigType) { - numAddedParams = inputSigType->getSignature().params.size() - numOutputParams; + numAddedParams = + inputSigType->getSignature().params.size() - numOutputParams; } else { // We failed to find a signature, either use the current one (binding no // input params) or invent a input one, adding one param. From 8f17eb882dd2cf83bfcdd8d6d2ce22d682a80a54 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 20 Mar 2026 09:47:14 -0700 Subject: [PATCH 12/18] fix --- 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 6ced72f9ea8..f29d2a82889 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5461,7 +5461,7 @@ Expression* TranslateToFuzzReader::makeBrOn(Type type) { Expression* TranslateToFuzzReader::makeContBind(Type type) { // We must output a signature that corresponds to the type we were given. auto outputSig = type.getHeapType().getContinuation().type.getSignature(); - auto numOutputParams = sig.params.size(); + auto numOutputParams = outputSig.params.size(); // Look for a compatible signature, one who we are a suffix of. For example, // with params [x,y,z] we'd want a signature like [a,b,x,y,z] so that we can @@ -5511,7 +5511,7 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { // We failed to find a signature, either use the current one (binding no // input params) or invent a input one, adding one param. if (oneIn(2)) { - inputSigType = sig; + inputSigType = outputSig; numAddedParams = 0; } else { std::vector inputParams; From 86733734a99e124bf8ae13c6c967fca60b000ca8 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 20 Mar 2026 09:47:44 -0700 Subject: [PATCH 13/18] undebug --- src/tools/fuzzing/fuzzing.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index f29d2a82889..bcc82fcbb43 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5498,7 +5498,6 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { } if (!bad) { inputSigType = pickedSigType; - Fatal() << "picked"; break; } } From 9036f0810ea8d9eab0ae03ac8d66390cbc65bd94 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 20 Mar 2026 09:56:37 -0700 Subject: [PATCH 14/18] fix --- src/tools/fuzzing/fuzzing.cpp | 44 ++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index bcc82fcbb43..f3edaab6945 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5476,30 +5476,32 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { } } std::optional inputSigType; - int tries = fuzzParams->TRIES; - while (tries-- > 0) { - auto pickedSigType = pick(relevantFuncTypes); - auto pickedSig = pickedSigType.getSignature(); - assert(pickedSig.results == outputSig.results); - auto numinputParams = pickedSig.params.size(); - if (numinputParams < numOutputParams) { - // Too short. - continue; - } - // Ignoring the input params at the start, compare the tails. - auto numAddedParams = numinputParams - numOutputParams; - bool bad = false; - for (Index i = 0; i < numOutputParams; i++) { - if (!Type::isSubType(pickedSig.params[numAddedParams + i], - outputSig.params[i])) { - bad = true; + if (!relevantFuncTypes.empty()) { + int tries = fuzzParams->TRIES; + while (tries-- > 0) { + auto pickedSigType = pick(relevantFuncTypes); + auto pickedSig = pickedSigType.getSignature(); + assert(pickedSig.results == outputSig.results); + auto numinputParams = pickedSig.params.size(); + if (numinputParams < numOutputParams) { + // Too short. + continue; + } + // Ignoring the input params at the start, compare the tails. + auto numAddedParams = numinputParams - numOutputParams; + bool bad = false; + for (Index i = 0; i < numOutputParams; i++) { + if (!Type::isSubType(pickedSig.params[numAddedParams + i], + outputSig.params[i])) { + bad = true; + break; + } + } + if (!bad) { + inputSigType = pickedSigType; break; } } - if (!bad) { - inputSigType = pickedSigType; - break; - } } Index numAddedParams; From 1a7460c576582b1a19312f4714a97e36cbe114d3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 20 Mar 2026 10:37:41 -0700 Subject: [PATCH 15/18] more flexibility --- src/tools/fuzzing/fuzzing.cpp | 67 ++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index f3edaab6945..18283a17b1f 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5460,47 +5460,50 @@ Expression* TranslateToFuzzReader::makeBrOn(Type type) { Expression* TranslateToFuzzReader::makeContBind(Type type) { // We must output a signature that corresponds to the type we were given. - auto outputSig = type.getHeapType().getContinuation().type.getSignature(); + auto outputSigType = type.getHeapType().getContinuation().type; + auto outputSig = outputSigType.getSignature(); auto numOutputParams = outputSig.params.size(); // Look for a compatible signature, one who we are a suffix of. For example, // with params [x,y,z] we'd want a signature like [a,b,x,y,z] so that we can // bind a and b. That will be the input signature, which is longer, and after - // cont.bind it becomes the output signature. - auto& funcTypes = interestingHeapSubTypes[HeapTypes::func]; - // Filter out signatures with incompatible results. - std::vector relevantFuncTypes; - for (auto funcType : funcTypes) { - if (funcType.getSignature().results == outputSig.results) { - relevantFuncTypes.push_back(funcType); - } - } + // cont.bind it becomes the output signature. Don't always do this, however. std::optional inputSigType; - if (!relevantFuncTypes.empty()) { - int tries = fuzzParams->TRIES; - while (tries-- > 0) { - auto pickedSigType = pick(relevantFuncTypes); - auto pickedSig = pickedSigType.getSignature(); - assert(pickedSig.results == outputSig.results); - auto numinputParams = pickedSig.params.size(); - if (numinputParams < numOutputParams) { - // Too short. - continue; + if (!oneIn(4)) { + auto& funcTypes = interestingHeapSubTypes[HeapTypes::func]; + // Filter out signatures with incompatible results. + std::vector relevantFuncTypes; + for (auto funcType : funcTypes) { + if (funcType.getSignature().results == outputSig.results) { + relevantFuncTypes.push_back(funcType); } - // Ignoring the input params at the start, compare the tails. - auto numAddedParams = numinputParams - numOutputParams; - bool bad = false; - for (Index i = 0; i < numOutputParams; i++) { - if (!Type::isSubType(pickedSig.params[numAddedParams + i], - outputSig.params[i])) { - bad = true; + } + if (!relevantFuncTypes.empty()) { + int tries = fuzzParams->TRIES; + while (tries-- > 0) { + auto pickedSigType = pick(relevantFuncTypes); + auto pickedSig = pickedSigType.getSignature(); + assert(pickedSig.results == outputSig.results); + auto numinputParams = pickedSig.params.size(); + if (numinputParams < numOutputParams) { + // Too short. + continue; + } + // Ignoring the input params at the start, compare the tails. + auto numAddedParams = numinputParams - numOutputParams; + bool bad = false; + for (Index i = 0; i < numOutputParams; i++) { + if (!Type::isSubType(pickedSig.params[numAddedParams + i], + outputSig.params[i])) { + bad = true; + break; + } + } + if (!bad) { + inputSigType = pickedSigType; break; } } - if (!bad) { - inputSigType = pickedSigType; - break; - } } } @@ -5512,7 +5515,7 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { // We failed to find a signature, either use the current one (binding no // input params) or invent a input one, adding one param. if (oneIn(2)) { - inputSigType = outputSig; + inputSigType = outputSigType; numAddedParams = 0; } else { std::vector inputParams; From 7c7af5d9da3237e4459b688076377d391ee9080a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 20 Mar 2026 10:52:36 -0700 Subject: [PATCH 16/18] fix subtyping check --- 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 18283a17b1f..8ff177b5be5 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5493,8 +5493,8 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { auto numAddedParams = numinputParams - numOutputParams; bool bad = false; for (Index i = 0; i < numOutputParams; i++) { - if (!Type::isSubType(pickedSig.params[numAddedParams + i], - outputSig.params[i])) { + if (!Type::isSubType(outputSig.params[i], + pickedSig.params[numAddedParams + i])) { bad = true; break; } From adef76e68e03901237d06e68277aa1e8c92ee84c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 20 Mar 2026 16:17:03 -0700 Subject: [PATCH 17/18] typo --- 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 8ff177b5be5..0a549a5e980 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5484,13 +5484,13 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { auto pickedSigType = pick(relevantFuncTypes); auto pickedSig = pickedSigType.getSignature(); assert(pickedSig.results == outputSig.results); - auto numinputParams = pickedSig.params.size(); - if (numinputParams < numOutputParams) { + auto numInputParams = pickedSig.params.size(); + if (numInputParams < numOutputParams) { // Too short. continue; } // Ignoring the input params at the start, compare the tails. - auto numAddedParams = numinputParams - numOutputParams; + auto numAddedParams = numInputParams - numOutputParams; bool bad = false; for (Index i = 0; i < numOutputParams; i++) { if (!Type::isSubType(outputSig.params[i], From 698c470762989033e663c3b6690b9c2b31f98158 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 20 Mar 2026 16:27:20 -0700 Subject: [PATCH 18/18] feedback --- src/tools/fuzzing/fuzzing.cpp | 61 +++++++++++++++++------------------ 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 0a549a5e980..1cc2c7f569b 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5464,51 +5464,50 @@ Expression* TranslateToFuzzReader::makeContBind(Type type) { auto outputSig = outputSigType.getSignature(); auto numOutputParams = outputSig.params.size(); - // Look for a compatible signature, one who we are a suffix of. For example, - // with params [x,y,z] we'd want a signature like [a,b,x,y,z] so that we can - // bind a and b. That will be the input signature, which is longer, and after - // cont.bind it becomes the output signature. Don't always do this, however. + // Look for a compatible signature. Don't always do this, however - we have a + // few other options below. std::optional inputSigType; if (!oneIn(4)) { auto& funcTypes = interestingHeapSubTypes[HeapTypes::func]; - // Filter out signatures with incompatible results. + // Filter out incompatible signatures. std::vector relevantFuncTypes; for (auto funcType : funcTypes) { - if (funcType.getSignature().results == outputSig.results) { - relevantFuncTypes.push_back(funcType); + auto funcSig = funcType.getSignature(); + if (funcSig.results != outputSig.results) { + // The results must match. + continue; } - } - if (!relevantFuncTypes.empty()) { - int tries = fuzzParams->TRIES; - while (tries-- > 0) { - auto pickedSigType = pick(relevantFuncTypes); - auto pickedSig = pickedSigType.getSignature(); - assert(pickedSig.results == outputSig.results); - auto numInputParams = pickedSig.params.size(); - if (numInputParams < numOutputParams) { - // Too short. - continue; - } - // Ignoring the input params at the start, compare the tails. - auto numAddedParams = numInputParams - numOutputParams; - bool bad = false; - for (Index i = 0; i < numOutputParams; i++) { - if (!Type::isSubType(outputSig.params[i], - pickedSig.params[numAddedParams + i])) { - bad = true; - break; - } - } - if (!bad) { - inputSigType = pickedSigType; + + // The params must be compatible. For example, with output params [x,y,z] + // we'd want an input signature like [a,b,x,y,z] so that we can bind a and + // b. + auto numInputParams = funcSig.params.size(); + if (numInputParams < numOutputParams) { + // Too short. + continue; + } + // Ignoring the input params at the start, compare the tails. + auto numAddedParams = numInputParams - numOutputParams; + bool bad = false; + for (Index i = 0; i < numOutputParams; i++) { + if (!Type::isSubType(outputSig.params[i], + funcSig.params[numAddedParams + i])) { + bad = true; break; } } + if (!bad) { + relevantFuncTypes.push_back(funcType); + } + } + if (!relevantFuncTypes.empty()) { + inputSigType = pick(relevantFuncTypes); } } Index numAddedParams; if (inputSigType) { + // We picked a signature, above. numAddedParams = inputSigType->getSignature().params.size() - numOutputParams; } else {