[PATCH] elf: Fix ld.so SIGSEGV in trace mode with unresolved TLS symbols (BZ 34532)

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Thu Aug 20 12:12:31 GMT 2026


Oops, I forgot to update it.  Fixed locally.

On 20/08/26 06:56, mengqinggang wrote:
> The bug ID in elf/tst-trace-tls.c appears to be a placeholder (XXXXX).
> 
> 
> 在 2026/8/17 22:21, Adhemerval Zanella 写道:
>> On loongarch and hppa, running ld.so in trace mode on an object with
>> dynamic relocations against undefined TLS symbols crashes with SIGSEGV.
>>
>> Add the same NULL guards used by all other targets.
>>
>> Checked on loongarch64-linux-gnu-lp64d and hppa-linux-gnu.
>> ---
>>   elf/Makefile                   |  5 +++
>>   elf/tst-trace-tls-mod.c        | 41 +++++++++++++++++
>>   elf/tst-trace-tls.c            | 82 ++++++++++++++++++++++++++++++++++
>>   sysdeps/hppa/dl-machine.h      |  4 +-
>>   sysdeps/loongarch/dl-machine.h | 14 ++++--
>>   5 files changed, 141 insertions(+), 5 deletions(-)
>>   create mode 100644 elf/tst-trace-tls-mod.c
>>   create mode 100644 elf/tst-trace-tls.c
>>
>> diff --git a/elf/Makefile b/elf/Makefile
>> index dbc6cfec7fe..d9abbad1cf7 100644
>> --- a/elf/Makefile
>> +++ b/elf/Makefile
>> @@ -529,6 +529,7 @@ tests += \
>>     tst-tlsalign \
>>     tst-tlsalign-extern \
>>     tst-tlsgap \
>> +  tst-trace-tls \
>>     tst-unique1 \
>>     tst-unique2 \
>>     tst-unwind-ctor \
>> @@ -1108,6 +1109,7 @@ modules-names += \
>>     tst-tlsmod7 \
>>     tst-tlsmod8 \
>>     tst-tlsmod9 \
>> +  tst-trace-tls-mod \
>>     tst-unique1mod1 \
>>     tst-unique1mod2 \
>>     tst-unique2mod1 \
>> @@ -3544,6 +3546,9 @@ $(objpfx)tst-nodeps2-mod.so: $(common-objpfx)libc.so \
>>   $(objpfx)tst-nodeps2.out: \
>>     $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.so
>>   +$(objpfx)tst-trace-tls.out: $(objpfx)tst-trace-tls-mod.so $(objpfx)ld.so
>> +tst-trace-tls-mod.so-no-z-defs = yes
>> +
>>   $(objpfx)tst-tlsgap: $(shared-thread-library)
>>   $(objpfx)tst-tlsgap.out: \
>>     $(objpfx)tst-tlsgap-mod0.so \
>> diff --git a/elf/tst-trace-tls-mod.c b/elf/tst-trace-tls-mod.c
>> new file mode 100644
>> index 00000000000..7b855fd814c
>> --- /dev/null
>> +++ b/elf/tst-trace-tls-mod.c
>> @@ -0,0 +1,41 @@
>> +/* Shared object with relocations against undefined TLS symbols.
>> +   Copyright (C) 2026 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   The GNU C Library is free software; you can redistribute it and/or
>> +   modify it under the terms of the GNU Lesser General Public
>> +   License as published by the Free Software Foundation; either
>> +   version 2.1 of the License, or (at your option) any later version.
>> +
>> +   The GNU C Library is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +   Lesser General Public License for more details.
>> +
>> +   You should have received a copy of the GNU Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <https://www.gnu.org/licenses/>.  */
>> +
>> +extern __thread int missing_tls_gd
>> +  __attribute__ ((tls_model ("global-dynamic")));
>> +extern __thread int missing_tls_ie
>> +  __attribute__ ((tls_model ("initial-exec")));
>> +extern int missing_data;
>> +
>> +int
>> +access_tls_gd (void)
>> +{
>> +  return missing_tls_gd;
>> +}
>> +
>> +int
>> +access_tls_ie (void)
>> +{
>> +  return missing_tls_ie;
>> +}
>> +
>> +int
>> +access_data (void)
>> +{
>> +  return missing_data;
>> +}
>> diff --git a/elf/tst-trace-tls.c b/elf/tst-trace-tls.c
>> new file mode 100644
>> index 00000000000..2d541b1a519
>> --- /dev/null
>> +++ b/elf/tst-trace-tls.c
>> @@ -0,0 +1,82 @@
>> +/* Check that trace mode handles unresolved TLS symbols (bug XXXXX).
>> +   Copyright (C) 2026 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   The GNU C Library is free software; you can redistribute it and/or
>> +   modify it under the terms of the GNU Lesser General Public
>> +   License as published by the Free Software Foundation; either
>> +   version 2.1 of the License, or (at your option) any later version.
>> +
>> +   The GNU C Library is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +   Lesser General Public License for more details.
>> +
>> +   You should have received a copy of the GNU Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <https://www.gnu.org/licenses/>.  */
>> +
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +#include <support/capture_subprocess.h>
>> +#include <support/check.h>
>> +#include <support/support.h>
>> +
>> +/* Check if unresolved TLS symbol in trace mode (LD_TRACE_LOADED_OBJECTS)
>> +   is correctly reported.  */
>> +
>> +static char *mod;
>> +
>> +static struct support_capture_subprocess
>> +run_ldso (const char *env1, const char *env2)
>> +{
>> +  char *const argv[] =
>> +    { (char *) support_objdir_elf_ldso, (char *) mod, NULL };
>> +  char *const envp[] =
>> +    { (char *) "LD_TRACE_LOADED_OBJECTS=1", (char *) env1, (char *) env2,
>> +      NULL };
>> +
>> +  struct support_capture_subprocess result
>> +    = support_capture_subprogram (argv[0], argv, envp);
>> +  support_capture_subprocess_check (&result, "tst-trace-tls", 0,
>> +                    sc_allow_stdout | sc_allow_stderr);
>> +  return result;
>> +}
>> +
>> +static void
>> +run_trace (const char *title, const char *env1, const char *env2,
>> +       bool check_undefined)
>> +{
>> +  printf ("info: checking %s\n", title);
>> +
>> +  struct support_capture_subprocess result = run_ldso (env1, env2);
>> +
>> +  if (check_undefined)
>> +    {
>> +      TEST_VERIFY (strstr (result.err.buffer,
>> +               "undefined symbol: missing_tls_gd") != NULL);
>> +      TEST_VERIFY (strstr (result.err.buffer,
>> +               "undefined symbol: missing_tls_ie") != NULL);
>> +      TEST_VERIFY (strstr (result.err.buffer,
>> +               "undefined symbol: missing_data") != NULL);
>> +    }
>> +
>> +  support_capture_subprocess_free (&result);
>> +}
>> +
>> +static int
>> +do_test (void)
>> +{
>> +  mod = xasprintf ("%s/elf/tst-trace-tls-mod.so", support_objdir_root);
>> +
>> +  run_trace ("ldd -d", "LD_WARN=yes", NULL, true);
>> +  run_trace ("ldd -r", "LD_WARN=yes", "LD_BIND_NOW=1", true);
>> +  run_trace ("ldd -u", "LD_DEBUG=unused", NULL, false);
>> +
>> +  free (mod);
>> +
>> +  return 0;
>> +}
>> +
>> +#include <support/test-driver.c>
>> diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h
>> index 9bdbd85b6b3..ba2e4123c6e 100644
>> --- a/sysdeps/hppa/dl-machine.h
>> +++ b/sysdeps/hppa/dl-machine.h
>> @@ -700,7 +700,9 @@ elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
>>     #if !defined RTLD_BOOTSTRAP
>>       case R_PARISC_TLS_DTPMOD32:
>> -      value = sym_map->l_tls_modid;
>> +      /* The sym_map may be NULL in trace mode (LD_TRACE_LOADED_OBJECTS).  */
>> +      if (sym_map != NULL)
>> +    value = sym_map->l_tls_modid;
>>         break;
>>         case R_PARISC_TLS_DTPOFF32:
>> diff --git a/sysdeps/loongarch/dl-machine.h b/sysdeps/loongarch/dl-machine.h
>> index ae295264ae9..1fb2635f92e 100644
>> --- a/sysdeps/loongarch/dl-machine.h
>> +++ b/sysdeps/loongarch/dl-machine.h
>> @@ -197,16 +197,22 @@ elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
>>     #ifndef RTLD_BOOTSTRAP
>>       case __WORDSIZE == 64 ? R_LARCH_TLS_DTPMOD64 : R_LARCH_TLS_DTPMOD32:
>> -      *addr_field = sym_map->l_tls_modid;
>> +      /* The sym_map may be NULL in trace mode (LD_TRACE_LOADED_OBJECTS).  */
>> +      if (sym_map != NULL)
>> +    *addr_field = sym_map->l_tls_modid;
>>         break;
>>         case __WORDSIZE == 64 ? R_LARCH_TLS_DTPREL64 : R_LARCH_TLS_DTPREL32:
>> -      *addr_field = TLS_DTPREL_VALUE (sym) + reloc->r_addend;
>> +      if (sym != NULL)
>> +    *addr_field = TLS_DTPREL_VALUE (sym) + reloc->r_addend;
>>         break;
>>         case __WORDSIZE == 64 ? R_LARCH_TLS_TPREL64 : R_LARCH_TLS_TPREL32:
>> -      CHECK_STATIC_TLS (map, sym_map, sym);
>> -      *addr_field = TLS_TPREL_VALUE (sym_map, sym) + reloc->r_addend;
>> +      if (sym != NULL)
>> +    {
>> +      CHECK_STATIC_TLS (map, sym_map, sym);
>> +      *addr_field = TLS_TPREL_VALUE (sym_map, sym) + reloc->r_addend;
>> +    }
>>         break;
>>         case __WORDSIZE == 64 ? R_LARCH_TLS_DESC64 : R_LARCH_TLS_DESC32:
> 



More information about the Libc-alpha mailing list