]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
elf: Avoid some free (NULL) calls in _dl_update_slotinfo
authorFlorian Weimer <fweimer@redhat.com>
Mon, 3 Jun 2024 08:49:40 +0000 (10:49 +0200)
committerFlorian Weimer <fweimer@redhat.com>
Mon, 3 Jun 2024 17:02:19 +0000 (19:02 +0200)
This has been confirmed to work around some interposed mallocs.  Here
is a discussion of the impact test ust/libc-wrapper/test_libc-wrapper
in lttng-tools:

  New TLS usage in libgcc_s.so.1, compatibility impact
  <https://inbox.sourceware.org/libc-alpha/8734v1ieke.fsf@oldenburg.str.redhat.com/>

Reportedly, this patch also papers over a similar issue when tcmalloc
2.9.1 is not compiled with -ftls-model=initial-exec.  Of course the
goal really should be to compile mallocs with the initial-exec TLS
model, but this commit appears to be a useful interim workaround.

Fixes commit d2123d68275acc0f061e73d5f86ca504e0d5a344 ("elf: Fix slow
tls access after dlopen [BZ #19924]").

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
elf/dl-tls.c

index 7b3dd9ab60e89ae91820dfe1d5c5a947ed33682c..670dbc42fc2e3334739e115dd12390a8abefbd49 100644 (file)
@@ -819,7 +819,14 @@ _dl_update_slotinfo (unsigned long int req_modid, size_t new_gen)
                 dtv entry free it.  Note: this is not AS-safe.  */
              /* XXX Ideally we will at some point create a memory
                 pool.  */
-             free (dtv[modid].pointer.to_free);
+             /* Avoid calling free on a null pointer.  Some mallocs
+                incorrectly use dynamic TLS, and depending on how the
+                free function was compiled, it could call
+                __tls_get_addr before the null pointer check in the
+                free implementation.  Checking here papers over at
+                least some dynamic TLS usage by interposed mallocs.  */
+             if (dtv[modid].pointer.to_free != NULL)
+               free (dtv[modid].pointer.to_free);
              dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
              dtv[modid].pointer.to_free = NULL;