diff --git a/load.c b/load.c index 4ccd2ed20f..4dc87ceaee 100644 --- a/load.c +++ b/load.c @@ -395,7 +395,11 @@ get_loaded_features_index(rb_vm_t *vm) VALUE previous_realpath_map = rb_hash_dup(realpath_map); rb_hash_clear(realpaths); rb_hash_clear(realpath_map); - features = vm->loaded_features; + + /* We have to make a copy of features here because the StringValue call + * below could call a Ruby method, which could modify $LOADED_FEATURES + * and cause it to be corrupt. */ + features = rb_ary_resurrect(vm->loaded_features); for (i = 0; i < RARRAY_LEN(features); i++) { VALUE entry, as_str; as_str = entry = rb_ary_entry(features, i); @@ -405,6 +409,10 @@ get_loaded_features_index(rb_vm_t *vm) rb_ary_store(features, i, as_str); features_index_add(vm, as_str, INT2FIX(i)); } + /* The user modified $LOADED_FEATURES, so we should restore the changes. */ + if (!rb_ary_shared_with_p(features, CURRENT_NS_LOADED_FEATURES(vm_ns))) { + rb_ary_replace(CURRENT_NS_LOADED_FEATURES(vm_ns), features); + } reset_loaded_features_snapshot(vm); features = rb_ary_dup(vm->loaded_features_snapshot); diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb index 5aadf779fb..f8578b4a90 100644 --- a/test/ruby/test_require.rb +++ b/test/ruby/test_require.rb @@ -840,6 +840,30 @@ class TestRequire < Test::Unit::TestCase p :ok end; } + + # [Bug #21567] + assert_separately(%w[-rtempfile], "#{<<~"begin;"}\n#{<<~"end;"}") + begin; + class MyString + def initialize(path) + @path = path + end + + def to_str + $LOADED_FEATURES.clear + @path + end + + def to_path = @path + end + + def create_ruby_file = Tempfile.create(["test", ".rb"]).path + + require MyString.new(create_ruby_file) + $LOADED_FEATURES.unshift(create_ruby_file) + $LOADED_FEATURES << MyString.new(create_ruby_file) + require create_ruby_file + end; end def test_loading_fifo_threading_raise diff --git a/version.h b/version.h index f591d1f062..631d03013b 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 5 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 52 +#define RUBY_PATCHLEVEL 53 #include "ruby/version.h" #include "ruby/internal/abi.h"