[PATCH 2/2] aarch64: Add workaround for GDB bug handling string literals

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Thu Jul 2 12:59:23 GMT 2026



On 02/07/26 05:10, Yury Khrustalev wrote:
> On Wed, Jul 01, 2026 at 01:25:14PM -0300, Adhemerval Zanella Netto wrote:
>>
>> On 01/07/26 12:53, Yury Khrustalev wrote:
>>> On Wed, Jul 01, 2026 at 12:25:59PM -0300, Adhemerval Zanella Netto wrote:
>>>>>
>>>>> ...
>>>>>
>>>>> OK, I see. Well, resolvers should be as simple as possible, so I'd
>>>>> rather do the check in the arch-specific way if it makes it smaller.
>>>>>
>>>>> However, a resolver can be correctly called from other places. For
>>>>> example, many binary instrumentation frameworks substitute dynamic
>>>>> loader and try to implement everything that a usual dynamic loader
>>>>> would do. With Wilco's approach, these use cases will work provided
>>>>> that the arguments for the resolver are compliant with the ABI, but
>>>>> a check based on the return address will fail rendering many valid
>>>>> use cases incorrect.
>>>>
>>>> But for ifunc resolver entered with ambiguous register state, we cannot satisfy
>>>> both:
>>>>
>>>> * Caller wants the resolver to behave like the function call (i.e - malloc 
>>>>   do the allocation).
>>>
>>> I don't think we should even discuss this.
>>>
>>>> * Caller wants the resolver to return the resolved address.
>>>
>>> If caller wants something else from an ifunc resolver, it is an error
>>> and we should abort.
>>>
>>>>
>>>> The on-entry state doesn't reliably encode intent across targets and ABI 
>>>> versions. On aarch64 you could test arg1 & _IFUNC_ARG_HWCAP, but:
>>>>
>>>> 1. that only separates new-ABI resolver call from everything else, it doesn't 
>>>>    rescue legacy case-2 callers (or any other ifunc that uses more 2 argument).
>>>
>>> Yep, as Wilco suggested we can use
>>>
>>>   (arg0 & ~_IFUNC_ARG_HWCAP) == GLRO (dl_hwcap)
>> It still has a hole, any resolver(n) where (n~_IFUNC_ARG_HWCAP) == dl_hwcap
>> passes the check.  It might not a problem for malloc, but maybe for 
>> environments that manipulate hwcap (valgrind, etc.) that calls other ifunc 
>> besides malloc we might hit it eventually.
>>
>> Maybe the arg0 maybe be added as a complementary arch-specific check after
>> the _dl_rtld_map bounds check.  The bound check still has the advantage of 
>> being platform-neutral and generic enough to not require any extra arch 
>> handling if some maintainer wants to enable malloc ifunc.
> 
> Adhemerval, I already explained that bounds check will render some use
> cases not working. Here is another example to demonstrate this problem.
> 
> GDB can call 'malloc' in different ways, e.g.
> 
>   a) internally to facilitate expression evaluation (this is where we're
>      having a problem right now, and this is what Florian's patch fixes)
> 
>   b) when 'malloc' is called as part of the expression.
> 
> Observe:
> 
>   (gdb) br main
>   (gdb) r
>   Breakpoint 1, main (...) at ...
>   (gdb) call printf("%s\n", "hello")
>   hello
>   $1 = 6
>   (gdb) p malloc(23)
>   Program received signal SIGSEGV, Segmentation fault.
>   0x0000ffff0828f010 in ?? ()
>   The program being debugged was signaled while in a function called from GDB.
> 
> This is with Florian's patch. Once again, this is not the only problem
> you have to solve. I suppose your suggestion above in this thread may
> work, however, like I already said, allowing resolvers to be only called
> from libc itself will make other runtimes stop working.
> 
> I think we've wasted enough time on try to find a "bug-compatible"
> implementation. I don't think we should be doing this at all. Bugs
> should be fixed. Complying software should not be the victim of bugs
> in other tools.

I think we are talking past each other since we have multiple divergent
ideas on how to approach this issue.

My point is *if* we decide to push a workaround in glibc to handle direct
malloc calls in gdb, I think we should do some as below. With this patch
applied:

  $ gdb -q -batch -ex "b main" -ex "run" -ex "p malloc(23)" --args malloc/tst-valloc-mcheck --direct
  Breakpoint 1 at 0x24c0: file ../support/test-driver.c, line 112.
  warning: Unable to find libthread_db matching inferior's thread library, thread debugging will not be available.

  Breakpoint 1, main (argc=2, argv=0xffffffffede8) at ../support/test-driver.c:112
  112     {
  malloc called in wrong context
  [Inferior 1 (process 530903) exited with code 0177]
  The program being debugged exited while in a function called from GDB.
  Evaluation of the expression containing the function
  (__libc_malloc_redirect_ifunc) will be abandoned.

So no crypt SIGSEGV triggered, platform agnostic, and with a clear indication
that this is not supported.  The gdb will need to proper call the function
through the GOT, which then will either trigger the lazy resolution (and thus
make ld.so call the ifunc resolver) or issue the resolved implementation directly
- thus mimic what the process itself is expected to do.

But I am not really proposing we go for this route, and I tend to agree that
fixing gdb and other tools is a better alternative. 

As far as I understand there is no easy way solely in the malloc ifunc
resolver context to make it bug compatible (which is not something I am *not*
advocating by the way) *and* make malloc 'work'.  We need to pick a poison: 
provide malloc as ifunc and disable this usercase by these tools; or work 
toward fixing the tools to proper handle it.


diff --git a/elf/Versions b/elf/Versions
index 1591031da99..5fe481d676e 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -79,5 +79,7 @@ ld {
     # Set value of a tunable.
     __tunable_is_initialized;
     __tunable_get_val;
+
+    _dl_rtld_map;
   }
 }
diff --git a/elf/rtld.c b/elf/rtld.c
index e5ba71fef18..02ba23e67ef 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -377,6 +377,7 @@ extern struct rtld_global_ro _rtld_local_ro
     __attribute__ ((alias ("_rtld_global_ro"), visibility ("hidden")));

 struct link_map _dl_rtld_map;
+rtld_hidden_def (_dl_rtld_map)
 struct auditstate _dl_rtld_auditstate[DL_NNS];

 static void dl_main (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
diff --git a/sysdeps/aarch64/multiarch/malloc-ifuncs.c b/sysdeps/aarch64/multiarch/malloc-ifuncs.c
index 648fb617de7..e0bc9843795 100644
--- a/sysdeps/aarch64/multiarch/malloc-ifuncs.c
+++ b/sysdeps/aarch64/multiarch/malloc-ifuncs.c
@@ -22,8 +22,22 @@
 #include <malloc-api.h>
 #include <shlib-compat.h>

-libc_ifunc_hidden (__libc_malloc, __libc_malloc_redirect,
-                  __libc_malloc)
+#include <sys/ifunc.h>
+
+static __typeof (__libc_malloc) *
+malloc_ifunc_call (uintptr_t return_address)
+{
+#ifdef SHARED
+  if (!(_dl_rtld_map.l_map_start <= return_address
+       && return_address < _dl_rtld_map.l_map_end))
+    _dl_fatal_printf ("malloc called in wrong context\n");
+#endif
+  return __libc_malloc;
+}
+
+__ifunc_hidden (__libc_malloc, __libc_malloc_redirect,
+               malloc_ifunc_call ((uintptr_t) __builtin_return_address (0)),
+               size_t size, INIT_ARCH)
 strong_alias (__libc_malloc_redirect, malloc)

 libc_ifunc_hidden (__libc_calloc, __libc_calloc_redirect,
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index f94247ad9fb..774f3c0f911 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1357,7 +1357,8 @@ rtld_active (void)
 }

 /* Pre-allocated link map for the dynamic linker itself.  */
-extern struct link_map _dl_rtld_map attribute_hidden;
+extern struct link_map _dl_rtld_map /*attribute_hidden*/;
+rtld_hidden_proto (_dl_rtld_map)

 /* Used to store the audit information for the link map of the
    dynamic loader.  */


More information about the Libc-alpha mailing list