summaryrefslogtreecommitdiff
path: root/source/fitz/draw-device.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2014-06-09 17:51:34 +0100
committerRobin Watts <robin.watts@artifex.com>2014-06-09 17:55:30 +0100
commitfdea617e38c4d4579b4edcc9ffaf7e4a8b067d6f (patch)
treed73ec93dd5025df974ffe1cbb615eb205f66c938 /source/fitz/draw-device.c
parenta6f0d56d2d2e66cef2b4ca6e810bf3630ed53d0b (diff)
downloadmupdf-fdea617e38c4d4579b4edcc9ffaf7e4a8b067d6f.tar.xz
Bug 695300: Sanitize draw-device stack handling in error cases.
When throwing an error during fz_alpha_from_gray, the stack depth can get confused. Fix this by moving some more code into the appropriate fz_try(). In the course of fixing this bug, I added some new optional debug code to display the stack level as it runs. This is committed here disabled; just change the appropriate #define in draw-device.c to enable it. Also, add some code to run_xobject, to avoid throwing in an fz_always() clause.
Diffstat (limited to 'source/fitz/draw-device.c')
-rw-r--r--source/fitz/draw-device.c68
1 files changed, 55 insertions, 13 deletions
diff --git a/source/fitz/draw-device.c b/source/fitz/draw-device.c
index c5354e61..4592f8cf 100644
--- a/source/fitz/draw-device.c
+++ b/source/fitz/draw-device.c
@@ -10,6 +10,9 @@
/* Enable the following to help debug group blending. */
#undef DUMP_GROUP_BLENDS
+/* Enable the following to help debug graphics stack pushes/pops */
+#undef DUMP_STACK_CHANGES
+
typedef struct fz_draw_device_s fz_draw_device;
enum {
@@ -73,6 +76,30 @@ static void dump_spaces(int x, const char *s)
#endif
+#ifdef DUMP_STACK_CHANGES
+#define STACK_PUSHED(A) stack_change(dev, ">" ## A)
+#define STACK_POPPED(A) stack_change(dev, "<" ## A)
+#define STACK_CONVERT(A) stack_change(dev, A)
+
+static void stack_change(fz_draw_device *dev, char *s)
+{
+ int depth = dev->top;
+ int n;
+
+ if (*s != '<')
+ depth--;
+ n = depth;
+ while (n--)
+ fputc(' ', stderr);
+ fprintf(stderr, "%s (%d)\n", s, depth);
+}
+#else
+#define STACK_PUSHED(A) do {} while (0)
+#define STACK_POPPED(A) do {} while (0)
+#define STACK_CONVERT(A) do {} while (0)
+#endif
+
+
static void fz_grow_stack(fz_draw_device *dev)
{
int max = dev->stack_cap * 2;
@@ -118,6 +145,7 @@ static void emergency_pop_stack(fz_draw_device *dev, fz_draw_state *state)
if (state[1].shape != state[0].shape)
fz_drop_pixmap(ctx, state[1].shape);
dev->top--;
+ STACK_POPPED("emergency");
fz_rethrow(ctx);
}
@@ -134,6 +162,7 @@ fz_knockout_begin(fz_draw_device *dev)
return state;
state = push_stack(dev);
+ STACK_PUSHED("knockout");
fz_pixmap_bbox(dev->ctx, state->dest, &bbox);
fz_intersect_irect(&bbox, &state->scissor);
@@ -195,6 +224,7 @@ static void fz_knockout_end(fz_draw_device *dev)
return;
}
state = &dev->stack[--dev->top];
+ STACK_POPPED("knockout");
if ((state[0].blendmode & FZ_BLEND_KNOCKOUT) == 0)
return;
@@ -371,6 +401,7 @@ fz_draw_clip_path(fz_device *devp, fz_path *path, const fz_rect *rect, int even_
fz_sort_gel(dev->gel);
state = push_stack(dev);
+ STACK_PUSHED("clip path");
model = state->dest->colorspace;
fz_intersect_irect(fz_bound_gel(dev->gel, &bbox), &state->scissor);
@@ -441,6 +472,7 @@ fz_draw_clip_stroke_path(fz_device *devp, fz_path *path, const fz_rect *rect, fz
fz_sort_gel(dev->gel);
state = push_stack(dev);
+ STACK_PUSHED("clip stroke");
model = state->dest->colorspace;
fz_intersect_irect(fz_bound_gel(dev->gel, &bbox), &state->scissor);
@@ -681,6 +713,7 @@ fz_draw_clip_text(fz_device *devp, fz_text *text, const fz_matrix *ctm, int accu
/* If accumulate == 2 then this text object is a continuation */
state = push_stack(dev);
+ STACK_PUSHED("clip text");
model = state->dest->colorspace;
if (accumulate == 0)
@@ -726,6 +759,7 @@ fz_draw_clip_text(fz_device *devp, fz_text *text, const fz_matrix *ctm, int accu
{
mask = state->mask;
dev->top--;
+ STACK_POPPED("clip text");
}
if (!fz_is_empty_irect(&bbox) && mask)
@@ -808,6 +842,7 @@ fz_draw_clip_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke
fz_colorspace *model = state->dest->colorspace;
fz_rect rect;
+ STACK_PUSHED("clip stroke text");
/* make the mask the exact size needed */
fz_irect_from_rect(&bbox, fz_bound_text(dev->ctx, text, stroke, ctm, &rect));
fz_intersect_irect(&bbox, &state->scissor);
@@ -1250,6 +1285,7 @@ fz_draw_clip_image_mask(fz_device *devp, fz_image *image, const fz_rect *rect, c
fz_matrix local_ctm = *ctm;
fz_rect urect;
+ STACK_PUSHED("clip image mask");
fz_pixmap_bbox(ctx, state->dest, &clip);
fz_intersect_irect(&clip, &state->scissor);
@@ -1345,6 +1381,7 @@ fz_draw_pop_clip(fz_device *devp)
return;
}
state = &dev->stack[--dev->top];
+ STACK_POPPED("clip");
/* We can get here with state[1].mask == NULL if the clipping actually
* resolved to a rectangle earlier.
@@ -1399,6 +1436,7 @@ fz_draw_begin_mask(fz_device *devp, const fz_rect *rect, int luminosity, fz_colo
fz_pixmap *shape = state->shape;
fz_context *ctx = dev->ctx;
+ STACK_PUSHED("mask");
fz_intersect_irect(fz_irect_from_rect(&bbox, rect), &state->scissor);
fz_try(ctx)
@@ -1460,33 +1498,33 @@ fz_draw_end_mask(fz_device *devp)
return;
}
state = &dev->stack[dev->top-1];
+ STACK_CONVERT("(mask)");
/* pop soft mask buffer */
luminosity = state[1].luminosity;
#ifdef DUMP_GROUP_BLENDS
dump_spaces(dev->top-1, "Mask -> Clip\n");
#endif
- /* convert to alpha mask */
- temp = fz_alpha_from_gray(dev->ctx, state[1].dest, luminosity);
- if (state[1].dest != state[0].dest)
- fz_drop_pixmap(dev->ctx, state[1].dest);
- state[1].dest = NULL;
- if (state[1].shape != state[0].shape)
- fz_drop_pixmap(dev->ctx, state[1].shape);
- state[1].shape = NULL;
- if (state[1].mask != state[0].mask)
- fz_drop_pixmap(dev->ctx, state[1].mask);
- state[1].mask = NULL;
-
fz_try(ctx)
{
+ /* convert to alpha mask */
+ temp = fz_alpha_from_gray(dev->ctx, state[1].dest, luminosity);
+ if (state[1].mask != state[0].mask)
+ fz_drop_pixmap(dev->ctx, state[1].mask);
+ state[1].mask = temp;
+ if (state[1].dest != state[0].dest)
+ fz_drop_pixmap(dev->ctx, state[1].dest);
+ state[1].dest = NULL;
+ if (state[1].shape != state[0].shape)
+ fz_drop_pixmap(dev->ctx, state[1].shape);
+ state[1].shape = NULL;
+
/* create new dest scratch buffer */
fz_pixmap_bbox(ctx, temp, &bbox);
dest = fz_new_pixmap_with_bbox(dev->ctx, state->dest->colorspace, &bbox);
fz_clear_pixmap(dev->ctx, dest);
/* push soft mask as clip mask */
- state[1].mask = temp;
state[1].dest = dest;
state[1].blendmode |= FZ_BLEND_ISOLATED;
/* If we have a shape, then it'll need to be masked with the
@@ -1518,6 +1556,7 @@ fz_draw_begin_group(fz_device *devp, const fz_rect *rect, int isolated, int knoc
fz_knockout_begin(dev);
state = push_stack(dev);
+ STACK_PUSHED("group");
fz_intersect_irect(fz_irect_from_rect(&bbox, rect), &state->scissor);
fz_try(ctx)
@@ -1581,6 +1620,7 @@ fz_draw_end_group(fz_device *devp)
}
state = &dev->stack[--dev->top];
+ STACK_POPPED("group");
alpha = state[1].alpha;
blendmode = state[1].blendmode & FZ_BLEND_MODEMASK;
isolated = state[1].blendmode & FZ_BLEND_ISOLATED;
@@ -1767,6 +1807,7 @@ fz_draw_begin_tile(fz_device *devp, const fz_rect *area, const fz_rect *view, fl
fz_knockout_begin(dev);
state = push_stack(dev);
+ STACK_PUSHED("tile");
fz_irect_from_rect(&bbox, fz_transform_rect(&local_view, ctm));
/* We should never have a bbox that entirely covers our destination.
* If we do, then the check for only 1 tile being visible above has
@@ -1859,6 +1900,7 @@ fz_draw_end_tile(fz_device *devp)
}
state = &dev->stack[--dev->top];
+ STACK_PUSHED("tile");
xstep = state[1].xstep;
ystep = state[1].ystep;
area = state[1].area;