diff --git a/configure.ac b/configure.ac index f8c814c22c..014ca40f4c 100644 --- a/configure.ac +++ b/configure.ac @@ -4751,7 +4751,7 @@ config_summary "target OS" "$target_os" config_summary "compiler" "$CC" config_summary "with thread" "$THREAD_MODEL" config_summary "with coroutine" "$coroutine_type" -config_summary "with shared GC" "$with_shared_gc" +config_summary "with shared GC" "$shared_gc_summary" config_summary "enable shared libs" "$ENABLE_SHARED" config_summary "dynamic library ext" "$DLEXT" config_summary "CFLAGS" "$cflags" diff --git a/gc.c b/gc.c index 8a7ce3f949..fc83ace418 100644 --- a/gc.c +++ b/gc.c @@ -748,14 +748,39 @@ typedef struct gc_function_map { static rb_gc_function_map_t rb_gc_functions; -# define RUBY_GC_LIBRARY_PATH "RUBY_GC_LIBRARY_PATH" +# define RUBY_GC_LIBRARY "RUBY_GC_LIBRARY" static void ruby_external_gc_init(void) { - char *gc_so_path = getenv(RUBY_GC_LIBRARY_PATH); + // Assert that the directory path ends with a / + GC_ASSERT(SHARED_GC_DIR[strlen(SHARED_GC_DIR) - 2] == '/'); + + char *gc_so_file = getenv(RUBY_GC_LIBRARY); + + char *gc_so_path = NULL; void *handle = NULL; - if (gc_so_path && dln_supported_p()) { + if (gc_so_file && dln_supported_p()) { + /* Check to make sure that gc_so_file matches /[\w-_.]+/ so that it does + * not load a shared object outside of the directory. */ + for (size_t i = 0; i < strlen(gc_so_file); i++) { + char c = gc_so_file[i]; + if (isalnum(c)) continue; + switch (c) { + case '-': + case '_': + case '.': + break; + default: + rb_bug("Only alphanumeric, dash, underscore, and period is allowed in "RUBY_GC_LIBRARY""); + } + } + + gc_so_path = alloca(strlen(SHARED_GC_DIR) + strlen(gc_so_file) + 1); + strcpy(gc_so_path, SHARED_GC_DIR); + strcpy(gc_so_path + strlen(SHARED_GC_DIR), gc_so_file); + gc_so_path[strlen(SHARED_GC_DIR) + strlen(gc_so_file)] = '\0'; + char error[1024]; handle = dln_open(gc_so_path, error, sizeof(error)); if (!handle) { @@ -4625,8 +4650,8 @@ void Init_GC(void) { #if USE_SHARED_GC - if (getenv(RUBY_GC_LIBRARY_PATH) != NULL && !dln_supported_p()) { - rb_warn(RUBY_GC_LIBRARY_PATH " is ignored because this executable file can't load extension libraries"); + if (getenv(RUBY_GC_LIBRARY) != NULL && !dln_supported_p()) { + rb_warn(RUBY_GC_LIBRARY " is ignored because this executable file can't load extension libraries"); } #endif diff --git a/tool/m4/ruby_shared_gc.m4 b/tool/m4/ruby_shared_gc.m4 index a27b9b8505..a65c26b876 100644 --- a/tool/m4/ruby_shared_gc.m4 +++ b/tool/m4/ruby_shared_gc.m4 @@ -1,19 +1,36 @@ dnl -*- Autoconf -*- AC_DEFUN([RUBY_SHARED_GC],[ AC_ARG_WITH(shared-gc, - AS_HELP_STRING([--with-shared-gc], - [Enable replacement of Ruby's GC from a shared library.]), - [with_shared_gc=$withval], [unset with_shared_gc] + AS_HELP_STRING([--with-shared-gc=DIR], + [Enable replacement of Ruby's GC from a shared library in the specified directory.]), + [shared_gc_dir=$withval], [unset shared_gc_dir] ) -AC_SUBST([with_shared_gc]) AC_MSG_CHECKING([if Ruby is build with shared GC support]) -AS_IF([test "$with_shared_gc" = "yes"], [ +AS_IF([test x"$shared_gc_dir" != x], [ AC_MSG_RESULT([yes]) + + # Ensure that shared_gc_dir is always an absolute path so that Ruby + # never loads a shared GC from a relative path + AS_CASE(["$shared_gc_dir"], + [/*], [shared_gc_dir=$shared_gc_dir], + [shared_gc_dir=`pwd`/$shared_gc_dir] + ) + + # Ensure that shared_gc_dir always terminates with a / + AS_CASE(["$shared_gc_dir"], + [*/], [], + [shared_gc_dir="$shared_gc_dir/"] + ) + AC_DEFINE([USE_SHARED_GC], [1]) + AC_DEFINE_UNQUOTED([SHARED_GC_DIR], "$shared_gc_dir") + + shared_gc_summary="yes (in $shared_gc_dir)" ], [ AC_MSG_RESULT([no]) - with_shared_gc="no" AC_DEFINE([USE_SHARED_GC], [0]) + + shared_gc_summary="no" ]) ])dnl