diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-11-13 08:34:43 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-11-13 08:34:43 +0000 |
commit | ffd3cbdc759841c984ec35bfecfb9f7ed28d4faa (patch) | |
tree | 9977cb9dc1d1c5f986736c558311e9bad2d355a2 | |
parent | db31b3dad519f755358f0a96baad5c378e7c7972 (diff) | |
download | ruby-ffd3cbdc759841c984ec35bfecfb9f7ed28d4faa.tar.gz |
* vm_insnhelper.c (vm_caller_setup_args): save and restore
ci->argc and ci->blockptr before and after method invocations
because these method dispatches override call_info.
* bootstraptest/test_method.rb: add tests for this fix.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37641 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | bootstraptest/test_method.rb | 58 | ||||
-rw-r--r-- | vm_insnhelper.c | 15 |
3 files changed, 79 insertions, 2 deletions
@@ -1,3 +1,11 @@ +Tue Nov 13 17:28:47 2012 Koichi Sasada <ko1@atdot.net> + + * vm_insnhelper.c (vm_caller_setup_args): save and restore + ci->argc and ci->blockptr before and after method invocations + because these method dispatches override call_info. + + * bootstraptest/test_method.rb: add tests for this fix. + Tue Nov 13 16:38:02 2012 NARUSE, Yui <naruse@ruby-lang.org> * common.mk (dmyprobes.h): always create for make dist. diff --git a/bootstraptest/test_method.rb b/bootstraptest/test_method.rb index d6b8c0ea24..ed22608aea 100644 --- a/bootstraptest/test_method.rb +++ b/bootstraptest/test_method.rb @@ -1204,3 +1204,61 @@ assert_equal 'ok', %q{ 'ok' end } + +assert_equal 'DC', %q{ + $result = [] + + class C + def foo *args + $result << 'C' + end + end + class D + def foo *args + $result << 'D' + end + end + + o1 = $o1 = C.new + o2 = $o2 = D.new + + args = Object.new + def args.to_a + test1 $o2, nil + [] + end + def test1 o, args + o.foo(*args) + end + test1 o1, args + $result.join +} + +assert_equal 'DC', %q{ + $result = [] + + class C + def foo *args + $result << 'C' + end + end + class D + def foo *args + $result << 'D' + end + end + + o1 = $o1 = C.new + o2 = $o2 = D.new + + block = Object.new + def block.to_proc + test2 $o2, %w(a, b, c), nil + Proc.new{} + end + def test2 o, args, block + o.foo(*args, &block) + end + test2 o1, [], block + $result.join +} diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 32b0851320..3e1ca3866c 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1036,6 +1036,12 @@ vm_base_ptr(rb_control_frame_t *cfp) static void vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) { +#define SAVE_RESTORE_CI(expr, ci) do { \ + int saved_argc = (ci)->argc; rb_block_t *saved_blockptr = (ci)->blockptr; /* save */ \ + expr; \ + (ci)->argc = saved_argc; (ci)->blockptr = saved_blockptr; /* restore */ \ +} while (0) + if (UNLIKELY(ci->flag & VM_CALL_ARGS_BLOCKARG)) { rb_proc_t *po; VALUE proc; @@ -1044,7 +1050,10 @@ vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_inf if (proc != Qnil) { if (!rb_obj_is_proc(proc)) { - VALUE b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); + VALUE b; + + SAVE_RESTORE_CI(b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"), ci); + if (NIL_P(b) || !rb_obj_is_proc(b)) { rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc)", @@ -1069,7 +1078,9 @@ vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_inf VALUE ary = *(cfp->sp - 1); VALUE *ptr; int i; - VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"); + VALUE tmp; + + SAVE_RESTORE_CI(tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"), ci); if (NIL_P(tmp)) { /* do nothing */ |