Date: Sat, 29 Dec 2001 17:10:34 -0800 (PST) From: Eric Albert <ejalbert@cs.stanford.edu> To: freebsd-gnats-submit@FreeBSD.org Subject: misc/33315: pthread_key_create does not zero out the new value Message-ID: <200112300110.fBU1AYH69103@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 33315 >Category: misc >Synopsis: pthread_key_create does not zero out the new value >Confidential: no >Severity: serious >Priority: high >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sat Dec 29 17:20:01 PST 2001 >Closed-Date: >Last-Modified: >Originator: Eric Albert >Release: 4.4-RELEASE >Organization: >Environment: Unavailable at the moment. Mail me if it's necessary and I'll sent it in. >Description: The man page for pthread_key_create(3) says this: "Upon key creation, the value NULL is associated with the new key in all active threads." On FreeBSD, the pthread implementation reuses keys immediately, so if you call pthread_key_create, pthread_key_delete on the created key, and pthread_key_create again, you get the same pthread_key_t as the original call to pthread_key_create returned. If you set a value on the current thread with the original key (using pthread_setspecific), pthread_getspecific will return that same value immediately after the second pthread_key_create. That's wrong -- by the man page, and to be useful for a program that uses, deletes, and reuses a substantial number of keys, calling pthread_key_create should set the key's value to zero on all threads. If it doesn't, there's no way to guarantee that the initial value for a new key is anything expected, since the same key might have been previously used and deleted in the same process. The behavior specified by the man page is the only way to ensure that a consistent value is set for a given key across all threads. >How-To-Repeat: Compile this as test.c with 'gcc -pthread -o test test.c'. Run ./test. The test will print a message at the end that says whether it succeeded. ----- #include <assert.h> #include <pthread.h> #include <stdio.h> int main(void) { pthread_key_t originalKey; pthread_key_t key; void *value; assert(pthread_key_create(&key, NULL) == 0); printf("Key is %ld\n", key); originalKey = key; value = pthread_getspecific(key); printf("Initial value is 0x%08x\n", (unsigned int) value); value = (void *) 0x12345678; assert(pthread_setspecific(key, value) == 0); printf("After setting key %ld to 0x%08x, value is 0x%08x\n", key, (unsigned int) value, (unsigned int) pthread_getspecific(key)); value = (void *) 0xabcdef12; assert(pthread_setspecific(key, value) == 0); printf("After setting key %ld to 0x%08x, value is 0x%08x\n", key, (unsigned int) value, (unsigned int) pthread_getspecific(key)); assert(pthread_key_delete(key) == 0); printf("Key %ld deleted\n", key); assert(pthread_key_create(&key, NULL) == 0); printf("New key is %ld\n", key); assert(key == originalKey); value = pthread_getspecific(key); printf("Initial value is 0x%08x\n", (unsigned int) value); if (value == 0) { printf("Test succeeded\n"); } else { printf("Test failed; value of a new key is non-zero\n"); } return 0; } >Fix: src/lib/libc_r/uthread/uthread_spec.c's _pthread_key_create function doesn't currently walk the list of all threads and zero out their value for *key. It'd need to do this. Another option is to do the zeroing in the same file in _pthread_key_delete, since that would ensure that if the key is reused its corresponding values are correct on all threads. >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200112300110.fBU1AYH69103>