Closed Bug 1694400 Opened 4 years ago Closed 4 years ago

Deleting a node in a same-process frame and navigating will freeze the content process

Categories

(DevTools :: General, defect, P2)

Firefox 86
defect

Tracking

(firefox-esr78 unaffected, firefox86 wontfix, firefox87 wontfix, firefox88 fixed)

RESOLVED FIXED
88 Branch
Tracking Status
firefox-esr78 --- unaffected
firefox86 --- wontfix
firefox87 --- wontfix
firefox88 --- fixed

People

(Reporter: mcccs, Assigned: jdescottes)

References

(Regression)

Details

(Keywords: regression)

Attachments

(2 files)

Steps to reproduce:

  • Open the HTML file below
  • Right click on the Google logo
  • Choose "Inspect Element"
  • Hit backspace once to remove the frontmost div
  • Right click on the Google logo again
  • Choose "View Image"

Kill the content process or Firefox won't quit.

<html><head></head><body>
<iframe style="width:100%;height:100%" srcdoc="<!doctype html>
<html>
<head></head>
<body>
<iframe srcdoc='<!doctype html><html><head></head><body style=width:1000px;height:1500px;margin:0>
<div>
<img style=position:absolute;top:0;left:0 src=&quot;https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png&quot;>
</div>
                  
</body></html>'  width=100% height=100% frameborder=0></iframe>
<div style='position:absolute;top:0;bottom:0;left:0;right:0;background-color:rgba(0,0,0,0)'></div>

</body>
</html>
"></iframe>
</body></html>
Product: Firefox → DevTools
Attached file test_image.html
Status: UNCONFIRMED → NEW
Ever confirmed: true
Flags: needinfo?(jdescottes)

Thanks for filing, and adding an example.

I reduced the STRs a bit:

  • open a page with a same-process iframe
  • delete an element in the iframe using the inspector
  • try to navigate to a new URL

The issue will not be triggered if the deleted element is in a remote frame.
It seems linked to nodes retained by the devtools server. Before deleting a node we first "retain" it : https://searchfox.org/mozilla-central/rev/df23c6e58c6be1eb8399e475878f73d4867bef87/devtools/client/inspector/markup/markup.js#1287

On the server this will simply set the node.retained flag to true on the node actor. This will trigger some additional processing when unloading the frame, especially a call to _childOfWindow. This method seems completely buggy and I this must have been broken for a very long time:

  _childOfWindow: function(window, domNode) {
    let win = nodeDocument(domNode).defaultView;
    while (win) {
      if (win === window) {
        return true;
      }
      win = getFrameElement(win);
    }
    return false;
  },

getFrameElement returns a <frame> element, not a window object. And if you look at the implementation of getFrameElement:

const getFrameElement = win => {
  const isTopWindow = win && DevToolsUtils.getTopWindow(win) === win;
  return isTopWindow ? null : win.browsingContext.embedderElement;
};

If win here is actually a frame element, win.browsingContext.embedderElement will just return the same element (because the browsingContext property on a frame element points to browsingContext embedded in the frame.
Meaning _childOfWindow is an infinite while loop which keeps testing the same frame element forever.

Flags: needinfo?(jdescottes)
Summary: right click => View Image makes tab unresponsive → Deleting a node in a same-process frame and navigating will freeze the content process

This broke after Bug 1647438 which modified the implementation of getFrameElement.

Severity: -- → S3
Priority: -- → P2
Regressed by: 1647438
Has Regression Range: --- → yes

Before Bug 1647438, getFrameElement had a different implementation:

const getFrameElement = win => {
  const isTopWindow = win && DevToolsUtils.getTopWindow(win) === win;
  return isTopWindow ? null : utilsFor(win).containerElement;
};

utilsFor is a memoized helper which returns win.windowUtils. And on an iframeElement, windowUtils is undefined, which means that accessing containerElement threw an exception. Code was still buggy but it just didn't block the process.

Deleting a node with the inspector puts the corresponding NodeActor in the retained nodes, in case the user cancels the deletion.
When a frame is unloaded we try to remove all the retained node to free memory.
For each retained node, we try to climb up the window hierarchy to know if it should be released or not.
However the implementation was buggy, relying on a while loop which was incorrectly mixing window objects and frame elements.
This previously lead to errors, and now leads to infinite loops.

A new test is added to cover this scenario.

Assignee: nobody → jdescottes
Status: NEW → ASSIGNED
Pushed by jdescottes@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/803c26c09271 [devtools] Fix infinite loop after deleting node in same-process frame r=nchevobbe
Status: ASSIGNED → RESOLVED
Closed: 4 years ago
Resolution: --- → FIXED
Target Milestone: --- → 88 Branch
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: