Work around glibc 2.1.x dlopen bug (again).

This commit is contained in:
James Abbatiello 2000-12-13 21:32:55 +00:00 committed by Alexandre Julliard
parent 559f432126
commit e675887129
8 changed files with 149 additions and 73 deletions

View File

@ -11,11 +11,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <string.h>
#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;
}
}

View File

@ -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 );

View File

@ -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 <dlfcn.h>
#else
#define RTLD_LAZY 0x001
#define RTLD_NOW 0x002
#define RTLD_GLOBAL 0x100
#endif
#endif /* !defined(__WINE_WINE_PORT_H) */

View File

@ -15,9 +15,6 @@
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#ifdef HAVE_DL_API
#include <dlfcn.h>
#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;
}

View File

@ -38,6 +38,9 @@
#ifdef HAVE_LIBUTIL_H
# include <libutil.h>
#endif
#ifdef HAVE_DL_API
# include <dlfcn.h>
#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
}

View File

@ -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 <dlfcn.h>
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);

View File

@ -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 );

View File

@ -10,9 +10,6 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_DL_API
#include <dlfcn.h>
#endif
#include <sys/types.h>
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
@ -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;
}