summaryrefslogtreecommitdiff
path: root/src/tools/fuzzing/fuzzing.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/fuzzing/fuzzing.cpp')
-rw-r--r--src/tools/fuzzing/fuzzing.cpp84
1 files changed, 52 insertions, 32 deletions
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index 1b1d2cb01..f4f059deb 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -379,26 +379,46 @@ void TranslateToFuzzReader::setupGlobals() {
}
}
+ auto useGlobalLater = [&](Global* global) {
+ auto type = global->type;
+ auto name = global->name;
+ globalsByType[type].push_back(name);
+ if (global->mutable_) {
+ mutableGlobalsByType[type].push_back(name);
+ } else {
+ immutableGlobalsByType[type].push_back(name);
+ if (global->imported()) {
+ importedImmutableGlobalsByType[type].push_back(name);
+ }
+ }
+ };
+
// 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);
+ if (!wasm.globals.empty()) {
+ unsigned percentUsedInitialGlobals = upTo(100);
+ for (auto& global : wasm.globals) {
+ if (upTo(100) < percentUsedInitialGlobals) {
+ useGlobalLater(global.get());
+ }
+ }
}
// Create new random globals.
for (size_t index = upTo(MAX_GLOBALS); index > 0; --index) {
auto type = getConcreteType();
- auto* init = makeConst(type);
+ // Prefer immutable ones as they can be used in global.gets in other
+ // globals, for more interesting patterns.
+ auto mutability = oneIn(3) ? Builder::Mutable : Builder::Immutable;
+
+ // We can only make something trivial (like a constant) in a global
+ // initializer.
+ auto* init = makeTrivial(type);
+
if (!FindAll<RefAs>(init).list.empty()) {
// When creating this initial value we ended up emitting a RefAs, which
// means we had to stop in the middle of an overly-nested struct or array,
@@ -407,27 +427,16 @@ void TranslateToFuzzReader::setupGlobals() {
// validate in a global. Switch to something safe instead.
type = getMVPType();
init = makeConst(type);
+ } else if (type.isTuple() && !init->is<TupleMake>()) {
+ // For now we disallow anything but tuple.make at the top level of tuple
+ // globals (see details in wasm-binary.cpp). In the future we may allow
+ // global.get or other things here.
+ init = makeConst(type);
+ assert(init->is<TupleMake>());
}
- auto mutability = oneIn(2) ? Builder::Mutable : Builder::Immutable;
auto global = builder.makeGlobal(
Names::getValidGlobalName(wasm, "global$"), type, init, mutability);
- 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);
- }
+ useGlobalLater(wasm.addGlobal(std::move(global)));
}
}
@@ -1477,9 +1486,12 @@ Expression* TranslateToFuzzReader::makeTrivial(Type type) {
// using it before it was set, which would trap.
if (funcContext && oneIn(type.isNonNullable() ? 10 : 2)) {
return makeLocalGet(type);
- } else {
- return makeConst(type);
}
+
+ // Either make a const, or a global.get (which may fail to find a suitable
+ // global, especially in a non-function context, and if so it will make a
+ // constant instead).
+ return oneIn(2) ? makeConst(type) : makeGlobalGet(type);
} else if (type == Type::none) {
return makeNop(type);
}
@@ -1900,9 +1912,17 @@ Expression* TranslateToFuzzReader::makeLocalSet(Type type) {
}
Expression* TranslateToFuzzReader::makeGlobalGet(Type type) {
- auto it = globalsByType.find(type);
- if (it == globalsByType.end() || it->second.empty()) {
- return makeTrivial(type);
+ // In a non-function context, like in another global, we can only get from an
+ // immutable global. Whether GC is enabled also matters, as it allows getting
+ // from a non-import.
+ auto& relevantGlobals =
+ funcContext ? globalsByType
+ : (wasm.features.hasGC() ? immutableGlobalsByType
+ : importedImmutableGlobalsByType);
+ auto it = relevantGlobals.find(type);
+ // If we have no such relevant globals give up and emit a constant instead.
+ if (it == relevantGlobals.end() || it->second.empty()) {
+ return makeConst(type);
}
auto name = pick(it->second);