From ec099ecbd9ddcaeb0f575fcb399f4823b608c1ad Mon Sep 17 00:00:00 2001 From: Alexandre Poirot Date: Tue, 25 Jun 2024 22:15:10 +0000 Subject: [PATCH] Bug 1903980 - [devtools] Better handle short lived iframes. r=devtools-reviewers,nchevobbe WindowGlobalTarget actors are currently being destroyed via the docshell listeners registered by the WindowGlobalTargetActor class (_watchDocShells). This is a bit unexpected as the WindowGlobal Watcher Class is meant to handle the lifecycle (creation and destruction) of these actors. On top of that, this docshell listener code (_watchDocShells) isn't really meant to be executed. It's main goal is to implement the non-EFT(EveryFrameTarget) codepath, where the WindowGlobalTarget actor may be focusing on more than one WindowGlobal/document instance. The situation here is that this code throws on creation as well as destruction, leading to a broken target actor still registered in TargetRegistry/ContentProcessWatcherRegistry. Differential Revision: https://phabricator.services.mozilla.com/D214755 --- devtools/server/actors/targets/window-global.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/devtools/server/actors/targets/window-global.js b/devtools/server/actors/targets/window-global.js index ea3813795da7..6fa405ae6077 100644 --- a/devtools/server/actors/targets/window-global.js +++ b/devtools/server/actors/targets/window-global.js @@ -868,6 +868,13 @@ class WindowGlobalTargetActor extends BaseTargetActor { return; } + // This method is called asynchronously and the document may have been destroyed in the meantime. + // In such case, automatically destroy the target actor. + if (this.docShell.isBeingDestroyed()) { + this.destroy(); + return; + } + // In child processes, we watch all docshells living in the process. Services.obs.addObserver(this, "webnavigation-create"); Services.obs.addObserver(this, "webnavigation-destroy"); @@ -1743,6 +1750,12 @@ class DebuggerProgressListener { } unwatch(docShell) { + // If the docshell is being destroyed, we won't be able to retrieve its related window object, + // which is the key ingredient for all cleanup operations done in this method. + if (docShell.isBeingDestroyed()) { + return; + } + const docShellWindow = docShell.domWindow; if (!this._watchedDocShells.has(docShellWindow)) { return;