[PATCH] elf: Don't crash in dlsym() when tail-called from a constructor [BZ #34156]
Florian Weimer
fw@deneb.enyo.de
Sun May 17 14:16:54 GMT 2026
* Daan De Meyer:
> Tail-call optimization is a legal C transformation and there is no way
> for the dynamic linker to recover the real caller from the elided frame.
> Detect the situation by its observable effect — a link map with no
> l_scope — and fall back to the main program's link map, the same
> treatment used when the caller's address is otherwise unrecognized.
Agreed. We should fix this in a different way eventually (pass the
caller link map in a hidden argument), but such a fix is of course
more difficult.
> diff --git a/elf/dl-sym-post.h b/elf/dl-sym-post.h
> index 8f45298cc9..514f5e623f 100644
> --- a/elf/dl-sym-post.h
> +++ b/elf/dl-sym-post.h
> @@ -22,12 +22,17 @@ static struct link_map *
> _dl_sym_find_caller_link_map (ElfW(Addr) caller)
> {
> struct link_map *l = _dl_find_dso_for_object (caller);
> + /* If the resolved caller has no usable lookup scope, the real caller is
> + a constructor that tail-called dlsym(): __builtin_return_address(0)
> + in the public dlsym() wrapper read through the elided frame and landed
> + inside call_init() in ld.so, which has no l_scope. Using that link
> + map for a lookup would deref NULL. Treat it like an unknown caller
> + and fall back to the main program's link map. */
> + if (l != NULL && l->l_scope != NULL)
> return l;
> + /* If the address is not recognized the call comes from the main
> + program (we hope). */
> + return GL(dl_ns)[LM_ID_BASE]._ns_loaded;
> }
I would appreciate if you could clean up the comments a bit: the l ==
NULL case could be call from JIT-generated code. GNU style doesn't
use () after function names. I don't think it's necessary to mention
__builtin_return_address, just mention tail calls and that l_scope is
not set for the ld.so link map. I think it would be more likely for
this bug to happen due to dlopen than to dlsym because dlopen at least
has an effect, so tail calls seem more likely.
The l_scope crash can also happen with JIT-generated code before bug
31943 was fixed. This is just for folks find this thread later. I
don't think we should document this in the sources.
More information about the Libc-alpha
mailing list