From b9109b270d129561f06bc2dcd6feaf5c43e82360 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Tue, 23 Apr 2024 14:30:31 -0400 Subject: [PATCH] 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. --- dln.c | 29 +++++++++++++++-------------- dln.h | 2 +- dmydln.c | 4 ++-- gc.c | 13 ++++--------- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/dln.c b/dln.c index 3e08728a6b..ca520acd06 100644 --- a/dln.c +++ b/dln.c @@ -340,10 +340,9 @@ dln_disable_dlclose(void) #if defined(_WIN32) || defined(USE_DLN_DLOPEN) void * -dln_open(const char *file) +dln_open(const char *file, const char **error) { static const char incompatible[] = "incompatible library version"; - const char *error = NULL; void *handle; #if defined(_WIN32) @@ -360,15 +359,15 @@ dln_open(const char *file) free(winfile); if (!handle) { - error = dln_strerror(); - goto failed; + *error = dln_strerror(); + return NULL; } # if defined(RUBY_EXPORT) if (!rb_w32_check_imported(handle, rb_libruby_handle())) { FreeLibrary(handle); - error = incompatible; - goto failed; + *error = incompatible; + return NULL; } # endif @@ -387,8 +386,8 @@ dln_open(const char *file) /* Load file */ handle = dlopen(file, RTLD_LAZY|RTLD_GLOBAL); if (handle == NULL) { - error = dln_strerror(); - goto failed; + *error = dln_strerror(); + return NULL; } # if defined(RUBY_EXPORT) @@ -413,8 +412,8 @@ dln_open(const char *file) if (libruby_name) { dln_loaderror("linked to incompatible %s - %s", libruby_name, file); } - error = incompatible; - goto failed; + *error = incompatible; + return NULL; } } } @@ -422,9 +421,6 @@ dln_open(const char *file) #endif return handle; - - failed: - dln_loaderror("%s - %s", error, file); } void * @@ -501,7 +497,12 @@ void * dln_load(const char *file) { #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 typedef unsigned long long abi_version_number; diff --git a/dln.h b/dln.h index 13eef58d9f..0bbbc73378 100644 --- a/dln.h +++ b/dln.h @@ -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_file_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL); 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*); RUBY_SYMBOL_EXPORT_END diff --git a/dmydln.c b/dmydln.c index 22f40e82eb..70fd2c1d6c 100644 --- a/dmydln.c +++ b/dmydln.c @@ -21,9 +21,9 @@ dln_symbol(void *handle, const char *symbol) UNREACHABLE_RETURN(NULL); } -NORETURN(void *dln_open(const char*)); +NORETURN(void *dln_open(const char *library, const char **error)); void* -dln_open(const char *library) +dln_open(const char *library, const char **error) { rb_loaderror("this executable file can't load extension libraries"); diff --git a/gc.c b/gc.c index ef3e1538a0..d8898b2cf1 100644 --- a/gc.c +++ b/gc.c @@ -1900,20 +1900,15 @@ ruby_external_gc_init() return; } - void *h = dln_open(gc_so_path); + const char *error = NULL; + void *h = dln_open(gc_so_path, &error); if (!h) { - rb_bug( - "ruby_external_gc_init: Shared library %s cannot be opened.", - gc_so_path - ); + rb_bug("ruby_external_gc_init: Shared library %s cannot be opened (%s)", gc_so_path, error); } void *gc_init_func = dln_symbol(h, "Init_GC"); if (!gc_init_func) { - rb_bug( - "ruby_external_gc_init: Init_GC func not exported by library %s", - gc_so_path - ); + rb_bug("ruby_external_gc_init: Init_GC func not exported by library %s", gc_so_path); } map->init = gc_init_func;