summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2024-11-06 15:31:09 -0800
committerGitHub <noreply@github.com>2024-11-06 15:31:09 -0800
commit40210446937cbef7d73606e4331cb6a782e2a875 (patch)
tree6273041ace4186b577ca603631331c1a7b93c454
parent92917c28ea6ef017e71a8a97eb364ed20bc52fe2 (diff)
downloadbinaryen-40210446937cbef7d73606e4331cb6a782e2a875.tar.gz
binaryen-40210446937cbef7d73606e4331cb6a782e2a875.tar.bz2
binaryen-40210446937cbef7d73606e4331cb6a782e2a875.zip
Fuzzer: Handle exported table for wasm-merge (#7055)
When fuzzing wasm-merge, we need to avoid the first module not having an exported table but the second having one, as the way the table operation imports work, they are sensitive to the existence of such an export, so just merging in such an export can alter behavior.
-rwxr-xr-xscripts/fuzz_opt.py34
1 files changed, 27 insertions, 7 deletions
diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py
index 3d4663501..2bf5cd820 100755
--- a/scripts/fuzz_opt.py
+++ b/scripts/fuzz_opt.py
@@ -1194,19 +1194,22 @@ def get_exports(wasm, kinds):
# given a wasm and a list of exports we want to keep, remove all other exports.
-def filter_exports(wasm, output, keep):
+# we also keep a list of default exports, unless that is overridden (overriding
+# it may lead to changes in behavior).
+def filter_exports(wasm, output, keep, keep_defaults=True):
# based on
# https://github.com/WebAssembly/binaryen/wiki/Pruning-unneeded-code-in-wasm-files-with-wasm-metadce#example-pruning-exports
# we append to keep; avoid modifying the object that was sent in.
keep = keep[:]
- # some exports must always be preserved, if they exist, like the table
- # (which can be called from JS imports for table operations).
- existing_exports = set(get_exports(wasm, ['func', 'table']))
- for export in ['table']:
- if export in existing_exports:
- keep.append(export)
+ if not keep_defaults:
+ # some exports must normally be preserved, if they exist, like the table
+ # (which can be called from JS imports for table operations).
+ existing_exports = set(get_exports(wasm, ['func', 'table']))
+ for export in ['table']:
+ if export in existing_exports:
+ keep.append(export)
# build json to represent the exports we want.
graph = [{
@@ -1369,6 +1372,23 @@ class Merge(TestCaseHandler):
second_wasm = abspath('second.wasm')
run([in_bin('wasm-opt'), second_input, '-ttf', '-o', second_wasm] + GEN_ARGS + FEATURE_OPTS)
+ # the second wasm file must not have an export that can influence our
+ # execution. the JS exports have that behavior, as when "table-set" is
+ # called it will look for the export "table" on which to operate, then
+ # imagine we lack that export in the first module but add it in the
+ # second, then code that failed before will now use the exported table
+ # from the second module (and maybe work). to avoid that, remove the
+ # table export, if it exists (and if the first module doesn't export
+ # it).
+ second_exports = get_exports(second_wasm, ['func', 'table'])
+ wasm_exports = get_exports(wasm, ['table'])
+ if 'table' in second_exports and 'table' not in wasm_exports:
+ filtered = [e for e in second_exports if e != 'table']
+ # note we override the set of default things to keep, as we want to
+ # remove the table export. doing so might change the behavior of
+ # second.wasm, but that is ok.
+ filter_exports(second_wasm, second_wasm, filtered, keep_defaults=False)
+
# sometimes also optimize the second module
if random.random() < 0.5:
opts = get_random_opts()