From nobody@FreeBSD.org  Tue Feb 13 01:15:21 2001
Return-Path: <nobody@FreeBSD.org>
Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21])
	by hub.freebsd.org (Postfix) with ESMTP id 1322E37B491
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 13 Feb 2001 01:15:21 -0800 (PST)
Received: (from nobody@localhost)
	by freefall.freebsd.org (8.11.1/8.11.1) id f1D9FLZ54623;
	Tue, 13 Feb 2001 01:15:21 -0800 (PST)
	(envelope-from nobody)
Message-Id: <200102130915.f1D9FLZ54623@freefall.freebsd.org>
Date: Tue, 13 Feb 2001 01:15:21 -0800 (PST)
From: nikip@iname.com
To: freebsd-gnats-submit@FreeBSD.org
Subject: dlopen(..,RTLD_GLOBAL) doesn't work for shared libraries linked to the loaded one
X-Send-Pr-Version: www-1.0

>Number:         25059
>Category:       bin
>Synopsis:       dlopen(..,RTLD_GLOBAL) doesn't work for shared libraries linked to the loaded one
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    des
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Feb 13 01:20:00 PST 2001
>Closed-Date:    Tue Apr 02 14:59:19 PST 2002
>Last-Modified:  Tue Apr 02 14:59:19 PST 2002
>Originator:     Nikolay Pelov
>Release:        FreeBSD 4.2-STABLE i386
>Organization:
>Environment:
FreeBSD guest1.lucky.net 4.2-STABLE FreeBSD 4.2-STABLE #0: Tue Dec 19 14:20:35 EET 2000     root@guest1.lucky.net:/usr/src/sys/compile/GUEST  i386
>Description:
If a shared library is loaded with dlopen(..., RTLD_GLOBAL) and it is linked at compile time to another *shared* library then the symbols of the second library are not exported.
>How-To-Repeat:
The test suite goes as follows.
There is a shared library "dl1.so" which is linked to another shared library "st1.so".
The second library exports a constant, say 'char *ok'.
Then there is a third shared library, called "dl2.so" which is independent of the other two but uses the symbol defined in "st1.so".
The main program dlopen()'s "dl1.so" and "dl2.so" and calls a function in "dl2.so" which uses the constant 'ok' and you get the error that it is not defined.

You can download the test suite from http://www.cs.kuleuven.ac.be/~pelov/pam/download/dltest2.tar.gz
To run it just type 'gmake test'.
The test runs ok on both Linux and Solaris machines.
A similar problem appeared in some of the early development versions of glibc2.

----------- begin Makefile -----------
CFLAGS  = -g -Wall
LDFLAGS = -export-dynamic -fpic

all: main st1.so dl1.so dl2.so

%.so: %.o
	$(LD) $(LDFLAGS) -o $@ -shared $<

dl1.so: dl1.o st1.so
	$(LD) $(LDFLAGS) -o $@ -shared $^

clean:
	rm -f main *.so *.o

test: all
	LD_LIBRARY_PATH=. && export LD_LIBRARY_PATH && ./main

----------- end Makefile ---------------

----------- begin main.c  ---------------
#include <stdio.h>
#include <dlfcn.h>

void * open_lib(const char *name)
{
  void *lib = dlopen(name, RTLD_NOW | RTLD_GLOBAL);
  if (lib == NULL) {
    printf("dlopen error: %s\n", dlerror());
    exit(1);
  }
  return lib;
}

int main() {
   void *dl1_lib = open_lib("dl1.so");
   void *dl2_lib = open_lib("dl2.so");
   void (*func)(void) = dlsym(dl2_lib, "test_dl2");

   if (func == 0) {
      printf("dlsym error: %s\n", dlerror());
      return 1;
   }
   func();
   
   dlclose(dl1_lib);
   dlclose(dl2_lib);
   return 0;
}
----------- end main.c  ---------------

----------- begin dl1.c  --------------
void test_dl1() {
  /* some dummy function */
}
----------- end dl1.c  ----------------

----------- begin st1.c  --------------
char *ok = "\n The dlopen() function is OK\n";
----------- end st1.c  ----------------

----------- begin dl2.c  --------------
#include <stdio.h>

extern char *ok;

void test_dl2() {
  printf("%s\n", ok);
}
----------- end dl2.c  ----------------

----------- begin output --------------
bash-2.03$ gmake test
cc -g -Wall  -export-dynamic -fpic  main.c   -o main
cc -g -Wall   -c -o st1.o st1.c
ld -export-dynamic -fpic -o st1.so -shared st1.o
cc -g -Wall   -c -o dl1.o dl1.c
ld -export-dynamic -fpic -o dl1.so -shared dl1.o st1.so
cc -g -Wall   -c -o dl2.o dl2.c
ld -export-dynamic -fpic -o dl2.so -shared dl2.o
LD_LIBRARY_PATH=. && export LD_LIBRARY_PATH && ./main
dlopen error: ./dl2.so: Undefined symbol "ok"
gmake: *** [test] Error 1
rm st1.o dl2.o

>Fix:


>Release-Note:
>Audit-Trail:

From: Dag-Erling Smorgrav <des@ofug.org>
To: arch@freebsd.org
Cc:  
Subject: bin/25059 (rtld bug)
Date: 24 Feb 2002 00:21:49 +0100

 --=-=-=
 
 Our dlopen(3) man page states:
 
      RTLD_GLOBAL   Symbols from this shared object and its directed acyclic
                    graph (DAG) of needed objects will be available for resolv
                    ing undefined references from all other shared objects.
 
 but this is a lie - only the object itself is searched, not its DAG.
 
 The attached patch fixes this by adding a flag to the Obj_Entry
 structure that marks an object as global, and changing symlook_list()
 to search each global object's DAG if the object itself doesn't have
 the requested symbol.  With this patch applied, the test program
 referenced in the PR works.
 
 (some might argue that symlook_obj() should be changed instead - but
 changing symlook_list() was simpler, and the only difference it makes
 is, in the worst case, a slightly longer search)
 
 DES
 -- 
 Dag-Erling Smorgrav - des@ofug.org
 
 
 --=-=-=
 Content-Type: text/x-patch
 Content-Disposition: attachment; filename=rtld.diff
 
 Index: rtld.c
 ===================================================================
 RCS file: /home/ncvs/src/libexec/rtld-elf/rtld.c,v
 retrieving revision 1.60
 diff -u -r1.60 rtld.c
 --- rtld.c	17 Feb 2002 07:00:25 -0000	1.60
 +++ rtld.c	23 Feb 2002 23:21:28 -0000
 @@ -1329,6 +1329,7 @@
      elm = NEW(Objlist_Entry);
      elm->obj = obj;
      STAILQ_INSERT_TAIL(list, elm, link);
 +    obj->global = true;
  }
  
  static void
 @@ -1581,7 +1582,7 @@
  
      if (obj) {
  	obj->dl_refcount++;
 -	if (mode & RTLD_GLOBAL && objlist_find(&list_global, obj) == NULL)
 +	if (mode & RTLD_GLOBAL && !obj->global)
  	    objlist_push_tail(&list_global, obj);
  	mode &= RTLD_MODEMASK;
  	if (*old_obj_tail != NULL) {		/* We loaded something new. */
 @@ -1915,7 +1916,7 @@
  	}
      }
  
 -    /* Search all RTLD_GLOBAL objects. */
 +    /* Search all RTLD_GLOBAL objects and their DAGs. */
      if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
  	symp = symlook_list(name, hash, &list_global, &obj, in_plt, &donelist);
  	if (symp != NULL &&
 @@ -1965,6 +1966,12 @@
  		if (ELF_ST_BIND(def->st_info) != STB_WEAK)
  		    break;
  	    }
 +	} else if (elm->obj->global) {
 +	    /* search the DAGs of global objects */
 +	    symp = symlook_list(name, hash, &elm->obj->dagmembers,
 +	      defobj_out, in_plt, dlp);
 +	    if (symp != NULL)
 +		return symp;
  	}
      }
      if (def != NULL)
 Index: rtld.h
 ===================================================================
 RCS file: /home/ncvs/src/libexec/rtld-elf/rtld.h,v
 retrieving revision 1.24
 diff -u -r1.24 rtld.h
 --- rtld.h	29 Oct 2001 10:10:02 -0000	1.24
 +++ rtld.h	23 Feb 2002 23:02:18 -0000
 @@ -155,6 +155,7 @@
      bool traced;		/* Already printed in ldd trace output */
      bool jmpslots_done;		/* Already have relocated the jump slots */
      bool init_done;		/* Already have added object to init list */
 +    bool global;		/* This object is on the global list */
  
      struct link_map linkmap;	/* for GDB */
      Objlist dldags;		/* Object belongs to these dlopened DAGs (%) */
 
 --=-=-=--
Responsible-Changed-From-To: freebsd-bugs->des 
Responsible-Changed-By: des 
Responsible-Changed-When: Sat Feb 23 15:36:53 PST 2002 
Responsible-Changed-Why:  
I have a patch for this. 

http://www.FreeBSD.org/cgi/query-pr.cgi?pr=25059 

From: John Polstra <jdp@polstra.com>
To: bug-followup@freebsd.org
Cc: Dag-Erling Smorgrav <des@freebsd.org>
Subject: Re: bin/25059: dlopen(..,RTLD_GLOBAL) doesn't work for shared libraries linked to the loaded one
Date: Tue, 26 Feb 2002 17:11:26 -0800 (PST)

 I'm a little bit wary of Dag-Erling's patch because it changes the
 semantics of symlook_list(), which is supposed to be a utility
 function that does a particular thing.  I would prefer to change
 symlook_default() to search the RTLD_GLOBAL DAGs explicitly, as in the
 patch below.  This patch makes Nikolay Pelov's test case work OK.
 
 Dag-Erling, if this patch looks OK to you and it solves your problem,
 please feel free to commit it for me.  I am leaving on holiday, and
 won't be able to do it myself for a couple weeks.
 
 John
 
 Index: rtld.c
 ===================================================================
 RCS file: /home/ncvs/src/libexec/rtld-elf/rtld.c,v
 retrieving revision 1.59
 diff -U9 -r1.59 rtld.c
 --- rtld.c      4 Feb 2002 10:44:15 -0000       1.59
 +++ rtld.c      26 Feb 2002 18:49:47 -0000
 @@ -1909,21 +1909,24 @@
         symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt,
           &donelist);
         if (symp != NULL &&
           (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
             def = symp;
             defobj = obj;
         }
      }
  
 -    /* Search all RTLD_GLOBAL objects. */
 -    if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
 -       symp = symlook_list(name, hash, &list_global, &obj, in_plt, &donelist);
 +    /* Search all DAGs whose roots are RTLD_GLOBAL objects. */
 +    STAILQ_FOREACH(elm, &list_global, link) {
 +       if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
 +           break;
 +       symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt,
 +         &donelist);
         if (symp != NULL &&
           (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
             def = symp;
             defobj = obj;
         }
      }
  
      /*
       * Search the dynamic linker itself, and possibly resolve the
 
 
State-Changed-From-To: open->feedback 
State-Changed-By: des 
State-Changed-When: Fri Mar 8 09:34:50 PST 2002 
State-Changed-Why:  
Fixed in -CURRENT, awaiting MFC. 

http://www.FreeBSD.org/cgi/query-pr.cgi?pr=25059 
State-Changed-From-To: feedback->closed 
State-Changed-By: des 
State-Changed-When: Tue Apr 2 14:59:18 PST 2002 
State-Changed-Why:  
MFCed, thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=25059 
>Unformatted:
