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 libc/1319] New: dlsym/RTLD_NEXT is broken when more than 1 lib has the symbol.


The dlsym(RTLD_NEXT, "foo") is broken when more than one library contain the  "foo".

Here are some samples :

Here are 2 little programs and 4 libraries to underline the faulty behaviour:
# the libraries:
for i in 1 2 3 4
do
cat > lib$i.c <<EOF
#include <stdio.h>
#include <dlfcn.h>
void foo() {
     void (*next_foo)(void);
     printf("lib$i.foo()\n");
     if (next_foo = (void (*)(void)) dlsym(RTLD_NEXT, "foo")) next_foo();
}

EOF
gcc -shared -fPIC lib$i.c -o lib$i.so -D_GNU_SOURCE
done
# the test program liking libs at compile time:
cat > chain.c <<EOF
#include <dlfcn.h>
extern void foo();
int main() {
     foo();
     return 0;
}

EOF
gcc chain.c -o chain -L. -l1 -l2 -l3 -l4 -ldl
LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./chain

#And the result :
#
# lib1.foo()
# lib2.foo()
# lib3.foo()
# lib4.foo()
#
# And now a runtime linking version:
#
cat > chain2.c <<EOF
#include <dlfcn.h>
int main() {
         void *l1, *l2, *l3, *l4;
         void (*bar)();
         l1 = dlopen("lib1.so", RTLD_NOW | RTLD_GLOBAL);
         l2 = dlopen("lib2.so", RTLD_NOW | RTLD_GLOBAL);
         l3 = dlopen("lib3.so", RTLD_NOW | RTLD_GLOBAL);
         l4 = dlopen("lib4.so", RTLD_NOW | RTLD_GLOBAL);
         bar = (void (*)()) dlsym(RTLD_DEFAULT, "foo");
         bar();
         dlclose(l4);
         dlclose(l3);
         dlclose(l2);
         dlclose(l1);
         return 0;
}

EOF
gcc chain2.c -o chain2 -ldl -D_GNU_SOURCE
#
LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./chain2
#
# And the result :
#
# lib1.foo()
#

On alternate plateforms (bsd/libtld, Sun/libdl) the result is :

lib1.foo()
lib2.foo()
lib3.foo()
lib4.foo()



Here is a more verbose version of chain2:


cat > chain5.c <<EOF
#include <dlfcn.h>
int main() {
         void *l1, *l2, *l3, *l4;
         void (*bar)();

         l1 = dlopen("lib1.so", RTLD_NOW | RTLD_GLOBAL);
         bar = (void (*)()) dlsym(l1, "foo");
                printf("l1 is %x l1.foo is %x\n", l1, bar);

         l2 = dlopen("lib2.so", RTLD_NOW | RTLD_GLOBAL);
         bar = (void (*)()) dlsym(l2, "foo");
                printf("l2 is %x l2.foo is %x\n", l2, bar);

         l3 = dlopen("lib3.so", RTLD_NOW | RTLD_GLOBAL);
         bar = (void (*)()) dlsym(l3, "foo");
                printf("l3 is %x l3.foo is %x\n", l3, bar);

         l4 = dlopen("lib4.so", RTLD_NOW | RTLD_GLOBAL);
         bar = (void (*)()) dlsym(l4, "foo");
                printf("l4 is %x l4.foo is %x\n", l4, bar);

         bar = (void (*)()) dlsym(l1, "foo");
                printf("l1.foo is %x \n", bar);
         bar = (void (*)()) dlsym(l2, "foo");
                printf("l2.foo is %x \n", bar);
         bar = (void (*)()) dlsym(l3, "foo");
                printf("l3.foo is %x \n", bar);
         bar = (void (*)()) dlsym(l4, "foo");
                printf("l4.foo is %x \n", bar);

         bar = (void (*)()) dlsym(RTLD_DEFAULT, "foo");
                printf("default foo is %x \n", bar);

         bar();
         dlclose(l4);
         dlclose(l3);
         dlclose(l2);
         dlclose(l1);
         return 0;
}

EOF
gcc chain5.c -o chain5 -ldl -D_GNU_SOURCE

LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./chain5

And the result looks like this :

l1 is 804a018 l1.foo is 5556d584
l2 is 804a3b0 l2.foo is 55570584
l3 is 804a710 l3.foo is 55572584
l4 is 804aa70 l4.foo is 55574584
l1.foo is 5556d584
l2.foo is 55570584
l3.foo is 55572584
l4.foo is 55574584
default foo is 5556d584
lib1.foo()

Running the chain2 program with LD_DEBUG="files symbols" gives :

      14129:     symbol=dlsym;  lookup in file=./chain2
      14129:     symbol=dlsym;  lookup in file=/lib/tls/libdl.so.2
      14129:     symbol=_dl_sym;  lookup in file=./chain2
      14129:     symbol=_dl_sym;  lookup in file=/lib/tls/libdl.so.2
      14129:     symbol=_dl_sym;  lookup in file=/lib/tls/libc.so.6
      14129:     symbol=foo;  lookup in file=./chain2
      14129:     symbol=foo;  lookup in file=/lib/tls/libdl.so.2
      14129:     symbol=foo;  lookup in file=/lib/tls/libc.so.6
      14129:     symbol=foo;  lookup in file=/lib/ld-linux.so.2
      14129:     symbol=foo;  lookup in file=lib1.so

--> foo is found in lib1.so

lib1.foo()
      14129:     symbol=foo;  lookup in file=/lib/tls/libc.so.6
      14129:     symbol=foo;  lookup in file=/lib/ld-linux.so.2

--> Then all other lib$i.so are ignored :

      14129:     symbol=dlclose;  lookup in file=./chain2
      14129:     symbol=dlclose;  lookup in file=/lib/tls/libdl.so.2
      14129:     symbol=_dl_close;  lookup in file=./chain2
      14129:     symbol=_dl_close;  lookup in file=/lib/tls/libdl.so.2
      14129:     symbol=_dl_close;  lookup in file=/lib/tls/libc.so.6
      14129:

According to "Open Group Base Specifications Issue 6IEEE Std 1003.1, 2004
Edition" dlopen and dlsym entry, this should be a bug.

Fell free to contact me for any info.

Regards.
Yann LANGAIS.

-- 
           Summary: dlsym/RTLD_NEXT is broken when more than 1 lib has the
                    symbol.
           Product: glibc
           Version: unspecified
            Status: NEW
          Severity: normal
          Priority: P2
         Component: libc
        AssignedTo: gotom at debian dot or dot jp
        ReportedBy: langlais at ilay dot org
                CC: glibc-bugs at sources dot redhat dot com,langlais at
                    ilay dot org


http://sourceware.org/bugzilla/show_bug.cgi?id=1319

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


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