Bug 1621283 - Ensure the WebP image decoder can handle source buffer errors. r=tnikkel

If we hit an OOM or similar when creating a SourceBuffer for an image,
we will hit COMPLETE immediately as the next read that goes to the
SourceBuffer from a SourceBufferIterator. If the iterator has yet to do
a read, that means it will hit COMPLETE right away without giving
anything. This patch fixes the WebP decoder to handle this case, as well
as adds test cases for all of the current image decoders.

Differential Revision: https://phabricator.services.mozilla.com/D77131
This commit is contained in:
Andrew Osmond 2020-05-27 22:52:10 +00:00
parent 2533f8da77
commit b1a4d4c79f
4 changed files with 51 additions and 0 deletions

View File

@ -144,6 +144,14 @@ LexerResult nsWebPDecoder::UpdateBuffer(SourceBufferIterator& aIterator,
mLength += aIterator.Length();
return ReadData();
case SourceBufferIterator::COMPLETE:
if (!mData) {
// We must have hit an error, such as an OOM, when buffering the
// first set of encoded data.
MOZ_LOG(
sWebPLog, LogLevel::Error,
("[this=%p] nsWebPDecoder::DoDecode -- complete no data\n", this));
return LexerResult(TerminalState::FAILURE);
}
return ReadData();
default:
MOZ_LOG(sWebPLog, LogLevel::Error,

View File

@ -53,6 +53,7 @@ AutoInitializeImageLib::AutoInitializeImageLib() {
gfxPlatform::GetPlatform();
// Ensure we always color manage images with gtests.
gfxPlatform::GetCMSMode();
gfxPlatform::SetCMSModeOverride(eCMSMode_All);
// Depending on initialization order, it is possible that our pref changes

View File

@ -138,6 +138,12 @@ struct ImageTestCase {
return self;
}
ImageTestCase WithFlags(uint32_t aFlags) const {
ImageTestCase self = *this;
self.mFlags = aFlags;
return self;
}
BGRAColor ChooseColor(const BGRAColor& aColor) const {
// If we are forcing the output to be sRGB via the surface flag, or the
// test case is marked as assuming sRGB (used when the image itself is not

View File

@ -90,6 +90,37 @@ static void CheckDecoderResults(const ImageTestCase& aTestCase,
EXPECT_TRUE(IsSolidColor(surface, aTestCase.Color(), aTestCase.Fuzz()));
}
template <typename Func>
void WithBadBufferDecode(const ImageTestCase& aTestCase,
const Maybe<IntSize>& aOutputSize,
Func aResultChecker) {
// Prepare a SourceBuffer with an error that will immediately move iterators
// to COMPLETE.
auto sourceBuffer = MakeNotNull<RefPtr<SourceBuffer>>();
sourceBuffer->ExpectLength(SIZE_MAX);
// Create a decoder.
DecoderType decoderType = DecoderFactory::GetDecoderType(aTestCase.mMimeType);
RefPtr<image::Decoder> decoder = DecoderFactory::CreateAnonymousDecoder(
decoderType, sourceBuffer, aOutputSize, DecoderFlags::FIRST_FRAME_ONLY,
aTestCase.mSurfaceFlags);
ASSERT_TRUE(decoder != nullptr);
RefPtr<IDecodingTask> task =
new AnonymousDecodingTask(WrapNotNull(decoder), /* aResumable */ false);
// Run the full decoder synchronously on the main thread.
task->Run();
// Call the lambda to verify the expected results.
aResultChecker(decoder);
}
static void CheckDecoderBadBuffer(const ImageTestCase& aTestCase) {
WithBadBufferDecode(aTestCase, Nothing(), [&](image::Decoder* aDecoder) {
CheckDecoderResults(aTestCase, aDecoder);
});
}
template <typename Func>
void WithSingleChunkDecode(const ImageTestCase& aTestCase,
const Maybe<IntSize>& aOutputSize,
@ -634,6 +665,11 @@ class ImageDecoders : public ::testing::Test {
TEST_F(ImageDecoders, test_prefix##ForceSRGB) { \
CheckDecoderSingleChunk(Green##test_prefix##TestCase().WithSurfaceFlags( \
SurfaceFlags::TO_SRGB_COLORSPACE)); \
} \
\
TEST_F(ImageDecoders, test_prefix##BadBuffer) { \
CheckDecoderBadBuffer(Green##test_prefix##TestCase().WithFlags( \
TEST_CASE_HAS_ERROR | TEST_CASE_IGNORE_OUTPUT)); \
}
IMAGE_GTEST_DECODER_BASE_F(PNG)