diff --git a/src/cairo-bentley-ottmann-rectangular.c b/src/cairo-bentley-ottmann-rectangular.c index 65f95d797..b4c18cef2 100644 --- a/src/cairo-bentley-ottmann-rectangular.c +++ b/src/cairo-bentley-ottmann-rectangular.c @@ -847,12 +847,16 @@ _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in, rectangles[j].left.x = box[i].p2.x; rectangles[j].left.dir = -1; } + if (unlikely (rectangles[j].left.x == INT32_MAX)) rectangles[j].left.x = INT32_MAX-1; + if (unlikely (rectangles[j].right.x == INT32_MAX)) rectangles[j].right.x = INT32_MAX-1; rectangles[j].left.right = NULL; rectangles[j].right.right = NULL; rectangles[j].top = box[i].p1.y; rectangles[j].bottom = box[i].p2.y; + if (unlikely (rectangles[j].top == INT32_MIN)) rectangles[j].top = INT32_MIN+1; + if (unlikely (rectangles[j].bottom == INT32_MIN)) rectangles[j].bottom = INT32_MIN+1; if (rectangles_chain) { h = _cairo_fixed_integer_floor (box[i].p1.y) - y_min; diff --git a/test/bug-crash-tessellate.c b/test/bug-crash-tessellate.c new file mode 100644 index 000000000..5c68de899 --- /dev/null +++ b/test/bug-crash-tessellate.c @@ -0,0 +1,104 @@ +/* + * Copyright © 2025 Uli Schlachter + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Author: Uli Schlachter + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw_y (cairo_t *cr, int width, int height) +{ + // the minimum value that cairo_fixed_t can represent + // (because it uses a 24.8 fixed point format) + double fixed_min = INT32_MIN / (double) (1 << 8); + + // Fill the output with black so that CONTENT_COLOR and CONTENT_COLOR_ALPHA + // can use the same reference image. + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + // Work around the clamping done by commit 47a21c6e30eef91db503a5a183d5c8cf558aaa56 + cairo_set_line_width(cr, 1.0 / (double) (1 << 16)); + + // Some identical rectangles with their lower edge at fixed_min + cairo_rectangle (cr, 0, fixed_min, 10, 10); + cairo_rectangle (cr, 0, fixed_min, 10, 10); + cairo_rectangle (cr, 0, fixed_min, 10, -10); + cairo_rectangle (cr, 0, fixed_min, 10, -10); + + cairo_clip (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_pdf (cairo_t *cr, int width, int height) +{ + // This is a reduction from some drawing commands found in a PDF + cairo_matrix_t m1 = {1, 0, 0, -1, 0, 792}; + cairo_matrix_t m2 = {8262, 0, 0, 0.148262, 0, 0}; + + // Fill the output with black so that CONTENT_COLOR and CONTENT_COLOR_ALPHA + // can use the same reference image. + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_transform(cr, &m1); + cairo_transform(cr, &m2); + cairo_set_line_width(cr, 0.0000145243); + + cairo_new_path(cr); + + cairo_move_to(cr, 801.285, 801.285); + cairo_line_to(cr, 3205.145, 801.285); + cairo_line_to(cr, 3205.145, 1602.57); + cairo_line_to(cr, 801.285, 1602.57); + cairo_line_to(cr, 801.285, 801.285); + cairo_close_path(cr); + + cairo_move_to(cr, 801.285, 2403.86); + cairo_line_to(cr, 3205.145, 2403.86); + cairo_line_to(cr, 3205.145, 3205.145); + cairo_line_to(cr, 801.285, 3205.145); + cairo_line_to(cr, 801.285, 2403.86); + cairo_close_path(cr); + + cairo_clip(cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_crash_tessellate_y, + "Trigger a crash in _cairo_bentley_ottmann_tessellate_rectangular with overlapping rectangles near the minimum possible y coordinate", + NULL, /* keywords */ + NULL, /* requirements */ + 1, 1, + NULL, draw_y) + +CAIRO_TEST (bug_crash_tessellate_pdf, + "Trigger a crash in _cairo_bentley_ottmann_tessellate_rectangular; reduced from a PDF", + NULL, /* keywords */ + NULL, /* requirements */ + 1, 1, + NULL, draw_pdf) diff --git a/test/meson.build b/test/meson.build index 3b460afc5..8aaa823b7 100644 --- a/test/meson.build +++ b/test/meson.build @@ -23,6 +23,7 @@ test_sources = [ 'big-little-triangle.c', 'bug-spline.c', 'big-trap.c', + 'bug-crash-tessellate.c', 'bilevel-image.c', 'bug-277.c', 'bug-361.c', diff --git a/test/reference/bug-crash-tessellate-pdf.ref.png b/test/reference/bug-crash-tessellate-pdf.ref.png new file mode 100644 index 000000000..7d5589c1d Binary files /dev/null and b/test/reference/bug-crash-tessellate-pdf.ref.png differ diff --git a/test/reference/bug-crash-tessellate-y.ref.png b/test/reference/bug-crash-tessellate-y.ref.png new file mode 100644 index 000000000..7d5589c1d Binary files /dev/null and b/test/reference/bug-crash-tessellate-y.ref.png differ