parsing-evaluate.js (3069B)
1 /* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 // This fuzzing target aims to stress the SpiderMonkey parser. However, for 7 // this purpose, it does *not* use `parse()` because some past bugs in the 8 // parser could only be triggered in the runtime later. Instead, we use 9 // the `evaluate` function which parses and runs the code. This brings in 10 // other problems like timeouts and permanent side-effects. We try to minimize 11 // the amount of permanent side-effects from running the code by running it 12 // in a fresh global for each iteration. We also use a special function 13 // called `sanitizeGlobal` to remove any harmful shell functions from the 14 // global prior to running. Many of these shell functions would otherwise 15 // have permanent side-effects of some sort or be disruptive to testing like 16 // increasing the amount of timeouts or leak memory. Finally, the target also 17 // tries to catch timeouts locally and signal back any timeouts by returning 1 18 // from the iteration function. 19 20 // This global will hold the current fuzzing buffer for each iteration. 21 var fuzzBuf; 22 23 loadRelativeToScript("util/sanitize.js"); 24 25 deterministicgc(true); 26 27 // Set a default value for timeouts to 1 second, but allow this to 28 // be set on the command line as well using -e fuzzTimeout=VAL. 29 if (typeof fuzzTimeout === "undefined") { 30 fuzzTimeout = 1; 31 } 32 33 function JSFuzzIterate() { 34 try { 35 let code = String.fromCharCode(...fuzzBuf); 36 let result = null; 37 38 // Create a new global and sanitize it such that its potentially permanent 39 // side-effects are reduced to a minimum. 40 let global = newGlobal(); 41 sanitizeGlobal(global); 42 43 // Work around memory leaks when the hook is not set 44 evaluate(` 45 setModuleResolveHook(function(module, specifier) { 46 throw "Module '" + specifier + "' not found"; 47 }); 48 setModuleResolveHook = function() {}; 49 `, { global: global, catchTermination: true }); 50 51 // Start a timer and set a timeout in addition 52 let lfStart = monotonicNow(); 53 timeout(fuzzTimeout, function() { return false; }); 54 55 try { 56 result = evaluate(code, { global: global, catchTermination: true }); 57 } catch(exc) { 58 print(exc); 59 } 60 61 timeout(-1); 62 let lfStop = monotonicNow(); 63 64 // Reset some things that could have been altered by the code we ran 65 gczeal(0); 66 schedulegc(0); 67 setGCCallback({ action: "majorGC" }); 68 clearSavedFrames(); 69 70 // If we either ended terminating the script, or we took longer than 71 // the timeout set (but timeout didn't kick in), then we return 1 to 72 // signal libFuzzer that the sample just be abandoned. 73 if (result === "terminated" || (lfStop - lfStart > (fuzzTimeout * 1000 + 200))) { 74 return 1; 75 } 76 77 return 0; 78 } catch(exc) { 79 print("Caught toplevel exception: " + exc); 80 } 81 82 return 1; 83 }