summaryrefslogtreecommitdiff
path: root/load.c
diff options
context:
space:
mode:
authorAlan Wu <XrXr@users.noreply.github.com>2022-11-17 17:33:18 -0500
committerAlan Wu <XrXr@users.noreply.github.com>2022-11-25 16:21:40 -0500
commit790cf4b6d0475614afb127b416e87cfa39044d67 (patch)
treed04089ae209b4c3b27b6ab68097a6065d3583520 /load.c
parente15cd01149afe4924460f81cb6e27dd96de06657 (diff)
downloadruby-790cf4b6d0475614afb127b416e87cfa39044d67.tar.gz
Fix autoload status of statically linked extensions
Previously, for statically-linked extensions, we used `vm->loading_table` to delay calling the init function until the extensions are required. This caused the extensions to look like they are in the middle of being loaded even before they're required. (`rb_feature_p()` returned true with a loading path output.) Combined with autoload, queries like `defined?(CONST)` and `Module#autoload?` were confused by this and returned nil incorrectly. RubyGems uses `defined?` to detect if OpenSSL is available and failed when OpenSSL was available in builds using `--with-static-linked-ext`. Use a dedicated table for the init functions instead of adding them to the loading table. This lets us remove some logic from non-EXTSTATIC builds. [Bug #19115]
Diffstat (limited to 'load.c')
-rw-r--r--load.c55
1 files changed, 42 insertions, 13 deletions
diff --git a/load.c b/load.c
index 5900a6af8e..282bebdb62 100644
--- a/load.c
+++ b/load.c
@@ -850,14 +850,6 @@ load_lock(rb_vm_t *vm, const char *ftptr, bool warn)
st_insert(loading_tbl, (st_data_t)ftptr, data);
return (char *)ftptr;
}
- else if (imemo_type_p(data, imemo_memo)) {
- struct MEMO *memo = MEMO_CAST(data);
- void (*init)(void) = memo->u3.func;
- data = (st_data_t)rb_thread_shield_new();
- st_insert(loading_tbl, (st_data_t)ftptr, data);
- (*init)();
- return (char *)"";
- }
if (warn) {
VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
rb_backtrace_each(rb_str_append, warning);
@@ -1025,6 +1017,23 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
}
tmp = fname;
type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
+#if EXTSTATIC
+ if (!ft && type != 1) { // not already a feature and not found as a dynamic library
+ VALUE lookup_name = tmp;
+ // Append ".so" if not already present so for example "etc" can find "etc.so".
+ // We always register statically linked extensions with a ".so" extension.
+ // See encinit.c and extinit.c (generated at build-time).
+ if (!ext) {
+ lookup_name = rb_str_dup(lookup_name);
+ rb_str_cat_cstr(lookup_name, ".so");
+ }
+ ftptr = RSTRING_PTR(lookup_name);
+ if (st_lookup(vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
+ *path = rb_filesystem_str_new_cstr(ftptr);
+ return 's';
+ }
+ }
+#endif
switch (type) {
case 0:
if (ft)
@@ -1063,6 +1072,20 @@ load_ext(VALUE path)
return (VALUE)dln_load(RSTRING_PTR(path));
}
+#if EXTSTATIC
+static bool
+run_static_ext_init(rb_vm_t *vm, const char *feature)
+{
+ st_data_t key = (st_data_t)feature;
+ st_data_t init_func;
+ if (st_delete(vm->static_ext_inits, &key, &init_func)) {
+ ((void (*)(void))init_func)();
+ return true;
+ }
+ return false;
+}
+#endif
+
static int
no_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
{
@@ -1164,6 +1187,11 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
else if (!*ftptr) {
result = TAG_RETURN;
}
+#if EXTSTATIC
+ else if (found == 's' && run_static_ext_init(th->vm, RSTRING_PTR(path))) {
+ result = TAG_RETURN;
+ }
+#endif
else if (RTEST(rb_hash_aref(realpaths,
realpath = rb_realpath_internal(Qnil, path, 1)))) {
result = 0;
@@ -1280,6 +1308,7 @@ rb_require(const char *fname)
return rb_require_string(rb_str_new_cstr(fname));
}
+#if EXTSTATIC
static int
register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
{
@@ -1289,22 +1318,22 @@ register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing
rb_warn("%s is already registered", name);
}
else {
- *value = (st_data_t)MEMO_NEW(0, 0, init);
- *key = (st_data_t)ruby_strdup(name);
+ *value = (st_data_t)init;
}
return ST_CONTINUE;
}
-RUBY_FUNC_EXPORTED void
+void
ruby_init_ext(const char *name, void (*init)(void))
{
rb_vm_t *vm = GET_VM();
- st_table *loading_tbl = get_loading_table(vm);
+ st_table *inits_table = vm->static_ext_inits;
if (feature_provided(vm, name, 0))
return;
- st_update(loading_tbl, (st_data_t)name, register_init_ext, (st_data_t)init);
+ st_update(inits_table, (st_data_t)name, register_init_ext, (st_data_t)init);
}
+#endif
/*
* call-seq: