|
|
Created:
4 years, 10 months ago by dcheng Modified:
4 years, 10 months ago CC:
blink-reviews, blink-reviews-dom_chromium.org, chromium-reviews, dglazkov+blink, eae+blinkwatch, rwlbuis, sof Base URL:
https://chromium.googlesource.com/chromium/src.git@master Target Ref:
refs/pending/heads/master Project:
chromium Visibility:
Public. |
DescriptionDisable sub frame loads more reliably in frame detach.
Previously, guarding against attaching a new frame in frame detach
was done by inspecting LoadEventProgress. There are certain
operations, such as document.open(), that can cause LoadEventProgress
to never advance, causing the guard to get skipped.
BUG=577105
Committed: https://crrev.com/a4bcdcb1f8df4f7427e208201501a9d8e41e386b
Cr-Commit-Position: refs/heads/master@{#373581}
Patch Set 1 #Patch Set 2 : . #Patch Set 3 : test #
Total comments: 5
Patch Set 4 : Better fix #
Total comments: 1
Patch Set 5 : Fix unit test and adjust comments. #
Total comments: 2
Patch Set 6 : Components fix #Patch Set 7 : One more disabler #
Messages
Total messages: 37 (15 generated)
Description was changed from ========== Fix BUG=577105 ========== to ========== Don't reset LoadEventProgress if frame unload has already started. LoadEventProgress is used to guard against creation of additional subframes during frame detach. Calling document.open() without ever calling document.close() results in a situation where LoadEventProgress is never advanced during frame detach, causing the logic to guard against subframe loads in detach to be skipped. BUG=577105 ==========
dcheng@chromium.org changed reviewers: + japhet@chromium.org, kinuko@chromium.org
https://codereview.chromium.org/1659013003/diff/40001/third_party/WebKit/Layo... File third_party/WebKit/LayoutTests/fast/frames/open-then-unload.html (right): https://codereview.chromium.org/1659013003/diff/40001/third_party/WebKit/Layo... third_party/WebKit/LayoutTests/fast/frames/open-then-unload.html:10: window[0].document.open(); At this point, LoadEventProgress gets reset to LoadEventNotRun without my patch. https://codereview.chromium.org/1659013003/diff/40001/third_party/WebKit/Layo... third_party/WebKit/LayoutTests/fast/frames/open-then-unload.html:11: window[0].document.appendChild(document.createElement('iframe')); Right now, our tree looks like this: [Main frame] | [Child A] (m_loadEventProgress == LoadEventNotRun) Since this child frame won't run unload events, we nest another frame under Child A: [Main frame] | [Child A] (m_loadEventProgress == LoadEventNotRun) | [Child B] (m_loadEventProgress == LoadEventCompleted) https://codereview.chromium.org/1659013003/diff/40001/third_party/WebKit/Layo... third_party/WebKit/LayoutTests/fast/frames/open-then-unload.html:13: window[0].document.documentElement.appendChild(document.createElement('iframe')); Since Child B's load event progress is normal, we can use an unload handler to try to attach a frame to [Child A] as it is navigating. https://codereview.chromium.org/1659013003/diff/40001/third_party/WebKit/Layo... third_party/WebKit/LayoutTests/fast/frames/open-then-unload.html:14: shouldBe('1', 'window[0].length'); If the iframe load is blocked, then window[0].length should remain at 1. https://codereview.chromium.org/1659013003/diff/40001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/dom/Document.cpp (right): https://codereview.chromium.org/1659013003/diff/40001/third_party/WebKit/Sour... third_party/WebKit/Source/core/dom/Document.cpp:2776: m_loadEventProgress = UnloadEventHandled; This was the original fix proposed in the bug. I believe it is insufficient. 1. Page starts XHR that never completes. 2. Navigation starts. 3. Provisional navigation prepares to commit. 4. Unload handlers run. At this point, m_loadEventProgres == UnloadEventHandled. 5. Now XHR abort handlers run. 6. XHR abort handler calls document.open(), which resets m_loadEventProgress to LoadEventNotRun. 7. Now, XHR abort handler can attach a child frame during frame detach again.
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/patch-status/1659013003/40001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1659013003/40001
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: This issue passed the CQ dry run.
Description was changed from ========== Don't reset LoadEventProgress if frame unload has already started. LoadEventProgress is used to guard against creation of additional subframes during frame detach. Calling document.open() without ever calling document.close() results in a situation where LoadEventProgress is never advanced during frame detach, causing the logic to guard against subframe loads in detach to be skipped. BUG=577105 ========== to ========== Disable sub frame loads more reliably in frame detach. Previously, guarding against attaching a new frame in frame detach was done by inspecting LoadEventProgress. There are certain operations, such as document.open(), that can cause LoadEventProgress to never advance, causing the guard to get skipped. BUG=577105 ==========
I found a better (and more reliable way) to do this. We should still probably make the document.open() fixes, but that can be done in a separate bug: https://crbug.com/583586 https://codereview.chromium.org/1659013003/diff/60001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/loader/FrameLoader.cpp (right): https://codereview.chromium.org/1659013003/diff/60001/third_party/WebKit/Sour... third_party/WebKit/Source/core/loader/FrameLoader.cpp:1047: SubframeLoadingDisabler disabler(m_frame->document()); Here, m_frame->document() might be null during the commit of the initial empty page. The other alternative was to make SubframeLoadingDisabler not stack allocated, but that gets complicated as well.
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/patch-status/1659013003/60001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1659013003/60001
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: Try jobs failed on following builders: linux_chromium_rel_ng on tryserver.chromium.linux (JOB_FAILED, http://build.chromium.org/p/tryserver.chromium.linux/builders/linux_chromium_...)
On 2016/02/03 03:13:29, dcheng wrote: > https://codereview.chromium.org/1659013003/diff/40001/third_party/WebKit/Sour... > third_party/WebKit/Source/core/dom/Document.cpp:2776: m_loadEventProgress = > UnloadEventHandled; > This was the original fix proposed in the bug. I believe it is insufficient. > > 1. Page starts XHR that never completes. > 2. Navigation starts. > 3. Provisional navigation prepares to commit. > 4. Unload handlers run. At this point, m_loadEventProgres == UnloadEventHandled. > 5. Now XHR abort handlers run. > 6. XHR abort handler calls document.open(), which resets m_loadEventProgress to > LoadEventNotRun. > 7. Now, XHR abort handler can attach a child frame during frame detach again. FWIW, calling document.open() in step #6 would cause the provisional document loader to be detached (Document::open does |m_frame->loader().stopAllLoaders()|), so the navigation started in step #2 would be safely aborted (when DocumentLoader::processData null-checks the frameLoader later on). It'd assert in Document::detach, though, so I agree it's suboptimal.
This looks reasonable to me, but it looks it breaks some test like WebViewTest.AddFrameInCloseURLUnload... where we directly call dispatchUnloadEvent(). Should the test be updated?
The CQ bit was checked by dcheng@chromium.org to run a CQ dry run
On 2016/02/03 at 12:23:33, kinuko wrote: > This looks reasonable to me, but it looks it breaks some test like WebViewTest.AddFrameInCloseURLUnload... where we directly call dispatchUnloadEvent(). Should the test be updated? I updated dispatchUnloadEvent() to also instantiate a SubframeLoadingDisabler, to keep things consistent between the non-process-swap and the process-swap case. PTAL.
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1659013003/80001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1659013003/80001
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: Try jobs failed on following builders: linux_chromium_compile_dbg_32_ng on tryserver.chromium.linux (JOB_FAILED, http://build.chromium.org/p/tryserver.chromium.linux/builders/linux_chromium_...) mac_chromium_compile_dbg_ng on tryserver.chromium.mac (JOB_FAILED, http://build.chromium.org/p/tryserver.chromium.mac/builders/mac_chromium_comp...)
https://codereview.chromium.org/1659013003/diff/80001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h (right): https://codereview.chromium.org/1659013003/diff/80001/third_party/WebKit/Sour... third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h:116: explicit SubframeLoadingDisabler(Node* root) Do we have to have constructors for both a pointer and a reference? That seems kind of lame.
Also uploading a fix for the component build. https://codereview.chromium.org/1659013003/diff/80001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h (right): https://codereview.chromium.org/1659013003/diff/80001/third_party/WebKit/Sour... third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h:116: explicit SubframeLoadingDisabler(Node* root) On 2016/02/03 at 23:25:14, Nate Chapin wrote: > Do we have to have constructors for both a pointer and a reference? That seems kind of lame. A pre-Oilpan alternative is to just keep the reference constructor. Then we could do something like: OwnPtr<SubframeLoadingDisabler> disabler; if (m_frame->document()) disabler.reset(new SubframeLoadingDisabler(*m_frame->document())); But this doesn't work with Oilpan: SubframeLoadingDisabler would have to become a garbage collected class, but then it references a garbage collected member in the destructor, and all sorts of complexity. I just added the pointer version because it is still nice to assert that the passed in Node* is not null (which is true 99% of the time). An alternative (which I want to try following up on) is to rearrange prepareForCommit() to make it so we only take this branch if document is not null, but that's a bigger change and harder to merge.
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/patch-status/1659013003/100001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1659013003/100001
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 to run a CQ dry run
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1659013003/120001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1659013003/120001
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: This issue passed the CQ dry run.
lgtm, though you'd probably want to wait for Nate's stamp :)
lgtm
The CQ bit was checked by dcheng@chromium.org
CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1659013003/120001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1659013003/120001
Message was sent while issue was closed.
Committed patchset #7 (id:120001)
Message was sent while issue was closed.
Description was changed from ========== Disable sub frame loads more reliably in frame detach. Previously, guarding against attaching a new frame in frame detach was done by inspecting LoadEventProgress. There are certain operations, such as document.open(), that can cause LoadEventProgress to never advance, causing the guard to get skipped. BUG=577105 ========== to ========== Disable sub frame loads more reliably in frame detach. Previously, guarding against attaching a new frame in frame detach was done by inspecting LoadEventProgress. There are certain operations, such as document.open(), that can cause LoadEventProgress to never advance, causing the guard to get skipped. BUG=577105 Committed: https://crrev.com/a4bcdcb1f8df4f7427e208201501a9d8e41e386b Cr-Commit-Position: refs/heads/master@{#373581} ==========
Message was sent while issue was closed.
Patchset 7 (id:??) landed as https://crrev.com/a4bcdcb1f8df4f7427e208201501a9d8e41e386b Cr-Commit-Position: refs/heads/master@{#373581} |