Fixed stack overflow [Bug #16382]
Get rid of infinite recursion in expanding a load path to the real path while loading a transcoder.
This commit is contained in:
parent
8bddf1bc9b
commit
14a17063a1
Notes:
git
2019-12-03 10:16:57 +09:00
33
file.c
33
file.c
@ -242,7 +242,7 @@ rb_str_encode_ospath(VALUE path)
|
|||||||
encidx = rb_filesystem_encindex();
|
encidx = rb_filesystem_encindex();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (encidx != ENCINDEX_UTF_8) {
|
if (encidx != ENCINDEX_ASCII && encidx != ENCINDEX_UTF_8) {
|
||||||
rb_encoding *enc = rb_enc_from_index(encidx);
|
rb_encoding *enc = rb_enc_from_index(encidx);
|
||||||
rb_encoding *utf8 = rb_utf8_encoding();
|
rb_encoding *utf8 = rb_utf8_encoding();
|
||||||
path = rb_str_conv_enc(path, enc, utf8);
|
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
|
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;
|
long prefixlen;
|
||||||
VALUE resolved;
|
VALUE resolved;
|
||||||
@ -4251,7 +4251,7 @@ rb_check_realpath_emulate(VALUE basedir, VALUE path, enum rb_realpath_mode mode)
|
|||||||
VALUE loopcheck;
|
VALUE loopcheck;
|
||||||
VALUE curdir = Qnil;
|
VALUE curdir = Qnil;
|
||||||
|
|
||||||
rb_encoding *enc, *origenc;
|
rb_encoding *enc;
|
||||||
char *path_names = NULL, *basedir_names = NULL, *curdir_names = NULL;
|
char *path_names = NULL, *basedir_names = NULL, *curdir_names = NULL;
|
||||||
char *ptr, *prefixptr = NULL, *pend;
|
char *ptr, *prefixptr = NULL, *pend;
|
||||||
long len;
|
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);
|
enc = rb_enc_get(unresolved_path);
|
||||||
origenc = enc;
|
|
||||||
unresolved_path = TO_OSPATH(unresolved_path);
|
unresolved_path = TO_OSPATH(unresolved_path);
|
||||||
RSTRING_GETMEM(unresolved_path, ptr, len);
|
RSTRING_GETMEM(unresolved_path, ptr, len);
|
||||||
path_names = skipprefixroot(ptr, ptr + len, rb_enc_get(unresolved_path));
|
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))
|
if (realpath_rec(&prefixlen, &resolved, path_names, Qnil, loopcheck, mode, 1))
|
||||||
return Qnil;
|
return Qnil;
|
||||||
|
|
||||||
if (origenc != rb_enc_get(resolved)) {
|
if (origenc && origenc != rb_enc_get(resolved)) {
|
||||||
if (rb_enc_str_asciionly_p(resolved)) {
|
if (rb_enc_str_asciionly_p(resolved)) {
|
||||||
rb_enc_associate(resolved, origenc);
|
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_file_join(VALUE ary);
|
||||||
|
|
||||||
static VALUE
|
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
|
#ifdef HAVE_REALPATH
|
||||||
VALUE unresolved_path;
|
VALUE unresolved_path;
|
||||||
rb_encoding *origenc;
|
|
||||||
char *resolved_ptr = NULL;
|
char *resolved_ptr = NULL;
|
||||||
VALUE resolved;
|
VALUE resolved;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (mode == RB_REALPATH_DIR) {
|
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);
|
unresolved_path = rb_str_dup_frozen(path);
|
||||||
origenc = rb_enc_get(unresolved_path);
|
|
||||||
if (*RSTRING_PTR(unresolved_path) != '/' && !NIL_P(basedir)) {
|
if (*RSTRING_PTR(unresolved_path) != '/' && !NIL_P(basedir)) {
|
||||||
unresolved_path = rb_file_join(rb_assoc_new(basedir, unresolved_path));
|
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) {
|
if ((resolved_ptr = realpath(RSTRING_PTR(unresolved_path), NULL)) == NULL) {
|
||||||
/* glibc realpath(3) does not allow /path/to/file.rb/../other_file.rb,
|
/* 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. */
|
Fallback to the emulated approach in either of those cases. */
|
||||||
if (errno == ENOTDIR ||
|
if (errno == ENOTDIR ||
|
||||||
(errno == ENOENT && rb_file_exist_p(0, unresolved_path))) {
|
(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) {
|
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());
|
resolved = ospath_new(resolved_ptr, strlen(resolved_ptr), rb_filesystem_encoding());
|
||||||
free(resolved_ptr);
|
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) {
|
if (mode == RB_REALPATH_CHECK) {
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
rb_sys_fail_path(unresolved_path);
|
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)) {
|
if (!rb_enc_str_asciionly_p(resolved)) {
|
||||||
resolved = rb_str_conv_enc(resolved, NULL, origenc);
|
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);
|
RB_GC_GUARD(unresolved_path);
|
||||||
return resolved;
|
return resolved;
|
||||||
#else
|
#else
|
||||||
return rb_check_realpath_emulate(basedir, path, mode);
|
return rb_check_realpath_emulate(basedir, path, origenc, mode);
|
||||||
#endif /* HAVE_REALPATH */
|
#endif /* HAVE_REALPATH */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4411,13 +4410,13 @@ rb_realpath_internal(VALUE basedir, VALUE path, int strict)
|
|||||||
{
|
{
|
||||||
const enum rb_realpath_mode mode =
|
const enum rb_realpath_mode mode =
|
||||||
strict ? RB_REALPATH_STRICT : RB_REALPATH_DIR;
|
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
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1583,7 +1583,9 @@ extern const char ruby_null_device[];
|
|||||||
VALUE rb_home_dir_of(VALUE user, VALUE result);
|
VALUE rb_home_dir_of(VALUE user, VALUE result);
|
||||||
VALUE rb_default_home_dir(VALUE result);
|
VALUE rb_default_home_dir(VALUE result);
|
||||||
VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict);
|
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);
|
void rb_file_const(const char*, VALUE);
|
||||||
int rb_file_load_ok(const char *);
|
int rb_file_load_ok(const char *);
|
||||||
VALUE rb_file_expand_path_fast(VALUE, VALUE);
|
VALUE rb_file_expand_path_fast(VALUE, VALUE);
|
||||||
|
2
load.c
2
load.c
@ -79,7 +79,7 @@ rb_construct_expanded_load_path(enum expand_type type, int *has_relative, int *h
|
|||||||
if (is_string)
|
if (is_string)
|
||||||
rb_str_freeze(path);
|
rb_str_freeze(path);
|
||||||
as_str = rb_get_path_check_convert(as_str);
|
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;
|
if (NIL_P(expanded_path)) expanded_path = as_str;
|
||||||
rb_ary_push(ary, rb_fstring(expanded_path));
|
rb_ary_push(ary, rb_fstring(expanded_path));
|
||||||
}
|
}
|
||||||
|
@ -123,4 +123,15 @@ class TestEncoding < Test::Unit::TestCase
|
|||||||
assert_include(e.message, "/regexp/sQ\n")
|
assert_include(e.message, "/regexp/sQ\n")
|
||||||
end;
|
end;
|
||||||
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
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user