From df1973849cc06a821e98457e00e5f78f98263b3a Mon Sep 17 00:00:00 2001 From: Mikhail Fludkov Date: Fri, 6 Oct 2017 13:47:51 +0200 Subject: [PATCH] Fix the race around accessing cairo_image_traps_compositor https://bugs.freedesktop.org/show_bug.cgi?id=103037 --- src/cairo-atomic-private.h | 30 ++++++++++++++++++++++++++++++ src/cairo-image-compositor.c | 5 ++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/cairo-atomic-private.h b/src/cairo-atomic-private.h index 5001290..27f407f 100644 --- a/src/cairo-atomic-private.h +++ b/src/cairo-atomic-private.h @@ -45,6 +45,8 @@ #include "config.h" #endif +#include + /* The autoconf on OpenBSD 4.5 produces the malformed constant name * SIZEOF_VOID__ rather than SIZEOF_VOID_P. Work around that here. */ #if !defined(SIZEOF_VOID_P) && defined(SIZEOF_VOID__) @@ -393,6 +395,34 @@ _cairo_atomic_ptr_cmpxchg_return_old_fallback(void **x, void *oldv, void *newv) (void) ret__; \ } while (0) +typedef struct _cairo_atomic_once cairo_atomic_once_t; +struct _cairo_atomic_once { + cairo_atomic_int_t completed; + cairo_atomic_int_t inprogress; +}; + +#define CAIRO_ATOMIC_ONCE_INIT {0, 0} + +static cairo_always_inline cairo_bool_t +_cairo_atomic_once_init_enter(cairo_atomic_once_t *once) +{ + if (likely (once->completed)) + return 0; + + if (_cairo_atomic_int_cmpxchg(&once->inprogress, 0, 1)) + return 1; + + while (!_cairo_atomic_int_get(&once->completed)) {} + return 0; +} + +static cairo_always_inline void +_cairo_atomic_once_init_leave(cairo_atomic_once_t *once) +{ + if (unlikely (!_cairo_atomic_int_cmpxchg(&once->completed, 0, 1))) + assert (0 && "incorrect use of _cairo_atomic_once API (completed != FALSE)"); +} + CAIRO_END_DECLS #endif diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c index bfa1e92..d88e941 100644 --- a/src/cairo-image-compositor.c +++ b/src/cairo-image-compositor.c @@ -1244,9 +1244,10 @@ check_composite (const cairo_composite_rectangles_t *extents) const cairo_compositor_t * _cairo_image_traps_compositor_get (void) { + static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT; static cairo_traps_compositor_t compositor; - if (compositor.base.delegate == NULL) { + if (_cairo_atomic_once_init_enter(&once)) { _cairo_traps_compositor_init (&compositor, &__cairo_no_compositor); compositor.acquire = acquire; @@ -1269,6 +1270,8 @@ _cairo_image_traps_compositor_get (void) #endif compositor.check_composite_glyphs = check_composite_glyphs; compositor.composite_glyphs = composite_glyphs; + + _cairo_atomic_once_init_leave(&once); } return &compositor.base; -- 2.7.4