* 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
This commit is contained in:
ko1 2015-04-06 07:14:28 +00:00
parent 07264c40da
commit 633574eee5
6 changed files with 55 additions and 18 deletions

View File

@ -1,3 +1,18 @@
Mon Apr 6 16:09:58 2015 Koichi Sasada <ko1@atdot.net>
* 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.
Mon Apr 6 11:26:42 2015 NARUSE, Yui <naruse@ruby-lang.org> Mon Apr 6 11:26:42 2015 NARUSE, Yui <naruse@ruby-lang.org>
* tool/downloader.rb (http_options): prevent content auto decoding * tool/downloader.rb (http_options): prevent content auto decoding

2
cont.c
View File

@ -490,7 +490,7 @@ cont_capture(volatile int *stat)
contval = cont->self; contval = cont->self;
#ifdef CAPTURE_JUST_VALID_VM_STACK #ifdef CAPTURE_JUST_VALID_VM_STACK
cont->vm_stack_slen = th->cfp->sp + th->mark_stack_len - th->stack; cont->vm_stack_slen = th->cfp->sp - th->stack;
cont->vm_stack_clen = th->stack + th->stack_size - (VALUE*)th->cfp; cont->vm_stack_clen = th->stack + th->stack_size - (VALUE*)th->cfp;
cont->vm_stack = ALLOC_N(VALUE, cont->vm_stack_slen + cont->vm_stack_clen); cont->vm_stack = ALLOC_N(VALUE, cont->vm_stack_slen + cont->vm_stack_clen);
MEMCPY(cont->vm_stack, th->stack, VALUE, cont->vm_stack_slen); MEMCPY(cont->vm_stack, th->stack, VALUE, cont->vm_stack_slen);

View File

@ -566,4 +566,14 @@ class TestKeywordArguments < Test::Unit::TestCase
result = m(["a" => 10]) { |a = nil, **b| [a, b] } result = m(["a" => 10]) { |a = nil, **b| [a, b] }
assert_equal([{"a" => 10}, {}], result) assert_equal([{"a" => 10}, {}], result)
end end
def method_for_test_to_hash_call_during_setup_complex_parameters k1:, k2:, **rest_kw
[k1, k2, rest_kw]
end
def test_to_hash_call_during_setup_complex_parameters
sym = "sym_#{Time.now}".to_sym
h = method_for_test_to_hash_call_during_setup_complex_parameters k1: "foo", k2: "bar", sym => "baz"
assert_equal ["foo", "bar", {sym => "baz"}], h, '[Bug #11027]'
end
end end

1
vm.c
View File

@ -2048,7 +2048,6 @@ rb_thread_mark(void *ptr)
rb_control_frame_t *limit_cfp = (void *)(th->stack + th->stack_size); rb_control_frame_t *limit_cfp = (void *)(th->stack + th->stack_size);
rb_gc_mark_values((long)(sp - p), p); rb_gc_mark_values((long)(sp - p), p);
rb_gc_mark_locations(sp, sp + th->mark_stack_len);
while (cfp != limit_cfp) { while (cfp != limit_cfp) {
rb_iseq_t *iseq = cfp->iseq; rb_iseq_t *iseq = cfp->iseq;

View File

@ -83,19 +83,17 @@ args_reduce(struct args_info *args, int over_argc)
} }
static inline int 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; VALUE ary = Qnil;
if (args->rest && RARRAY_LEN(args->rest) == 1) { if (args->rest && RARRAY_LEN(args->rest) == 1) {
VALUE arg0 = RARRAY_AREF(args->rest, 0); VALUE arg0 = RARRAY_AREF(args->rest, 0);
ary = rb_check_array_type(arg0); ary = rb_check_array_type(arg0);
th->mark_stack_len = msl;
} }
else if (args->argc == 1) { else if (args->argc == 1) {
VALUE arg0 = args->argv[0]; VALUE arg0 = args->argv[0];
ary = rb_check_array_type(arg0); ary = rb_check_array_type(arg0);
th->mark_stack_len = msl;
args->argv[0] = arg0; /* see: https://bugs.ruby-lang.org/issues/8484 */ 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 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); *rest_hash_ptr = rb_check_hash_type(*kw_hash_ptr);
th->mark_stack_len = msl;
if (!NIL_P(*rest_hash_ptr)) { if (!NIL_P(*rest_hash_ptr)) {
VALUE hash = rb_extract_keywords(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 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; 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); assert(args->argc > 0);
*kw_hash_ptr = args->argv[args->argc-1]; *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) { if (rest_hash) {
args->argv[args->argc-1] = 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) { if (len > 0) {
*kw_hash_ptr = RARRAY_AREF(args->rest, len - 1); *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) { if (rest_hash) {
RARRAY_ASET(args->rest, len - 1, 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; int given_argc;
struct args_info args_body, *args; struct args_info args_body, *args;
VALUE keyword_hash = Qnil; 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 */ /* setup args */
args = &args_body; 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 || (min_argc > 0 || iseq->param.opt_num > 1 ||
iseq->param.flags.has_kw || iseq->param.flags.has_kwrest) && iseq->param.flags.has_kw || iseq->param.flags.has_kwrest) &&
!iseq->param.flags.ambiguous_param0 && !iseq->param.flags.ambiguous_param0 &&
args_check_block_arg0(args, th, msl)) { args_check_block_arg0(args, th)) {
given_argc = RARRAY_LENINT(args->rest); given_argc = RARRAY_LENINT(args->rest);
} }
break; break;
@ -564,7 +579,7 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r
if (given_argc == 1 && if (given_argc == 1 &&
given_argc != iseq->param.lead_num && given_argc != iseq->param.lead_num &&
!iseq->param.flags.has_rest && !iseq->param.flags.has_rest &&
args_check_block_arg0(args, th, msl)) { args_check_block_arg0(args, th)) {
given_argc = RARRAY_LENINT(args->rest); 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 && if (given_argc > min_argc &&
(iseq->param.flags.has_kw || iseq->param.flags.has_kwrest) && (iseq->param.flags.has_kw || iseq->param.flags.has_kwrest) &&
args->kw_argv == NULL) { 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--; given_argc--;
} }
} }
@ -662,8 +677,7 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r
} }
#endif #endif
th->mark_stack_len = 0; th->cfp->sp = orig_sp;
return opt_pc; return opt_pc;
} }

View File

@ -631,7 +631,6 @@ typedef struct rb_thread_struct {
enum rb_thread_status status; enum rb_thread_status status;
int to_kill; int to_kill;
int priority; int priority;
int mark_stack_len;
native_thread_data_t native_thread_data; native_thread_data_t native_thread_data;
void *blocking_region_buffer; void *blocking_region_buffer;