public inbox for glibc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug dynamic-link/28248] New: is there a way to LD_PRELOAD library before other dynamic libraries?
@ 2021-08-19 12:57 mail at milianw dot de
2021-08-31 17:41 ` [Bug dynamic-link/28248] " amonakov at gmail dot com
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: mail at milianw dot de @ 2021-08-19 12:57 UTC (permalink / raw)
To: glibc-bugs
https://sourceware.org/bugzilla/show_bug.cgi?id=28248
Bug ID: 28248
Summary: is there a way to LD_PRELOAD library before other
dynamic libraries?
Product: glibc
Version: 2.33
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: dynamic-link
Assignee: unassigned at sourceware dot org
Reporter: mail at milianw dot de
Target Milestone: ---
Hey there, I hope this is the right place to report this.
I'm the author of heaptrack, which relies on LD_PRELOAD to intercept calls to
malloc and friends. Only recently, I realized my assumption about LD_PRELOAD
behavior is wrong - I thought it would be loaded _before_ all other dynamic
libraries, but that isn't the case.
See documentation over at
https://www.man7.org/linux/man-pages/man8/ld.so.8.html:
> LD_PRELOAD
> A list of additional, user-specified, ELF shared objects
> to be loaded before all others.
But as can be seen by the below, the preloaded library will be loaded after
other dependencies of the binary we are executing, i.e.:
```
$ cat preload_dump.c:
#include <stdio.h>
void __attribute__ ((constructor)) init(void)
{
fprintf(stderr, "preload init!\n");
}
void __attribute__ ((destructor)) cleanup(void)
{
fprintf(stderr, "preload cleanup!\n");
}
$ gcc -shared -fPIC -o preload_dump.so preload_dump.c
```
```
$ readelf -d $(which bash) | grep NEEDED
0x0000000000000001 (NEEDED) Shared library: [libtinfo.so.5]
0x0000000000000001 (NEEDED) Shared library: [libdl.so.2]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
```
```
LD_DEBUG=files LD_PRELOAD=$PWD/preload_dump.so bash --version
83:
83: file=/opt/craft/preload_dump.so [0]; needed by bash [0]
83: file=/opt/craft/preload_dump.so [0]; generating link map
83: dynamic: 0x00007fb5dbbd3dd0 base: 0x00007fb5dbbd2000 size:
0x0000000000002029
83: entry: 0x00007fb5dbbd2000 phdr: 0x00007fb5dbbd2040 phnum:
8
83:
83:
83: file=libtinfo.so.5 [0]; needed by bash [0]
83: file=libtinfo.so.5 [0]; generating link map
83: dynamic: 0x00007fb5db9b3d10 base: 0x00007fb5db78b000 size:
0x0000000000229f00
83: entry: 0x00007fb5db797e40 phdr: 0x00007fb5db78b040 phnum:
7
83:
83:
83: file=libdl.so.2 [0]; needed by bash [0]
83: file=libdl.so.2 [0]; generating link map
83: dynamic: 0x00007fb5db789d68 base: 0x00007fb5db587000 size:
0x0000000000203130
83: entry: 0x00007fb5db587e50 phdr: 0x00007fb5db587040 phnum:
7
83:
83:
83: file=libc.so.6 [0]; needed by bash [0]
83: file=libc.so.6 [0]; generating link map
83: dynamic: 0x00007fb5db57fb60 base: 0x00007fb5db1b9000 size:
0x00000000003cd200
83: entry: 0x00007fb5db1db660 phdr: 0x00007fb5db1b9040 phnum:
10
83:
83:
83: calling init: /lib64/libc.so.6
83:
83:
83: calling init: /lib64/libdl.so.2
83:
83:
83: calling init: /lib64/libtinfo.so.5
83:
83:
83: calling init: /opt/craft/preload_dump.so
83:
preload init!
83:
83: initialize program: bash
83:
83:
83: transferring control: bash
83:
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
83:
83: calling fini: bash [0]
83:
83:
83: calling fini: /opt/craft/preload_dump.so [0]
83:
preload cleanup!
83:
83: calling fini: /lib64/libtinfo.so.5 [0]
83:
83:
83: calling fini: /lib64/libdl.so.2 [0]
83:
```
Note how the needed libs of the binary are loaded before the LD_PRELOAD'ed
library. And note how that then obviously means the fini call for preload_dump
happens before e.g. libtinfo.so's fini call.
Is there a way for me to inject a library into the dynamic loader in such a
way, that it is loaded first before any other dependency of the executable?
In my case, the main reason why I want the above behavior is actually to
enforce proper shutdown semantics: As a memory profiler, I have an atexit
handler which is calling `__libc_freeres` and `__gnu_cxx::__freeres`, similar
to and inspired by valgrind. But because my preloaded library is loaded *after*
the other libraries, its cleanup code will run *before* that of other
libraries.
Combined, this can lead to crashes when another fini of some other library
calls code that depends on resources that get freed by the freeres calls.
so, tl;dr;
- is there a way to force something like LD_PRELOAD, but load the library
before all others?
- is there an alternative way to force an atexit handler call at the very end
of the shutdown semantics, after all other libraries got unloaded?
Many thanks!
--
You are receiving this mail because:
You are on the CC list for the bug.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Bug dynamic-link/28248] is there a way to LD_PRELOAD library before other dynamic libraries?
2021-08-19 12:57 [Bug dynamic-link/28248] New: is there a way to LD_PRELOAD library before other dynamic libraries? mail at milianw dot de
@ 2021-08-31 17:41 ` amonakov at gmail dot com
2021-09-06 8:19 ` mail at milianw dot de
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: amonakov at gmail dot com @ 2021-08-31 17:41 UTC (permalink / raw)
To: glibc-bugs
https://sourceware.org/bugzilla/show_bug.cgi?id=28248
Alexander Monakov <amonakov at gmail dot com> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |amonakov at gmail dot com
--- Comment #1 from Alexander Monakov <amonakov at gmail dot com> ---
You're mixing up two separate library orderings: the symbol lookup order (which
is what the man page implicitly refers to, it's breadth-first order over
DT_NEEDED links, with LD_PRELOAD modules appearing just after the main
executable and before its first DT_NEEDED library), and initialization order
(which is reverse topological order over DT_NEEDED links, assuming lack of
cycles).
To interpose malloc and the like, your library needs to appear prior to libc.so
in the former; also, your library in all likelihood depends on libc.so, so it
will appear after libc.so in the latter.
The log you've shown confirms this: preload_dump.so is loaded prior to
libtinfo.so.5, but its constructors are invoked last.
ELF gABI document explains this, please have a look:
http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#init_fini
--
You are receiving this mail because:
You are on the CC list for the bug.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Bug dynamic-link/28248] is there a way to LD_PRELOAD library before other dynamic libraries?
2021-08-19 12:57 [Bug dynamic-link/28248] New: is there a way to LD_PRELOAD library before other dynamic libraries? mail at milianw dot de
2021-08-31 17:41 ` [Bug dynamic-link/28248] " amonakov at gmail dot com
@ 2021-09-06 8:19 ` mail at milianw dot de
2021-09-06 8:32 ` fweimer at redhat dot com
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: mail at milianw dot de @ 2021-09-06 8:19 UTC (permalink / raw)
To: glibc-bugs
https://sourceware.org/bugzilla/show_bug.cgi?id=28248
--- Comment #2 from Milian Wolff <mail at milianw dot de> ---
I see, thank you!
Is there an alternative mechanism - potentially low-level / undocumented - that
I could leverage to somehow inject my interposing library in such a way, that
it's initialization happens after libc, but before any other libraries?
I.e. instead of this:
```
83: calling init: /lib64/libc.so.6
83:
83:
83: calling init: /lib64/libdl.so.2
83:
83:
83: calling init: /lib64/libtinfo.so.5
83:
83:
83: calling init: /opt/craft/preload_dump.so
```
I would like to somehow achieve this:
```
83: calling init: /lib64/libc.so.6
83:
83:
83: calling init: /opt/craft/preload_dump.so
83:
83:
83: calling init: /lib64/libdl.so.2
83:
83:
83: calling init: /lib64/libtinfo.so.5
```
That way, I can call `__libc_freeres` safely, as no other library code run -
except that of libc itself.
Thanks
--
You are receiving this mail because:
You are on the CC list for the bug.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Bug dynamic-link/28248] is there a way to LD_PRELOAD library before other dynamic libraries?
2021-08-19 12:57 [Bug dynamic-link/28248] New: is there a way to LD_PRELOAD library before other dynamic libraries? mail at milianw dot de
2021-08-31 17:41 ` [Bug dynamic-link/28248] " amonakov at gmail dot com
2021-09-06 8:19 ` mail at milianw dot de
@ 2021-09-06 8:32 ` fweimer at redhat dot com
2021-09-09 8:35 ` mail at milianw dot de
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: fweimer at redhat dot com @ 2021-09-06 8:32 UTC (permalink / raw)
To: glibc-bugs
https://sourceware.org/bugzilla/show_bug.cgi?id=28248
Florian Weimer <fweimer at redhat dot com> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |fweimer at redhat dot com
--- Comment #3 from Florian Weimer <fweimer at redhat dot com> ---
(In reply to Milian Wolff from comment #2)
> I see, thank you!
>
> Is there an alternative mechanism - potentially low-level / undocumented -
> that I could leverage to somehow inject my interposing library in such a
> way, that it's initialization happens after libc, but before any other
> libraries?
For glibc 2.34 on Linux, linking with -Wl,-z,initfirst should work. glibc
should no longer use DF_1_INITFIRST itself, so it's available for application
use.
> That way, I can call `__libc_freeres` safely, as no other library code run -
> except that of libc itself.
So this is about destructors? glibc currently does not guarantee that
destructors run in the opposite order of constructors (even without dlclose,
which can make some reordering necessary due to early unloading).
--
You are receiving this mail because:
You are on the CC list for the bug.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Bug dynamic-link/28248] is there a way to LD_PRELOAD library before other dynamic libraries?
2021-08-19 12:57 [Bug dynamic-link/28248] New: is there a way to LD_PRELOAD library before other dynamic libraries? mail at milianw dot de
` (2 preceding siblings ...)
2021-09-06 8:32 ` fweimer at redhat dot com
@ 2021-09-09 8:35 ` mail at milianw dot de
2021-09-09 8:54 ` mail at milianw dot de
2022-08-29 9:53 ` fweimer at redhat dot com
5 siblings, 0 replies; 7+ messages in thread
From: mail at milianw dot de @ 2021-09-09 8:35 UTC (permalink / raw)
To: glibc-bugs
https://sourceware.org/bugzilla/show_bug.cgi?id=28248
--- Comment #4 from Milian Wolff <mail at milianw dot de> ---
Thank you, I'll try out that linker flag and report back.
> So this is about destructors?
Yes, indeed. As a heap profiler and leak checker, I would like to call
`__libc_freeres` to silence leaks, similar to how valgrind does it. And I need
do that before any other library gets unloaded, as those could potentially try
to dlclose plugins loaded at runtime (this is what QtCore does). Doing that
after `__libc_freeres` would lead to crashes. So here I'm looking for ways of
preventing said crash.
> glibc currently does not guarantee that destructors run in the opposite order of constructors
Hm that sounds unfortunate. But if you say: "don't guarantee" - does it do it
normally, and there are just some corner cases where it wouldn't happen? As
long as it would help with the common case I'm running into (see above), it
would help me.
Cheers
--
You are receiving this mail because:
You are on the CC list for the bug.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Bug dynamic-link/28248] is there a way to LD_PRELOAD library before other dynamic libraries?
2021-08-19 12:57 [Bug dynamic-link/28248] New: is there a way to LD_PRELOAD library before other dynamic libraries? mail at milianw dot de
` (3 preceding siblings ...)
2021-09-09 8:35 ` mail at milianw dot de
@ 2021-09-09 8:54 ` mail at milianw dot de
2022-08-29 9:53 ` fweimer at redhat dot com
5 siblings, 0 replies; 7+ messages in thread
From: mail at milianw dot de @ 2021-09-09 8:54 UTC (permalink / raw)
To: glibc-bugs
https://sourceware.org/bugzilla/show_bug.cgi?id=28248
--- Comment #5 from Milian Wolff <mail at milianw dot de> ---
I just tried the linker flag with the example given above, but sadly it doesn't
help as only the `calling init` is changed, but `calling fini` isn't - this was
probably what you had in mind when you raised the potential issue about
constructor/destructor order.
```
$ gcc -shared -fPIC -o preload_dump.so preload_dump.c
LD_DEBUG=files LD_PRELOAD=$PWD/preload_dump.so bash --version |& grep -i
calling
7413: calling init: /lib64/ld-linux-x86-64.so.2
7413: calling init: /usr/lib/libc.so.6
7413: calling init: /usr/lib/libncursesw.so.6
7413: calling init: /usr/lib/libdl.so.2
7413: calling init: /usr/lib/libreadline.so.8
7413: calling init: /tmp/preload_dump.so
7413: calling fini: bash [0]
7413: calling fini: /tmp/preload_dump.so [0]
7413: calling fini: /usr/lib/libreadline.so.8 [0]
7413: calling fini: /usr/lib/libdl.so.2 [0]
7413: calling fini: /usr/lib/libncursesw.so.6 [0]
$ gcc -shared -fPIC -Wl,-z,initfirst -o preload_dump.so preload_dump.c
$ LD_DEBUG=files LD_PRELOAD=$PWD/preload_dump.so bash --version |& grep -i
calling
7373: calling init: /tmp/preload_dump.so
7373: calling init: /lib64/ld-linux-x86-64.so.2
7373: calling init: /usr/lib/libc.so.6
7373: calling init: /usr/lib/libncursesw.so.6
7373: calling init: /usr/lib/libdl.so.2
7373: calling init: /usr/lib/libreadline.so.8
7373: calling fini: bash [0]
7373: calling fini: /tmp/preload_dump.so [0]
7373: calling fini: /usr/lib/libreadline.so.8 [0]
7373: calling fini: /usr/lib/libdl.so.2 [0]
7373: calling fini: /usr/lib/libncursesw.so.6 [0]
```
Too bad! That would seem to indicate that I'm out of luck here and must stop
calling `__libc_freeres` - or does someone have an alternative suggestion I
could employ?
--
You are receiving this mail because:
You are on the CC list for the bug.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Bug dynamic-link/28248] is there a way to LD_PRELOAD library before other dynamic libraries?
2021-08-19 12:57 [Bug dynamic-link/28248] New: is there a way to LD_PRELOAD library before other dynamic libraries? mail at milianw dot de
` (4 preceding siblings ...)
2021-09-09 8:54 ` mail at milianw dot de
@ 2022-08-29 9:53 ` fweimer at redhat dot com
5 siblings, 0 replies; 7+ messages in thread
From: fweimer at redhat dot com @ 2022-08-29 9:53 UTC (permalink / raw)
To: glibc-bugs
https://sourceware.org/bugzilla/show_bug.cgi?id=28248
Florian Weimer <fweimer at redhat dot com> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|UNCONFIRMED |WAITING
Ever confirmed|0 |1
Last reconfirmed| |2022-08-29
--- Comment #6 from Florian Weimer <fweimer at redhat dot com> ---
In glibc 2.34, we stopped using -z initfirst for libpthread, which means that
is in theory now available for application use. Maybe using that for your
shared object is now an option?
--
You are receiving this mail because:
You are on the CC list for the bug.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2022-08-29 9:53 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-19 12:57 [Bug dynamic-link/28248] New: is there a way to LD_PRELOAD library before other dynamic libraries? mail at milianw dot de
2021-08-31 17:41 ` [Bug dynamic-link/28248] " amonakov at gmail dot com
2021-09-06 8:19 ` mail at milianw dot de
2021-09-06 8:32 ` fweimer at redhat dot com
2021-09-09 8:35 ` mail at milianw dot de
2021-09-09 8:54 ` mail at milianw dot de
2022-08-29 9:53 ` fweimer at redhat dot com
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).