diff options
author | Alon Zakai <azakai@google.com> | 2024-04-23 16:42:01 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-23 16:42:01 -0700 |
commit | 42db73abe388c7c8ee990ef839a36fd74a0eaadd (patch) | |
tree | 7a4050dc1710c14bca24aa15e8f06c6f9a8b566d /src | |
parent | 94ddae02e591adeb994ae2f798878e814f976bc1 (diff) | |
download | binaryen-42db73abe388c7c8ee990ef839a36fd74a0eaadd.tar.gz binaryen-42db73abe388c7c8ee990ef839a36fd74a0eaadd.tar.bz2 binaryen-42db73abe388c7c8ee990ef839a36fd74a0eaadd.zip |
[Strings] Fuzz and interpret all relevant StringNew methods (#6526)
This adds fuzzing for string.new_wtf16_array and string.from_code_point. The
latter was also missing interpreter support, which this adds.
Diffstat (limited to 'src')
-rw-r--r-- | src/tools/fuzzing.h | 3 | ||||
-rw-r--r-- | src/tools/fuzzing/fuzzing.cpp | 121 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 11 |
3 files changed, 94 insertions, 41 deletions
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 76c0e13c8..5b3c0037b 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -315,6 +315,8 @@ private: Expression* makeBasicRef(Type type); Expression* makeCompoundRef(Type type); + Expression* makeString(); + // 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 // struct.get or array.set would use this. @@ -378,6 +380,7 @@ private: Type getLoggableType(); bool isLoggableType(Type type); Nullability getNullability(); + Mutability getMutability(); Nullability getSubType(Nullability nullability); HeapType getSubType(HeapType type); Type getSubType(Type type); diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 5a3e9002a..9698c06eb 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -2605,47 +2605,7 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) { return null; } case HeapType::string: { - // Construct an interesting WTF-8 string from parts. - std::stringstream wtf8; - bool lastWasLeadingSurrogate = false; - for (size_t i = 0, end = upTo(4); i < end; ++i) { - switch (upTo(6)) { - case 0: - // A simple ascii string. - wtf8 << std::to_string(upTo(1024)); - break; - case 1: - // '£' - wtf8 << "\xC2\xA3"; - break; - case 2: - // '€' - wtf8 << "\xE2\x82\xAC"; - break; - case 3: - // '𐍈' - wtf8 << "\xF0\x90\x8D\x88"; - break; - case 4: - // The leading surrogate in '𐍈' - wtf8 << "\xED\xA0\x80"; - lastWasLeadingSurrogate = true; - continue; - case 5: - if (lastWasLeadingSurrogate) { - // Avoid invalid WTF-8. - continue; - } - // The trailing surrogate in '𐍈' - wtf8 << "\xED\xBD\x88"; - break; - } - lastWasLeadingSurrogate = false; - } - std::stringstream wtf16; - // TODO: Use wtf16.view() once we have C++20. - String::convertWTF8ToWTF16(wtf16, wtf8.str()); - return builder.makeStringConst(wtf16.str()); + return makeString(); } case HeapType::stringview_wtf16: // We fully support wtf16 strings. @@ -2760,6 +2720,81 @@ Expression* TranslateToFuzzReader::makeCompoundRef(Type type) { } } +Expression* TranslateToFuzzReader::makeString() { + // Fuzz with JS-style strings. + auto mutability = getMutability(); + auto arrayHeapType = + HeapType(Array(Field(Field::PackedType::i16, mutability))); + auto nullability = getNullability(); + auto arrayType = Type(arrayHeapType, nullability); + switch (upTo(3)) { + case 0: { + // Make a string from an array. We can only do this in functions. + if (funcContext) { + auto array = make(arrayType); + auto* start = make(Type::i32); + auto* end = make(Type::i32); + return builder.makeStringNew( + StringNewWTF16Array, array, start, end, false); + } + [[fallthrough]]; + } + case 1: { + // Make a string from a code point. We can only do this in functions. + if (funcContext) { + auto codePoint = make(Type::i32); + return builder.makeStringNew( + StringNewFromCodePoint, codePoint, nullptr, false); + } + [[fallthrough]]; + } + case 2: { + // Construct an interesting WTF-8 string from parts and use string.const. + std::stringstream wtf8; + bool lastWasLeadingSurrogate = false; + for (size_t i = 0, end = upTo(4); i < end; ++i) { + switch (upTo(6)) { + case 0: + // A simple ascii string. + wtf8 << std::to_string(upTo(1024)); + break; + case 1: + // '£' + wtf8 << "\xC2\xA3"; + break; + case 2: + // '€' + wtf8 << "\xE2\x82\xAC"; + break; + case 3: + // '𐍈' + wtf8 << "\xF0\x90\x8D\x88"; + break; + case 4: + // The leading surrogate in '𐍈' + wtf8 << "\xED\xA0\x80"; + lastWasLeadingSurrogate = true; + continue; + case 5: + if (lastWasLeadingSurrogate) { + // Avoid invalid WTF-8. + continue; + } + // The trailing surrogate in '𐍈' + wtf8 << "\xED\xBD\x88"; + break; + } + lastWasLeadingSurrogate = false; + } + std::stringstream wtf16; + // TODO: Use wtf16.view() once we have C++20. + String::convertWTF8ToWTF16(wtf16, wtf8.str()); + return builder.makeStringConst(wtf16.str()); + } + } + WASM_UNREACHABLE("bad switch"); +} + Expression* TranslateToFuzzReader::makeTrappingRefUse(HeapType type) { auto percent = upTo(100); // Only give a low probability to emit a nullable reference. @@ -4071,6 +4106,10 @@ Nullability TranslateToFuzzReader::getNullability() { return Nullable; } +Mutability TranslateToFuzzReader::getMutability() { + return oneIn(2) ? Mutable : Immutable; +} + Nullability TranslateToFuzzReader::getSubType(Nullability nullability) { if (nullability == NonNullable) { return NonNullable; diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 64c0bfb2d..0afbaba94 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -33,6 +33,7 @@ #include "support/bits.h" #include "support/safe_integer.h" #include "support/stdckdint.h" +#include "support/string.h" #include "wasm-builder.h" #include "wasm-traversal.h" #include "wasm.h" @@ -1898,6 +1899,16 @@ public: } return makeGCData(contents, curr->type); } + case StringNewFromCodePoint: { + uint32_t codePoint = ptr.getSingleValue().getUnsigned(); + if (codePoint > 0x10FFFF) { + trap("invalid code point"); + } + std::stringstream wtf16; + String::writeWTF16CodePoint(wtf16, codePoint); + std::string str = wtf16.str(); + return Literal(str); + } default: // TODO: others return Flow(NONCONSTANT_FLOW); |