Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This fuzzing target aims to stress the SpiderMonkey parser. However, for
// this purpose, it does *not* use `parse()` because some past bugs in the
// parser could only be triggered in the runtime later. Instead, we use
// the `evaluate` function which parses and runs the code. This brings in
// other problems like timeouts and permanent side-effects. We try to minimize
// the amount of permanent side-effects from running the code by running it
// in a fresh global for each iteration. We also use a special function
// called `sanitizeGlobal` to remove any harmful shell functions from the
// global prior to running. Many of these shell functions would otherwise
// have permanent side-effects of some sort or be disruptive to testing like
// increasing the amount of timeouts or leak memory. Finally, the target also
// tries to catch timeouts locally and signal back any timeouts by returning 1
// from the iteration function.
// This global will hold the current fuzzing buffer for each iteration.
var fuzzBuf;
loadRelativeToScript("util/sanitize.js");
deterministicgc(true);
// Set a default value for timeouts to 1 second, but allow this to
// be set on the command line as well using -e fuzzTimeout=VAL.
if (typeof fuzzTimeout === "undefined") {
fuzzTimeout = 1;
}
function JSFuzzIterate() {
try {
let code = String.fromCharCode(...fuzzBuf);
let result = null;
// Create a new global and sanitize it such that its potentially permanent
// side-effects are reduced to a minimum.
let global = newGlobal();
sanitizeGlobal(global);
// Work around memory leaks when the hook is not set
evaluate(`
setModuleResolveHook(function(module, specifier) {
throw "Module '" + specifier + "' not found";
});
setModuleResolveHook = function() {};
`, { global: global, catchTermination: true });
// Start a timer and set a timeout in addition
let lfStart = monotonicNow();
timeout(fuzzTimeout, function() { return false; });
try {
result = evaluate(code, { global: global, catchTermination: true });
} catch(exc) {
print(exc);
}
timeout(-1);
let lfStop = monotonicNow();
// Reset some things that could have been altered by the code we ran
gczeal(0);
schedulegc(0);
setGCCallback({ action: "majorGC" });
clearSavedFrames();
// If we either ended terminating the script, or we took longer than
// the timeout set (but timeout didn't kick in), then we return 1 to
// signal libFuzzer that the sample just be abandoned.
if (result === "terminated" || (lfStop - lfStart > (fuzzTimeout * 1000 + 200))) {
return 1;
}
return 0;
} catch(exc) {
print("Caught toplevel exception: " + exc);
}
return 1;
}