/* * Copyright 2017 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. */ // // Emit a JavaScript wrapper to run a wasm module with some test // values, useful for fuzzing. // namespace wasm { static std::string generateJSWrapper(Module& wasm) { std::string ret; ret += "if (typeof console === 'undefined') {\n" " console = { log: print };\n" "}\n" "var tempRet0;\n" "var binary;\n" "if (typeof process === 'object' && typeof require === 'function' /* " "node.js detection */) {\n" " var args = process.argv.slice(2);\n" " binary = require('fs').readFileSync(args[0]);\n" " if (!binary.buffer) binary = new Uint8Array(binary);\n" "} else {\n" " var args;\n" " if (typeof scriptArgs != 'undefined') {\n" " args = scriptArgs;\n" " } else if (typeof arguments != 'undefined') {\n" " args = arguments;\n" " }\n" " if (typeof readbuffer === 'function') {\n" " binary = new Uint8Array(readbuffer(args[0]));\n" " } else {\n" " binary = read(args[0], 'binary');\n" " }\n" "}\n" "function literal(x, type) {\n" " var ret = '';\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 += Number(x).toString();\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('[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" " 'getTempRet0': function() { return tempRet0 },\n" " },\n" "});\n"; for (auto& exp : wasm.exports) { if (exp->kind != ExternalKind::Function) { continue; // something exported other than a function } auto* func = wasm.getFunction(exp->value); ret += "if (instance.exports.hangLimitInitializer) " "instance.exports.hangLimitInitializer();\n"; ret += "try {\n"; ret += std::string(" console.log('[fuzz-exec] calling ") + exp->name.str + "');\n"; if (func->sig.results != Type::none) { 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 (const auto& param : func->sig.params) { // zeros in arguments TODO more? if (first) { first = false; } else { ret += ", "; } ret += "0"; if (param == Type::i64) { ret += ", 0"; } } ret += ")"; if (func->sig.results != Type::none) { ret += ", '" + func->sig.results.toString() + "'))"; // TODO: getTempRet } ret += ";\n"; ret += "} catch (e) {\n"; ret += " console.log('exception!' /* + e */);\n"; ret += "}\n"; } return ret; } } // namespace wasm