aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Leon Scroggins III <scroggo@google.com>2018-02-16 12:03:03 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-02-16 17:26:56 +0000
commitcbf66a22130a1fd13285bb65d3a0d7ee6b4e8ab3 (patch)
tree37e60202849dfce25b2a9a8e204ce0cb730da84c
parent50d4a6a661909a36d259e3c6007337af8050a9fe (diff)
Ensure all rows of a gif are initialized
Bug: oss-fuzz:6274 Even if a frame does not have enough LZW blocks to decode all rows, (which is unknown until we actually decode them), it is marked complete once there are no more LZW blocks. When decoding, even if we've decoded all LZW blocks, check fRowsDecoded to determine whether we've actually all the rows. Report the number of rows decoded so that SkCodec can fill in the remaining ones. Change-Id: I1d6e0c29e3c37649725836cf24a4a239e3266b76 Reviewed-on: https://skia-review.googlesource.com/106964 Commit-Queue: Leon Scroggins <scroggo@google.com> Reviewed-by: Mike Klein <mtklein@google.com>
-rw-r--r--resources/invalid_images/ossfuzz6274.gifbin0 -> 45 bytes
-rw-r--r--src/codec/SkGifCodec.cpp8
-rw-r--r--tests/CodecTest.cpp37
3 files changed, 41 insertions, 4 deletions
diff --git a/resources/invalid_images/ossfuzz6274.gif b/resources/invalid_images/ossfuzz6274.gif
new file mode 100644
index 0000000000..faa3b6e575
--- /dev/null
+++ b/resources/invalid_images/ossfuzz6274.gif
Binary files differ
diff --git a/src/codec/SkGifCodec.cpp b/src/codec/SkGifCodec.cpp
index 1118ed0e7d..dbff9287eb 100644
--- a/src/codec/SkGifCodec.cpp
+++ b/src/codec/SkGifCodec.cpp
@@ -332,6 +332,8 @@ SkCodec::Result SkGifCodec::onIncrementalDecode(int* rowsDecoded) {
SkCodec::Result SkGifCodec::decodeFrame(bool firstAttempt, const Options& opts, int* rowsDecoded) {
const SkImageInfo& dstInfo = this->dstInfo();
+ const int scaledHeight = get_scaled_dimension(dstInfo.height(), fSwizzler->sampleY());
+
const int frameIndex = opts.fFrameIndex;
SkASSERT(frameIndex < fReader->imagesCount());
const SkGIFFrameContext* frameContext = fReader->frameContext(frameIndex);
@@ -354,8 +356,6 @@ SkCodec::Result SkGifCodec::decodeFrame(bool firstAttempt, const Options& opts,
|| frameContext->interlaced() || !fCurrColorTableIsReal) {
// fill ignores the width (replaces it with the actual, scaled width).
// But we need to scale in Y.
- const int scaledHeight = get_scaled_dimension(dstInfo.height(),
- fSwizzler->sampleY());
auto fillInfo = dstInfo.makeWH(0, scaledHeight);
fSwizzler->fill(fillInfo, fDst, fDstRowBytes, this->getFillValue(dstInfo),
opts.fZeroInitialized);
@@ -370,7 +370,7 @@ SkCodec::Result SkGifCodec::decodeFrame(bool firstAttempt, const Options& opts,
fFilledBackground = filledBackground;
if (filledBackground) {
// Report the full (scaled) height, since the client will never need to fill.
- fRowsDecoded = get_scaled_dimension(dstInfo.height(), fSwizzler->sampleY());
+ fRowsDecoded = scaledHeight;
} else {
// This will be updated by haveDecodedRow.
fRowsDecoded = 0;
@@ -384,7 +384,7 @@ SkCodec::Result SkGifCodec::decodeFrame(bool firstAttempt, const Options& opts,
bool frameDecoded = false;
const bool fatalError = !fReader->decode(frameIndex, &frameDecoded);
- if (fatalError || !frameDecoded) {
+ if (fatalError || !frameDecoded || fRowsDecoded != scaledHeight) {
if (rowsDecoded) {
*rowsDecoded = fRowsDecoded;
}
diff --git a/tests/CodecTest.cpp b/tests/CodecTest.cpp
index 290686fa37..6e0a88cd5a 100644
--- a/tests/CodecTest.cpp
+++ b/tests/CodecTest.cpp
@@ -10,6 +10,7 @@
#include "SkAndroidCodec.h"
#include "SkAutoMalloc.h"
#include "SkBitmap.h"
+#include "SkCanvas.h"
#include "SkCodec.h"
#include "SkCodecImageGenerator.h"
#include "SkColorSpace_XYZ.h"
@@ -27,6 +28,7 @@
#include "SkRandom.h"
#include "SkStream.h"
#include "SkStreamPriv.h"
+#include "SkUnPreMultiply.h"
#include "SkWebpEncoder.h"
#include "Test.h"
@@ -1528,3 +1530,38 @@ DEF_TEST(Codec_webp_rowsDecoded, r) {
test_info(r, codec.get(), codec->getInfo(), SkCodec::kInvalidInput, nullptr);
}
+
+DEF_TEST(Codec_ossfuzz6274, r) {
+ if (GetResourcePath().isEmpty()) {
+ return;
+ }
+
+ const char* file = "invalid_images/ossfuzz6274.gif";
+ auto image = GetResourceAsImage(file);
+ if (!image) {
+ ERRORF(r, "Missing %s", file);
+ return;
+ }
+
+ REPORTER_ASSERT(r, image->width() == 32);
+ REPORTER_ASSERT(r, image->height() == 32);
+
+ SkBitmap bm;
+ if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(32, 32))) {
+ ERRORF(r, "Failed to allocate pixels");
+ return;
+ }
+
+ bm.eraseColor(SK_ColorTRANSPARENT);
+
+ SkCanvas canvas(bm);
+ canvas.drawImage(image, 0, 0, nullptr);
+
+ for (int i = 0; i < image->width(); ++i)
+ for (int j = 0; j < image->height(); ++j) {
+ SkColor actual = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(i, j));
+ if (actual != SK_ColorTRANSPARENT) {
+ ERRORF(r, "did not initialize pixels! %i, %i is %x", i, j, actual);
+ }
+ }
+}