From a7bd809fa906df28f503acd985c306c875b6acbf Mon Sep 17 00:00:00 2001 From: Simon Evans Date: Thu, 13 Jul 2017 15:39:38 +0100 Subject: [PATCH] [TLS]: Pass a heap-allocated value to pthread_setspecific() - pthread_setspecific() requires the pointer passed as a value to be either NULL or allocated on the heap as the destructor called when the thread exits will pass this value to free(). - __dispatch_tsd is already allocated per thread as it is declared using __thread so it is stored in the .tbss not the heap. Allocate a pointer to hold the address of __dispatch_tsd instead of passing the address directly to satisfy pthread_setspecific() and still allow _libdispatch_tsd_cleanup() to retrieve the address. --- src/queue.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/queue.c b/src/queue.c index 2406e7e7b..874df2f15 100644 --- a/src/queue.c +++ b/src/queue.c @@ -900,7 +900,7 @@ _dispatch_install_thread_detach_callback(dispatch_function_t cb) void _libdispatch_tsd_cleanup(void *ctx) { - struct dispatch_tsd *tsd = (struct dispatch_tsd*) ctx; + struct dispatch_tsd *tsd = *(struct dispatch_tsd **)ctx; _tsd_call_cleanup(dispatch_priority_key, NULL); _tsd_call_cleanup(dispatch_r2k_key, NULL); @@ -933,7 +933,15 @@ DISPATCH_NOINLINE void libdispatch_tsd_init(void) { - pthread_setspecific(__dispatch_tsd_key, &__dispatch_tsd); + // pthread_setspecific() requires the value to be heap allocated + // memory as it gets free()'d by the pthread destructor. + struct dispatch_tsd **tsd_ptr = malloc(sizeof(struct dispatch_tsd *)); + if (tsd_ptr == NULL) { + perror("malloc"); + exit(1); + } + *tsd_ptr = &__dispatch_tsd; + pthread_setspecific(__dispatch_tsd_key, tsd_ptr); __dispatch_tsd.tid = gettid(); } #endif