Skip to content

Commit

Permalink
Fix data race in freed_pool
Browse files Browse the repository at this point in the history
This adds _cairo_atomic_int_get_relaxed and _cairo_atomic_int_set_relaxed which
are meant to have a behaviour of relaxed read/writes in C11's memory model. This
patch also uses these new function to fix a data race with freed_pool_t's |top|
data member.

Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=90318
Signed-off-by: Wan-Teh Chang <wtc@google.com>
Signed-off-by: Uli Schlachter <psychon@znc.in>
  • Loading branch information
Wan-Teh Chang authored and Uli Schlachter committed Mar 5, 2016
1 parent af42fc7 commit 3538ac3
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 10 deletions.
36 changes: 36 additions & 0 deletions src/cairo-atomic-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ _cairo_atomic_int_get (cairo_atomic_int_t *x)
return __atomic_load_n(x, __ATOMIC_SEQ_CST);
}

static cairo_always_inline cairo_atomic_int_t
_cairo_atomic_int_get_relaxed (cairo_atomic_int_t *x)
{
return __atomic_load_n(x, __ATOMIC_RELAXED);
}

static cairo_always_inline void
_cairo_atomic_int_set_relaxed (cairo_atomic_int_t *x, cairo_atomic_int_t val)
{
__atomic_store_n(x, val, __ATOMIC_RELAXED);
}

static cairo_always_inline void *
_cairo_atomic_ptr_get (void **x)
{
Expand Down Expand Up @@ -157,6 +169,18 @@ _cairo_atomic_int_get (cairo_atomic_int_t *x)
return *x;
}

static cairo_always_inline cairo_atomic_int_t
_cairo_atomic_int_get_relaxed (cairo_atomic_int_t *x)
{
return *x;
}

static cairo_always_inline void
_cairo_atomic_int_set_relaxed (cairo_atomic_int_t *x, cairo_atomic_int_t val)
{
*x = val;
}

static cairo_always_inline void *
_cairo_atomic_ptr_get (void **x)
{
Expand All @@ -165,6 +189,8 @@ _cairo_atomic_ptr_get (void **x)
}
#else
# define _cairo_atomic_int_get(x) (*x)
# define _cairo_atomic_int_get_relaxed(x) (*x)
# define _cairo_atomic_int_set_relaxed(x, val) (*x) = (val)
# define _cairo_atomic_ptr_get(x) (*x)
#endif

Expand Down Expand Up @@ -200,6 +226,8 @@ typedef long long cairo_atomic_intptr_t;
typedef AO_t cairo_atomic_int_t;

# define _cairo_atomic_int_get(x) (AO_load_full (x))
# define _cairo_atomic_int_get_relaxed(x) (AO_load_full (x))
# define _cairo_atomic_int_set_relaxed(x, val) (AO_store_full ((x), (val)))

# define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x))
# define _cairo_atomic_int_dec(x) ((void) AO_fetch_and_sub1_full(x))
Expand Down Expand Up @@ -230,6 +258,8 @@ typedef unsigned long long cairo_atomic_intptr_t;
typedef int32_t cairo_atomic_int_t;

# define _cairo_atomic_int_get(x) (OSMemoryBarrier(), *(x))
# define _cairo_atomic_int_get_relaxed(x) *(x)
# define _cairo_atomic_int_set_relaxed(x, val) *(x) = (val)

# define _cairo_atomic_int_inc(x) ((void) OSAtomicIncrement32Barrier (x))
# define _cairo_atomic_int_dec(x) ((void) OSAtomicDecrement32Barrier (x))
Expand Down Expand Up @@ -288,9 +318,15 @@ _cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv);
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
cairo_private cairo_atomic_int_t
_cairo_atomic_int_get (cairo_atomic_int_t *x);
cairo_private cairo_atomic_int_t
_cairo_atomic_int_get_relaxed (cairo_atomic_int_t *x);
void
_cairo_atomic_int_set_relaxed (cairo_atomic_int_t *x, cairo_atomic_int_t val);
# define _cairo_atomic_ptr_get(x) (void *) _cairo_atomic_int_get((cairo_atomic_int_t *) x)
#else
# define _cairo_atomic_int_get(x) (*x)
# define _cairo_atomic_int_get_relaxed(x) (*x)
# define _cairo_atomic_int_set_relaxed(x, val) (*x) = (val)
# define _cairo_atomic_ptr_get(x) (*x)
#endif

Expand Down
14 changes: 14 additions & 0 deletions src/cairo-atomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,20 @@ _cairo_atomic_int_get (cairo_atomic_intptr_t *x)

return ret;
}

cairo_atomic_intptr_t
_cairo_atomic_int_get_relaxed (cairo_atomic_intptr_t *x)
{
return _cairo_atomic_int_get (x);
}

void
_cairo_atomic_int_set_relaxed (cairo_atomic_intptr_t *x, cairo_atomic_intptr_t val)
{
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
*x = val;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
}
#endif

#endif
10 changes: 5 additions & 5 deletions src/cairo-freed-pool-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ CAIRO_BEGIN_DECLS
#define MAX_FREED_POOL_SIZE 16
typedef struct {
void *pool[MAX_FREED_POOL_SIZE];
int top;
cairo_atomic_int_t top;
} freed_pool_t;

static cairo_always_inline void *
Expand Down Expand Up @@ -81,13 +81,13 @@ _freed_pool_get (freed_pool_t *pool)
void *ptr;
int i;

i = pool->top - 1;
i = _cairo_atomic_int_get_relaxed (&pool->top) - 1;
if (i < 0)
i = 0;

ptr = _atomic_fetch (&pool->pool[i]);
if (likely (ptr != NULL)) {
pool->top = i;
_cairo_atomic_int_set_relaxed (&pool->top, i);
return ptr;
}

Expand All @@ -103,11 +103,11 @@ _freed_pool_put (freed_pool_t *pool, void *ptr)
{
int i;

i = pool->top;
i = _cairo_atomic_int_get_relaxed (&pool->top);
if (likely (i < ARRAY_LENGTH (pool->pool) &&
_atomic_store (&pool->pool[i], ptr)))
{
pool->top = i + 1;
_cairo_atomic_int_set_relaxed (&pool->top, i + 1);
return;
}

Expand Down
10 changes: 5 additions & 5 deletions src/cairo-freed-pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ _freed_pool_get_search (freed_pool_t *pool)
for (i = ARRAY_LENGTH (pool->pool); i--;) {
ptr = _atomic_fetch (&pool->pool[i]);
if (ptr != NULL) {
pool->top = i;
_cairo_atomic_int_set_relaxed (&pool->top, i);
return ptr;
}
}

/* empty */
pool->top = 0;
_cairo_atomic_int_set_relaxed (&pool->top, 0);
return NULL;
}

Expand All @@ -67,13 +67,13 @@ _freed_pool_put_search (freed_pool_t *pool, void *ptr)

for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
if (_atomic_store (&pool->pool[i], ptr)) {
pool->top = i + 1;
_cairo_atomic_int_set_relaxed (&pool->top, i + 1);
return;
}
}

/* full */
pool->top = i;
_cairo_atomic_int_set_relaxed (&pool->top, i);
free (ptr);
}

Expand All @@ -87,7 +87,7 @@ _freed_pool_reset (freed_pool_t *pool)
pool->pool[i] = NULL;
}

pool->top = 0;
_cairo_atomic_int_set_relaxed (&pool->top, 0);
}

#endif

0 comments on commit 3538ac3

Please sign in to comment.