MallocPixelRef should always allocate as large as computeByteSize() says

Bug: 1103827
Change-Id: I837f92cf10a1a389fe1b0ba55ae1323e7e68f741
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/304416
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/src/core/SkMallocPixelRef.cpp b/src/core/SkMallocPixelRef.cpp
index d998029..02fd9c4 100644
--- a/src/core/SkMallocPixelRef.cpp
+++ b/src/core/SkMallocPixelRef.cpp
@@ -30,12 +30,9 @@
     if (!is_valid(info) || !info.validRowBytes(rowBytes)) {
         return nullptr;
     }
-    size_t size = 0;
-    if (!info.isEmpty() && rowBytes) {
-        size = info.computeByteSize(rowBytes);
-        if (SkImageInfo::ByteSizeOverflowed(size)) {
-            return nullptr;
-        }
+    size_t size = info.computeByteSize(rowBytes);
+    if (SkImageInfo::ByteSizeOverflowed(size)) {
+        return nullptr;
     }
     void* addr = sk_calloc_canfail(size);
     if (nullptr == addr) {
diff --git a/tests/BitmapTest.cpp b/tests/BitmapTest.cpp
index 680c1d0..be1f3c7 100644
--- a/tests/BitmapTest.cpp
+++ b/tests/BitmapTest.cpp
@@ -412,3 +412,38 @@
         }
     }
 }
+
+/*  computeByteSize() is documented to return 0 if height is zero, but does not
+ *  special-case width==0, so computeByteSize() can return non-zero for that
+ *  (since it is defined to return (height-1)*rb + ...
+ *
+ *  Test that allocPixels() respects this, and allocates a buffer as large as
+ *  computeByteSize()... even though the bitmap is logicallly empty.
+ */
+DEF_TEST(bitmap_zerowidth_crbug_1103827, reporter) {
+    const size_t big_rb = 1 << 16;
+
+    struct {
+        int width, height;
+        size_t rowbytes, expected_size;
+    } rec[] = {
+        { 2, 0,     big_rb,         0 },    // zero-height means zero-size
+        { 0, 2,     big_rb,    big_rb },    // zero-width is computed normally
+    };
+
+    for (const auto& r : rec) {
+        auto info = SkImageInfo::Make(r.width, r.height,
+                                      kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+        size_t size = info.computeByteSize(r.rowbytes);
+        REPORTER_ASSERT(reporter, size == r.expected_size);
+
+        SkBitmap bm;
+        bm.setInfo(info, r.rowbytes);
+        REPORTER_ASSERT(reporter, size == bm.computeByteSize());
+
+        // Be sure we can actually write to that much memory. If the bitmap underallocated
+        // the buffer, this should trash memory and crash (we hope).
+        bm.allocPixels();
+        sk_bzero(bm.getPixels(), size);
+    }
+}