From c3dae88f9cc38c75d8450c0946fe9c4206cfd592 Mon Sep 17 00:00:00 2001 From: Petter Urkedal Date: Sat, 21 Apr 2012 13:28:12 +0400 Subject: [PATCH] Fix GC_check_fl_marks regarding concurrent access * alloc.c (GC_check_fl_marks): Re-read each pointer atomically before following the pointed-to link and bail out if the result is different (this can happen if the thread has popped the object off the free-list); the function is a no-op if AO_load is unavailable. --- alloc.c | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/alloc.c b/alloc.c index 1d365f4d..3cfcd831 100644 --- a/alloc.c +++ b/alloc.c @@ -734,17 +734,41 @@ GC_INNER void GC_set_fl_marks(ptr_t q) /* (*pfreelist) are set. Check skipped if points to a special value. */ void GC_check_fl_marks(void **pfreelist) { - ptr_t list = *pfreelist; - ptr_t p; - - if ((word)list <= HBLKSIZE) return; +# ifdef AO_HAVE_load_acquire_read + AO_t *list = (AO_t *)AO_load_acquire_read((AO_t *)pfreelist); + /* Atomic operations are used because the world is running. */ + AO_t *prev; + AO_t *p; + + if ((word)list <= HBLKSIZE) return; + + prev = (AO_t *)pfreelist; + for (p = list; p != NULL;) { + AO_t *next; + + if (!GC_is_marked(p)) { + GC_err_printf("Unmarked object %p on list %p\n", + (void *)p, (void *)list); + ABORT("Unmarked local free list entry"); + } - for (p = list; p != 0; p = obj_link(p)) { - if (!GC_is_marked(p)) { - GC_err_printf("Unmarked object %p on list %p\n", p, list); - ABORT("Unmarked local free list entry"); - } - } + /* While traversing the free-list, it re-reads the pointer to */ + /* the current node before accepting its next pointer and */ + /* bails out if the latter has changed. That way, it won't */ + /* try to follow the pointer which might be been modified */ + /* after the object was returned to the client. It might */ + /* perform the mark-check on the just allocated object but */ + /* that should be harmless. */ + next = (AO_t *)AO_load_acquire_read(p); + if (AO_load(prev) != (AO_t)p) + break; + prev = p; + p = next; + } +# else + /* FIXME: Not implemented (just skipped). */ + (void)pfreelist; +# endif } #endif /* GC_ASSERTIONS && THREAD_LOCAL_ALLOC */ -- 2.40.0