Bug 1247247 - Add AFL-style wasmLoop function for persistent fuzzing. r=luke draft
authorChristian Holler <choller@mozilla.com>
Thu, 11 Feb 2016 14:55:53 +0100
changeset 330338 6c7ef9ea3d8a426d7f474bf46e07c3002753ca02
parent 330337 5b3ab5363bf0eade63509e5f1c08073cde3841dc
child 514154 074fb8f8abec1143fb9f88003d4a19131dd2e65b
push id10736
push usercholler@mozilla.com
push dateThu, 11 Feb 2016 14:54:12 +0000
reviewersluke
bugs1247247
milestone47.0a1
Bug 1247247 - Add AFL-style wasmLoop function for persistent fuzzing. r=luke MozReview-Commit-ID: RFQ5pqCvl6
js/src/shell/OSObject.cpp
js/src/shell/OSObject.h
js/src/shell/js.cpp
--- a/js/src/shell/OSObject.cpp
+++ b/js/src/shell/OSObject.cpp
@@ -142,17 +142,17 @@ ResolvePath(JSContext* cx, HandleString 
     buffer[len] = '/';
     strncpy(buffer + len + 1, filename.ptr(), sizeof(buffer) - (len+1));
     if (buffer[PATH_MAX] != '\0')
         return nullptr;
 
     return JS_NewStringCopyZ(cx, buffer);
 }
 
-static JSObject*
+JSObject*
 FileAsTypedArray(JSContext* cx, const char* pathname)
 {
     FILE* file = fopen(pathname, "rb");
     if (!file) {
         JS_ReportError(cx, "can't open %s: %s", pathname, strerror(errno));
         return nullptr;
     }
     AutoCloseFile autoClose(file);
--- a/js/src/shell/OSObject.h
+++ b/js/src/shell/OSObject.h
@@ -21,12 +21,15 @@ DefineOS(JSContext* cx, JS::HandleObject
 enum PathResolutionMode {
     RootRelative,
     ScriptRelative
 };
 
 JSString*
 ResolvePath(JSContext* cx, JS::HandleString filenameStr, PathResolutionMode resolveMode);
 
+JSObject* 
+FileAsTypedArray(JSContext* cx, const char* pathname);
+
 } // namespace shell
 } // namespace js
 
 #endif /* shell_OSObject_h */
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -89,16 +89,18 @@
 
 #include "jscompartmentinlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/ErrorObject-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/Stack-inl.h"
 
+#include "asmjs/Wasm.h"
+
 using namespace js;
 using namespace js::cli;
 using namespace js::shell;
 
 using mozilla::ArrayLength;
 using mozilla::Atomic;
 using mozilla::Maybe;
 using mozilla::NumberEqualsInt32;
@@ -4910,16 +4912,72 @@ SetARMHwCapFlags(JSContext* cx, unsigned
 
     jit::ParseARMHwCapFlags(flagsList.ptr());
 #endif
 
     args.rval().setUndefined();
     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<JSObject*> ret(cx, FileAsTypedArray(cx, filename.ptr()));
+        if (!ret)
+            return false;
+
+        Rooted<TypedArrayObject*> typedArray(cx, &ret->as<TypedArrayObject>());
+        if (!TypedArrayObject::ensureHasBuffer(cx, typedArray))
+            return false;
+
+        Rooted<ArrayBufferObject*> 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])",
 "  Get or force a script compilation version number."),
 
     JS_FN_HELP("options", Options, 0, 0,
 "options([option ...])",
 "  Get or toggle JavaScript options."),
@@ -5379,16 +5437,23 @@ TestAssertRecoveredOnBailout,
 "crash([message])",
 "  Crashes the process with a MOZ_CRASH."),
 
     JS_FN_HELP("setARMHwCapFlags", SetARMHwCapFlags, 1, 0,
 "setARMHwCapFlags(\"flag1,flag2 flag3\")",
 "  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
 };
 
 static const JSFunctionSpecWithHelp console_functions[] = {
     JS_FN_HELP("log", Print, 0, 0,
 "log([exp ...])",
 "  Evaluate and print expressions to stdout.\n"
 "  This function is an alias of the print() function."),