aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeon Scroggins III <scroggo@google.com>2018-10-16 15:29:11 -0400
committerLeon Scroggins <scroggo@google.com>2018-11-26 19:57:38 +0000
commitfc165d5cccf133574058cd0c5ba3a95ea6ad2bb8 (patch)
tree26201d60e503cb4167217b435484cc02493e9cf9
parent2277702eee7eb6e99002b6b5248254fe9ffd5f76 (diff)
downloadskia-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.cpp14
-rw-r--r--src/codec/SkPngCodec.cpp77
-rw-r--r--src/codec/SkSampledCodec.cpp8
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;