mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Only set RB_PASS_CALLED_KEYWORDS in C functions called directly from Ruby
It is not safe to set this in C functions that can be called from other C functions, as in the non argument-delegation case, you can end up calling a Ruby method with a flag indicating keywords are set without passing keywords. Introduce some new *_kw functions that take a kw_splat flag and use these functions to set RB_PASS_CALLED_KEYWORDS in places where we know we are delegating methods (e.g. Class#new, Method#call)
This commit is contained in:
parent
b2c29bbab6
commit
b78a345bd6
7 changed files with 77 additions and 19 deletions
9
eval.c
9
eval.c
|
@ -1672,7 +1672,14 @@ void
|
|||
rb_obj_call_init(VALUE obj, int argc, const VALUE *argv)
|
||||
{
|
||||
PASS_PASSED_BLOCK_HANDLER();
|
||||
rb_funcallv_kw(obj, idInitialize, argc, argv, RB_PASS_CALLED_KEYWORDS);
|
||||
rb_funcallv_kw(obj, idInitialize, argc, argv, RB_NO_KEYWORDS);
|
||||
}
|
||||
|
||||
void
|
||||
rb_obj_call_init_kw(VALUE obj, int argc, const VALUE *argv, int kw_splat)
|
||||
{
|
||||
PASS_PASSED_BLOCK_HANDLER();
|
||||
rb_funcallv_kw(obj, idInitialize, argc, argv, kw_splat);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -443,7 +443,9 @@ void rb_provide(const char*);
|
|||
VALUE rb_f_require(VALUE, VALUE);
|
||||
VALUE rb_require_safe(VALUE, int);
|
||||
void rb_obj_call_init(VALUE, int, const VALUE*);
|
||||
void rb_obj_call_init_kw(VALUE, int, const VALUE*, int);
|
||||
VALUE rb_class_new_instance(int, const VALUE*, VALUE);
|
||||
VALUE rb_class_new_instance_kw(int, const VALUE*, VALUE, int);
|
||||
VALUE rb_block_proc(void);
|
||||
VALUE rb_block_lambda(void);
|
||||
VALUE rb_proc_new(rb_block_call_func_t, VALUE);
|
||||
|
@ -456,7 +458,9 @@ VALUE rb_binding_new(void);
|
|||
VALUE rb_obj_method(VALUE, VALUE);
|
||||
VALUE rb_obj_is_method(VALUE);
|
||||
VALUE rb_method_call(int, const VALUE*, VALUE);
|
||||
VALUE rb_method_call_kw(int, const VALUE*, VALUE, int);
|
||||
VALUE rb_method_call_with_block(int, const VALUE *, VALUE, VALUE);
|
||||
VALUE rb_method_call_with_block_kw(int, const VALUE *, VALUE, VALUE, int);
|
||||
int rb_mod_method_arity(VALUE, ID);
|
||||
int rb_obj_method_arity(VALUE, ID);
|
||||
VALUE rb_protect(VALUE (*)(VALUE), VALUE, int*);
|
||||
|
|
|
@ -1901,6 +1901,7 @@ VALUE rb_funcall_with_block(VALUE, ID, int, const VALUE*, VALUE);
|
|||
VALUE rb_funcall_with_block_kw(VALUE, ID, int, const VALUE*, VALUE, int);
|
||||
int rb_scan_args(int, const VALUE*, const char*, ...);
|
||||
VALUE rb_call_super(int, const VALUE*);
|
||||
VALUE rb_call_super_kw(int, const VALUE*, int);
|
||||
VALUE rb_current_receiver(void);
|
||||
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *);
|
||||
VALUE rb_extract_keywords(VALUE *orighash);
|
||||
|
|
21
object.c
21
object.c
|
@ -2196,7 +2196,19 @@ rb_class_s_new(int argc, const VALUE *argv, VALUE klass)
|
|||
VALUE obj;
|
||||
|
||||
obj = rb_class_alloc(klass);
|
||||
rb_obj_call_init(obj, argc, argv);
|
||||
rb_obj_call_init_kw(obj, argc, argv, RB_PASS_CALLED_KEYWORDS);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
|
||||
{
|
||||
VALUE obj;
|
||||
Check_Type(klass, T_CLASS);
|
||||
|
||||
obj = rb_class_alloc(klass);
|
||||
rb_obj_call_init_kw(obj, argc, argv, kw_splat);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
@ -2216,8 +2228,13 @@ rb_class_s_new(int argc, const VALUE *argv, VALUE klass)
|
|||
VALUE
|
||||
rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
|
||||
{
|
||||
VALUE obj;
|
||||
Check_Type(klass, T_CLASS);
|
||||
return rb_class_s_new(argc, argv, klass);
|
||||
|
||||
obj = rb_class_alloc(klass);
|
||||
rb_obj_call_init_kw(obj, argc, argv, RB_NO_KEYWORDS);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
44
proc.c
44
proc.c
|
@ -819,7 +819,7 @@ rb_proc_s_new(int argc, VALUE *argv, VALUE klass)
|
|||
{
|
||||
VALUE block = proc_new(klass, FALSE);
|
||||
|
||||
rb_obj_call_init(block, argc, argv);
|
||||
rb_obj_call_init_kw(block, argc, argv, RB_PASS_CALLED_KEYWORDS);
|
||||
return block;
|
||||
}
|
||||
|
||||
|
@ -2204,6 +2204,20 @@ method_clone(VALUE self)
|
|||
* m.call(20) #=> 32
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_method_call_pass_called_kw(int argc, const VALUE *argv, VALUE method)
|
||||
{
|
||||
VALUE procval = rb_block_given_p() ? rb_block_proc() : Qnil;
|
||||
return rb_method_call_with_block_kw(argc, argv, method, procval, RB_PASS_CALLED_KEYWORDS);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_method_call_kw(int argc, const VALUE *argv, VALUE method, int kw_splat)
|
||||
{
|
||||
VALUE procval = rb_block_given_p() ? rb_block_proc() : Qnil;
|
||||
return rb_method_call_with_block_kw(argc, argv, method, procval, kw_splat);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_method_call(int argc, const VALUE *argv, VALUE method)
|
||||
{
|
||||
|
@ -2220,17 +2234,17 @@ method_callable_method_entry(const struct METHOD *data)
|
|||
|
||||
static inline VALUE
|
||||
call_method_data(rb_execution_context_t *ec, const struct METHOD *data,
|
||||
int argc, const VALUE *argv, VALUE passed_procval)
|
||||
int argc, const VALUE *argv, VALUE passed_procval, int kw_splat)
|
||||
{
|
||||
vm_passed_block_handler_set(ec, proc_to_block_handler(passed_procval));
|
||||
return rb_vm_call_kw(ec, data->recv, data->me->called_id, argc, argv,
|
||||
method_callable_method_entry(data), RB_PASS_CALLED_KEYWORDS);
|
||||
method_callable_method_entry(data), kw_splat);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
call_method_data_safe(rb_execution_context_t *ec, const struct METHOD *data,
|
||||
int argc, const VALUE *argv, VALUE passed_procval,
|
||||
int safe)
|
||||
int safe, int kw_splat)
|
||||
{
|
||||
VALUE result = Qnil; /* OK */
|
||||
enum ruby_tag_type state;
|
||||
|
@ -2239,7 +2253,7 @@ call_method_data_safe(rb_execution_context_t *ec, const struct METHOD *data,
|
|||
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
|
||||
/* result is used only if state == 0, no exceptions is caught. */
|
||||
/* otherwise it doesn't matter even if clobbered. */
|
||||
NO_CLOBBERED(result) = call_method_data(ec, data, argc, argv, passed_procval);
|
||||
NO_CLOBBERED(result) = call_method_data(ec, data, argc, argv, passed_procval, kw_splat);
|
||||
}
|
||||
EC_POP_TAG();
|
||||
rb_set_safe_level_force(safe);
|
||||
|
@ -2249,7 +2263,7 @@ call_method_data_safe(rb_execution_context_t *ec, const struct METHOD *data,
|
|||
}
|
||||
|
||||
VALUE
|
||||
rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE passed_procval)
|
||||
rb_method_call_with_block_kw(int argc, const VALUE *argv, VALUE method, VALUE passed_procval, int kw_splat)
|
||||
{
|
||||
const struct METHOD *data;
|
||||
rb_execution_context_t *ec = GET_EC();
|
||||
|
@ -2263,10 +2277,16 @@ rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE passe
|
|||
int safe = rb_safe_level();
|
||||
if (safe < safe_level_to_run) {
|
||||
rb_set_safe_level_force(safe_level_to_run);
|
||||
return call_method_data_safe(ec, data, argc, argv, passed_procval, safe);
|
||||
return call_method_data_safe(ec, data, argc, argv, passed_procval, safe, kw_splat);
|
||||
}
|
||||
}
|
||||
return call_method_data(ec, data, argc, argv, passed_procval);
|
||||
return call_method_data(ec, data, argc, argv, passed_procval, kw_splat);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE passed_procval)
|
||||
{
|
||||
return rb_method_call_with_block_kw(argc, argv, method, passed_procval, RB_NO_KEYWORDS);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
@ -2439,7 +2459,7 @@ umethod_bind_call(int argc, VALUE *argv, VALUE method)
|
|||
VALUE passed_procval = rb_block_given_p() ? rb_block_proc() : Qnil;
|
||||
|
||||
rb_execution_context_t *ec = GET_EC();
|
||||
return call_method_data(ec, &bound, argc, argv, passed_procval);
|
||||
return call_method_data(ec, &bound, argc, argv, passed_procval, RB_PASS_CALLED_KEYWORDS);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3692,12 +3712,12 @@ Init_Proc(void)
|
|||
rb_define_method(rb_cMethod, "eql?", method_eq, 1);
|
||||
rb_define_method(rb_cMethod, "hash", method_hash, 0);
|
||||
rb_define_method(rb_cMethod, "clone", method_clone, 0);
|
||||
rb_define_method(rb_cMethod, "call", rb_method_call, -1);
|
||||
rb_define_method(rb_cMethod, "===", rb_method_call, -1);
|
||||
rb_define_method(rb_cMethod, "call", rb_method_call_pass_called_kw, -1);
|
||||
rb_define_method(rb_cMethod, "===", rb_method_call_pass_called_kw, -1);
|
||||
rb_define_method(rb_cMethod, "curry", rb_method_curry, -1);
|
||||
rb_define_method(rb_cMethod, "<<", rb_method_compose_to_left, 1);
|
||||
rb_define_method(rb_cMethod, ">>", rb_method_compose_to_right, 1);
|
||||
rb_define_method(rb_cMethod, "[]", rb_method_call, -1);
|
||||
rb_define_method(rb_cMethod, "[]", rb_method_call_pass_called_kw, -1);
|
||||
rb_define_method(rb_cMethod, "arity", method_arity_m, 0);
|
||||
rb_define_method(rb_cMethod, "inspect", method_inspect, 0);
|
||||
rb_define_method(rb_cMethod, "to_s", method_inspect, 0);
|
||||
|
|
2
thread.c
2
thread.c
|
@ -882,7 +882,7 @@ thread_s_new(int argc, VALUE *argv, VALUE klass)
|
|||
if (GET_VM()->main_thread->status == THREAD_KILLED)
|
||||
rb_raise(rb_eThreadError, "can't alloc thread");
|
||||
|
||||
rb_obj_call_init(thread, argc, argv);
|
||||
rb_obj_call_init_kw(thread, argc, argv, RB_PASS_CALLED_KEYWORDS);
|
||||
th = rb_thread_ptr(thread);
|
||||
if (!threadptr_initialized(th)) {
|
||||
rb_raise(rb_eThreadError, "uninitialized thread - check `%"PRIsVALUE"#initialize'",
|
||||
|
|
15
vm_eval.c
15
vm_eval.c
|
@ -269,7 +269,7 @@ rb_vm_call_kw(rb_execution_context_t *ec, VALUE recv, VALUE id, int argc, const
|
|||
}
|
||||
|
||||
static inline VALUE
|
||||
vm_call_super(rb_execution_context_t *ec, int argc, const VALUE *argv)
|
||||
vm_call_super(rb_execution_context_t *ec, int argc, const VALUE *argv, int kw_splat)
|
||||
{
|
||||
VALUE recv = ec->cfp->self;
|
||||
VALUE klass;
|
||||
|
@ -290,16 +290,25 @@ vm_call_super(rb_execution_context_t *ec, int argc, const VALUE *argv)
|
|||
return method_missing(recv, id, argc, argv, MISSING_SUPER);
|
||||
}
|
||||
else {
|
||||
return rb_vm_call0(ec, recv, id, argc, argv, me, RB_PASS_CALLED_KEYWORDS);
|
||||
add_empty_keyword(&argc, &argv, &kw_splat);
|
||||
return rb_vm_call0(ec, recv, id, argc, argv, me, kw_splat);
|
||||
}
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_call_super_kw(int argc, const VALUE *argv, int kw_splat)
|
||||
{
|
||||
rb_execution_context_t *ec = GET_EC();
|
||||
PASS_PASSED_BLOCK_HANDLER_EC(ec);
|
||||
return vm_call_super(ec, argc, argv, kw_splat);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_call_super(int argc, const VALUE *argv)
|
||||
{
|
||||
rb_execution_context_t *ec = GET_EC();
|
||||
PASS_PASSED_BLOCK_HANDLER_EC(ec);
|
||||
return vm_call_super(ec, argc, argv);
|
||||
return vm_call_super(ec, argc, argv, RB_NO_KEYWORDS);
|
||||
}
|
||||
|
||||
VALUE
|
||||
|
|
Loading…
Reference in a new issue