diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-09-27 16:35:08 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-09-27 16:37:24 +0100 |
commit | c1ac8db7e60bcec8235b09729b34154e95790534 (patch) | |
tree | 6a4911a6b5d3343f1b370fb15787d72932df4f7e | |
parent | 0c2faf6621c4983e2ec2bea7c722a5cd3d89cc6d (diff) |
trace: Fix operand emission
Recent updates (in the past couple of years) to firefox have exposed
numerous bugs in the way we emit the operands. A few off-by-ones,
missing surfaces and outright bugs all of which are intermixed into
producing a corrupt stack.
Reported-by: Siarhei Siamashka <siarhei.siamashka@gmail.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | util/cairo-trace/trace.c | 232 |
1 files changed, 182 insertions, 50 deletions
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 05e97d2..0188d77 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -60,6 +60,8 @@ #define CAIRO_TRACE_OUTDIR "." #endif +#define DEBUG_STACK 0 + #if HAVE_BYTESWAP_H # include <byteswap.h> #endif @@ -424,6 +426,7 @@ _object_create (Type *type, const void *ptr) int bucket = BUCKET (type->objects, ptr); obj = malloc (sizeof (Object)); + obj->unknown = TRUE; obj->defined = FALSE; obj->foreign = FALSE; obj->operand = -1; @@ -920,10 +923,30 @@ static Object *current_object[2048]; /* XXX limit operand stack */ static int current_stack_depth; static void +dump_stack(const char *func) +{ +#if DEBUG_STACK + int n; + + _trace_printf ("%% %s: stack[%d] = [", func, current_stack_depth); + fflush (logfile); + for (n = 0; n < current_stack_depth; n++) { + Object *obj = current_object[n]; + assert(obj && obj->type); + _trace_printf (" %s%s%ld", + obj->defined ? "" : "*", + obj->type->op_code, obj->token); + fflush (logfile); + } + _trace_printf (" ]\n"); + fflush (logfile); +#endif +} + +static void ensure_operands (int num_operands) { - if (current_stack_depth < num_operands) - { + if (current_stack_depth < num_operands) { int n; fprintf (stderr, "Operand stack underflow!\n"); @@ -971,26 +994,36 @@ _exch_operands (void) static cairo_bool_t _pop_operands_to_depth (int depth) { - while (current_stack_depth > depth) { + if (depth < 0) + return FALSE; + + assert(current_stack_depth >= depth); + if (current_stack_depth == depth) + return TRUE; + + while (current_stack_depth > depth + 1) { Object *c_obj; ensure_operands (1); c_obj = current_object[--current_stack_depth]; - c_obj->operand = -1; - if (! c_obj->defined) { - if (c_obj->unknown) - return FALSE; - _trace_printf ("/%s%ld exch def\n", - c_obj->type->op_code, - c_obj->token); - c_obj->defined = TRUE; - } else { - _trace_printf ("pop %% %s%ld\n", - c_obj->type->op_code, c_obj->token); + assert(c_obj); + assert(c_obj->type); + + if (! c_obj->defined) { + current_stack_depth++; + return FALSE; } + + _trace_printf ("pop %% %s%ld\n", + c_obj->type->op_code, c_obj->token); + c_obj->operand = -1; } + _exch_operands (); + _trace_printf ("exch\n"); + + dump_stack(__func__); return TRUE; } @@ -1012,7 +1045,7 @@ _pop_operands_to_object (Object *obj) return TRUE; } - return _pop_operands_to_depth (obj->operand + 2); + return _pop_operands_to_depth (obj->operand + 1); } static cairo_bool_t @@ -1038,9 +1071,9 @@ _is_current (enum operand_type type, const void *ptr, int depth) static void _push_object(Object *obj) { + assert(obj->operand == -1); - if (current_stack_depth == ARRAY_LENGTH (current_object)) - { + if (current_stack_depth == ARRAY_LENGTH (current_object)) { int n; fprintf (stderr, "Operand stack overflow!\n"); @@ -1088,7 +1121,10 @@ _object_remove (Object *obj) current_object[n]->operand = n; } } + obj->operand = -1; + current_stack_depth--; + dump_stack(__func__); } } @@ -1218,7 +1254,7 @@ _emit_pattern_id (cairo_pattern_t *pattern) _trace_printf ("p%ld ", obj->token); } else { _trace_printf ("%d index ", - current_stack_depth - obj->operand - 1); + current_stack_depth - obj->operand - 1); } } } @@ -1894,22 +1930,26 @@ static void _emit_current (Object *obj) { if (obj != NULL && ! _pop_operands_to_object (obj)) { - if (obj->defined) { - _trace_printf ("%s%ld\n", obj->type->op_code, obj->token); - } else { + if (obj->operand != -1) { int n; _trace_printf ("%d -1 roll %% %s%ld\n", - current_stack_depth - obj->operand + 1, + current_stack_depth - obj->operand, obj->type->op_code, obj->token); for (n = obj->operand; n < current_stack_depth - 1; n++) { current_object[n] = current_object[n+1]; current_object[n]->operand = n; } + obj->operand = -1; current_stack_depth--; + } else { + assert(obj->defined); + _trace_printf ("%s%ld\n", obj->type->op_code, obj->token); } + _push_object (obj); + dump_stack(__func__); } } @@ -1974,6 +2014,7 @@ cairo_create (cairo_surface_t *target) } _trace_printf ("context %% c%ld\n", context_id); _push_operand (CONTEXT, ret); + dump_stack(__func__); } _write_unlock (); } @@ -2045,6 +2086,7 @@ cairo_pop_group (cairo_t *cr) _emit_line_info (); _emit_cairo_op (cr, "pop-group %% p%ld\n", _create_pattern_id (ret)); _push_operand (PATTERN, ret); + dump_stack(__func__); _exit_trace (); return ret; @@ -2270,7 +2312,7 @@ cairo_set_source (cairo_t *cr, cairo_pattern_t *source) _emit_pattern_id (source); } - _trace_printf ("set-source\n"); + _trace_printf ("set-source %% p%ld\n", obj->token); _write_unlock (); } @@ -2924,6 +2966,7 @@ cairo_get_font_face (cairo_t *cr) _emit_cairo_op (cr, "/font-face get %% f%ld\n", font_face_id); _push_operand (FONT_FACE, ret); + dump_stack(__func__); _exit_trace (); return ret; @@ -3136,6 +3179,7 @@ cairo_set_scaled_font (cairo_t *cr, const cairo_scaled_font_t *scaled_font) } _trace_printf ("set-scaled-font\n"); + _write_unlock (); } DLCALL (cairo_set_scaled_font, cr, scaled_font); @@ -3179,6 +3223,12 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, options != NULL && _write_lock ()) { + Object *obj; + + obj = _type_object_create (SCALED_FONT, ret); + DLCALL (cairo_scaled_font_set_user_data, + ret, &destroy_key, obj, _object_undef); + if (_pop_operands_to (FONT_FACE, font_face)) _consume_operand (false); else @@ -3192,10 +3242,9 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, _emit_font_options (options); - _trace_printf (" scaled-font dup /sf%ld exch def\n", - _create_scaled_font_id (ret)); - _push_operand (SCALED_FONT, ret); - _get_object (SCALED_FONT, ret)->defined = TRUE; + _trace_printf (" scaled-font /sf%ld exch def\n", + obj->token); + obj->defined = TRUE; _write_unlock (); } @@ -3493,6 +3542,7 @@ cairo_image_surface_create (cairo_format_t format, int width, int height) obj->height = height; obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -3543,6 +3593,7 @@ cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format, obj->height = height; obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -3607,6 +3658,8 @@ cairo_pattern_create_raster_source (void *data, cairo_content_t content, int wid pattern_id); _push_operand (PATTERN, ret); + _get_object (PATTERN, ret)->defined = TRUE; + dump_stack(__func__); _write_unlock (); } @@ -3630,19 +3683,28 @@ cairo_surface_create_similar (cairo_surface_t *other, Object *other_obj = _get_object(SURFACE, other); Object *new_obj = _create_surface (ret); - if (other_obj->defined) + if (other_obj->operand != -1) { + if (current_stack_depth == other_obj->operand + 1) + _trace_printf ("dup "); + else + _trace_printf ("%d index ", + current_stack_depth - other_obj->operand - 1); + } else { + assert(other_obj->defined); _trace_printf ("s%ld ", other_obj->token); - else if (current_stack_depth == other_obj->operand + 1) - _trace_printf ("dup "); - else - _trace_printf ("%d index ", - current_stack_depth - other_obj->operand - 1); - _trace_printf ("%d %d //%s similar %% s%ld\n", + } + + _trace_printf ("%d %d //%s similar dup /s%ld exch def\n", width, height, _content_to_string (content), new_obj->token); + new_obj->width = width; + new_obj->height = height; + new_obj->defined = TRUE; + _push_object (new_obj); + dump_stack(__func__); _write_unlock (); } @@ -3679,8 +3741,11 @@ cairo_surface_create_similar_image (cairo_surface_t *other, _format_to_string (format), width, height, new_obj->token); + new_obj->width = width; + new_obj->height = height; _push_object (new_obj); + dump_stack(__func__); _write_unlock (); } @@ -3714,8 +3779,8 @@ cairo_surface_map_to_image (cairo_surface_t *surface, _trace_printf ("[ ] map-to-image %% s%ld\n", obj->token); } - obj->unknown = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -3777,6 +3842,7 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target, child_obj->token); _push_object (child_obj); + dump_stack(__func__); _write_unlock (); } @@ -4093,6 +4159,7 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface) _trace_printf ("pattern %% p%ld\n", pattern_id); _push_operand (PATTERN, ret); + dump_stack(__func__); _write_unlock (); } @@ -4116,6 +4183,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1) _trace_printf ("%g %g %g %g linear %% p%ld\n", x0, y0, x1, y1, pattern_id); _push_operand (PATTERN, ret); + dump_stack(__func__); _write_unlock (); } @@ -4142,6 +4210,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0, double cx1, cx0, cy0, radius0, cx1, cy1, radius1, pattern_id); _push_operand (PATTERN, ret); + dump_stack(__func__); _write_unlock (); } @@ -4257,24 +4326,26 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern) _emit_line_info (); if (pattern != NULL && _write_lock ()) { Object *obj; - FcChar8 *parsed; obj = _get_object (FONT_FACE, ret); - if (obj->operand != -1) - _object_remove (obj); - - parsed = DLCALL (FcNameUnparse, pattern); - _trace_printf ("dict\n" - " /type 42 set\n" - " /pattern "); - _emit_string_literal ((char *) parsed, -1); - _trace_printf (" set\n" - " font %% f%ld\n", - font_face_id); - _push_operand (FONT_FACE, ret); + if (obj->unknown) { + FcChar8 *parsed; + + parsed = DLCALL (FcNameUnparse, pattern); + _trace_printf ("dict\n" + " /type 42 set\n" + " /pattern "); + _emit_string_literal ((char *) parsed, -1); + _trace_printf (" set\n" + " font %% f%ld\n", + font_face_id); + obj->unknown = FALSE; + _push_operand (FONT_FACE, ret); + dump_stack(__func__); + + free (parsed); + } _write_unlock (); - - free (parsed); } _exit_trace (); @@ -4332,6 +4403,7 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face, int load_flags) _trace_printf (" /index %lu /flags %d >> font %% f%ld\n", data->index, load_flags, font_face_id); _push_operand (FONT_FACE, ret); + dump_stack(__func__); _write_unlock (); } @@ -4524,6 +4596,7 @@ cairo_ps_surface_create (const char *filename, double width_in_points, double he obj->width = width_in_points; obj->height = height_in_points; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -4555,6 +4628,7 @@ cairo_ps_surface_create_for_stream (cairo_write_func_t write_func, void *closure obj->width = width_in_points; obj->height = height_in_points; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -4603,6 +4677,7 @@ cairo_pdf_surface_create (const char *filename, double width_in_points, double h obj->width = width_in_points; obj->height = height_in_points; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -4634,6 +4709,7 @@ cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, void *closur obj->width = width_in_points; obj->height = height_in_points; _push_object (obj); + dump_stack(__func__); _write_unlock (); } _exit_trace (); @@ -4680,6 +4756,7 @@ cairo_svg_surface_create (const char *filename, double width, double height) obj->width = width; obj->height = height; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -4711,6 +4788,7 @@ cairo_svg_surface_create_for_stream (cairo_write_func_t write_func, void *closur obj->width = width; obj->height = height; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -4742,6 +4820,7 @@ cairo_image_surface_create_from_png (const char *filename) _surface_object_set_size_from_surface (ret); obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -4769,6 +4848,7 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, void *c _surface_object_set_size_from_surface (ret); obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -4783,6 +4863,40 @@ _content_from_surface (cairo_surface_t *surface) return _content_to_string (DLCALL (cairo_surface_get_content, surface)); } +#if CAIRO_HAS_TEE_SURFACE +#include <cairo-tee.h> + +cairo_surface_t * +cairo_tee_surface_create (cairo_surface_t *master) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_tee_surface_create, master); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /tee set\n" + " /master s%ld set\n" + " surface dup /s%ld exch def\n", + _get_object (SURFACE, master)->token, + obj->token); + obj->defined = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +#endif + #if CAIRO_HAS_XLIB_SURFACE #include <cairo-xlib.h> @@ -4819,6 +4933,7 @@ cairo_xlib_surface_create (Display *dpy, obj->height = height; obj->foreign = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -4860,6 +4975,7 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy, obj->height = height; obj->foreign = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -4905,6 +5021,7 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy, obj->height = height; obj->foreign = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -4945,6 +5062,7 @@ cairo_script_surface_create (cairo_device_t *device, obj->height = height; obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -4972,6 +5090,7 @@ cairo_script_surface_create_for_target (cairo_device_t *device, obj->token); obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -5003,6 +5122,7 @@ _cairo_test_paginated_surface_create (cairo_surface_t *surface) _get_surface_id (surface), obj->token); _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -5036,6 +5156,7 @@ _cairo_test_fallback_compositor_surface_create (cairo_content_t content, int wid obj->token); obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -5067,6 +5188,7 @@ _cairo_test_mask_compositor_surface_create (cairo_content_t content, int width, obj->token); obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -5098,6 +5220,7 @@ _cairo_test_spans_compositor_surface_create (cairo_content_t content, int width, obj->token); obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -5129,6 +5252,7 @@ _cairo_test_traps_compositor_surface_create (cairo_content_t content, int width, obj->token); obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -5167,6 +5291,7 @@ cairo_recording_surface_create (cairo_content_t content, } obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -5204,6 +5329,7 @@ cairo_vg_surface_create (cairo_vg_context_t *context, obj->height = height; obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -5243,6 +5369,7 @@ cairo_vg_surface_create_for_image (cairo_vg_context_t *context, obj->height = height; obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -5282,6 +5409,7 @@ cairo_gl_surface_create (cairo_device_t *abstract_device, obj->height = height; obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -5319,6 +5447,7 @@ cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device, obj->height = height; obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -5353,6 +5482,7 @@ cairo_gl_surface_create_for_window (cairo_device_t *device, obj->height = height; obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -5389,6 +5519,7 @@ cairo_gl_surface_create_for_dc (cairo_device_t *device, obj->height = height; obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } @@ -5425,6 +5556,7 @@ cairo_gl_surface_create_for_egl (cairo_device_t *device, obj->height = height; obj->defined = TRUE; _push_object (obj); + dump_stack(__func__); _write_unlock (); } |