diff --git a/js/src/shell/OSObject.cpp b/js/src/shell/OSObject.cpp index e97125ce9403..42c37922a193 100644 --- a/js/src/shell/OSObject.cpp +++ b/js/src/shell/OSObject.cpp @@ -147,7 +147,7 @@ ResolvePath(JSContext* cx, HandleString filenameStr, PathResolutionMode resolveM return JS_NewStringCopyZ(cx, buffer); } -static JSObject* +JSObject* FileAsTypedArray(JSContext* cx, const char* pathname) { FILE* file = fopen(pathname, "rb"); diff --git a/js/src/shell/OSObject.h b/js/src/shell/OSObject.h index 745f3c26a3e1..478a7f892e77 100644 --- a/js/src/shell/OSObject.h +++ b/js/src/shell/OSObject.h @@ -26,6 +26,9 @@ enum PathResolutionMode { JSString* ResolvePath(JSContext* cx, JS::HandleString filenameStr, PathResolutionMode resolveMode); +JSObject* +FileAsTypedArray(JSContext* cx, const char* pathname); + } // namespace shell } // namespace js diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 7b0b8aff6c67..9937681a2184 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -58,6 +58,7 @@ #include "jswrapper.h" #include "shellmoduleloader.out.h" +#include "asmjs/Wasm.h" #include "builtin/ModuleObject.h" #include "builtin/TestingFunctions.h" #include "frontend/Parser.h" @@ -4915,6 +4916,62 @@ SetARMHwCapFlags(JSContext* cx, unsigned argc, Value* vp) return true; } +#ifdef __AFL_HAVE_MANUAL_CONTROL +static bool +WasmLoop(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + RootedObject callee(cx, &args.callee()); + + if (args.length() < 1 || args.length() > 2) { + ReportUsageError(cx, callee, "Wrong number of arguments"); + return false; + } + + if (!args[0].isString()) { + ReportUsageError(cx, callee, "First argument must be a String"); + return false; + } + + RootedObject importObj(cx); + if (!args.get(1).isUndefined()) { + if (!args.get(1).isObject()) { + ReportUsageError(cx, callee, "Second argument, if present, must be an Object"); + return false; + } + importObj = &args[1].toObject(); + } + + RootedString givenPath(cx, args[0].toString()); + RootedString str(cx, ResolvePath(cx, givenPath, RootRelative)); + if (!str) + return false; + + JSAutoByteString filename(cx, str); + if (!filename) + return false; + + while (__AFL_LOOP(1000)) { + Rooted ret(cx, FileAsTypedArray(cx, filename.ptr())); + if (!ret) + return false; + + Rooted typedArray(cx, &ret->as()); + if (!TypedArrayObject::ensureHasBuffer(cx, typedArray)) + return false; + + Rooted arrayBuffer(cx, typedArray->bufferUnshared()); + RootedObject exportObj(cx); + if (!wasm::Eval(cx, arrayBuffer, importObj, &exportObj)) { + // Clear any pending exceptions, we don't care about them + cx->clearPendingException(); + } + } + + return true; +} +#endif // __AFL_HAVE_MANUAL_CONTROL + static const JSFunctionSpecWithHelp shell_functions[] = { JS_FN_HELP("version", Version, 0, 0, "version([number])", @@ -5384,6 +5441,13 @@ TestAssertRecoveredOnBailout, " On non-ARM, no-op. On ARM, set the hardware capabilities. The list of \n" " flags is available by calling this function with \"help\" as the flag's name"), +#ifdef __AFL_HAVE_MANUAL_CONTROL + JS_FN_HELP("wasmLoop", WasmLoop, 2, 0, +"wasmLoop(filename, imports)", +" Performs an AFL-style persistent loop reading data from the given file and passing it\n" +" to the 'wasmEval' function together with the specified imports object."), +#endif + JS_FS_HELP_END };