[patch v1] nptl: namespace-safe pthread keys implementation
Florian Weimer
fweimer@redhat.com
Fri Jul 3 11:14:19 GMT 2026
* Adhemerval Zanella Netto:
> The old design stored a generation sequence number in both the global
> slot and the per-thread slot (KEY_UNUSED and KEY_USABLE). When a key
> was deleted and its slot reused, per-thread values from the old key
> failed the sequence-number check in pthread_getspecific and
> deallocate_tsd, and were silently ignored.
>
> This new design replaces this with something like zero existing
> per-thread slots at key creation. It is seems somewhat weaker:
>
> * a thread calling pthread_setspecific(K, v) reads the global slot
> (outside any lock) to validate K, then writes its per-thread
> slot. Between those two steps, another thread can delete K and a third
> thread can create a new key that reuses the same slot. The first
> thread's write then silently deposits a value for the new key.
But the old scheme has the same problem? It's already use-after-free on
K if it's used after pthread_key_delete.
> * __nptl_deallocate_tsd reads the global destructor and the per-thread
> value with no synchronisation between them. If the key is deleted and
> reused between those two reads, the wrong destructor may be called
> with the wrong value.
>
>
> I think either it will need to keep the generation counter or add
> synchronization between pthread_setspecific and rely on delete-time
> zeroing. The extra synchronization adds more synchronization what
> should be fast-path, so I am not sure which one is preferable.
A simple scheme does not immediately come to my mind.
We could perhaps use an rwlock. I'm not sure if we need to hold a lock
while the destructors are running. It looks to me glibc is only
responsible for avoiding calling the wrong destructor/value combination,
not that no destructors are called after pthread_key_delete returns.
Thanks,
Florian
More information about the Libc-alpha
mailing list