1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Fix Module#const_source_location for autoload constants with direct requires

If an autoload exists for a constant, but the path for the autoload
was required, const_source_location would return [false, 0] instead
of the actual file and line. This fixes it by setting the appropriate
file and line in rb_const_set, and saving the file and line in
const_tbl_update before they get reset by current_autoload_data.

Fixes [Bug #18624]
This commit is contained in:
Jeremy Evans 2022-03-11 21:43:47 -08:00
parent 653e517eef
commit c85d1cda86
Notes: git 2022-06-07 03:13:14 +09:00
2 changed files with 22 additions and 2 deletions

View file

@ -443,6 +443,23 @@ p Foo::Bar
end
end
def test_source_location_after_require
bug = "Bug18624"
Dir.mktmpdir('autoload') do |tmpdir|
path = "#{tmpdir}/test-#{bug}.rb"
File.write(path, "C::#{bug} = __FILE__\n")
assert_separately(%W[-I #{tmpdir}], "#{<<-"begin;"}\n#{<<-"end;"}")
begin;
class C; end
C.autoload(:Bug18624, #{path.dump})
require #{path.dump}
assert_equal [#{path.dump}, 1], C.const_source_location(#{bug.dump})
assert_equal #{path.dump}, C.const_get(#{bug.dump})
assert_equal [#{path.dump}, 1], C.const_source_location(#{bug.dump})
end;
end
end
def test_no_memory_leak
assert_no_memory_leak([], '', "#{<<~"begin;"}\n#{<<~'end;'}", 'many autoloads', timeout: 60)
begin;

View file

@ -3264,6 +3264,7 @@ const_set(VALUE klass, ID id, VALUE val)
.value = val, .flag = CONST_PUBLIC,
/* fill the rest with 0 */
};
ac.file = rb_source_location(&ac.line);
const_tbl_update(&ac, false);
}
}
@ -3337,6 +3338,8 @@ const_tbl_update(struct autoload_const *ac, int autoload_force)
ce = (rb_const_entry_t *)value;
if (ce->value == Qundef) {
RUBY_ASSERT_CRITICAL_SECTION_ENTER();
VALUE file = ac->file;
int line = ac->line;
struct autoload_data *ele = autoload_data_for_named_constant(klass, id, &ac);
if (!autoload_force && ele) {
@ -3350,8 +3353,8 @@ const_tbl_update(struct autoload_const *ac, int autoload_force)
autoload_delete(klass, id);
ce->flag = visibility;
RB_OBJ_WRITE(klass, &ce->value, val);
RB_OBJ_WRITE(klass, &ce->file, ac->file);
ce->line = ac->line;
RB_OBJ_WRITE(klass, &ce->file, file);
ce->line = line;
}
RUBY_ASSERT_CRITICAL_SECTION_LEAVE();
return;