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 <msarett@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
diff --git a/src/codec/SkBmpBaseCodec.cpp b/src/codec/SkBmpBaseCodec.cpp
new file mode 100644
index 0000000..0e74435
--- /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 0000000..0b9f919
--- /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<uint8_t*>(fSrcBuffer.get()); }
+
+private:
+    SkAutoFree fSrcBuffer;
+
+    typedef SkBmpCodec INHERITED;
+};
+#endif // SkBmpBaseCodec_DEFINED
diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp
index 3158e99..0525d95 100644
--- a/src/codec/SkBmpCodec.cpp
+++ b/src/codec/SkBmpCodec.cpp
@@ -481,8 +481,13 @@
 
                 // 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<SkBmpStandardCodec> 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 @@
                     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<SkBmpMaskCodec> 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 9612a23..c839983 100644
--- a/src/codec/SkBmpMaskCodec.cpp
+++ b/src/codec/SkBmpMaskCodec.cpp
@@ -18,7 +18,6 @@
     : INHERITED(width, height, info, stream, bitsPerPixel, rowOrder)
     , fMasks(masks)
     , fMaskSwizzler(nullptr)
-    , fSrcBuffer(new uint8_t [this->srcRowBytes()])
 {}
 
 /*
@@ -81,7 +80,7 @@
                                            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 50e285d..2f8c060 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 @@
 
     std::unique_ptr<SkMasks>        fMasks;
     std::unique_ptr<SkMaskSwizzler> fMaskSwizzler;
-    std::unique_ptr<uint8_t[]>      fSrcBuffer;
 
-    typedef SkBmpCodec INHERITED;
+    typedef SkBmpBaseCodec INHERITED;
 };
 #endif  // SkBmpMaskCodec_DEFINED
diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp
index a0ad787..c223678 100644
--- a/src/codec/SkBmpStandardCodec.cpp
+++ b/src/codec/SkBmpStandardCodec.cpp
@@ -25,7 +25,6 @@
     , 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 @@
     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 @@
         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 @@
     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 @@
             int modulus;
             SkTDivMod(srcX, 8, &quotient, &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 740db8e..82937f3 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 @@
     const uint32_t              fBytesPerColor;
     const uint32_t              fOffset;
     std::unique_ptr<SkSwizzler> fSwizzler;
-    std::unique_ptr<uint8_t[]>  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