Bug 1023336, part 1 - Add a Moz2D helper to consistently limit the size of data-wrapping DataSourceSurface buffers. r=Bas, a=1.3+
authorJonathan Watt <jwatt@jwatt.org>
Tue, 08 Jul 2014 21:28:48 +0100
changeset 171595 2dcf2952d2c356df7f8d4c78f7f40b4aa5e29aa3
parent 171594 45ae726b1d909b17824c0dcde32deaf900980a1f
child 171596 601d27e413a936d32633cba67112287351a6fce2
push id578
push userjwatt@jwatt.org
push dateTue, 08 Jul 2014 22:46:56 +0000
reviewersBas, 1.3
bugs1023336
milestone28.0
Bug 1023336, part 1 - Add a Moz2D helper to consistently limit the size of data-wrapping DataSourceSurface buffers. r=Bas, a=1.3+
gfx/2d/DataSurfaceHelpers.cpp
gfx/2d/DataSurfaceHelpers.h
gfx/2d/moz.build
new file mode 100644
--- /dev/null
+++ b/gfx/2d/DataSurfaceHelpers.cpp
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "2D.h"
+#include "DataSurfaceHelpers.h"
+#include "Logging.h"
+#include "mozilla/CheckedInt.h"
+#include "mozilla/MathAlgorithms.h"
+
+namespace mozilla {
+namespace gfx {
+
+size_t
+BufferSizeFromStrideAndHeight(int32_t aStride,
+                              int32_t aHeight,
+                              int32_t aExtraBytes)
+{
+  if (MOZ_UNLIKELY(aHeight <= 0)) {
+    return 0;
+  }
+
+  // We limit the length returned to values that can be represented by int32_t
+  // because we don't want to allocate buffers any bigger than that. This
+  // allows for a buffer size of over 2 GiB which is already rediculously
+  // large and will make the process janky. (Note the choice of the signed type
+  // is deliberate because we specifically don't want the returned value to
+  // overflow if someone stores the buffer length in an int32_t variable.)
+
+  CheckedInt32 requiredBytes =
+    CheckedInt32(aStride) * CheckedInt32(aHeight) + CheckedInt32(aExtraBytes);
+  if (MOZ_UNLIKELY(!requiredBytes.isValid())) {
+    gfxWarning() << "Buffer size too big; returning zero";
+    return 0;
+  }
+  return requiredBytes.value();
+}
+
+}
+}
+
--- a/gfx/2d/DataSurfaceHelpers.h
+++ b/gfx/2d/DataSurfaceHelpers.h
@@ -71,10 +71,26 @@ SurfaceToPackedBGRA(SourceSurface *aSurf
   if (format == FORMAT_B8G8R8X8) {
     // Convert BGRX to BGRA by setting a to 255.
     ConvertBGRXToBGRA(reinterpret_cast<uint8_t *>(imageBuffer), size, size.width * sizeof(uint32_t));
   }
 
   return imageBuffer;
 }
 
+/**
+ * Multiplies aStride and aHeight and makes sure the result is limited to
+ * something sane. To keep things consistent, this should always be used
+ * wherever we allocate a buffer based on surface stride and height.
+ *
+ * @param aExtra Optional argument to specify an additional number of trailing
+ *   bytes (useful for creating intermediate surfaces for filters, for
+ *   example).
+ *
+ * @return The result of the multiplication if it is acceptable, or else zero.
+ */
+size_t
+BufferSizeFromStrideAndHeight(int32_t aStride,
+                              int32_t aHeight,
+                              int32_t aExtraBytes = 0);
+
 }
 }
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -89,16 +89,17 @@ if CONFIG['INTEL_ARCHITECTURE']:
             'FilterProcessingSSE2.cpp',
             'ImageScalingSSE2.cpp',
         ]
         DEFINES['USE_SSE2'] = True
 
 UNIFIED_SOURCES += [
     'Blur.cpp',
     'DataSourceSurface.cpp',
+    'DataSurfaceHelpers.cpp',
     'DrawEventRecorder.cpp',
     'DrawTargetCairo.cpp',
     'DrawTargetDual.cpp',
     'DrawTargetRecording.cpp',
     'Factory.cpp',
     'FilterNodeSoftware.cpp',
     'FilterProcessing.cpp',
     'FilterProcessingScalar.cpp',