summaryrefslogtreecommitdiffstats
path: root/js/src/fuzz-tests/differential-parsing.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/fuzz-tests/differential-parsing.js
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/fuzz-tests/differential-parsing.js')
-rw-r--r--js/src/fuzz-tests/differential-parsing.js148
1 files changed, 148 insertions, 0 deletions
diff --git a/js/src/fuzz-tests/differential-parsing.js b/js/src/fuzz-tests/differential-parsing.js
new file mode 100644
index 0000000000..1a61175721
--- /dev/null
+++ b/js/src/fuzz-tests/differential-parsing.js
@@ -0,0 +1,148 @@
+/* -*- 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 file is used to detect and find cases where the Visage's parser is
+// accepting more inputs than SpiderMonkey's parser.
+//
+// 1. Find new cases:
+//
+// To find new cases, we have to build with libFuzzer. The JS Shell can easily
+// be built with libFuzzer by adding --enable-fuzzing to the configure script
+// command line.
+//
+// Create a directory, and copy all test cases from the JS shell to this
+// directory:
+//
+// $ mkdir fuzzer-input
+// $ cd fuzzer-input
+// $ find ../ -name \*.js -print0 | xargs -I '{}' -0 -n1 cp '{}' $(pwd)
+//
+// Once the JS Shell is built, set the FUZZER environment variable to this
+// script location.
+//
+// $ FUZZER="./fuzz-tests/differential-parsing.js" build.dir/dist/bin/js -- \
+// -use_value_profile=1 -print_pcs=1 -timeout=5 -max_len=32 -only_ascii=1 \
+// ./fuzzer-input
+//
+// 2. Test a crashing test case:
+//
+// Once a new crashing test case is found, this script can be used to
+// reproduce the crashing conditions.
+//
+// To do so, you need a JS Shell and to load this script and use the testFile
+// function with the location of the crashing file.
+//
+// $ build.dir/dist/bin/js
+// js> load("./fuzz-tests/differential-parsing.js");
+// js> testFile("./crash-42");
+// Parse Script C++: fail
+// Parse Module C++: fail
+// Parse Script Rust: succeed
+// Parse Module Rust: fail
+// Hit MOZ_CRASH(Rust accept more than C++)
+//
+
+/* global crash, os, parse, timeout */
+
+// This global will hold the current fuzzing buffer for each iteration.
+var fuzzBuf;
+
+function timed(sec, f) {
+ // If the function `f` takes more than 3 seconds, then the evaluation ends
+ // prematurely and returns in libFuzzer handler without considering this
+ // test case as interesting.
+ timeout(sec, function() {
+ return false;
+ });
+ f();
+
+ // Remove the timeout handler, to not kill future executions.
+ timeout(-1);
+}
+
+var parseScriptCpp = { module: false, smoosh: false };
+var parseScriptRust = { module: false, smoosh: true };
+var parseModuleRust = { module: true, smoosh: true };
+var parseModuleCpp = { module: true, smoosh: false };
+function test(code, verbose = false) {
+ var isScriptCpp = false,
+ isModuleCpp = false,
+ isScriptRust = false,
+ isModuleRust = false;
+ try {
+ parse(code, parseScriptCpp);
+ isScriptCpp = true;
+ if (verbose) {
+ console.log("Parse Script C++: succeed");
+ }
+ } catch (exc) {
+ if (verbose) {
+ console.log("Parse Script C++: fail");
+ }
+ }
+ try {
+ parse(code, parseModuleCpp);
+ isModuleCpp = true;
+ if (verbose) {
+ console.log("Parse Module C++: succeed");
+ }
+ } catch (exc) {
+ if (verbose) {
+ console.log("Parse Module C++: fail");
+ }
+ }
+ try {
+ parse(code, parseScriptRust);
+ isScriptRust = true;
+ if (verbose) {
+ console.log("Parse Script Rust: succeed");
+ }
+ } catch (exc) {
+ if (verbose) {
+ console.log("Parse Script Rust: fail");
+ }
+ }
+ try {
+ parse(code, parseModuleRust);
+ isModuleRust = true;
+ if (verbose) {
+ console.log("Parse Module Rust: succeed");
+ }
+ } catch (exc) {
+ if (verbose) {
+ console.log("Parse Module Rust: fail");
+ }
+ }
+ if ((isScriptRust && !isScriptCpp) || (isModuleRust && !isModuleCpp)) {
+ crash("Rust accept more than C++");
+ }
+}
+
+function JSFuzzIterate() {
+ // This function is called per iteration. You must ensure that:
+ //
+ // 1) Each of your actions/decisions is only based on fuzzBuf,
+ // in particular not on Math.random(), Date/Time or other
+ // external inputs.
+ //
+ // 2) Your actions should be deterministic. The same fuzzBuf
+ // should always lead to the same set of actions/decisions.
+ //
+ // 3) You can modify the global where needed, but ensure that
+ // each iteration is isolated from one another by cleaning
+ // any modifications to the global after each iteration.
+ // In particular, iterations must not depend on or influence
+ // each other in any way (see also 1)).
+ //
+ // 4) You must catch all exceptions.
+ let code = String.fromCharCode(...fuzzBuf);
+ timed(3, _ => test(code));
+ return 0;
+}
+
+function testFile(file) {
+ let content = os.file.readFile(file);
+ test(content, true);
+}