зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1596691 - Add a JSParser target to fuzz-tests. r=jandem
Differential Revision: https://phabricator.services.mozilla.com/D77006
This commit is contained in:
Родитель
97d7ed04a7
Коммит
f3e4280df1
|
@ -143,6 +143,9 @@ js/src/jsapi-tests/binast/
|
|||
js/src/tests/
|
||||
js/src/Y.js
|
||||
|
||||
# Fuzzing code for testing only, targeting the JS shell
|
||||
js/src/fuzz-tests/
|
||||
|
||||
# Uses `#filter substitution`
|
||||
mobile/android/app/mobile.js
|
||||
mobile/android/app/geckoview-prefs.js
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/* -*- 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;
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/* -*- 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 function can be used to "sanitize" a new global for fuzzing in such
|
||||
// a way that permanent side-effects, hangs and behavior that could be harmful
|
||||
// to libFuzzer targets is reduced to a minimum.
|
||||
function sanitizeGlobal(g) {
|
||||
let lfFuncs = {
|
||||
// Noisy functions (output)
|
||||
backtrace: function() {},
|
||||
getBacktrace: function() {},
|
||||
help: function() {},
|
||||
print: function(s) { return s.toString(); },
|
||||
printErr: function(s) { return s.toString(); },
|
||||
putstr: function(s) { return s.toString(); },
|
||||
stackDump: function() {},
|
||||
dumpHeap: function() {},
|
||||
dumpScopeChain: function() {},
|
||||
dumpObjectWrappers: function() {},
|
||||
dumpGCArenaInfo: function() {},
|
||||
printProfilerEvents: function() {},
|
||||
|
||||
// Harmful functions (hangs, timeouts, leaks)
|
||||
getLcovInfo: function() {},
|
||||
readline: function() {},
|
||||
readlineBuf: function() {},
|
||||
timeout: function() {},
|
||||
quit: function() {},
|
||||
interruptIf: function() {},
|
||||
terminate: function() {},
|
||||
invokeInterruptCallback: function() {},
|
||||
setInterruptCallback: function() {},
|
||||
intern: function() {},
|
||||
evalInWorker: function() {},
|
||||
sleep: function() {},
|
||||
cacheEntry: function() {},
|
||||
streamCacheEntry: function() {},
|
||||
createMappedArrayBuffer: function() {},
|
||||
wasmCompileInSeparateProcess: function() {},
|
||||
gcparam: function() {},
|
||||
newGlobal: function() { return g; },
|
||||
|
||||
// Harmful functions (throw)
|
||||
assertEq: function(a,b) { return a.toString() == b.toString(); },
|
||||
throwError: function() {},
|
||||
reportOutOfMemory: function() {},
|
||||
throwOutOfMemory: function() {},
|
||||
reportLargeAllocationFailure: function() {},
|
||||
|
||||
// Functions that need limiting
|
||||
gczeal: function(m, f) { return gczeal(m, 100); },
|
||||
startgc: function(n, o) { startgc(n > 20 ? 20 : n, o); },
|
||||
gcslice: function(n) { gcslice(n > 20 ? 20 : n); },
|
||||
|
||||
// Global side-effects
|
||||
deterministicgc: function() {},
|
||||
fullcompartmentchecks: function() {},
|
||||
setIonCheckGraphCoherency: function() {},
|
||||
enableShellAllocationMetadataBuilder: function() {},
|
||||
setTimeResolution: function() {},
|
||||
options: function() { return "tracejit,methodjit,typeinfer"; },
|
||||
setJitCompilerOption: function() {},
|
||||
clearLastWarning: function() {},
|
||||
enableSingleStepProfiling: function() {},
|
||||
disableSingleStepProfiling: function() {},
|
||||
enableGeckoProfiling: function() {},
|
||||
enableGeckoProfilingWithSlowAssertions: function() {},
|
||||
disableGeckoProfiling: function() {},
|
||||
enqueueJob: function() {},
|
||||
globalOfFirstJobInQueue: function() {},
|
||||
drainJobQueue: function() {},
|
||||
setPromiseRejectionTrackerCallback: function() {},
|
||||
startTimingMutator: function() {},
|
||||
stopTimingMutator: function() {},
|
||||
setModuleLoadHook: function() {},
|
||||
// Left enabled, as it is required for now to avoid leaks
|
||||
//setModuleResolveHook: function() {},
|
||||
setModuleMetadataHook: function() {},
|
||||
setModuleDynamicImportHook: function() {},
|
||||
finishDynamicModuleImport: function() {},
|
||||
abortDynamicModuleImport: function() {},
|
||||
offThreadCompileScript: function() {},
|
||||
runOffThreadScript: function() {},
|
||||
offThreadCompileModule: function() {},
|
||||
finishOffThreadModule: function() {},
|
||||
offThreadDecodeScript: function() {},
|
||||
runOffThreadDecodedScript: function() {},
|
||||
addPromiseReactions: function() {},
|
||||
ignoreUnhandledRejections: function() {},
|
||||
enableTrackAllocations: function() {},
|
||||
disableTrackAllocations: function() {},
|
||||
startTraceLogger: function() {},
|
||||
stopTraceLogger: function() {},
|
||||
setTestFilenameValidationCallback: function() {},
|
||||
};
|
||||
|
||||
for (let lfFunc in lfFuncs) {
|
||||
g[lfFunc] = lfFuncs[lfFunc];
|
||||
}
|
||||
|
||||
return g;
|
||||
}
|
Загрузка…
Ссылка в новой задаче