fast/loader/javascript-url-iframe-remove-on-navigate.html is a flaky crash on iOS...
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Mar 2018 01:02:21 +0000 (01:02 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Mar 2018 01:02:21 +0000 (01:02 +0000)
https://bugs.webkit.org/show_bug.cgi?id=183610

Reviewed by Youenn Fablet.

The issue was that in DocumentLoader::loadMainResource(), the call to requestMainResource() which
return null due to the load getting cancelled synchronously. If this load is the parent frame's last
pending load, then the 'load' event gets fired in the parent frame. In the test, the parent frame's
load event handler does a document.write() call which blows away the iframe. As a result, when
we return from the requestMainResource(), m_frame is null and we crash later on dereferencing it.

No new tests, covered by fast/loader/javascript-url-iframe-remove-on-navigate-async-delegate.html
which was crashing flakily.

* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::loadMainResource):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229596 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/loader/DocumentLoader.cpp

index aae645f..765f772 100644 (file)
@@ -1,3 +1,22 @@
+2018-03-13  Chris Dumez  <cdumez@apple.com>
+
+        fast/loader/javascript-url-iframe-remove-on-navigate.html is a flaky crash on iOS with async delegates
+        https://bugs.webkit.org/show_bug.cgi?id=183610
+
+        Reviewed by Youenn Fablet.
+
+        The issue was that in DocumentLoader::loadMainResource(), the call to requestMainResource() which
+        return null due to the load getting cancelled synchronously. If this load is the parent frame's last
+        pending load, then the 'load' event gets fired in the parent frame. In the test, the parent frame's
+        load event handler does a document.write() call which blows away the iframe. As a result, when
+        we return from the requestMainResource(), m_frame is null and we crash later on dereferencing it.
+
+        No new tests, covered by fast/loader/javascript-url-iframe-remove-on-navigate-async-delegate.html
+        which was crashing flakily.
+
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::loadMainResource):
+
 2018-03-13  Jer Noble  <jer.noble@apple.com>
 
         [iOS] Muted media playback can interrupt out-of-process audio
index f1ea0b3..c850fc3 100644 (file)
@@ -1718,15 +1718,12 @@ void DocumentLoader::loadMainResource(ResourceRequest&& request)
 
     m_mainResource = m_cachedResourceLoader->requestMainResource(WTFMove(mainResourceRequest)).value_or(nullptr);
 
-#if ENABLE(CONTENT_EXTENSIONS)
-    if (m_mainResource && m_mainResource->errorOccurred() && m_frame->page() && m_mainResource->resourceError().domain() == ContentExtensions::WebKitContentBlockerDomain) {
-        RELEASE_LOG_IF_ALLOWED("startLoadingMainResource: Blocked by content blocker error (frame = %p, main = %d)", m_frame, m_frame->isMainFrame());
-        cancelMainResourceLoad(frameLoader()->blockedByContentBlockerError(m_request));
-        return;
-    }
-#endif
-
     if (!m_mainResource) {
+        // The frame may have gone away if this load was cancelled synchronously and this was the last pending load.
+        // This is because we may have fired the load event in a parent frame.
+        if (!m_frame)
+            return;
+
         if (!m_request.url().isValid()) {
             RELEASE_LOG_IF_ALLOWED("startLoadingMainResource: Unable to load main resource, URL is invalid (frame = %p, main = %d)", m_frame, m_frame->isMainFrame());
             cancelMainResourceLoad(frameLoader()->client().cannotShowURLError(m_request));
@@ -1744,6 +1741,16 @@ void DocumentLoader::loadMainResource(ResourceRequest&& request)
         return;
     }
 
+    ASSERT(m_frame);
+
+#if ENABLE(CONTENT_EXTENSIONS)
+    if (m_mainResource->errorOccurred() && m_frame->page() && m_mainResource->resourceError().domain() == ContentExtensions::WebKitContentBlockerDomain) {
+        RELEASE_LOG_IF_ALLOWED("startLoadingMainResource: Blocked by content blocker error (frame = %p, main = %d)", m_frame, m_frame->isMainFrame());
+        cancelMainResourceLoad(frameLoader()->blockedByContentBlockerError(m_request));
+        return;
+    }
+#endif
+
     if (!mainResourceLoader()) {
         m_identifierForLoadWithoutResourceLoader = m_frame->page()->progress().createUniqueIdentifier();
         frameLoader()->notifier().assignIdentifierToInitialRequest(m_identifierForLoadWithoutResourceLoader, this, request);