Title: [167851] trunk/Source/WebCore
Revision
167851
Author
[email protected]
Date
2014-04-26 21:09:45 -0700 (Sat, 26 Apr 2014)

Log Message

Frame and page lifetime fixes in WebCore::createWindow
https://bugs.webkit.org/show_bug.cgi?id=132089

Reviewed by Sam Weinig.

Speculative fix because I was unable to reproduce the crash that was
reported with the test case attached to this bug.

* loader/FrameLoader.cpp:
(WebCore::createWindow): Changed code to remove the assumption that calls
out will not destroy the page or frame. Use RefPtr for the frame, and
added early exits if frame->page() becomes null at any point before we
use a page pointer.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (167850 => 167851)


--- trunk/Source/WebCore/ChangeLog	2014-04-27 02:48:19 UTC (rev 167850)
+++ trunk/Source/WebCore/ChangeLog	2014-04-27 04:09:45 UTC (rev 167851)
@@ -1,3 +1,19 @@
+2014-04-26  Darin Adler  <[email protected]>
+
+        Frame and page lifetime fixes in WebCore::createWindow
+        https://bugs.webkit.org/show_bug.cgi?id=132089
+
+        Reviewed by Sam Weinig.
+
+        Speculative fix because I was unable to reproduce the crash that was
+        reported with the test case attached to this bug.
+
+        * loader/FrameLoader.cpp:
+        (WebCore::createWindow): Changed code to remove the assumption that calls
+        out will not destroy the page or frame. Use RefPtr for the frame, and
+        added early exits if frame->page() becomes null at any point before we
+        use a page pointer.
+
 2014-04-26  Alexey Proskuryakov  <[email protected]>
 
         Local files should not be allowed to read pasteboard data during drag

Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (167850 => 167851)


--- trunk/Source/WebCore/loader/FrameLoader.cpp	2014-04-27 02:48:19 UTC (rev 167850)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp	2014-04-27 04:09:45 UTC (rev 167851)
@@ -3426,14 +3426,15 @@
 {
     ASSERT(!features.dialog || request.frameName().isEmpty());
 
+    created = false;
+
     if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
-        if (Frame* frame = lookupFrame->loader().findFrameForNavigation(request.frameName(), openerFrame->document())) {
+        if (RefPtr<Frame> frame = lookupFrame->loader().findFrameForNavigation(request.frameName(), openerFrame->document())) {
             if (request.frameName() != "_self") {
                 if (Page* page = frame->page())
                     page->chrome().focus();
             }
-            created = false;
-            return frame;
+            return frame.release();
         }
     }
 
@@ -3441,7 +3442,7 @@
     if (isDocumentSandboxed(openerFrame, SandboxPopups)) {
         // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
         openerFrame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Blocked opening '" + request.resourceRequest().url().stringCenterEllipsizedToLength() + "' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set.");
-        return 0;
+        return nullptr;
     }
 
     // FIXME: Setting the referrer should be the caller's responsibility.
@@ -3453,29 +3454,42 @@
 
     Page* oldPage = openerFrame->page();
     if (!oldPage)
-        return 0;
+        return nullptr;
 
-    NavigationAction action(requestWithReferrer.resourceRequest());
-    Page* page = oldPage->chrome().createWindow(openerFrame, requestWithReferrer, features, action);
+    Page* page = oldPage->chrome().createWindow(openerFrame, requestWithReferrer, features, NavigationAction(requestWithReferrer.resourceRequest()));
     if (!page)
-        return 0;
+        return nullptr;
 
-    page->mainFrame().loader().forceSandboxFlags(openerFrame->document()->sandboxFlags());
+    RefPtr<Frame> frame = &page->mainFrame();
 
+    frame->loader().forceSandboxFlags(openerFrame->document()->sandboxFlags());
+
     if (request.frameName() != "_blank")
-        page->mainFrame().tree().setName(request.frameName());
+        frame->tree().setName(request.frameName());
 
     page->chrome().setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
+
+    if (!frame->page())
+        return nullptr;
     page->chrome().setStatusbarVisible(features.statusBarVisible);
+
+    if (!frame->page())
+        return nullptr;
     page->chrome().setScrollbarsVisible(features.scrollbarsVisible);
+
+    if (!frame->page())
+        return nullptr;
     page->chrome().setMenubarVisible(features.menuBarVisible);
+
+    if (!frame->page())
+        return nullptr;
     page->chrome().setResizable(features.resizable);
 
     // 'x' and 'y' specify the location of the window, while 'width' and 'height'
     // specify the size of the viewport. We can only resize the window, so adjust
     // for the difference between the window size and the viewport size.
 
-// FIXME: We should reconcile the initialization of viewport arguments between iOS and OpenSource.
+    // FIXME: We should reconcile the initialization of viewport arguments between iOS and non-IOS.
 #if !PLATFORM(IOS)
     FloatSize viewportSize = page->chrome().pageRect().size();
     FloatRect windowRect = page->chrome().windowRect();
@@ -3492,6 +3506,8 @@
     // Ensure non-NaN values, minimum size as well as being within valid screen area.
     FloatRect newWindowRect = DOMWindow::adjustWindowRect(page, windowRect);
 
+    if (!frame->page())
+        return nullptr;
     page->chrome().setWindowRect(newWindowRect);
 #else
     // On iOS, width and height refer to the viewport dimensions.
@@ -3501,13 +3517,15 @@
         arguments.width = features.width;
     if (features.heightSet && features.height)
         arguments.height = features.height;
-    page->mainFrame().setViewportArguments(arguments);
+    frame->setViewportArguments(arguments);
 #endif
 
+    if (!frame->page())
+        return nullptr;
     page->chrome().show();
 
     created = true;
-    return &page->mainFrame();
+    return frame.release();
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/loader/SubframeLoader.cpp (167850 => 167851)


--- trunk/Source/WebCore/loader/SubframeLoader.cpp	2014-04-27 02:48:19 UTC (rev 167850)
+++ trunk/Source/WebCore/loader/SubframeLoader.cpp	2014-04-27 04:09:45 UTC (rev 167851)
@@ -322,6 +322,9 @@
 
 Frame* SubframeLoader::loadOrRedirectSubframe(HTMLFrameOwnerElement& ownerElement, const URL& url, const AtomicString& frameName, LockHistory lockHistory, LockBackForwardList lockBackForwardList)
 {
+    if (!url.isValid())
+        return nullptr;
+
     Frame* frame = ownerElement.contentFrame();
     if (frame)
         frame->navigationScheduler().scheduleLocationChange(m_frame.document()->securityOrigin(), url.string(), m_frame.loader().outgoingReferrer(), lockHistory, lockBackForwardList);

Modified: trunk/Source/WebCore/page/DOMWindow.cpp (167850 => 167851)


--- trunk/Source/WebCore/page/DOMWindow.cpp	2014-04-27 02:48:19 UTC (rev 167850)
+++ trunk/Source/WebCore/page/DOMWindow.cpp	2014-04-27 04:09:45 UTC (rev 167851)
@@ -1891,19 +1891,20 @@
         return;
 
     URL completedURL = firstFrame->document()->completeURL(urlString);
-    if (completedURL.isNull())
+    if (!completedURL.isValid())
         return;
 
     if (isInsecureScriptAccess(activeWindow, completedURL))
         return;
 
+    Frame* referrerFrame = activeDocument->frame();
+    if (!referrerFrame)
+        return;
+
     // We want a new history item if we are processing a user gesture.
     LockHistory lockHistory = (locking != LockHistoryBasedOnGestureState || !ScriptController::processingUserGesture()) ? LockHistory::Yes : LockHistory::No;
     LockBackForwardList lockBackForwardList = (locking != LockHistoryBasedOnGestureState) ? LockBackForwardList::Yes : LockBackForwardList::No;
-    m_frame->navigationScheduler().scheduleLocationChange(activeDocument->securityOrigin(),
-        // FIXME: What if activeDocument()->frame() is 0?
-        completedURL, activeDocument->frame()->loader().outgoingReferrer(),
-        lockHistory, lockBackForwardList);
+    m_frame->navigationScheduler().scheduleLocationChange(activeDocument->securityOrigin(), completedURL, referrerFrame->loader().outgoingReferrer(), lockHistory, lockBackForwardList);
 }
 
 void DOMWindow::printErrorMessage(const String& message)
@@ -1988,7 +1989,7 @@
     if (!completedURL.isEmpty() && !completedURL.isValid()) {
         // Don't expose client code to invalid URLs.
         activeWindow.printErrorMessage("Unable to open a window with invalid URL '" + completedURL.string() + "'.\n");
-        return 0;
+        return nullptr;
     }
 
     // For whatever reason, Firefox uses the first frame to determine the outgoingReferrer. We replicate that behavior here.
@@ -2003,7 +2004,7 @@
     bool created;
     RefPtr<Frame> newFrame = WebCore::createWindow(activeFrame, openerFrame, frameRequest, windowFeatures, created);
     if (!newFrame)
-        return 0;
+        return nullptr;
 
     newFrame->loader().setOpener(openerFrame);
     newFrame->page()->setOpenedByDOM();
@@ -2032,24 +2033,24 @@
     DOMWindow& activeWindow, DOMWindow& firstWindow)
 {
     if (!isCurrentlyDisplayedInFrame())
-        return 0;
+        return nullptr;
     Document* activeDocument = activeWindow.document();
     if (!activeDocument)
-        return 0;
+        return nullptr;
     Frame* firstFrame = firstWindow.frame();
     if (!firstFrame)
-        return 0;
+        return nullptr;
 
     if (!firstWindow.allowPopUp()) {
         // Because FrameTree::find() returns true for empty strings, we must check for empty frame names.
         // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
         if (frameName.isEmpty() || !m_frame->tree().find(frameName))
-            return 0;
+            return nullptr;
     }
 
     // Get the target frame for the special cases of _top and _parent.
     // In those cases, we schedule a location change right now and return early.
-    Frame* targetFrame = 0;
+    Frame* targetFrame = nullptr;
     if (frameName == "_top")
         targetFrame = &m_frame->tree().top();
     else if (frameName == "_parent") {
@@ -2060,9 +2061,11 @@
     }
     if (targetFrame) {
         if (!activeDocument->canNavigate(targetFrame))
-            return 0;
+            return nullptr;
 
         URL completedURL = firstFrame->document()->completeURL(urlString);
+        if (!completedURL.isValid())
+            return nullptr;
 
         if (targetFrame->document()->domWindow()->isInsecureScriptAccess(activeWindow, completedURL))
             return targetFrame->document()->domWindow();
@@ -2080,7 +2083,7 @@
 
     WindowFeatures windowFeatures(windowFeaturesString);
     RefPtr<Frame> result = createWindow(urlString, frameName, windowFeatures, activeWindow, firstFrame, m_frame);
-    return result ? result->document()->domWindow() : 0;
+    return result ? result->document()->domWindow() : nullptr;
 }
 
 void DOMWindow::showModalDialog(const String& urlString, const String& dialogFeaturesString, DOMWindow& activeWindow, DOMWindow& firstWindow, std::function<void (DOMWindow&)> prepareDialogFunction)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to