Surround initialisations with atomic critical section

Fixes the race condition when one thread uses cairo_mask_compositor_t
pointer returned by _cairo_image_mask_compositor_get, while another one
started but has not finished it's initialisation yet

Usage:
static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
if (_cairo_atomic_init_once_enter(&once)) {
    /* Initialization code */
    _cairo_atomic_init_once_leave(&once);
}

https://bugs.freedesktop.org/show_bug.cgi?id=103037
This commit is contained in:
Mikhail Fludkov 2017-10-06 13:47:51 +02:00 committed by Adrian Johnson
parent 79e0e25e44
commit 90104809b0
10 changed files with 87 additions and 15 deletions

View file

@ -45,6 +45,8 @@
#include "config.h"
#endif
#include <assert.h>
/* 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,37 @@ _cairo_atomic_ptr_cmpxchg_return_old_fallback(void **x, void *oldv, void *newv)
(void) ret__; \
} while (0)
typedef cairo_atomic_int_t cairo_atomic_once_t;
#define CAIRO_ATOMIC_ONCE_UNINITIALIZED (0)
#define CAIRO_ATOMIC_ONCE_INITIALIZING (1)
#define CAIRO_ATOMIC_ONCE_INITIALIZED (2)
#define CAIRO_ATOMIC_ONCE_INIT CAIRO_ATOMIC_ONCE_UNINITIALIZED
static cairo_always_inline cairo_bool_t
_cairo_atomic_init_once_enter(cairo_atomic_once_t *once)
{
if (likely(_cairo_atomic_int_get(once) == CAIRO_ATOMIC_ONCE_INITIALIZED))
return 0;
if (_cairo_atomic_int_cmpxchg(once,
CAIRO_ATOMIC_ONCE_UNINITIALIZED,
CAIRO_ATOMIC_ONCE_INITIALIZING))
return 1;
while (_cairo_atomic_int_get(once) != CAIRO_ATOMIC_ONCE_INITIALIZED) {}
return 0;
}
static cairo_always_inline void
_cairo_atomic_init_once_leave(cairo_atomic_once_t *once)
{
if (unlikely(!_cairo_atomic_int_cmpxchg(once,
CAIRO_ATOMIC_ONCE_INITIALIZING,
CAIRO_ATOMIC_ONCE_INITIALIZED)))
assert (0 && "incorrect use of _cairo_atomic_init_once API (once != CAIRO_ATOMIC_ONCE_INITIALIZING)");
}
CAIRO_END_DECLS
#endif

View file

@ -944,10 +944,13 @@ _cairo_gl_msaa_compositor_init (cairo_compositor_t *compositor,
const cairo_compositor_t *
_cairo_gl_msaa_compositor_get (void)
{
static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
static cairo_compositor_t compositor;
if (compositor.delegate == NULL)
if (_cairo_atomic_init_once_enter(&once)) {
_cairo_gl_msaa_compositor_init (&compositor,
_cairo_gl_span_compositor_get ());
_cairo_atomic_init_once_leave(&once);
}
return &compositor;
}

View file

@ -528,10 +528,11 @@ _cairo_gl_span_renderer_fini (cairo_abstract_span_renderer_t *_r,
const cairo_compositor_t *
_cairo_gl_span_compositor_get (void)
{
static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
static cairo_spans_compositor_t spans;
static cairo_compositor_t shape;
if (spans.base.delegate == NULL) {
if (_cairo_atomic_init_once_enter(&once)) {
/* The fallback to traps here is essentially just for glyphs... */
_cairo_shape_mask_compositor_init (&shape,
_cairo_gl_traps_compositor_get());
@ -547,6 +548,8 @@ _cairo_gl_span_compositor_get (void)
//spans.check_span_renderer = check_span_renderer;
spans.renderer_init = _cairo_gl_span_renderer_init;
spans.renderer_fini = _cairo_gl_span_renderer_fini;
_cairo_atomic_init_once_leave(&once);
}
return &spans.base;

View file

@ -500,9 +500,10 @@ check_composite (const cairo_composite_rectangles_t *extents)
const cairo_compositor_t *
_cairo_gl_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_init_once_enter(&once)) {
_cairo_traps_compositor_init (&compositor, &_cairo_fallback_compositor);
compositor.acquire = acquire;
compositor.release = release;
@ -522,6 +523,8 @@ _cairo_gl_traps_compositor_get (void)
compositor.composite_tristrip = composite_tristrip;
compositor.check_composite_glyphs = _cairo_gl_check_composite_glyphs;
compositor.composite_glyphs = _cairo_gl_composite_glyphs;
_cairo_atomic_init_once_leave(&once);
}
return &compositor.base;

View file

@ -1244,11 +1244,12 @@ 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) {
_cairo_traps_compositor_init (&compositor,
&__cairo_no_compositor);
if (_cairo_atomic_init_once_enter(&once)) {
_cairo_traps_compositor_init(&compositor,
&__cairo_no_compositor);
compositor.acquire = acquire;
compositor.release = release;
compositor.set_clip_region = set_clip_region;
@ -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_init_once_leave(&once);
}
return &compositor.base;
@ -1277,9 +1280,10 @@ _cairo_image_traps_compositor_get (void)
const cairo_compositor_t *
_cairo_image_mask_compositor_get (void)
{
static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
static cairo_mask_compositor_t compositor;
if (compositor.base.delegate == NULL) {
if (_cairo_atomic_init_once_enter(&once)) {
_cairo_mask_compositor_init (&compositor,
_cairo_image_traps_compositor_get ());
compositor.acquire = acquire;
@ -1296,6 +1300,8 @@ _cairo_image_mask_compositor_get (void)
compositor.composite_boxes = composite_boxes;
compositor.check_composite_glyphs = check_composite_glyphs;
compositor.composite_glyphs = composite_glyphs;
_cairo_atomic_init_once_leave(&once);
}
return &compositor.base;
@ -3105,10 +3111,11 @@ span_renderer_fini (cairo_abstract_span_renderer_t *_r,
const cairo_compositor_t *
_cairo_image_spans_compositor_get (void)
{
static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
static cairo_spans_compositor_t spans;
static cairo_compositor_t shape;
if (spans.base.delegate == NULL) {
if (_cairo_atomic_init_once_enter(&once)) {
_cairo_shape_mask_compositor_init (&shape,
_cairo_image_traps_compositor_get());
shape.glyphs = NULL;
@ -3131,6 +3138,8 @@ _cairo_image_spans_compositor_get (void)
//spans.check_span_renderer = check_span_renderer;
spans.renderer_init = span_renderer_init;
spans.renderer_fini = span_renderer_fini;
_cairo_atomic_init_once_leave(&once);
}
return &spans.base;

View file

@ -387,9 +387,10 @@ composite_boxes (void *_dst,
const cairo_compositor_t *
_cairo_image_mask_compositor_get (void)
{
static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
static cairo_mask_compositor_t compositor;
if (compositor.base.delegate == NULL) {
if (_cairo_atomic_init_once_enter(&once)) {
_cairo_mask_compositor_init (&compositor,
_cairo_image_traps_compositor_get ());
compositor.acquire = acquire;
@ -405,6 +406,8 @@ _cairo_image_mask_compositor_get (void)
compositor.composite = composite;
//compositor.check_composite_boxes = check_composite_boxes;
compositor.composite_boxes = composite_boxes;
_cairo_atomic_init_once_leave(&once);
}
return &compositor.base;

View file

@ -632,9 +632,10 @@ _cairo_xlib_core_compositor_fill (const cairo_compositor_t *compositor,
const cairo_compositor_t *
_cairo_xlib_core_compositor_get (void)
{
static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
static cairo_compositor_t compositor;
if (compositor.delegate == NULL) {
if (_cairo_atomic_init_once_enter(&once)) {
compositor.delegate = _cairo_xlib_fallback_compositor_get ();
compositor.paint = _cairo_xlib_core_compositor_paint;
@ -642,6 +643,8 @@ _cairo_xlib_core_compositor_get (void)
compositor.fill = _cairo_xlib_core_compositor_fill;
compositor.stroke = _cairo_xlib_core_compositor_stroke;
compositor.glyphs = NULL; /* XXX PolyGlyph? */
_cairo_atomic_init_once_leave(&once);
}
return &compositor;

View file

@ -1725,9 +1725,10 @@ composite_glyphs (void *surface,
const cairo_compositor_t *
_cairo_xlib_mask_compositor_get (void)
{
static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
static cairo_mask_compositor_t compositor;
if (compositor.base.delegate == NULL) {
if (_cairo_atomic_init_once_enter(&once)) {
_cairo_mask_compositor_init (&compositor,
_cairo_xlib_fallback_compositor_get ());
@ -1745,6 +1746,8 @@ _cairo_xlib_mask_compositor_get (void)
compositor.composite_boxes = composite_boxes;
compositor.check_composite_glyphs = check_composite_glyphs;
compositor.composite_glyphs = composite_glyphs;
_cairo_atomic_init_once_leave(&once);
}
return &compositor.base;
@ -1973,9 +1976,10 @@ composite_tristrip (void *abstract_dst,
const cairo_compositor_t *
_cairo_xlib_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_init_once_enter(&once)) {
_cairo_traps_compositor_init (&compositor,
_cairo_xlib_mask_compositor_get ());
@ -1997,6 +2001,8 @@ _cairo_xlib_traps_compositor_get (void)
compositor.composite_tristrip = composite_tristrip;
compositor.check_composite_glyphs = check_composite_glyphs;
compositor.composite_glyphs = composite_glyphs;
_cairo_atomic_init_once_leave(&once);
}
return &compositor.base;

View file

@ -404,9 +404,10 @@ check_composite (const cairo_composite_rectangles_t *extents)
static const cairo_compositor_t *
no_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_init_once_enter(&once)) {
_cairo_traps_compositor_init (&compositor,
no_fallback_compositor_get ());
@ -426,6 +427,8 @@ no_traps_compositor_get (void)
compositor.composite_traps = composite_traps;
compositor.check_composite_glyphs = check_composite_glyphs;
compositor.composite_glyphs = composite_glyphs;
_cairo_atomic_init_once_leave(&once);
}
return &compositor.base;
@ -434,9 +437,10 @@ no_traps_compositor_get (void)
static const cairo_compositor_t *
no_spans_compositor_get (void)
{
static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
static cairo_spans_compositor_t compositor;
if (compositor.base.delegate == NULL) {
if (_cairo_atomic_init_once_enter(&once)) {
_cairo_spans_compositor_init (&compositor,
no_traps_compositor_get());
@ -448,6 +452,8 @@ no_spans_compositor_get (void)
//compositor.check_span_renderer = check_span_renderer;
compositor.renderer_init = span_renderer_init;
compositor.renderer_fini = span_renderer_fini;
_cairo_atomic_init_once_leave(&once);
}
return &compositor.base;

View file

@ -634,9 +634,10 @@ _cairo_win32_gdi_compositor_glyphs (const cairo_compositor_t *compositor,
const cairo_compositor_t *
_cairo_win32_gdi_compositor_get (void)
{
static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
static cairo_compositor_t compositor;
if (compositor.delegate == NULL) {
if (_cairo_atomic_init_once_enter(&once)) {
compositor.delegate = &_cairo_fallback_compositor;
compositor.paint = _cairo_win32_gdi_compositor_paint;
@ -644,6 +645,8 @@ _cairo_win32_gdi_compositor_get (void)
compositor.fill = _cairo_win32_gdi_compositor_fill;
compositor.stroke = _cairo_win32_gdi_compositor_stroke;
compositor.glyphs = _cairo_win32_gdi_compositor_glyphs;
_cairo_atomic_init_once_leave(&once);
}
return &compositor;