diff options
author | Alon Zakai <azakai@google.com> | 2024-11-06 15:31:09 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-06 15:31:09 -0800 |
commit | 40210446937cbef7d73606e4331cb6a782e2a875 (patch) | |
tree | 6273041ace4186b577ca603631331c1a7b93c454 | |
parent | 92917c28ea6ef017e71a8a97eb364ed20bc52fe2 (diff) | |
download | binaryen-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-x | scripts/fuzz_opt.py | 34 |
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() |