Why do Glibc needs to hold a lock in tls_get_addr_tail?

Maxim Ostapenko chefmax7@gmail.com
Tue Dec 20 09:55:00 GMT 2016


Hi Glibc developers,

I had several issues with TLS on our system (BZ #17620 and BZ #18457
actually) and fortunately was able to fix them with corresponding
patches.
However, during investigation, I tried to understand details of TLS
implementation in Glibc (I was looking to current trunk) and was
confused by some code paths.
In particular, I can't understand following comment in
tls_get_addr_tail function:

static void *
__attribute_noinline__
tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
{
  [...]
  /* Make sure that, if a dlopen running in parallel forces the
     variable into static storage, we'll wait until the address in the
     static TLS block is set up, and use that.  If we're undecided
     yet, make sure we make the decision holding the lock as well.  */
  if (__glibc_unlikely (the_map->l_tls_offset
                        != FORCED_DYNAMIC_TLS_OFFSET))
    {
      __rtld_lock_lock_recursive (GL(dl_load_lock));
      if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET))
        {
          the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
          __rtld_lock_unlock_recursive (GL(dl_load_lock));
        }
      else if (__glibc_likely (the_map->l_tls_offset
                               != FORCED_DYNAMIC_TLS_OFFSET))
        {


How could it be that dynamic linker resolves thread local symbol to a
library that still not loaded (dlopen still running)?
The only case I can imagine here is something like this:

Thread 1
  Thread 2

while (!sym)
 dlopen ("libfoo.so". RTLD_GLOBAL);
  sym = dlsym (RTLD_DEFAULT, "foo");
*sym = ...

where "foo" is defined in libfoo.so library.

Is that the case we need to protect with lock inside
tls_get_addr_tail? Or maybe there is another test case for this code
path (perhaps in Glibc testsuite)?

Thanks,
-Maxim



More information about the Libc-help mailing list