summaryrefslogtreecommitdiff
path: root/src/tools/fuzzing
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2024-04-24 11:05:16 -0700
committerGitHub <noreply@github.com>2024-04-24 11:05:16 -0700
commit22e80de9a32c19d294080242559fb3c2a84a42b5 (patch)
tree55a7e702f6b2f7fcd427e87eafb9563123c38d22 /src/tools/fuzzing
parent1c977ba820e7d1027c5f1c457ea350b7220b789d (diff)
downloadbinaryen-22e80de9a32c19d294080242559fb3c2a84a42b5.tar.gz
binaryen-22e80de9a32c19d294080242559fb3c2a84a42b5.tar.bz2
binaryen-22e80de9a32c19d294080242559fb3c2a84a42b5.zip
[Strings] Fuzzer: Emit StringConcat (#6532)
Also refactor the code a little to make it easier to add this (mostly whitespace).
Diffstat (limited to 'src/tools/fuzzing')
-rw-r--r--src/tools/fuzzing/fuzzing.cpp152
1 files changed, 86 insertions, 66 deletions
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index 5760a26f1..0120dbef3 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -2494,6 +2494,9 @@ Expression* TranslateToFuzzReader::makeConst(Type type) {
if (type.isNullable() && oneIn(8)) {
return builder.makeRefNull(type.getHeapType());
}
+ if (type.getHeapType().isString()) {
+ return makeStringConst();
+ }
if (type.getHeapType().isBasic()) {
return makeBasicRef(type);
} else {
@@ -2599,7 +2602,31 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) {
return null;
}
case HeapType::string: {
- return makeString();
+ // In non-function contexts all we can do is string.const.
+ if (!funcContext) {
+ return makeStringConst();
+ }
+ switch (upTo(9)) {
+ case 0:
+ case 1:
+ case 2:
+ return makeStringConst();
+ case 3:
+ case 4:
+ case 5:
+ return makeStringNewCodePoint();
+ case 6:
+ case 7:
+ // We less frequently make string.new_array as it may generate a lot
+ // of code for the array in some cases.
+ return makeStringNewArray();
+ case 8:
+ // We much less frequently make string.concat as it will recursively
+ // generate two string children, i.e., it can lead to exponential
+ // growth.
+ return makeStringConcat();
+ }
+ WASM_UNREACHABLE("bad switch");
}
case HeapType::stringview_wtf16:
// We fully support wtf16 strings.
@@ -2714,79 +2741,72 @@ Expression* TranslateToFuzzReader::makeCompoundRef(Type type) {
}
}
-Expression* TranslateToFuzzReader::makeString() {
- // Fuzz with JS-style strings.
+Expression* TranslateToFuzzReader::makeStringNewArray() {
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;
+ auto array = make(arrayType);
+ auto* start = make(Type::i32);
+ auto* end = make(Type::i32);
+ return builder.makeStringNew(StringNewWTF16Array, array, start, end, false);
+}
+
+Expression* TranslateToFuzzReader::makeStringNewCodePoint() {
+ auto codePoint = make(Type::i32);
+ return builder.makeStringNew(
+ StringNewFromCodePoint, codePoint, nullptr, false);
+}
+
+Expression* TranslateToFuzzReader::makeStringConst() {
+ // 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;
}
- lastWasLeadingSurrogate = false;
- }
- std::stringstream wtf16;
- // TODO: Use wtf16.view() once we have C++20.
- String::convertWTF8ToWTF16(wtf16, wtf8.str());
- return builder.makeStringConst(wtf16.str());
+ // The trailing surrogate in '𐍈'
+ wtf8 << "\xED\xBD\x88";
+ break;
}
+ lastWasLeadingSurrogate = false;
}
- WASM_UNREACHABLE("bad switch");
+ std::stringstream wtf16;
+ // TODO: Use wtf16.view() once we have C++20.
+ String::convertWTF8ToWTF16(wtf16, wtf8.str());
+ return builder.makeStringConst(wtf16.str());
+}
+
+Expression* TranslateToFuzzReader::makeStringConcat() {
+ auto left = make(Type(HeapType::string, getNullability()));
+ auto right = make(Type(HeapType::string, getNullability()));
+ return builder.makeStringConcat(left, right);
}
Expression* TranslateToFuzzReader::makeTrappingRefUse(HeapType type) {