From 6a0d7ac3af7a37c018196e86913382983fd40d9e Mon Sep 17 00:00:00 2001 From: Zachary Whitley Date: Fri, 29 May 2026 16:04:43 -0400 Subject: [PATCH 1/2] fix(p2-shim): coerce browser file read bounds to numbers wasi-filesystem read takes filesize (u64) arguments, which the canonical-ABI binding passes as BigInt. Uint8Array.slice rejects BigInt and throws "Cannot convert a BigInt value to a number" on the first read against any file in the browser implementation: TypeError: Cannot convert a BigInt value to a number at Uint8Array.slice () at Descriptor.read (preview2-shim/lib/browser/filesystem.js:191) Coerce both arguments to Number on entry. Safe up to Number.MAX_SAFE_INTEGER bytes (~9 PB), well above any practical browser use. Signed-off-by: Zachary Whitley --- packages/preview2-shim/lib/browser/filesystem.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/preview2-shim/lib/browser/filesystem.js b/packages/preview2-shim/lib/browser/filesystem.js index 6c585ac1b..6bf819130 100644 --- a/packages/preview2-shim/lib/browser/filesystem.js +++ b/packages/preview2-shim/lib/browser/filesystem.js @@ -188,7 +188,9 @@ class Descriptor { read(length, offset) { const source = getSource(this.#entry); - return [source.slice(offset, offset + length), offset + length >= source.byteLength]; + const off = typeof offset === "bigint" ? Number(offset) : offset; + const len = typeof length === "bigint" ? Number(length) : length; + return [source.slice(off, off + len), off + len >= source.byteLength]; } write(buffer, offset) { From 03aac3722e64e50bd861bc9fbaa75b7f753ab960 Mon Sep 17 00:00:00 2001 From: Victor Adossi Date: Mon, 1 Jun 2026 16:23:42 +0900 Subject: [PATCH 2/2] chore(p2-shim): add helper function for coercing read args --- .../preview2-shim/lib/browser/filesystem.js | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/preview2-shim/lib/browser/filesystem.js b/packages/preview2-shim/lib/browser/filesystem.js index 6bf819130..5827b8955 100644 --- a/packages/preview2-shim/lib/browser/filesystem.js +++ b/packages/preview2-shim/lib/browser/filesystem.js @@ -43,6 +43,22 @@ const timeZero = { nanoseconds: 0, }; +/** Coerce the given object to a safe integer */ +function coerceToSafeIntegerNumber(obj) { + let n; + if (typeof obj === "number") { + n = obj; + } else if (typeof obj == "bigint") { + n = Number(obj); + } else { + throw new TypeError(`unexpected non-numeric type: ${obj}`); + } + if (n > Number.MAX_SAFE_INTEGER) { + throw new TypeError(`excessively large number: ${n}`); + } + return n; +} + function getChildEntry(parentEntry, subpath, openFlags) { if (subpath === "." && _rootPreopen && descriptorGetEntry(_rootPreopen[0]) === parentEntry) { subpath = _getCwd(); @@ -188,8 +204,8 @@ class Descriptor { read(length, offset) { const source = getSource(this.#entry); - const off = typeof offset === "bigint" ? Number(offset) : offset; - const len = typeof length === "bigint" ? Number(length) : length; + const off = coerceToSafeIntegerNumber(offset); + const len = coerceToSafeIntegerNumber(length); return [source.slice(off, off + len), off + len >= source.byteLength]; }