Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fuzzer: Better handling of globals from initial content #6072

Merged
merged 11 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading