commit f9df4b9ecac27120498993b2e4e7099394e78785
parent 7950242da0f65154aeeed52e1a18866ce56ef730
Author: Asumu Takikawa <asumu@igalia.com>
Date: Mon, 8 Dec 2025 16:02:53 +0000
Bug 1977854 - Wasm custom page sizes part 4: add import check for page size r=rhunt,bvisness
Differential Revision: https://phabricator.services.mozilla.com/D267332
Diffstat:
5 files changed, 108 insertions(+), 0 deletions(-)
diff --git a/js/public/friend/ErrorNumbers.msg b/js/public/friend/ErrorNumbers.msg
@@ -439,6 +439,7 @@ MSG_DEF(JSMSG_WASM_BAD_TAG_SIG, 2, JSEXN_WASMLINKERROR, "imported tag '{0
MSG_DEF(JSMSG_WASM_BAD_IMP_ADDRESS, 2, JSEXN_WASMLINKERROR, "imported {0} with incompatible address type {1}")
MSG_DEF(JSMSG_WASM_BAD_IMP_SIZE, 1, JSEXN_WASMLINKERROR, "imported {0} with incompatible size")
MSG_DEF(JSMSG_WASM_BAD_IMP_MAX, 1, JSEXN_WASMLINKERROR, "imported {0} with incompatible maximum size")
+MSG_DEF(JSMSG_WASM_BAD_IMP_PAGE_SIZE, 0, JSEXN_WASMLINKERROR, "imported memory with incompatible page size")
MSG_DEF(JSMSG_WASM_IMP_SHARED_REQD, 0, JSEXN_WASMLINKERROR, "imported unshared memory but shared required")
MSG_DEF(JSMSG_WASM_IMP_SHARED_BANNED, 0, JSEXN_WASMLINKERROR, "imported shared memory but unshared required")
MSG_DEF(JSMSG_WASM_NO_SHMEM_LINK, 0, JSEXN_WASMLINKERROR, "shared memory is disabled")
diff --git a/js/src/jit-test/tests/wasm/custom-page-sizes/js-api.js b/js/src/jit-test/tests/wasm/custom-page-sizes/js-api.js
@@ -0,0 +1,78 @@
+// |jit-test| skip-if: !wasmCustomPageSizesEnabled()
+
+load(libdir + "wasm-binary.js");
+
+{
+ let instance = wasmEvalText(`(module
+ (memory (export "mem") 0 1 (pagesize 1))
+ )
+ `);
+
+ assertErrorMessage(
+ () => wasmEvalText(`(module
+ (memory (import "m" "mem") 0 1 (pagesize 65536))
+ )
+ `, { m: { mem: instance.exports.mem } }),
+ WebAssembly.LinkError,
+ /imported memory with incompatible page size/
+ )
+}
+
+// Test against explicit page size in the binary encoding.
+{
+ let instance = wasmEvalBinary(
+ moduleWithSections([ {name:memoryId, body:[0x01, 0x08, 0x00, 0x10]},
+ exportSection([ {name: "mem", memIndex: 0} ]) ])
+ );
+
+ assertErrorMessage(
+ () => wasmEvalText(`(module
+ (memory (import "m" "mem") 0 1 (pagesize 1))
+ )
+ `, { m: { mem: instance.exports.mem } }),
+ WebAssembly.LinkError,
+ /imported memory with incompatible page size/
+ )
+}
+
+// Test against default page size in the binary encoding.
+{
+ let instance = wasmEvalBinary(
+ moduleWithSections([ {name:memoryId, body:[0x01, 0x01, 0x00, 0x01]},
+ exportSection([ {name: "mem", memIndex: 0} ]) ])
+ );
+
+ assertErrorMessage(
+ () => wasmEvalText(`(module
+ (memory (import "m" "mem") 0 1 (pagesize 1))
+ )
+ `, { m: { mem: instance.exports.mem } }),
+ WebAssembly.LinkError,
+ /imported memory with incompatible page size/
+ )
+}
+
+// Valid cases
+{
+ let instance = wasmEvalText(`(module
+ (memory (export "mem") 0 1 (pagesize 1))
+ )
+ `);
+
+ wasmEvalText(`(module
+ (memory (import "m" "mem") 0 1 (pagesize 1))
+ )
+ `, { m: { mem: instance.exports.mem } });
+}
+
+{
+ let instance = wasmEvalText(`(module
+ (memory (export "mem") 0 1)
+ )
+ `);
+
+ wasmEvalText(`(module
+ (memory (import "m" "mem") 0 1 (pagesize 65536))
+ )
+ `, { m: { mem: instance.exports.mem } });
+}
diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp
@@ -2626,6 +2626,13 @@ size_t WasmMemoryObject::boundsCheckLimit() const {
return limit;
}
+wasm::PageSize WasmMemoryObject::pageSize() const {
+ if (isShared()) {
+ return sharedArrayRawBuffer()->wasmPageSize();
+ }
+ return buffer().wasmPageSize();
+}
+
bool WasmMemoryObject::addMovingGrowObserver(JSContext* cx,
WasmInstanceObject* instance) {
MOZ_ASSERT(movingGrowable());
diff --git a/js/src/wasm/WasmJS.h b/js/src/wasm/WasmJS.h
@@ -319,6 +319,7 @@ class WasmMemoryObject : public NativeObject {
bool isHuge() const;
bool movingGrowable() const;
size_t boundsCheckLimit() const;
+ wasm::PageSize pageSize() const;
// If isShared() is true then obtain the underlying buffer object.
WasmSharedArrayRawBuffer* sharedArrayRawBuffer() const;
diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp
@@ -494,6 +494,19 @@ static bool CheckSharing(JSContext* cx, bool declaredShared, bool isShared) {
return true;
}
+#ifdef ENABLE_WASM_CUSTOM_PAGE_SIZES
+static bool CheckPageSize(JSContext* cx, PageSize declaredPageSize,
+ PageSize actualPageSize) {
+ if (declaredPageSize != actualPageSize) {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
+ JSMSG_WASM_BAD_IMP_PAGE_SIZE);
+ return false;
+ }
+
+ return true;
+}
+#endif
+
// asm.js module instantiation supplies its own buffer, but for wasm, create and
// initialize the buffer if one is requested. Either way, the buffer is wrapped
// in a WebAssembly.Memory object which is what the Instance stores.
@@ -518,6 +531,14 @@ bool Module::instantiateMemories(
return false;
}
+#ifdef ENABLE_WASM_CUSTOM_PAGE_SIZES
+ // Page size needs to be checked first because comparisons between
+ // incompatible page sizes are invalid in CheckLimits.
+ if (!CheckPageSize(cx, desc.pageSize(), memory->pageSize())) {
+ return false;
+ }
+#endif
+
if (!CheckLimits(cx, desc.initialPages(), desc.maximumPages(),
/* defaultMax */
MaxMemoryPages(desc.addressType(), desc.pageSize()),