diff options
author | Leon Scroggins III <scroggo@google.com> | 2018-10-16 15:29:11 -0400 |
---|---|---|
committer | Leon Scroggins <scroggo@google.com> | 2018-11-26 19:57:38 +0000 |
commit | fc165d5cccf133574058cd0c5ba3a95ea6ad2bb8 (patch) | |
tree | 26201d60e503cb4167217b435484cc02493e9cf9 | |
parent | 2277702eee7eb6e99002b6b5248254fe9ffd5f76 (diff) | |
download | skia-fc165d5cccf133574058cd0c5ba3a95ea6ad2bb8.tar.gz |
RESTRICT AUTOMERGE: Fix uninitialized errors in SkPngCodec
Bug: 117838472
Test: Iae4d7f393c892111b12282c5eae31d79912721f9
- Initialize rowsDecoded in SkSampledCodec. Otherwise,
fillIncompleteImage may be called with an uninitialized
value. This change was originally uploaded to AOSP as
https://android-review.googlesource.com/c/platform/external/skia/+/785816
- If SkPngCodec hits an error, still transform from the
interlace buffer (if needed) and set rowsDecoded properly.
- Do not copy uninitialized memory from the interlace buffer.
- Make BRD treat kErrorInInput like kIncompleteInput. The two errors
are different for the purposes of incremental decode. For a direct
decode, they're essentially the same - part was decoded, but then
the decode was interrupted. This allows testing images with
errors on the bots without reporting a failure.
Originally uploaded as https://skia-review.googlesource.com/c/skia/+/161822
- Also includes SkPngCodec SafetyNet logging from
https://skia-review.googlesource.com/c/skia/+/170354
Change-Id: Ie170abf65393feb4edba60aa941f2783fe18cd8b
-rw-r--r-- | src/android/SkBitmapRegionCodec.cpp | 14 | ||||
-rw-r--r-- | src/codec/SkPngCodec.cpp | 77 | ||||
-rw-r--r-- | src/codec/SkSampledCodec.cpp | 8 |
3 files changed, 53 insertions, 46 deletions
diff --git a/src/android/SkBitmapRegionCodec.cpp b/src/android/SkBitmapRegionCodec.cpp index 6b17a9015d..682c70526a 100644 --- a/src/android/SkBitmapRegionCodec.cpp +++ b/src/android/SkBitmapRegionCodec.cpp @@ -106,10 +106,14 @@ bool SkBitmapRegionCodec::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocat SkCodec::Result result = fCodec->getAndroidPixels(decodeInfo, dst, bitmap->rowBytes(), &options); - if (SkCodec::kSuccess != result && SkCodec::kIncompleteInput != result) { - SkCodecPrintf("Error: Could not get pixels.\n"); - return false; + switch (result) { + case SkCodec::kSuccess: + case SkCodec::kIncompleteInput: + case SkCodec::kErrorInInput: + return true; + default: + SkCodecPrintf("Error: Could not get pixels with message \"%s\".\n", + SkCodec::ResultToString(result)); + return false; } - - return true; } diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp index 31a407c670..aa621380c4 100644 --- a/src/codec/SkPngCodec.cpp +++ b/src/codec/SkPngCodec.cpp @@ -25,6 +25,10 @@ #include "png.h" #include <algorithm> +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + #include "SkAndroidFrameworkUtils.h" +#endif + // This warning triggers false postives way too often in here. #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic ignored "-Wclobbered" @@ -481,6 +485,14 @@ void SkPngCodec::applyXformRow(void* dst, const void* src) { } } +static SkCodec::Result log_and_return_error(bool success) { + if (success) return SkCodec::kIncompleteInput; +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + SkAndroidFrameworkUtils::SafetyNetLog("117838472"); +#endif + return SkCodec::kErrorInInput; +} + class SkPngNormalDecoder : public SkPngCodec { public: SkPngNormalDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo, @@ -528,19 +540,16 @@ private: fFirstRow = 0; fLastRow = height - 1; - if (!this->processData()) { - return kErrorInInput; - } - - if (fRowsWrittenToOutput == height) { - return SkCodec::kSuccess; + const bool success = this->processData(); + if (success && fRowsWrittenToOutput == height) { + return kSuccess; } if (rowsDecoded) { *rowsDecoded = fRowsWrittenToOutput; } - return SkCodec::kIncompleteInput; + return log_and_return_error(success); } void allRowsCallback(png_bytep row, int rowNum) { @@ -560,25 +569,22 @@ private: fRowsNeeded = fLastRow - fFirstRow + 1; } - SkCodec::Result decode(int* rowsDecoded) override { + Result decode(int* rowsDecoded) override { if (this->swizzler()) { const int sampleY = this->swizzler()->sampleY(); fRowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY); } - if (!this->processData()) { - return kErrorInInput; - } - - if (fRowsWrittenToOutput == fRowsNeeded) { - return SkCodec::kSuccess; + const bool success = this->processData(); + if (success && fRowsWrittenToOutput == fRowsNeeded) { + return kSuccess; } if (rowsDecoded) { *rowsDecoded = fRowsWrittenToOutput; } - return SkCodec::kIncompleteInput; + return log_and_return_error(success); } void rowCallback(png_bytep row, int rowNum) { @@ -670,7 +676,7 @@ private: } } - SkCodec::Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override { + Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override { const int height = this->getInfo().height(); this->setUpInterlaceBuffer(height); png_set_progressive_read_fn(this->png_ptr(), this, nullptr, InterlacedRowCallback, @@ -680,10 +686,7 @@ private: fLastRow = height - 1; fLinesDecoded = 0; - if (!this->processData()) { - return kErrorInInput; - } - + const bool success = this->processData(); png_bytep srcRow = fInterlaceBuffer.get(); // FIXME: When resuming, this may rewrite rows that did not change. for (int rowNum = 0; rowNum < fLinesDecoded; rowNum++) { @@ -691,15 +694,15 @@ private: dst = SkTAddOffset<void>(dst, rowBytes); srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes); } - if (fInterlacedComplete) { - return SkCodec::kSuccess; + if (success && fInterlacedComplete) { + return kSuccess; } if (rowsDecoded) { *rowsDecoded = fLinesDecoded; } - return SkCodec::kIncompleteInput; + return log_and_return_error(success); } void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override { @@ -713,45 +716,45 @@ private: fLinesDecoded = 0; } - SkCodec::Result decode(int* rowsDecoded) override { - if (this->processData() == false) { - return kErrorInInput; - } + Result decode(int* rowsDecoded) override { + const bool success = this->processData(); // Now apply Xforms on all the rows that were decoded. if (!fLinesDecoded) { if (rowsDecoded) { *rowsDecoded = 0; } - return SkCodec::kIncompleteInput; + return log_and_return_error(success); } const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1; const int rowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY); - int rowsWrittenToOutput = 0; // FIXME: For resuming interlace, we may swizzle a row that hasn't changed. But it // may be too tricky/expensive to handle that correctly. // Offset srcRow by get_start_coord rows. We do not need to account for fFirstRow, // since the first row in fInterlaceBuffer corresponds to fFirstRow. - png_bytep srcRow = SkTAddOffset<png_byte>(fInterlaceBuffer.get(), - fPng_rowbytes * get_start_coord(sampleY)); + int srcRow = get_start_coord(sampleY); void* dst = fDst; - for (; rowsWrittenToOutput < rowsNeeded; rowsWrittenToOutput++) { - this->applyXformRow(dst, srcRow); + int rowsWrittenToOutput = 0; + while (rowsWrittenToOutput < rowsNeeded && srcRow < fLinesDecoded) { + png_bytep src = SkTAddOffset<png_byte>(fInterlaceBuffer.get(), fPng_rowbytes * srcRow); + this->applyXformRow(dst, src); dst = SkTAddOffset<void>(dst, fRowBytes); - srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes * sampleY); + + rowsWrittenToOutput++; + srcRow += sampleY; } - if (fInterlacedComplete) { - return SkCodec::kSuccess; + if (success && fInterlacedComplete) { + return kSuccess; } if (rowsDecoded) { *rowsDecoded = rowsWrittenToOutput; } - return SkCodec::kIncompleteInput; + return log_and_return_error(success); } void setUpInterlaceBuffer(int height) { diff --git a/src/codec/SkSampledCodec.cpp b/src/codec/SkSampledCodec.cpp index ac0539fc74..2282d6beb4 100644 --- a/src/codec/SkSampledCodec.cpp +++ b/src/codec/SkSampledCodec.cpp @@ -113,17 +113,17 @@ SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void const SkCodec::Result startResult = this->codec()->startIncrementalDecode( scaledInfo, pixels, rowBytes, &codecOptions); if (SkCodec::kSuccess == startResult) { - int rowsDecoded; + int rowsDecoded = 0; const SkCodec::Result incResult = this->codec()->incrementalDecode(&rowsDecoded); if (incResult == SkCodec::kSuccess) { return SkCodec::kSuccess; } - SkASSERT(SkCodec::kIncompleteInput == incResult); + SkASSERT(incResult == SkCodec::kIncompleteInput || incResult == SkCodec::kErrorInInput); // FIXME: Can zero initialized be read from SkCodec::fOptions? this->codec()->fillIncompleteImage(scaledInfo, pixels, rowBytes, options.fZeroInitialized, scaledSubsetHeight, rowsDecoded); - return SkCodec::kIncompleteInput; + return incResult; } else if (startResult != SkCodec::kUnimplemented) { return startResult; } @@ -244,7 +244,7 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix sampler->setSampleY(sampleY); - int rowsDecoded; + int rowsDecoded = 0; const SkCodec::Result incResult = this->codec()->incrementalDecode(&rowsDecoded); if (incResult == SkCodec::kSuccess) { return SkCodec::kSuccess; |