Port of https://skia.googlesource.com/skia.git/+/3a49520696b2eca69e57884657d23fd2402ccfd1 to M38 branch.
Sanitize SkMatrixConvolutionImageFilter creation params.
Apply the same memory limit in the Create() function that we do when
deserializing.
Author: senorblanco@chromium.org
Review URL: https://codereview.chromium.org/610723002
BUG=skia:
TBR=reed@google.com
Review URL: https://codereview.chromium.org/612483005
diff --git a/include/effects/SkMatrixConvolutionImageFilter.h b/include/effects/SkMatrixConvolutionImageFilter.h
index 0cb848b..f021bf0 100644
--- a/include/effects/SkMatrixConvolutionImageFilter.h
+++ b/include/effects/SkMatrixConvolutionImageFilter.h
@@ -60,11 +60,7 @@
TileMode tileMode,
bool convolveAlpha,
SkImageFilter* input = NULL,
- const CropRect* cropRect = NULL) {
- return SkNEW_ARGS(SkMatrixConvolutionImageFilter, (kernelSize, kernel, gain, bias,
- kernelOffset, tileMode, convolveAlpha,
- input, cropRect));
- }
+ const CropRect* cropRect = NULL);
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMatrixConvolutionImageFilter)
diff --git a/src/effects/SkMatrixConvolutionImageFilter.cpp b/src/effects/SkMatrixConvolutionImageFilter.cpp
index 6e1d1a4..f617742 100644
--- a/src/effects/SkMatrixConvolutionImageFilter.cpp
+++ b/src/effects/SkMatrixConvolutionImageFilter.cpp
@@ -29,6 +29,10 @@
return false;
}
+// We need to be able to read at most SK_MaxS32 bytes, so divide that
+// by the size of a scalar to know how many scalars we can read.
+static const int32_t gMaxKernelSize = SK_MaxS32 / sizeof(SkScalar);
+
SkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(
const SkISize& kernelSize,
const SkScalar* kernel,
@@ -46,7 +50,7 @@
fKernelOffset(kernelOffset),
fTileMode(tileMode),
fConvolveAlpha(convolveAlpha) {
- uint32_t size = fKernelSize.fWidth * fKernelSize.fHeight;
+ size_t size = (size_t) sk_64_mul(fKernelSize.width(), fKernelSize.height());
fKernel = SkNEW_ARRAY(SkScalar, size);
memcpy(fKernel, kernel, size * sizeof(SkScalar));
SkASSERT(kernelSize.fWidth >= 1 && kernelSize.fHeight >= 1);
@@ -54,18 +58,39 @@
SkASSERT(kernelOffset.fY >= 0 && kernelOffset.fY < kernelSize.fHeight);
}
+SkMatrixConvolutionImageFilter* SkMatrixConvolutionImageFilter::Create(
+ const SkISize& kernelSize,
+ const SkScalar* kernel,
+ SkScalar gain,
+ SkScalar bias,
+ const SkIPoint& kernelOffset,
+ TileMode tileMode,
+ bool convolveAlpha,
+ SkImageFilter* input,
+ const CropRect* cropRect) {
+ if (kernelSize.width() < 1 || kernelSize.height() < 1) {
+ return NULL;
+ }
+ if (gMaxKernelSize / kernelSize.fWidth < kernelSize.fHeight) {
+ return NULL;
+ }
+ if (!kernel) {
+ return NULL;
+ }
+ return SkNEW_ARGS(SkMatrixConvolutionImageFilter, (kernelSize, kernel, gain, bias,
+ kernelOffset, tileMode, convolveAlpha,
+ input, cropRect));
+}
+
SkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(SkReadBuffer& buffer)
: INHERITED(1, buffer) {
- // We need to be able to read at most SK_MaxS32 bytes, so divide that
- // by the size of a scalar to know how many scalars we can read.
- static const int32_t kMaxSize = SK_MaxS32 / sizeof(SkScalar);
fKernelSize.fWidth = buffer.readInt();
fKernelSize.fHeight = buffer.readInt();
if ((fKernelSize.fWidth >= 1) && (fKernelSize.fHeight >= 1) &&
// Make sure size won't be larger than a signed int,
// which would still be extremely large for a kernel,
// but we don't impose a hard limit for kernel size
- (kMaxSize / fKernelSize.fWidth >= fKernelSize.fHeight)) {
+ (gMaxKernelSize / fKernelSize.fWidth >= fKernelSize.fHeight)) {
size_t size = fKernelSize.fWidth * fKernelSize.fHeight;
fKernel = SkNEW_ARRAY(SkScalar, size);
SkDEBUGCODE(bool success =) buffer.readScalarArray(fKernel, size);
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index 9f6144b..8767ff2 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -774,6 +774,60 @@
test_huge_blur(&device, reporter);
}
+DEF_TEST(MatrixConvolutionSanityTest, reporter) {
+ SkScalar kernel[1] = { 0 };
+ SkScalar gain = SK_Scalar1, bias = 0;
+ SkIPoint kernelOffset = SkIPoint::Make(1, 1);
+
+ // Check that an enormous (non-allocatable) kernel gives a NULL filter.
+ SkAutoTUnref<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Create(
+ SkISize::Make(1<<30, 1<<30),
+ kernel,
+ gain,
+ bias,
+ kernelOffset,
+ SkMatrixConvolutionImageFilter::kRepeat_TileMode,
+ false));
+
+ REPORTER_ASSERT(reporter, NULL == conv.get());
+
+ // Check that a NULL kernel gives a NULL filter.
+ conv.reset(SkMatrixConvolutionImageFilter::Create(
+ SkISize::Make(1, 1),
+ NULL,
+ gain,
+ bias,
+ kernelOffset,
+ SkMatrixConvolutionImageFilter::kRepeat_TileMode,
+ false));
+
+ REPORTER_ASSERT(reporter, NULL == conv.get());
+
+ // Check that a kernel width < 1 gives a NULL filter.
+ conv.reset(SkMatrixConvolutionImageFilter::Create(
+ SkISize::Make(0, 1),
+ kernel,
+ gain,
+ bias,
+ kernelOffset,
+ SkMatrixConvolutionImageFilter::kRepeat_TileMode,
+ false));
+
+ REPORTER_ASSERT(reporter, NULL == conv.get());
+
+ // Check that kernel height < 1 gives a NULL filter.
+ conv.reset(SkMatrixConvolutionImageFilter::Create(
+ SkISize::Make(1, -1),
+ kernel,
+ gain,
+ bias,
+ kernelOffset,
+ SkMatrixConvolutionImageFilter::kRepeat_TileMode,
+ false));
+
+ REPORTER_ASSERT(reporter, NULL == conv.get());
+}
+
static void test_xfermode_cropped_input(SkBaseDevice* device, skiatest::Reporter* reporter) {
SkCanvas canvas(device);
canvas.clear(0);