From owner-freebsd-bugs@FreeBSD.ORG Sat Oct 31 15:40:02 2009 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 614CC1065679 for ; Sat, 31 Oct 2009 15:40:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 3D6898FC1E for ; Sat, 31 Oct 2009 15:40:02 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.3/8.14.3) with ESMTP id n9VFe2FD009507 for ; Sat, 31 Oct 2009 15:40:02 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.3/8.14.3/Submit) id n9VFe2CR009506; Sat, 31 Oct 2009 15:40:02 GMT (envelope-from gnats) Resent-Date: Sat, 31 Oct 2009 15:40:02 GMT Resent-Message-Id: <200910311540.n9VFe2CR009506@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, David Naylor Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 78083106568D for ; Sat, 31 Oct 2009 15:33:55 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21]) by mx1.freebsd.org (Postfix) with ESMTP id 663668FC1D for ; Sat, 31 Oct 2009 15:33:55 +0000 (UTC) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.14.3/8.14.3) with ESMTP id n9VFXswU069446 for ; Sat, 31 Oct 2009 15:33:54 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.14.3/8.14.3/Submit) id n9VFXs4G069445; Sat, 31 Oct 2009 15:33:54 GMT (envelope-from nobody) Message-Id: <200910311533.n9VFXs4G069445@www.freebsd.org> Date: Sat, 31 Oct 2009 15:33:54 GMT From: David Naylor To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: bin/140143: dlopen doesn't promote RTLD_GLOBAL for linked libraries X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 31 Oct 2009 15:40:02 -0000 >Number: 140143 >Category: bin >Synopsis: dlopen doesn't promote RTLD_GLOBAL for linked libraries >Confidential: no >Severity: serious >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sat Oct 31 15:40:01 UTC 2009 >Closed-Date: >Last-Modified: >Originator: David Naylor >Release: FreeBSD 8 RC2 >Organization: Private >Environment: FreeBSD dragon.dg 8.0-RC2 FreeBSD 8.0-RC2 #0: Sat Oct 31 11:30:28 SAST 2009 root@dragon.dg:/tmp/usr/src/sys/GENERIC i386 >Description: If a shared library is linked to another than any attempts from the first library to promote the symbols of the second library to RTLD_GLOBAL does not work [via dlopen("libsecond.so", RTLD_NOLOAD|RTLD_GLOBAL), or using RTLD_LAZY or RTLD_NOW]. This is known to affect devel/kdebindings4-python-pykde4. This is not a problem under Linux (i.e. linux exhibits expected behaviour). >How-To-Repeat: [skip to bottom for coded example] Have a shared library that is linked (at compile time) to a second library then have the second library load a third that requires symbols from the second but does not declare its dependency on the second library [e.g. libpython and lib/python26/lib-dynload/*]. If the second library is loaded (without being linked) with RTLD_GLOBAL then all is well. See attached for rtld_global.shar. Extract content and run: # make * # make -DTRIGGER ** This runs two tests. The first test is the first library that dlopen's the second library (it should run fine). The second test is the first library that is linked to the second library and attempts to promote the second libraries symbols to RTLD_GLOBAL. See below: * Runs with work-around (see Fix below). This works ** Runs without work-around [aka dlopen("libmaster.so", RTLD_NOW | RTLD_GLOBAL)] with 'libmaster.so' being the second library. This does not work. >Fix: There is only a work-around that may not work in all situations: Promote the first libraries symbols to RTLD_GLOBAL. This, however, I think is overly broad and deviates from established behaviour (under Linux). In the example attached this amounts to: dlopen("libplugin.so", RTLD_NOLOAD | RTLD_GLOBAL) where libplugin.so is the first library. Patch attached with submission follows: # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # rtld_global # rtld_global/Makefile # rtld_global/libmaster.c # rtld_global/main.c # rtld_global/libslave.c # rtld_global/common.h # rtld_global/libplugin.c # echo c - rtld_global mkdir -p rtld_global > /dev/null 2>&1 echo x - rtld_global/Makefile sed 's/^X//' >rtld_global/Makefile << '54185eeffb995a36288ad17f38c2bdc0' X.SUFFIXES: .a .c .o .so .so.1 X.SILENT: X XCFLAGS=-Wall -rdynamic X X.if defined(TRIGGER) XCFLAGS+=-DTRIGGER X.endif X XCC=cc XAR=ar XLN=ln X Xall: X echo "Running test without linking: " X make clean test #> /dev/null X echo "done" X echo X echo "Running test with linking: " X make clean test -DLINKED #> /dev/null X echo "done" X Xclean: X rm -f *.a *.o *.so* main X Xtest: main libmaster.so libslave.so X env LD_LIBRARY_PATH=${PWD} ./main X X.c.o: X ${CC} ${CFLAGS} -c -fPIC -o $@ $< X X.c.so: X ${CC} ${CFLAGS} -fPIC -shared -Wl,-soname,$@ -o $@ $< X X.if defined(LINKED) Xlibplugin.so: libplugin.c libmaster.so X ${CC} ${CFLAGS} -DLINKED -fPIC -L. -lmaster -shared -Wl,-soname,$@ -o $@ $< X.endif X Xmain: main.o libplugin.so X cc ${CFLAGS} -o main main.o 54185eeffb995a36288ad17f38c2bdc0 echo x - rtld_global/libmaster.c sed 's/^X//' >rtld_global/libmaster.c << '4c7e49ccff36dd33ab5357b611fe5d83' X#include "common.h" X Xint master_func() { X void* libslave; X func_t func; X X printf("libmaster: opening libslave:"); X libslave = dlopen("libslave.so", RTLD_NOW); X STATUS_CHECK(libslave); X X printf("libmaster: getting symbol 'libslave::slave_func':"); X func = (func_t)dlfunc(libslave, "slave_func"); X STATUS_CHECK(func); X X printf("libmaster: calling 'libslave::slave_func'...\n"); X return func(); X} X Xconst char* master_name() { X return "libmaster.1"; X} 4c7e49ccff36dd33ab5357b611fe5d83 echo x - rtld_global/main.c sed 's/^X//' >rtld_global/main.c << 'cb6b43e30862d408f1380a58a3050ed8' X#include "common.h" X Xint main(int argc, char** argv) { X void* libplugin; X func_t func; X X printf("main: opening libplugin:"); X libplugin = dlopen("libplugin.so", RTLD_LAZY /*| RTLD_GLOBAL*/); X STATUS_CHECK(libplugin); X X printf("main: getting symbol 'libplugin::plugin_func':"); X func = (func_t)dlfunc(libplugin, "plugin_func"); X STATUS_CHECK(func); X X printf("main: calling 'libplugin::plugin_func'...\n"); X return func(); X} cb6b43e30862d408f1380a58a3050ed8 echo x - rtld_global/libslave.c sed 's/^X//' >rtld_global/libslave.c << '6027f0c5e11bc3f1d64c5398f3095d35' X#include X X/* Forward declaration from libmaster */ Xconst char* master_name(); X Xint slave_func() { X printf("libslave: %s\n", master_name()); X return 0; X} 6027f0c5e11bc3f1d64c5398f3095d35 echo x - rtld_global/common.h sed 's/^X//' >rtld_global/common.h << '96ded3809880f52ca04e85b8175d157f' X#include X#include X X#define STATUS_CHECK(var) \ X if ((var) == NULL) { \ X printf(" failure (%s)\n", dlerror()); \ X return 1; \ X } else \ X printf(" success\n") X Xtypedef int (*func_t)(); 96ded3809880f52ca04e85b8175d157f echo x - rtld_global/libplugin.c sed 's/^X//' >rtld_global/libplugin.c << 'a806cc4670bd702634b1d6e2d06150e5' X#include "common.h" X X#ifdef LINKED Xint master_func(); X#endif X Xint plugin_func() { X func_t func; X X#if !defined(LINKED) || defined(TRIGGER) X void* libmaster; X X printf("libplugin: opening libmaster:"); X libmaster = dlopen("libmaster.so", RTLD_LAZY | RTLD_GLOBAL); X STATUS_CHECK(libmaster); X#else X void* libplugin; X X printf("libplugin: exposing symbols globally:"); X libplugin = dlopen("libplugin.so", RTLD_NOLOAD | RTLD_GLOBAL); X STATUS_CHECK(libplugin); X#endif X X#ifndef LINKED X printf("libplugin: getting symbol 'libmaster::master_func':"); X func = (func_t)dlfunc(libmaster, "master_func"); X STATUS_CHECK(func); X#else X func = &master_func; X#endif X X printf("libplugin: calling 'libmaster::master_func'...\n"); X return func(); X} a806cc4670bd702634b1d6e2d06150e5 exit >Release-Note: >Audit-Trail: >Unformatted: