summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2019-12-03 08:12:57 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2019-12-03 08:51:50 +0900
commit14a17063a11a01d518b4bbaf0eb967330aec3984 (patch)
tree5cc6a25e09b593f2bc5a66bef09b35f823075ebd
parent8bddf1bc9bdd1db7ce2e3fec15f2f06ff355b0a7 (diff)
Fixed stack overflow [Bug #16382]
Get rid of infinite recursion in expanding a load path to the real path while loading a transcoder.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2714
-rw-r--r--file.c33
-rw-r--r--internal.h4
-rw-r--r--load.c2
-rw-r--r--test/ruby/test_encoding.rb11
4 files changed, 31 insertions, 19 deletions
diff --git a/file.c b/file.c
index 05cdf51e77..5644656b44 100644
--- a/file.c
+++ b/file.c
@@ -242,7 +242,7 @@ rb_str_encode_ospath(VALUE path)
encidx = rb_filesystem_encindex();
}
#endif
- if (encidx != ENCINDEX_UTF_8) {
+ if (encidx != ENCINDEX_ASCII && encidx != ENCINDEX_UTF_8) {
rb_encoding *enc = rb_enc_from_index(encidx);
rb_encoding *utf8 = rb_utf8_encoding();
path = rb_str_conv_enc(path, enc, utf8);
@@ -4243,7 +4243,7 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE f
}
static VALUE
-rb_check_realpath_emulate(VALUE basedir, VALUE path, enum rb_realpath_mode mode)
+rb_check_realpath_emulate(VALUE basedir, VALUE path, rb_encoding *origenc, enum rb_realpath_mode mode)
{
long prefixlen;
VALUE resolved;
@@ -4251,7 +4251,7 @@ rb_check_realpath_emulate(VALUE basedir, VALUE path, enum rb_realpath_mode mode)
VALUE loopcheck;
VALUE curdir = Qnil;
- rb_encoding *enc, *origenc;
+ rb_encoding *enc;
char *path_names = NULL, *basedir_names = NULL, *curdir_names = NULL;
char *ptr, *prefixptr = NULL, *pend;
long len;
@@ -4264,7 +4264,6 @@ rb_check_realpath_emulate(VALUE basedir, VALUE path, enum rb_realpath_mode mode)
}
enc = rb_enc_get(unresolved_path);
- origenc = enc;
unresolved_path = TO_OSPATH(unresolved_path);
RSTRING_GETMEM(unresolved_path, ptr, len);
path_names = skipprefixroot(ptr, ptr + len, rb_enc_get(unresolved_path));
@@ -4322,7 +4321,7 @@ rb_check_realpath_emulate(VALUE basedir, VALUE path, enum rb_realpath_mode mode)
if (realpath_rec(&prefixlen, &resolved, path_names, Qnil, loopcheck, mode, 1))
return Qnil;
- if (origenc != rb_enc_get(resolved)) {
+ if (origenc && origenc != rb_enc_get(resolved)) {
if (rb_enc_str_asciionly_p(resolved)) {
rb_enc_associate(resolved, origenc);
}
@@ -4339,25 +4338,23 @@ rb_check_realpath_emulate(VALUE basedir, VALUE path, enum rb_realpath_mode mode)
static VALUE rb_file_join(VALUE ary);
static VALUE
-rb_check_realpath_internal(VALUE basedir, VALUE path, enum rb_realpath_mode mode)
+rb_check_realpath_internal(VALUE basedir, VALUE path, rb_encoding *origenc, enum rb_realpath_mode mode)
{
#ifdef HAVE_REALPATH
VALUE unresolved_path;
- rb_encoding *origenc;
char *resolved_ptr = NULL;
VALUE resolved;
struct stat st;
if (mode == RB_REALPATH_DIR) {
- return rb_check_realpath_emulate(basedir, path, mode);
+ return rb_check_realpath_emulate(basedir, path, origenc, mode);
}
unresolved_path = rb_str_dup_frozen(path);
- origenc = rb_enc_get(unresolved_path);
if (*RSTRING_PTR(unresolved_path) != '/' && !NIL_P(basedir)) {
unresolved_path = rb_file_join(rb_assoc_new(basedir, unresolved_path));
}
- unresolved_path = TO_OSPATH(unresolved_path);
+ if (origenc) unresolved_path = TO_OSPATH(unresolved_path);
if ((resolved_ptr = realpath(RSTRING_PTR(unresolved_path), NULL)) == NULL) {
/* glibc realpath(3) does not allow /path/to/file.rb/../other_file.rb,
@@ -4367,7 +4364,7 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, enum rb_realpath_mode mode
Fallback to the emulated approach in either of those cases. */
if (errno == ENOTDIR ||
(errno == ENOENT && rb_file_exist_p(0, unresolved_path))) {
- return rb_check_realpath_emulate(basedir, path, mode);
+ return rb_check_realpath_emulate(basedir, path, origenc, mode);
}
if (mode == RB_REALPATH_CHECK) {
@@ -4378,14 +4375,16 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, enum rb_realpath_mode mode
resolved = ospath_new(resolved_ptr, strlen(resolved_ptr), rb_filesystem_encoding());
free(resolved_ptr);
- if (rb_stat(resolved, &st) < 0) {
+ /* As `resolved` is a String in the filesystem encoding, no
+ * conversion is needed */
+ if (stat_without_gvl(RSTRING_PTR(resolved), &st) < 0) {
if (mode == RB_REALPATH_CHECK) {
return Qnil;
}
rb_sys_fail_path(unresolved_path);
}
- if (origenc != rb_enc_get(resolved)) {
+ if (origenc && origenc != rb_enc_get(resolved)) {
if (!rb_enc_str_asciionly_p(resolved)) {
resolved = rb_str_conv_enc(resolved, NULL, origenc);
}
@@ -4402,7 +4401,7 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, enum rb_realpath_mode mode
RB_GC_GUARD(unresolved_path);
return resolved;
#else
- return rb_check_realpath_emulate(basedir, path, mode);
+ return rb_check_realpath_emulate(basedir, path, origenc, mode);
#endif /* HAVE_REALPATH */
}
@@ -4411,13 +4410,13 @@ rb_realpath_internal(VALUE basedir, VALUE path, int strict)
{
const enum rb_realpath_mode mode =
strict ? RB_REALPATH_STRICT : RB_REALPATH_DIR;
- return rb_check_realpath_internal(basedir, path, mode);
+ return rb_check_realpath_internal(basedir, path, rb_enc_get(path), mode);
}
VALUE
-rb_check_realpath(VALUE basedir, VALUE path)
+rb_check_realpath(VALUE basedir, VALUE path, rb_encoding *enc)
{
- return rb_check_realpath_internal(basedir, path, RB_REALPATH_CHECK);
+ return rb_check_realpath_internal(basedir, path, enc, RB_REALPATH_CHECK);
}
/*
diff --git a/internal.h b/internal.h
index ca635c9e36..77101d0195 100644
--- a/internal.h
+++ b/internal.h
@@ -1583,7 +1583,9 @@ extern const char ruby_null_device[];
VALUE rb_home_dir_of(VALUE user, VALUE result);
VALUE rb_default_home_dir(VALUE result);
VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict);
-VALUE rb_check_realpath(VALUE basedir, VALUE path);
+#ifdef RUBY_ENCODING_H
+VALUE rb_check_realpath(VALUE basedir, VALUE path, rb_encoding *origenc);
+#endif
void rb_file_const(const char*, VALUE);
int rb_file_load_ok(const char *);
VALUE rb_file_expand_path_fast(VALUE, VALUE);
diff --git a/load.c b/load.c
index 7772e746f9..fda100fb1a 100644
--- a/load.c
+++ b/load.c
@@ -79,7 +79,7 @@ rb_construct_expanded_load_path(enum expand_type type, int *has_relative, int *h
if (is_string)
rb_str_freeze(path);
as_str = rb_get_path_check_convert(as_str);
- expanded_path = rb_check_realpath(Qnil, as_str);
+ expanded_path = rb_check_realpath(Qnil, as_str, NULL);
if (NIL_P(expanded_path)) expanded_path = as_str;
rb_ary_push(ary, rb_fstring(expanded_path));
}
diff --git a/test/ruby/test_encoding.rb b/test/ruby/test_encoding.rb
index 40fd302c07..019cb2417f 100644
--- a/test/ruby/test_encoding.rb
+++ b/test/ruby/test_encoding.rb
@@ -123,4 +123,15 @@ class TestEncoding < Test::Unit::TestCase
assert_include(e.message, "/regexp/sQ\n")
end;
end
+
+ def test_nonascii_library_path
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}".force_encoding("US-ASCII"))
+ begin;
+ assert_equal(Encoding::US_ASCII, __ENCODING__)
+ $:.unshift("/\x80")
+ assert_raise_with_message(LoadError, /\[Bug #16382\]/) do
+ $:.resolve_feature_path "[Bug #16382]"
+ end
+ end;
+ end
end