Bug 1023336, part 1 - Add a Moz2D helper to consistently limit the size of data-wrapping DataSourceSurface buffers. r=Bas, a=sylvestre
authorJonathan Watt <jwatt@jwatt.org>
Wed, 02 Jul 2014 11:41:13 +0100
changeset 207563 072b0d1c3098e447a9f09009e424c7a92475f215
parent 207562 64e35d6863d15b64b72450e58bd70957db6ff059
child 207564 a6e69640a00bd186337531fd4d6b2c6e0d60fa04
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas, sylvestre
bugs1023336
milestone32.0a2
Bug 1023336, part 1 - Add a Moz2D helper to consistently limit the size of data-wrapping DataSourceSurface buffers. r=Bas, a=sylvestre
gfx/2d/DataSurfaceHelpers.cpp
gfx/2d/DataSurfaceHelpers.h
--- a/gfx/2d/DataSurfaceHelpers.cpp
+++ b/gfx/2d/DataSurfaceHelpers.cpp
@@ -2,16 +2,19 @@
  * 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 <cstring>
 
 #include "2D.h"
 #include "DataSurfaceHelpers.h"
+#include "Logging.h"
+#include "mozilla/CheckedInt.h"
+#include "mozilla/MathAlgorithms.h"
 #include "Tools.h"
 
 namespace mozilla {
 namespace gfx {
 
 void
 ConvertBGRXToBGRA(uint8_t* aData, const IntSize &aSize, int32_t aStride)
 {
@@ -162,10 +165,35 @@ ClearDataSourceSurface(DataSourceSurface
   while (row != end) {
     memset(row, 0, bytesPerRow);
     row += map.mStride;
   }
 
   aSurface->Unmap();
 }
 
+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
@@ -47,12 +47,28 @@ SurfaceToPackedBGR(DataSourceSurface *aS
 
 /**
  * Clears all the bytes in a DataSourceSurface's data array to zero (so to
  * transparent black for SurfaceFormat::B8G8R8A8, for example).
  */
 void
 ClearDataSourceSurface(DataSourceSurface *aSurface);
 
+/**
+ * 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);
+
 }
 }
 
 #endif // _MOZILLA_GFX_DATASURFACEHELPERS_H