summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThomas Lively <7121787+tlively@users.noreply.github.com>2021-11-04 11:05:01 -0700
committerGitHub <noreply@github.com>2021-11-04 11:05:01 -0700
commitf1947db456df4576ac857a535f16cba3ffbfdc37 (patch)
treee8b9cb213dc3cfc1babce105abb7802958efd370 /src
parentab66e9ab1210a87d1db8ebe93cf8463eafe34e33 (diff)
downloadbinaryen-f1947db456df4576ac857a535f16cba3ffbfdc37.tar.gz
binaryen-f1947db456df4576ac857a535f16cba3ffbfdc37.tar.bz2
binaryen-f1947db456df4576ac857a535f16cba3ffbfdc37.zip
[NFC] Factor fuzzer randomness into a separate utility (#4304)
In preparation for using it from a separate file specifically for generating random HeapTypes that has no need to depend on all of fuzzing.h.
Diffstat (limited to 'src')
-rw-r--r--src/tools/CMakeLists.txt1
-rw-r--r--src/tools/fuzzing.h41
-rw-r--r--src/tools/fuzzing/fuzzing.cpp68
-rw-r--r--src/tools/fuzzing/random.cpp77
-rw-r--r--src/tools/fuzzing/random.h62
5 files changed, 164 insertions, 85 deletions
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
index 5a2144f4a..cda38a369 100644
--- a/src/tools/CMakeLists.txt
+++ b/src/tools/CMakeLists.txt
@@ -12,6 +12,7 @@ include_directories(fuzzing)
FILE(GLOB fuzzing_HEADERS fuzzing/*h)
set(fuzzing_SOURCES
fuzzing/fuzzing.cpp
+ fuzzing/random.cpp
${fuzzing_HEADERS}
)
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h
index e58b0f51b..9507d8a5c 100644
--- a/src/tools/fuzzing.h
+++ b/src/tools/fuzzing.h
@@ -30,6 +30,7 @@ high chance for set at start of loop
#include "ir/branch-utils.h"
#include "ir/memory-utils.h"
#include "support/insert_ordered.h"
+#include "tools/fuzzing/random.h"
#include <ir/find_all.h>
#include <ir/literal-utils.h>
#include <ir/manipulation.h>
@@ -65,7 +66,7 @@ struct BinaryArgs {
class TranslateToFuzzReader {
public:
- TranslateToFuzzReader(Module& wasm, std::vector<char> input);
+ TranslateToFuzzReader(Module& wasm, std::vector<char>&& input);
TranslateToFuzzReader(Module& wasm, std::string& filename);
void pickPasses(OptimizationOptions& options);
@@ -77,11 +78,7 @@ public:
private:
Module& wasm;
Builder builder;
- std::vector<char> bytes; // the input bytes
- size_t pos; // the position in the input
- // whether we already cycled through all the input (if so, we should try to
- // finish things off)
- bool finishedInput = false;
+ Random random;
// Whether to emit memory operations like loads and stores.
bool allowMemory = true;
@@ -93,10 +90,6 @@ private:
// Whether to emit atomic waits (which in single-threaded mode, may hang...)
static const bool ATOMIC_WAITS = false;
- // After we finish the input, we start going through it again, but xoring
- // so it's not identical
- int xorFactor = 0;
-
// The chance to emit a logging operation for a none expression. We
// randomize this in each function.
unsigned LOGGING_PERCENT = 0;
@@ -137,25 +130,21 @@ private:
int nesting = 0;
- // Methods for getting random data.
- int8_t get();
- int16_t get16();
- int32_t get32();
- int64_t get64();
- float getFloat() { return Literal(get32()).reinterpretf32(); }
- double getDouble() { return Literal(get64()).reinterpretf64(); }
-
- // Choose an integer value in [0, x). This doesn't use a perfectly uniform
- // distribution, but it's fast and reasonable.
- Index upTo(Index x);
- bool oneIn(Index x) { return upTo(x) == 0; }
-
- // Apply upTo twice, generating a skewed distribution towards
- // low values.
- Index upToSquared(Index x) { return upTo(upTo(x)); }
+ // Generating random data is common enough that it's worth having helpers that
+ // forward to `random`.
+ int8_t get() { return random.get(); }
+ int16_t get16() { return random.get16(); }
+ int32_t get32() { return random.get32(); }
+ int64_t get64() { return random.get64(); }
+ float getFloat() { return random.getFloat(); }
+ double getDouble() { return random.getDouble(); }
+ Index upTo(Index x) { return random.upTo(x); }
+ bool oneIn(Index x) { return random.oneIn(x); }
+ Index upToSquared(Index x) { return random.upToSquared(x); }
// Setup methods
void setupMemory();
+ void setupHeapTypes();
void setupTables();
void setupGlobals();
void setupTags();
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index 6ee8b4cd0..3182936cd 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -43,15 +43,8 @@ constexpr size_t Important = 2;
} // anonymous namespace
TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm,
- std::vector<char> input)
- : wasm(wasm), builder(wasm) {
- bytes.swap(input);
- pos = 0;
- finishedInput = false;
- // ensure *some* input to be read
- if (bytes.size() == 0) {
- bytes.push_back(0);
- }
+ std::vector<char>&& input)
+ : wasm(wasm), builder(wasm), random(std::move(input)) {
// - funcref cannot be logged because referenced functions can be inlined or
// removed during optimization
// - there's no point in logging externref or anyref because these are opaque
@@ -67,51 +60,8 @@ TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm,
: TranslateToFuzzReader(
wasm, read_file<std::vector<char>>(filename, Flags::Binary)) {}
-int8_t TranslateToFuzzReader::get() {
- if (pos == bytes.size()) {
- // we ran out of input, go to the start for more stuff
- finishedInput = true;
- pos = 0;
- xorFactor++;
- }
- return bytes[pos++] ^ xorFactor;
-}
-
-int16_t TranslateToFuzzReader::get16() {
- auto temp = uint16_t(get()) << 8;
- return temp | uint16_t(get());
-}
-
-int32_t TranslateToFuzzReader::get32() {
- auto temp = uint32_t(get16()) << 16;
- return temp | uint32_t(get16());
-}
-
-int64_t TranslateToFuzzReader::get64() {
- auto temp = uint64_t(get32()) << 32;
- return temp | uint64_t(get32());
-}
-
-Index TranslateToFuzzReader::upTo(Index x) {
- if (x == 0) {
- return 0;
- }
- Index raw;
- if (x <= 255) {
- raw = get();
- } else if (x <= 65535) {
- raw = get16();
- } else {
- raw = get32();
- }
- auto ret = raw % x;
- // use extra bits as "noise" for later
- xorFactor += raw / x;
- return ret;
-}
-
void TranslateToFuzzReader::pickPasses(OptimizationOptions& options) {
- while (options.passes.size() < 20 && !finishedInput && !oneIn(3)) {
+ while (options.passes.size() < 20 && !random.finished() && !oneIn(3)) {
switch (upTo(32)) {
case 0:
case 1:
@@ -235,7 +185,7 @@ void TranslateToFuzzReader::build() {
modifyInitialFunctions();
addImportLoggingSupport();
// keep adding functions until we run out of input
- while (!finishedInput) {
+ while (!random.finished()) {
auto* func = addFunction();
addInvocations(func);
}
@@ -604,7 +554,7 @@ Function* TranslateToFuzzReader::addFunction() {
wasm.addExport(export_);
}
// add some to an elem segment
- while (oneIn(3) && !finishedInput) {
+ while (oneIn(3) && !random.finished()) {
auto type = Type(func->type, NonNullable);
std::vector<ElementSegment*> compatibleSegments;
ModuleUtils::iterActiveElementSegments(wasm, [&](ElementSegment* segment) {
@@ -874,7 +824,7 @@ void TranslateToFuzzReader::addInvocations(Function* func) {
return;
}
std::vector<Expression*> invocations;
- while (oneIn(2) && !finishedInput) {
+ while (oneIn(2) && !random.finished()) {
std::vector<Expression*> args;
for (const auto& type : func->getParams()) {
args.push_back(makeConst(type));
@@ -906,7 +856,7 @@ void TranslateToFuzzReader::addInvocations(Function* func) {
Expression* TranslateToFuzzReader::make(Type type) {
// When we should stop, emit something small (but not necessarily trivial).
- if (finishedInput || nesting >= 5 * NESTING_LIMIT || // hard limit
+ if (random.finished() || nesting >= 5 * NESTING_LIMIT || // hard limit
(nesting >= NESTING_LIMIT && !oneIn(3))) {
if (type.isConcrete()) {
if (oneIn(2)) {
@@ -1086,13 +1036,13 @@ Expression* TranslateToFuzzReader::makeBlock(Type type) {
if (num == 0 && !oneIn(10)) {
num++;
}
- while (num > 0 && !finishedInput) {
+ while (num > 0 && !random.finished()) {
ret->list.push_back(make(Type::none));
num--;
}
// give a chance to make the final element an unreachable break, instead
// of concrete - a common pattern (branch to the top of a loop etc.)
- if (!finishedInput && type.isConcrete() && oneIn(2)) {
+ if (!random.finished() && type.isConcrete() && oneIn(2)) {
ret->list.push_back(makeBreak(Type::unreachable));
} else {
ret->list.push_back(make(type));
diff --git a/src/tools/fuzzing/random.cpp b/src/tools/fuzzing/random.cpp
new file mode 100644
index 000000000..38a86924e
--- /dev/null
+++ b/src/tools/fuzzing/random.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2021 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "literal.h"
+
+#include "random.h"
+
+namespace wasm {
+
+Random::Random(std::vector<char>&& bytes) : bytes(std::move(bytes)) {
+ // Ensure there is *some* input to be read.
+ if (bytes.empty()) {
+ bytes.push_back(0);
+ }
+}
+
+int8_t Random::get() {
+ if (pos == bytes.size()) {
+ // We ran out of input; go back to the start for more.
+ finishedInput = true;
+ pos = 0;
+ xorFactor++;
+ }
+ return bytes[pos++] ^ xorFactor;
+}
+
+int16_t Random::get16() {
+ auto temp = uint16_t(get()) << 8;
+ return temp | uint16_t(get());
+}
+
+int32_t Random::get32() {
+ auto temp = uint32_t(get16()) << 16;
+ return temp | uint32_t(get16());
+}
+
+int64_t Random::get64() {
+ auto temp = uint64_t(get32()) << 32;
+ return temp | uint64_t(get32());
+}
+
+float Random::getFloat() { return Literal(get32()).reinterpretf32(); }
+
+double Random::getDouble() { return Literal(get64()).reinterpretf64(); }
+
+uint32_t Random::upTo(uint32_t x) {
+ if (x == 0) {
+ return 0;
+ }
+ uint32_t raw;
+ if (x <= 255) {
+ raw = get();
+ } else if (x <= 65535) {
+ raw = get16();
+ } else {
+ raw = get32();
+ }
+ auto ret = raw % x;
+ // use extra bits as "noise" for later
+ xorFactor += raw / x;
+ return ret;
+}
+
+} // namespace wasm
diff --git a/src/tools/fuzzing/random.h b/src/tools/fuzzing/random.h
new file mode 100644
index 000000000..156f248ca
--- /dev/null
+++ b/src/tools/fuzzing/random.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef wasm_tools_fuzzing_random_h
+#define wasm_tools_fuzzing_random_h
+
+#include <cstdint>
+#include <vector>
+
+namespace wasm {
+
+class Random {
+ // The input seed bytes.
+ std::vector<char> bytes;
+ // The current position in `bytes`.
+ size_t pos = 0;
+ // Whether we already cycled through all the input (which might mean we should
+ // try to finish things off).
+ bool finishedInput = false;
+ // After we finish the input, we start going through it again, but xoring
+ // so it's not identical.
+ int xorFactor = 0;
+
+public:
+ Random(std::vector<char>&& bytes);
+
+ // Methods for getting random data.
+ int8_t get();
+ int16_t get16();
+ int32_t get32();
+ int64_t get64();
+ float getFloat();
+ double getDouble();
+
+ // Choose an integer value in [0, x). This doesn't use a perfectly uniform
+ // distribution, but it's fast and reasonable.
+ uint32_t upTo(uint32_t x);
+ bool oneIn(uint32_t x) { return upTo(x) == 0; }
+
+ // Apply upTo twice, generating a skewed distribution towards
+ // low values.
+ uint32_t upToSquared(uint32_t x) { return upTo(upTo(x)); }
+
+ bool finished() { return finishedInput; }
+};
+
+} // namespace wasm
+
+#endif // wasm_tools_fuzzing_random_h