Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 7 Sep 2001 00:25:13 -0700 (PDT)
From:      Steve Whiteley <stevew@wrcad.com>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   misc/30412: rtdl/dlopen() fails to merge common variables in 2 or more dlopen'ed libs
Message-ID:  <200109070725.f877PDl62797@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         30412
>Category:       misc
>Synopsis:       rtdl/dlopen() fails to merge common variables in 2 or more dlopen'ed libs
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Sep 07 00:30:01 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     Steve Whiteley
>Release:        4.3-stable
>Organization:
Whiteley Research Inc.
>Environment:
FreeBSD chaucer.srware.com 4.3-RC FreeBSD 4.3-RC #2: Sun Apr 22 14:16:02 PDT 2001     stevew@chaucer.srware.com:/usr3/obj/usr/src/sys/CHAUCER  i386

>Description:

It seems that in FreeBSD 4.3, if two shared libraries, each of which 
define an exported pointer variable of the same name, are opened using
dlopen(), each pointer retains a unique address.  This is different
from Solaris and Linux, where the pointers are merged into a common
symbol.

For example, both libtcl and libtk (8.3.3) define tclStubsPtr.  If   
these two libraries are opened with dlopen(..., RTLD_GLOBAL), calling
Tk_Init() causes a seg fault on the first call of a tcl function from
libtk.  The problem is that the libtcl tclStubsPtr struct is being
initialized, but the separate address of the tclStubsPtr in libtk 
which is resolved for all references in libtk remains a null pointer. 
 
Here is a mod to rtld.c in the rtld source that seems to fix the problem: 
In rtld.c near line 1862 in symlook_default() 
 
/**/ 
    /* 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); 
        if (symp != NULL && 
          (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { 
            def = symp;  
            defobj = obj; 
        } 
    } 
 
/* SRW ** block below was ahead of block above */ 
 
    /* Search all dlopened DAGs containing the referencing object. */ 
    STAILQ_FOREACH(elm, &refobj->dldags, 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; 
        }
    }
/**/

This will cause linkage to an exported symbol from the other dlopen'ed
library, ahead of the variable local to the library whose references  
are being resolved.  This would seem to be better logic, but there may
be a disadvantage I have overlooked.

My program works in Linux and Solaris.  For FreeBSD I'm using a 
work-around that uses dlsym() to grab the two addresses and then
explicitly setting the unset pointer.

There is also an open problem report #25059 relating to dlopen(),
possibly related?

>How-To-Repeat:
See "Full Description"
>Fix:
See "Full Description"
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200109070725.f877PDl62797>