[前][次][番号順一覧][スレッド一覧]

ruby-changes:57744

From: Jeremy <ko1@a...>
Date: Sat, 14 Sep 2019 17:57:23 +0900 (JST)
Subject: [ruby-changes:57744] b78a345bd6 (master): Only set RB_PASS_CALLED_KEYWORDS in C functions called directly from Ruby

https://git.ruby-lang.org/ruby.git/commit/?id=b78a345bd6

From b78a345bd63ff2b52ea0f84754ab0988748a9bd0 Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Sat, 14 Sep 2019 01:49:33 -0700
Subject: 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)

diff --git a/eval.c b/eval.c
index ca4456d..5d402e5 100644
--- a/eval.c
+++ b/eval.c
@@ -1672,7 +1672,14 @@ void https://github.com/ruby/ruby/blob/trunk/eval.c#L1672
 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);
 }
 
 /*!
diff --git a/include/ruby/intern.h b/include/ruby/intern.h
index 4fa00d5..8a83928 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -443,7 +443,9 @@ void rb_provide(const char*); https://github.com/ruby/ruby/blob/trunk/include/ruby/intern.h#L443
 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); https://github.com/ruby/ruby/blob/trunk/include/ruby/intern.h#L458
 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*);
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index 1b396f4..b60afde 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -1901,6 +1901,7 @@ VALUE rb_funcall_with_block(VALUE, ID, int, const VALUE*, VALUE); https://github.com/ruby/ruby/blob/trunk/include/ruby/ruby.h#L1901
 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);
diff --git a/object.c b/object.c
index 501fcfc..de2d72f 100644
--- a/object.c
+++ b/object.c
@@ -2196,7 +2196,19 @@ rb_class_s_new(int argc, const VALUE *argv, VALUE klass) https://github.com/ruby/ruby/blob/trunk/object.c#L2196
     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) https://github.com/ruby/ruby/blob/trunk/object.c#L2228
 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;
 }
 
 /**
diff --git a/proc.c b/proc.c
index 92264af..62b8ead 100644
--- a/proc.c
+++ b/proc.c
@@ -819,7 +819,7 @@ rb_proc_s_new(int argc, VALUE *argv, VALUE klass) https://github.com/ruby/ruby/blob/trunk/proc.c#L819
 {
     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) https://github.com/ruby/ruby/blob/trunk/proc.c#L2204
  *     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) https://github.com/ruby/ruby/blob/trunk/proc.c#L2234
 
 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, https://github.com/ruby/ruby/blob/trunk/proc.c#L2253
     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, https://github.com/ruby/ruby/blob/trunk/proc.c#L2263
 }
 
 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 https://github.com/ruby/ruby/blob/trunk/proc.c#L2277
 	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) https://github.com/ruby/ruby/blob/trunk/proc.c#L2459
     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) https://github.com/ruby/ruby/blob/trunk/proc.c#L3712
     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);
diff --git a/thread.c b/thread.c
index 6958897..3b6ded9 100644
--- a/thread.c
+++ b/thread.c
@@ -882,7 +882,7 @@ thread_s_new(int argc, VALUE *argv, VALUE klass) https://github.com/ruby/ruby/blob/trunk/thread.c#L882
     if (GET_VM()->main_thread->status == THREAD_K (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]