Title: [219501] trunk/Source/WebCore
Revision
219501
Author
cdu...@apple.com
Date
2017-07-14 01:17:10 -0700 (Fri, 14 Jul 2017)

Log Message

PageCache::removeAllItemsForPage(Page&) may reenter itself and cause crashes
https://bugs.webkit.org/show_bug.cgi?id=174473
<rdar://problem/32177485>

Reviewed by Antti Koivisto.

This could happen when a Page containing an SVGImage is removed from PageCache and
this resulted in the destruction of the SVGImage. Because the SVGImage has an internal
utility Page, it will also call PageCache::removeAllItemsForPage(WebCore::Page&) upon
destruction, causing us to reenter.

Address the issue by not calling PageCache::removeAllItemsForPage() for utility pages
since those cannot be in PageCache in the first place.

Also add assertions to make sure:
1. We never insert a utility page into PageCache
2. PageCache::removeAllItemsForPage() does not reenter

No new tests, because I was unable to write a test which reproduced the crash. This
is in theory testable using an API test which enables PageCache, loads a page
containing an SVGImage, navigates away from this page so that it goes into PageCache,
and then calls [WebView _close]. However, when I tried writing such test, I could
not get the SVGImage to get destroyed while PageCache::removeAllItemsForPage() is
called for the top-level page for some reason. Something seems to be keeping the
SVGImage alive longer. I tried disabling the MemoryCache but it did not help.

* history/PageCache.cpp:
(WebCore::PageCache::addIfCacheable):
(WebCore::PageCache::removeAllItemsForPage):
* history/PageCache.h:
* page/Page.cpp:
(WebCore::Page::~Page):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (219500 => 219501)


--- trunk/Source/WebCore/ChangeLog	2017-07-14 07:07:49 UTC (rev 219500)
+++ trunk/Source/WebCore/ChangeLog	2017-07-14 08:17:10 UTC (rev 219501)
@@ -1,3 +1,38 @@
+2017-07-14  Chris Dumez  <cdu...@apple.com>
+
+        PageCache::removeAllItemsForPage(Page&) may reenter itself and cause crashes
+        https://bugs.webkit.org/show_bug.cgi?id=174473
+        <rdar://problem/32177485>
+
+        Reviewed by Antti Koivisto.
+
+        This could happen when a Page containing an SVGImage is removed from PageCache and
+        this resulted in the destruction of the SVGImage. Because the SVGImage has an internal
+        utility Page, it will also call PageCache::removeAllItemsForPage(WebCore::Page&) upon
+        destruction, causing us to reenter.
+
+        Address the issue by not calling PageCache::removeAllItemsForPage() for utility pages
+        since those cannot be in PageCache in the first place.
+
+        Also add assertions to make sure:
+        1. We never insert a utility page into PageCache
+        2. PageCache::removeAllItemsForPage() does not reenter
+
+        No new tests, because I was unable to write a test which reproduced the crash. This
+        is in theory testable using an API test which enables PageCache, loads a page
+        containing an SVGImage, navigates away from this page so that it goes into PageCache,
+        and then calls [WebView _close]. However, when I tried writing such test, I could
+        not get the SVGImage to get destroyed while PageCache::removeAllItemsForPage() is
+        called for the top-level page for some reason. Something seems to be keeping the
+        SVGImage alive longer. I tried disabling the MemoryCache but it did not help.
+
+        * history/PageCache.cpp:
+        (WebCore::PageCache::addIfCacheable):
+        (WebCore::PageCache::removeAllItemsForPage):
+        * history/PageCache.h:
+        * page/Page.cpp:
+        (WebCore::Page::~Page):
+
 2017-07-14  Aaron Chu  <aaron_...@apple.com>
 
         AX: VoiceOver silent or skipping over time values on media player.

Modified: trunk/Source/WebCore/history/PageCache.cpp (219500 => 219501)


--- trunk/Source/WebCore/history/PageCache.cpp	2017-07-14 07:07:49 UTC (rev 219500)
+++ trunk/Source/WebCore/history/PageCache.cpp	2017-07-14 08:17:10 UTC (rev 219501)
@@ -409,6 +409,8 @@
     if (!page || !canCache(*page))
         return;
 
+    ASSERT_WITH_MESSAGE(!page->isUtilityPage(), "Utility pages such as SVGImage pages should never go into PageCache");
+
     setPageCacheState(*page, Document::AboutToEnterPageCache);
 
     // Focus the main frame, defocusing a focused subframe (if we have one). We do this here,
@@ -462,6 +464,11 @@
 
 void PageCache::removeAllItemsForPage(Page& page)
 {
+#if !ASSERT_DISABLED
+    ASSERT_WITH_MESSAGE(!m_isInRemoveAllItemsForPage, "We should not reenter this method");
+    SetForScope<bool> inRemoveAllItemsForPageScope { m_isInRemoveAllItemsForPage, true };
+#endif
+
     for (auto it = m_items.begin(); it != m_items.end();) {
         // Increment iterator first so it stays valid after the removal.
         auto current = it;

Modified: trunk/Source/WebCore/history/PageCache.h (219500 => 219501)


--- trunk/Source/WebCore/history/PageCache.h	2017-07-14 07:07:49 UTC (rev 219500)
+++ trunk/Source/WebCore/history/PageCache.h	2017-07-14 08:17:10 UTC (rev 219501)
@@ -78,6 +78,10 @@
     ListHashSet<RefPtr<HistoryItem>> m_items;
     unsigned m_maxSize {0};
 
+#if !ASSERT_DISABLED
+    bool m_isInRemoveAllItemsForPage { false };
+#endif
+
     friend class WTF::NeverDestroyed<PageCache>;
 };
 

Modified: trunk/Source/WebCore/page/Page.cpp (219500 => 219501)


--- trunk/Source/WebCore/page/Page.cpp	2017-07-14 07:07:49 UTC (rev 219500)
+++ trunk/Source/WebCore/page/Page.cpp	2017-07-14 08:17:10 UTC (rev 219501)
@@ -331,7 +331,8 @@
         m_scrollingCoordinator->pageDestroyed();
 
     backForward().close();
-    PageCache::singleton().removeAllItemsForPage(*this);
+    if (!isUtilityPage())
+        PageCache::singleton().removeAllItemsForPage(*this);
 
 #ifndef NDEBUG
     pageCounter.decrement();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to