Skip to content

Commit 9dfd3d9

Browse files
authored
Fuzzing: Fix fuzz_shell.js on exports whose name is an integer (#7205)
JS sorts such indexes to the start of wasm.exports, but we want the order in the wasm, so get the proper ordering using WebAssembly.Module.exports.
1 parent 1c38766 commit 9dfd3d9

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed

scripts/fuzz_shell.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,13 +350,20 @@ function build(binary) {
350350
quit();
351351
}
352352

353-
// Update the exports. Note that this adds onto |exports|, |exportList|,
353+
// Update the exports. Note that this adds onto |exports| and |exportList|,
354354
// which is intentional: if we build another wasm, or build this one more
355355
// than once, we want to be able to call them all, so we unify all their
356356
// exports. (We do trample in |exports| when keys are equal - basically this
357357
// is a single global namespace - but |exportList| is appended to, so we do
358358
// keep the ability to call anything that was ever exported.)
359-
for (var key in instance.exports) {
359+
//
360+
// Note we do not iterate on instance.exports: the order there is not
361+
// necessarily the order in the wasm (which is what wasm-opt --fuzz-exec uses,
362+
// for example), because of JS object iteration rules (numbers are considered
363+
// "array indexes" and appear first,
364+
// https://tc39.es/ecma262/#sec-ordinaryownpropertykeys).
365+
for (var e of WebAssembly.Module.exports(module)) {
366+
var key = e.name;
360367
var value = instance.exports[key];
361368
value = wrapExportForJSPI(value);
362369
exports[key] = value;

scripts/wasm2js.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ var WebAssembly = {
6767
info['env']['__tempMemory__'] = 0; // risky!
6868
// This will be replaced by the actual wasm2js code.
6969
var exports = instantiate(info, wasmMemory);
70+
71+
// Save the exports on the module object, so that
72+
// WebAssembly.Module.exports() works. Ideally we would do this in
73+
// WebAssembly.Module(), but we don't know the exports at that point - all
74+
// the actual work happens in Instance(), here. In practice this is enough
75+
// as calls to WebAssembly.Module.exports() from the fuzzer happen after
76+
// instantiation.
77+
module.exports = exports;
78+
7079
return {
7180
'exports': exports
7281
};
@@ -83,6 +92,15 @@ var WebAssembly = {
8392
}
8493
};
8594

95+
// Add the exports() API on top of the Module constructor.
96+
WebAssembly.Module.exports = (module) => {
97+
var ret = [];
98+
for (var key in module.exports) {
99+
ret.push({ name: key });
100+
}
101+
return ret;
102+
};
103+
86104
var tempRet0 = 0;
87105

88106
var env = {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
;; Test that numeric exports appear in the right position. The JS rules
2+
;; affecting the order of instance.exports can be confusing, and we want the
3+
;; actual order in the wasm.
4+
5+
(module
6+
(func $a (export "a") (result i32)
7+
(i32.const 10)
8+
)
9+
10+
(func $0 (export "0") (result i32)
11+
(i32.const 20)
12+
)
13+
14+
(func $c (export "c") (result i32)
15+
(i32.const 30)
16+
)
17+
)
18+
19+
;; Run in wasm-opt and in node to see they agree.
20+
;; RUN: wasm-opt %s -o %t.wasm -q --fuzz-exec-before | filecheck %s
21+
;; RUN: node %S/../../../scripts/fuzz_shell.js %t.wasm | filecheck %s
22+
;;
23+
;; CHECK: [fuzz-exec] calling a
24+
;; CHECK: [fuzz-exec] note result: a => 10
25+
;; CHECK: [fuzz-exec] calling 0
26+
;; CHECK: [fuzz-exec] note result: 0 => 20
27+
;; CHECK: [fuzz-exec] calling c
28+
;; CHECK: [fuzz-exec] note result: c => 30
29+

0 commit comments

Comments
 (0)