aboutsummaryrefslogtreecommitdiffstats
path: root/vm_args.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-04-06 07:14:28 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-04-06 07:14:28 +0000
commit633574eee5ed28367d868bbe6391b3e8f7bba08f (patch)
tree77c6cd00a90c7aa646e8ce65947c7c9bec2c59bf /vm_args.c
parent07264c40da8b19f86132a898f1a3ac74ceecf42c (diff)
downloadruby-633574eee5ed28367d868bbe6391b3e8f7bba08f.tar.gz
* vm_args.c: protect value stack from calling other methods
during complex parameter setting process (splat, kw, and so on). [Bug #11027] * vm_core.h: remove rb_thead_t::mark_stack_len. With this modification, we don't need to use th->mark_stack_len. * test/ruby/test_keyword.rb: add a test. * cont.c (cont_capture): catch up this fix. * vm.c (rb_thread_mark): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@50172 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'vm_args.c')
-rw-r--r--vm_args.c44
1 files changed, 29 insertions, 15 deletions
diff --git a/vm_args.c b/vm_args.c
index e4ade6bb2f..2f5c7c986e 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -83,19 +83,17 @@ args_reduce(struct args_info *args, int over_argc)
}
static inline int
-args_check_block_arg0(struct args_info *args, rb_thread_t *th, const int msl)
+args_check_block_arg0(struct args_info *args, rb_thread_t *th)
{
VALUE ary = Qnil;
if (args->rest && RARRAY_LEN(args->rest) == 1) {
VALUE arg0 = RARRAY_AREF(args->rest, 0);
ary = rb_check_array_type(arg0);
- th->mark_stack_len = msl;
}
else if (args->argc == 1) {
VALUE arg0 = args->argv[0];
ary = rb_check_array_type(arg0);
- th->mark_stack_len = msl;
args->argv[0] = arg0; /* see: https://bugs.ruby-lang.org/issues/8484 */
}
@@ -173,10 +171,9 @@ args_rest_array(struct args_info *args)
}
static int
-keyword_hash_p(VALUE *kw_hash_ptr, VALUE *rest_hash_ptr, rb_thread_t *th, const int msl)
+keyword_hash_p(VALUE *kw_hash_ptr, VALUE *rest_hash_ptr, rb_thread_t *th)
{
*rest_hash_ptr = rb_check_hash_type(*kw_hash_ptr);
- th->mark_stack_len = msl;
if (!NIL_P(*rest_hash_ptr)) {
VALUE hash = rb_extract_keywords(rest_hash_ptr);
@@ -191,7 +188,7 @@ keyword_hash_p(VALUE *kw_hash_ptr, VALUE *rest_hash_ptr, rb_thread_t *th, const
}
static VALUE
-args_pop_keyword_hash(struct args_info *args, VALUE *kw_hash_ptr, rb_thread_t *th, const int msl)
+args_pop_keyword_hash(struct args_info *args, VALUE *kw_hash_ptr, rb_thread_t *th)
{
VALUE rest_hash;
@@ -200,7 +197,7 @@ args_pop_keyword_hash(struct args_info *args, VALUE *kw_hash_ptr, rb_thread_t *t
assert(args->argc > 0);
*kw_hash_ptr = args->argv[args->argc-1];
- if (keyword_hash_p(kw_hash_ptr, &rest_hash, th, msl)) {
+ if (keyword_hash_p(kw_hash_ptr, &rest_hash, th)) {
if (rest_hash) {
args->argv[args->argc-1] = rest_hash;
}
@@ -216,7 +213,7 @@ args_pop_keyword_hash(struct args_info *args, VALUE *kw_hash_ptr, rb_thread_t *t
if (len > 0) {
*kw_hash_ptr = RARRAY_AREF(args->rest, len - 1);
- if (keyword_hash_p(kw_hash_ptr, &rest_hash, th, msl)) {
+ if (keyword_hash_p(kw_hash_ptr, &rest_hash, th)) {
if (rest_hash) {
RARRAY_ASET(args->rest, len - 1, rest_hash);
}
@@ -511,9 +508,27 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r
int given_argc;
struct args_info args_body, *args;
VALUE keyword_hash = Qnil;
- const int msl = ci->argc + iseq->param.size;
+ VALUE * const orig_sp = th->cfp->sp;
+ int i;
- th->mark_stack_len = msl;
+ /*
+ * Extend SP for GC.
+ *
+ * [pushed values] [uninitialized values]
+ * <- ci->argc -->
+ * <- iseq->param.size------------------>
+ * ^ locals ^ sp
+ *
+ * =>
+ * [pushed values] [initialized values ]
+ * <- ci->argc -->
+ * <- iseq->param.size------------------>
+ * ^ locals ^ sp
+ */
+ for (i=ci->argc; i<iseq->param.size; i++) {
+ locals[i] = Qnil;
+ }
+ th->cfp->sp = &locals[i];
/* setup args */
args = &args_body;
@@ -556,7 +571,7 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r
(min_argc > 0 || iseq->param.opt_num > 1 ||
iseq->param.flags.has_kw || iseq->param.flags.has_kwrest) &&
!iseq->param.flags.ambiguous_param0 &&
- args_check_block_arg0(args, th, msl)) {
+ args_check_block_arg0(args, th)) {
given_argc = RARRAY_LENINT(args->rest);
}
break;
@@ -564,7 +579,7 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r
if (given_argc == 1 &&
given_argc != iseq->param.lead_num &&
!iseq->param.flags.has_rest &&
- args_check_block_arg0(args, th, msl)) {
+ args_check_block_arg0(args, th)) {
given_argc = RARRAY_LENINT(args->rest);
}
}
@@ -590,7 +605,7 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r
if (given_argc > min_argc &&
(iseq->param.flags.has_kw || iseq->param.flags.has_kwrest) &&
args->kw_argv == NULL) {
- if (args_pop_keyword_hash(args, &keyword_hash, th, msl)) {
+ if (args_pop_keyword_hash(args, &keyword_hash, th)) {
given_argc--;
}
}
@@ -662,8 +677,7 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r
}
#endif
- th->mark_stack_len = 0;
-
+ th->cfp->sp = orig_sp;
return opt_pc;
}