This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug dynamic-link/14379] New: shared object constructors are called in the wrong order


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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]