Fixed bad bitmap size crashes
There were 2 issues :
1 ) If the size of an SkBitmap's underlying SkPixelRef's alocated memory is too small to fit the bitmap, then the deserialization will now check this and set an error appropriately.
2 ) If a device fails to allocate its pixels, the device will be deleted and NULL will be returned to avoid attempting to draw on a bad device.
BUG=
R=senorblanco@chromium.org, reed@google.com, sugoi@google.com, halcanary@google.com, mtklein@google.com
Author: sugoi@chromium.org
Review URL: https://codereview.chromium.org/92793002
git-svn-id: http://skia.googlecode.com/svn/trunk@12484 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tests/SerializationTest.cpp b/tests/SerializationTest.cpp
index 9e63249..26c7fb0 100644
--- a/tests/SerializationTest.cpp
+++ b/tests/SerializationTest.cpp
@@ -5,8 +5,13 @@
* found in the LICENSE file.
*/
+#include "SkBitmapDevice.h"
+#include "SkBitmapSource.h"
+#include "SkCanvas.h"
+#include "SkMallocPixelRef.h"
#include "SkOrderedWriteBuffer.h"
#include "SkValidatingReadBuffer.h"
+#include "SkXfermodeImageFilter.h"
#include "Test.h"
static const uint32_t kArraySize = 64;
@@ -22,6 +27,13 @@
}
template<typename T> struct SerializationUtils {
+ // Generic case for flattenables
+ static void Write(SkOrderedWriteBuffer& writer, const T* flattenable) {
+ writer.writeFlattenable(flattenable);
+ }
+ static void Read(SkValidatingReadBuffer& reader, T** flattenable) {
+ *flattenable = (T*)reader.readFlattenable(T::GetFlattenableType());
+ }
};
template<> struct SerializationUtils<SkMatrix> {
@@ -127,6 +139,45 @@
}
template<typename T>
+static T* TestFlattenableSerialization(T* testObj, bool shouldSucceed,
+ skiatest::Reporter* reporter) {
+ SkOrderedWriteBuffer writer(1024);
+ writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag);
+ SerializationUtils<T>::Write(writer, testObj);
+ size_t bytesWritten = writer.bytesWritten();
+ REPORTER_ASSERT(reporter, SkAlign4(bytesWritten) == bytesWritten);
+
+ unsigned char dataWritten[1024];
+ writer.writeToMemory(dataWritten);
+
+ // Make sure this fails when it should (test with smaller size, but still multiple of 4)
+ SkValidatingReadBuffer buffer(dataWritten, bytesWritten - 4);
+ T* obj = NULL;
+ SerializationUtils<T>::Read(buffer, &obj);
+ REPORTER_ASSERT(reporter, !buffer.validate(true));
+ REPORTER_ASSERT(reporter, NULL == obj);
+
+ // Make sure this succeeds when it should
+ SkValidatingReadBuffer buffer2(dataWritten, bytesWritten);
+ const unsigned char* peekBefore = static_cast<const unsigned char*>(buffer2.skip(0));
+ T* obj2 = NULL;
+ SerializationUtils<T>::Read(buffer2, &obj2);
+ const unsigned char* peekAfter = static_cast<const unsigned char*>(buffer2.skip(0));
+ if (shouldSucceed) {
+ // This should have succeeded, since there are enough bytes to read this
+ REPORTER_ASSERT(reporter, buffer2.validate(true));
+ REPORTER_ASSERT(reporter, static_cast<size_t>(peekAfter - peekBefore) == bytesWritten);
+ REPORTER_ASSERT(reporter, NULL != obj2);
+ } else {
+ // If the deserialization was supposed to fail, make sure it did
+ REPORTER_ASSERT(reporter, !buffer.validate(true));
+ REPORTER_ASSERT(reporter, NULL == obj2);
+ }
+
+ return obj2; // Return object to perform further validity tests on it
+}
+
+template<typename T>
static void TestArraySerialization(T* data, skiatest::Reporter* reporter) {
SkOrderedWriteBuffer writer(1024);
writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag);
@@ -152,6 +203,35 @@
REPORTER_ASSERT(reporter, success);
}
+static void TestBitmapSerialization(const SkBitmap& validBitmap,
+ const SkBitmap& invalidBitmap,
+ bool shouldSucceed,
+ skiatest::Reporter* reporter) {
+ SkBitmapSource validBitmapSource(validBitmap);
+ SkBitmapSource invalidBitmapSource(invalidBitmap);
+ SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
+ SkXfermodeImageFilter xfermodeImageFilter(mode, &invalidBitmapSource, &validBitmapSource);
+
+ SkAutoTUnref<SkImageFilter> deserializedFilter(
+ TestFlattenableSerialization<SkImageFilter>(
+ &xfermodeImageFilter, shouldSucceed, reporter));
+
+ // Try to render a small bitmap using the invalid deserialized filter
+ // to make sure we don't crash while trying to render it
+ if (shouldSucceed) {
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 24, 24);
+ bitmap.allocPixels();
+ SkBitmapDevice device(bitmap);
+ SkCanvas canvas(&device);
+ canvas.clear(0x00000000);
+ SkPaint paint;
+ paint.setImageFilter(deserializedFilter);
+ canvas.clipRect(SkRect::MakeXYWH(0, 0, SkIntToScalar(24), SkIntToScalar(24)));
+ canvas.drawBitmap(bitmap, 0, 0, &paint);
+ }
+}
+
static void Tests(skiatest::Reporter* reporter) {
// Test matrix serialization
{
@@ -212,6 +292,29 @@
SkScalar data[kArraySize] = { SK_Scalar1, SK_ScalarHalf, SK_ScalarMax };
TestArraySerialization(data, reporter);
}
+
+ // Test invalid deserializations
+ {
+ SkBitmap validBitmap;
+ validBitmap.setConfig(SkBitmap::kARGB_8888_Config, 256, 256);
+
+ // Create a bitmap with a really large height
+ SkBitmap invalidBitmap;
+ invalidBitmap.setConfig(SkBitmap::kARGB_8888_Config, 256, 1000000000);
+
+ // The deserialization should succeed, and the rendering shouldn't crash,
+ // even when the device fails to initialize, due to its size
+ TestBitmapSerialization(validBitmap, invalidBitmap, true, reporter);
+
+ // Create a bitmap with a pixel ref too small
+ SkBitmap invalidBitmap2;
+ invalidBitmap2.setConfig(SkBitmap::kARGB_8888_Config, 256, 256);
+ invalidBitmap2.setPixelRef(SkNEW_ARGS(SkMallocPixelRef,
+ (NULL, 256, NULL)))->unref();
+
+ // The deserialization should detect the pixel ref being too small and fail
+ TestBitmapSerialization(validBitmap, invalidBitmap2, false, reporter);
+ }
}
#include "TestClassDef.h"