Revision: 187 http://trac.macosforge.org/projects/libdispatch/changeset/187 Author: kvv@apple.com Date: 2010-02-18 00:09:57 -0800 (Thu, 18 Feb 2010) Log Message: ----------- protect transparent union use with __GNUC__ Modified Paths: -------------- trunk/src/internal.h trunk/src/object.c trunk/src/object_internal.h Modified: trunk/src/internal.h =================================================================== --- trunk/src/internal.h 2010-02-18 05:49:14 UTC (rev 186) +++ trunk/src/internal.h 2010-02-18 08:09:57 UTC (rev 187) @@ -137,8 +137,13 @@ #define NSEC_PER_USEC 1000ull /* I wish we had __builtin_expect_range() */ +#if __GNUC__ #define fastpath(x) ((typeof(x))__builtin_expect((long)(x), ~0l)) #define slowpath(x) ((typeof(x))__builtin_expect((long)(x), 0l)) +#else +#define fastpath(x) (x) +#define slowpath(x) (x) +#endif void _dispatch_bug(size_t line, long val) __attribute__((__noinline__)); void _dispatch_abort(size_t line, long val) __attribute__((__noinline__,__noreturn__)); @@ -215,8 +220,12 @@ } \ } while (0) +#if __GNUC__ +#define DO_CAST(x) ((struct dispatch_object_s *)(x)._do) +#else +#define DO_CAST(x) ((struct dispatch_object_s *)(x)) +#endif - #ifdef __BLOCKS__ dispatch_block_t _dispatch_Block_copy(dispatch_block_t block); void _dispatch_call_block_and_release(void *block); Modified: trunk/src/object.c =================================================================== --- trunk/src/object.c 2010-02-18 05:49:14 UTC (rev 186) +++ trunk/src/object.c 2010-02-18 08:09:57 UTC (rev 187) @@ -20,15 +20,14 @@ #include "internal.h" - void -dispatch_debug(dispatch_object_t dou, const char *msg, ...) +dispatch_debug(dispatch_object_t obj, const char *msg, ...) { va_list ap; va_start(ap, msg); - dispatch_debugv(dou._do, msg, ap); + dispatch_debugv(obj, msg, ap); va_end(ap); } @@ -39,8 +38,10 @@ char buf[4096]; size_t offs; - if (dou._do && dou._do->do_vtable->do_debug) { - offs = dx_debug(dou._do, buf, sizeof(buf)); + struct dispatch_object_s *obj = DO_CAST(dou); + + if (obj && obj->do_vtable->do_debug) { + offs = dx_debug(obj, buf, sizeof(buf)); } else { offs = snprintf(buf, sizeof(buf), "NULL vtable slot"); } @@ -53,10 +54,12 @@ void dispatch_retain(dispatch_object_t dou) { - if (dou._do->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) { + struct dispatch_object_s *obj = DO_CAST(dou); + + if (obj->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) { return; // global object } - if ((dispatch_atomic_inc(&dou._do->do_xref_cnt) - 1) == 0) { + if ((dispatch_atomic_inc(&obj->do_xref_cnt) - 1) == 0) { DISPATCH_CLIENT_CRASH("Resurrection of an object"); } } @@ -64,10 +67,12 @@ void _dispatch_retain(dispatch_object_t dou) { - if (dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) { + struct dispatch_object_s *obj = DO_CAST(dou); + + if (obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) { return; // global object } - if ((dispatch_atomic_inc(&dou._do->do_ref_cnt) - 1) == 0) { + if ((dispatch_atomic_inc(&obj->do_ref_cnt) - 1) == 0) { DISPATCH_CLIENT_CRASH("Resurrection of an object"); } } @@ -75,26 +80,28 @@ void dispatch_release(dispatch_object_t dou) { - typeof(dou._do->do_xref_cnt) oldval; + struct dispatch_object_s *obj = DO_CAST(dou); - if (dou._do->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) { + unsigned int oldval; + + if (obj->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) { return; } - oldval = dispatch_atomic_dec(&dou._do->do_xref_cnt) + 1; + oldval = dispatch_atomic_dec(&obj->do_xref_cnt) + 1; if (fastpath(oldval > 1)) { return; } if (oldval == 1) { - if (dou._do->do_vtable == (void*)&_dispatch_source_kevent_vtable) { - return _dispatch_source_xref_release(dou._ds); + if ((uintptr_t)obj->do_vtable == (uintptr_t)&_dispatch_source_kevent_vtable) { + return _dispatch_source_xref_release((dispatch_source_t)obj); } - if (slowpath(DISPATCH_OBJECT_SUSPENDED(dou._do))) { + if (slowpath(DISPATCH_OBJECT_SUSPENDED(obj))) { // Arguments for and against this assert are within 6705399 DISPATCH_CLIENT_CRASH("Release of a suspended object"); } - return _dispatch_release(dou._do); + return _dispatch_release(obj); } DISPATCH_CLIENT_CRASH("Over-release of an object"); } @@ -102,14 +109,16 @@ void _dispatch_dispose(dispatch_object_t dou) { - dispatch_queue_t tq = dou._do->do_targetq; - dispatch_function_t func = dou._do->do_finalizer; - void *ctxt = dou._do->do_ctxt; + struct dispatch_object_s *obj = DO_CAST(dou); - dou._do->do_vtable = (void *)0x200; + dispatch_queue_t tq = obj->do_targetq; + dispatch_function_t func = obj->do_finalizer; + void *ctxt = obj->do_ctxt; - free(dou._do); + obj->do_vtable = (struct dispatch_object_vtable_s *)0x200; + free(obj); + if (func && ctxt) { dispatch_async_f(tq, ctxt, func); } @@ -119,26 +128,28 @@ void _dispatch_release(dispatch_object_t dou) { - typeof(dou._do->do_ref_cnt) oldval; + struct dispatch_object_s *obj = DO_CAST(dou); - if (dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) { + unsigned int oldval; + + if (obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) { return; // global object } - oldval = dispatch_atomic_dec(&dou._do->do_ref_cnt) + 1; + oldval = dispatch_atomic_dec(&obj->do_ref_cnt) + 1; if (fastpath(oldval > 1)) { return; } if (oldval == 1) { - if (dou._do->do_next != DISPATCH_OBJECT_LISTLESS) { + if (obj->do_next != DISPATCH_OBJECT_LISTLESS) { DISPATCH_CRASH("release while enqueued"); } - if (dou._do->do_xref_cnt) { + if (obj->do_xref_cnt) { DISPATCH_CRASH("release while external references exist"); } - return dx_dispose(dou._do); + return dx_dispose(obj); } DISPATCH_CRASH("over-release"); } @@ -146,42 +157,61 @@ void * dispatch_get_context(dispatch_object_t dou) { - return dou._do->do_ctxt; + struct dispatch_object_s *obj = DO_CAST(dou); + + return obj->do_ctxt; } void dispatch_set_context(dispatch_object_t dou, void *context) { - if (dou._do->do_ref_cnt != DISPATCH_OBJECT_GLOBAL_REFCNT) { - dou._do->do_ctxt = context; + struct dispatch_object_s *obj = DO_CAST(dou); + + if (obj->do_ref_cnt != DISPATCH_OBJECT_GLOBAL_REFCNT) { + obj->do_ctxt = context; } } void dispatch_set_finalizer_f(dispatch_object_t dou, dispatch_function_t finalizer) { - dou._do->do_finalizer = finalizer; + struct dispatch_object_s *obj = DO_CAST(dou); + + obj->do_finalizer = finalizer; } void dispatch_suspend(dispatch_object_t dou) { - if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) { + struct dispatch_object_s *obj = DO_CAST(dou); + + if (slowpath(obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) { return; } - dispatch_atomic_add(&dou._do->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL); + (void)dispatch_atomic_add(&obj->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL); } void dispatch_resume(dispatch_object_t dou) { - if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) { + struct dispatch_object_s *obj = DO_CAST(dou); + + // Global objects cannot be suspended or resumed. This also has the + // side effect of saturating the suspend count of an object and + // guarding against resuming due to overflow. + if (slowpath(obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) { return; } - switch (dispatch_atomic_sub(&dou._do->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL) + DISPATCH_OBJECT_SUSPEND_INTERVAL) { + + // Switch on the previous value of the suspend count. If the previous + // value was a single suspend interval, the object should be resumed. + // If the previous value was less than the suspend interval, the object + // has been over-resumed. + switch (dispatch_atomic_sub(&obj->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL) + DISPATCH_OBJECT_SUSPEND_INTERVAL) { case DISPATCH_OBJECT_SUSPEND_INTERVAL: - _dispatch_wakeup(dou._do); + _dispatch_wakeup(obj); break; + case DISPATCH_OBJECT_SUSPEND_LOCK: case 0: DISPATCH_CLIENT_CRASH("Over-resume of an object"); break; @@ -193,6 +223,8 @@ size_t dispatch_object_debug_attr(dispatch_object_t dou, char* buf, size_t bufsiz) { + struct dispatch_object_s *obj = DO_CAST(dou); + return snprintf(buf, bufsiz, "refcnt = 0x%x, suspend_cnt = 0x%x, ", - dou._do->do_ref_cnt, dou._do->do_suspend_cnt); + obj->do_ref_cnt, obj->do_suspend_cnt); } Modified: trunk/src/object_internal.h =================================================================== --- trunk/src/object_internal.h 2010-02-18 05:49:14 UTC (rev 186) +++ trunk/src/object_internal.h 2010-02-18 08:09:57 UTC (rev 187) @@ -72,7 +72,7 @@ unsigned int do_suspend_cnt; \ struct dispatch_queue_s *do_targetq; \ void *do_ctxt; \ - void *do_finalizer + dispatch_function_t do_finalizer #define DISPATCH_OBJECT_GLOBAL_REFCNT (~0u) #define DISPATCH_OBJECT_SUSPEND_LOCK 1u // "word and bit" must be a power of two to be safely subtracted
participants (1)
-
source_changes@macosforge.org