Bug 1180105 - Do not leak the SourceSurface returned from imgIContainer::GetFrame in BlockUntilDecodedAndFinishObserving; r=seth
authorEhsan Akhgari <ehsan@mozilla.com>
Fri, 03 Jul 2015 10:45:33 -0400
changeset 251625 da0f70cf87a3153f7d4db6f699d1b33cf7729070
parent 251624 17f5cab3e712305af92161db0e7c71ccb9fcccbe
child 251626 6629ba7c735ad4c775ff2afbd3d8621915602fb1
push id29007
push userryanvm@gmail.com
push dateTue, 07 Jul 2015 18:38:06 +0000
treeherdermozilla-central@9340658848d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersseth
bugs1180105
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1180105 - Do not leak the SourceSurface returned from imgIContainer::GetFrame in BlockUntilDecodedAndFinishObserving; r=seth
image/MultipartImage.cpp
image/test/mochitest/bug1180105-waiter.sjs
image/test/mochitest/bug1180105.sjs
image/test/mochitest/mochitest.ini
image/test/mochitest/test_bug1180105.html
--- a/image/MultipartImage.cpp
+++ b/image/MultipartImage.cpp
@@ -33,18 +33,19 @@ public:
 
     nsRefPtr<ProgressTracker> tracker = mImage->GetProgressTracker();
     tracker->AddObserver(this);
   }
 
   void BlockUntilDecodedAndFinishObserving()
   {
     // Use GetFrame() to block until our image finishes decoding.
-    mImage->GetFrame(imgIContainer::FRAME_CURRENT,
-                     imgIContainer::FLAG_SYNC_DECODE);
+    nsRefPtr<SourceSurface> surface =
+      mImage->GetFrame(imgIContainer::FRAME_CURRENT,
+                       imgIContainer::FLAG_SYNC_DECODE);
 
     FinishObserving();
   }
 
   virtual void Notify(int32_t aType,
                       const nsIntRect* aRect = nullptr) override
   {
     if (!mImage) {
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/bug1180105-waiter.sjs
@@ -0,0 +1,24 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var timer = Components.classes["@mozilla.org/timer;1"];
+var waitTimer = timer.createInstance(Components.interfaces.nsITimer);
+
+function handleRequest(request, response) {
+  response.setHeader("Content-Type", "text/html", false);
+  response.setHeader("Cache-Control", "no-cache", false);
+  response.setStatusLine(request.httpVersion, 200, "OK");
+  response.processAsync();
+  waitForFinish(response);
+}
+
+function waitForFinish(response) {
+  if (getSharedState("all-parts-done") === "1") {
+    response.write("done");
+    response.finish();
+  } else {
+    waitTimer.initWithCallback(function() {waitForFinish(response);}, 10,
+                               Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/bug1180105.sjs
@@ -0,0 +1,63 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var counter = 100;
+var timer = Components.classes["@mozilla.org/timer;1"];
+var partTimer = timer.createInstance(Components.interfaces.nsITimer);
+
+function getFileAsInputStream(aFilename) {
+  var file = Components.classes["@mozilla.org/file/directory_service;1"]
+             .getService(Components.interfaces.nsIProperties)
+             .get("CurWorkD", Components.interfaces.nsIFile);
+
+  file.append("tests");
+  file.append("image");
+  file.append("test");
+  file.append("mochitest");
+  file.append(aFilename);
+
+  var fileStream = Components.classes['@mozilla.org/network/file-input-stream;1']
+                   .createInstance(Components.interfaces.nsIFileInputStream);
+  fileStream.init(file, 1, 0, false);
+  return fileStream;
+}
+
+function handleRequest(request, response)
+{
+  response.setHeader("Content-Type",
+                     "multipart/x-mixed-replace;boundary=BOUNDARYOMG", false);
+  response.setHeader("Cache-Control", "no-cache", false);
+  response.setStatusLine(request.httpVersion, 200, "OK");
+  // We're sending parts off in a delayed fashion, to let the tests occur.
+  response.processAsync();
+  response.write("--BOUNDARYOMG\r\n");
+  sendParts(response);
+}
+
+function sendParts(response) {
+  if (counter-- == 0) {
+    sendClose(response);
+    setSharedState("all-parts-done", "1");
+    return;
+  }
+  sendNextPart(response);
+  partTimer.initWithCallback(function() {sendParts(response);}, 1,
+                             Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
+
+function sendClose(response) {
+  response.write("--BOUNDARYOMG--\r\n");
+  response.finish();
+}
+
+function sendNextPart(response) {
+  var nextPartHead = "Content-Type: image/jpeg\r\n\r\n";
+  var inputStream = getFileAsInputStream("damon.jpg");
+  response.bodyOutputStream.write(nextPartHead, nextPartHead.length);
+  response.bodyOutputStream.writeFrom(inputStream, inputStream.available());
+  inputStream.close();
+  // Toss in the boundary, so the browser can know this part is complete
+  response.write("--BOUNDARYOMG\r\n");
+}
+
--- a/image/test/mochitest/mochitest.ini
+++ b/image/test/mochitest/mochitest.ini
@@ -25,16 +25,18 @@ support-files =
   bug671906.sjs
   bug733553-informant.sjs
   bug733553.sjs
   bug767779.sjs
   bug89419-iframe.html
   bug89419.sjs
   bug900200.png
   bug900200-ref.png
+  bug1180105.sjs
+  bug1180105-waiter.sjs
   clear.gif
   clear.png
   clear2.gif
   clear2-results.gif
   damon.jpg
   error-early.png
   green.png
   green-background.html
@@ -81,16 +83,17 @@ skip-if = (toolkit == 'android' && proce
 skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
 [test_bug733553.html]
 [test_bug767779.html]
 [test_bug865919.html]
 [test_bug89419-1.html]
 skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
 [test_bug89419-2.html]
 skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
+[test_bug1180105.html]
 [test_animation_operators.html]
 [test_drawDiscardedImage.html]
 skip-if = toolkit == "gonk" #Bug 997034 - canvas.toDataURL() often causes lost connection to device.
 [test_error_events.html]
 [test_short_gif_header.html]
 [test_image_buffer_limit.html]
 #skip-if = toolkit != "gonk" #Image buffer limit is only set for Firefox OS currently.
 disabled = bug 1060869
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/test_bug1180105.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1180105
+-->
+<head>
+  <title>Test for Bug 1180105</title>
+  <script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="initializeOnload()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1180105">Mozilla Bug 1180105</a>
+<p id="display"></p>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+const WAITER_URL = "bug1180105-waiter.sjs";
+
+function initializeOnload() {
+  var firstimg = document.createElement('img');
+  firstimg.src = "bug1180105.sjs";
+  document.getElementById('content').appendChild(firstimg);
+
+  waitForFinish();
+}
+
+function waitForFinish() {
+  var loader = document.getElementById("loader");
+  loader.src = WAITER_URL;
+  loader.onload = function() {
+    var img = document.getElementsByTagName('img')[0];
+    ok(img.width > 0, "Image should be loaded by now");
+    SimpleTest.finish();
+  };
+}
+
+</script>
+</pre>
+<div id="content">>
+<iframe id="loader"></iframe>
+</div>
+</body>
+</html>