summaryrefslogtreecommitdiff
path: root/scripts/fuzz_shell.js
Commit message (Collapse)AuthorAgeFilesLines
* [NFC] Refactor nice methods in fuzz_shell.js (#7096)Alon Zakai2024-11-201-55/+70
| | | | | | | | | | | | This mostly moves the code around and avoids some duplication. It also tracks the list of exports with both names and values, so that if we compile more than one module, we can still access exports from the previous. Also add a first test of running fuzz_shell.js in node. This does make build() append the exports, which was done before on the main module but not the second one. That only affects the wasm-split fuzzer, which is not active yet, so this is still NFC.
* Fuzzing: ClusterFuzz integration (#7079)Alon Zakai2024-11-191-3/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The main addition here is a bundle_clusterfuzz.py script which will package up the exact files that should be uploaded to ClusterFuzz. It also documents the process and bundling and testing. You can do bundle.py OUTPUT_FILE.tgz That bundles wasm-opt from ./bin., which is enough for local testing. For actually uploading to ClusterFuzz, we need a portable build, and @dschuff had the idea to reuse the emsdk build, which works nicely. Doing bundle.py OUTPUT_FILE.tgz --build-dir=/path/to/emsdk/upstream/ will bundle wasm-opt (+libs) from the emsdk. I verified that those builds work on ClusterFuzz. I added several forms of testing here. First, our main fuzzer fuzz_opt.py now has a ClusterFuzz testcase handler, which simulates a ClusterFuzz environment. Second, there are smoke tests that run in the unit test suite, and can also be run separately: python -m unittest test/unit/test_cluster_fuzz.py Those unit tests can also run on a given bundle, e.g. one created from an emsdk build, for testing right before upload: BINARYEN_CLUSTER_FUZZ_BUNDLE=/path/to/bundle.tgz python -m unittest test/unit/test_cluster_fuzz.py A third piece of testing is to add a --fuzz-passes test. That is a mode for -ttf (translate random data into a valid wasm fuzz testcase) that uses random data to pick and run a set of passes, to further shape the wasm. (--fuzz-passes had no previous testing, and this PR fixes it and tidies it up a little, adding some newer passes too). Otherwise this PR includes the key run.py script that is bundled and then executed by ClusterFuzz, basically a python script that runs wasm-opt -ttf [..] to generate testcases, sets up their JS, and emits them. fuzz_shell.js, which is the JS to execute testcases, will now check if it is provided binary data of a wasm file. If so, it does not read a wasm file from argv[1]. (This is needed because ClusterFuzz expects a single file for the testcase, so we make a JS file with bundled wasm inside it.)
* [EH] Fuzz calls from JS by calling wasm exports, sometimes catching (#7067)Alon Zakai2024-11-081-7/+68
| | | | | | | | | | | | | | | | This adds two new imports to fuzzer modules: * call-export, which gets an export index and calls it. * call-export-catch, which does the call in a try-catch, swallowing any error, and returning 1 if it saw an error. The former gives us calls back into the wasm, possibly making various trips between wasm and JS in interesting ways. The latter adds a try-catch which helps fuzz wasm EH. We do these calls using a wasm export index, i.e., the index in the list of exports. This is simple, but it does have the downside that it makes executing the wasm sensitive to changes in exports (e.g. wasm-merge adds more), which requires some handling in the fuzzer.
* [wasm64] Fuzzer: Fix table import operations on table64 (#7056)Alon Zakai2024-11-071-2/+13
| | | | The old code assumed the index was a JS number, but if the table has 64-bit indexes it must be a BigInt. Detect that and cast as needed.
* Fuzz the Table from JS (#7042)Alon Zakai2024-10-311-1/+9
| | | | | Continues the work from #7027 which added throwing from JS, this adds table get/set operations from JS, to further increase our coverage of Wasm/JS interactions (the table can be used from both sides).
* [EH] Fuzz throws from JS (#7027)Alon Zakai2024-10-231-0/+7
| | | | | | | | | | | We already generated (throw ..) instructions in wasm, but it makes sense to model throws from outside as well, as they cross the module boundary. This adds a new fuzzer import to the generated modules, "throw", that just does a throw from JS etc. Also be more precise about handling fuzzing-support imports in fuzz-exec: we now check that logging functions start with "log*" and error otherwise (this check is now needed given we have "throw", which is not logging). Also fix a minor issue with name conflicts for logging functions by using getValidFunctionName for them, both for logging and for throw.
* wasm-split: Add fuzzer support (#7014)Alon Zakai2024-10-181-35/+80
| | | | | | | | | | | | The support is added but not enabled as this is still finding bugs. The first part here is to add Split testcase handler to the fuzzer, which runs a wasm, then runs it again after splitting it and then linking it at runtime, and checking for different results. The second part is support for linking two modules at runtime in the fuzzer's JS code, that works in tandem with the first part. New options are added to load and link a second wasm, and to pick which exports to run.
* [Strings] Escape strings printed by fuzz-exec (#6441)Thomas Lively2024-03-261-3/+52
| | | | | | | | | | | Previously we printed strings as WTF-8 in the output of fuzz-exec, but this could produce invalid unicode output and did not make unprintable characters visible. Fix both these problems by escaping the output, using the JSON string escape procedure since the string to be escaped is WTF-16. Reimplement the same escaping procedure in fuzz_shell.js so that the way we print strings when running on a real JS engine matches the way we print them in our own fuzz-exec interpreter. Fixes #6435.
* Fuzzer: Standardize notation for exception prefixes (#6369)Alon Zakai2024-03-051-2/+2
| | | | | | | | | We had exception: in one and exception thrown: in another. Making those consistent allows fuzz_shell.js to print the exception after that prefix, which makes debugging easier sometimes. Also canonicalize tag names. Like funcref names, JS VMs print out the internal name, which can change after opts, so canonicalize it.
* Fuzzer: Fix BigInt printing (#6348)Alon Zakai2024-02-261-0/+4
| | | | Before this we only printed the type of a BigInt and not the value.
* Fuzzer: Allow using initial content with V8 (#6327)Alon Zakai2024-02-221-1/+4
| | | | | | | | | | | | | | | One problem was that spec testcases had exports with names that are not valid to write as JS exports.name. For example an export with a - in the name would end up as exports.foo-bar etc. Since #6310 that is fixed as we do not emit such JS (we use the generic fuzz_shell.js script which iterates over the keys in exports with exports[name]). Also fix a few trivial fuzzer issues that initial content uncovered: - Ignore a wat file with invalid utf-8. - Print string literals in the same way from JS as from C++. - Enable the stringref flag in V8. - Remove tag imports (the same as we do for global and function and other imports).
* Fuzzer: Add a pass to prune illegal imports and exports for JS (#6312)Alon Zakai2024-02-201-0/+5
| | | | | | | | | | | | | | | | | | We already have passes to legalize i64 imports and exports, which the fuzzer will run so that we can run wasm files in JS VMs. SIMD and multivalue also pose a problem as they trap on the boundary. In principle we could legalize them as well, but that is substantial effort, so instead just prune them: given a wasm module, remove any imports or exports that use SIMD or multivalue (or anything else that is not legal for JS). Running this in the fuzzer will allow us to not skip running v8 on any testcase we enable SIMD and multivalue for. (Multivalue is allowed in newer VMs, so that part of this PR could be removed eventually.) Also remove the limitation on running v8 with multimemory (v8 now supports that).
* Fuzzer: Remove --emit-js-shell logic and reuse fuzz_shell.js instead (#6310)Alon Zakai2024-02-201-13/+36
| | | | | | | | | | | | | | | | | | | | | | | | | We had two JS files that could run a wasm file for fuzzing purposes: * --emit-js-shell, which emitted a custom JS file that runs the wasm. * scripts/fuzz_shell.js, which was a generic file that did the same. Both of those load the wasm and then call the exports in order and print out logging as it goes of their return values (if any), exceptions, etc. Then the fuzzer compares that output to running the same wasm in another VM, etc. The difference is that one was custom for the wasm file, and one was generic. Aside from that they are similar and duplicated a bunch of code. This PR improves things by removing 1 and using 2 in all places, that is, we now use the generic file everywhere. I believe we added 1 because we thought a generic file can't do all the things we need, like know the order of exports and the types of return values, but in practice there are ways to do those things: The exports are in fact in the proper order (JS order of iteration is deterministic, thankfully), and for the type we don't want to print type internals anyhow since that would limit fuzzing --closed-world. We do need to be careful with types in JS (see notes in the PR about the type of null) but it's not too bad. As for the types of params, it's fine to pass in null for them all anyhow (null converts to a number or a reference without error).
* Fuzzer: Remove Asyncify integration (#6309)Alon Zakai2024-02-141-123/+0
| | | | | | | | | | | Fuzzing Asyncify has a significant cost both in terms of the complexity in the fuzzer and the slowness of the fuzzing. In practice it was useful years ago when Asyncify was written but hasn't found anything for a while, and Asyncify is really deprecated given JSPI. For all those reasons, remove it from the fuzzer. We do still have lots of normal coverage of asyncify in lit tests, unit tests, and the Emscripten test suite. Removing this will also make future improvements to the fuzzer simpler.
* Fuzz shell: Add a j2wasm import (#6296)Alon Zakai2024-02-121-0/+9
| | | | With this, the fuzz shell can run a hello world Java file compiled by j2wasm.
* Use more than a single wasm page in Asyncify fuzzing (#5597)Alon Zakai2023-03-221-1/+3
| | | | | I saw a testcase fail on the internal assertion of the buffer being too small. Enlarge it to use as much of the memory we have anyhow to reduce that risk (we can use 15 pages instead of 1, without changing anything else).
* Bail out of fuzz_shell.js if instantiation fails (#4873)Thomas Lively2022-08-041-2/+9
| | | | | | | | | Sometimes the fuzzer produces valid modules that trap during instantiation. When that happens, the JS harness used to run the fuzzer output in d8 would previously throw an error, creating spurious fuzzer failures on valid modules. Update fuzz_shell.js to catch and supress errors during instantiation (but not validation) to avoid these spurious failures. Fixes #4865.
* Asyncify fuzzing harness fix for growth (#3205)Alon Zakai2020-10-091-2/+9
| | | | | Fuzzing Asyncify on data with a memory growth showed that the harness did not handle a growth. When growth happens we must recreate the view. For simplicity, always refresh, in a location that dominates all the uses.
* Fuzz asyncify fuzzer: when no exported memory, skip (#2874)Alon Zakai2020-05-271-3/+4
| | | | We need the memory to be exported in order to read and write stuff for the asyncify data structure.
* Enable cross-VM fuzzing + related improvements to fuzz_opt.py (#2762)Alon Zakai2020-04-151-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The main benefit here is comparing VMs, instead of just comparing each VM to itself after opts. Comparing VMs is a little tricky since there is room for nondeterminism with how results are printed and other annoying things, which is why that didn't work well earlier. With this PR I can run 10's of thousands of iterations without finding any issues between v8 and the binaryen interpreter. That's after fixing the various issues over the last few days as found by this: #2760 #2757 #2750 #2752 Aside from that main benefit I ended up adding more improvements to make it practical to do all that testing: Randomize global fuzz settings like whether we allow NaNs and out-of-bounds memory accesses. (This was necessary here since we have to disable cross-VM comparisons if NaNs are enabled.) Better logging of statistics like how many times each handler was run. Remove redundant FuzzExecImmediately handler (looks like after past refactorings it was no longer adding any value). Deterministic testcase handling: if you run e.g. fuzz_opt.py 42 it will run one testcase and exactly the same one. If you run without an argument it will run forever until it fails, and if it fails, it prints out that ID so that you can easily reproduce it (I guess, on the same binaryen + same python, not sure how python's deterministic RNG changes between versions and builds). Upgrade to Python 3.
* Bysyncify => Asyncify (#2226)Alon Zakai2019-07-151-36/+36
| | | | | | | After some discussion this seems like a less confusing name: what the pass does is "asyncify" code, after all. The one downside is the name overlaps with the old emscripten "Asyncify" utility, which we'll need to clarify in the docs there. This keeps the old --bysyncify flag around for now, which is helpful for avoiding temporary breakage on CI as we move the emscripten side as well.
* Support wasm files without exported memory in scripts/fuzz_shell.js (#2210)Alon Zakai2019-07-091-1/+3
|
* Bysyncify: Fuzzing (#2192)Alon Zakai2019-07-011-0/+209
Gets fuzzing support for Bysyncify working. * Add the python to run the fuzzing on bysyncify. * Add a JS script to load and run a testcase with bysyncify support. The code has all the runtime support for sleep/resume etc., which it does on calls to imports at random in a deterministic manner. * Export memory from fuzzer so JS can access it. * Fix tiny builder bug with makeExport.