<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[197765] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/197765">197765</a></dd>
<dt>Author</dt> <dd>akling@apple.com</dd>
<dt>Date</dt> <dd>2016-03-08 07:14:54 -0800 (Tue, 08 Mar 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>ImageDocuments leak their world.
&lt;https://webkit.org/b/155167&gt;
&lt;rdar://problem/24987363&gt;

Reviewed by Antti Koivisto.

Source/WebCore:

ImageDocument uses a special code path in ImageLoader in order to manually
control how the image is loaded. It has to do this because the ImageDocument
is really just a synthetic wrapper around a main resource that's an image.

This custom loading code had a bug where it would create a new CachedImage
and neglect to set its CachedResource::m_state flag to Pending (which is
normally set by CachedResource::load(), but we don't call that for these.)

This meant that when ImageDocument called CachedImage::finishLoading() to
trigger the notifyFinished() callback path, the image would look at its
loading state and see that it was Unknown (not Pending), and conclude that
it hadn't loaded yet. So we never got the notifyFinished() signal.

The world leaks here because ImageLoader slaps a ref on its &lt;img&gt; element
while it waits for the loading operation to complete. Once finished, whether
successfully or with an error, it derefs the &lt;img&gt;.

Since we never fired notifyFinished(), we ended up with an extra ref on
these &lt;img&gt; forever, and then the element kept its document alive too.

Test: fast/dom/ImageDocument-world-leak.html

* loader/ImageLoader.cpp:
(WebCore::ImageLoader::updateFromElement):

LayoutTests:

Made a little test that loads an image into an &lt;iframe&gt; 10 times and then
triggers a garbage collection and checks that all the documents got destroyed.

Prior to this change, all 10 ImageDocuments would remain alive at the end.

* fast/dom/ImageDocument-world-leak-expected.txt: Added.
* fast/dom/ImageDocument-world-leak.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreloaderImageLoadercpp">trunk/Source/WebCore/loader/ImageLoader.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastdomImageDocumentworldleakexpectedtxt">trunk/LayoutTests/fast/dom/ImageDocument-world-leak-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastdomImageDocumentworldleakhtml">trunk/LayoutTests/fast/dom/ImageDocument-world-leak.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (197764 => 197765)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-03-08 14:59:53 UTC (rev 197764)
+++ trunk/LayoutTests/ChangeLog        2016-03-08 15:14:54 UTC (rev 197765)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2016-03-08  Andreas Kling  &lt;akling@apple.com&gt;
+
+        ImageDocuments leak their world.
+        &lt;https://webkit.org/b/155167&gt;
+        &lt;rdar://problem/24987363&gt;
+
+        Reviewed by Antti Koivisto.
+
+        Made a little test that loads an image into an &lt;iframe&gt; 10 times and then
+        triggers a garbage collection and checks that all the documents got destroyed.
+
+        Prior to this change, all 10 ImageDocuments would remain alive at the end.
+
+        * fast/dom/ImageDocument-world-leak-expected.txt: Added.
+        * fast/dom/ImageDocument-world-leak.html: Added.
+
</ins><span class="cx"> 2016-03-08  Alejandro G. Castro  &lt;alex@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed EFL build fix after r197752.
</span></span></pre></div>
<a id="trunkLayoutTestsfastdomImageDocumentworldleakexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/dom/ImageDocument-world-leak-expected.txt (0 => 197765)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/dom/ImageDocument-world-leak-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/dom/ImageDocument-world-leak-expected.txt        2016-03-08 15:14:54 UTC (rev 197765)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+Test that ImageDocuments don't leak their world.
+
+Number of live documents: 2 (was 2)
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastdomImageDocumentworldleakhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/dom/ImageDocument-world-leak.html (0 => 197765)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/dom/ImageDocument-world-leak.html                                (rev 0)
+++ trunk/LayoutTests/fast/dom/ImageDocument-world-leak.html        2016-03-08 15:14:54 UTC (rev 197765)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+&lt;head&gt;
+&lt;script&gt;
+function gc() {
+    if (window.GCController)
+        GCController.collect();
+}
+
+function numberOfLiveDocuments() {
+    if (window.internals)
+        return window.internals.numberOfLiveDocuments();
+    return 1;
+}
+
+gc();
+
+iterations = 10;
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+function test() {
+    var f = document.getElementById(&quot;frame&quot;);
+    f.onload = function() {
+        f.contentDocument.open();
+        f.contentDocument.close();
+        --iterations;
+        if (iterations)
+            setTimeout(&quot;test()&quot;, 0);
+        else {
+            gc();
+            var out = document.getElementById(&quot;out&quot;);
+            out.innerText += &quot;Number of live documents: &quot; + numberOfLiveDocuments() + &quot; (was &quot; + numberOfLiveDocumentsAtStart + &quot;)&quot;;
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+    }
+    f.setAttribute(&quot;src&quot;, &quot;resources/apple.gif&quot;);
+}
+
+function begin() {
+    numberOfLiveDocumentsAtStart = numberOfLiveDocuments();
+    test();
+}
+&lt;/script&gt;
+&lt;/head&gt;
+&lt;body onload=&quot;begin()&quot;&gt;
+    &lt;p&gt;Test that ImageDocuments don't leak their world. &lt;/p&gt;
+    &lt;pre id=&quot;out&quot;&gt;&lt;/pre&gt;
+    &lt;iframe id=&quot;frame&quot;&gt;&lt;/iframe&gt;
+&lt;/body&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (197764 => 197765)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-03-08 14:59:53 UTC (rev 197764)
+++ trunk/Source/WebCore/ChangeLog        2016-03-08 15:14:54 UTC (rev 197765)
</span><span class="lines">@@ -1,3 +1,36 @@
</span><ins>+2016-03-08  Andreas Kling  &lt;akling@apple.com&gt;
+
+        ImageDocuments leak their world.
+        &lt;https://webkit.org/b/155167&gt;
+        &lt;rdar://problem/24987363&gt;
+
+        Reviewed by Antti Koivisto.
+
+        ImageDocument uses a special code path in ImageLoader in order to manually
+        control how the image is loaded. It has to do this because the ImageDocument
+        is really just a synthetic wrapper around a main resource that's an image.
+
+        This custom loading code had a bug where it would create a new CachedImage
+        and neglect to set its CachedResource::m_state flag to Pending (which is
+        normally set by CachedResource::load(), but we don't call that for these.)
+
+        This meant that when ImageDocument called CachedImage::finishLoading() to
+        trigger the notifyFinished() callback path, the image would look at its
+        loading state and see that it was Unknown (not Pending), and conclude that
+        it hadn't loaded yet. So we never got the notifyFinished() signal.
+
+        The world leaks here because ImageLoader slaps a ref on its &lt;img&gt; element
+        while it waits for the loading operation to complete. Once finished, whether
+        successfully or with an error, it derefs the &lt;img&gt;.
+
+        Since we never fired notifyFinished(), we ended up with an extra ref on
+        these &lt;img&gt; forever, and then the element kept its document alive too.
+
+        Test: fast/dom/ImageDocument-world-leak.html
+
+        * loader/ImageLoader.cpp:
+        (WebCore::ImageLoader::updateFromElement):
+
</ins><span class="cx"> 2016-03-07  Antti Koivisto  &lt;antti@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         ElementRuleCollector should not mutate document and style
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderImageLoadercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/ImageLoader.cpp (197764 => 197765)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/ImageLoader.cpp        2016-03-08 14:59:53 UTC (rev 197764)
+++ trunk/Source/WebCore/loader/ImageLoader.cpp        2016-03-08 15:14:54 UTC (rev 197765)
</span><span class="lines">@@ -188,6 +188,7 @@
</span><span class="cx">             bool autoLoadOtherImages = document.cachedResourceLoader().autoLoadImages();
</span><span class="cx">             document.cachedResourceLoader().setAutoLoadImages(false);
</span><span class="cx">             newImage = new CachedImage(request.resourceRequest(), m_element.document().page()-&gt;sessionID());
</span><ins>+            newImage-&gt;setStatus(CachedResource::Pending);
</ins><span class="cx">             newImage-&gt;setLoading(true);
</span><span class="cx">             newImage-&gt;setOwningCachedResourceLoader(&amp;document.cachedResourceLoader());
</span><span class="cx">             document.cachedResourceLoader().m_documentResources.set(newImage-&gt;url(), newImage.get());
</span></span></pre>
</div>
</div>

</body>
</html>