diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | bootstraptest/test_flow.rb | 13 | ||||
-rw-r--r-- | vm.c | 17 |
3 files changed, 44 insertions, 0 deletions
@@ -1,3 +1,17 @@ +Thu Aug 25 08:19:43 2011 Koichi Sasada <ko1@atdot.net> + + * vm.c (vm_make_env_each): work around to solve Bug #2729. + fixes: Bug #2729 + a patch from Kazuki Tsujimoto <kazuki@callcc.net> + This problem is caused by changing dfp (dynamic env pointer) + from saved dfp. Saved dfp is pointed env in VM stack. However, + the dfp can be moved because VM copies env from VM stack to + the heap. At this copying, dfp was also changed. To solve this + problem, I'll try to change throw mechanism (not save target dfp, + but save target cfp). + + * bootstraptest/test_flow.rb: add a test for above. + Thu Aug 25 08:04:08 2011 Marc-Andre Lafortune <ruby-core@marc-andre.ca> * numeric.c (int_round): Fix Integer#round [ruby-core:39096] diff --git a/bootstraptest/test_flow.rb b/bootstraptest/test_flow.rb index 02062755aa..100ad0a2f1 100644 --- a/bootstraptest/test_flow.rb +++ b/bootstraptest/test_flow.rb @@ -517,6 +517,19 @@ assert_equal %Q{ENSURE\n}, %q{ end end e = Bug2728.new +}], + ['[ruby-core:28132]', %q{ + class Bug2729 + include Enumerable + def each + begin + yield :foo + ensure + proc {}.call + end + end + end + e = Bug2729.new }]].each do |bug, src| assert_equal "foo", src + %q{e.detect {true}}, bug assert_equal "true", src + %q{e.any? {true}}, bug @@ -415,6 +415,23 @@ vm_make_env_each(rb_thread_t * const th, rb_control_frame_t * const cfp, if (!RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { /* TODO */ env->block.iseq = 0; + } else { + /* rewrite dfp in errinfo to point to heap */ + if (cfp->iseq->type == ISEQ_TYPE_RESCUE || + cfp->iseq->type == ISEQ_TYPE_ENSURE) { + VALUE errinfo = env->env[0]; /* #$! */ + if (RB_TYPE_P(errinfo, T_NODE)) { + VALUE *escape_dfp = GET_THROWOBJ_CATCH_POINT(errinfo); + if (! ENV_IN_HEAP_P(th, escape_dfp)) { + VALUE dfpval = *escape_dfp; + if (CLASS_OF(dfpval) == rb_cEnv) { + rb_env_t *dfpenv; + GetEnvPtr(dfpval, dfpenv); + SET_THROWOBJ_CATCH_POINT(errinfo, (VALUE)(dfpenv->env + dfpenv->local_size)); + } + } + } + } } return envval; } |