mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-02-27 12:50:35 +01:00
Commits cb871c6c made the function _cairo_clip_reduce_to_boxes()
actually do something instead of being a no-op. This exposed a latent
bug in cairo that was so far just not hit due to luck.
The function _cairo_clip_steal_boxes() removes the boxes from a clip and
gives them to a cairo_boxes_t. _cairo_clip_unsteal_boxes() undoes this
operation. For efficiency reasons, cairo_clip_t contains an embedded
cairo_box_t that is used when the clip has only one box to avoid a
memory allocation. Thus, _cairo_clip_unsteal_boxes() must be called on
the same clip that was given to _cairo_clip_steal_boxes(), or otherwise
a clip could end up to the embedded box of another instance of
cairo_clip_t. This is exactly what was happening here.
For example, cairo-xcb can replace extents->clip with another clip via
the call chain _cairo_xcb_render_compositor_paint() (which is where
boxes are stolen) -> _clip_and_composite_boxes() ->
trim_extents_to_traps() ->
_cairo_composite_rectangles_intersect_mask_extents(). This function
replaced the clip with the result of _cairo_clip_reduce_for_composite()
and frees the old clip. At this point, the boxes that were stolen
previously become invalid / become a dangling pointer. The crash later
on is just one of the side effects of this.
This commit fixes this problem by treating embedded boxes specially in
_cairo_clip_steal_boxes() and _cairo_clip_unsteal_boxes(): The
cairo_boxes_t instance also has embedded boxes. An embedded box on the
clip is copied to these other embedded boxes. When unstealing, the
embedded box of the clip is used again. Thus, it does not matter anymore
that another instance of _cairo_clip_t is used for unstealing.
Fixes: https://gitlab.freedesktop.org/cairo/cairo/issues/358
Signed-off-by: Uli Schlachter <psychon@znc.in>
96 lines
3.1 KiB
C
96 lines
3.1 KiB
C
/* cairo - a vector graphics library with display and print output
|
|
*
|
|
* Copyright © 2005 Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it either under the terms of the GNU Lesser General Public
|
|
* License version 2.1 as published by the Free Software Foundation
|
|
* (the "LGPL") or, at your option, under the terms of the Mozilla
|
|
* Public License Version 1.1 (the "MPL"). If you do not alter this
|
|
* notice, a recipient may use your version of this file under either
|
|
* the MPL or the LGPL.
|
|
*
|
|
* You should have received a copy of the LGPL along with this library
|
|
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
|
|
* You should have received a copy of the MPL along with this library
|
|
* in the file COPYING-MPL-1.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
|
|
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
|
|
* the specific language governing rights and limitations.
|
|
*
|
|
* The Original Code is the cairo graphics library.
|
|
*
|
|
* The Initial Developer of the Original Code is Red Hat, Inc.
|
|
*
|
|
* Contributor(s):
|
|
* Kristian Høgsberg <krh@redhat.com>
|
|
* Chris Wilson <chris@chris-wilson.co.uk>
|
|
*/
|
|
|
|
#ifndef CAIRO_CLIP_INLINE_H
|
|
#define CAIRO_CLIP_INLINE_H
|
|
|
|
#include "cairo-clip-private.h"
|
|
|
|
static inline cairo_bool_t _cairo_clip_is_all_clipped(const cairo_clip_t *clip)
|
|
{
|
|
return clip == &__cairo_clip_all;
|
|
}
|
|
|
|
static inline cairo_clip_t *
|
|
_cairo_clip_set_all_clipped (cairo_clip_t *clip)
|
|
{
|
|
_cairo_clip_destroy (clip);
|
|
return (cairo_clip_t *) &__cairo_clip_all;
|
|
}
|
|
|
|
static inline cairo_clip_t *
|
|
_cairo_clip_copy_intersect_rectangle (const cairo_clip_t *clip,
|
|
const cairo_rectangle_int_t *r)
|
|
{
|
|
return _cairo_clip_intersect_rectangle (_cairo_clip_copy (clip), r);
|
|
}
|
|
|
|
static inline cairo_clip_t *
|
|
_cairo_clip_copy_intersect_clip (const cairo_clip_t *clip,
|
|
const cairo_clip_t *other)
|
|
{
|
|
return _cairo_clip_intersect_clip (_cairo_clip_copy (clip), other);
|
|
}
|
|
|
|
static inline void
|
|
_cairo_clip_steal_boxes (cairo_clip_t *clip, cairo_boxes_t *boxes)
|
|
{
|
|
cairo_box_t *array = clip->boxes;
|
|
|
|
if (array == &clip->embedded_box) {
|
|
assert (clip->num_boxes == 1);
|
|
boxes->boxes_embedded[0] = clip->embedded_box;
|
|
array = &boxes->boxes_embedded[0];
|
|
}
|
|
_cairo_boxes_init_for_array (boxes, array, clip->num_boxes);
|
|
clip->boxes = NULL;
|
|
clip->num_boxes = 0;
|
|
}
|
|
|
|
static inline void
|
|
_cairo_clip_unsteal_boxes (cairo_clip_t *clip, cairo_boxes_t *boxes)
|
|
{
|
|
if (boxes->chunks.base == &boxes->boxes_embedded[0]) {
|
|
assert(boxes->num_boxes == 1);
|
|
clip->embedded_box = *boxes->chunks.base;
|
|
clip->boxes = &clip->embedded_box;
|
|
} else {
|
|
clip->boxes = boxes->chunks.base;
|
|
}
|
|
clip->num_boxes = boxes->num_boxes;
|
|
}
|
|
|
|
#endif /* CAIRO_CLIP_INLINE_H */
|