fix: hook requestWindow via prototype to avoid instantiating DocumentPictureInPicture#171
Draft
MajorLift wants to merge 1 commit into
Draft
Conversation
5 tasks
pull Bot
pushed a commit
to Reality2byte/metamask-extension
that referenced
this pull request
Jul 10, 2026
…ctureInPicture` instantiation in Snow hook cp-13.39.2 (MetaMask#44352) ## **Motivation** On Firefox, every closed MetaMask window (popup, notification, home) is retained in memory ([MetaMask#42891](MetaMask#42891) and recent internal reports). - **Rate:** ~70 detached window entries (~105MB, fresh test wallet) per popup open/close, linear with use. 30 cycles leave **3.56GB** (13.37.0) / **3.31GB** (13.38.1) of detached documents, surviving forced GC. State-heavy wallets multiply every retained document. - **Mechanism** (heap-graph traced, intervention-tested): Snow's picture-in-picture hook reads `win?.documentPictureInPicture?.requestWindow` in every window. The read lazily instantiates a per-window `DocumentPictureInPicture`, and Firefox's cycle collector fails to break the instance's preserved-wrapper cycle after window close, pinning the entire realm. - **Why now:** Firefox shipped the API in 151 (May 2026). The April-2023 hook was dormant until users auto-updated. The collection failure itself is a Gecko defect (upstream filing in progress; prior art: [Bugzilla 1902438](https://bugzilla.mozilla.org/show_bug.cgi?id=1902438)), but this fix does not depend on Mozilla. ## **Description** Applies the upstream Snow fix ([LavaMoat/snow#171](LavaMoat/snow#171)) as a Yarn patch: the hook moves from the per-window instance to `DocumentPictureInPicture.prototype`, reached through the interface object, which does not invoke the instance-creating getter. - Call semantics unchanged: instance lookup falls through to the patched prototype, `this` stays the instance, same wrapped native. Snow's PiP realm monitoring is preserved. - The patch covers `snow.prod.js` and `snow.js` in addition to `src/request.js`: the extension consumes Snow's prebuilt bundle as a LavaMoat static shim (`LavamoatPlugin`), and webpack never processes `@lavamoat/snow/**`. - **Interim:** remove this patch when `@lavamoat/snow` is bumped to a release containing the upstream fix. The bump is the removal trigger. ## **Cherry-pick candidacy** - Affected population: every Firefox user on 151+ (effectively the whole Firefox base via auto-update). Reproduces from a fresh wallet in five popup opens. No workaround short of a browser restart. - Proposed: next RC, with a hotfix on the current production line worth considering. - Snow is security-team-owned. Their sign-off on shipping a patched Snow is part of this review. ## **Verification** | Check | Result | |---|---| | Intervention: official 13.37.0 artifact, only this hook changed, 30 cycles | **+2,100 docs (3.35GB) → -13 (1.6MB total)**. Hook is the sole delta, so this is also the causal proof | | This PR's CI artifact (`d4dd55f`), probed directly | Patched hook present; 5 cycles: +7 KB-scale entries (1.1MB) vs +345 docs (+534MB) stock | | Field | Original reporter confirms the leak is gone on this PR's CI build | | Independent repro | Manual steps + automated probe: https://github.com/MajorLift/snow/tree/verification/pip-realm-leak/verification | ## **Related issues** Fixes: MetaMask#42891 ## **Manual testing steps** 1. Install this PR's Firefox build (metamaskbot comment) in a fresh profile via `about:debugging` → Load Temporary Add-on. Onboard with a test SRP. 2. Confirm the fix is live: extension console → `DocumentPictureInPicture.prototype.requestWindow.name` → `"open"` (stock: `"requestWindow"`). 3. Open/close the popup five times, visiting activity or a swap view on a few opens. 4. `about:memory` → Minimize memory usage → Measure → filter `detached`: no `moz-extension` UI-document cohorts (stock: ~70 entries / ~105MB per cycle). ## **Screenshots/Recordings** Heap-graph traces, memory reports, and retaining-path analysis: see the verification bundle above. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. CHANGELOG entry: Fixed a memory leak on Firefox where closed MetaMask windows were retained in memory, growing extension memory use with every popup open
runway-github Bot
added a commit
to MetaMask/metamask-extension
that referenced
this pull request
Jul 13, 2026
…entPictureInPicture` instantiation in Snow hook cp-13.39.2 (#44352) ## **Motivation** On Firefox, every closed MetaMask window (popup, notification, home) is retained in memory ([#42891](#42891) and recent internal reports). - **Rate:** ~70 detached window entries (~105MB, fresh test wallet) per popup open/close, linear with use. 30 cycles leave **3.56GB** (13.37.0) / **3.31GB** (13.38.1) of detached documents, surviving forced GC. State-heavy wallets multiply every retained document. - **Mechanism** (heap-graph traced, intervention-tested): Snow's picture-in-picture hook reads `win?.documentPictureInPicture?.requestWindow` in every window. The read lazily instantiates a per-window `DocumentPictureInPicture`, and Firefox's cycle collector fails to break the instance's preserved-wrapper cycle after window close, pinning the entire realm. - **Why now:** Firefox shipped the API in 151 (May 2026). The April-2023 hook was dormant until users auto-updated. The collection failure itself is a Gecko defect (upstream filing in progress; prior art: [Bugzilla 1902438](https://bugzilla.mozilla.org/show_bug.cgi?id=1902438)), but this fix does not depend on Mozilla. ## **Description** Applies the upstream Snow fix ([LavaMoat/snow#171](LavaMoat/snow#171)) as a Yarn patch: the hook moves from the per-window instance to `DocumentPictureInPicture.prototype`, reached through the interface object, which does not invoke the instance-creating getter. - Call semantics unchanged: instance lookup falls through to the patched prototype, `this` stays the instance, same wrapped native. Snow's PiP realm monitoring is preserved. - The patch covers `snow.prod.js` and `snow.js` in addition to `src/request.js`: the extension consumes Snow's prebuilt bundle as a LavaMoat static shim (`LavamoatPlugin`), and webpack never processes `@lavamoat/snow/**`. - **Interim:** remove this patch when `@lavamoat/snow` is bumped to a release containing the upstream fix. The bump is the removal trigger. ## **Cherry-pick candidacy** - Affected population: every Firefox user on 151+ (effectively the whole Firefox base via auto-update). Reproduces from a fresh wallet in five popup opens. No workaround short of a browser restart. - Proposed: next RC, with a hotfix on the current production line worth considering. - Snow is security-team-owned. Their sign-off on shipping a patched Snow is part of this review. ## **Verification** | Check | Result | |---|---| | Intervention: official 13.37.0 artifact, only this hook changed, 30 cycles | **+2,100 docs (3.35GB) → -13 (1.6MB total)**. Hook is the sole delta, so this is also the causal proof | | This PR's CI artifact (`d4dd55f`), probed directly | Patched hook present; 5 cycles: +7 KB-scale entries (1.1MB) vs +345 docs (+534MB) stock | | Field | Original reporter confirms the leak is gone on this PR's CI build | | Independent repro | Manual steps + automated probe: https://github.com/MajorLift/snow/tree/verification/pip-realm-leak/verification | ## **Related issues** Fixes: #42891 ## **Manual testing steps** 1. Install this PR's Firefox build (metamaskbot comment) in a fresh profile via `about:debugging` → Load Temporary Add-on. Onboard with a test SRP. 2. Confirm the fix is live: extension console → `DocumentPictureInPicture.prototype.requestWindow.name` → `"open"` (stock: `"requestWindow"`). 3. Open/close the popup five times, visiting activity or a swap view on a few opens. 4. `about:memory` → Minimize memory usage → Measure → filter `detached`: no `moz-extension` UI-document cohorts (stock: ~70 entries / ~105MB per cycle). ## **Screenshots/Recordings** Heap-graph traces, memory reports, and retaining-path analysis: see the verification bundle above. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. CHANGELOG entry: Fixed a memory leak on Firefox where closed MetaMask windows were retained in memory, growing extension memory use with every popup open
runway-github Bot
added a commit
to MetaMask/metamask-extension
that referenced
this pull request
Jul 13, 2026
…entPictureInPicture` instantiation in Snow hook cp-13.39.2 (#44352) ## **Motivation** On Firefox, every closed MetaMask window (popup, notification, home) is retained in memory ([#42891](#42891) and recent internal reports). - **Rate:** ~70 detached window entries (~105MB, fresh test wallet) per popup open/close, linear with use. 30 cycles leave **3.56GB** (13.37.0) / **3.31GB** (13.38.1) of detached documents, surviving forced GC. State-heavy wallets multiply every retained document. - **Mechanism** (heap-graph traced, intervention-tested): Snow's picture-in-picture hook reads `win?.documentPictureInPicture?.requestWindow` in every window. The read lazily instantiates a per-window `DocumentPictureInPicture`, and Firefox's cycle collector fails to break the instance's preserved-wrapper cycle after window close, pinning the entire realm. - **Why now:** Firefox shipped the API in 151 (May 2026). The April-2023 hook was dormant until users auto-updated. The collection failure itself is a Gecko defect (upstream filing in progress; prior art: [Bugzilla 1902438](https://bugzilla.mozilla.org/show_bug.cgi?id=1902438)), but this fix does not depend on Mozilla. ## **Description** Applies the upstream Snow fix ([LavaMoat/snow#171](LavaMoat/snow#171)) as a Yarn patch: the hook moves from the per-window instance to `DocumentPictureInPicture.prototype`, reached through the interface object, which does not invoke the instance-creating getter. - Call semantics unchanged: instance lookup falls through to the patched prototype, `this` stays the instance, same wrapped native. Snow's PiP realm monitoring is preserved. - The patch covers `snow.prod.js` and `snow.js` in addition to `src/request.js`: the extension consumes Snow's prebuilt bundle as a LavaMoat static shim (`LavamoatPlugin`), and webpack never processes `@lavamoat/snow/**`. - **Interim:** remove this patch when `@lavamoat/snow` is bumped to a release containing the upstream fix. The bump is the removal trigger. ## **Cherry-pick candidacy** - Affected population: every Firefox user on 151+ (effectively the whole Firefox base via auto-update). Reproduces from a fresh wallet in five popup opens. No workaround short of a browser restart. - Proposed: next RC, with a hotfix on the current production line worth considering. - Snow is security-team-owned. Their sign-off on shipping a patched Snow is part of this review. ## **Verification** | Check | Result | |---|---| | Intervention: official 13.37.0 artifact, only this hook changed, 30 cycles | **+2,100 docs (3.35GB) → -13 (1.6MB total)**. Hook is the sole delta, so this is also the causal proof | | This PR's CI artifact (`d4dd55f`), probed directly | Patched hook present; 5 cycles: +7 KB-scale entries (1.1MB) vs +345 docs (+534MB) stock | | Field | Original reporter confirms the leak is gone on this PR's CI build | | Independent repro | Manual steps + automated probe: https://github.com/MajorLift/snow/tree/verification/pip-realm-leak/verification | ## **Related issues** Fixes: #42891 ## **Manual testing steps** 1. Install this PR's Firefox build (metamaskbot comment) in a fresh profile via `about:debugging` → Load Temporary Add-on. Onboard with a test SRP. 2. Confirm the fix is live: extension console → `DocumentPictureInPicture.prototype.requestWindow.name` → `"open"` (stock: `"requestWindow"`). 3. Open/close the popup five times, visiting activity or a swap view on a few opens. 4. `about:memory` → Minimize memory usage → Measure → filter `detached`: no `moz-extension` UI-document cohorts (stock: ~70 entries / ~105MB per cycle). ## **Screenshots/Recordings** Heap-graph traces, memory reports, and retaining-path analysis: see the verification bundle above. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. CHANGELOG entry: Fixed a memory leak on Firefox where closed MetaMask windows were retained in memory, growing extension memory use with every popup open
runway-github Bot
pushed a commit
to MetaMask/metamask-extension
that referenced
this pull request
Jul 13, 2026
… leak by avoiding `DocumentPictureInPicture` instantiation in Snow hook cp-13.39.2 (#44352) ## **Motivation** On Firefox, every closed MetaMask window (popup, notification, home) is retained in memory ([#42891](#42891) and recent internal reports). - **Rate:** ~70 detached window entries (~105MB, fresh test wallet) per popup open/close, linear with use. 30 cycles leave **3.56GB** (13.37.0) / **3.31GB** (13.38.1) of detached documents, surviving forced GC. State-heavy wallets multiply every retained document. - **Mechanism** (heap-graph traced, intervention-tested): Snow's picture-in-picture hook reads `win?.documentPictureInPicture?.requestWindow` in every window. The read lazily instantiates a per-window `DocumentPictureInPicture`, and Firefox's cycle collector fails to break the instance's preserved-wrapper cycle after window close, pinning the entire realm. - **Why now:** Firefox shipped the API in 151 (May 2026). The April-2023 hook was dormant until users auto-updated. The collection failure itself is a Gecko defect (upstream filing in progress; prior art: [Bugzilla 1902438](https://bugzilla.mozilla.org/show_bug.cgi?id=1902438)), but this fix does not depend on Mozilla. ## **Description** Applies the upstream Snow fix ([LavaMoat/snow#171](LavaMoat/snow#171)) as a Yarn patch: the hook moves from the per-window instance to `DocumentPictureInPicture.prototype`, reached through the interface object, which does not invoke the instance-creating getter. - Call semantics unchanged: instance lookup falls through to the patched prototype, `this` stays the instance, same wrapped native. Snow's PiP realm monitoring is preserved. - The patch covers `snow.prod.js` and `snow.js` in addition to `src/request.js`: the extension consumes Snow's prebuilt bundle as a LavaMoat static shim (`LavamoatPlugin`), and webpack never processes `@lavamoat/snow/**`. - **Interim:** remove this patch when `@lavamoat/snow` is bumped to a release containing the upstream fix. The bump is the removal trigger. ## **Cherry-pick candidacy** - Affected population: every Firefox user on 151+ (effectively the whole Firefox base via auto-update). Reproduces from a fresh wallet in five popup opens. No workaround short of a browser restart. - Proposed: next RC, with a hotfix on the current production line worth considering. - Snow is security-team-owned. Their sign-off on shipping a patched Snow is part of this review. ## **Verification** | Check | Result | |---|---| | Intervention: official 13.37.0 artifact, only this hook changed, 30 cycles | **+2,100 docs (3.35GB) → -13 (1.6MB total)**. Hook is the sole delta, so this is also the causal proof | | This PR's CI artifact (`d4dd55f`), probed directly | Patched hook present; 5 cycles: +7 KB-scale entries (1.1MB) vs +345 docs (+534MB) stock | | Field | Original reporter confirms the leak is gone on this PR's CI build | | Independent repro | Manual steps + automated probe: https://github.com/MajorLift/snow/tree/verification/pip-realm-leak/verification | ## **Related issues** Fixes: #42891 ## **Manual testing steps** 1. Install this PR's Firefox build (metamaskbot comment) in a fresh profile via `about:debugging` → Load Temporary Add-on. Onboard with a test SRP. 2. Confirm the fix is live: extension console → `DocumentPictureInPicture.prototype.requestWindow.name` → `"open"` (stock: `"requestWindow"`). 3. Open/close the popup five times, visiting activity or a swap view on a few opens. 4. `about:memory` → Minimize memory usage → Measure → filter `detached`: no `moz-extension` UI-document cohorts (stock: ~70 entries / ~105MB per cycle). ## **Screenshots/Recordings** Heap-graph traces, memory reports, and retaining-path analysis: see the verification bundle above. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. CHANGELOG entry: Fixed a memory leak on Firefox where closed MetaMask windows were retained in memory, growing extension memory use with every popup open
Gudahtt
pushed a commit
to MetaMask/metamask-extension
that referenced
this pull request
Jul 13, 2026
… leak by avoiding `DocumentPictureInPicture` instantiation in Snow hook cp-13.39.2 (#44401) - fix: Fix Firefox detatched-window memory leak by avoiding `DocumentPictureInPicture` instantiation in Snow hook cp-13.39.2 (#44352) ## **Motivation** On Firefox, every closed MetaMask window (popup, notification, home) is retained in memory ([#42891](#42891) and recent internal reports). - **Rate:** ~70 detached window entries (~105MB, fresh test wallet) per popup open/close, linear with use. 30 cycles leave **3.56GB** (13.37.0) / **3.31GB** (13.38.1) of detached documents, surviving forced GC. State-heavy wallets multiply every retained document. - **Mechanism** (heap-graph traced, intervention-tested): Snow's picture-in-picture hook reads `win?.documentPictureInPicture?.requestWindow` in every window. The read lazily instantiates a per-window `DocumentPictureInPicture`, and Firefox's cycle collector fails to break the instance's preserved-wrapper cycle after window close, pinning the entire realm. - **Why now:** Firefox shipped the API in 151 (May 2026). The April-2023 hook was dormant until users auto-updated. The collection failure itself is a Gecko defect (upstream filing in progress; prior art: [Bugzilla 1902438](https://bugzilla.mozilla.org/show_bug.cgi?id=1902438)), but this fix does not depend on Mozilla. ## **Description** Applies the upstream Snow fix ([LavaMoat/snow#171](LavaMoat/snow#171)) as a Yarn patch: the hook moves from the per-window instance to `DocumentPictureInPicture.prototype`, reached through the interface object, which does not invoke the instance-creating getter. - Call semantics unchanged: instance lookup falls through to the patched prototype, `this` stays the instance, same wrapped native. Snow's PiP realm monitoring is preserved. - The patch covers `snow.prod.js` and `snow.js` in addition to `src/request.js`: the extension consumes Snow's prebuilt bundle as a LavaMoat static shim (`LavamoatPlugin`), and webpack never processes `@lavamoat/snow/**`. - **Interim:** remove this patch when `@lavamoat/snow` is bumped to a release containing the upstream fix. The bump is the removal trigger. ## **Cherry-pick candidacy** - Affected population: every Firefox user on 151+ (effectively the whole Firefox base via auto-update). Reproduces from a fresh wallet in five popup opens. No workaround short of a browser restart. - Proposed: next RC, with a hotfix on the current production line worth considering. - Snow is security-team-owned. Their sign-off on shipping a patched Snow is part of this review. ## **Verification** | Check | Result | |---|---| | Intervention: official 13.37.0 artifact, only this hook changed, 30 cycles | **+2,100 docs (3.35GB) → -13 (1.6MB total)**. Hook is the sole delta, so this is also the causal proof | | This PR's CI artifact (`d4dd55f`), probed directly | Patched hook present; 5 cycles: +7 KB-scale entries (1.1MB) vs +345 docs (+534MB) stock | | Field | Original reporter confirms the leak is gone on this PR's CI build | | Independent repro | Manual steps + automated probe: https://github.com/MajorLift/snow/tree/verification/pip-realm-leak/verification | ## **Related issues** Fixes: #42891 ## **Manual testing steps** 1. Install this PR's Firefox build (metamaskbot comment) in a fresh profile via `about:debugging` → Load Temporary Add-on. Onboard with a test SRP. 2. Confirm the fix is live: extension console → `DocumentPictureInPicture.prototype.requestWindow.name` → `"open"` (stock: `"requestWindow"`). 3. Open/close the popup five times, visiting activity or a swap view on a few opens. 4. `about:memory` → Minimize memory usage → Measure → filter `detached`: no `moz-extension` UI-document cohorts (stock: ~70 entries / ~105MB per cycle). ## **Screenshots/Recordings** Heap-graph traces, memory reports, and retaining-path analysis: see the verification bundle above. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. CHANGELOG entry: Fixed a memory leak on Firefox where closed MetaMask windows were retained in memory, growing extension memory use with every popup open [942441b](942441b) Co-authored-by: Jongsun Suh <jongsun.suh@icloud.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
hookRequest's guard readswin?.documentPictureInPicture?.requestWindow.documentPictureInPictureis a lazily instantiated WebIDL attribute, so the guard itself creates a per-windowDocumentPictureInPictureinstance in every window Snow protects, whether or not the API is ever used.On Firefox, which shipped the API in Firefox 151 (May 2026), the created instance's preserved JS wrapper acts as a black GC root that the cycle collector fails to break after the window closes, pinning the closed window's entire realm (document, React tree, application state). In the MetaMask extension this retains every closed UI window: measured ~70 detached window entries (~105MB on a fresh wallet) per popup open/close on official builds, reaching 3.5GB after 30 cycles (MetaMask/metamask-extension#42891). Dev builds, which do not run Snow, retain zero under the same protocol. The onset matches Firefox 151's rollout: this hook dates to April 2023 and was dormant on Firefox until the API shipped.
The retaining path (two independent windows traced via CC/GC heap logs and
find_roots.py):The collection failure itself is a Gecko defect (related family: Bugzilla 1902438) and is being filed upstream separately. This change removes the instantiation regardless, which prevents the leak on current Firefox releases.
Description
This commit moves the
requestWindowhook from the per-window instance toDocumentPictureInPicture.prototype, reached through the interface object, which does not invoke the instance-creating getter.Call semantics are unchanged: instance method lookup falls through to the patched prototype,
thisremains the instance at call time, and the wrapped native is the same function object previously found via the instance.hookDocumentPictureInPicturealready operated on interface prototypes. Behavior on browsers without the API is unchanged (the guard returns early on a missing interface object, without touching the lazy attribute).Verification
Existing suites should pass unchanged (no behavioral difference for API users). In the MetaMask extension context, an automated probe (headless Firefox 152, official production builds, forced GC/CC before every reading) shows the leak at ~70 detached window entries per popup cycle with the instance hook; the acceptance criterion for this fix is zero net detached documents over 30 cycles on a build carrying it. Happy to share the probe and heap-log traces.