Skip to content

Commit 45c25a5

Browse files
committed
[wasm2js] Enforce declared memory maximum in __wasm_memory_grow
The generated __wasm_memory_grow JS function only checked against the absolute wasm32 page limit (65536) but did not enforce the module's declared memory maximum. For example, a module with (memory 1 2) would allow growing beyond 2 pages in the JS output. Add a check against wasm->memories[0]->max when the memory has a declared maximum, generating an additional (newPages <= max) condition in the grow function's guard.
1 parent fd5e86e commit 45c25a5

6 files changed

Lines changed: 197 additions & 11 deletions

File tree

src/wasm2js.h

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,17 +2531,25 @@ void Wasm2JSBuilder::addMemoryGrowFunc(Ref ast, Module* wasm) {
25312531
JsType::JS_INT));
25322532

25332533
Ref block = ValueBuilder::makeBlock();
2534-
memoryGrowFunc[3]->push_back(ValueBuilder::makeIf(
2535-
ValueBuilder::makeBinary(
2536-
ValueBuilder::makeBinary(ValueBuilder::makeName(IString("oldPages")),
2537-
LT,
2538-
ValueBuilder::makeName(IString("newPages"))),
2534+
Ref condition = ValueBuilder::makeBinary(
2535+
ValueBuilder::makeBinary(ValueBuilder::makeName(IString("oldPages")),
2536+
LT,
2537+
ValueBuilder::makeName(IString("newPages"))),
2538+
IString("&&"),
2539+
ValueBuilder::makeBinary(ValueBuilder::makeName(IString("newPages")),
2540+
LT,
2541+
ValueBuilder::makeInt(Memory::kMaxSize32)));
2542+
// Also enforce the module's declared memory maximum, if one exists.
2543+
if (!wasm->memories.empty() && wasm->memories[0]->hasMax()) {
2544+
condition = ValueBuilder::makeBinary(
2545+
condition,
25392546
IString("&&"),
25402547
ValueBuilder::makeBinary(ValueBuilder::makeName(IString("newPages")),
2541-
LT,
2542-
ValueBuilder::makeInt(Memory::kMaxSize32))),
2543-
block,
2544-
NULL));
2548+
LE,
2549+
ValueBuilder::makeInt(static_cast<uint32_t>(
2550+
wasm->memories[0]->max.addr))));
2551+
}
2552+
memoryGrowFunc[3]->push_back(ValueBuilder::makeIf(condition, block, NULL));
25452553

25462554
Ref newBuffer = ValueBuilder::makeVar();
25472555
ValueBuilder::appendToBlock(block, newBuffer);

test/wasm2js/emscripten-grow-yes.2asm.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ function asmFunc(imports) {
6464
pagesToAdd = pagesToAdd | 0;
6565
var oldPages = __wasm_memory_size() | 0;
6666
var newPages = oldPages + pagesToAdd | 0;
67-
if ((oldPages < newPages) && (newPages < 65536)) {
67+
if ((oldPages < newPages) && (newPages < 65536) && (newPages <= 1024)) {
6868
var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
6969
var newHEAP8 = new Int8Array(newBuffer);
7070
newHEAP8.set(HEAP8);

test/wasm2js/emscripten-grow-yes.2asm.js.opt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ function asmFunc(imports) {
6464
pagesToAdd = pagesToAdd | 0;
6565
var oldPages = __wasm_memory_size() | 0;
6666
var newPages = oldPages + pagesToAdd | 0;
67-
if ((oldPages < newPages) && (newPages < 65536)) {
67+
if ((oldPages < newPages) && (newPages < 65536) && (newPages <= 1024)) {
6868
var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
6969
var newHEAP8 = new Int8Array(newBuffer);
7070
newHEAP8.set(HEAP8);
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
function asmFunc(imports) {
3+
var buffer = new ArrayBuffer(65536);
4+
var HEAP8 = new Int8Array(buffer);
5+
var HEAP16 = new Int16Array(buffer);
6+
var HEAP32 = new Int32Array(buffer);
7+
var HEAPU8 = new Uint8Array(buffer);
8+
var HEAPU16 = new Uint16Array(buffer);
9+
var HEAPU32 = new Uint32Array(buffer);
10+
var HEAPF32 = new Float32Array(buffer);
11+
var HEAPF64 = new Float64Array(buffer);
12+
var Math_imul = Math.imul;
13+
var Math_fround = Math.fround;
14+
var Math_abs = Math.abs;
15+
var Math_clz32 = Math.clz32;
16+
var Math_min = Math.min;
17+
var Math_max = Math.max;
18+
var Math_floor = Math.floor;
19+
var Math_ceil = Math.ceil;
20+
var Math_trunc = Math.trunc;
21+
var Math_sqrt = Math.sqrt;
22+
function grow($0) {
23+
$0 = $0 | 0;
24+
return __wasm_memory_grow($0 | 0) | 0;
25+
}
26+
27+
function size() {
28+
return __wasm_memory_size() | 0;
29+
}
30+
31+
function __wasm_memory_size() {
32+
return buffer.byteLength / 65536 | 0;
33+
}
34+
35+
function __wasm_memory_grow(pagesToAdd) {
36+
pagesToAdd = pagesToAdd | 0;
37+
var oldPages = __wasm_memory_size() | 0;
38+
var newPages = oldPages + pagesToAdd | 0;
39+
if ((oldPages < newPages) && (newPages < 65536) && (newPages <= 2)) {
40+
var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
41+
var newHEAP8 = new Int8Array(newBuffer);
42+
newHEAP8.set(HEAP8);
43+
HEAP8 = new Int8Array(newBuffer);
44+
HEAP16 = new Int16Array(newBuffer);
45+
HEAP32 = new Int32Array(newBuffer);
46+
HEAPU8 = new Uint8Array(newBuffer);
47+
HEAPU16 = new Uint16Array(newBuffer);
48+
HEAPU32 = new Uint32Array(newBuffer);
49+
HEAPF32 = new Float32Array(newBuffer);
50+
HEAPF64 = new Float64Array(newBuffer);
51+
buffer = newBuffer;
52+
}
53+
return oldPages;
54+
}
55+
56+
return {
57+
"memory": Object.create(Object.prototype, {
58+
"grow": {
59+
"value": __wasm_memory_grow
60+
},
61+
"buffer": {
62+
"get": function () {
63+
return buffer;
64+
}
65+
66+
}
67+
}),
68+
"grow": grow,
69+
"size": size
70+
};
71+
}
72+
73+
var retasmFunc = asmFunc({
74+
});
75+
export var memory = retasmFunc.memory;
76+
export var grow = retasmFunc.grow;
77+
export var size = retasmFunc.size;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
function asmFunc(imports) {
3+
var buffer = new ArrayBuffer(65536);
4+
var HEAP8 = new Int8Array(buffer);
5+
var HEAP16 = new Int16Array(buffer);
6+
var HEAP32 = new Int32Array(buffer);
7+
var HEAPU8 = new Uint8Array(buffer);
8+
var HEAPU16 = new Uint16Array(buffer);
9+
var HEAPU32 = new Uint32Array(buffer);
10+
var HEAPF32 = new Float32Array(buffer);
11+
var HEAPF64 = new Float64Array(buffer);
12+
var Math_imul = Math.imul;
13+
var Math_fround = Math.fround;
14+
var Math_abs = Math.abs;
15+
var Math_clz32 = Math.clz32;
16+
var Math_min = Math.min;
17+
var Math_max = Math.max;
18+
var Math_floor = Math.floor;
19+
var Math_ceil = Math.ceil;
20+
var Math_trunc = Math.trunc;
21+
var Math_sqrt = Math.sqrt;
22+
function grow($0) {
23+
$0 = $0 | 0;
24+
return __wasm_memory_grow($0 | 0) | 0;
25+
}
26+
27+
function size() {
28+
return __wasm_memory_size() | 0;
29+
}
30+
31+
function __wasm_memory_size() {
32+
return buffer.byteLength / 65536 | 0;
33+
}
34+
35+
function __wasm_memory_grow(pagesToAdd) {
36+
pagesToAdd = pagesToAdd | 0;
37+
var oldPages = __wasm_memory_size() | 0;
38+
var newPages = oldPages + pagesToAdd | 0;
39+
if ((oldPages < newPages) && (newPages < 65536) && (newPages <= 2)) {
40+
var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
41+
var newHEAP8 = new Int8Array(newBuffer);
42+
newHEAP8.set(HEAP8);
43+
HEAP8 = new Int8Array(newBuffer);
44+
HEAP16 = new Int16Array(newBuffer);
45+
HEAP32 = new Int32Array(newBuffer);
46+
HEAPU8 = new Uint8Array(newBuffer);
47+
HEAPU16 = new Uint16Array(newBuffer);
48+
HEAPU32 = new Uint32Array(newBuffer);
49+
HEAPF32 = new Float32Array(newBuffer);
50+
HEAPF64 = new Float64Array(newBuffer);
51+
buffer = newBuffer;
52+
}
53+
return oldPages;
54+
}
55+
56+
return {
57+
"memory": Object.create(Object.prototype, {
58+
"grow": {
59+
"value": __wasm_memory_grow
60+
},
61+
"buffer": {
62+
"get": function () {
63+
return buffer;
64+
}
65+
66+
}
67+
}),
68+
"grow": grow,
69+
"size": size
70+
};
71+
}
72+
73+
var retasmFunc = asmFunc({
74+
});
75+
export var memory = retasmFunc.memory;
76+
export var grow = retasmFunc.grow;
77+
export var size = retasmFunc.size;

test/wasm2js/grow-memory-max.wast

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
(module
2+
(memory $0 1 2)
3+
(export "memory" (memory $0))
4+
(export "grow" (func $grow))
5+
(export "size" (func $size))
6+
7+
(func $grow (param i32) (result i32)
8+
(memory.grow (local.get 0))
9+
)
10+
11+
(func $size (result i32)
12+
(memory.size)
13+
)
14+
)
15+
16+
;; The initial size is 1 page, max is 2 pages.
17+
;; Growing by 1 should succeed (1+1=2 <= max).
18+
(assert_return (invoke "size") (i32.const 1))
19+
(assert_return (invoke "grow" (i32.const 1)) (i32.const 1))
20+
(assert_return (invoke "size") (i32.const 2))
21+
;; Growing by 1 more should fail (2+1=3 > max).
22+
;; The size should remain at 2.
23+
(assert_return (invoke "grow" (i32.const 1)) (i32.const 2))
24+
(assert_return (invoke "size") (i32.const 2))

0 commit comments

Comments
 (0)