summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSatoshi Tagomori <s-tagomori@sakura.ad.jp>2025-06-29 09:44:31 +0900
committerSatoshi Tagomori <tagomoris@gmail.com>2025-09-29 01:15:38 +0900
commitbb21b619f01926fa99f6cca5ec8ac89389207d10 (patch)
tree0a1e916b314cf695043d5b8ff7768cd254435c41
parent48523daef68a9ad2361bb2ee281c90e940330ed2 (diff)
Detect the correct loading namespace from control frames
* checking all control frames (instead of filtering by VM_FRAME_RUBYFRAME_P) because VM_FRAME_FLAG_NS_REQUIRE is set on non-rubyframe * skip frames of CFUNC in the root namespace for Kernel#require (etc) to avoid detecting the root namespace of those frames wrongly
-rw-r--r--vm.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/vm.c b/vm.c
index 76f356342b..790a5af4f0 100644
--- a/vm.c
+++ b/vm.c
@@ -3065,10 +3065,24 @@ rb_vm_caller_namespace(const rb_execution_context_t *ec)
// The current control frame is MAGIC_CFUNC to call Namespace.current, but
// we want to get the current namespace of its caller.
- caller_cfp = vm_get_ruby_level_caller_cfp(ec, RUBY_VM_PREVIOUS_CONTROL_FRAME(ec->cfp));
+ caller_cfp = vm_get_ruby_level_caller_cfp(ec, ec->cfp);
return current_namespace_on_env(caller_cfp->ep);
}
+static const rb_control_frame_t *
+find_loader_control_frame(const rb_control_frame_t *cfp, const rb_control_frame_t *end_cfp)
+{
+ while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
+ if (!VM_ENV_FRAME_TYPE_P(cfp->ep, VM_FRAME_MAGIC_CFUNC))
+ break;
+ if (!NAMESPACE_ROOT_P(current_namespace_on_env(cfp->ep)))
+ break;
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+ }
+ VM_ASSERT(RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp));
+ return cfp;
+}
+
const rb_namespace_t *
rb_vm_loading_namespace(const rb_execution_context_t *ec)
{
@@ -3082,14 +3096,14 @@ rb_vm_loading_namespace(const rb_execution_context_t *ec)
end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
- if (VM_FRAME_RUBYFRAME_P(cfp)) {
- if (VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_NS_REQUIRE)) {
- if (RTEST(cfp->self) && NAMESPACE_OBJ_P(cfp->self)) {
- // Namespace#require (, require_relative, load)
- return rb_get_namespace_t(cfp->self);
- }
- return current_namespace_on_env(cfp->ep);
+ if (VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_NS_REQUIRE)) {
+ if (RTEST(cfp->self) && NAMESPACE_OBJ_P(cfp->self)) {
+ // Namespace#require, #require_relative, #load
+ return rb_get_namespace_t(cfp->self);
}
+ // Kernel#require, #require_relative, #load
+ cfp = find_loader_control_frame(cfp, end_cfp);
+ return current_namespace_on_env(cfp->ep);
}
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
}