Get rid of infinite recursion in expanding a load path to the real
path while loading a transcoder.
This commit is contained in:
Nobuyoshi Nakada 2019-12-03 08:12:57 +09:00
Родитель 8bddf1bc9b
Коммит 14a17063a1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4BC7D6DF58D8DF60
4 изменённых файлов: 31 добавлений и 19 удалений

33
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);
}
/*

Просмотреть файл

@ -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);

2
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));
}

Просмотреть файл

@ -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