diff options
-rw-r--r-- | src/tools/fuzzing.h | 11 | ||||
-rw-r--r-- | src/tools/fuzzing/fuzzing.cpp | 35 | ||||
-rw-r--r-- | test/passes/translate-to-fuzz_all-features_metrics_noprint.txt | 68 |
3 files changed, 64 insertions, 50 deletions
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 9789a3a5b..4eb0c3960 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -138,8 +138,19 @@ private: FunctionCreationContext* funcContext = nullptr; +public: int nesting = 0; + struct AutoNester { + TranslateToFuzzReader& parent; + + AutoNester(TranslateToFuzzReader& parent) : parent(parent) { + parent.nesting++; + } + ~AutoNester() { parent.nesting--; } + }; + +private: // Generating random data is common enough that it's worth having helpers that // forward to `random`. int8_t get() { return random.get(); } diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index db4d0196e..7d663641e 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -2172,28 +2172,27 @@ Expression* TranslateToFuzzReader::makeConstCompoundRef(Type type) { auto heapType = type.getHeapType(); assert(!heapType.isBasic()); assert(wasm.features.hasReferenceTypes()); - if (heapType.isSignature()) { - return makeRefFuncConst(type); - } - // We weren't able to directly materialize a non-null constant. Try again to - // create a null. - if (type.isNullable()) { + // Prefer not to emit a null, in general, as we can trap from them. If it is + // nullable, give a small chance to do so; if we hit the nesting limit then we + // really have no choice and must emit a null (or else we could infinitely + // recurse). For the nesting limit, use a bound that is higher than the normal + // one, so that the normal mechanisms should prevent us from getting here; + // this limit is really a last resort we want to never reach. + // + // Note that we might have cycles of types where some are non-nullable. We + // will only stop here when we exceed the nesting and reach a nullable one. + // (This assumes there is a nullable one, that is, that the types are + // inhabitable.) + const auto LIMIT = 2 * NESTING_LIMIT; + AutoNester nester(*this); + if (type.isNullable() && (oneIn(10) || nesting >= LIMIT)) { return builder.makeRefNull(heapType); } - // We have to produce a non-null value. Possibly create a null and cast it - // to non-null even though that will trap at runtime. We must have a - // function context for this because the cast is not allowed in globals. - if (funcContext) { - return builder.makeRefAs(RefAsNonNull, builder.makeRefNull(heapType)); - } - - // Otherwise, we are not in a function context. This can happen if we need - // to make a constant for the initializer of a global, for example. We've - // already handled simple cases of this above, for basic heap types, so what - // we have left here are user-defined heap types like structs. - if (type.isStruct()) { + if (heapType.isSignature()) { + return makeRefFuncConst(type); + } else if (type.isStruct()) { auto& fields = heapType.getStruct().fields; std::vector<Expression*> values; // TODO: use non-default values randomly even when not necessary, sometimes 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 cdbd4dd27..24943eddd 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,39 +1,43 @@ total - [exports] : 4 - [funcs] : 8 + [exports] : 6 + [funcs] : 13 [globals] : 5 [imports] : 5 [memories] : 1 [memory-data] : 20 - [table-data] : 2 + [table-data] : 3 [tables] : 1 [tags] : 1 - [total] : 526 - [vars] : 8 - Binary : 69 - Block : 74 - Break : 11 - Call : 10 - Const : 100 - Drop : 1 - GlobalGet : 32 - GlobalSet : 33 - I31Get : 1 - I31New : 3 - If : 23 - Load : 19 - LocalGet : 40 - LocalSet : 23 - Loop : 10 - Nop : 17 - RefAs : 2 - RefFunc : 5 - RefIsNull : 1 - RefNull : 3 - Return : 2 - Select : 1 - Store : 1 - StructNew : 2 - TupleMake : 3 - Unary : 23 - Unreachable : 17 + [total] : 558 + [vars] : 36 + ArrayNew : 7 + ArrayNewFixed : 3 + AtomicCmpxchg : 1 + AtomicNotify : 1 + Binary : 70 + Block : 73 + Break : 2 + Call : 21 + CallRef : 1 + Const : 120 + Drop : 9 + GlobalGet : 34 + GlobalSet : 34 + I31New : 1 + If : 22 + Load : 18 + LocalGet : 38 + LocalSet : 19 + Loop : 5 + Nop : 5 + RefAs : 1 + RefFunc : 8 + RefNull : 4 + Return : 5 + SIMDExtract : 1 + Select : 2 + StructNew : 6 + TupleExtract : 3 + TupleMake : 6 + Unary : 20 + Unreachable : 18 |