merge revision(s) 4329554f17: [Backport #19985]

[Bug #19985] Raise LoadError with the converted feature name

	`Kernel#require` converts feature name objects that have the `to_path`
	method such as `Pathname`, but had used the original object on error
	and had resulted in an unexpected `TypeError`.
	---
	 load.c                    | 14 +++++++++++---
	 test/ruby/test_require.rb | 26 +++++++++++++++++++++-----
	 2 files changed, 32 insertions(+), 8 deletions(-)
This commit is contained in:
U.Nakamura 2023-11-06 20:22:27 +09:00
parent 4f7b595815
commit 881088e06f
3 changed files with 33 additions and 9 deletions

14
load.c
View file

@ -869,6 +869,7 @@ load_unlock(rb_vm_t *vm, const char *ftptr, int done)
} }
} }
static VALUE rb_require_string_internal(VALUE fname);
/* /*
* call-seq: * call-seq:
@ -930,7 +931,7 @@ rb_f_require_relative(VALUE obj, VALUE fname)
rb_loaderror("cannot infer basepath"); rb_loaderror("cannot infer basepath");
} }
base = rb_file_dirname(base); base = rb_file_dirname(base);
return rb_require_string(rb_file_absolute_path(fname, base)); return rb_require_string_internal(rb_file_absolute_path(fname, base));
} }
typedef int (*feature_func)(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn); typedef int (*feature_func)(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn);
@ -1140,7 +1141,6 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
volatile bool reset_ext_config = false; volatile bool reset_ext_config = false;
struct rb_ext_config prev_ext_config; struct rb_ext_config prev_ext_config;
fname = rb_get_path(fname);
path = rb_str_encode_ospath(fname); path = rb_str_encode_ospath(fname);
RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname)); RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
saved_path = path; saved_path = path;
@ -1267,6 +1267,12 @@ ruby_require_internal(const char *fname, unsigned int len)
VALUE VALUE
rb_require_string(VALUE fname) rb_require_string(VALUE fname)
{
return rb_require_string_internal(FilePathValue(fname));
}
static VALUE
rb_require_string_internal(VALUE fname)
{ {
rb_execution_context_t *ec = GET_EC(); rb_execution_context_t *ec = GET_EC();
int result = require_internal(ec, fname, 1, RTEST(ruby_verbose)); int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
@ -1284,7 +1290,9 @@ rb_require_string(VALUE fname)
VALUE VALUE
rb_require(const char *fname) rb_require(const char *fname)
{ {
return rb_require_string(rb_str_new_cstr(fname)); struct RString fake;
VALUE str = rb_setup_fake_str(&fake, fname, strlen(fname), 0);
return rb_require_string_internal(str);
} }
#if EXTSTATIC #if EXTSTATIC

View file

@ -6,11 +6,27 @@ require 'tmpdir'
class TestRequire < Test::Unit::TestCase class TestRequire < Test::Unit::TestCase
def test_load_error_path def test_load_error_path
filename = "should_not_exist" Tempfile.create(["should_not_exist", ".rb"]) {|t|
error = assert_raise(LoadError) do filename = t.path
require filename t.close
end File.unlink(filename)
assert_equal filename, error.path
error = assert_raise(LoadError) do
require filename
end
assert_equal filename, error.path
# with --disable=gems
assert_separately(["-", filename], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
filename = ARGV[0]
path = Struct.new(:to_path).new(filename)
error = assert_raise(LoadError) do
require path
end
assert_equal filename, error.path
end;
}
end end
def test_require_invalid_shared_object def test_require_invalid_shared_object

View file

@ -11,7 +11,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 4 #define RUBY_VERSION_TEENY 4
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
#define RUBY_PATCHLEVEL 246 #define RUBY_PATCHLEVEL 247
#define RUBY_RELEASE_YEAR 2023 #define RUBY_RELEASE_YEAR 2023
#define RUBY_RELEASE_MONTH 11 #define RUBY_RELEASE_MONTH 11