* 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
Родитель 07264c40da
Коммит 633574eee5
6 изменённых файлов: 55 добавлений и 18 удалений

Просмотреть файл

@ -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>
* tool/downloader.rb (http_options): prevent content auto decoding

2
cont.c
Просмотреть файл

@ -490,7 +490,7 @@ cont_capture(volatile int *stat)
contval = cont->self;
#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 = ALLOC_N(VALUE, cont->vm_stack_slen + cont->vm_stack_clen);
MEMCPY(cont->vm_stack, th->stack, VALUE, cont->vm_stack_slen);

Просмотреть файл

@ -566,4 +566,14 @@ class TestKeywordArguments < Test::Unit::TestCase
result = m(["a" => 10]) { |a = nil, **b| [a, b] }
assert_equal([{"a" => 10}, {}], result)
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

1
vm.c
Просмотреть файл

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

Просмотреть файл

@ -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;
}

Просмотреть файл

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