From d81fed9ce2b9c8f2f227cf74c2578b90aafbe196 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Thu, 1 Jun 2017 13:42:28 -0400 Subject: Replace BMP calls to new with calls to malloc A BMP can have an arbitrarily large width. We typically read a row into a block of memory before swizzling it to the output. Rather than calling new to create that block of memory, which may crash when we run out of memory, call malloc, and return null if malloc fails. Add a common base class for Mask and Standard BMP codecs. This class handles allocating and freeing the buffer. Bug: b/37623797 Change-Id: I0510b76d688d030865faa481bb2fb1351dac2c97 Reviewed-on: https://skia-review.googlesource.com/18400 Reviewed-by: Matt Sarett Commit-Queue: Leon Scroggins --- src/codec/SkBmpBaseCodec.cpp | 16 ++++++++++++++++ src/codec/SkBmpBaseCodec.h | 38 ++++++++++++++++++++++++++++++++++++++ src/codec/SkBmpCodec.cpp | 17 +++++++++++++---- src/codec/SkBmpMaskCodec.cpp | 3 +-- src/codec/SkBmpMaskCodec.h | 7 +++---- src/codec/SkBmpStandardCodec.cpp | 11 +++++------ src/codec/SkBmpStandardCodec.h | 7 +++---- 7 files changed, 79 insertions(+), 20 deletions(-) create mode 100644 src/codec/SkBmpBaseCodec.cpp create mode 100644 src/codec/SkBmpBaseCodec.h (limited to 'src') diff --git a/src/codec/SkBmpBaseCodec.cpp b/src/codec/SkBmpBaseCodec.cpp new file mode 100644 index 0000000000..0e744351f0 --- /dev/null +++ b/src/codec/SkBmpBaseCodec.cpp @@ -0,0 +1,16 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "SkBmpBaseCodec.h" +#include "../private/SkMalloc.h" + +SkBmpBaseCodec::~SkBmpBaseCodec() {} + +SkBmpBaseCodec::SkBmpBaseCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, + uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder) + : INHERITED(width, height, info, stream, bitsPerPixel, rowOrder) + , fSrcBuffer(sk_malloc_flags(this->srcRowBytes(), 0)) +{} diff --git a/src/codec/SkBmpBaseCodec.h b/src/codec/SkBmpBaseCodec.h new file mode 100644 index 0000000000..0b9f91977e --- /dev/null +++ b/src/codec/SkBmpBaseCodec.h @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkBmpBaseCodec_DEFINED +#define SkBmpBaseCodec_DEFINED + +#include "SkBmpCodec.h" +#include "SkTemplates.h" + +/* + * Common base class for SkBmpStandardCodec and SkBmpMaskCodec. + */ +class SkBmpBaseCodec : public SkBmpCodec { +public: + ~SkBmpBaseCodec() override; + + /* + * Whether fSrcBuffer was successfully created. + * + * If false, this Codec must not be used. + */ + bool didCreateSrcBuffer() const { return fSrcBuffer != nullptr; } + +protected: + SkBmpBaseCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, + uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder); + + uint8_t* srcBuffer() { return reinterpret_cast(fSrcBuffer.get()); } + +private: + SkAutoFree fSrcBuffer; + + typedef SkBmpCodec INHERITED; +}; +#endif // SkBmpBaseCodec_DEFINED diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp index 3158e992d2..0525d9530c 100644 --- a/src/codec/SkBmpCodec.cpp +++ b/src/codec/SkBmpCodec.cpp @@ -481,8 +481,13 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { // Set the image info and create a codec. const SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, bitsPerComponent); - *codecOut = new SkBmpStandardCodec(width, height, info, stream, bitsPerPixel, - numColors, bytesPerColor, offset - bytesRead, rowOrder, isOpaque, inIco); + std::unique_ptr codec(new SkBmpStandardCodec(width, height, + info, stream, bitsPerPixel, numColors, bytesPerColor, offset - bytesRead, + rowOrder, isOpaque, inIco)); + if (!codec->didCreateSrcBuffer()) { + return false; + } + *codecOut = codec.release(); } return true; } @@ -534,8 +539,12 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { alpha = SkEncodedInfo::kOpaque_Alpha; } const SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8); - *codecOut = new SkBmpMaskCodec(width, height, info, stream, bitsPerPixel, - masks.release(), rowOrder); + std::unique_ptr codec(new SkBmpMaskCodec(width, height, info, + stream, bitsPerPixel, masks.release(), rowOrder)); + if (!codec->didCreateSrcBuffer()) { + return false; + } + *codecOut = codec.release(); } return true; } diff --git a/src/codec/SkBmpMaskCodec.cpp b/src/codec/SkBmpMaskCodec.cpp index 9612a23b53..c839983d43 100644 --- a/src/codec/SkBmpMaskCodec.cpp +++ b/src/codec/SkBmpMaskCodec.cpp @@ -18,7 +18,6 @@ SkBmpMaskCodec::SkBmpMaskCodec(int width, int height, const SkEncodedInfo& info, : INHERITED(width, height, info, stream, bitsPerPixel, rowOrder) , fMasks(masks) , fMaskSwizzler(nullptr) - , fSrcBuffer(new uint8_t [this->srcRowBytes()]) {} /* @@ -81,7 +80,7 @@ int SkBmpMaskCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts) { // Iterate over rows of the image - uint8_t* srcRow = fSrcBuffer.get(); + uint8_t* srcRow = this->srcBuffer(); const int height = dstInfo.height(); for (int y = 0; y < height; y++) { // Read a row of the input diff --git a/src/codec/SkBmpMaskCodec.h b/src/codec/SkBmpMaskCodec.h index 50e285dff3..2f8c060c7a 100644 --- a/src/codec/SkBmpMaskCodec.h +++ b/src/codec/SkBmpMaskCodec.h @@ -8,7 +8,7 @@ #ifndef SkBmpMaskCodec_DEFINED #define SkBmpMaskCodec_DEFINED -#include "SkBmpCodec.h" +#include "SkBmpBaseCodec.h" #include "SkImageInfo.h" #include "SkMaskSwizzler.h" #include "SkTypes.h" @@ -16,7 +16,7 @@ /* * This class implements the decoding for bmp images using bit masks */ -class SkBmpMaskCodec : public SkBmpCodec { +class SkBmpMaskCodec : public SkBmpBaseCodec { public: /* @@ -57,8 +57,7 @@ private: std::unique_ptr fMasks; std::unique_ptr fMaskSwizzler; - std::unique_ptr fSrcBuffer; - typedef SkBmpCodec INHERITED; + typedef SkBmpBaseCodec INHERITED; }; #endif // SkBmpMaskCodec_DEFINED diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp index a0ad7875eb..c223678769 100644 --- a/src/codec/SkBmpStandardCodec.cpp +++ b/src/codec/SkBmpStandardCodec.cpp @@ -25,7 +25,6 @@ SkBmpStandardCodec::SkBmpStandardCodec(int width, int height, const SkEncodedInf , fBytesPerColor(bytesPerColor) , fOffset(offset) , fSwizzler(nullptr) - , fSrcBuffer(new uint8_t[this->srcRowBytes()]) , fIsOpaque(isOpaque) , fInIco(inIco) , fAndMaskRowBytes(fInIco ? SkAlign4(compute_row_bytes(this->getInfo().width(), 1)) : 0) @@ -231,7 +230,7 @@ int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t const int height = dstInfo.height(); for (int y = 0; y < height; y++) { // Read a row of the input - if (this->stream()->read(fSrcBuffer.get(), this->srcRowBytes()) != this->srcRowBytes()) { + if (this->stream()->read(this->srcBuffer(), this->srcRowBytes()) != this->srcRowBytes()) { SkCodecPrintf("Warning: incomplete input stream.\n"); return y; } @@ -244,10 +243,10 @@ int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t if (fXformOnDecode) { SkASSERT(this->colorXform()); SkImageInfo xformInfo = dstInfo.makeWH(fSwizzler->swizzleWidth(), dstInfo.height()); - fSwizzler->swizzle(this->xformBuffer(), fSrcBuffer.get()); + fSwizzler->swizzle(this->xformBuffer(), this->srcBuffer()); this->applyColorXform(xformInfo, dstRow, this->xformBuffer()); } else { - fSwizzler->swizzle(dstRow, fSrcBuffer.get()); + fSwizzler->swizzle(dstRow, this->srcBuffer()); } } @@ -321,7 +320,7 @@ void SkBmpStandardCodec::decodeIcoMask(SkStream* stream, const SkImageInfo& dstI SkPMColor* dstPtr = (SkPMColor*) dst; for (int y = 0; y < dstInfo.height(); y++) { // The srcBuffer will at least be large enough - if (stream->read(fSrcBuffer.get(), fAndMaskRowBytes) != fAndMaskRowBytes) { + if (stream->read(this->srcBuffer(), fAndMaskRowBytes) != fAndMaskRowBytes) { SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n"); return; } @@ -346,7 +345,7 @@ void SkBmpStandardCodec::decodeIcoMask(SkStream* stream, const SkImageInfo& dstI int modulus; SkTDivMod(srcX, 8, "ient, &modulus); uint32_t shift = 7 - modulus; - uint64_t alphaBit = (fSrcBuffer.get()[quotient] >> shift) & 0x1; + uint64_t alphaBit = (this->srcBuffer()[quotient] >> shift) & 0x1; applyMask(dstRow, dstX, alphaBit); srcX += sampleX; } diff --git a/src/codec/SkBmpStandardCodec.h b/src/codec/SkBmpStandardCodec.h index 740db8ead0..82937f385c 100644 --- a/src/codec/SkBmpStandardCodec.h +++ b/src/codec/SkBmpStandardCodec.h @@ -7,7 +7,7 @@ #ifndef SkBmpStandardCodec_DEFINED #define SkBmpStandardCodec_DEFINED -#include "SkBmpCodec.h" +#include "SkBmpBaseCodec.h" #include "SkColorTable.h" #include "SkImageInfo.h" #include "SkSwizzler.h" @@ -17,7 +17,7 @@ * This class implements the decoding for bmp images that use "standard" modes, * which essentially means they do not contain bit masks or RLE codes. */ -class SkBmpStandardCodec : public SkBmpCodec { +class SkBmpStandardCodec : public SkBmpBaseCodec { public: /* @@ -92,12 +92,11 @@ private: const uint32_t fBytesPerColor; const uint32_t fOffset; std::unique_ptr fSwizzler; - std::unique_ptr fSrcBuffer; const bool fIsOpaque; const bool fInIco; const size_t fAndMaskRowBytes; // only used for fInIco decodes bool fXformOnDecode; - typedef SkBmpCodec INHERITED; + typedef SkBmpBaseCodec INHERITED; }; #endif // SkBmpStandardCodec_DEFINED -- cgit v1.2.3