Bug 368675 - limit maximum size of filtered surface. r=dveditz, sr=roc
authortor@cs.brown.edu
Tue, 17 Apr 2007 12:34:52 -0700
changeset 597 19fd0f380b34d2c5ec9680efdce0b4259da7d8f3
parent 596 db2231af02eb5b62a7f9f7a92bbb66f5e32f0db2
child 598 c8818f341ad42599b0f4d1c76f20c7844893b0ef
push idunknown
push userunknown
push dateunknown
reviewersdveditz, roc
bugs368675
milestone1.9a4pre
Bug 368675 - limit maximum size of filtered surface. r=dveditz, sr=roc
layout/svg/base/src/nsSVGFilterFrame.cpp
--- a/layout/svg/base/src/nsSVGFilterFrame.cpp
+++ b/layout/svg/base/src/nsSVGFilterFrame.cpp
@@ -46,16 +46,23 @@
 #include "nsSVGUtils.h"
 #include "nsSVGFilterElement.h"
 #include "nsSVGFilterInstance.h"
 #include "nsSVGFilters.h"
 #include "gfxASurface.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 
+// maximum dimension of a filter - choose so that
+// 4*(FILTER_RES_MAX^2) < UINT_MAX, it's small
+// enough that it could be computed in a reasonable
+// amount of time, and large enough for most content
+// window sizes.
+#define FILTER_RES_MAX 16384
+
 nsIFrame*
 NS_NewSVGFilterFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContext* aContext)
 {
   return new (aPresShell) nsSVGFilterFrame(aContext);
 }
 
 nsIContent *
 NS_GetSVGFilterElement(nsIURI *aURI, nsIContent *aContent)
@@ -192,33 +199,37 @@ nsSVGFilterFrame::FilterPaint(nsSVGRende
     filter->GetFilterResY(getter_AddRefs(filterRes));
     filterRes->GetAnimVal(&filterResY);
   }
 
   // filterRes = 0 disables rendering, < 0 is error
   if (filterResX <= 0.0f || filterResY <= 0.0f)
     return NS_OK;
 
+  // prevent filters from overflowing or generally using excessive memory
+  filterResX = PR_MIN(FILTER_RES_MAX, filterResX);
+  filterResY = PR_MIN(FILTER_RES_MAX, filterResY);
+
 #ifdef DEBUG_tor
   fprintf(stderr, "filter bbox: %f,%f  %fx%f\n", x, y, width, height);
   fprintf(stderr, "filterRes: %u %u\n", filterResX, filterResY);
 #endif
 
   nsCOMPtr<nsIDOMSVGMatrix> filterTransform;
   NS_NewSVGMatrix(getter_AddRefs(filterTransform),
                   filterResX/width,  0.0f,
                   0.0f,              filterResY/height,
                   -x*filterResX/width,                 -y*filterResY/height);
   aTarget->SetOverrideCTM(filterTransform);
   aTarget->NotifyCanvasTMChanged(PR_TRUE);
 
   // paint the target geometry
   nsRefPtr<gfxImageSurface> tmpSurface =
     new gfxImageSurface(gfxIntSize(filterResX, filterResY), gfxASurface::ImageFormatARGB32);
-  if (!tmpSurface) {
+  if (!tmpSurface || !tmpSurface->Data()) {
     FilterFailCleanup(aContext, aTarget);
     return NS_OK;
   }
 
   gfxContext tmpContext(tmpSurface);
   nsSVGRenderState tmpState(&tmpContext);
 
   memset(tmpSurface->Data(), 0, tmpSurface->GetSize().height * tmpSurface->Stride());
@@ -234,27 +245,29 @@ nsSVGFilterFrame::FilterPaint(nsSVGRende
     colorModel(nsSVGFilterInstance::ColorModel::SRGB,
                nsSVGFilterInstance::ColorModel::PREMULTIPLIED);
 
   if (requirements & NS_FE_SOURCEALPHA) {
     cairo_surface_t *alpha =
       cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
                                  filterResX, filterResY);
 
-    if (!alpha) {
+    if (!alpha || cairo_surface_status(alpha)) {
+      if (alpha)
+        cairo_surface_destroy(alpha);
       FilterFailCleanup(aContext, aTarget);
       return NS_OK;
     }
 
     PRUint8 *data = tmpSurface->Data();
     PRUint8 *alphaData = cairo_image_surface_get_data(alpha);
     PRUint32 stride = tmpSurface->Stride();
 
-    for (PRUint32 yy=0; yy<filterResY; yy++)
-      for (PRUint32 xx=0; xx<filterResX; xx++) {
+    for (PRUint32 yy = 0; yy < PRUint32(filterResY); yy++)
+      for (PRUint32 xx = 0; xx < PRUint32(filterResX); xx++) {
         alphaData[stride*yy + 4*xx + GFX_ARGB32_OFFSET_B] = 0;
         alphaData[stride*yy + 4*xx + GFX_ARGB32_OFFSET_G] = 0;
         alphaData[stride*yy + 4*xx + GFX_ARGB32_OFFSET_R] = 0;
         alphaData[stride*yy + 4*xx + GFX_ARGB32_OFFSET_A] =
           data[stride*yy + 4*xx + 3];
     }
 
     instance.DefineImage(NS_LITERAL_STRING("SourceAlpha"), alpha,
@@ -495,18 +508,25 @@ nsSVGFilterInstance::GetFilterSubregion(
   fprintf(stderr, "GFS[3]: %d %d %d %d\n",
           result->x, result->y, result->width, result->height);
 #endif
 }
 
 cairo_surface_t *
 nsSVGFilterInstance::GetImage()
 {
-  return cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
-                                    mFilterResX, mFilterResY);
+  cairo_surface_t *surface =
+    cairo_image_surface_create(CAIRO_FORMAT_ARGB32, mFilterResX, mFilterResY);
+
+  if (surface && cairo_surface_status(surface)) {
+    cairo_surface_destroy(surface);
+    surface = nsnull;
+  }
+
+  return surface;
 }
 
 void
 nsSVGFilterInstance::LookupImage(const nsAString &aName,
                                  cairo_surface_t **aImage,
                                  nsRect *aRegion,
                                  const ColorModel &aRequiredColorModel)
 {