diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/shell-interface.h | 2 | ||||
-rw-r--r-- | src/tools/execution-results.h | 29 | ||||
-rw-r--r-- | src/tools/js-wrapper.h | 48 | ||||
-rw-r--r-- | src/tools/wasm-opt.cpp | 21 |
4 files changed, 61 insertions, 39 deletions
diff --git a/src/shell-interface.h b/src/shell-interface.h index fc6a5897c..071cc614d 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -200,7 +200,7 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface { } void trap(const char* why) override { - std::cerr << "[trap " << why << "]\n"; + std::cout << "[trap " << why << "]\n"; throw TrapException(); } }; diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 89e0440bb..554b4eb6c 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -26,20 +26,22 @@ namespace wasm { typedef std::vector<Literal> Loggings; -// Logs every single import call parameter. +// Logs every relevant import call parameter. struct LoggingExternalInterface : public ShellExternalInterface { Loggings& loggings; LoggingExternalInterface(Loggings& loggings) : loggings(loggings) {} Literal callImport(Function* import, LiteralList& arguments) override { - std::cout << "[LoggingExternalInterface logging"; - loggings.push_back(Literal()); // buffer with a None between calls - for (auto argument : arguments) { - std::cout << ' ' << argument; - loggings.push_back(argument); + if (import->module == "fuzzing-support") { + std::cout << "[LoggingExternalInterface logging"; + loggings.push_back(Literal()); // buffer with a None between calls + for (auto argument : arguments) { + std::cout << ' ' << argument; + loggings.push_back(argument); + } + std::cout << "]\n"; } - std::cout << "]\n"; return Literal(); } }; @@ -60,21 +62,23 @@ struct ExecutionResults { // execute all exported methods (that are therefore preserved through opts) for (auto& exp : wasm.exports) { if (exp->kind != ExternalKind::Function) continue; + std::cout << "[fuzz-exec] calling " << exp->name << "\n"; auto* func = wasm.getFunction(exp->value); if (func->result != none) { // this has a result results[exp->name] = run(func, wasm, instance); - std::cout << "[fuzz-exec] note result: " << exp->name << " => " << results[exp->name] << '\n'; + // ignore the result if we hit an unreachable and returned no value + if (isConcreteType(results[exp->name].type)) { + std::cout << "[fuzz-exec] note result: " << exp->name << " => " << results[exp->name] << '\n'; + } } else { // no result, run it anyhow (it might modify memory etc.) run(func, wasm, instance); - std::cout << "[fuzz-exec] no result for void func: " << exp->name << '\n'; } } } catch (const TrapException&) { // may throw in instance creation (init of offsets) } - std::cout << "[fuzz-exec] " << results.size() << " results noted\n"; } // get current results and check them against previous ones @@ -85,7 +89,6 @@ struct ExecutionResults { std::cout << "[fuzz-exec] optimization passes changed execution results"; abort(); } - std::cout << "[fuzz-exec] " << results.size() << " results match\n"; } bool operator==(ExecutionResults& other) { @@ -127,8 +130,8 @@ struct ExecutionResults { try { LiteralList arguments; // init hang support, if present - if (wasm.getFunctionOrNull("hangLimitInitializer")) { - instance.callFunction("hangLimitInitializer", arguments); + if (auto* ex = wasm.getExportOrNull("hangLimitInitializer")) { + instance.callFunction(ex->value, arguments); } // call the method for (Type param : func->params) { diff --git a/src/tools/js-wrapper.h b/src/tools/js-wrapper.h index 7cf2ffc53..765a638c5 100644 --- a/src/tools/js-wrapper.h +++ b/src/tools/js-wrapper.h @@ -22,10 +22,6 @@ namespace wasm { static std::string generateJSWrapper(Module& wasm) { - PassRunner runner(&wasm); - runner.add("legalize-js-interface"); - runner.run(); - std::string ret; ret += "if (typeof console === 'undefined') {\n" " console = { log: print };\n" @@ -49,12 +45,26 @@ static std::string generateJSWrapper(Module& wasm) { " binary = read(args[0], 'binary');\n" " }\n" "}\n" + "function literal(x, type) {\n" + " var ret = type + '.const ';\n" + " switch (type) {\n" + " case 'i32': ret += (x | 0); break;\n" + " case 'f32':\n" + " case 'f64': {\n" + " if (x == 0 && (1 / x) < 0) ret += '-';\n" + " ret += x;\n" + " break;\n" + " }\n" + " default: throw 'what?';\n" + " }\n" + " return ret;\n" + "}\n" "var instance = new WebAssembly.Instance(new WebAssembly.Module(binary), {\n" " 'fuzzing-support': {\n" - " 'log-i32': function(x) { console.log('i32: ' + x) },\n" - " 'log-i64': function(x, y) { console.log('i64: ' + x + ', ' + y) },\n" - " 'log-f32': function(x) { console.log('f32: ' + x) },\n" - " 'log-f64': function(x) { console.log('f64: ' + x) }\n" + " 'log-i32': function(x) { console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') + ']') },\n" + " 'log-i64': function(x, y) { console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') + ' ' + literal(y, 'i32') + ']') },\n" // legalization: two i32s + " 'log-f32': function(x) { console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') + ']') },\n" // legalization: an f64 + " 'log-f64': function(x) { console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') + ']') },\n" " },\n" " 'env': {\n" " 'setTempRet0': function(x) { tempRet0 = x },\n" @@ -64,22 +74,17 @@ static std::string generateJSWrapper(Module& wasm) { for (auto& exp : wasm.exports) { auto* func = wasm.getFunctionOrNull(exp->value); if (!func) continue; // something exported other than a function - auto bad = false; // check for things we can't support - for (Type param : func->params) { - if (param == i64) bad = true; - } - if (func->result == i64) bad = true; - if (bad) continue; ret += "if (instance.exports.hangLimitInitializer) instance.exports.hangLimitInitializer();\n"; ret += "try {\n"; - ret += std::string(" console.log('calling: ") + exp->name.str + "');\n"; + ret += std::string(" console.log('[fuzz-exec] calling $") + exp->name.str + "');\n"; if (func->result != none) { - ret += " console.log(' result: ' + "; + ret += std::string(" console.log('[fuzz-exec] note result: $") + exp->name.str + " => ' + literal("; + } else { + ret += " "; } ret += std::string("instance.exports.") + exp->name.str + "("; bool first = true; for (Type param : func->params) { - WASM_UNUSED(param); // zeros in arguments TODO more? if (first) { first = false; @@ -87,17 +92,20 @@ static std::string generateJSWrapper(Module& wasm) { ret += ", "; } ret += "0"; + if (param == i64) { + ret += ", 0"; + } } ret += ")"; if (func->result != none) { - ret += ")"; // for console.log + ret += ", '" + std::string(printType(func->result)) + "'))"; + // TODO: getTempRet } ret += ";\n"; ret += "} catch (e) {\n"; - ret += " console.log(' exception: ' + e);\n"; + ret += " console.log('exception: ' + e);\n"; ret += "}\n"; } - ret += "console.log('done.')\n"; return ret; } diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index 3e04fc644..5238caf7a 100644 --- a/src/tools/wasm-opt.cpp +++ b/src/tools/wasm-opt.cpp @@ -65,7 +65,8 @@ int main(int argc, const char* argv[]) { bool emitBinary = true; bool debugInfo = false; bool converge = false; - bool fuzzExec = false; + bool fuzzExecBefore = false; + bool fuzzExecAfter = false; bool fuzzBinary = false; std::string extraFuzzCommand; bool translateToFuzz = false; @@ -93,9 +94,12 @@ int main(int argc, const char* argv[]) { .add("--converge", "-c", "Run passes to convergence, continuing while binary size decreases", Options::Arguments::Zero, [&](Options *o, const std::string& arguments) { converge = true; }) + .add("--fuzz-exec-before", "-feh", "Execute functions before optimization, helping fuzzing find bugs", + Options::Arguments::Zero, + [&](Options *o, const std::string& arguments) { fuzzExecBefore = true; }) .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; }) + [&](Options *o, const std::string& arguments) { fuzzExecBefore = fuzzExecAfter = 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; }) @@ -172,8 +176,15 @@ int main(int argc, const char* argv[]) { } } + if (emitJSWrapper.size() > 0) { + // As the code will run in JS, we must legalize it. + PassRunner runner(&wasm); + runner.add("legalize-js-interface"); + runner.run(); + } + ExecutionResults results; - if (fuzzExec) { + if (fuzzExecBefore) { results.get(wasm); } @@ -207,7 +218,7 @@ int main(int argc, const char* argv[]) { Module* curr = &wasm; Module other; - if (fuzzExec && fuzzBinary) { + if (fuzzExecAfter && fuzzBinary) { BufferWithRandomAccess buffer(false); // write the binary WasmBinaryWriter writer(&wasm, buffer, false); @@ -259,7 +270,7 @@ int main(int argc, const char* argv[]) { } } - if (fuzzExec) { + if (fuzzExecAfter) { results.check(*curr); } |