Skip to content

Commit 9137cbf

Browse files
authored
[Fuzzing] Add a script to embed wasm files into JS testcases (#7323)
This is the inverse of extract_wasms.py: the previous script extracted wasm files from JS, and this one can re-embed them back in. This can be useful when working with ClusterFuzz and Fuzzilli testcases.
1 parent 7fe07c0 commit 9137cbf

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

scripts/clusterfuzz/embed_wasms.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#
2+
# Copyright 2025 WebAssembly Community Group participants
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
'''
17+
Reverse script for extract_wasms.py: That one extracts wasm files from a
18+
JavaScript testcase (which has wasm files embedded as arrays of numbers), and
19+
this one re-embeds them back. To do so, we use the magic comments that the
20+
extractor uses: it replaces each wasm array with
21+
22+
'undefined /* extracted wasm */'
23+
24+
We simply replace those with the given wasm files, in JS format.
25+
26+
For example, assume INFILE.js contains two wasm files. Then
27+
28+
extract_wasms.py INFILE.js OUTFILE
29+
30+
will emit
31+
32+
OUTFILE.js, OUTFILE.0.wasm, OUTFILE.1.wasm
33+
34+
We now have a JS file without the wasm (which includes the magic comments
35+
mentioned before) and one binary wasm file for each wasm. We can now re-embed
36+
them, creating a merged JS file containing JS + wasm, using
37+
38+
embed_wasms.py OUTFILE.js OUTFILE.0.wasm OUTFILE.1.wasm MERGED.js
39+
40+
The first argument is the input JS, then the wasm files, then the last argument
41+
is the output JS.
42+
'''
43+
44+
import re
45+
import sys
46+
47+
in_js = sys.argv[1]
48+
in_wasms = sys.argv[2:-1]
49+
out_js = sys.argv[-1]
50+
51+
with open(in_js) as f:
52+
js = f.read()
53+
54+
wasm_index = 0
55+
56+
57+
def replace_wasm(text):
58+
global wasm_index
59+
wasm_file = in_wasms[wasm_index]
60+
wasm_index += 1
61+
62+
with open(wasm_file, 'rb') as f:
63+
wasm = f.read()
64+
65+
bytes = [str(int(x)) for x in wasm]
66+
bytes = ', '.join(bytes)
67+
68+
return f'new Uint8Array([{bytes}])'
69+
70+
71+
js = re.sub(r'undefined [/][*] extracted wasm [*][/]', replace_wasm, js)
72+
73+
# Write out the new JS.
74+
with open(out_js, 'w') as f:
75+
f.write(js)

test/lit/scripts/embed_wasms.lit

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
;; Test embedding wasm files into JS.
2+
3+
;; Wasm files replace undefined + magical comments, like these:
4+
;; RUN: echo "good1(undefined /* extracted wasm */);" > %t.js
5+
6+
;; Slight changes mean we ignore the pattern.
7+
;; RUN: echo "bad(undefinedey /* random stuff */);" >> %t.js
8+
9+
;; Add a second valid one.
10+
;; RUN: echo "good2(undefined /* extracted wasm */);" >> %t.js
11+
12+
;; Generate two valid wasm files to embed.
13+
;; RUN: echo "(module)" > %t.1.wat
14+
;; RUN: echo "(module (func $foo))" > %t.2.wat
15+
16+
;; RUN: wasm-as %t.1.wat -o %t.1.wasm
17+
;; RUN: wasm-as %t.2.wat -o %t.2.wasm
18+
19+
;; RUN: python %S/../../../scripts/clusterfuzz/embed_wasms.py %t.js %t.1.wasm %t.2.wasm %t.out.js
20+
;; RUN: cat %t.out.js | filecheck %s
21+
;;
22+
;; CHECK: good1(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0]));
23+
;; CHECK: bad(undefinedey
24+
;; 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]));
25+

0 commit comments

Comments
 (0)