diff options
author | jdp <jdp@FreeBSD.org> | 1996-05-22 06:34:12 +0000 |
---|---|---|
committer | jdp <jdp@FreeBSD.org> | 1996-05-22 06:34:12 +0000 |
commit | 8e810e6d1389d594b6d69e010e278dd540be436a (patch) | |
tree | 31a36ebe3a29e8a015939936a239973a9c33d144 /gnu | |
parent | 501579ff4d8385cfd9375d38bb9516624a68df61 (diff) | |
download | FreeBSD-src-8e810e6d1389d594b6d69e010e278dd540be436a.zip FreeBSD-src-8e810e6d1389d594b6d69e010e278dd540be436a.tar.gz |
When checking to see whether a needed shared library has already
been loaded, look for a match by device and inode number if the
traditional pathname comparisons don't find a match. This detects
the case in which a library is requested using two different names
which are really links to the same file, and avoids loading it
twice.
Requested by: peter@freebsd.org
Reviewed by: peter@freebsd.org
Diffstat (limited to 'gnu')
-rw-r--r-- | gnu/usr.bin/ld/rtld/rtld.c | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/gnu/usr.bin/ld/rtld/rtld.c b/gnu/usr.bin/ld/rtld/rtld.c index bade56e..989f77e 100644 --- a/gnu/usr.bin/ld/rtld/rtld.c +++ b/gnu/usr.bin/ld/rtld/rtld.c @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: rtld.c,v 1.32 1996/01/13 00:15:25 jdp Exp $ + * $Id: rtld.c,v 1.33 1996/04/20 18:29:50 jdp Exp $ */ #include <sys/param.h> @@ -88,6 +88,8 @@ struct somap_private { struct so_map *spd_parent; struct so_list *spd_children; struct so_map *spd_prev; + dev_t spd_dev; + ino_t spd_ino; int spd_refcount; int spd_flags; #define RTLD_MAIN 0x01 @@ -491,17 +493,41 @@ map_object(path, sodp, parent) struct so_map *parent; { struct so_map *smp; + struct stat statbuf; if(path == NULL) /* Special case for the main program itself */ smp = link_map_head; else { - /* Check whether the shared object is already mapped */ + /* + * Check whether the shared object is already mapped. + * We check first for an exact match by pathname. That + * will detect the usual case. If no match is found by + * pathname, then stat the file, and check for a match by + * device and inode. That will detect the less common case + * involving multiple links to the same library. + */ for(smp = link_map_head; smp != NULL; smp = smp->som_next) { if(!(LM_PRIVATE(smp)->spd_flags & (RTLD_MAIN|RTLD_RTLD)) && smp->som_path != NULL && strcmp(smp->som_path, path) == 0) break; } + if(smp == NULL) { /* Check for a match by device and inode */ + if (stat(path, &statbuf) == -1) { + generror ("cannot stat \"%s\" : %s", + path, strerror(errno)); + return NULL; + } + for (smp = link_map_head; smp != NULL; + smp = smp->som_next) { + struct somap_private *smpp = LM_PRIVATE(smp); + + if (!(smpp->spd_flags & (RTLD_MAIN | RTLD_RTLD)) + && smpp->spd_ino == statbuf.st_ino + && smpp->spd_dev == statbuf.st_dev) + break; + } + } } if (smp == NULL) { /* We must map the object */ @@ -589,6 +615,14 @@ map_object(path, sodp, parent) smpp->a_text = hdr.a_text; smpp->a_data = hdr.a_data; smpp->a_bss = hdr.a_bss; + + /* + * Save the device and inode, so we can detect multiple links + * to the same library. Note, if we reach this point, then + * statbuf is guaranteed to have been filled in. + */ + smpp->spd_dev = statbuf.st_dev; + smpp->spd_ino = statbuf.st_ino; } LM_PRIVATE(smp)->spd_refcount++; |