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);
|
||||
}
|
||||
|
||||
int
|
||||
rb_numparam_id_p(ID id)
|
||||
{
|
||||
return (tNUMPARAM_1 << ID_SCOPE_SHIFT) <= id && id < ((tNUMPARAM_1 + 10) << ID_SCOPE_SHIFT);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* binding.local_variable_get(symbol) -> obj
|
||||
@ -525,6 +531,10 @@ bind_local_variable_get(VALUE bindval, VALUE sym)
|
||||
const rb_env_t *env;
|
||||
|
||||
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);
|
||||
|
||||
@ -574,6 +584,10 @@ bind_local_variable_set(VALUE bindval, VALUE sym, VALUE val)
|
||||
const rb_env_t *env;
|
||||
|
||||
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);
|
||||
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]]
|
||||
end
|
||||
|
||||
it "affects binding local variables" do
|
||||
-> { _1; binding.local_variables }.call("a").should == [:_1]
|
||||
-> { _2; binding.local_variables }.call("a", "b").should == [:_1, :_2]
|
||||
ruby_version_is "".."3.4" do
|
||||
it "affects binding local variables" do
|
||||
-> { _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
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
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_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 VALUE *rb_binding_add_dynavars(VALUE bindval, rb_binding_t *bind, int dyncount, const ID *dynvars);
|
||||
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;
|
||||
}
|
||||
|
||||
extern int rb_numparam_id_p(ID id);
|
||||
|
||||
static void
|
||||
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 */
|
||||
rb_hash_stlike_update(vars->tbl, ID2SYM(lid), local_var_list_update, idx);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user