From 13a5b0c623a9598428a15e8ae522f83a352aa0e5 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Thu, 26 Jan 2012 08:55:53 -0500 Subject: [PATCH] change `ffi-lib' to not make library symbols global by default --- collects/ffi/unsafe.rkt | 9 +++---- collects/scribblings/foreign/libs.scrbl | 12 +++++++++- doc/release-notes/racket/HISTORY.txt | 3 +++ src/foreign/foreign.c | 26 ++++++++++++++++----- src/foreign/foreign.rktc | 31 ++++++++++++++++++------- src/racket/src/schvers.h | 4 ++-- 6 files changed, 63 insertions(+), 22 deletions(-) diff --git a/collects/ffi/unsafe.rkt b/collects/ffi/unsafe.rkt index 845067d6c4..7fcfda9076 100644 --- a/collects/ffi/unsafe.rkt +++ b/collects/ffi/unsafe.rkt @@ -93,7 +93,8 @@ ffi-lib? ffi-lib-name) (define (get-ffi-lib name [version/s ""] #:fail [fail #f] - #:get-lib-dirs [get-lib-dirs get-lib-search-dirs]) + #:get-lib-dirs [get-lib-dirs get-lib-search-dirs] + #:global? [global? #f]) (cond [(not name) (ffi-lib name)] ; #f => NULL => open this executable [(not (or (string? name) (path? name))) @@ -123,7 +124,7 @@ (string-append name0 "." lib-suffix v) (string-append name0 v "." lib-suffix)))) versions)] - [ffi-lib* (lambda (name) (ffi-lib name #t))]) + [ffi-lib* (lambda (name) (ffi-lib name #t global?))]) (or ;; try to look in our library paths first (and (not absolute?) (ormap (lambda (dir) @@ -145,8 +146,8 @@ (if fail (fail) (if (pair? names) - (ffi-lib (car names)) - (ffi-lib name0)))))])) + (ffi-lib (car names) #f global?) + (ffi-lib name0 #f global?)))))])) (define (get-ffi-lib-internal x) (if (ffi-lib? x) x (get-ffi-lib x))) diff --git a/collects/scribblings/foreign/libs.scrbl b/collects/scribblings/foreign/libs.scrbl index 266d23bb33..5e5051aeec 100644 --- a/collects/scribblings/foreign/libs.scrbl +++ b/collects/scribblings/foreign/libs.scrbl @@ -17,7 +17,8 @@ Returns @racket[#t] if @racket[v] is a @deftech{foreign-library value}, @defproc[(ffi-lib [path (or/c path-string? #f)] [version (or/c string? (listof (or/c string? #f)) #f) #f] [#:get-lib-dirs get-lib-dirs (-> (listof path?)) get-lib-search-dirs] - [#:fail fail (or/c #f (-> any)) #f]) + [#:fail fail (or/c #f (-> any)) #f] + [#:global? global? any/c #f]) any]{ Returns a @tech{foreign-library value} or the result of @racket[fail]. @@ -96,6 +97,15 @@ by the run-time system (as described in @|InsideRacket|). The @racket[version] argument is ignored when @racket[path] is @racket[#f]. +If @racket[path] is not @racket[#f], @racket[global?] is true, and the +operating system supports opening a library in ``global'' mode so that +the library's symbols are used for resolving references from libraries +that are loaded later, then global mode is used to open the +library. Otherwise, the library is opened in ``local'' mode, where the +library's symbols are not made available for future resolution. This +local-versus-global choice does not affect whether the library's +symbols are available via @racket[(ffi-lib #f)]. + Due to the way the operating system performs dynamic binding, loaded libraries are associated with Racket (or DrRacket) for the duration of the process. Re-evaluating @racket[ffi-lib] (or hitting the diff --git a/doc/release-notes/racket/HISTORY.txt b/doc/release-notes/racket/HISTORY.txt index 0aefd6ab6f..196e20f56c 100644 --- a/doc/release-notes/racket/HISTORY.txt +++ b/doc/release-notes/racket/HISTORY.txt @@ -1,3 +1,6 @@ +Version 5.2.1.4 +Changed ffi-lib to open libraries in local mode by default + Version 5.2.1, January 2012 Changed I/O scheduling to use epoll()/kqueue() when available Cross-module inline trivial functions, plus map, for-each, diff --git a/src/foreign/foreign.c b/src/foreign/foreign.c index b95488e234..8d06284858 100644 --- a/src/foreign/foreign.c +++ b/src/foreign/foreign.c @@ -168,6 +168,7 @@ typedef struct ffi_lib_struct { NON_GCBALE_PTR(void) handle; Scheme_Object* name; Scheme_Hash_Table* objects; + int is_global; } ffi_lib_struct; #define SCHEME_FFILIBP(x) (SCHEME_TYPE(x)==ffi_lib_tag) #define MYNAME "ffi-lib?" @@ -199,17 +200,18 @@ END_XFORM_SKIP; THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs); -/* (ffi-lib filename no-error?) -> ffi-lib */ +/* (ffi-lib filename no-error? global?) -> ffi-lib */ #define MYNAME "ffi-lib" static Scheme_Object *foreign_ffi_lib(int argc, Scheme_Object *argv[]) { char *name; Scheme_Object *path, *hashname; void *handle; - int null_ok = 0; + int null_ok = 0, as_global = 0; ffi_lib_struct *lib; if (!(SCHEME_PATH_STRINGP(argv[0]) || SCHEME_FALSEP(argv[0]))) scheme_wrong_type(MYNAME, "string-or-false", 0, argc, argv); + as_global = ((argc > 2) && SCHEME_TRUEP(argv[2])); /* leave the filename as given, the system will look for it */ /* (`#f' means open the executable) */ path = SCHEME_FALSEP(argv[0]) ? NULL : TO_PATH(argv[0]); @@ -226,7 +228,7 @@ static Scheme_Object *foreign_ffi_lib(int argc, Scheme_Object *argv[]) } else handle = LoadLibraryW(WIDE_PATH(name)); # else /* WINDOWS_DYNAMIC_LOAD undefined */ - handle = dlopen(name, RTLD_NOW | RTLD_GLOBAL); + handle = dlopen(name, RTLD_NOW | (as_global ? RTLD_GLOBAL : RTLD_LOCAL)); # endif /* WINDOWS_DYNAMIC_LOAD */ if (handle == NULL && !null_ok) { if (argc > 1 && SCHEME_TRUEP(argv[1])) return scheme_false; @@ -248,6 +250,7 @@ static Scheme_Object *foreign_ffi_lib(int argc, Scheme_Object *argv[]) lib->handle = (handle); lib->name = (argv[0]); lib->objects = (ht); + lib->is_global = (!name); scheme_hash_set(opened_libs, hashname, (Scheme_Object*)lib); /* no dlclose finalizer - since the hash table always keeps a reference */ /* maybe add some explicit unload at some point */ @@ -309,7 +312,7 @@ static Scheme_Object *foreign_ffi_obj(int argc, Scheme_Object *argv[]) { ffi_obj_struct *obj; void *dlobj; - ffi_lib_struct *lib = NULL; + ffi_lib_struct *lib = NULL, *lib2; char *dlname; if (SCHEME_FFILIBP(argv[1])) lib = (ffi_lib_struct*)argv[1]; @@ -361,6 +364,17 @@ static Scheme_Object *foreign_ffi_obj(int argc, Scheme_Object *argv[]) } # else /* WINDOWS_DYNAMIC_LOAD undefined */ dlobj = dlsym(lib->handle, dlname); + if (!dlobj && lib->is_global) { + /* Try every handle in the table of opened libraries. */ + int i; + for (i = opened_libs->size; i--; ) { + if (opened_libs->vals[i]) { + lib2 = (ffi_lib_struct *)opened_libs->vals[i]; + dlobj = dlsym(lib2->handle, dlname); + if (dlobj) break; + } + } + } if (!dlobj) { const char *err; err = dlerror(); @@ -3430,7 +3444,7 @@ void scheme_init_foreign(Scheme_Env *env) scheme_add_global("ffi-lib?", scheme_make_prim_w_arity(foreign_ffi_lib_p, "ffi-lib?", 1, 1), menv); scheme_add_global("ffi-lib", - scheme_make_prim_w_arity(foreign_ffi_lib, "ffi-lib", 1, 2), menv); + scheme_make_prim_w_arity(foreign_ffi_lib, "ffi-lib", 1, 3), menv); scheme_add_global("ffi-lib-name", scheme_make_prim_w_arity(foreign_ffi_lib_name, "ffi-lib-name", 1, 1), menv); scheme_add_global("ffi-obj?", @@ -3743,7 +3757,7 @@ void scheme_init_foreign(Scheme_Env *env) scheme_add_global("ffi-lib?", scheme_make_prim_w_arity((Scheme_Prim *)unimplemented, "ffi-lib?", 1, 1), menv); scheme_add_global("ffi-lib", - scheme_make_prim_w_arity((Scheme_Prim *)unimplemented, "ffi-lib", 1, 2), menv); + scheme_make_prim_w_arity((Scheme_Prim *)unimplemented, "ffi-lib", 1, 3), menv); scheme_add_global("ffi-lib-name", scheme_make_prim_w_arity((Scheme_Prim *)unimplemented, "ffi-lib-name", 1, 1), menv); scheme_add_global("ffi-obj?", diff --git a/src/foreign/foreign.rktc b/src/foreign/foreign.rktc index cb5f359854..def50c5c4f 100755 --- a/src/foreign/foreign.rktc +++ b/src/foreign/foreign.rktc @@ -165,21 +165,23 @@ END_XFORM_SKIP; /* Library objects */ @cdefstruct[ffi-lib - [handle "NON_GCBALE_PTR(void)"] - [name "Scheme_Object*"] - [objects "Scheme_Hash_Table*"]] + [handle "NON_GCBALE_PTR(void)"] + [name "Scheme_Object*"] + [objects "Scheme_Hash_Table*"] + [is_global "int"]] THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs); -/* (ffi-lib filename no-error?) -> ffi-lib */ -@cdefine[ffi-lib 1 2]{ +/* (ffi-lib filename no-error? global?) -> ffi-lib */ +@cdefine[ffi-lib 1 3]{ char *name; Scheme_Object *path, *hashname; void *handle; - int null_ok = 0; + int null_ok = 0, as_global = 0; ffi_lib_struct *lib; if (!(SCHEME_PATH_STRINGP(argv[0]) || SCHEME_FALSEP(argv[0]))) scheme_wrong_type(MYNAME, "string-or-false", 0, argc, argv); + as_global = ((argc > 2) && SCHEME_TRUEP(argv[2])); /* leave the filename as given, the system will look for it */ /* (`#f' means open the executable) */ path = SCHEME_FALSEP(argv[0]) ? NULL : TO_PATH(argv[0]); @@ -196,7 +198,7 @@ THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs); } else handle = LoadLibraryW(WIDE_PATH(name)); }{ - handle = dlopen(name, RTLD_NOW | RTLD_GLOBAL); + handle = dlopen(name, RTLD_NOW | (as_global ? RTLD_GLOBAL : RTLD_LOCAL)); } if (handle == NULL && !null_ok) { if (argc > 1 && SCHEME_TRUEP(argv[1])) return scheme_false; @@ -213,7 +215,7 @@ THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs); } } ht = scheme_make_hash_table(SCHEME_hash_string); - @cmake["lib" ffi-lib "handle" "argv[0]" "ht"] + @cmake["lib" ffi-lib "handle" "argv[0]" "ht" "!name"] scheme_hash_set(opened_libs, hashname, (Scheme_Object*)lib); /* no dlclose finalizer - since the hash table always keeps a reference */ /* maybe add some explicit unload at some point */ @@ -240,7 +242,7 @@ THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs); @cdefine[ffi-obj 2]{ ffi_obj_struct *obj; void *dlobj; - ffi_lib_struct *lib = NULL; + ffi_lib_struct *lib = NULL, *lib2; char *dlname; if (SCHEME_FFILIBP(argv[1])) lib = (ffi_lib_struct*)argv[1]; @@ -292,6 +294,17 @@ THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs); } }{ dlobj = dlsym(lib->handle, dlname); + if (!dlobj && lib->is_global) { + /* Try every handle in the table of opened libraries. */ + int i; + for (i = opened_libs->size; i--; ) { + if (opened_libs->vals[i]) { + lib2 = (ffi_lib_struct *)opened_libs->vals[i]; + dlobj = dlsym(lib2->handle, dlname); + if (dlobj) break; + } + } + } if (!dlobj) { const char *err; err = dlerror(); diff --git a/src/racket/src/schvers.h b/src/racket/src/schvers.h index 5cbe742973..48401e8796 100644 --- a/src/racket/src/schvers.h +++ b/src/racket/src/schvers.h @@ -13,12 +13,12 @@ consistently.) */ -#define MZSCHEME_VERSION "5.2.1.3" +#define MZSCHEME_VERSION "5.2.1.4" #define MZSCHEME_VERSION_X 5 #define MZSCHEME_VERSION_Y 2 #define MZSCHEME_VERSION_Z 1 -#define MZSCHEME_VERSION_W 3 +#define MZSCHEME_VERSION_W 4 #define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y) #define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W)