[PATCH] Improve loadlib handling of absolute and partial pathnames

1 view
Skip to first unread message

Bob Rogers

unread,
May 29, 2005, 12:11:18 PM5/29/05
to perl6-i...@perl.org
The problem is that if you do

loadlib "/home/rogers/foo/bar/baz"

Parrot_load_lib finds and loads "/home/rogers/foo/bar/baz.so" just fine,
but then the library isn't initialized properly because it attempts to
look up the address of "Parrot_lib_/home/rogers/foo/bar/baz_load" via
dlsym, and similarly if you add an explicit ".so" to the arg. This
patch does the following:

1. Computes a trimmed "lib_name" as the part between the last "/" or
"\" and the last ".", exclusive, and uses that for constructing entry
names for dlsym.

2. Attempts to fix an apparent memory leak, via the addition of line
172 to src/dynext.c. (C heavies, please scrutinize.)

3. Calls Parrot_locate_runtime_file on files with explicit
extensions, for completeness.

4. Rewrites the test for a missing extension slightly, so that it
won't get confused by a "." in a directory name. (Not specifically
tested.)

5. Includes four new test cases for loadlib, with absolute/partial
pathnames with/without an extension.

There is also this "#ifdef WIN32" business about dropping a "lib"
prefix from the name if all else fails; I am guessing that this no
longer works, but I have no way of testing it myself, so I haven't tried
to resuscitate it. But I'm not sure that it ever worked; seems to me
that this would have to be folded into the Parrot_locate_runtime_file
library directory search in order to do the right thing.

-- Bob Rogers
http://rgrjr.dyndns.org/

------------------------------------------------------------------------
Index: src/dynext.c
===================================================================
--- src/dynext.c (revision 8203)
+++ src/dynext.c (working copy)
@@ -123,26 +123,41 @@
/*

=item C<static STRING *
-get_path(Interp *interpreter, STRING *lib, void **handle)>
+get_path(Interp *interpreter, STRING *lib, void **handle, char **lib_name)>

-Return path and handle of a dynamic lib.
+Return path and handle of a dynamic lib, setting lib_name to just the filestem
+(i.e. without path or extension) as a freshly-allocated C string.

=cut

*/

static STRING *
-get_path(Interp *interpreter, STRING *lib, void **handle)
+get_path(Interp *interpreter, STRING *lib, void **handle, char **lib_name)
{
STRING *path;
char *full_name, *file_name, *file_w_ext = NULL;
+ char *tmp_lib_name, *path_end, *ext_start;
const char *err;

+ /* Find the pure library name, without path or extension. */
+ file_name = string_to_cstring(interpreter, lib);
+ tmp_lib_name = file_name;
+ path_end = strrchr(tmp_lib_name, '/');
+ if (! path_end)
+ path_end = strrchr(tmp_lib_name, '\\');
+ if (path_end)
+ tmp_lib_name = path_end+1;
+ *lib_name = malloc(strlen(tmp_lib_name)+1);
+ strcpy(*lib_name, tmp_lib_name);
+ ext_start = strrchr(*lib_name, '.');
+ if (ext_start)
+ *ext_start = '\0';
+
/*
- * first try file with extension if it got none
+ * first, try to add an extension to the file if it has none.
*/
- file_name = string_to_cstring(interpreter, lib);
- if (!strchr(file_name, '.')) {
+ if (! ext_start) {
file_w_ext = malloc(strlen(file_name) +
strlen(PARROT_LOAD_EXT) + 1);
strcpy(file_w_ext, file_name);
@@ -154,6 +169,7 @@
if (*handle) {
path = string_from_cstring(interpreter, full_name, 0);
string_cstring_free(file_name);
+ string_cstring_free(full_name);
string_cstring_free(file_w_ext);
return path;
}
@@ -207,16 +223,25 @@
}
}
/*
- * then the given file name as is
+ * finally, try the given file name as is. we still use
+ * Parrot_locate_runtime_file so that (a) relative pathnames are searched in
+ * the standard locations, and (b) the angle of the slashes are adjusted as
+ * required for non-Unix systems.
*/
- *handle = Parrot_dlopen(file_name);
- if (*handle) {
- path = string_from_cstring(interpreter, file_name, 0);
- string_cstring_free(file_name);
- return path;
+ full_name = Parrot_locate_runtime_file(interpreter, file_name,
+ PARROT_RUNTIME_FT_DYNEXT);
+ if (full_name) {
+ *handle = Parrot_dlopen(full_name);
+ if (*handle) {
+ path = string_from_cstring(interpreter, full_name, 0);
+ string_cstring_free(file_name);
+ string_cstring_free(full_name);
+ return path;
+ }
}
/*
* and on windows strip a leading "lib"
+ * [shouldn't this happen in Parrot_locate_runtime_file instead?]
*/
#ifdef WIN32
if (memcmp(file_name, "lib", 3) == 0) {
@@ -297,9 +322,10 @@
void (*init_func)(Interp *, PMC *);
char *cinit_func_name, *cload_func_name;
PMC *lib_pmc;
+ char *lib_name; /* library stem without path or extension. */

UNUSED(initializer);
- path = get_path(interpreter, lib, &handle);
+ path = get_path(interpreter, lib, &handle, &lib_name);
if (!path || !handle) {
/*
* XXX internal_exception? return PMCNULL?
@@ -325,17 +351,20 @@
*/
Parrot_block_DOD(interpreter);
/* get load_func */
- load_func_name = Parrot_sprintf_c(interpreter, "Parrot_lib_%Ss_load", lib);
+ load_func_name = Parrot_sprintf_c(interpreter, "Parrot_lib_%s_load",
+ lib_name);
cload_func_name = string_to_cstring(interpreter, load_func_name);
load_func = (PMC * (*)(Interp *))D2FPTR(Parrot_dlsym(handle,
cload_func_name));
string_cstring_free(cload_func_name);
/* get init_func */
- init_func_name = Parrot_sprintf_c(interpreter, "Parrot_lib_%Ss_init", lib);
+ init_func_name = Parrot_sprintf_c(interpreter, "Parrot_lib_%s_init",
+ lib_name);
cinit_func_name = string_to_cstring(interpreter, init_func_name);
init_func = (void (*)(Interp *, PMC *))D2FPTR(Parrot_dlsym(handle,
cinit_func_name));
string_cstring_free(cinit_func_name);
+ string_cstring_free(lib_name);

lib_pmc = Parrot_init_lib(interpreter, load_func, init_func);

Index: t/dynclass/foo.t
===================================================================
--- t/dynclass/foo.t (revision 8203)
+++ t/dynclass/foo.t (working copy)
@@ -16,7 +16,7 @@

=cut

-use Parrot::Test tests => 3;
+use Parrot::Test tests => 7;
use Parrot::Config;

pir_output_is(<< 'CODE', << 'OUTPUT', "get_integer");
@@ -34,6 +34,99 @@
42
OUTPUT

+pir_output_is(<< 'CODE', << 'OUTPUT', "loadlib with relative pathname, no ext");
+.sub main @MAIN
+ ## load a relative pathname without the extension. loadlib will convert the
+ ## '/' characters to '\\' on windows.
+ $S0 = "runtime/parrot/dynext/foo"
+ loadlib P1, $S0
+
+ ## ensure that we can still make Foo instances.
+ find_type $I0, "Foo"
+ new $P1, $I0
+ $I1 = $P1
+ print $I1
+ print "\n"
+.end
+CODE
+42
+OUTPUT
+
+pir_output_is(<< 'CODE', << 'OUTPUT', "loadlib with absolute pathname, no ext");
+.sub main @MAIN
+ ## get cwd in $S0.
+ .include "iglobals.pasm"
+ $P11 = getinterp
+ $P12 = $P11[.IGLOBALS_CONFIG_HASH]
+ $S0 = $P12["prefix"]
+
+ ## convert cwd to an absolute pathname without the extension, and load it.
+ ## this should always find the version in the build directory, since that's
+ ## the only place "make test" will work.
+ $S0 = concat "/runtime/parrot/dynext/foo"
+ loadlib P1, $S0
+
+ ## ensure that we can still make Foo instances.
+ find_type $I0, "Foo"
+ new $P1, $I0
+ $I1 = $P1
+ print $I1
+ print "\n"
+.end
+CODE
+42
+OUTPUT
+
+pir_output_is(<< 'CODE', << 'OUTPUT', "loadlib with relative pathname & ext");
+.sub main @MAIN
+ ## get share_ext in $S0.
+ .include "iglobals.pasm"
+ $P11 = getinterp
+ $P12 = $P11[.IGLOBALS_CONFIG_HASH]
+ $S0 = $P12["share_ext"]
+
+ ## load a relative pathname with an extension.
+ $S0 = concat "runtime/parrot/dynext/foo", $S0
+ loadlib P1, $S0
+
+ ## ensure that we can still make Foo instances.
+ find_type $I0, "Foo"
+ new $P1, $I0
+ $I1 = $P1
+ print $I1
+ print "\n"
+.end
+CODE
+42
+OUTPUT
+
+pir_output_is(<< 'CODE', << 'OUTPUT', "loadlib with absolute pathname & ext");
+.sub main @MAIN
+ ## get cwd in $S0, share_ext in $S1.
+ .include "iglobals.pasm"
+ $P11 = getinterp
+ $P12 = $P11[.IGLOBALS_CONFIG_HASH]
+ $S0 = $P12["prefix"]
+ $S1 = $P12["share_ext"]
+
+ ## convert $S0 to an absolute pathname with extension, and load it.
+ ## this should always find the version in the build directory, since that's
+ ## the only place "make test" will work.
+ $S0 = concat $S0, "/runtime/parrot/dynext/foo"
+ $S0 = concat $S0, $S1
+ loadlib P1, $S0
+
+ ## ensure that we can still make Foo instances.
+ find_type $I0, "Foo"
+ new $P1, $I0
+ $I1 = $P1
+ print $I1
+ print "\n"
+.end
+CODE
+42
+OUTPUT
+
SKIP: { skip("No BigInt Lib configured", 1) if !$PConfig{gmp};

pir_output_is(<< 'CODE', << 'OUTPUT', "inherited add");

Leopold Toetsch

unread,
May 30, 2005, 4:05:56 AM5/30/05
to Bob Rogers, perl6-i...@perl.org
Bob Rogers <rogers...@rgrjr.dyndns.org> wrote:
> The problem is that if you do

> loadlib "/home/rogers/foo/bar/baz"

[...]

Thanks, applied - r8209
leo

Reply all
Reply to author
Forward
0 new messages