reject numbered parameters from Binding#local_variables
Also, Binding#local_variable_get and #local_variable_set rejects an access to numbered parameters. [Bug #20965] [Bug #21049]
This commit is contained in:
parent
6d75599a1a
commit
993fd96ce6
Notes:
git
2025-02-18 07:23:41 +00:00
14
proc.c
14
proc.c
@ -499,6 +499,12 @@ bind_local_variables(VALUE bindval)
|
|||||||
return rb_vm_env_local_variables(env);
|
return rb_vm_env_local_variables(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rb_numparam_id_p(ID id)
|
||||||
|
{
|
||||||
|
return (tNUMPARAM_1 << ID_SCOPE_SHIFT) <= id && id < ((tNUMPARAM_1 + 10) << ID_SCOPE_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* binding.local_variable_get(symbol) -> obj
|
* binding.local_variable_get(symbol) -> obj
|
||||||
@ -525,6 +531,10 @@ bind_local_variable_get(VALUE bindval, VALUE sym)
|
|||||||
const rb_env_t *env;
|
const rb_env_t *env;
|
||||||
|
|
||||||
if (!lid) goto undefined;
|
if (!lid) goto undefined;
|
||||||
|
if (rb_numparam_id_p(lid)) {
|
||||||
|
rb_name_err_raise("numbered parameter '%1$s' is not a local variable",
|
||||||
|
bindval, ID2SYM(lid));
|
||||||
|
}
|
||||||
|
|
||||||
GetBindingPtr(bindval, bind);
|
GetBindingPtr(bindval, bind);
|
||||||
|
|
||||||
@ -574,6 +584,10 @@ bind_local_variable_set(VALUE bindval, VALUE sym, VALUE val)
|
|||||||
const rb_env_t *env;
|
const rb_env_t *env;
|
||||||
|
|
||||||
if (!lid) lid = rb_intern_str(sym);
|
if (!lid) lid = rb_intern_str(sym);
|
||||||
|
if (rb_numparam_id_p(lid)) {
|
||||||
|
rb_name_err_raise("numbered parameter '%1$s' is not a local variable",
|
||||||
|
bindval, ID2SYM(lid));
|
||||||
|
}
|
||||||
|
|
||||||
GetBindingPtr(bindval, bind);
|
GetBindingPtr(bindval, bind);
|
||||||
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
|
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
|
||||||
|
@ -90,9 +90,18 @@ describe "Numbered parameters" do
|
|||||||
proc { _2 }.parameters.should == [[:opt, :_1], [:opt, :_2]]
|
proc { _2 }.parameters.should == [[:opt, :_1], [:opt, :_2]]
|
||||||
end
|
end
|
||||||
|
|
||||||
it "affects binding local variables" do
|
ruby_version_is "".."3.4" do
|
||||||
-> { _1; binding.local_variables }.call("a").should == [:_1]
|
it "affects binding local variables" do
|
||||||
-> { _2; binding.local_variables }.call("a", "b").should == [:_1, :_2]
|
-> { _1; binding.local_variables }.call("a").should == [:_1]
|
||||||
|
-> { _2; binding.local_variables }.call("a", "b").should == [:_1, :_2]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "3.5" do
|
||||||
|
it "does not affect binding local variables" do
|
||||||
|
-> { _1; binding.local_variables }.call("a").should == []
|
||||||
|
-> { _2; binding.local_variables }.call("a", "b").should == []
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not work in methods" do
|
it "does not work in methods" do
|
||||||
|
15
vm.c
15
vm.c
@ -1106,6 +1106,21 @@ rb_vm_env_local_variables(const rb_env_t *env)
|
|||||||
return local_var_list_finish(&vars);
|
return local_var_list_finish(&vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_vm_env_numbered_parameters(const rb_env_t *env)
|
||||||
|
{
|
||||||
|
struct local_var_list vars;
|
||||||
|
local_var_list_init(&vars);
|
||||||
|
// if (VM_ENV_FLAGS(env->ep, VM_ENV_FLAG_ISOLATED)) break; // TODO: is this needed?
|
||||||
|
const rb_iseq_t *iseq = env->iseq;
|
||||||
|
unsigned int i;
|
||||||
|
if (!iseq) return 0;
|
||||||
|
for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
|
||||||
|
numparam_list_add(&vars, ISEQ_BODY(iseq)->local_table[i]);
|
||||||
|
}
|
||||||
|
return local_var_list_finish(&vars);
|
||||||
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_iseq_local_variables(const rb_iseq_t *iseq)
|
rb_iseq_local_variables(const rb_iseq_t *iseq)
|
||||||
{
|
{
|
||||||
|
@ -1853,6 +1853,7 @@ rb_vm_make_lambda(const rb_execution_context_t *ec, const struct rb_captured_blo
|
|||||||
|
|
||||||
VALUE rb_vm_make_binding(const rb_execution_context_t *ec, const rb_control_frame_t *src_cfp);
|
VALUE rb_vm_make_binding(const rb_execution_context_t *ec, const rb_control_frame_t *src_cfp);
|
||||||
VALUE rb_vm_env_local_variables(const rb_env_t *env);
|
VALUE rb_vm_env_local_variables(const rb_env_t *env);
|
||||||
|
VALUE rb_vm_env_numbered_parameters(const rb_env_t *env);
|
||||||
const rb_env_t *rb_vm_env_prev_env(const rb_env_t *env);
|
const rb_env_t *rb_vm_env_prev_env(const rb_env_t *env);
|
||||||
const VALUE *rb_binding_add_dynavars(VALUE bindval, rb_binding_t *bind, int dyncount, const ID *dynvars);
|
const VALUE *rb_binding_add_dynavars(VALUE bindval, rb_binding_t *bind, int dyncount, const ID *dynvars);
|
||||||
void rb_vm_inc_const_missing_count(void);
|
void rb_vm_inc_const_missing_count(void);
|
||||||
|
24
vm_eval.c
24
vm_eval.c
@ -2661,11 +2661,31 @@ local_var_list_update(st_data_t *key, st_data_t *value, st_data_t arg, int exist
|
|||||||
return ST_CONTINUE;
|
return ST_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern int rb_numparam_id_p(ID id);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
local_var_list_add(const struct local_var_list *vars, ID lid)
|
local_var_list_add(const struct local_var_list *vars, ID lid)
|
||||||
{
|
{
|
||||||
if (lid && rb_is_local_id(lid)) {
|
/* should skip temporary variable */
|
||||||
/* should skip temporary variable */
|
if (!lid) return;
|
||||||
|
if (!rb_is_local_id(lid)) return;
|
||||||
|
|
||||||
|
/* should skip numbered parameters as well */
|
||||||
|
if (rb_numparam_id_p(lid)) return;
|
||||||
|
|
||||||
|
st_data_t idx = 0; /* tbl->num_entries */
|
||||||
|
rb_hash_stlike_update(vars->tbl, ID2SYM(lid), local_var_list_update, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
numparam_list_add(const struct local_var_list *vars, ID lid)
|
||||||
|
{
|
||||||
|
/* should skip temporary variable */
|
||||||
|
if (!lid) return;
|
||||||
|
if (!rb_is_local_id(lid)) return;
|
||||||
|
|
||||||
|
/* should skip anything but numbered parameters */
|
||||||
|
if (rb_numparam_id_p(lid)) {
|
||||||
st_data_t idx = 0; /* tbl->num_entries */
|
st_data_t idx = 0; /* tbl->num_entries */
|
||||||
rb_hash_stlike_update(vars->tbl, ID2SYM(lid), local_var_list_update, idx);
|
rb_hash_stlike_update(vars->tbl, ID2SYM(lid), local_var_list_update, idx);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user