Skip to content

Commit f9d4be9

Browse files
authored
Fuzzer: Improve handling of small inputs and their debugging (#7832)
Add a new env var to control the fuzzer input size, BINARYEN_FUZZER_MAX_BYTES When set, we will truncate the random bytes we receive as input in translate-to-fuzz. This makes it simple to bisect on the input, for example. Also make the fuzzer notice that the input has run out in more cases, and stop emitting things. This makes small inputs to the fuzzer smaller in output.
1 parent ea62172 commit f9d4be9

File tree

5 files changed

+47
-32
lines changed

5 files changed

+47
-32
lines changed

src/tools/fuzzing/fuzzing.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ void TranslateToFuzzReader::setupTags() {
717717
}
718718

719719
// Add the fuzzing support tags manually sometimes.
720-
if (!preserveImportsAndExports && oneIn(2)) {
720+
if (!preserveImportsAndExports && oneIn(2) && !random.finished()) {
721721
auto wasmTag = builder.makeTag(Names::getValidTagName(wasm, "wasmtag"),
722722
Signature(Type::i32, Type::none));
723723
wasmTag->module = "fuzzing-support";
@@ -859,7 +859,8 @@ void TranslateToFuzzReader::shuffleExports() {
859859
// find more things). But we also keep a good chance for the natural order
860860
// here, as it may help some initial content. Note we cannot do this if we are
861861
// preserving the exports, as their order is something we must maintain.
862-
if (wasm.exports.empty() || preserveImportsAndExports || oneIn(2)) {
862+
if (wasm.exports.empty() || preserveImportsAndExports || oneIn(2) ||
863+
random.finished()) {
863864
return;
864865
}
865866

@@ -937,7 +938,7 @@ void TranslateToFuzzReader::addImportCallingSupport() {
937938
// Only add these some of the time, as they inhibit some fuzzing (things like
938939
// wasm-ctor-eval and wasm-merge are sensitive to the wasm being able to call
939940
// its own exports, and to care about the indexes of the exports).
940-
if (oneIn(2)) {
941+
if (oneIn(2) || random.finished()) {
941942
return;
942943
}
943944

@@ -1005,6 +1006,9 @@ void TranslateToFuzzReader::addImportCallingSupport() {
10051006
}
10061007

10071008
void TranslateToFuzzReader::addImportThrowingSupport() {
1009+
if (random.finished()) {
1010+
return;
1011+
}
10081012
// Throw some kind of exception from JS. If we send 0 then a pure JS
10091013
// exception is thrown, and any other value is the value in a wasm tag.
10101014
throwImportName = Names::getValidFunctionName(wasm, "throw");
@@ -1026,7 +1030,7 @@ void TranslateToFuzzReader::addImportTableSupport() {
10261030
// for them. For simplicity, use the funcref table we use internally, though
10271031
// we could pick one at random, support non-funcref ones, and even export
10281032
// multiple ones TODO
1029-
if (!funcrefTableName) {
1033+
if (!funcrefTableName || random.finished()) {
10301034
return;
10311035
}
10321036

@@ -1068,7 +1072,7 @@ void TranslateToFuzzReader::addImportTableSupport() {
10681072
void TranslateToFuzzReader::addImportSleepSupport() {
10691073
// Fuzz this somewhat rarely, as it may be slow, and only when we can add
10701074
// imports.
1071-
if (preserveImportsAndExports || !oneIn(4)) {
1075+
if (preserveImportsAndExports || !oneIn(4) || random.finished()) {
10721076
return;
10731077
}
10741078

@@ -1086,7 +1090,7 @@ void TranslateToFuzzReader::addImportSleepSupport() {
10861090

10871091
void TranslateToFuzzReader::addHashMemorySupport() {
10881092
// Don't always add this.
1089-
if (oneIn(2)) {
1093+
if (oneIn(2) || random.finished()) {
10901094
return;
10911095
}
10921096

@@ -5202,7 +5206,7 @@ Expression* TranslateToFuzzReader::makeI31Get(Type type) {
52025206
Expression* TranslateToFuzzReader::makeThrow(Type type) {
52035207
assert(type == Type::unreachable);
52045208
Tag* tag;
5205-
if (trivialNesting) {
5209+
if (trivialNesting || random.finished()) {
52065210
// We are nested under a makeTrivial call, so only emit something trivial.
52075211
// Get (or create) a trivial tag, so we have no operands (and will not call
52085212
// make(), below). Otherwise, we might recurse very deeply if we threw a

src/tools/fuzzing/random.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ Random::Random(std::vector<char>&& bytes_, FeatureSet features)
2626
if (bytes.empty()) {
2727
bytes.push_back(0);
2828
}
29+
if (auto* maxBytes = getenv("BINARYEN_FUZZER_MAX_BYTES")) {
30+
unsigned max = atoi(maxBytes);
31+
if (max < bytes.size()) {
32+
std::cerr << "fuzzer: resizing from " << bytes.size() << " to " << max
33+
<< '\n';
34+
bytes.resize(max);
35+
}
36+
}
2937
}
3038

3139
int8_t Random::get() {
@@ -58,6 +66,9 @@ float Random::getFloat() { return Literal(get32()).reinterpretf32(); }
5866
double Random::getDouble() { return Literal(get64()).reinterpretf64(); }
5967

6068
uint32_t Random::upTo(uint32_t x) {
69+
if (finished()) {
70+
return 0;
71+
}
6172
if (x == 0) {
6273
return 0;
6374
}

test/passes/fuzz_metrics_noprint.bin.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ total
99
[table-data] : 25
1010
[tables] : 1
1111
[tags] : 0
12-
[total] : 6791
12+
[total] : 6794
1313
[vars] : 256
1414
Binary : 454
15-
Block : 1201
15+
Block : 1202
1616
Break : 188
1717
Call : 205
1818
CallIndirect : 61
19-
Const : 1131
20-
Drop : 88
19+
Const : 1132
20+
Drop : 89
2121
GlobalGet : 635
2222
GlobalSet : 487
2323
If : 378
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Metrics
22
total
3-
[exports] : 37
3+
[exports] : 38
44
[funcs] : 59
55
[globals] : 4
66
[imports] : 6
@@ -9,27 +9,27 @@ total
99
[table-data] : 28
1010
[tables] : 1
1111
[tags] : 0
12-
[total] : 9390
12+
[total] : 9393
1313
[vars] : 189
1414
Binary : 651
15-
Block : 1536
15+
Block : 1535
1616
Break : 316
1717
Call : 296
1818
CallIndirect : 91
19-
Const : 1666
19+
Const : 1670
2020
Drop : 66
2121
GlobalGet : 650
2222
GlobalSet : 582
2323
If : 506
2424
Load : 149
25-
LocalGet : 827
25+
LocalGet : 823
2626
LocalSet : 497
2727
Loop : 232
2828
Nop : 114
2929
RefFunc : 28
30-
Return : 81
30+
Return : 83
3131
Select : 75
3232
Store : 71
3333
Switch : 7
34-
Unary : 657
34+
Unary : 659
3535
Unreachable : 292

test/passes/translate-to-fuzz_all-features_metrics_noprint.txt

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,50 @@
11
Metrics
22
total
3-
[exports] : 16
4-
[funcs] : 21
3+
[exports] : 14
4+
[funcs] : 20
55
[globals] : 26
66
[imports] : 12
77
[memories] : 1
88
[memory-data] : 16
99
[table-data] : 6
1010
[tables] : 2
1111
[tags] : 1
12-
[total] : 887
13-
[vars] : 47
14-
ArrayNewFixed : 6
12+
[total] : 734
13+
[vars] : 45
14+
ArrayNewFixed : 5
1515
AtomicCmpxchg : 1
1616
AtomicFence : 1
1717
AtomicNotify : 2
1818
AtomicRMW : 1
19-
Binary : 93
20-
Block : 116
19+
Binary : 43
20+
Block : 115
2121
BrOn : 1
2222
Break : 11
2323
Call : 27
2424
CallRef : 2
25-
Const : 178
25+
Const : 144
2626
Drop : 15
2727
GlobalGet : 66
2828
GlobalSet : 50
2929
If : 32
30-
Load : 21
31-
LocalGet : 54
32-
LocalSet : 29
30+
Load : 5
31+
LocalGet : 20
32+
LocalSet : 11
3333
Loop : 5
3434
MemoryCopy : 1
3535
MemoryFill : 1
3636
MemoryInit : 1
37-
Nop : 14
37+
Nop : 13
3838
RefEq : 3
3939
RefFunc : 11
40-
RefI31 : 11
40+
RefI31 : 12
4141
RefNull : 11
4242
RefTest : 1
4343
Return : 6
4444
SIMDExtract : 2
4545
Select : 3
4646
Store : 3
47-
StringConst : 12
47+
StringConst : 13
4848
StringEq : 2
4949
StringWTF16Get : 1
5050
StructNew : 14

0 commit comments

Comments
 (0)