From 391832de43d1f780e4ee31ab977292fad48a9b17 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Fri, 10 Mar 2017 15:31:16 -0800 Subject: [PATCH] Strip chroot path from $LOADED_FEATURES when calling Dir.chroot 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: 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. --- dir.c | 27 +++++++++++++++++++++++++++ load.c | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/dir.c b/dir.c index 365f059b0f..8e6cdc0a0e 100644 --- a/dir.c +++ b/dir.c @@ -1119,10 +1119,37 @@ 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; + 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) { + feature = rb_str_substr(feature, chroot_len, + RSTRING_LEN(feature)); + RARRAY_ASET(features, i, feature); + features_index_add(feature, INT2FIX(i)); + } + } + } + return INT2FIX(0); } #else diff --git a/load.c b/load.c index 284ebf2e48..701f039d3e 100644 --- a/load.c +++ b/load.c @@ -220,7 +220,7 @@ features_index_add_single(VALUE short_feature, VALUE offset) or ends in '/'. This maintains the invariant that `rb_feature_p()` relies on for its fast lookup. */ -static void +void features_index_add(VALUE feature, VALUE offset) { VALUE short_feature; -- 2.11.0