summaryrefslogtreecommitdiff
path: root/src/tools/wasm-opt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/wasm-opt.cpp')
-rw-r--r--src/tools/wasm-opt.cpp132
1 files changed, 64 insertions, 68 deletions
diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp
index 184dbae1b..c34331366 100644
--- a/src/tools/wasm-opt.cpp
+++ b/src/tools/wasm-opt.cpp
@@ -29,65 +29,16 @@
#include "wasm-validator.h"
#include "wasm-io.h"
#include "wasm-interpreter.h"
+#include "wasm-binary.h"
#include "shell-interface.h"
#include "optimization-options.h"
+#include "execution-results.h"
+#include "translate-to-fuzz.h"
+#include "js-wrapper.h"
+#include "spec-wrapper.h"
using namespace wasm;
-// gets execution results from a wasm module. this is useful for fuzzing
-//
-// we can only get results when there are no imports. we then call each method
-// that has a result, with some values
-struct ExecutionResults {
- std::map<Name, Literal> results;
-
- void get(Module& wasm) {
- if (wasm.imports.size() > 0) {
- std::cout << "[fuzz-exec] imports, so quitting\n";
- return;
- }
- for (auto& func : wasm.functions) {
- if (func->result != none) {
- // this is good
- results[func->name] = run(func.get(), wasm);
- }
- }
- std::cout << "[fuzz-exec] " << results.size() << " results noted\n";
- }
-
- bool operator==(ExecutionResults& other) {
- for (auto& iter : results) {
- auto name = iter.first;
- if (other.results.find(name) != other.results.end()) {
- if (results[name] != other.results[name]) {
- return false;
- }
- }
- }
- return true;
- }
-
- bool operator!=(ExecutionResults& other) {
- return !((*this) == other);
- }
-
- Literal run(Function* func, Module& wasm) {
- ShellExternalInterface interface;
- try {
- ModuleInstance instance(wasm, &interface);
- LiteralList arguments;
- for (WasmType param : func->params) {
- // zeros in arguments TODO: more?
- arguments.push_back(Literal(param));
- }
- return instance.callFunction(func->name, arguments);
- } catch (const TrapException&) {
- // may throw in instance creation (init of offsets) or call itself
- return Literal();
- }
- }
-};
-
//
// main
//
@@ -98,8 +49,12 @@ int main(int argc, const char* argv[]) {
bool emitBinary = true;
bool debugInfo = false;
bool fuzzExec = false;
+ bool fuzzBinary = false;
+ bool translateToFuzz = false;
+ std::string emitJSWrapper;
+ std::string emitSpecWrapper;
- OptimizationOptions options("wasm-opt", "Optimize .wast files");
+ OptimizationOptions options("wasm-opt", "Read, write, and optimize files");
options
.add("--output", "-o", "Output file (stdout if not specified)",
Options::Arguments::One,
@@ -116,21 +71,31 @@ int main(int argc, const char* argv[]) {
.add("--fuzz-exec", "-fe", "Execute functions before and after optimization, helping fuzzing find bugs",
Options::Arguments::Zero,
[&](Options *o, const std::string &arguments) { fuzzExec = true; })
+ .add("--fuzz-binary", "-fb", "Convert to binary and back after optimizations and before fuzz-exec, helping fuzzing find binary format bugs",
+ Options::Arguments::Zero,
+ [&](Options *o, const std::string &arguments) { fuzzBinary = true; })
+ .add("--translate-to-fuzz", "-ttf", "Translate the input into a valid wasm module *somehow*, useful for fuzzing",
+ Options::Arguments::Zero,
+ [&](Options *o, const std::string &arguments) { translateToFuzz = true; })
+ .add("--emit-js-wrapper", "-ejw", "Emit a JavaScript wrapper file that can run the wasm with some test values, useful for fuzzing",
+ Options::Arguments::One,
+ [&](Options *o, const std::string &arguments) { emitJSWrapper = arguments; })
+ .add("--emit-spec-wrapper", "-esw", "Emit a wasm spec interpreter wrapper file that can run the wasm with some test values, useful for fuzzing",
+ Options::Arguments::One,
+ [&](Options *o, const std::string &arguments) { emitSpecWrapper = arguments; })
.add_positional("INFILE", Options::Arguments::One,
[](Options* o, const std::string& argument) {
o->extra["infile"] = argument;
});
options.parse(argc, argv);
- auto input(read_file<std::string>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release));
-
Module wasm;
- {
- if (options.debug) std::cerr << "reading...\n";
+ if (options.debug) std::cerr << "reading...\n";
+
+ if (!translateToFuzz) {
ModuleReader reader;
reader.setDebug(options.debug);
-
try {
reader.read(options.extra["infile"], wasm);
} catch (ParseException& p) {
@@ -139,10 +104,18 @@ int main(int argc, const char* argv[]) {
} catch (std::bad_alloc& b) {
Fatal() << "error in building module, std::bad_alloc (possibly invalid request for silly amounts of memory)";
}
- }
- if (!WasmValidator().validate(wasm)) {
- Fatal() << "error in validating input";
+ if (!WasmValidator().validate(wasm)) {
+ Fatal() << "error in validating input";
+ }
+ } else {
+ // translate-to-fuzz
+ TranslateToFuzzReader reader(wasm);
+ reader.read(options.extra["infile"]);
+ if (!WasmValidator().validate(wasm)) {
+ std::cerr << "translate-to-fuzz must always generate a valid module";
+ abort();
+ }
}
ExecutionResults results;
@@ -158,12 +131,21 @@ int main(int argc, const char* argv[]) {
}
if (fuzzExec) {
- ExecutionResults optimizedResults;
- optimizedResults.get(wasm);
- if (optimizedResults != results) {
- Fatal() << "[fuzz-exec] optimization passes changed execution results";
+ auto* compare = &wasm;
+ Module second;
+ if (fuzzBinary) {
+ compare = &second;
+ BufferWithRandomAccess buffer(false);
+ // write the binary
+ WasmBinaryWriter writer(&wasm, buffer, false);
+ writer.write();
+ // read the binary
+ auto input = buffer.getAsChars();
+ WasmBinaryBuilder parser(second, input, false);
+ parser.read();
+ assert(WasmValidator().validate(second));
}
- std::cout << "[fuzz-exec] results match\n";
+ results.check(*compare);
}
if (options.extra.count("output") > 0) {
@@ -174,4 +156,18 @@ int main(int argc, const char* argv[]) {
writer.setDebugInfo(debugInfo);
writer.write(wasm, options.extra["output"]);
}
+
+ if (emitJSWrapper.size() > 0) {
+ std::ofstream outfile;
+ outfile.open(emitJSWrapper, std::ofstream::out);
+ outfile << generateJSWrapper(wasm);
+ outfile.close();
+ }
+
+ if (emitSpecWrapper.size() > 0) {
+ std::ofstream outfile;
+ outfile.open(emitSpecWrapper, std::ofstream::out);
+ outfile << generateSpecWrapper(wasm);
+ outfile.close();
+ }
}