This is the mail archive of the
glibc-bugs@sourceware.org
mailing list for the glibc project.
[Bug dynamic-link/14379] New: shared object constructors are called in the wrong order
- From: "luto at mit dot edu" <sourceware-bugzilla at sourceware dot org>
- To: glibc-bugs at sources dot redhat dot com
- Date: Fri, 20 Jul 2012 19:12:14 +0000
- Subject: [Bug dynamic-link/14379] New: shared object constructors are called in the wrong order
- Auto-submitted: auto-generated
http://sourceware.org/bugzilla/show_bug.cgi?id=14379
Bug #: 14379
Summary: shared object constructors are called in the wrong
order
Product: glibc
Version: unspecified
Status: NEW
Severity: normal
Priority: P2
Component: dynamic-link
AssignedTo: unassigned@sourceware.org
ReportedBy: luto@mit.edu
Classification: Unclassified
[This is not clearly a bug in the strictest sense, as the ELF spec, AFAICT, has
nothing useful to say. It's rather unfortunate behavior, though, that makes
writing efficient and reliable malloc replacements very difficult, for
example.]
glibc's dynamic elf loader makes some effort to initialize an SO's DT_NEEDED
dependencies before initializing the SO that depended on them. This is nice.
Unfortunately, for sibling dependencies, it appears that the first library is
searched first for symbols (as required by the ELF spec) but the *last* library
is initialized first. This means that, if an earlier library overrides a
symbol called by the constructor of a later library, then the earlier library
is called before it is initialized.
This is quite unfortunate for malloc replacements. I have one that is intended
to be used with LD_PRELOAD, which causes its symbols to be searched first (as
desired) but causes it to be constructed last (which is bad).
Fixing this would be more complicated than just reversing the order of
initialization: it would still be good for deeper dependencies to be
initialized first.
As a demonstration, create lib.c and bin.c, as below. Then do:
$ for name in lib1 lib2 preload_lib; do gcc -DLIBNAME="\"$name\"" -fPIC -shared
-o ${name}.so lib.c -Wl,--no-undefined; done
$ gcc -Wl,--no-as-needed -o bin_12 bin.c lib1.so lib2.so -Wl,-rpath -Wl,.
$ gcc -Wl,--no-as-needed -o bin_1 bin.c lib1.so -Wl,-rpath -Wl,.
$ ./bin_12
lib2: ctor called. calling the_func
lib1: the_func called
lib1: NOT INITED!
lib1: ctor called. calling the_func
lib1: the_func called
main: calling the_func
lib1: the_func called
$ LD_PRELOAD=preload_lib.so ./bin_1
lib1: ctor called. calling the_func
preload_lib: the_func called
preload_lib: NOT INITED!
preload_lib: ctor called. calling the_func
preload_lib: the_func called
main: calling the_func
preload_lib: the_func called
-- start of lib.c --
#include <unistd.h>
#define PRINT(x) do { static const char __s[] = x; write(1, __s,
sizeof(__s)-1); } while(0)
static int inited = 0;
void the_func(void)
{
PRINT(" " LIBNAME ": the_func called\n");
if (!inited)
PRINT(" " LIBNAME ": NOT INITED!\n");
}
__attribute__((constructor)) static void ctor(void)
{
inited = 1;
PRINT(LIBNAME ": ctor called. calling the_func\n");
the_func();
}
-- end of lib.c --
-- start of bin.c --
#include <unistd.h>
#define PRINT(x) do { static const char __s[] = x; write(1, __s,
sizeof(__s)-1); } while(0)
extern void the_func(void);
int main()
{
PRINT("main: calling the_func\n");
the_func();
return 0;
}
-- end of bin.c --
--
Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.