Issue #13300 has been updated by Nobuyoshi Nakada.


Should not use `features_index_add`.
By replacing `$LOADED_FEATURES`, the internal snapshot will be invalidated.
And doesn't `$LOAD_PATH` need to be stripped?

```diff
diff --git a/dir.c b/dir.c
index 365f059b0f..3b55e4f4a0 100644
--- a/dir.c
+++ b/dir.c
@@ -1119,10 +1119,42 @@ check_dirname(VALUE dir)
 static VALUE
 dir_s_chroot(VALUE dir, VALUE path)
 {
+    VALUE features = rb_gv_get("$LOADED_FEATURES");
+    VALUE chroot_to;
+
     path = check_dirname(path);
+    chroot_to = rb_file_s_expand_path(1, &path);
     if (chroot(RSTRING_PTR(path)) == -1)
 	rb_sys_fail_path(path);
 
+    if (rb_type(features) == RUBY_T_ARRAY &&
+        rb_type(chroot_to) == RUBY_T_STRING) {
+	long i, features_len, chroot_len, feature_min_len;
+	VALUE feature, old_features = 0;
+	char * chroot_str = RSTRING_PTR(chroot_to);
+
+	features_len = RARRAY_LEN(features);
+	chroot_len = RSTRING_LEN(chroot_to);
+	feature_min_len = chroot_len + 1;
+
+	for (i=0; i < features_len; i++) {
+	    feature = RARRAY_AREF(features, i);
+	    if ((rb_type(feature) == RUBY_T_STRING) &&
+		RSTRING_LEN(feature) > feature_min_len &&
+	        strncmp(chroot_str, RSTRING_PTR(feature), chroot_len) == 0) {
+		if (!old_features) {
+		    features = rb_ary_dup(old_features = features);
+		}
+		feature = rb_str_substr(feature, chroot_len,
+		                        RSTRING_LEN(feature));
+		RARRAY_ASET(features, i, feature);
+	    }
+	}
+	if (old_features) {
+	    rb_ary_replace(old_features, features);
+	}
+    }
+
     return INT2FIX(0);
 }
 #else
```

----------------------------------------
Feature #13300: Strip chroot path from $LOADED_FEATURES when calling Dir.chroot
https://bugs.ruby-lang.org/issues/13300#change-63424

* Author: Jeremy Evans
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
Currently, `Dir.chroot` doesn't modify `$LOADED_FEATURES`, leading
to a situation where `Kernel#require` will attempt to load the same
file twice, or a different file not at all because it thinks it
is already loaded.

With this example code:

~~~ ruby
require 'fileutils'
File.write('baz.rb', 'A = 1')
require './baz'
pwd = Dir.pwd
Dir.chroot(pwd)
require './baz'
FileUtils.mkdir_p(pwd)
File.write(File.join(pwd, 'baz.rb'), '$a = 2')
require "#{pwd}/baz"
warn "$a => #{$a.inspect}" unless $a == 2
~~~

Previous output on stderr:

~~~
/baz.rb:1: warning: already initialized constant A
/home/billg/baz.rb:1: warning: previous definition of A was here
$a => nil
~~~

With this patch, no output on stderr.

---Files--------------------------------
0001-Strip-chroot-path-from-LOADED_FEATURES-when-calling-.patch (2.6 KB)


-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>