From 7983d5f0c57d4c839e4941aa056ce33217bcdb88 Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Tue, 27 Oct 2015 14:23:04 -0700 Subject: [PATCH] Fix a memory leak in CanvasImageDecoder CanvasImageDecoder is instantiated with a callback into a Dart closure. That closure was holding references to the ImageDecoder and the returned Image. The circular reference between the ImageDecoder and the callback prevented the objects from being GCed, resulting in leakage of the image buffer. CanvasImageDecoder will now destroy the callback after it is invoked, thus releasing its handle to the Dart closure. --- sky/engine/core/painting/CanvasImageDecoder.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/sky/engine/core/painting/CanvasImageDecoder.cpp b/sky/engine/core/painting/CanvasImageDecoder.cpp index 4dac958c30f..df295d2436d 100644 --- a/sky/engine/core/painting/CanvasImageDecoder.cpp +++ b/sky/engine/core/painting/CanvasImageDecoder.cpp @@ -49,18 +49,25 @@ void CanvasImageDecoder::initWithList(const Uint8List& list) { void CanvasImageDecoder::Decode(PassRefPtr buffer) { TRACE_EVENT0("blink", "CanvasImageDecoder::Decode"); + + // Destroy the callback after this function completes. The Dart closure + // associated with the callback may hold a reference to the ImageDecoder, + // resulting in a circular reference. + CHECK(callback_); + OwnPtr callback(callback_.release()); + OwnPtr decoder = ImageDecoder::create(*buffer.get(), ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileIgnored); // decoder can be null if the buffer we was empty and we couldn't even guess // what type of image to decode. if (!decoder) { - callback_->handleEvent(nullptr); + callback->handleEvent(nullptr); return; } decoder->setData(buffer.get(), true); if (decoder->failed() || decoder->frameCount() == 0) { - callback_->handleEvent(nullptr); + callback->handleEvent(nullptr); return; } @@ -68,11 +75,13 @@ void CanvasImageDecoder::Decode(PassRefPtr buffer) { ImageFrame* imageFrame = decoder->frameBufferAtIndex(0); RefPtr skImage = adoptRef(SkImage::NewFromBitmap(imageFrame->getSkBitmap())); resultImage->setImage(skImage.release()); - callback_->handleEvent(resultImage.get()); + callback->handleEvent(resultImage.get()); } void CanvasImageDecoder::RejectCallback() { - callback_->handleEvent(nullptr); + CHECK(callback_); + OwnPtr callback(callback_.release()); + callback->handleEvent(nullptr); } } // namespace blink