From 557337b9348f29b29acb4b226fd8ffddf5f22d30 Mon Sep 17 00:00:00 2001 From: Pino Toscano Date: Wed, 2 Nov 2011 17:38:46 +0100 Subject: [PATCH] Remove all the values when deleting a key When deleting a key using `pthread_key_delete', delete all the values associated to that key in all the threads available. Otherwise, the key reuse in `pthread_key_create' can cause new keys to have thread specific data of the previously used key with the same index. Add a test for this case, which creates and deletes pairs of keys checking that they have a NULL thread specific data after creation. * sysdeps/hurd/pt-key-delete.c (pthread_key_delete): Remove all the values of the key in all the threads. * tests/Makefile (CHECK_SRC): Add test-17.c. * tests/test-17.c: New file. --- sysdeps/hurd/pt-key-delete.c | 19 ++++++++++++++ tests/Makefile | 2 +- tests/test-17.c | 57 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletions(-) create mode 100644 tests/test-17.c diff --git a/sysdeps/hurd/pt-key-delete.c b/sysdeps/hurd/pt-key-delete.c index 2426bb1..9d88647 100644 --- a/sysdeps/hurd/pt-key-delete.c +++ b/sysdeps/hurd/pt-key-delete.c @@ -35,8 +35,27 @@ pthread_key_delete (pthread_key_t key) err = EINVAL; else { + int i; + __pthread_key_destructors[key] = PTHREAD_KEY_INVALID; __pthread_key_invalid_count ++; + + pthread_rwlock_rdlock (&__pthread_threads_lock); + for (i = 0; i < __pthread_num_threads; ++i) + { + struct __pthread *t; + + t = __pthread_threads[i]; + + if (t == NULL) + continue; + + /* Just remove the key, no need to care whether it was + already there. */ + if (t->thread_specifics) + hurd_ihash_remove (t->thread_specifics, key); + } + pthread_rwlock_unlock (&__pthread_threads_lock); } __pthread_mutex_unlock (&__pthread_key_lock); diff --git a/tests/Makefile b/tests/Makefile index 9509c95..4e2a4a8 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -4,7 +4,7 @@ LDLIBS = -lpthread CHECK_SRC := test-1.c test-2.c test-3.c test-6.c test-7.c test-8.c \ test-9.c test-10.c test-11.c test-12.c test-13.c test-14.c \ - test-15.c test-16.c + test-15.c test-16.c test-17.c CHECK_OBJS := $(addsuffix .o,$(basename $(notdir $(CHECK_SRC)))) CHECK_PROGS := $(basename $(notdir $(CHECK_SRC))) \ diff --git a/tests/test-17.c b/tests/test-17.c new file mode 100644 index 0000000..a8bd150 --- /dev/null +++ b/tests/test-17.c @@ -0,0 +1,57 @@ +/* Test that the key reuse inside libpthread does not cause thread + specific values to persist. */ + +#define _GNU_SOURCE 1 + +#include +#include +#include +#include + +void +work (int iter) +{ + error_t err; + pthread_key_t key1; + pthread_key_t key2; + void *value1; + void *value2; + + printf ("work/%d: start\n", iter); + err = pthread_key_create (&key1, NULL); + assert (err == 0); + err = pthread_key_create (&key2, NULL); + assert (err == 0); + + value1 = pthread_getspecific (key1); + value2 = pthread_getspecific (key2); + printf ("work/%d: pre-setspecific: %p,%p\n", iter, value1, value2); + assert (value1 == NULL); + assert (value2 == NULL); + err = pthread_setspecific (key1, (void *)(0x100 + iter)); + assert (err == 0); + err = pthread_setspecific (key2, (void *)(0x200 + iter)); + assert (err == 0); + + value1 = pthread_getspecific (key1); + value2 = pthread_getspecific (key2); + printf ("work/%d: post-setspecific: %p,%p\n", iter, value1, value2); + assert (value1 == (void *)(0x100 + iter)); + assert (value2 == (void *)(0x200 + iter)); + + err = pthread_key_delete (key1); + assert (err == 0); + err = pthread_key_delete (key2); + assert (err == 0); +} + +int +main (int argc, char *argv[]) +{ + int i; + + for (i = 0; i < 8; ++i) + work (i + 1); + + return 0; +} -- 1.7.7