Skip to content

Commit

Permalink
Fuzzer: Better handling of globals from initial content (WebAssembly#…
Browse files Browse the repository at this point in the history
…6072)

Previously the fuzzer never added gets or sets of globals from initial content. That was
an oversight, I'm pretty sure - it's just that the code that sets up the lists from which we
pick globals for gets and sets was in another place. That is, any globals in the initial
content file were never used in new random code the fuzzer generates (only new
globals the fuzzer generated were used there).

This PR allows us to use those globals, but also ignores them with some probability,
to avoid breaking patterns like "once" globals (that we want to only be used from
initial content, at least much of the time).

Also simplify the code here: we don't need isInvalidGlobal just to handle the hang
limit global, which is already handled by not being added to the lists we pick names
from anyhow.
  • Loading branch information
kripken authored and radekdoulik committed Jul 12, 2024
1 parent 72d2c1e commit 586fd4e
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 68 deletions.
4 changes: 0 additions & 4 deletions src/tools/fuzzing.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,10 +289,6 @@ class TranslateToFuzzReader {
Expression* makeCallRef(Type type);
Expression* makeLocalGet(Type type);
Expression* makeLocalSet(Type type);
// Some globals are for internal use, and should not be modified by random
// fuzz code.
bool isValidGlobal(Name name);

Expression* makeGlobalGet(Type type);
Expression* makeGlobalSet(Type type);
Expression* makeTupleMake(Type type);
Expand Down
62 changes: 43 additions & 19 deletions src/tools/fuzzing/fuzzing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,24 @@ void TranslateToFuzzReader::setupGlobals() {
}
}
}

// Randomly assign some globals from initial content to be ignored for the
// fuzzer to use. Such globals will only be used from initial content. This is
// important to preserve some real-world patterns, like the "once" pattern in
// which a global is used in one function only. (If we randomly emitted gets
// and sets of such globals, we'd with very high probability end up breaking
// that pattern, and not fuzzing it at all.)
//
// Pick a percentage of initial globals to ignore later down when we decide
// which to allow uses from.
auto numInitialGlobals = wasm.globals.size();
unsigned percentIgnoredInitialGlobals = 0;
if (numInitialGlobals) {
// Only generate this random number if it will be used.
percentIgnoredInitialGlobals = upTo(100);
}

// Create new random globals.
for (size_t index = upTo(MAX_GLOBALS); index > 0; --index) {
auto type = getConcreteType();
auto* init = makeConst(type);
Expand All @@ -394,12 +412,24 @@ void TranslateToFuzzReader::setupGlobals() {
auto mutability = oneIn(2) ? Builder::Mutable : Builder::Immutable;
auto global = builder.makeGlobal(
Names::getValidGlobalName(wasm, "global$"), type, init, mutability);
globalsByType[type].push_back(global->name);
if (mutability == Builder::Mutable) {
mutableGlobalsByType[type].push_back(global->name);
}
wasm.addGlobal(std::move(global));
}

// Set up data structures for picking globals later for get/set operations.
for (Index i = 0; i < wasm.globals.size(); i++) {
auto& global = wasm.globals[i];

// Apply the chance for initial globals to be ignored, see above.
if (i < numInitialGlobals && upTo(100) < percentIgnoredInitialGlobals) {
continue;
}

// This is a global we can use later, note it.
globalsByType[global->type].push_back(global->name);
if (global->mutable_) {
mutableGlobalsByType[global->type].push_back(global->name);
}
}
}

void TranslateToFuzzReader::setupTags() {
Expand Down Expand Up @@ -1696,21 +1726,16 @@ Expression* TranslateToFuzzReader::makeLocalSet(Type type) {
}
}

bool TranslateToFuzzReader::isValidGlobal(Name name) {
return name != HANG_LIMIT_GLOBAL;
}

Expression* TranslateToFuzzReader::makeGlobalGet(Type type) {
auto it = globalsByType.find(type);
if (it == globalsByType.end() || it->second.empty()) {
return makeConst(type);
}
auto name = pick(it->second);
if (isValidGlobal(name)) {
return builder.makeGlobalGet(name, type);
} else {
return makeTrivial(type);
}

auto name = pick(it->second);
// We don't want random fuzz code to use the hang limit global.
assert(name != HANG_LIMIT_GLOBAL);
return builder.makeGlobalGet(name, type);
}

Expression* TranslateToFuzzReader::makeGlobalSet(Type type) {
Expand All @@ -1720,12 +1745,11 @@ Expression* TranslateToFuzzReader::makeGlobalSet(Type type) {
if (it == mutableGlobalsByType.end() || it->second.empty()) {
return makeTrivial(Type::none);
}

auto name = pick(it->second);
if (isValidGlobal(name)) {
return builder.makeGlobalSet(name, make(type));
} else {
return makeTrivial(Type::none);
}
// We don't want random fuzz code to use the hang limit global.
assert(name != HANG_LIMIT_GLOBAL);
return builder.makeGlobalSet(name, make(type));
}

Expression* TranslateToFuzzReader::makeTupleMake(Type type) {
Expand Down
77 changes: 32 additions & 45 deletions test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,48 +8,35 @@ total
[table-data] : 1
[tables] : 1
[tags] : 2
[total] : 643
[vars] : 36
ArrayCopy : 1
ArrayFill : 1
ArrayGet : 1
ArrayLen : 5
ArrayNew : 7
ArraySet : 1
AtomicNotify : 1
AtomicRMW : 1
Binary : 84
Block : 58
Break : 9
Call : 22
CallRef : 2
Const : 144
Drop : 2
GlobalGet : 16
GlobalSet : 16
I31Get : 2
If : 20
Load : 20
LocalGet : 75
LocalSet : 48
Loop : 4
MemoryInit : 1
Nop : 4
Pop : 4
RefAs : 4
RefFunc : 6
RefI31 : 3
RefNull : 11
RefTest : 1
Return : 7
SIMDExtract : 1
Select : 5
Store : 3
StructGet : 3
StructNew : 7
StructSet : 1
Try : 3
TupleExtract : 7
TupleMake : 10
Unary : 14
Unreachable : 8
[total] : 314
[vars] : 38
ArrayNew : 2
ArrayNewFixed : 1
AtomicFence : 1
Binary : 58
Block : 28
Break : 6
Call : 10
Const : 72
Drop : 3
GlobalGet : 10
GlobalSet : 10
I31Get : 1
If : 7
Load : 18
LocalGet : 36
LocalSet : 21
Loop : 1
Nop : 2
RefEq : 1
RefFunc : 2
RefI31 : 2
RefNull : 1
Return : 2
Select : 1
Store : 1
StructGet : 1
StructNew : 3
TupleMake : 2
Unary : 6
Unreachable : 5

0 comments on commit 586fd4e

Please sign in to comment.