[前][次][番号順一覧][スレッド一覧]

ruby-changes:59047

From: Nobuyoshi <ko1@a...>
Date: Tue, 3 Dec 2019 10:16:54 +0900 (JST)
Subject: [ruby-changes:59047] 14a17063a1 (master): Fixed stack overflow [Bug #16382]

https://git.ruby-lang.org/ruby.git/commit/?id=14a17063a1

From 14a17063a11a01d518b4bbaf0eb967330aec3984 Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@r...>
Date: Tue, 3 Dec 2019 08:12:57 +0900
Subject: Fixed stack overflow [Bug #16382]

Get rid of infinite recursion in expanding a load path to the real
path while loading a transcoder.

diff --git a/file.c b/file.c
index 05cdf51..5644656 100644
--- a/file.c
+++ b/file.c
@@ -242,7 +242,7 @@ rb_str_encode_ospath(VALUE path) https://github.com/ruby/ruby/blob/trunk/file.c#L242
 	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 https://github.com/ruby/ruby/blob/trunk/file.c#L4243
 }
 
 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) https://github.com/ruby/ruby/blob/trunk/file.c#L4251
     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) https://github.com/ruby/ruby/blob/trunk/file.c#L4264
     }
 
     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) https://github.com/ruby/ruby/blob/trunk/file.c#L4321
     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) https://github.com/ruby/ruby/blob/trunk/file.c#L4338
 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 https://github.com/ruby/ruby/blob/trunk/file.c#L4364
            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 https://github.com/ruby/ruby/blob/trunk/file.c#L4375
     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 https://github.com/ruby/ruby/blob/trunk/file.c#L4401
     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) https://github.com/ruby/ruby/blob/trunk/file.c#L4410
 {
     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 ca635c9..77101d0 100644
--- a/internal.h
+++ b/internal.h
@@ -1583,7 +1583,9 @@ extern const char ruby_null_device[]; https://github.com/ruby/ruby/blob/trunk/internal.h#L1583
 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 7772e74..fda100f 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 https://github.com/ruby/ruby/blob/trunk/load.c#L79
 	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 40fd302..019cb24 100644
--- a/test/ruby/test_encoding.rb
+++ b/test/ruby/test_encoding.rb
@@ -123,4 +123,15 @@ class TestEncoding < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_encoding.rb#L123
       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
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]