summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2025-11-08 11:05:17 +0900
committerNobuyoshi Nakada <nobu.nakada@gmail.com>2025-12-09 23:41:50 +0900
commit573896a40ac25bd9febb2bbc0502b43ef36f9b9b (patch)
treebc893ac96eedf12685e42fe63fe35ad734d01c0b
parente8568bbcf20fafcb82d8b537b99762528dfbdc3e (diff)
Box: remove copied extension files
-rw-r--r--box.c60
-rw-r--r--internal/box.h13
-rw-r--r--load.c16
-rw-r--r--test/ruby/test_box.rb4
4 files changed, 74 insertions, 19 deletions
diff --git a/box.c b/box.c
index e7065c1c29..0ce8d0aee0 100644
--- a/box.c
+++ b/box.c
@@ -62,6 +62,7 @@ bool ruby_box_crashed = false; // extern, changed only in vm.c
VALUE rb_resolve_feature_path(VALUE klass, VALUE fname);
static VALUE rb_box_inspect(VALUE obj);
+static void cleanup_all_local_extensions(VALUE libmap);
void
rb_box_init_done(void)
@@ -274,6 +275,8 @@ box_entry_free(void *ptr)
st_foreach(box->classext_cow_classes, free_classext_for_box, (st_data_t)box);
}
+ cleanup_all_local_extensions(box->ruby_dln_libmap);
+
box_root_free(ptr);
xfree(ptr);
}
@@ -724,8 +727,57 @@ escaped_basename(const char *path, const char *fname, char *rvalue, size_t rsize
}
}
+static void
+box_ext_cleanup_mark(void *p)
+{
+ rb_gc_mark((VALUE)p);
+}
+
+static void
+box_ext_cleanup_free(void *p)
+{
+ VALUE path = (VALUE)p;
+ unlink(RSTRING_PTR(path));
+}
+
+static const rb_data_type_t box_ext_cleanup_type = {
+ "box_ext_cleanup",
+ {box_ext_cleanup_mark, box_ext_cleanup_free},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+void
+rb_box_cleanup_local_extension(VALUE cleanup)
+{
+ void *p = DATA_PTR(cleanup);
+ DATA_PTR(cleanup) = NULL;
+#ifndef _WIN32
+ if (p) box_ext_cleanup_free(p);
+#endif
+}
+
+static int
+cleanup_local_extension_i(VALUE key, VALUE value, VALUE arg)
+{
+#if defined(_WIN32)
+ HMODULE h = (HMODULE)NUM2SVALUE(value);
+ WCHAR module_path[MAXPATHLEN];
+ DWORD len = GetModuleFileNameW(h, module_path, numberof(module_path));
+
+ FreeLibrary(h);
+ if (len > 0 && len < numberof(module_path)) DeleteFileW(module_path);
+#endif
+ return ST_DELETE;
+}
+
+static void
+cleanup_all_local_extensions(VALUE libmap)
+{
+ rb_hash_foreach(libmap, cleanup_local_extension_i, 0);
+}
+
VALUE
-rb_box_local_extension(VALUE box_value, VALUE fname, VALUE path)
+rb_box_local_extension(VALUE box_value, VALUE fname, VALUE path, VALUE *cleanup)
{
char ext_path[MAXPATHLEN], fname2[MAXPATHLEN], basename[MAXPATHLEN];
int wrote;
@@ -739,14 +791,16 @@ rb_box_local_extension(VALUE box_value, VALUE fname, VALUE path)
if (wrote >= (int)sizeof(ext_path)) {
rb_bug("Extension file path in the box was too long");
}
+ VALUE new_path = rb_str_new_cstr(ext_path);
+ *cleanup = TypedData_Wrap_Struct(0, &box_ext_cleanup_type, NULL);
enum copy_error_type copy_error = copy_ext_file(src_path, ext_path);
if (copy_error) {
char message[1024];
copy_ext_file_error(message, sizeof(message), copy_error);
rb_raise(rb_eLoadError, "can't prepare the extension file for Ruby Box (%s from %"PRIsVALUE"): %s", ext_path, path, message);
}
- // TODO: register the path to be clean-uped
- return rb_str_new_cstr(ext_path);
+ DATA_PTR(*cleanup) = (void *)new_path;
+ return new_path;
}
// TODO: delete it just after dln_load? or delay it?
diff --git a/internal/box.h b/internal/box.h
index c341f046d3..72263cc9dc 100644
--- a/internal/box.h
+++ b/internal/box.h
@@ -3,6 +3,16 @@
#include "ruby/ruby.h" /* for VALUE */
+#if SIZEOF_VALUE <= SIZEOF_LONG
+# define SVALUE2NUM(x) LONG2NUM((long)(x))
+# define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LONG(x)
+#elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
+# define SVALUE2NUM(x) LL2NUM((LONG_LONG)(x))
+# define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LL(x)
+#else
+# error Need integer for VALUE
+#endif
+
/**
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
@@ -75,7 +85,8 @@ void rb_box_gc_update_references(void *ptr);
rb_box_t * rb_get_box_t(VALUE ns);
VALUE rb_get_box_object(rb_box_t *ns);
-VALUE rb_box_local_extension(VALUE box, VALUE fname, VALUE path);
+VALUE rb_box_local_extension(VALUE box, VALUE fname, VALUE path, VALUE *cleanup);
+void rb_box_cleanup_local_extension(VALUE cleanup);
void rb_initialize_main_box(void);
void rb_box_init_done(void);
diff --git a/load.c b/load.c
index 5a0697a262..466517f465 100644
--- a/load.c
+++ b/load.c
@@ -27,16 +27,6 @@
#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
-#if SIZEOF_VALUE <= SIZEOF_LONG
-# define SVALUE2NUM(x) LONG2NUM((long)(x))
-# define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LONG(x)
-#elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
-# define SVALUE2NUM(x) LL2NUM((LONG_LONG)(x))
-# define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LL(x)
-#else
-# error Need integer for VALUE
-#endif
-
enum {
loadable_ext_rb = (0+ /* .rb extension is the first in both tables */
1) /* offset by rb_find_file_ext() */
@@ -1203,11 +1193,15 @@ load_ext(VALUE path, VALUE fname)
{
VALUE loaded = path;
const rb_box_t *box = rb_loading_box();
+ VALUE cleanup = 0;
if (BOX_USER_P(box)) {
- loaded = rb_box_local_extension(box->box_object, fname, path);
+ loaded = rb_box_local_extension(box->box_object, fname, path, &cleanup);
}
rb_scope_visibility_set(METHOD_VISI_PUBLIC);
void *handle = dln_load_feature(RSTRING_PTR(loaded), RSTRING_PTR(fname));
+ if (cleanup) {
+ rb_box_cleanup_local_extension(cleanup);
+ }
RB_GC_GUARD(loaded);
RB_GC_GUARD(fname);
return (VALUE)handle;
diff --git a/test/ruby/test_box.rb b/test/ruby/test_box.rb
index c52c7564ae..2e4e07a86a 100644
--- a/test/ruby/test_box.rb
+++ b/test/ruby/test_box.rb
@@ -697,10 +697,6 @@ class TestBox < Test::Unit::TestCase
assert !$LOADED_FEATURES.include?("/tmp/barbaz")
assert !Object.const_defined?(:FooClass)
end;
- ensure
- tmp = ENV["TMPDIR"] || ENV["TMP"] || Etc.systmpdir || "/tmp"
- pat = "_ruby_ns_*."+RbConfig::CONFIG["DLEXT"]
- File.unlink(*Dir.glob(pat, base: tmp).map {|so| "#{tmp}/#{so}"})
end
def test_basic_box_detections