|
|
DescriptionDispose a persisted plugin widget if the content frame is detached.
HTMLPlugInElement::removedFrom() clears persisted plugin widgets, to
prevent reuse of a widget associated with a destroyed object. However,
when nodes containing connected subframes are removed from a Document,
it is possible to synchronously trigger script after subframes are
detached, but before the nodes themselves are actually removed. This
can cause a FrameView for a detached frame to be incorrectly reused.
BUG=671331
Committed: https://crrev.com/9485e0d3ee1ec3d8bd5578b7ed4493855cfc9898
Cr-Commit-Position: refs/heads/master@{#439339}
Patch Set 1 #
Total comments: 10
Patch Set 2 : Make layout test more testharness.js-y and address comments. #Patch Set 3 : Fix typos #
Total comments: 8
Messages
Total messages: 26 (10 generated)
The CQ bit was checked by dcheng@chromium.org to run a CQ dry run
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/v2/patch-status/codereview.chromium.or...
dcheng@chromium.org changed reviewers: + esprehn@chromium.org, sigbjornf@opera.com
Widgets are the gift that keep on giving. bokan's original CL (https://codereview.chromium.org/2560803002/) addressed one other potential crash, but I believe that crash can't happen if we clear the persisted widget correctly here.
lgtm w/ some nits. I have such nightmares from the widget tree. :( https://codereview.chromium.org/2586633002/diff/1/third_party/WebKit/LayoutTe... File third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html (right): https://codereview.chromium.org/2586633002/diff/1/third_party/WebKit/LayoutTe... third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html:1: <script src = "../../resources/testharness.js"></script> <!DOCTYPE html> unless you need quirks mode, then add a comment. https://codereview.chromium.org/2586633002/diff/1/third_party/WebKit/LayoutTe... third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html:4: function bodyLoaded() { onload = function() is the same as body onload https://codereview.chromium.org/2586633002/diff/1/third_party/WebKit/LayoutTe... third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html:23: embed.align = "right"; var embed = document.getElementById("embed"); https://codereview.chromium.org/2586633002/diff/1/third_party/WebKit/LayoutTe... third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html:30: body.innerText = ""; document.body.textContent = "" https://codereview.chromium.org/2586633002/diff/1/third_party/WebKit/LayoutTe... third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html:33: <body onload="bodyLoaded()" id="body"> leave this out, the embed and iframe are enough
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: This issue passed the CQ dry run.
The CQ bit was checked by dcheng@chromium.org
The patchset sent to the CQ was uploaded after l-g-t-m from esprehn@chromium.org Link to the patchset: https://codereview.chromium.org/2586633002/#ps40001 (title: "Fix typos")
I ended up rewriting the test to be more testharness.js-y, just to familiarize myself with the framework. https://codereview.chromium.org/2586633002/diff/1/third_party/WebKit/LayoutTe... File third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html (right): https://codereview.chromium.org/2586633002/diff/1/third_party/WebKit/LayoutTe... third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html:1: <script src = "../../resources/testharness.js"></script> On 2016/12/17 01:47:56, esprehn wrote: > <!DOCTYPE html> unless you need quirks mode, then add a comment. Done. https://codereview.chromium.org/2586633002/diff/1/third_party/WebKit/LayoutTe... third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html:4: function bodyLoaded() { On 2016/12/17 01:47:56, esprehn wrote: > onload = function() is the same as body onload Done. https://codereview.chromium.org/2586633002/diff/1/third_party/WebKit/LayoutTe... third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html:23: embed.align = "right"; On 2016/12/17 01:47:56, esprehn wrote: > var embed = document.getElementById("embed"); Done, though I just used querySelector and removed the id. https://codereview.chromium.org/2586633002/diff/1/third_party/WebKit/LayoutTe... third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html:30: body.innerText = ""; On 2016/12/17 01:47:56, esprehn wrote: > document.body.textContent = "" Done. https://codereview.chromium.org/2586633002/diff/1/third_party/WebKit/LayoutTe... third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html:33: <body onload="bodyLoaded()" id="body"> On 2016/12/17 01:47:56, esprehn wrote: > leave this out, the embed and iframe are enough Done.
CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/v2/patch-status/codereview.chromium.or...
(Adding some review comments for things that mystified me in the reduced test case... maybe one day someone will figure out what's going on here?) https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Layo... File third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html (right): https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Layo... third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html:11: video.poster = "foo"; I have no idea why this is necessary. https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Layo... third_party/WebKit/LayoutTests/fast/plugins/update-plugin-after-detachment-crash.html:19: embed.type = "foo"; Similarly, all three of these lines are necessary. Even though the reattach (which persists the FrameView) is triggered by line 18, line 17 and 19 are both important as well... though I don't know why.
CQ is committing da patch. Bot data: {"patchset_id": 40001, "attempt_start_ts": 1481965691700170, "parent_rev": "1625a33e55434cac56bc0881373526bc69d7bb5a", "commit_rev": "a17521763dcc43ca803b8dbde7c34e59ef725ea4"}
Message was sent while issue was closed.
Description was changed from ========== Dispose a persisted plugin widget if the content frame is detached. HTMLPlugInElement::removedFrom() clears persisted plugin widgets, to prevent reuse of a widget associated with a destroyed object. However, when nodes containing connected subframes are removed from a Document, it is possible to synchronously trigger script after subframes are detached, but before the nodes themselves are actually removed. This can cause a FrameView for a detached frame to be incorrectly reused. BUG=671331 ========== to ========== Dispose a persisted plugin widget if the content frame is detached. HTMLPlugInElement::removedFrom() clears persisted plugin widgets, to prevent reuse of a widget associated with a destroyed object. However, when nodes containing connected subframes are removed from a Document, it is possible to synchronously trigger script after subframes are detached, but before the nodes themselves are actually removed. This can cause a FrameView for a detached frame to be incorrectly reused. BUG=671331 Review-Url: https://codereview.chromium.org/2586633002 ==========
Message was sent while issue was closed.
Committed patchset #3 (id:40001)
Message was sent while issue was closed.
Description was changed from ========== Dispose a persisted plugin widget if the content frame is detached. HTMLPlugInElement::removedFrom() clears persisted plugin widgets, to prevent reuse of a widget associated with a destroyed object. However, when nodes containing connected subframes are removed from a Document, it is possible to synchronously trigger script after subframes are detached, but before the nodes themselves are actually removed. This can cause a FrameView for a detached frame to be incorrectly reused. BUG=671331 Review-Url: https://codereview.chromium.org/2586633002 ========== to ========== Dispose a persisted plugin widget if the content frame is detached. HTMLPlugInElement::removedFrom() clears persisted plugin widgets, to prevent reuse of a widget associated with a destroyed object. However, when nodes containing connected subframes are removed from a Document, it is possible to synchronously trigger script after subframes are detached, but before the nodes themselves are actually removed. This can cause a FrameView for a detached frame to be incorrectly reused. BUG=671331 Committed: https://crrev.com/9485e0d3ee1ec3d8bd5578b7ed4493855cfc9898 Cr-Commit-Position: refs/heads/master@{#439339} ==========
Message was sent while issue was closed.
Patchset 3 (id:??) landed as https://crrev.com/9485e0d3ee1ec3d8bd5578b7ed4493855cfc9898 Cr-Commit-Position: refs/heads/master@{#439339}
Message was sent while issue was closed.
https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp (right): https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp:212: // TODO(dcheng): This UpdateSuspendScope doesn't seem to provide much; Given that the persisted-widget detach happens slightly earlier now, is this override still needed? https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp:429: setPersistedPluginWidget(nullptr); If there is a reason for this (unexpected) ordering (to avoid an UpdateSuspendScope..?), could you document it?
Message was sent while issue was closed.
https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp (right): https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp:212: // TODO(dcheng): This UpdateSuspendScope doesn't seem to provide much; On 2016/12/17 15:01:53, sof wrote: > Given that the persisted-widget detach happens slightly earlier now, is this > override still needed? For now, yes. If I understand this correctly, PluginViews won't be detached by disconnectContentFrame(). My long-term plan is to move widget disposal into ChildFrameDisconnector, which will allow this to be removed. I also plan on making plugin loads respect SubframeLoadingDisabler. The eventual goal is to remove deferred widget updates altogether, and change UpdateSuspendScope to AssertNoWidgetUpdatesScope. However, I'm still trying to understand FrameView::updateWidgets, which (usually) run in a timer but can occasionally run synchronously when post layout tasks are flushed. I'm hoping that in all cases where we run updateWidgets, we don't need to suspend widget updates... but I'm not actually sure how this will work out in practice... https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp:429: setPersistedPluginWidget(nullptr); On 2016/12/17 15:01:53, sof wrote: > If there is a reason for this (unexpected) ordering (to avoid an > UpdateSuspendScope..?), could you document it? I /think/ that removedFrom() isn't allowed to run script, while disconnectContentFrame() is. Given that, it seems safer to clear the persisted widget afterwards. I'll update this comment when I move widget disposal into ChildFrameDisconnector.
Message was sent while issue was closed.
https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp (right): https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp:212: // TODO(dcheng): This UpdateSuspendScope doesn't seem to provide much; On 2016/12/17 20:20:02, dcheng wrote: > On 2016/12/17 15:01:53, sof wrote: > > Given that the persisted-widget detach happens slightly earlier now, is this > > override still needed? > > For now, yes. If I understand this correctly, PluginViews won't be detached by > disconnectContentFrame(). My long-term plan is to move widget disposal into > ChildFrameDisconnector, which will allow this to be removed. I also plan on > making plugin loads respect SubframeLoadingDisabler. > WebPluginContainerImpl won't separately call removedFrom(), as far as i know.
Message was sent while issue was closed.
https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp (right): https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp:212: // TODO(dcheng): This UpdateSuspendScope doesn't seem to provide much; On 2016/12/17 21:47:28, sof wrote: > On 2016/12/17 20:20:02, dcheng wrote: > > On 2016/12/17 15:01:53, sof wrote: > > > Given that the persisted-widget detach happens slightly earlier now, is this > > > override still needed? > > > > For now, yes. If I understand this correctly, PluginViews won't be detached by > > disconnectContentFrame(). My long-term plan is to move widget disposal into > > ChildFrameDisconnector, which will allow this to be removed. I also plan on > > making plugin loads respect SubframeLoadingDisabler. > > > > WebPluginContainerImpl won't separately call removedFrom(), as far as i know. WebPluginContainerImpl won't, but things like ContainerNode::removeChild will detach the layout tree (which may persist a widget), and then notify the Node that it was removed (which is when we clear any persisted widget). This path is not covered by frame disconnection.
Message was sent while issue was closed.
On 2016/12/18 06:40:39, dcheng wrote: > https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... > File third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp (right): > > https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... > third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp:212: // TODO(dcheng): > This UpdateSuspendScope doesn't seem to provide much; > On 2016/12/17 21:47:28, sof wrote: > > On 2016/12/17 20:20:02, dcheng wrote: > > > On 2016/12/17 15:01:53, sof wrote: > > > > Given that the persisted-widget detach happens slightly earlier now, is > this > > > > override still needed? > > > > > > For now, yes. If I understand this correctly, PluginViews won't be detached > by > > > disconnectContentFrame(). My long-term plan is to move widget disposal into > > > ChildFrameDisconnector, which will allow this to be removed. I also plan on > > > making plugin loads respect SubframeLoadingDisabler. > > > > > > > WebPluginContainerImpl won't separately call removedFrom(), as far as i know. > > WebPluginContainerImpl won't, but things like ContainerNode::removeChild will > detach the layout tree (which may persist a widget), and then notify the Node > that it was removed (which is when we clear any persisted widget). This path is > not covered by frame disconnection. Hmm, removeChild() always runs willRemoveChild() first.
Message was sent while issue was closed.
On 2016/12/18 06:54:41, sof wrote: > On 2016/12/18 06:40:39, dcheng wrote: > > > https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... > > File third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp (right): > > > > > https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... > > third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp:212: // > TODO(dcheng): > > This UpdateSuspendScope doesn't seem to provide much; > > On 2016/12/17 21:47:28, sof wrote: > > > On 2016/12/17 20:20:02, dcheng wrote: > > > > On 2016/12/17 15:01:53, sof wrote: > > > > > Given that the persisted-widget detach happens slightly earlier now, is > > this > > > > > override still needed? > > > > > > > > For now, yes. If I understand this correctly, PluginViews won't be > detached > > by > > > > disconnectContentFrame(). My long-term plan is to move widget disposal > into > > > > ChildFrameDisconnector, which will allow this to be removed. I also plan > on > > > > making plugin loads respect SubframeLoadingDisabler. > > > > > > > > > > WebPluginContainerImpl won't separately call removedFrom(), as far as i > know. > > > > WebPluginContainerImpl won't, but things like ContainerNode::removeChild will > > detach the layout tree (which may persist a widget), and then notify the Node > > that it was removed (which is when we clear any persisted widget). This path > is > > not covered by frame disconnection. > > Hmm, removeChild() always runs willRemoveChild() first. It does... but something with a PluginView won't have a content frame, and won't get processed by ChildFrameDisconnector.
Message was sent while issue was closed.
On 2016/12/18 07:05:54, dcheng wrote: > On 2016/12/18 06:54:41, sof wrote: > > On 2016/12/18 06:40:39, dcheng wrote: > > > > > > https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... > > > File third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp (right): > > > > > > > > > https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... > > > third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp:212: // > > TODO(dcheng): > > > This UpdateSuspendScope doesn't seem to provide much; > > > On 2016/12/17 21:47:28, sof wrote: > > > > On 2016/12/17 20:20:02, dcheng wrote: > > > > > On 2016/12/17 15:01:53, sof wrote: > > > > > > Given that the persisted-widget detach happens slightly earlier now, > is > > > this > > > > > > override still needed? > > > > > > > > > > For now, yes. If I understand this correctly, PluginViews won't be > > detached > > > by > > > > > disconnectContentFrame(). My long-term plan is to move widget disposal > > into > > > > > ChildFrameDisconnector, which will allow this to be removed. I also plan > > on > > > > > making plugin loads respect SubframeLoadingDisabler. > > > > > > > > > > > > > WebPluginContainerImpl won't separately call removedFrom(), as far as i > > know. > > > > > > WebPluginContainerImpl won't, but things like ContainerNode::removeChild > will > > > detach the layout tree (which may persist a widget), and then notify the > Node > > > that it was removed (which is when we clear any persisted widget). This path > > is > > > not covered by frame disconnection. > > > > Hmm, removeChild() always runs willRemoveChild() first. > > It does... but something with a PluginView won't have a content frame, and won't > get processed by ChildFrameDisconnector. ok, we're probably looking at different code, but ChildFrameDisconnector works over frame owners. Which HTMLPluginElement is.
Message was sent while issue was closed.
On 2016/12/18 07:29:08, sof wrote: > On 2016/12/18 07:05:54, dcheng wrote: > > On 2016/12/18 06:54:41, sof wrote: > > > On 2016/12/18 06:40:39, dcheng wrote: > > > > > > > > > > https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... > > > > File third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp (right): > > > > > > > > > > > > > > https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... > > > > third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp:212: // > > > TODO(dcheng): > > > > This UpdateSuspendScope doesn't seem to provide much; > > > > On 2016/12/17 21:47:28, sof wrote: > > > > > On 2016/12/17 20:20:02, dcheng wrote: > > > > > > On 2016/12/17 15:01:53, sof wrote: > > > > > > > Given that the persisted-widget detach happens slightly earlier now, > > is > > > > this > > > > > > > override still needed? > > > > > > > > > > > > For now, yes. If I understand this correctly, PluginViews won't be > > > detached > > > > by > > > > > > disconnectContentFrame(). My long-term plan is to move widget > disposal > > > into > > > > > > ChildFrameDisconnector, which will allow this to be removed. I also > plan > > > on > > > > > > making plugin loads respect SubframeLoadingDisabler. > > > > > > > > > > > > > > > > WebPluginContainerImpl won't separately call removedFrom(), as far as i > > > know. > > > > > > > > WebPluginContainerImpl won't, but things like ContainerNode::removeChild > > will > > > > detach the layout tree (which may persist a widget), and then notify the > > Node > > > > that it was removed (which is when we clear any persisted widget). This > path > > > is > > > > not covered by frame disconnection. > > > > > > Hmm, removeChild() always runs willRemoveChild() first. > > > > It does... but something with a PluginView won't have a content frame, and > won't > > get processed by ChildFrameDisconnector. > > ok, we're probably looking at different code, but ChildFrameDisconnector works > over frame owners. Which HTMLPluginElement is. Ah, I understand now. I was mixing up persisted widget and widget when reasoning through this. I think you're right, and I'll try cleaning that up in a follow up. The reason it's OK to skip this in removedFrom is because the AttachContext during Node removal will never be marked as for reattach, so we will never persist a widget in that case. Thus, by the time we get to removedFrom, we should be able to assert that there is no persisted widget at all.
Message was sent while issue was closed.
On 2016/12/18 08:09:42, dcheng wrote: > On 2016/12/18 07:29:08, sof wrote: > > On 2016/12/18 07:05:54, dcheng wrote: > > > On 2016/12/18 06:54:41, sof wrote: > > > > On 2016/12/18 06:40:39, dcheng wrote: > > > > > > > > > > > > > > > https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... > > > > > File third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp (right): > > > > > > > > > > > > > > > > > > > > https://codereview.chromium.org/2586633002/diff/40001/third_party/WebKit/Sour... > > > > > third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp:212: // > > > > TODO(dcheng): > > > > > This UpdateSuspendScope doesn't seem to provide much; > > > > > On 2016/12/17 21:47:28, sof wrote: > > > > > > On 2016/12/17 20:20:02, dcheng wrote: > > > > > > > On 2016/12/17 15:01:53, sof wrote: > > > > > > > > Given that the persisted-widget detach happens slightly earlier > now, > > > is > > > > > this > > > > > > > > override still needed? > > > > > > > > > > > > > > For now, yes. If I understand this correctly, PluginViews won't be > > > > detached > > > > > by > > > > > > > disconnectContentFrame(). My long-term plan is to move widget > > disposal > > > > into > > > > > > > ChildFrameDisconnector, which will allow this to be removed. I also > > plan > > > > on > > > > > > > making plugin loads respect SubframeLoadingDisabler. > > > > > > > > > > > > > > > > > > > WebPluginContainerImpl won't separately call removedFrom(), as far as > i > > > > know. > > > > > > > > > > WebPluginContainerImpl won't, but things like ContainerNode::removeChild > > > will > > > > > detach the layout tree (which may persist a widget), and then notify the > > > Node > > > > > that it was removed (which is when we clear any persisted widget). This > > path > > > > is > > > > > not covered by frame disconnection. > > > > > > > > Hmm, removeChild() always runs willRemoveChild() first. > > > > > > It does... but something with a PluginView won't have a content frame, and > > won't > > > get processed by ChildFrameDisconnector. > > > > ok, we're probably looking at different code, but ChildFrameDisconnector works > > over frame owners. Which HTMLPluginElement is. > > Ah, I understand now. I was mixing up persisted widget and widget when reasoning > through this. I think you're right, and I'll try cleaning that up in a follow > up. > > The reason it's OK to skip this in removedFrom is because the AttachContext > during Node removal will never be marked as for reattach, so we will never > persist a widget in that case. Thus, by the time we get to removedFrom, we > should be able to assert that there is no persisted widget at all. Actually, I thought about this a bit more, and the removedFrom block is still necessary. ChildFrameDisconnector only disconnects connected subframes. Embeds with actual plugins loaded aren't considered connected subframes, and won't have disconnectContentFrame() called. My plan is to make ChildFrameDiconnector also handle loaded widgets, though there's a question of how best to track them: we currently maintain connected subframe count in NodeRareData, so we can optimize the tree walk to only visit nodes that actually have connected subframes. I'm thinking of resurrecting https://codereview.chromium.org/1770523002/ for this purpose: our current frame limit is set based on how many bits we have to use in NodeRareData for counting this. Or we could just say that plugins count againt your connected subframe limit (I can't really imagine a case where someone would want an unlimited number of plugins, but who knows...) |