diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index 692d0c0746e..fa1275294f4 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -29,6 +29,7 @@ import contextlib import difflib +import functools import json import math import os @@ -1263,13 +1264,24 @@ def can_run_on_wasm(self, wasm): return all_disallowed(['exception-handling', 'simd', 'threads', 'tail-call', 'reference-types', 'multivalue', 'gc', 'multimemory', 'memory64', 'custom-descriptors', 'acquire-release-atomics', 'relaxed-atomics', 'wide-arithmetic']) +# Cache disassembled WAT strings by (wasm_bytes, tuple(FEATURE_OPTS), wasm). +# Within a single test_one() iteration, multiple handlers (e.g. TrapsNeverHappen, +# CtorEval, Merge) inspect the same wasm binary via wasm_notices_export_changes, +# get_exports, or filter_exports. Including the binary bytes in the key ensures +# reused filenames like a.wasm invalidate when overwritten. +@functools.lru_cache(maxsize=16) +def _disassemble_wat(_binary, feature_opts, wasm): + return run([in_bin('wasm-dis'), wasm] + list(feature_opts)) + + # Returns the wat for a wasm file. If it is already wat, it just returns that # (useful when reducing with --text, where wasm files are really wat files). def get_wat(wasm): - binary = open(wasm, 'rb').read() + with open(wasm, 'rb') as f: + binary = f.read() if binary.startswith(b'(module'): return binary.decode(encoding='utf-8') - return run([in_bin('wasm-dis'), wasm] + FEATURE_OPTS) + return _disassemble_wat(binary, tuple(FEATURE_OPTS), wasm) # given a wasm, find all the exports of particular kinds (for example, kinds @@ -1327,6 +1339,14 @@ def filter_exports(wasm, output, keep, keep_defaults=True): # Check if a wasm file would notice normally-unnoticeable changes to exports, # such as removing one that is not called. def wasm_notices_export_changes(wasm): + with open(wasm, 'rb') as f: + binary = f.read() + # Check the binary directly for the import strings before disassembling and + # doing full checks below. This saves the cost of running wasm-dis in the + # common case. + if b'call-export' not in binary and b'table-' not in binary: + return False + wat = get_wat(wasm) if '(import "fuzzing-support" "call-export' in wat: