Bug 514033 - Error recovery for imagelib - part 2 - Notify the superclass error reporting framework when an error occurs.r=joe

This commit is contained in:
Bobby Holley 2010-09-12 08:22:27 -07:00
Родитель d90e859bc8
Коммит 7b91b495f6
11 изменённых файлов: 69 добавлений и 58 удалений

Просмотреть файл

@ -71,7 +71,6 @@ nsBMPDecoder::nsBMPDecoder()
mState = eRLEStateInitial;
mStateData = 0;
mLOH = WIN_HEADER_LENGTH;
mError = PR_FALSE;
}
nsBMPDecoder::~nsBMPDecoder()
@ -100,7 +99,7 @@ nsBMPDecoder::FinishInternal()
NS_ABORT_IF_FALSE(GetFrameCount() <= 1, "Multiple BMP frames?");
// Send notifications if appropriate
if (!IsSizeDecode() && !mError && (GetFrameCount() == 1)) {
if (!IsSizeDecode() && !IsError() && (GetFrameCount() == 1)) {
PostFrameStop();
mImage->DecodingComplete();
if (mObserver) {
@ -155,7 +154,7 @@ nsresult
nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
{
// No forgiveness
if (mError)
if (IsError())
return NS_ERROR_FAILURE;
// aCount=0 means EOF, mCurLine=0 means we're past end of image
@ -175,7 +174,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
if (mPos == BFH_LENGTH) {
ProcessFileHeader();
if (mBFH.signature[0] != 'B' || mBFH.signature[1] != 'M') {
mError = PR_TRUE;
PostDataError();
return NS_ERROR_FAILURE;
}
if (mBFH.bihsize == OS2_BIH_LENGTH)
@ -197,7 +196,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
// Verify we support this bit depth
if (mBIH.bpp != 1 && mBIH.bpp != 4 && mBIH.bpp != 8 &&
mBIH.bpp != 16 && mBIH.bpp != 24 && mBIH.bpp != 32) {
mError = PR_TRUE;
PostDataError();
return NS_ERROR_UNEXPECTED;
}
@ -205,7 +204,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
// Reject extremely wide images to keep the math sane
const PRInt32 k64KWidth = 0x0000FFFF;
if (mBIH.width < 0 || mBIH.width > k64KWidth) {
mError = PR_TRUE;
PostDataError();
return NS_ERROR_FAILURE;
}
@ -230,7 +229,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
// Always allocate 256 even though mNumColors might be smaller
mColors = new colorTable[256];
if (!mColors) {
mError = PR_TRUE;
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
return NS_ERROR_OUT_OF_MEMORY;
}
@ -255,7 +254,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
// to make exact calculations here, that's unnecessary.
// Also, it compensates rounding error.
if (!mRow) {
mError = PR_TRUE;
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
return NS_ERROR_OUT_OF_MEMORY;
}
rv = mImage->AppendFrame(0, 0, mBIH.width, real_height, gfxASurface::ImageFormatRGB24,
@ -263,7 +262,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
}
NS_ENSURE_SUCCESS(rv, rv);
if (!mImageData) {
mError = PR_TRUE;
PostDecoderError(NS_ERROR_FAILURE);
return NS_ERROR_FAILURE;
}
@ -272,7 +271,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8))
|| ((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
mError = PR_TRUE;
PostDataError();
return NS_ERROR_FAILURE;
}
// Clear the image, as the RLE may jump over areas
@ -416,7 +415,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8))
|| ((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
mError = PR_TRUE;
PostDataError();
return NS_ERROR_FAILURE;
}
@ -484,7 +483,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
// pixel too many, but only if their width is odd.
mStateData -= mBIH.width & 1;
if (mCurPos + mStateData > (PRUint32)mBIH.width) {
mError = PR_TRUE;
PostDataError();
return NS_ERROR_FAILURE;
}
}
@ -569,8 +568,8 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
continue;
default :
NS_NOTREACHED("BMP RLE decompression: unknown state!");
mError = PR_TRUE;
NS_ABORT_IF_FALSE(0, "BMP RLE decompression: unknown state!");
PostDecoderError(NS_ERROR_UNEXPECTED);
return NS_ERROR_FAILURE;
}
// Because of the use of the continue statement

Просмотреть файл

@ -178,7 +178,6 @@ private:
ERLEState mState; ///< Maintains the current state of the RLE decoding
PRUint32 mStateData;///< Decoding information that is needed depending on mState
PRBool mError; ///< Did we hit an error?
/** Set mBFH from the raw data in mRawBuf, converting from little-endian
* data to native data as necessary */

Просмотреть файл

@ -117,7 +117,6 @@ nsGIFDecoder2::nsGIFDecoder2()
, mLastFlushedPass(0)
, mGIFOpen(PR_FALSE)
, mSawTransparency(PR_FALSE)
, mError(PR_FALSE)
, mEnded(PR_FALSE)
{
// Clear out the structure, excluding the arrays
@ -147,7 +146,7 @@ nsresult
nsGIFDecoder2::FinishInternal()
{
// Send notifications if appropriate
if (!IsSizeDecode() && !mError) {
if (!IsSizeDecode() && !IsError()) {
if (mCurrentFrame == mGIFStruct.images_decoded)
EndImageFrame();
EndGIF(/* aSuccess = */ PR_TRUE);
@ -194,7 +193,7 @@ nsresult
nsGIFDecoder2::WriteInternal(const char *aBuffer, PRUint32 aCount)
{
// Don't forgive previously flagged errors
if (mError)
if (IsError())
return NS_ERROR_FAILURE;
// Push the data to the GIF decoder
@ -212,7 +211,7 @@ nsGIFDecoder2::WriteInternal(const char *aBuffer, PRUint32 aCount)
// of an animated gif, we still want to display it (mostly for legacy reasons).
// libpr0n code is strict, so we have to lie and tell it we were successful. So
// if we have something to salvage, we send off final decode notifications, and
// pretend that we're decoded. Otherwise, we set mError.
// pretend that we're decoded. Otherwise, we set a data error.
if (NS_FAILED(rv)) {
// Determine if we want to salvage the situation.
@ -223,12 +222,12 @@ nsGIFDecoder2::WriteInternal(const char *aBuffer, PRUint32 aCount)
EndGIF(/* aSuccess = */ PR_TRUE);
}
// Otherwise, set mError
// Otherwise, set an error
else
mError = PR_TRUE;
PostDataError();
}
return mError ? NS_ERROR_FAILURE : NS_OK;
return IsError() ? NS_ERROR_FAILURE : NS_OK;
}
//******************************************************************************

Просмотреть файл

@ -99,7 +99,6 @@ private:
PRUint8 mColorMask; // Apply this to the pixel to keep within colormap
PRPackedBool mGIFOpen;
PRPackedBool mSawTransparency;
PRPackedBool mError;
PRPackedBool mEnded;
gif_struct mGIFStruct;

Просмотреть файл

@ -79,7 +79,6 @@ nsICODecoder::nsICODecoder()
mColors = nsnull;
mRow = nsnull;
mHaveAlphaData = mDecodingAndMask = PR_FALSE;
mError = PR_FALSE;
}
nsICODecoder::~nsICODecoder()
@ -120,7 +119,7 @@ nsICODecoder::FinishInternal()
NS_ABORT_IF_FALSE(GetFrameCount() <= 1, "Multiple ICO frames?");
// Send notifications if appropriate
if (!IsSizeDecode() && !mError && (GetFrameCount() == 1)) {
if (!IsSizeDecode() && !IsError() && (GetFrameCount() == 1)) {
// Invalidate
nsIntRect r(0, 0, mDirEntry.mWidth, mDirEntry.mHeight);
@ -141,7 +140,7 @@ nsresult
nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
{
// No forgiveness
if (mError)
if (IsError())
return NS_ERROR_FAILURE;
if (!aCount) // aCount=0 means EOF
@ -150,7 +149,7 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
while (aCount && (mPos < ICONCOUNTOFFSET)) { // Skip to the # of icons.
if (mPos == 2) { // if the third byte is 1: This is an icon, 2: a cursor
if ((*aBuffer != 1) && (*aBuffer != 2)) {
mError = PR_TRUE;
PostDataError();
return NS_ERROR_FAILURE;
}
mIsCursor = (*aBuffer == 2);
@ -194,7 +193,7 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
// ensure mImageOffset is >= the size of the direntry headers (bug #245631)
PRUint32 minImageOffset = DIRENTRYOFFSET + mNumIcons*sizeof(mDirEntryArray);
if (mImageOffset < minImageOffset) {
mError = PR_TRUE;
PostDataError();
return NS_ERROR_FAILURE;
}
@ -248,13 +247,13 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
mNumColors = 256;
break;
default:
mError = PR_TRUE;
PostDataError();
return NS_ERROR_FAILURE;
}
mColors = new colorTable[mNumColors];
if (!mColors) {
mError = PR_TRUE;
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
return NS_ERROR_OUT_OF_MEMORY;
}
}
@ -278,7 +277,7 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
// to make exact calculations here, that's unnecessary.
// Also, it compensates rounding error.
if (!mRow) {
mError = PR_TRUE;
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
return NS_ERROR_OUT_OF_MEMORY;
}
@ -325,10 +324,12 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
// Ensure memory has been allocated before decoding. If we get this far
// without allocated memory, the file is most likely invalid.
// XXXbholley - If null values can be triggered by bad input, why are we
// asserting here?
NS_ASSERTION(mRow, "mRow is null");
NS_ASSERTION(mImageData, "mImageData is null");
if (!mRow || !mImageData) {
mError = PR_TRUE;
PostDataError();
return NS_ERROR_FAILURE;
}
@ -414,7 +415,7 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
break;
default:
// This is probably the wrong place to check this...
mError = PR_TRUE;
PostDataError();
return NS_ERROR_FAILURE;
}
@ -436,7 +437,7 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
mCurLine = mDirEntry.mHeight;
mRow = (PRUint8*)realloc(mRow, rowSize);
if (!mRow) {
mError = PR_TRUE;
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
return NS_ERROR_OUT_OF_MEMORY;
}
}
@ -445,7 +446,7 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
NS_ASSERTION(mRow, "mRow is null");
NS_ASSERTION(mImageData, "mImageData is null");
if (!mRow || !mImageData) {
mError = PR_TRUE;
PostDataError();
return NS_ERROR_FAILURE;
}

Просмотреть файл

@ -112,7 +112,6 @@ private:
PRPackedBool mHaveAlphaData;
PRPackedBool mIsCursor;
PRPackedBool mDecodingAndMask;
PRPackedBool mError;
};
} // namespace imagelib

Просмотреть файл

@ -92,6 +92,9 @@ nsIconDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
{
nsresult rv;
if (IsError())
return NS_IMAGELIB_ERROR_FAILURE;
// We put this here to avoid errors about crossing initialization with case
// jumps on linux.
PRUint32 bytesToRead = 0;
@ -133,7 +136,7 @@ nsIconDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
gfxASurface::ImageFormatARGB32,
&mImageData, &mPixBytesTotal);
if (NS_FAILED(rv)) {
mState = iconStateError;
PostDecoderError(rv);
return rv;
}
@ -175,10 +178,6 @@ nsIconDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
aCount = 0;
break;
case iconStateError:
return NS_IMAGELIB_ERROR_FAILURE;
break;
}
}

Просмотреть файл

@ -96,8 +96,7 @@ enum {
iconStateStart = 0,
iconStateHaveHeight = 1,
iconStateReadPixels = 2,
iconStateFinished = 3,
iconStateError = 4
iconStateFinished = 3
};
} // namespace imagelib

Просмотреть файл

@ -155,6 +155,7 @@ nsJPEGDecoder::InitInternal()
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file, and return.
*/
PostDecoderError(NS_ERROR_FAILURE);
return NS_ERROR_FAILURE;
}
@ -217,6 +218,7 @@ nsJPEGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
nsresult error_code;
if ((error_code = setjmp(mErr.setjmp_buffer)) != 0) {
if (error_code == NS_ERROR_FAILURE) {
PostDataError();
/* Error due to corrupt stream - return NS_OK and consume silently
so that libpr0n doesn't throw away a partial image load */
mState = JPEG_SINK_NON_JPEG_TRAILER;
@ -227,6 +229,7 @@ nsJPEGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
/* Error due to reasons external to the stream (probably out of
memory) - let libpr0n attempt to clean up, even though
mozilla is seconds away from falling flat on its face. */
PostDecoderError(error_code);
mState = JPEG_ERROR;
PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
("} (setjmp returned an error)"));
@ -297,6 +300,7 @@ nsJPEGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
break;
default:
mState = JPEG_ERROR;
PostDataError();
PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
("} (unknown colorpsace (1))"));
return NS_ERROR_UNEXPECTED;
@ -313,6 +317,7 @@ nsJPEGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
break;
default:
mState = JPEG_ERROR;
PostDataError();
PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
("} (unknown colorpsace (2))"));
return NS_ERROR_UNEXPECTED;
@ -362,6 +367,7 @@ nsJPEGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
break;
default:
mState = JPEG_ERROR;
PostDataError();
PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
("} (unknown colorpsace (3))"));
return NS_ERROR_UNEXPECTED;
@ -386,6 +392,7 @@ nsJPEGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
gfxASurface::ImageFormatRGB24,
&mImageData, &imagelength))) {
mState = JPEG_ERROR;
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
("} (could not initialize image frame)"));
return NS_ERROR_OUT_OF_MEMORY;
@ -551,9 +558,7 @@ nsJPEGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
break;
case JPEG_ERROR:
PR_LOG(gJPEGlog, PR_LOG_DEBUG,
("[this=%p] nsJPEGDecoder::ProcessData -- entering JPEG_ERROR case\n", this));
return NS_ERROR_FAILURE;
NS_ABORT_IF_FALSE(0, "Should always return immediately after error and not re-enter decoder");
}
PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,

Просмотреть файл

@ -86,7 +86,7 @@ nsPNGDecoder::nsPNGDecoder() :
mCMSLine(nsnull), interlacebuf(nsnull),
mInProfile(nsnull), mTransform(nsnull),
mHeaderBuf(nsnull), mHeaderBytesRead(0),
mChannels(0), mError(PR_FALSE), mFrameIsHidden(PR_FALSE),
mChannels(0), mFrameIsHidden(PR_FALSE),
mNotifiedDone(PR_FALSE)
{
}
@ -242,8 +242,10 @@ nsPNGDecoder::InitInternal()
// For size decodes, we only need a small buffer
if (IsSizeDecode()) {
mHeaderBuf = (PRUint8 *)nsMemory::Alloc(BYTES_NEEDED_FOR_DIMENSIONS);
if (!mHeaderBuf)
if (!mHeaderBuf) {
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
@ -255,11 +257,14 @@ nsPNGDecoder::InitInternal()
mPNG = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL, nsPNGDecoder::error_callback,
nsPNGDecoder::warning_callback);
if (!mPNG)
if (!mPNG) {
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
return NS_ERROR_OUT_OF_MEMORY;
}
mInfo = png_create_info_struct(mPNG);
if (!mInfo) {
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
png_destroy_read_struct(&mPNG, NULL, NULL);
return NS_ERROR_OUT_OF_MEMORY;
}
@ -308,7 +313,7 @@ nsPNGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
PRUint32 height = 0;
// No forgiveness if we previously hit an error
if (mError)
if (IsError())
goto error;
// If we only want width/height, we don't need to go through libpng
@ -328,16 +333,20 @@ nsPNGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
if (mHeaderBytesRead == BYTES_NEEDED_FOR_DIMENSIONS) {
// Check that the signature bytes are right
if (memcmp(mHeaderBuf, pngSignatureBytes, sizeof(pngSignatureBytes)))
if (memcmp(mHeaderBuf, pngSignatureBytes, sizeof(pngSignatureBytes))) {
PostDataError();
goto error;
}
// Grab the width and height, accounting for endianness (thanks libpng!)
width = png_get_uint_32(mHeaderBuf + WIDTH_OFFSET);
height = png_get_uint_32(mHeaderBuf + HEIGHT_OFFSET);
// Too big?
if ((width > MOZ_PNG_MAX_DIMENSION) || (height > MOZ_PNG_MAX_DIMENSION))
if ((width > MOZ_PNG_MAX_DIMENSION) || (height > MOZ_PNG_MAX_DIMENSION)) {
PostDataError();
goto error;
}
// Post our size to the superclass
PostSize(width, height);
@ -349,6 +358,12 @@ nsPNGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
// libpng uses setjmp/longjmp for error handling - set the buffer
if (setjmp(png_jmpbuf(mPNG))) {
// We might not really know what caused the error, but it makes more
// sense to blame the data.
if (!IsError())
PostDataError();
png_destroy_read_struct(&mPNG, &mInfo, NULL);
goto error;
}
@ -362,7 +377,7 @@ nsPNGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
// Consolidate error handling
error:
mError = PR_TRUE;
NS_ABORT_IF_FALSE(IsError(), "Should only get here if we flagged an error!");
return NS_ERROR_FAILURE;
}
@ -791,9 +806,7 @@ nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row,
}
break;
default:
NS_ERROR("Unknown PNG format!");
NS_ABORT();
break;
longjmp(png_jmpbuf(decoder->mPNG), 1);
}
if (!rowHasNoAlpha)
@ -854,7 +867,7 @@ nsPNGDecoder::end_callback(png_structp png_ptr, png_infop info_ptr)
static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
// We shouldn't get here if we've hit an error
NS_ABORT_IF_FALSE(!decoder->mError, "Finishing up PNG but hit error!");
NS_ABORT_IF_FALSE(!decoder->IsError(), "Finishing up PNG but hit error!");
#ifdef PNG_APNG_SUPPORTED
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) {

Просмотреть файл

@ -91,7 +91,6 @@ public:
PRUint32 mHeaderBytesRead;
PRUint8 mChannels;
PRPackedBool mError;
PRPackedBool mFrameHasNoAlpha;
PRPackedBool mFrameIsHidden;
PRPackedBool mNotifiedDone;