From ede665570359e025226d7debeb9458258a415c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Thu, 7 May 2026 12:42:54 +0200 Subject: [PATCH 1/2] Avoid stringifying the whole typed array contents during parsing. `String(arbitraryFormat)` was meant to detect ArrayBuffers from different realms, but when the input is already a Uint8Array, it serializes all byte values as a comma-separated string, which allocates hundreds of megabytes for large profiles. Switch to `Object.prototype.toString.call` which returns the correct `[object ArrayBuffer]` tag cross-realm without touching the array contents. --- src/profile-logic/process-profile.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/profile-logic/process-profile.ts b/src/profile-logic/process-profile.ts index 709b3c048e..8a89feae17 100644 --- a/src/profile-logic/process-profile.ts +++ b/src/profile-logic/process-profile.ts @@ -2005,10 +2005,12 @@ export async function unserializeProfileOfArbitraryFormat( upgradeInfo: ProfileUpgradeInfo = {} ): Promise { try { - // We used to use `instanceof ArrayBuffer`, but this doesn't work when the - // object is constructed from an ArrayBuffer in a different context... which - // happens in our tests. - if (String(arbitraryFormat) === '[object ArrayBuffer]') { + // We use Object.prototype.toString instead of `instanceof ArrayBuffer` + // because instanceof doesn't work cross-realm (e.g. in tests), and we + // can't use String() since that serializes the full contents of a Uint8Array. + if ( + Object.prototype.toString.call(arbitraryFormat) === '[object ArrayBuffer]' + ) { const arrayBuffer = arbitraryFormat as ArrayBuffer; arbitraryFormat = new Uint8Array(arrayBuffer); } From 5783a76e263a5bab516d5fa56c2dc9cb07557a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Thu, 7 May 2026 13:08:57 +0200 Subject: [PATCH 2/2] Extract zip file entries as ArrayBuffer instead of Uint8Array This is not strictly necessary after we changed the `String()` inside `unserializeProfileOfArbitraryFormat`. But this is more correct, so it's better to keep change it. --- src/actions/zipped-profiles.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/zipped-profiles.ts b/src/actions/zipped-profiles.ts index acde01eee1..5353348dba 100644 --- a/src/actions/zipped-profiles.ts +++ b/src/actions/zipped-profiles.ts @@ -57,7 +57,7 @@ export function viewProfileFromZip( try { // Attempt to unserialize the profile. const profile = await unserializeProfileOfArbitraryFormat( - await file.async('uint8array'), + await file.async('arraybuffer'), pathInZipFile );