From e6758871296d70266258d2db9250736650fd65cf Mon Sep 17 00:00:00 2001 From: James Abbatiello Date: Wed, 13 Dec 2000 21:32:55 +0000 Subject: [PATCH] Work around glibc 2.1.x dlopen bug (again). --- dlls/odbc32/proxyodbc.c | 23 +++++----- include/wine/library.h | 2 +- include/wine/port.h | 12 +++++ library/loader.c | 37 +++++----------- library/port.c | 98 +++++++++++++++++++++++++++++++++++++++++ loader/elf.c | 22 ++++----- loader/module.c | 2 +- relay32/builtin32.c | 26 +++-------- 8 files changed, 149 insertions(+), 73 deletions(-) diff --git a/dlls/odbc32/proxyodbc.c b/dlls/odbc32/proxyodbc.c index bd12ea5cb07..6144c48c5ac 100644 --- a/dlls/odbc32/proxyodbc.c +++ b/dlls/odbc32/proxyodbc.c @@ -11,11 +11,11 @@ #include #include -#include #include #include "winbase.h" #include "debugtools.h" +#include "wine/port.h" #include "sql.h" #include "sqltypes.h" @@ -164,7 +164,7 @@ MAIN_OdbcInit(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) if (gProxyHandle.dmHandle) { - dlclose(gProxyHandle.dmHandle); + wine_dlclose(gProxyHandle.dmHandle,NULL,0); gProxyHandle.dmHandle = NULL; } } @@ -186,6 +186,7 @@ MAIN_OdbcInit(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) BOOL ODBC_LoadDriverManager() { char *s = getenv("LIB_ODBC_DRIVER_MANAGER"); + char error[256]; TRACE("\n"); @@ -196,13 +197,11 @@ BOOL ODBC_LoadDriverManager() else strcpy(gProxyHandle.dmLibName, "libodbc.so"); - dlerror(); /* clear dlerror first */ - gProxyHandle.dmHandle = dlopen(gProxyHandle.dmLibName, RTLD_LAZY); + gProxyHandle.dmHandle = wine_dlopen(gProxyHandle.dmLibName, RTLD_LAZY, error, sizeof(error)); if (gProxyHandle.dmHandle == NULL) /* fail to load unixODBC driver manager */ { - const char *err = dlerror(); - WARN("failed to open library %s: %s\n", gProxyHandle.dmLibName, err); + WARN("failed to open library %s: %s\n", gProxyHandle.dmLibName, error); gProxyHandle.dmLibName[0] = '\0'; gProxyHandle.nErrorType = ERROR_LIBRARY_NOT_FOUND; return FALSE; @@ -228,18 +227,18 @@ BOOL ODBC_LoadDriverManager() BOOL ODBC_LoadDMFunctions() { int i; + char error[256]; if (gProxyHandle.dmHandle == NULL) return FALSE; - dlerror(); /* clear dlerror first */ for ( i = 0; i < NUM_SQLFUNC; i ++ ) { gProxyHandle.functions[i] = template_func[i]; - gProxyHandle.functions[i].func = dlsym(gProxyHandle.dmHandle, - gProxyHandle.functions[i].name); + gProxyHandle.functions[i].func = wine_dlsym(gProxyHandle.dmHandle, + gProxyHandle.functions[i].name, error, sizeof(error)); - if (dlerror()) + if (error[0]) { ERR("Failed to load function %s",gProxyHandle.functions[i].name); gProxyHandle.functions[i].func = SQLDummyFunc; @@ -739,7 +738,7 @@ SQLRETURN WINAPI SQLFreeEnv(SQLHENV EnvironmentHandle) /* if (gProxyHandle.dmHandle) { - dlclose(gProxyHandle.dmHandle); + wine_dlclose(gProxyHandle.dmHandle,NULL,0); gProxyHandle.dmHandle = NULL; } */ @@ -769,7 +768,7 @@ SQLRETURN WINAPI SQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle) { if (gProxyHandle.dmHandle) { - dlclose(gProxyHandle.dmHandle); + wine_dlclose(gProxyHandle.dmHandle,NULL,0); gProxyHandle.dmHandle = NULL; } } diff --git a/include/wine/library.h b/include/wine/library.h index 53fe0d26077..bde09f84a8e 100644 --- a/include/wine/library.h +++ b/include/wine/library.h @@ -15,7 +15,7 @@ typedef void (*load_dll_callback_t)( void *, const char * ); extern void wine_dll_set_callback( load_dll_callback_t load ); -extern void *wine_dll_load( const char *filename ); +extern void *wine_dll_load( const char *filename, char *error, int errorsize ); extern void *wine_dll_load_main_exe( const char *name, int search_path ); extern void wine_dll_unload( void *handle ); diff --git a/include/wine/port.h b/include/wine/port.h index 877ab781dd5..4465e16ad81 100644 --- a/include/wine/port.h +++ b/include/wine/port.h @@ -130,4 +130,16 @@ int lstat(const char *file_name, struct stat *buf); #define S_ISLNK(mod) (0) #endif /* S_ISLNK */ +extern void *wine_dlopen( const char *filename, int flag, char *error, int errorsize ); +extern void *wine_dlsym( void *handle, const char *symbol, char *error, int errorsize ); +extern int wine_dlclose( void *handle, char *error, int errorsize ); + +#ifdef HAVE_DL_API +#include +#else +#define RTLD_LAZY 0x001 +#define RTLD_NOW 0x002 +#define RTLD_GLOBAL 0x100 +#endif + #endif /* !defined(__WINE_WINE_PORT_H) */ diff --git a/library/loader.c b/library/loader.c index 35a7b422972..aeb46f3e2ed 100644 --- a/library/loader.c +++ b/library/loader.c @@ -15,9 +15,6 @@ #ifdef HAVE_SYS_MMAN_H #include #endif -#ifdef HAVE_DL_API -#include -#endif #include "winnt.h" #include "wine/library.h" @@ -79,18 +76,14 @@ static void build_dll_path(void) /* open a library for a given dll, searching in the dll path * 'name' must be the Windows dll name (e.g. "kernel32.dll") */ -static void *dlopen_dll( const char *name ) +static void *dlopen_dll( const char *name, char *error, int errorsize ) { -#ifdef HAVE_DL_API int i, namelen = strlen(name); char *buffer, *p, *ext; void *ret = NULL; if (!init_done) build_dll_path(); - /* clear dlerror to avoid glibc bug */ - dlerror(); - buffer = malloc( dll_path_maxlen + namelen + 8 ); /* store the name at the end of the buffer, prefixed by /lib and followed by .so */ @@ -109,17 +102,14 @@ static void *dlopen_dll( const char *name ) int len = strlen(dll_paths[i]); char *p = buffer + dll_path_maxlen - len; memcpy( p, dll_paths[i], len ); - if ((ret = dlopen( p, RTLD_NOW ))) break; - dlerror(); /* clear dlerror to avoid glibc bug */ + if ((ret = wine_dlopen( p, RTLD_NOW, error, errorsize ))) break; } /* now try the default dlopen search path */ - if (!ret) ret = dlopen( buffer + dll_path_maxlen + 1, RTLD_NOW ); + if (!ret) + ret = wine_dlopen( buffer + dll_path_maxlen + 1, RTLD_NOW, error, errorsize ); free( buffer ); return ret; -#else - return NULL; -#endif } @@ -318,7 +308,7 @@ void wine_dll_set_callback( load_dll_callback_t load ) * * Load a builtin dll. */ -void *wine_dll_load( const char *filename ) +void *wine_dll_load( const char *filename, char *error, int errorsize ) { int i; @@ -338,7 +328,7 @@ void *wine_dll_load( const char *filename ) return (void *)1; } } - return dlopen_dll( filename ); + return dlopen_dll( filename, error, errorsize ); } @@ -349,9 +339,8 @@ void *wine_dll_load( const char *filename ) */ void wine_dll_unload( void *handle ) { -#ifdef HAVE_DL_API - if (handle != (void *)1) dlclose( handle ); -#endif + if (handle != (void *)1) + wine_dlclose( handle, NULL, 0 ); } @@ -359,20 +348,17 @@ void wine_dll_unload( void *handle ) * wine_dll_load_main_exe * * Try to load the .so for the main exe, optionally searching for it in PATH. - * Note: dlerror() is cleared before returning because of a glibc bug. */ void *wine_dll_load_main_exe( const char *name, int search_path ) { void *ret = NULL; -#ifdef HAVE_DL_API const char *path = NULL; if (search_path) path = getenv( "PATH" ); if (!path) { /* no path, try only the specified name */ - dlerror(); /* clear dlerror to avoid glibc bug */ - ret = dlopen( name, RTLD_NOW ); + ret = wine_dlopen( name, RTLD_NOW, NULL, 0 ); } else { @@ -394,8 +380,7 @@ void *wine_dll_load_main_exe( const char *name, int search_path ) if ((len = p - path) > 0) { memcpy( basename - len, path, len ); - dlerror(); /* clear dlerror to avoid glibc bug */ - if ((ret = dlopen( basename - len, RTLD_NOW ))) break; + if ((ret = wine_dlopen( basename - len, RTLD_NOW, NULL, 0 ))) break; } if (!*p) break; path = p + 1; @@ -403,7 +388,5 @@ void *wine_dll_load_main_exe( const char *name, int search_path ) if (tmp != buffer) free( tmp ); } } - if (!ret) dlerror(); /* clear dlerror to avoid glibc bug */ -#endif /* HAVE_DL_API */ return ret; } diff --git a/library/port.c b/library/port.c index 064c1833dde..f44f37e402c 100644 --- a/library/port.c +++ b/library/port.c @@ -38,6 +38,9 @@ #ifdef HAVE_LIBUTIL_H # include #endif +#ifdef HAVE_DL_API +# include +#endif #include "wine/port.h" @@ -411,3 +414,98 @@ void *wine_anon_mmap( void *start, size_t size, int prot, int flags ) #endif return mmap( start, size, prot, flags, fdzero, 0 ); } + + +/* + * These functions provide wrappers around dlopen() and associated + * functions. They work around a bug in glibc 2.1.x where calling + * a dl*() function after a previous dl*() function has failed + * without a dlerror() call between the two will cause a crash. + * They all take a pointer to a buffer that + * will receive the error description (from dlerror()). This + * parameter may be NULL if the error description is not required. + */ + +/*********************************************************************** + * wine_dlopen + */ +void *wine_dlopen( const char *filename, int flag, char *error, int errorsize ) +{ +#ifdef HAVE_DL_API + void *ret; + char *s; + dlerror(); dlerror(); + ret = dlopen( filename, flag ); + s = dlerror(); + if (error) + { + strncpy( error, s ? s : "", errorsize ); + error[errorsize - 1] = '\0'; + } + dlerror(); + return ret; +#else + if (error) + { + strncpy( error, "dlopen interface not detected by configure", errorsize ); + error[errorsize - 1] = '\0'; + } + return NULL; +#endif +} + +/*********************************************************************** + * wine_dlsym + */ +void *wine_dlsym( void *handle, const char *symbol, char *error, int errorsize ) +{ +#ifdef HAVE_DL_API + void *ret; + char *s; + dlerror(); dlerror(); + ret = dlsym( handle, symbol ); + s = dlerror(); + if (error) + { + strncpy( error, s ? s : "", errorsize ); + error[errorsize - 1] = '\0'; + } + dlerror(); + return ret; +#else + if (error) + { + strncpy( error, "dlopen interface not detected by configure", errorsize ); + error[errorsize - 1] = '\0'; + } + return NULL; +#endif +} + +/*********************************************************************** + * wine_dlclose + */ +int wine_dlclose( void *handle, char *error, int errorsize ) +{ +#ifdef HAVE_DL_API + int ret; + char *s; + dlerror(); dlerror(); + ret = dlclose( handle ); + s = dlerror(); + if (error) + { + strncpy( error, s ? s : "", errorsize ); + error[errorsize - 1] = '\0'; + } + dlerror(); + return ret; +#else + if (error) + { + strncpy( error, "dlopen interface not detected by configure", errorsize ); + error[errorsize - 1] = '\0'; + } + return 1; +#endif +} diff --git a/loader/elf.c b/loader/elf.c index 816b709f1fd..9303a9af700 100644 --- a/loader/elf.c +++ b/loader/elf.c @@ -22,6 +22,7 @@ #include "module.h" #include "debugtools.h" #include "winerror.h" +#include "wine/port.h" DEFAULT_DEBUG_CHANNEL(win32); @@ -49,8 +50,6 @@ typedef struct { sizeof(IMAGE_NT_HEADERS) + \ sizeof(IMAGE_SECTION_HEADER)) -#include - static FARPROC ELF_FindExportedFunction( WINE_MODREF *wm, LPCSTR funcName, BOOL snoop ); static HMODULE ELF_CreateDummyModule( LPCSTR libname, LPCSTR modname ) @@ -109,6 +108,7 @@ WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags) HMODULE hmod; char *modname,*s,*t,*x; LPVOID *dlhandle; + char error[256]; t = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(libname) + strlen("lib.so") + 1 ); @@ -152,10 +152,9 @@ WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags) points to the ENTIRE DOS filename of the library t is returned by HeapAlloc() above and so is also used with HeapFree() below */ - dlerror(); /* clear dlerror because of glibc bug */ - dlhandle = dlopen(s,RTLD_NOW); + dlhandle = wine_dlopen(s,RTLD_NOW,error,sizeof(error)); if (!dlhandle) { - dlerror(); /* clear dlerror because of glibc bug */ + WARN("failed to load %s: %s\n", s, error); HeapFree( GetProcessHeap(), 0, t ); SetLastError( ERROR_FILE_NOT_FOUND ); return NULL; @@ -176,22 +175,20 @@ static FARPROC ELF_FindExportedFunction( WINE_MODREF *wm, LPCSTR funcName, BOOL LPVOID fun; int i,nrofargs = 0; ELF_STDCALL_STUB *stub, *first_stub; + char error[256]; if (!HIWORD(funcName)) { ERR("Can't import from UNIX dynamic libs by ordinal, sorry.\n"); return (FARPROC)0; } - dlerror(); /* clear dlerror() first */ - fun = dlsym(wm->dlhandle,funcName); + fun = wine_dlsym(wm->dlhandle,funcName,error,sizeof(error)); if (!fun) { - dlerror(); /* clear dlerror() to avoid glibc bug */ /* we sometimes have an excess '_' at the beginning of the name */ if (funcName[0]=='_') { funcName++ ; - fun = dlsym(wm->dlhandle,funcName); - if (!fun) dlerror(); /* clear dlerror() to avoid glibc bug */ + fun = wine_dlsym(wm->dlhandle,funcName,error,sizeof(error)); } } if (!fun) { @@ -205,8 +202,7 @@ static FARPROC ELF_FindExportedFunction( WINE_MODREF *wm, LPCSTR funcName, BOOL *t = '\0'; nrofargs = 0; sscanf(t+1,"%d",&nrofargs); - fun = dlsym(wm->dlhandle,fn); - if (!fun) dlerror(); /* clear dlerror() to avoid glibc bug */ + fun = wine_dlsym(wm->dlhandle,fn,error,sizeof(error)); HeapFree( GetProcessHeap(), 0, fn ); } } @@ -266,7 +262,7 @@ static FARPROC ELF_FindExportedFunction( WINE_MODREF *wm, LPCSTR funcName, BOOL fun=(FARPROC)stub; } if (!fun) { - FIXME("function %s not found: %s\n",funcName,dlerror()); + FIXME("function %s not found: %s\n",funcName,error); return fun; } fun = SNOOP_GetProcAddress(wm->module,funcName,stub-first_stub,fun); diff --git a/loader/module.c b/loader/module.c index bd64dbecf0e..2d6b946d75d 100644 --- a/loader/module.c +++ b/loader/module.c @@ -1505,7 +1505,7 @@ static void MODULE_FlushModrefs(void) TRACE(" unloading %s\n", wm->filename); /* VirtualFree( (LPVOID)wm->module, 0, MEM_RELEASE ); */ /* FIXME */ - /* if (wm->dlhandle) dlclose( wm->dlhandle ); */ /* FIXME */ + /* if (wm->dlhandle) wine_dlclose( wm->dlhandle, NULL, 0 ); */ /* FIXME */ FreeLibrary16(wm->hDummyMod); HeapFree( GetProcessHeap(), 0, wm->deps ); HeapFree( GetProcessHeap(), 0, wm->filename ); diff --git a/relay32/builtin32.c b/relay32/builtin32.c index 41dcdae3853..6b5b7d8a44b 100644 --- a/relay32/builtin32.c +++ b/relay32/builtin32.c @@ -10,9 +10,6 @@ #include #include #include -#ifdef HAVE_DL_API -#include -#endif #include #ifdef HAVE_SYS_MMAN_H #include @@ -40,24 +37,17 @@ static HMODULE main_module; */ void *BUILTIN32_dlopen( const char *name ) { -#ifdef HAVE_DL_API void *handle; + char error[256]; - if (!(handle = wine_dll_load( name ))) + if (!(handle = wine_dll_load( name, error, sizeof(error) ))) { - LPSTR pErr; - if ((pErr = dlerror())) - { - if (strstr(pErr, "undefined symbol")) /* undef symbol -> ERR() */ - ERR("failed to load %s: %s\n", name, pErr); - else /* WARN() for libraries that are supposed to be native */ - WARN("failed to load %s: %s\n", name, pErr ); - } + if (strstr(error, "undefined symbol")) /* undef symbol -> ERR() */ + ERR("failed to load %s: %s\n", name, error); + else /* WARN() for libraries that are supposed to be native */ + WARN("failed to load %s: %s\n", name, error ); } return handle; -#else - return NULL; -#endif } /*********************************************************************** @@ -65,10 +55,8 @@ void *BUILTIN32_dlopen( const char *name ) */ int BUILTIN32_dlclose( void *handle ) { -#ifdef HAVE_DL_API /* FIXME: should unregister descriptors first */ - /* return dlclose( handle ); */ -#endif + /* wine_dll_unload( handle ); */ return 0; }