diff options
-rw-r--r-- | src/tools/fuzzing.h | 3 | ||||
-rw-r--r-- | src/tools/fuzzing/fuzzing.cpp | 64 | ||||
-rw-r--r-- | test/passes/translate-to-fuzz_all-features_metrics_noprint.txt | 61 |
3 files changed, 82 insertions, 46 deletions
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index ea9598f85..dc17f7c91 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -327,6 +327,7 @@ private: Expression* makeStringNewArray(); Expression* makeStringNewCodePoint(); Expression* makeStringConcat(); + Expression* makeStringEncode(Type type); // Similar to makeBasic/CompoundRef, but indicates that this value will be // used in a place that will trap on null. For example, the reference of a @@ -391,13 +392,13 @@ private: Type getLoggableType(); bool isLoggableType(Type type); Nullability getNullability(); - Mutability getMutability(); Nullability getSubType(Nullability nullability); HeapType getSubType(HeapType type); Type getSubType(Type type); Nullability getSuperType(Nullability nullability); HeapType getSuperType(HeapType type); Type getSuperType(Type type); + Type getArrayTypeForString(); // Utilities Name getTargetName(Expression* target); diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index a35a94d71..541b58b0f 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1366,6 +1366,9 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) { &Self::makeRefEq, &Self::makeRefTest, &Self::makeI31Get); + options.add(FeatureSet::ReferenceTypes | FeatureSet::GC | + FeatureSet::Strings, + &Self::makeStringEncode); } if (type.isTuple()) { options.add(FeatureSet::Multivalue, &Self::makeTupleMake); @@ -2752,12 +2755,7 @@ Expression* TranslateToFuzzReader::makeCompoundRef(Type type) { } Expression* TranslateToFuzzReader::makeStringNewArray() { - auto mutability = getMutability(); - auto arrayHeapType = - HeapType(Array(Field(Field::PackedType::i16, mutability))); - auto nullability = getNullability(); - auto arrayType = Type(arrayHeapType, nullability); - auto array = make(arrayType); + auto* array = make(getArrayTypeForString()); auto* start = make(Type::i32); auto* end = make(Type::i32); return builder.makeStringNew(StringNewWTF16Array, array, start, end, false); @@ -2814,8 +2812,8 @@ Expression* TranslateToFuzzReader::makeStringConst() { } Expression* TranslateToFuzzReader::makeStringConcat() { - auto left = make(Type(HeapType::string, getNullability())); - auto right = make(Type(HeapType::string, getNullability())); + auto* left = make(Type(HeapType::string, getNullability())); + auto* right = make(Type(HeapType::string, getNullability())); return builder.makeStringConcat(left, right); } @@ -3806,9 +3804,9 @@ static auto makeArrayBoundsCheck(Expression* ref, // An additional use of the reference (we stored the reference in a local, // so this reads from that local). Expression* getRef; - // An addition use of the index (as with the ref, it reads from a local). + // An additional use of the index (as with the ref, it reads from a local). Expression* getIndex; - // An addition use of the length, if it was provided. + // An additional use of the length, if it was provided. Expression* getLength = nullptr; } result = {builder.makeBinary(LtUInt32, effectiveIndex, getSize), builder.makeLocalGet(tempRef, ref->type), @@ -3919,6 +3917,40 @@ Expression* TranslateToFuzzReader::makeArrayBulkMemoryOp(Type type) { } } +Expression* TranslateToFuzzReader::makeStringEncode(Type type) { + assert(type == Type::i32); + + auto* ref = make(Type(HeapType::string, getNullability())); + auto* array = make(getArrayTypeForString()); + auto* start = make(Type::i32); + + // Only rarely emit without a bounds check, which might trap. See related + // logic in other array operations. + if (allowOOB || oneIn(10)) { + return builder.makeStringEncode(StringEncodeWTF16Array, ref, array, start); + } + + // Stash the string reference while computing its length for a bounds check. + auto refLocal = builder.addVar(funcContext->func, ref->type); + auto* setRef = builder.makeLocalSet(refLocal, ref); + auto* strLen = builder.makeStringMeasure( + StringMeasureWTF16, builder.makeLocalGet(refLocal, ref->type)); + + // Do a bounds check on the array. + auto check = + makeArrayBoundsCheck(array, start, funcContext->func, builder, strLen); + array = check.getRef; + start = check.getIndex; + auto* getRef = builder.makeLocalGet(refLocal, ref->type); + auto* encode = + builder.makeStringEncode(StringEncodeWTF16Array, getRef, array, start); + + // Emit the set of the string reference and then an if that picks which code + // path to visit, depending on the outcome of the bounds check. + auto* iff = builder.makeIf(check.condition, encode, make(Type::i32)); + return builder.makeSequence(setRef, iff); +} + Expression* TranslateToFuzzReader::makeI31Get(Type type) { assert(type == Type::i32); assert(wasm.features.hasReferenceTypes() && wasm.features.hasGC()); @@ -4136,10 +4168,6 @@ Nullability TranslateToFuzzReader::getNullability() { return Nullable; } -Mutability TranslateToFuzzReader::getMutability() { - return oneIn(2) ? Mutable : Immutable; -} - Nullability TranslateToFuzzReader::getSubType(Nullability nullability) { if (nullability == NonNullable) { return NonNullable; @@ -4279,6 +4307,14 @@ Type TranslateToFuzzReader::getSuperType(Type type) { return superType; } +Type TranslateToFuzzReader::getArrayTypeForString() { + // Emit an array that can be used with JS-style strings, containing 16-bit + // elements. For now, this must be a mutable type as that is all V8 accepts. + auto arrayHeapType = HeapType(Array(Field(Field::PackedType::i16, Mutable))); + auto nullability = getNullability(); + return Type(arrayHeapType, nullability); +} + Name TranslateToFuzzReader::getTargetName(Expression* target) { if (auto* block = target->dynCast<Block>()) { return block->name; 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 84f62758f..648cb053b 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,44 +1,43 @@ total - [exports] : 3 - [funcs] : 5 + [exports] : 7 + [funcs] : 12 [globals] : 14 [imports] : 5 [memories] : 1 [memory-data] : 20 - [table-data] : 1 + [table-data] : 6 [tables] : 1 [tags] : 1 - [total] : 387 - [vars] : 23 + [total] : 493 + [vars] : 31 ArrayNew : 1 - ArrayNewFixed : 3 - AtomicCmpxchg : 1 - AtomicNotify : 1 - Binary : 57 - Block : 33 + ArrayNewFixed : 1 + Binary : 61 + Block : 59 Break : 2 - Call : 4 - Const : 95 - Drop : 2 - GlobalGet : 15 - GlobalSet : 15 - If : 9 + Call : 29 + CallRef : 1 + Const : 101 + Drop : 10 + GlobalGet : 28 + GlobalSet : 26 + I31Get : 1 + If : 17 Load : 16 - LocalGet : 41 - LocalSet : 20 - Loop : 3 - Nop : 2 - Pop : 1 - RefAs : 3 - RefFunc : 2 + LocalGet : 36 + LocalSet : 29 + Loop : 2 + Nop : 5 + RefAs : 1 + RefCast : 2 + RefFunc : 8 RefI31 : 4 - RefNull : 5 + RefNull : 4 Return : 3 - Store : 1 + SIMDExtract : 1 StringConst : 1 - StructNew : 11 - Try : 1 - TupleExtract : 7 - TupleMake : 11 - Unary : 9 - Unreachable : 8 + StructNew : 5 + TupleExtract : 1 + TupleMake : 7 + Unary : 16 + Unreachable : 15 |