Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

dlopen() and putenv()

829 views
Skip to first unread message

Nathan Robertson

unread,
May 18, 2004, 10:22:54 AM5/18/04
to
Hi,

I have a situation where I need to load a .so at runtime (and I only find
out its name and location at runtime). After reading the dlopen() man
page, I felt one way to achieve this would be to
putenv("LD_LIBRARY_PATH=/path/to/dir") before I call dlopen(). Do a
getenv("LD_LIBRARY_PATH"), and as you'd expect it has the (new) value.
However, dlopen() doesn't appear to see this, and crashes the program.

Below is a small test code that shows this strangeness in pretty
simple terms. Run it without an LD_LIBRARY_PATH (which will crash --
why?), and then with LD_LIBRARY_PATH=`pwd` (which works perfectly). I've
tested this on both Solaris and Linux, and both exhibit the same behaviour:

$ ./maintest
LD_LIBRARY_PATH=/home/nathanr/tmp
dlopen failed: libtest.so: cannot open shared object file: No such file or directory

I realise I could edit ld.so.conf and run ldconfig or set the
LD_LIBRARY_PATH environment variable before execution and that works, but
I'm really curious as to why this doesn't work. I can't find anything in
Advanced Programming in the UNIX Environment that suggests that this
shouldn't work.

--- libtest.c ---
#include <stdio.h>

void test_func() {
printf("test\n");
}

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

int main(int argc, char **argv) {
void *handle;
void (*test)();
char buf[256], *error;

if (getenv("LD_LIBRARY_PATH") != 0)
puts("LD_LIBRARY_PATH environment variable was set.\n"
"We'll setenv() over the top of it\n");

strcpy(buf, "LD_LIBRARY_PATH=");
getcwd(&buf[16], 255-16);
putenv(buf);
printf("LD_LIBRARY_PATH=%s\n", getenv("LD_LIBRARY_PATH"));

if (!(handle = dlopen("libtest.so", RTLD_NOW))) {
printf("dlopen failed: %s\n", dlerror());
exit(1);
}
printf("Done dlopen\n");

dlerror(); // Clear any existing errors
test = dlsym(handle, "test_func");
if ((error = dlerror()) != NULL) {
printf("dlsym failed: %s\n", error);
exit(1);
}

printf("About to call test()\n");
(*test)();
printf("Done. Closing and exiting\n");

dlclose(handle);
return 0;
}

--- Makefile ---
build:
gcc -fPIC -c libtest.c -o libtest.o
gcc -g -shared -o libtest.so libtest.o
gcc -g main.c -o maintest -L. -ldl

clean:
rm -f *.o *.so *~ maintest

Jens.T...@physik.fu-berlin.de

unread,
May 18, 2004, 4:02:48 PM5/18/04
to
Nathan Robertson <nat...@nathanr.net> wrote:
> I have a situation where I need to load a .so at runtime (and I only find
> out its name and location at runtime). After reading the dlopen() man
> page, I felt one way to achieve this would be to
> putenv("LD_LIBRARY_PATH=/path/to/dir") before I call dlopen(). Do a
> getenv("LD_LIBRARY_PATH"), and as you'd expect it has the (new) value.
> However, dlopen() doesn't appear to see this, and crashes the program.

> Below is a small test code that shows this strangeness in pretty
> simple terms. Run it without an LD_LIBRARY_PATH (which will crash --
> why?), and then with LD_LIBRARY_PATH=`pwd` (which works perfectly). I've
> tested this on both Solaris and Linux, and both exhibit the same behaviour:

> $ ./maintest
> LD_LIBRARY_PATH=/home/nathanr/tmp
> dlopen failed: libtest.so: cannot open shared object file: No such file or directory

> I realise I could edit ld.so.conf and run ldconfig or set the
> LD_LIBRARY_PATH environment variable before execution and that works, but
> I'm really curious as to why this doesn't work. I can't find anything in
> Advanced Programming in the UNIX Environment that suggests that this
> shouldn't work.

Perhaps because no-one ever came up with that idea since you can get
the same effect much easier by simple prepending the path to the name
of the library you want to dlopen()?

I run your program (under Linux) and found:

a) when I run it without setting LD_LIBRARY_PATH before starting it it
does not find find the library but it doesn't crash (and I don't see
why you think it crashed when you run it - it outputs the error
message you asked it to and then exits). But that could also be the
result of adding <stdlib.h> and <string.h> to the files to be
included in my version... So better make sure you always compile
with the -W and -Wall options;-)

b) if I set LD_LIBRARY_PATH correctly before I start the program it
works flawlessly.

The obvious conclusion is that the runtime linker does not care about
the settings of environment variables internal to the program its
working with. This is in agreement with e.g. the notes from

http://www.netsys.com/cgi-bin/solaris9?dlopen(3DL)

where you find:

The directory search path used to find both path_name and the other needed
objects may be affected by setting the environment variable LD_LIBRARY_PATH,
which is analyzed once at process startup, and from a runpath setting within
the object from which the call to dlopen() originated. These search rules
will only be applied to path names that do not contain an embedded `/'.

I haven't found a man page for Linux yet that says the same explicitely.
On the other hand it doesn't look unreasonable to check LD_LIBRARY_PATH
only at startup because within the program you have complete control over
the location of the library since you can pass absolute and relative paths
to dlopen() (and you can evaluate LD_LIBRARY_PATH from the program yourself
if you need to).
Regards, Jens
--
\ Jens Thoms Toerring ___ Jens.T...@physik.fu-berlin.de
\__________________________ http://www.toerring.de

moma

unread,
May 19, 2004, 2:27:31 AM5/19/04
to
Interesting question,


Can you include the path in dlopen(...)
eg.

if (!(handle = dlopen("./libtest.so", RTLD_NOW))) { ...}

or:

if (!(handle = dlopen("libtest.so", RTLD_NOW))) {

if (!(handle = dlopen("/home/nathanr/tmp/libtest.so", RTLD_NOW))) {
perror(dlerror());
exit(1);
}
}
------

In bash, I write:
export LD_LIBRARY_PATH=/path/to/dir:$LD_LIBRARY_PATH
^^^^^^

// moma
http://www.futuredesktop.org

0 new messages