From dda59f83188a49935da4829af3400c0e25851ca7 Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Wed, 11 May 2011 11:46:59 +0200 Subject: [PATCH] Bug 639303. r=joe --- modules/libpr0n/decoders/nsBMPDecoder.cpp | 5 ++++ modules/libpr0n/decoders/nsGIFDecoder2.cpp | 6 ++++ modules/libpr0n/decoders/nsIconDecoder.cpp | 6 ++++ modules/libpr0n/decoders/nsJPEGDecoder.cpp | 6 ++++ modules/libpr0n/decoders/nsPNGDecoder.cpp | 5 ++++ modules/libpr0n/src/Decoder.h | 1 + modules/libpr0n/src/RasterImage.cpp | 33 ++++++++++++++++------ 7 files changed, 53 insertions(+), 9 deletions(-) diff --git a/modules/libpr0n/decoders/nsBMPDecoder.cpp b/modules/libpr0n/decoders/nsBMPDecoder.cpp index 474054247992..0df2f42c86d4 100644 --- a/modules/libpr0n/decoders/nsBMPDecoder.cpp +++ b/modules/libpr0n/decoders/nsBMPDecoder.cpp @@ -196,6 +196,11 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount) // Post our size to the superclass PostSize(mBIH.width, real_height); + if (HasError()) { + // Setting the size lead to an error; this can happen when for example + // a multipart channel sends an image of a different size. + return; + } // We have the size. If we're doing a size decode, we got what // we came for. diff --git a/modules/libpr0n/decoders/nsGIFDecoder2.cpp b/modules/libpr0n/decoders/nsGIFDecoder2.cpp index 06af2aec2442..f58c67175083 100644 --- a/modules/libpr0n/decoders/nsGIFDecoder2.cpp +++ b/modules/libpr0n/decoders/nsGIFDecoder2.cpp @@ -916,6 +916,12 @@ nsGIFDecoder2::WriteInternal(const char *aBuffer, PRUint32 aCount) } // Create the image container with the right size. BeginGIF(); + if (HasError()) { + // Setting the size lead to an error; this can happen when for example + // a multipart channel sends an image of a different size. + mGIFStruct.state = gif_error; + return; + } // If we were doing a size decode, we're done if (IsSizeDecode()) diff --git a/modules/libpr0n/decoders/nsIconDecoder.cpp b/modules/libpr0n/decoders/nsIconDecoder.cpp index 37bd695812b0..bbc8312dce4e 100644 --- a/modules/libpr0n/decoders/nsIconDecoder.cpp +++ b/modules/libpr0n/decoders/nsIconDecoder.cpp @@ -99,6 +99,12 @@ nsIconDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount) // Post our size to the superclass PostSize(mWidth, mHeight); + if (HasError()) { + // Setting the size lead to an error; this can happen when for example + // a multipart channel sends an image of a different size. + mState = iconStateFinished; + return; + } // If We're doing a size decode, we're done if (IsSizeDecode()) { diff --git a/modules/libpr0n/decoders/nsJPEGDecoder.cpp b/modules/libpr0n/decoders/nsJPEGDecoder.cpp index 306d8fb5aee1..cfd81a1994d5 100644 --- a/modules/libpr0n/decoders/nsJPEGDecoder.cpp +++ b/modules/libpr0n/decoders/nsJPEGDecoder.cpp @@ -256,6 +256,12 @@ nsJPEGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount) // Post our size to the superclass PostSize(mInfo.image_width, mInfo.image_height); + if (HasError()) { + // Setting the size lead to an error; this can happen when for example + // a multipart channel sends an image of a different size. + mState = JPEG_ERROR; + return; + } /* If we're doing a size decode, we're done. */ if (IsSizeDecode()) diff --git a/modules/libpr0n/decoders/nsPNGDecoder.cpp b/modules/libpr0n/decoders/nsPNGDecoder.cpp index 5751d8e4b990..d2bf3e9ee9fc 100644 --- a/modules/libpr0n/decoders/nsPNGDecoder.cpp +++ b/modules/libpr0n/decoders/nsPNGDecoder.cpp @@ -512,6 +512,11 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) // Post our size to the superclass decoder->PostSize(width, height); + if (decoder->HasError()) { + // Setting the size lead to an error; this can happen when for example + // a multipart channel sends an image of a different size. + longjmp(png_jmpbuf(decoder->mPNG), 1); + } if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); diff --git a/modules/libpr0n/src/Decoder.h b/modules/libpr0n/src/Decoder.h index f67cbdcf9939..e2e166bddfb3 100644 --- a/modules/libpr0n/src/Decoder.h +++ b/modules/libpr0n/src/Decoder.h @@ -121,6 +121,7 @@ public: bool HasDataError() { return mDataError; }; bool HasDecoderError() { return NS_FAILED(mFailCode); }; nsresult GetDecoderError() { return mFailCode; }; + void PostResizeError() { PostDataError(); } // flags. Keep these in sync with imgIContainer.idl. // SetDecodeFlags must be called before Init(), otherwise diff --git a/modules/libpr0n/src/RasterImage.cpp b/modules/libpr0n/src/RasterImage.cpp index 30ba66970255..5b5ea7730030 100644 --- a/modules/libpr0n/src/RasterImage.cpp +++ b/modules/libpr0n/src/RasterImage.cpp @@ -924,6 +924,11 @@ RasterImage::SetSize(PRInt32 aWidth, PRInt32 aHeight) else NS_WARNING("Multipart channel sent an image of a different size"); + // Make the decoder aware of the error so that it doesn't try to call + // FinishInternal during ShutdownDecoder. + if (mDecoder) + mDecoder->PostResizeError(); + DoError(); return NS_ERROR_UNEXPECTED; } @@ -1239,6 +1244,7 @@ RasterImage::AddSourceData(const char *aBuffer, PRUint32 aCount) // We're not storing source data, so this data is probably coming straight // from the network. In this case, we want to display data as soon as we // get it, so we want to flush invalidations after every write. + nsRefPtr kungFuDeathGrip = mDecoder; mInDecoder = PR_TRUE; mDecoder->FlushInvalidations(); mInDecoder = PR_FALSE; @@ -2208,14 +2214,16 @@ RasterImage::ShutdownDecoder(eShutdownIntent aIntent) bool wasSizeDecode = mDecoder->IsSizeDecode(); // Finalize the decoder + // null out mDecoder, _then_ check for errors on the close (otherwise the + // error routine might re-invoke ShutdownDecoder) + nsRefPtr decoder = mDecoder; + mDecoder = nsnull; + mInDecoder = PR_TRUE; - mDecoder->Finish(); + decoder->Finish(); mInDecoder = PR_FALSE; - // null out the decoder, _then_ check for errors on the close (otherwise the - // error routine might re-invoke ShutdownDecoder) - nsresult decoderStatus = mDecoder->GetDecoderError(); - mDecoder = nsnull; + nsresult decoderStatus = decoder->GetDecoderError(); if (NS_FAILED(decoderStatus)) { DoError(); return decoderStatus; @@ -2260,6 +2268,7 @@ RasterImage::WriteToDecoder(const char *aBuffer, PRUint32 aCount) } // Write + nsRefPtr kungFuDeathGrip = mDecoder; mInDecoder = PR_TRUE; mDecoder->Write(aBuffer, aCount); mInDecoder = PR_FALSE; @@ -2271,6 +2280,9 @@ RasterImage::WriteToDecoder(const char *aBuffer, PRUint32 aCount) curframe->UnlockImageData(); } + if (!mDecoder) + return NS_ERROR_FAILURE; + CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError()); // Keep track of the total number of bytes written over the lifetime of the @@ -2418,18 +2430,19 @@ RasterImage::SyncDecode() // image as possible. We've send the decoder all of our data, so now's a good // time to flush any invalidations (in case we don't have all the data and what // we got left us mid-frame). + nsRefPtr kungFuDeathGrip = mDecoder; mInDecoder = PR_TRUE; mDecoder->FlushInvalidations(); mInDecoder = PR_FALSE; // If we finished the decode, shutdown the decoder - if (IsDecodeFinished()) { + if (mDecoder && IsDecodeFinished()) { rv = ShutdownDecoder(eShutdownIntent_Done); CONTAINER_ENSURE_SUCCESS(rv); } - // All good! - return NS_OK; + // All good if no errors! + return mError ? NS_ERROR_FAILURE : NS_OK; } //****************************************************************************** @@ -2660,6 +2673,8 @@ imgDecodeWorker::Run() if (!image->mDecoder) return NS_OK; + nsRefPtr decoderKungFuDeathGrip = image->mDecoder; + // Size decodes are cheap and we more or less want them to be // synchronous. Write all the data in that case, otherwise write a // chunk @@ -2700,7 +2715,7 @@ imgDecodeWorker::Run() } // If the decode finished, shutdown the decoder - if (image->IsDecodeFinished()) { + if (image->mDecoder && image->IsDecodeFinished()) { rv = image->ShutdownDecoder(RasterImage::eShutdownIntent_Done); if (NS_FAILED(rv)) { image->DoError();