From 32f58628e900894b48b9e8630c250dedbbb1c126 Mon Sep 17 00:00:00 2001 From: Satoshi Tagomori Date: Sun, 10 Aug 2025 18:45:44 +0900 Subject: Update Namespace#eval to use control frames instead of namespace_push/pop With this change, the argument code of Namespace#eval cannot refer local variables around the calling line, but it should not be able to refer these values. The code is evaluated in the receiver namespace, independently from the local context. --- iseq.c | 15 +++++++++++++++ iseq.h | 1 + namespace.c | 18 +++++++++--------- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/iseq.c b/iseq.c index ad9149ef98..ae30d60ced 100644 --- a/iseq.c +++ b/iseq.c @@ -1161,6 +1161,21 @@ rb_iseq_load_iseq(VALUE fname) return NULL; } +const rb_iseq_t * +rb_iseq_compile_iseq(VALUE str, VALUE fname) +{ + VALUE args[] = { + str, fname + }; + VALUE iseqv = rb_check_funcall(rb_cISeq, rb_intern("compile"), 2, args); + + if (!SPECIAL_CONST_P(iseqv) && RBASIC_CLASS(iseqv) == rb_cISeq) { + return iseqw_check(iseqv); + } + + return NULL; +} + #define CHECK_ARRAY(v) rb_to_array_type(v) #define CHECK_HASH(v) rb_to_hash_type(v) #define CHECK_STRING(v) rb_str_to_str(v) diff --git a/iseq.h b/iseq.h index c7f091a0b4..a8ad8ef9b0 100644 --- a/iseq.h +++ b/iseq.h @@ -192,6 +192,7 @@ void rb_iseq_init_trace(rb_iseq_t *iseq); int rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line, bool target_bmethod); int rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval); const rb_iseq_t *rb_iseq_load_iseq(VALUE fname); +const rb_iseq_t *rb_iseq_compile_iseq(VALUE str, VALUE fname); int rb_iseq_opt_frozen_string_literal(void); #if VM_INSN_INFO_TABLE_IMPL == 2 diff --git a/namespace.c b/namespace.c index 82bacd4108..3b7185e9aa 100644 --- a/namespace.c +++ b/namespace.c @@ -12,6 +12,7 @@ #include "internal/namespace.h" #include "internal/st.h" #include "internal/variable.h" +#include "iseq.h" #include "ruby/internal/globals.h" #include "ruby/util.h" #include "vm_core.h" @@ -842,21 +843,20 @@ initialize_root_namespace(void) } } -static VALUE -rb_namespace_eval_string(VALUE str) -{ - return rb_eval_string(RSTRING_PTR(str)); -} - static VALUE rb_namespace_eval(VALUE namespace, VALUE str) { - rb_thread_t *th = GET_THREAD(); + const rb_iseq_t *iseq; + const rb_namespace_t *ns; StringValue(str); - namespace_push(th, namespace); - return rb_ensure(rb_namespace_eval_string, str, namespace_pop, (VALUE)th); + iseq = rb_iseq_compile_iseq(str, rb_str_new_cstr("eval")); + VM_ASSERT(iseq); + + ns = (const rb_namespace_t *)rb_get_namespace_t(namespace); + + return rb_iseq_eval(iseq, ns); } static int namespace_experimental_warned = 0; -- cgit v1.2.3