diff options
| author | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2025-11-08 11:05:17 +0900 |
|---|---|---|
| committer | Nobuyoshi Nakada <nobu.nakada@gmail.com> | 2025-12-09 23:41:50 +0900 |
| commit | 573896a40ac25bd9febb2bbc0502b43ef36f9b9b (patch) | |
| tree | bc893ac96eedf12685e42fe63fe35ad734d01c0b | |
| parent | e8568bbcf20fafcb82d8b537b99762528dfbdc3e (diff) | |
Box: remove copied extension files
| -rw-r--r-- | box.c | 60 | ||||
| -rw-r--r-- | internal/box.h | 13 | ||||
| -rw-r--r-- | load.c | 16 | ||||
| -rw-r--r-- | test/ruby/test_box.rb | 4 |
4 files changed, 74 insertions, 19 deletions
@@ -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); @@ -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 |
