Get error from dln_open when USE_SHARED_GC

Before, if dln_open failed to open RUBY_GC_LIBRARY_PATH, it would segfault
because it would try to raise an error, which cannot happen because the
GC has not been initialized yet.

This commit changes dln_open to return the error that occurred so the
caller can handle the error.
This commit is contained in:
Peter Zhu 2024-04-23 14:30:31 -04:00
parent 81433fd0f5
commit b9109b270d
4 changed files with 22 additions and 26 deletions

29
dln.c
View File

@ -340,10 +340,9 @@ dln_disable_dlclose(void)
#if defined(_WIN32) || defined(USE_DLN_DLOPEN) #if defined(_WIN32) || defined(USE_DLN_DLOPEN)
void * void *
dln_open(const char *file) dln_open(const char *file, const char **error)
{ {
static const char incompatible[] = "incompatible library version"; static const char incompatible[] = "incompatible library version";
const char *error = NULL;
void *handle; void *handle;
#if defined(_WIN32) #if defined(_WIN32)
@ -360,15 +359,15 @@ dln_open(const char *file)
free(winfile); free(winfile);
if (!handle) { if (!handle) {
error = dln_strerror(); *error = dln_strerror();
goto failed; return NULL;
} }
# if defined(RUBY_EXPORT) # if defined(RUBY_EXPORT)
if (!rb_w32_check_imported(handle, rb_libruby_handle())) { if (!rb_w32_check_imported(handle, rb_libruby_handle())) {
FreeLibrary(handle); FreeLibrary(handle);
error = incompatible; *error = incompatible;
goto failed; return NULL;
} }
# endif # endif
@ -387,8 +386,8 @@ dln_open(const char *file)
/* Load file */ /* Load file */
handle = dlopen(file, RTLD_LAZY|RTLD_GLOBAL); handle = dlopen(file, RTLD_LAZY|RTLD_GLOBAL);
if (handle == NULL) { if (handle == NULL) {
error = dln_strerror(); *error = dln_strerror();
goto failed; return NULL;
} }
# if defined(RUBY_EXPORT) # if defined(RUBY_EXPORT)
@ -413,8 +412,8 @@ dln_open(const char *file)
if (libruby_name) { if (libruby_name) {
dln_loaderror("linked to incompatible %s - %s", libruby_name, file); dln_loaderror("linked to incompatible %s - %s", libruby_name, file);
} }
error = incompatible; *error = incompatible;
goto failed; return NULL;
} }
} }
} }
@ -422,9 +421,6 @@ dln_open(const char *file)
#endif #endif
return handle; return handle;
failed:
dln_loaderror("%s - %s", error, file);
} }
void * void *
@ -501,7 +497,12 @@ void *
dln_load(const char *file) dln_load(const char *file)
{ {
#if defined(_WIN32) || defined(USE_DLN_DLOPEN) #if defined(_WIN32) || defined(USE_DLN_DLOPEN)
void *handle = dln_open(file); const char *error = NULL;
void *handle = dln_open(file, &error);
if (handle == NULL) {
dln_loaderror("%s - %s", error, file);
}
#ifdef RUBY_DLN_CHECK_ABI #ifdef RUBY_DLN_CHECK_ABI
typedef unsigned long long abi_version_number; typedef unsigned long long abi_version_number;

2
dln.h
View File

@ -25,7 +25,7 @@ RUBY_SYMBOL_EXPORT_BEGIN
char *dln_find_exe_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL); char *dln_find_exe_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL);
char *dln_find_file_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL); char *dln_find_file_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL);
void *dln_load(const char*); void *dln_load(const char*);
void *dln_open(const char *file); void *dln_open(const char *file, const char **error);
void *dln_symbol(void*,const char*); void *dln_symbol(void*,const char*);
RUBY_SYMBOL_EXPORT_END RUBY_SYMBOL_EXPORT_END

View File

@ -21,9 +21,9 @@ dln_symbol(void *handle, const char *symbol)
UNREACHABLE_RETURN(NULL); UNREACHABLE_RETURN(NULL);
} }
NORETURN(void *dln_open(const char*)); NORETURN(void *dln_open(const char *library, const char **error));
void* void*
dln_open(const char *library) dln_open(const char *library, const char **error)
{ {
rb_loaderror("this executable file can't load extension libraries"); rb_loaderror("this executable file can't load extension libraries");

13
gc.c
View File

@ -1900,20 +1900,15 @@ ruby_external_gc_init()
return; return;
} }
void *h = dln_open(gc_so_path); const char *error = NULL;
void *h = dln_open(gc_so_path, &error);
if (!h) { if (!h) {
rb_bug( rb_bug("ruby_external_gc_init: Shared library %s cannot be opened (%s)", gc_so_path, error);
"ruby_external_gc_init: Shared library %s cannot be opened.",
gc_so_path
);
} }
void *gc_init_func = dln_symbol(h, "Init_GC"); void *gc_init_func = dln_symbol(h, "Init_GC");
if (!gc_init_func) { if (!gc_init_func) {
rb_bug( rb_bug("ruby_external_gc_init: Init_GC func not exported by library %s", gc_so_path);
"ruby_external_gc_init: Init_GC func not exported by library %s",
gc_so_path
);
} }
map->init = gc_init_func; map->init = gc_init_func;