From 16564a2fd81dded2f976692fd5dd1d555a80b798 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Fri, 18 Sep 2026 18:20:03 -0700 Subject: [PATCH] Add a wasm-embed tool The tool embeds a given sequence of Wasm modules in place of the Wasm modules already present in a given JS file. Alternatively, with the --extract option, it extracts the embedded modules from the JS file and writes them as standalone Wasm files. This replaces the embed_wasms.py and extract_wasms.py scripts, reusing the C++ embedded module parsing logic added for wasm-reduce --js. The differences in behavior from the replaced scripts are that the new tool 1) can accept .wat files as input, assembling them before embedding, and 2) does not modify the original source when extracting modules and does not rely on a sentinel placeholder to determine where to embed new modules. --- scripts/clusterfuzz/embed_wasms.py | 76 -------------- scripts/clusterfuzz/extract_wasms.py | 94 ----------------- scripts/fuzz_opt.py | 5 +- scripts/test/shared.py | 1 + scripts/update_help_checks.py | 3 +- src/tools/CMakeLists.txt | 1 + src/tools/wasm-embed.cpp | 151 +++++++++++++++++++++++++++ test/lit/help/wasm-embed.test | 27 +++++ test/lit/scripts/embed_wasms.lit | 25 ----- test/lit/scripts/extract_wasms.lit | 28 ----- test/lit/wasm-embed/embed.test | 48 +++++++++ test/lit/wasm-embed/extract.test | 28 +++++ test/unit/test_cluster_fuzz.py | 4 +- 13 files changed, 261 insertions(+), 230 deletions(-) delete mode 100644 scripts/clusterfuzz/embed_wasms.py delete mode 100644 scripts/clusterfuzz/extract_wasms.py create mode 100644 src/tools/wasm-embed.cpp create mode 100644 test/lit/help/wasm-embed.test delete mode 100644 test/lit/scripts/embed_wasms.lit delete mode 100644 test/lit/scripts/extract_wasms.lit create mode 100644 test/lit/wasm-embed/embed.test create mode 100644 test/lit/wasm-embed/extract.test diff --git a/scripts/clusterfuzz/embed_wasms.py b/scripts/clusterfuzz/embed_wasms.py deleted file mode 100644 index 17b4bcaf06d..00000000000 --- a/scripts/clusterfuzz/embed_wasms.py +++ /dev/null @@ -1,76 +0,0 @@ -# -# Copyright 2025 WebAssembly Community Group participants -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Reverse of extract_wasms.py. - -extract_wasms.py extracts wasm files from a JavaScript testcase (which has wasm -files embedded as arrays of numbers), and this script re-embeds them back. To -do so, we use the magic comments that the extractor uses: it replaces each -wasm array with - - 'undefined /* extracted wasm */' - -We simply replace those with the given wasm files, in JS format. - -For example, assume INFILE.js contains two wasm files. Then - - extract_wasms.py INFILE.js OUTFILE - -will emit - - OUTFILE.js, OUTFILE.0.wasm, OUTFILE.1.wasm - -We now have a JS file without the wasm (which includes the magic comments -mentioned before) and one binary wasm file for each wasm. We can now re-embed -them, creating a merged JS file containing JS + wasm, using - - embed_wasms.py OUTFILE.js OUTFILE.0.wasm OUTFILE.1.wasm MERGED.js - -The first argument is the input JS, then the wasm files, then the last argument -is the output JS. -""" - -import re -import sys - -in_js = sys.argv[1] -in_wasms = sys.argv[2:-1] -out_js = sys.argv[-1] - -with open(in_js) as f: - js = f.read() - -wasm_index = 0 - - -def replace_wasm(_text): - global wasm_index - wasm_file = in_wasms[wasm_index] - wasm_index += 1 - - with open(wasm_file, 'rb') as f: - wasm = f.read() - - bytes = [str(int(x)) for x in wasm] - bytes = ', '.join(bytes) - - return f'new Uint8Array([{bytes}])' - - -js = re.sub(r'undefined [/][*] extracted wasm [*][/]', replace_wasm, js) - -# Write out the new JS. -with open(out_js, 'w') as f: - f.write(js) diff --git a/scripts/clusterfuzz/extract_wasms.py b/scripts/clusterfuzz/extract_wasms.py deleted file mode 100644 index 2833305b92d..00000000000 --- a/scripts/clusterfuzz/extract_wasms.py +++ /dev/null @@ -1,94 +0,0 @@ -# -# Copyright 2024 WebAssembly Community Group participants -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Wasm extractor for testcases generated by the ClusterFuzz run.py script. - -This is general enough to also handle Fuzzilli output. - -Usage: - -extract_wasms.py INFILE.js OUTFILE - -That will find embedded wasm files in INFILE.js, of the form - - new Uint8Array([..wasm_contents..]); - -and extract them into OUTFILE.0.wasm, OUTFILE.1.wasm, etc. It also emits -OUTFILE.js which will no longer contain the embedded contents, after which the -script can be run as - - d8 OUTFILE.js -- OUTFILE.0.wasm - -That is, the embedded file can now be provided as a filename argument. -""" - -import re -import sys - -file_counter = 0 - - -def get_wasm_filename(): - global file_counter - file_counter += 1 - return f'{out}.{file_counter - 1}.wasm' - - -in_js = sys.argv[1] -out = sys.argv[2] - -with open(in_js) as f: - js = f.read() - - -def repl(match): - text = match.group(0) - - # We found something of the form - # - # new Uint8Array([..binary data as numbers..]); - # - # See if the numbers are the beginnings of a wasm file, "\0asm". If so, we - # assume it is wasm. (We are careful here because Fuzzilli output can - # contain normal JavaScript Typed Arrays, which we do not want to touch.) - numbers = match.groups()[0] - numbers = numbers.split(',') - - try: - # Handle both base 10 and 16 by passing in base 0. - parsed = [int(n, 0) for n in numbers] - binary = bytes(parsed) - except ValueError: - # Not wasm; return the existing text. - return text - - if binary[:4] != b'\0asm': - return text - - # It is wasm. Parse out the numbers into a binary wasm file. - with open(get_wasm_filename(), 'wb') as f: - f.write(binary) - - # Replace the Uint8Array with undefined + a comment. - return 'undefined /* extracted wasm */' - - -# Replace the wasm files and write them out. We investigate any new Uint8Array -# on an array of values like [100, 200] or [0x61, 0x6D, 0x6a] etc. -js = re.sub(r'new Uint8Array\(\[([\d,x a-fA-F]+)\]\)', repl, js) - -# Write out the new JS. -with open(f'{out}.js', 'w') as f: - f.write(js) diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index 67b00e7b94d..5b5b967897b 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -1863,10 +1863,7 @@ def handle_pair(self, input, before_wasm, after_wasm, opts): if output != IGNORE and INSTANTIATE_ERROR not in output: # Do the work to find if there were function exports: extract the # wasm from the JS, and process it. - run([sys.executable, - in_binaryen('scripts', 'clusterfuzz', 'extract_wasms.py'), - fuzz_file, - 'extracted']) + run([in_bin('wasm-embed'), '--extract', fuzz_file, 'extracted']) if get_exports('extracted.0.wasm', ['func']): assert FUZZ_EXEC_EXPORT_PREFIX in output diff --git a/scripts/test/shared.py b/scripts/test/shared.py index 0e65e159056..2041d6c59f7 100644 --- a/scripts/test/shared.py +++ b/scripts/test/shared.py @@ -270,6 +270,7 @@ def is_exe(fpath): WASM_CTOR_EVAL = [os.path.join(options.binaryen_bin, 'wasm-ctor-eval')] WASM_SHELL = [os.path.join(options.binaryen_bin, 'wasm-shell')] WASM_REDUCE = [os.path.join(options.binaryen_bin, 'wasm-reduce')] +WASM_EMBED = [os.path.join(options.binaryen_bin, 'wasm-embed')] WASM_METADCE = [os.path.join(options.binaryen_bin, 'wasm-metadce')] WASM_EMSCRIPTEN_FINALIZE = [os.path.join(options.binaryen_bin, 'wasm-emscripten-finalize')] diff --git a/scripts/update_help_checks.py b/scripts/update_help_checks.py index e7e3e0deb21..13680b88554 100755 --- a/scripts/update_help_checks.py +++ b/scripts/update_help_checks.py @@ -26,7 +26,8 @@ TOOLS = ['wasm-opt', 'wasm-as', 'wasm-dis', 'wasm2js', 'wasm-ctor-eval', 'wasm-shell', 'wasm-reduce', 'wasm-metadce', 'wasm-split', - 'wasm-fuzz-types', 'wasm-emscripten-finalize', 'wasm-merge'] + 'wasm-fuzz-types', 'wasm-emscripten-finalize', 'wasm-merge', + 'wasm-embed'] def main(): diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 4a24d506ec0..061a8e4747a 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -21,6 +21,7 @@ if(NOT BUILD_EMSCRIPTEN_TOOLS_ONLY) binaryen_add_executable(wasm-merge wasm-merge.cpp) binaryen_add_executable(wasm-fuzz-types "${fuzzing_SOURCES};wasm-fuzz-types.cpp") binaryen_add_executable(wasm-fuzz-lattices "${fuzzing_SOURCES};wasm-fuzz-lattices.cpp") + binaryen_add_executable(wasm-embed wasm-embed.cpp) add_subdirectory(wasm-reduce) endif() diff --git a/src/tools/wasm-embed.cpp b/src/tools/wasm-embed.cpp new file mode 100644 index 00000000000..d01a6e68363 --- /dev/null +++ b/src/tools/wasm-embed.cpp @@ -0,0 +1,151 @@ +/* + * Copyright 2026 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Embed Wasm binaries into a JS file, or extract embedded Wasm binaries from a +// JS file. +// + +#include +#include +#include + +#include "parsing.h" +#include "pass.h" +#include "support/command-line.h" +#include "support/file.h" +#include "support/js-embedded-module.h" +#include "support/utilities.h" +#include "wasm-io.h" +#include "wasm-validator.h" + +using namespace wasm; + +int main(int argc, const char* argv[]) { + const std::string WasmEmbedOption = "wasm-embed options"; + + bool extract = false; + std::string output; + std::vector positionals; + + Options options( + "wasm-embed", + "Embed Wasm binaries into a JS file, or extract embedded Wasm binaries " + "from a JS file"); + options + .add("--extract", + "-e", + "Extract embedded Wasm modules from the input JS file into " + ".0.wasm, .1.wasm, ...", + WasmEmbedOption, + Options::Arguments::Zero, + [&](Options* o, const std::string& argument) { extract = true; }) + .add("--output", + "-o", + "Output JS file (or output prefix when --extract is used)", + WasmEmbedOption, + Options::Arguments::One, + [&](Options* o, const std::string& argument) { output = argument; }) + .add_positional("INFILE.js [WASM_FILES...] [OUTFILE]", + Options::Arguments::N, + [&](Options* o, const std::string& argument) { + positionals.push_back(argument); + }); + options.parse(argc, argv); + + if (extract) { + std::string inJsFile; + if (output.empty()) { + if (positionals.size() != 2) { + Fatal() << "Expected input JS file and output prefix"; + } + inJsFile = positionals[0]; + output = positionals[1]; + } else { + if (positionals.size() != 1) { + Fatal() << "Expected a single input JS file when --output is specified"; + } + inJsFile = positionals[0]; + } + + auto js = read_file(inJsFile, Flags::Text); + auto modules = findEmbeddedModules(js); + for (size_t i = 0; i < modules.size(); ++i) { + write_file(output + "." + std::to_string(i) + ".wasm", modules[i].bytes); + } + flush_and_quick_exit(0); + } + + std::string inJsFile; + std::vector wasmFiles; + if (output.empty()) { + if (positionals.size() < 2) { + Fatal() << "Expected input JS file, wasm files, and output JS file"; + } + inJsFile = positionals.front(); + output = positionals.back(); + wasmFiles.assign(positionals.begin() + 1, positionals.end() - 1); + } else { + if (positionals.empty()) { + Fatal() << "Expected input JS file"; + } + inJsFile = positionals.front(); + wasmFiles.assign(positionals.begin() + 1, positionals.end()); + } + + auto js = read_file(inJsFile, Flags::Text); + auto existing = findEmbeddedModules(js); + if (existing.size() != wasmFiles.size()) { + Fatal() << "Number of embedded wasm modules in " << inJsFile << " (" + << existing.size() + << ") does not match number of provided wasm files (" + << wasmFiles.size() << ")"; + } + + for (size_t i = existing.size(); i > 0; --i) { + const auto& mod = existing[i - 1]; + const auto& wasmFile = wasmFiles[i - 1]; + auto bytes = read_file>(wasmFile, Flags::Binary); + bool isBinary = bytes.size() >= 4 && bytes[0] == '\0' && bytes[1] == 'a' && + bytes[2] == 's' && bytes[3] == 'm'; + + Module wasm; + wasm.features = FeatureSet::All; + try { + ModuleReader().readData(bytes, wasm); + } catch (ParseException& p) { + p.dump(std::cerr); + std::cerr << '\n'; + Fatal() << "error parsing wasm (" << wasmFile << ")"; + } + + if (!WasmValidator().validate(wasm)) { + Fatal() << "error validating module (" << wasmFile << ")"; + } + + if (!isBinary) { + PassOptions passOptions; + ModuleWriter writer(passOptions); + writer.setBinary(true); + writer.write(wasm, bytes); + } + + js.replace(mod.start, mod.end - mod.start, formatByteArray(bytes)); + } + + write_file(output, js); + flush_and_quick_exit(0); +} diff --git a/test/lit/help/wasm-embed.test b/test/lit/help/wasm-embed.test new file mode 100644 index 00000000000..7b0ce9aaae0 --- /dev/null +++ b/test/lit/help/wasm-embed.test @@ -0,0 +1,27 @@ +;; RUN: wasm-embed --help | filecheck %s +;; CHECK: ================================================================================ +;; CHECK-NEXT: wasm-embed INFILE.js [WASM_FILES...] [OUTFILE] +;; CHECK-EMPTY: +;; CHECK-NEXT: Embed Wasm binaries into a JS file, or extract embedded Wasm binaries from a JS +;; CHECK-NEXT: file +;; CHECK-NEXT: ================================================================================ +;; CHECK-EMPTY: +;; CHECK-EMPTY: +;; CHECK-NEXT: wasm-embed options: +;; CHECK-NEXT: ------------------- +;; CHECK-EMPTY: +;; CHECK-NEXT: --extract,-e Extract embedded Wasm modules from the input JS file into +;; CHECK-NEXT: .0.wasm, .1.wasm, ... +;; CHECK-EMPTY: +;; CHECK-NEXT: --output,-o Output JS file (or output prefix when --extract is used) +;; CHECK-EMPTY: +;; CHECK-EMPTY: +;; CHECK-NEXT: General options: +;; CHECK-NEXT: ---------------- +;; CHECK-EMPTY: +;; CHECK-NEXT: --version Output version information and exit +;; CHECK-EMPTY: +;; CHECK-NEXT: --help,-h Show this help message and exit +;; CHECK-EMPTY: +;; CHECK-NEXT: --debug,-d Print debug information to stderr +;; CHECK-EMPTY: diff --git a/test/lit/scripts/embed_wasms.lit b/test/lit/scripts/embed_wasms.lit deleted file mode 100644 index d5b579bac66..00000000000 --- a/test/lit/scripts/embed_wasms.lit +++ /dev/null @@ -1,25 +0,0 @@ -;; Test embedding wasm files into JS. - -;; Wasm files replace undefined + magical comments, like these: -;; RUN: echo "good1(undefined /* extracted wasm */);" > %t.js - -;; Slight changes mean we ignore the pattern. -;; RUN: echo "bad(undefinedey /* random stuff */);" >> %t.js - -;; Add a second valid one. -;; RUN: echo "good2(undefined /* extracted wasm */);" >> %t.js - -;; Generate two valid wasm files to embed. -;; RUN: echo "(module)" > %t.1.wat -;; RUN: echo "(module (func $foo))" > %t.2.wat - -;; RUN: wasm-as %t.1.wat -o %t.1.wasm -;; RUN: wasm-as %t.2.wat -o %t.2.wasm - -;; RUN: python %S/../../../scripts/clusterfuzz/embed_wasms.py %t.js %t.1.wasm %t.2.wasm %t.out.js -;; RUN: cat %t.out.js | filecheck %s -;; -;; CHECK: good1(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0])); -;; CHECK: bad(undefinedey -;; CHECK: good2(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0, 0, 3, 2, 1, 0, 10, 4, 1, 2, 0, 11])); - diff --git a/test/lit/scripts/extract_wasms.lit b/test/lit/scripts/extract_wasms.lit deleted file mode 100644 index 70cc59b4a59..00000000000 --- a/test/lit/scripts/extract_wasms.lit +++ /dev/null @@ -1,28 +0,0 @@ -;; Test extracting wasm files from JS. - -;; A proper wasm start sequence (\0asm), so we will extract it. -;; RUN: echo "good1(new Uint8Array([0x00, 0x61, 0x73, 0x6D, 0x01]));" > %t.js - -;; A difference in the second byte, so we won't. -;; RUN: echo "bad1(new Uint8Array([0x00, 0xff, 0x73, 0x6D, 0x01]));" >> %t.js - -;; The last byte is unparsable as an integer, so we won't. -;; RUN: echo "bad2(new Uint8Array([0x00, 0x61, 0x73, 0x6D, 6Dx0]));" >> %t.js - -;; This is not a Uint8Array, so we do nothing. -;; RUN: echo "bad3(new Uint16Array([0x00, 0x61, 0x73, 0x6D, 0x01]));" >> %t.js - -;; Another proper one. Note the second number is in base 10, which works too, -;; & there is various odd whitespace which we also ignore. -;; RUN: echo "good2(new Uint8Array([0x00,97, 0x73, 0x6D,0x01]));" >> %t.js - -;; RUN: python %S/../../../scripts/clusterfuzz/extract_wasms.py %t.js %t.out -;; RUN: cat %t.out.js | filecheck %s -;; -;; We extracted the good but not the bad. -;; CHECK: good1(undefined /* extracted wasm */) -;; CHECK: bad1(new Uint8Array -;; CHECK: bad2(new Uint8Array -;; CHECK: bad3(new Uint16Array -;; CHECK: good2(undefined /* extracted wasm */) - diff --git a/test/lit/wasm-embed/embed.test b/test/lit/wasm-embed/embed.test new file mode 100644 index 00000000000..f7b2eaefc73 --- /dev/null +++ b/test/lit/wasm-embed/embed.test @@ -0,0 +1,48 @@ +;; Test embedding wasm and wat files into JS by replacing existing embedded modules. + +;; Existing embedded modules will be replaced: +;; RUN: echo "good1(new Uint8Array([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2a]));" > %t.js + +;; Non-wasm arrays are ignored: +;; RUN: echo "bad(new Uint8Array([0x00, 0xff, 0x73, 0x6d, 0x01]));" >> %t.js + +;; Add a second valid embedded module without new Uint8Array: +;; RUN: echo "good2([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]);" >> %t.js + +;; Assemble %t.wat with -g so %t.wasm contains a name custom section that would +;; be stripped if the module were reserialized. Pass %t.wasm as the first input +;; (verifying original binary bytes are preserved) and %t.wat as the second +;; input (verifying WAT is converted to binary before embedding). +;; RUN: echo "(module (func $foo))" > %t.wat +;; RUN: wasm-as %t.wat -g -o %t.wasm + +;; RUN: wasm-embed %t.js %t.wasm %t.wat %t.out.js +;; RUN: cat %t.out.js | filecheck %s +;; +;; CHECK: good1(new Uint8Array([ +;; CHECK-NEXT: 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, +;; CHECK-NEXT: 0x01, 0x00, 0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b, 0x00, 0x0d, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x01, +;; CHECK-NEXT: 0x06, 0x01, 0x00, 0x03, 0x66, 0x6f, 0x6f +;; CHECK-NEXT: ])); +;; CHECK-NEXT: bad(new Uint8Array([0x00, 0xff, 0x73, 0x6d, 0x01])); +;; CHECK-NEXT: good2([ +;; CHECK-NEXT: 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, +;; CHECK-NEXT: 0x01, 0x00, 0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b +;; CHECK-NEXT: ]); + +;; Verify that invalid WAT text errors out: +;; RUN: echo "not a module" > %t.bad.wat +;; RUN: not wasm-embed %t.js %t.bad.wat %t.wat %t.out.js 2>&1 | filecheck %s --check-prefix=BAD-WAT +;; BAD-WAT: Fatal: 1:0: error: unrecognized module field + +;; Verify that malformed binary Wasm errors out: +;; RUN: printf '\x00asm\x01' > %t.bad.wasm +;; RUN: not wasm-embed %t.js %t.bad.wasm %t.wat %t.out.js 2>&1 | filecheck %s --check-prefix=BAD-WASM +;; BAD-WASM: Fatal: error parsing wasm + +;; Verify that WAT and binary Wasm modules failing WebAssembly validation error out: +;; RUN: echo "(module (func (result i32) (f32.const 0)))" > %t.invalid.wat +;; RUN: wasm-as %t.invalid.wat -v none -o %t.invalid.wasm +;; RUN: not wasm-embed %t.js %t.invalid.wat %t.wat %t.out.js 2>&1 | filecheck %s --check-prefix=INVALID-MOD +;; RUN: not wasm-embed %t.js %t.invalid.wasm %t.wat %t.out.js 2>&1 | filecheck %s --check-prefix=INVALID-MOD +;; INVALID-MOD: Fatal: error validating module diff --git a/test/lit/wasm-embed/extract.test b/test/lit/wasm-embed/extract.test new file mode 100644 index 00000000000..e7f7b29267b --- /dev/null +++ b/test/lit/wasm-embed/extract.test @@ -0,0 +1,28 @@ +;; Test extracting wasm files from JS. + +;; A proper wasm module (\0asm), so we will extract it as %t.out.0.wasm. +;; RUN: echo "good1(new Uint8Array([0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00]));" > %t.js + +;; A difference in the second byte, so we won't extract it. +;; RUN: echo "bad1(new Uint8Array([0x00, 0xff, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00]));" >> %t.js + +;; The last byte is unparsable as an integer, so we won't extract it. +;; RUN: echo "bad2(new Uint8Array([0x00, 0x61, 0x73, 0x6D, 6Dx0]));" >> %t.js + +;; Another proper one ((module (func))) with base 10 and odd whitespace, +;; extracted as %t.out.1.wasm. +;; RUN: echo "good2([0x00,97, 0x73, 0x6D,0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b]);" >> %t.js + +;; RUN: wasm-embed --extract %t.js %t.out +;; RUN: wasm-dis %t.out.0.wasm | filecheck %s --check-prefix=WASM0 +;; RUN: wasm-dis %t.out.1.wasm | filecheck %s --check-prefix=WASM1 +;; RUN: not wasm-dis %t.out.2.wasm + +;; WASM0: (module +;; WASM0-NEXT: ) + +;; WASM1: (module +;; WASM1-NEXT: (type $0 (func)) +;; WASM1-NEXT: (func $0 +;; WASM1-NEXT: ) +;; WASM1-NEXT: ) diff --git a/test/unit/test_cluster_fuzz.py b/test/unit/test_cluster_fuzz.py index 578ec2690a5..31d73f7bb1e 100644 --- a/test/unit/test_cluster_fuzz.py +++ b/test/unit/test_cluster_fuzz.py @@ -194,8 +194,8 @@ def test_file_contents(self): # stale files. for f in glob.glob('extracted*'): os.unlink(f) - extractor = shared.in_binaryen('scripts', 'clusterfuzz', 'extract_wasms.py') - subprocess.check_call([sys.executable, extractor, fuzz_file, 'extracted']) + subprocess.check_call( + shared.WASM_EMBED + ['--extract', fuzz_file, 'extracted']) # One wasm file must always exist, and must be valid. binary_file = 'extracted.0.wasm'