mailing list of musl libc
 help / color / mirror / code / Atom feed
From: Rich Felker <dalias@libc.org>
To: musl@lists.openwall.com
Subject: Re: value of thread-specific data immediately after initialization
Date: Mon, 17 Sep 2018 16:54:56 -0400	[thread overview]
Message-ID: <20180917205456.GP17995@brightrain.aerifal.cx> (raw)
In-Reply-To: <1536871178.1074978.1507360824.56778F86@webmail.messagingengine.com>

On Thu, Sep 13, 2018 at 01:39:38PM -0700, Benjamin Peterson wrote:
> POSIX says that after the creation of a thread-specific key, its
> associated value should be NULL in all threads. musl may not uphold
> this requirement if a particular key is deleted and later resued.
> 
> Here's an example of the bug:
> 
> #include <pthread.h>
> #include <stdio.h>
> 
> int main() {
> 	pthread_key_t k;
> 	pthread_key_create(&k, NULL);
> 	printf("%p\n", pthread_getspecific(k));
> 	pthread_setspecific(k, &k);
> 	pthread_key_delete(k);
> 	pthread_key_create(&k, NULL);
> 	printf("%p\n", pthread_getspecific(k));
> 	pthread_key_delete(k);
> 	return 0;
> }
> 
> Per POSIX, I would expect this testcase to output two NULLs.
> However, musl prints the address of the old data even after the
> second initialization:
> 
> $ musl-gcc -o test test.c
> $ ./test 
> 0
> 0x7fff2ba3d004

I'm aware of this, and was aware of it when I wrote the code. My view
was that it's a programming error to delete a key while there are
still values associated with it, especially when the intended usage
has dtors (which obviously couldn't be run) linked to the keys, with
the implication that the data stored may have nontrivial destruction
requirements. However, this is not in agreement with POSIX, which
says:

    "The thread-specific data values associated with key need not be
    NULL at the time pthread_key_delete() is called."

I think this should be fixed, but I'm not sure the whole thing is
sufficiently specified. For example what is supposed to happen if a
call to pthread_key_delete is made concurrently with the exit of
another thread?

I think pthread_key_create and delete need to take an rwlock for write
on the keys (dtors) array, and __pthread_tsd_run_dtors needs to hold a
read lock while walking the list, releasing and reacquiring it
whenever it finds a dtor it needs to call. This at least makes it
thread-safe. The current code is not; if a key is deleted while data
remains, the loop in __pthread_tsd_run_dtors has a TOCTOU race where
it could find (self->tsd[i] && keys[i]) true, then crash when calling
keys[i] if keys[i] has become a null pointer.

For clearing values at delete time, I don't want to use sequence
numbers and lazy deletion. They waste a lot of memory, aren't robust
unless they're very large (at least 64-bit, preferably larger), and
slow down read access to tsd values. Instead I think we can move
pthread_key_delete to a separate file (so it doesn't pull in bulky
dependencies if not linked) and have it call __synccall to zero the
value in all threads. This is very expensive, but deletion is not
something you expect to have happen often if at all.

If we maintained a linked list of all live threads we could just walk
that instead, but doing that would impose heavy synchronization costs
on reasonable operations rather than just on unreasonable ones, I
think.

One mitigation of the cost would be not to reuse keys until they're
exhausted. That is, on deletion, set the dtor value to a sentinel
rather than clearing it. Then, pthread_key_create would only allocate
new key values that haven't been recycled until they all run out. When
they run out, __synccall would be used to clear all the stale values
at once, and all the sentinel dtor pointers could be cleared for
reuse.

Rich


  reply	other threads:[~2018-09-17 20:54 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-09-13 20:39 Benjamin Peterson
2018-09-17 20:54 ` Rich Felker [this message]
2018-09-18  3:18   ` Rich Felker

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180917205456.GP17995@brightrain.aerifal.cx \
    --to=dalias@libc.org \
    --cc=musl@lists.openwall.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).