diff options
| author | Satoshi Tagomori <s-tagomori@sakura.ad.jp> | 2025-06-29 09:44:31 +0900 |
|---|---|---|
| committer | Satoshi Tagomori <tagomoris@gmail.com> | 2025-09-29 01:15:38 +0900 |
| commit | bb21b619f01926fa99f6cca5ec8ac89389207d10 (patch) | |
| tree | 0a1e916b314cf695043d5b8ff7768cd254435c41 | |
| parent | 48523daef68a9ad2361bb2ee281c90e940330ed2 (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.c | 30 |
1 files changed, 22 insertions, 8 deletions
@@ -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); } |
