summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorM Joonas Pihlaja <jpihlaja@cc.helsinki.fi>2009-09-03 19:18:07 +0300
committerM Joonas Pihlaja <jpihlaja@cc.helsinki.fi>2009-09-03 19:27:24 +0300
commit9e45673e197d0f43e296483cc6b5ca6df94e7f02 (patch)
tree0373403303cc677f2e7c022e0103ae73a7d1fde3
parent12d0613210547b8a50dd7b21a12eb1485ee496b9 (diff)
[image] Check for out of bounds image surface sizes in constructors.
The image surface code doesn't reliably work on images larger than 32767 in width or height. This patch makes the image surface constructors fail by returning a surface in the CAIRO_STATUS_INVALID_SIZE state when given negative or too large dimensions so that client code gets a prompt and correct error rather than flaky rendering on large images.
-rw-r--r--src/cairo-image-surface.c27
-rw-r--r--test/large-source-roi.c4
-rw-r--r--test/large-source-roi.ref.pngbin0 -> 112 bytes
-rw-r--r--test/large-source.c4
4 files changed, 29 insertions, 6 deletions
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 1d778cdb7..b35905f5f 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -40,6 +40,18 @@
#include "cairo-clip-private.h"
#include "cairo-region-private.h"
+/* Limit on the width / height of an image surface in pixels. This is
+ * mainly determined by coordinates of things sent to pixman at the
+ * moment being in 16.16 format. */
+#define MAX_IMAGE_SIZE 32767
+
+static cairo_bool_t
+_cairo_image_surface_is_size_valid (int width, int height)
+{
+ return 0 <= width && width <= MAX_IMAGE_SIZE &&
+ 0 <= height && height <= MAX_IMAGE_SIZE;
+}
+
static cairo_format_t
_cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
{
@@ -152,6 +164,12 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
pixman_format_code_t pixman_format)
{
cairo_image_surface_t *surface;
+ int width = pixman_image_get_width (pixman_image);
+ int height = pixman_image_get_height (pixman_image);
+
+ if (! _cairo_image_surface_is_size_valid (width, height)) {
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
+ }
surface = malloc (sizeof (cairo_image_surface_t));
if (unlikely (surface == NULL))
@@ -168,8 +186,8 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
surface->owns_data = FALSE;
surface->transparency = CAIRO_IMAGE_UNKNOWN;
- surface->width = pixman_image_get_width (pixman_image);
- surface->height = pixman_image_get_height (pixman_image);
+ surface->width = width;
+ surface->height = height;
surface->stride = pixman_image_get_stride (pixman_image);
surface->depth = pixman_image_get_depth (pixman_image);
surface->is_clear = FALSE;
@@ -349,6 +367,11 @@ _cairo_image_surface_create_with_pixman_format (unsigned char *data,
cairo_surface_t *surface;
pixman_image_t *pixman_image;
+ if (! _cairo_image_surface_is_size_valid (width, height))
+ {
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
+ }
+
pixman_image = pixman_image_create_bits (pixman_format, width, height,
(uint32_t *) data, stride);
diff --git a/test/large-source-roi.c b/test/large-source-roi.c
index 8709e4b47..e429f989c 100644
--- a/test/large-source-roi.c
+++ b/test/large-source-roi.c
@@ -47,7 +47,7 @@ static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
cairo_surface_t *source;
- double source_width = 66000.0;
+ double source_width = 32767.0;
cairo_set_source_rgb (cr, 1,1,1);
cairo_paint (cr);
@@ -72,5 +72,5 @@ CAIRO_TEST (large_source_roi,
"Uses a all of a large source image.",
"stress, source", /* keywords */
NULL, /* requirements */
- 20, 20,
+ 7, 7,
NULL, draw)
diff --git a/test/large-source-roi.ref.png b/test/large-source-roi.ref.png
new file mode 100644
index 000000000..b8dc8b1b6
--- /dev/null
+++ b/test/large-source-roi.ref.png
Binary files differ
diff --git a/test/large-source.c b/test/large-source.c
index 5b2254cc2..b02b493a5 100644
--- a/test/large-source.c
+++ b/test/large-source.c
@@ -49,7 +49,7 @@ draw (cairo_t *cr, int width, int height)
cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
cairo_paint (cr);
- surface = cairo_image_surface_create (CAIRO_FORMAT_A1, 64000, 20);
+ surface = cairo_image_surface_create (CAIRO_FORMAT_A1, 32000, 20);
data = cairo_image_surface_get_data (surface);
if (data != NULL) {
int stride = cairo_image_surface_get_stride (surface);
@@ -68,7 +68,7 @@ draw (cairo_t *cr, int width, int height)
cairo_mask_surface (cr, surface, 0, 0);
cairo_surface_destroy (surface);
- surface = cairo_image_surface_create (CAIRO_FORMAT_A1, 20, 64000);
+ surface = cairo_image_surface_create (CAIRO_FORMAT_A1, 20, 32000);
data = cairo_image_surface_get_data (surface);
if (data != NULL) {
int stride = cairo_image_surface_get_stride (surface);