Always pass lower-case filenames to wine_dll_load().

Clear dlerror() before and after calls to dlopen/dlsym to work around
a glibc bug (thanks to James Abbatiello for tracking the bug).
This commit is contained in:
Alexandre Julliard 2000-12-05 21:17:59 +00:00
parent 01eeb01f0b
commit 886604c715
5 changed files with 44 additions and 19 deletions

View File

@ -196,11 +196,13 @@ BOOL ODBC_LoadDriverManager()
else else
strcpy(gProxyHandle.dmLibName, "libodbc.so"); strcpy(gProxyHandle.dmLibName, "libodbc.so");
dlerror(); /* clear dlerror first */
gProxyHandle.dmHandle = dlopen(gProxyHandle.dmLibName, RTLD_LAZY); gProxyHandle.dmHandle = dlopen(gProxyHandle.dmLibName, RTLD_LAZY);
if (gProxyHandle.dmHandle == NULL) /* fail to load unixODBC driver manager */ if (gProxyHandle.dmHandle == NULL) /* fail to load unixODBC driver manager */
{ {
WARN("failed to open library %s\n", gProxyHandle.dmLibName); const char *err = dlerror();
WARN("failed to open library %s: %s\n", gProxyHandle.dmLibName, err);
gProxyHandle.dmLibName[0] = '\0'; gProxyHandle.dmLibName[0] = '\0';
gProxyHandle.nErrorType = ERROR_LIBRARY_NOT_FOUND; gProxyHandle.nErrorType = ERROR_LIBRARY_NOT_FOUND;
return FALSE; return FALSE;
@ -230,6 +232,7 @@ BOOL ODBC_LoadDMFunctions()
if (gProxyHandle.dmHandle == NULL) if (gProxyHandle.dmHandle == NULL)
return FALSE; return FALSE;
dlerror(); /* clear dlerror first */
for ( i = 0; i < NUM_SQLFUNC; i ++ ) for ( i = 0; i < NUM_SQLFUNC; i ++ )
{ {
gProxyHandle.functions[i] = template_func[i]; gProxyHandle.functions[i] = template_func[i];

View File

@ -122,6 +122,7 @@ HMODULE16 BUILTIN_LoadModule( LPCSTR name )
strcpy( dllname, name ); strcpy( dllname, name );
p = strrchr( dllname, '.' ); p = strrchr( dllname, '.' );
if (!p) strcat( dllname, ".dll" ); if (!p) strcat( dllname, ".dll" );
for (p = dllname; *p; p++) *p = FILE_tolower(*p);
for (i = 0; i < nb_dlls; i++) for (i = 0; i < nb_dlls; i++)
{ {

View File

@ -83,23 +83,25 @@ static void *dlopen_dll( const char *name )
{ {
#ifdef HAVE_DL_API #ifdef HAVE_DL_API
int i, namelen = strlen(name); int i, namelen = strlen(name);
char *buffer, *p; char *buffer, *p, *ext;
void *ret = NULL; void *ret = NULL;
if (!init_done) build_dll_path(); if (!init_done) build_dll_path();
/* check for .dll or .exe extension to remove */ /* clear dlerror to avoid glibc bug */
if ((p = strrchr( name, '.' ))) dlerror();
{
if (!strcasecmp( p, ".dll" ) || !strcasecmp( p, ".exe" )) namelen -= 4;
}
buffer = malloc( dll_path_maxlen + namelen + 8 ); buffer = malloc( dll_path_maxlen + namelen + 8 );
/* store the name at the end of the buffer, prefixed by /lib and followed by .so */ /* store the name at the end of the buffer, prefixed by /lib and followed by .so */
p = buffer + dll_path_maxlen; p = buffer + dll_path_maxlen;
memcpy( p, "/lib", 4 ); memcpy( p, "/lib", 4 );
for (i = 0, p += 4; i < namelen; i++, p++) *p = tolower(name[i]); p += 4;
memcpy( p, name, namelen+1 );
ext = strrchr( p, '.' );
p += namelen;
/* check for .dll or .exe extension to remove */
if (ext && (!strcmp( ext, ".dll" ) || !strcmp( ext, ".exe" ))) p = ext;
memcpy( p, ".so", 4 ); memcpy( p, ".so", 4 );
for (i = 0; i < nb_dll_paths; i++) for (i = 0; i < nb_dll_paths; i++)
@ -108,6 +110,7 @@ static void *dlopen_dll( const char *name )
char *p = buffer + dll_path_maxlen - len; char *p = buffer + dll_path_maxlen - len;
memcpy( p, dll_paths[i], len ); memcpy( p, dll_paths[i], len );
if ((ret = dlopen( p, RTLD_NOW ))) break; if ((ret = dlopen( p, RTLD_NOW ))) break;
dlerror(); /* clear dlerror to avoid glibc bug */
} }
/* now try the default dlopen search path */ /* now try the default dlopen search path */
@ -327,7 +330,7 @@ void *wine_dll_load( const char *filename )
for (i = 0; i < nb_dlls; i++) for (i = 0; i < nb_dlls; i++)
{ {
if (!builtin_dlls[i].nt) continue; if (!builtin_dlls[i].nt) continue;
if (!strcasecmp( builtin_dlls[i].filename, filename )) if (!strcmp( builtin_dlls[i].filename, filename ))
{ {
const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt; const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
builtin_dlls[i].nt = NULL; builtin_dlls[i].nt = NULL;
@ -356,6 +359,7 @@ void wine_dll_unload( void *handle )
* wine_dll_load_main_exe * wine_dll_load_main_exe
* *
* Try to load the .so for the main exe, optionally searching for it in PATH. * 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 *wine_dll_load_main_exe( const char *name, int search_path )
{ {
@ -367,6 +371,7 @@ void *wine_dll_load_main_exe( const char *name, int search_path )
if (!path) if (!path)
{ {
/* no path, try only the specified name */ /* no path, try only the specified name */
dlerror(); /* clear dlerror to avoid glibc bug */
ret = dlopen( name, RTLD_NOW ); ret = dlopen( name, RTLD_NOW );
} }
else else
@ -389,6 +394,7 @@ void *wine_dll_load_main_exe( const char *name, int search_path )
if ((len = p - path) > 0) if ((len = p - path) > 0)
{ {
memcpy( basename - len, path, len ); memcpy( basename - len, path, len );
dlerror(); /* clear dlerror to avoid glibc bug */
if ((ret = dlopen( basename - len, RTLD_NOW ))) break; if ((ret = dlopen( basename - len, RTLD_NOW ))) break;
} }
if (!*p) break; if (!*p) break;
@ -397,6 +403,7 @@ void *wine_dll_load_main_exe( const char *name, int search_path )
if (tmp != buffer) free( tmp ); if (tmp != buffer) free( tmp );
} }
} }
if (!ret) dlerror(); /* clear dlerror to avoid glibc bug */
#endif /* HAVE_DL_API */ #endif /* HAVE_DL_API */
return ret; return ret;
} }

View File

@ -154,8 +154,10 @@ WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags)
points to the ENTIRE DOS filename of the library points to the ENTIRE DOS filename of the library
t is returned by HeapAlloc() above and so is also used t is returned by HeapAlloc() above and so is also used
with HeapFree() below */ with HeapFree() below */
dlhandle = ELFDLL_dlopen(s,RTLD_NOW); dlerror(); /* clear dlerror because of glibc bug */
dlhandle = dlopen(s,RTLD_NOW);
if (!dlhandle) { if (!dlhandle) {
dlerror(); /* clear dlerror because of glibc bug */
HeapFree( GetProcessHeap(), 0, t ); HeapFree( GetProcessHeap(), 0, t );
SetLastError( ERROR_FILE_NOT_FOUND ); SetLastError( ERROR_FILE_NOT_FOUND );
return NULL; return NULL;
@ -181,12 +183,19 @@ static FARPROC ELF_FindExportedFunction( WINE_MODREF *wm, LPCSTR funcName, BOOL
ERR("Can't import from UNIX dynamic libs by ordinal, sorry.\n"); ERR("Can't import from UNIX dynamic libs by ordinal, sorry.\n");
return (FARPROC)0; return (FARPROC)0;
} }
dlerror(); /* clear dlerror() first */
fun = dlsym(wm->dlhandle,funcName); fun = dlsym(wm->dlhandle,funcName);
/* we sometimes have an excess '_' at the beginning of the name */ if (!fun)
if (!fun && (funcName[0]=='_')) { {
dlerror(); /* clear dlerror() to avoid glibc bug */
/* we sometimes have an excess '_' at the beginning of the name */
if (funcName[0]=='_')
{
funcName++ ; funcName++ ;
fun = dlsym(wm->dlhandle,funcName); fun = dlsym(wm->dlhandle,funcName);
} if (!fun) dlerror(); /* clear dlerror() to avoid glibc bug */
}
}
if (!fun) { if (!fun) {
/* Function@nrofargs usually marks a stdcall function /* Function@nrofargs usually marks a stdcall function
* with nrofargs bytes that are popped at the end * with nrofargs bytes that are popped at the end
@ -199,6 +208,7 @@ static FARPROC ELF_FindExportedFunction( WINE_MODREF *wm, LPCSTR funcName, BOOL
nrofargs = 0; nrofargs = 0;
sscanf(t+1,"%d",&nrofargs); sscanf(t+1,"%d",&nrofargs);
fun = dlsym(wm->dlhandle,fn); fun = dlsym(wm->dlhandle,fn);
if (!fun) dlerror(); /* clear dlerror() to avoid glibc bug */
HeapFree( GetProcessHeap(), 0, fn ); HeapFree( GetProcessHeap(), 0, fn );
} }
} }

View File

@ -23,6 +23,7 @@
#include "wine/library.h" #include "wine/library.h"
#include "global.h" #include "global.h"
#include "module.h" #include "module.h"
#include "file.h"
#include "heap.h" #include "heap.h"
#include "main.h" #include "main.h"
#include "winerror.h" #include "winerror.h"
@ -46,12 +47,14 @@ void *BUILTIN32_dlopen( const char *name )
if (!(handle = wine_dll_load( name ))) if (!(handle = wine_dll_load( name )))
{ {
LPSTR pErr; LPSTR pErr;
pErr = dlerror(); if ((pErr = dlerror()))
if (strstr(pErr, "undefined symbol")) /* undef symbol -> ERR() */ {
ERR("failed to load %s: %s\n", name, pErr); if (strstr(pErr, "undefined symbol")) /* undef symbol -> ERR() */
else /* WARN() for libraries that are supposed to be native */ ERR("failed to load %s: %s\n", name, pErr);
WARN("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 );
}
} }
return handle; return handle;
#else #else
@ -136,6 +139,7 @@ WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags)
strcpy( dllname, name ); strcpy( dllname, name );
p = strrchr( dllname, '.' ); p = strrchr( dllname, '.' );
if (!p) strcat( dllname, ".dll" ); if (!p) strcat( dllname, ".dll" );
for (p = dllname; *p; p++) *p = FILE_tolower(*p);
if (!(handle = BUILTIN32_dlopen( dllname ))) goto error; if (!(handle = BUILTIN32_dlopen( dllname ))) goto error;