Work around glibc 2.1.x dlopen bug (again).
This commit is contained in:
parent
559f432126
commit
e675887129
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
22
loader/elf.c
22
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 <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);
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue