diff --git a/ChangeLog b/ChangeLog index e88ab65b18..c6f1dbde85 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Fri Feb 8 16:09:45 2013 Nobuyoshi Nakada + + * eval.c (rb_ensure): preserve errinfo accross ensure proc before + JUMP_TAG(). [ruby-core:52022] [Bug #7802] + Fri Feb 8 16:08:28 2013 Nobuyoshi Nakada * test/ruby/envutil.rb (assert_separately): check also terminating diff --git a/eval.c b/eval.c index c4bda48524..958daa8752 100644 --- a/eval.c +++ b/eval.c @@ -805,6 +805,8 @@ rb_ensure(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*e_proc)(ANYARGS), VALUE { int state; volatile VALUE result = Qnil; + volatile VALUE errinfo; + rb_thread_t *const th = GET_THREAD(); PUSH_TAG(); if ((state = EXEC_TAG()) == 0) { @@ -813,7 +815,9 @@ rb_ensure(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*e_proc)(ANYARGS), VALUE POP_TAG(); /* TODO: fix me */ /* retval = prot_tag ? prot_tag->retval : Qnil; */ /* save retval */ + errinfo = th->errinfo; (*e_proc) (data2); + th->errinfo = errinfo; if (state) JUMP_TAG(state); return result; diff --git a/ext/-test-/exception/ensured.c b/ext/-test-/exception/ensured.c new file mode 100644 index 0000000000..365e1f4f79 --- /dev/null +++ b/ext/-test-/exception/ensured.c @@ -0,0 +1,25 @@ +#include + +static VALUE +begin(VALUE object) +{ + return rb_funcall(object, rb_intern("try_method"), 0); +} + +static VALUE +ensure(VALUE object) +{ + return rb_funcall(object, rb_intern("ensured_method"), 0); +} + +static VALUE +ensured(VALUE module, VALUE object) +{ + return rb_ensure(begin, object, ensure, object); +} + +void +Init_ensured(VALUE klass) +{ + rb_define_module_function(klass, "ensured", ensured, 1); +} diff --git a/test/-ext-/exception/test_ensured.rb b/test/-ext-/exception/test_ensured.rb new file mode 100644 index 0000000000..103250c678 --- /dev/null +++ b/test/-ext-/exception/test_ensured.rb @@ -0,0 +1,32 @@ +require 'test/unit' +require_relative '../../ruby/envutil' + +module Bug + class Bug7802 < RuntimeError + end + + class TestException < Test::Unit::TestCase + def test_ensured + assert_separately([], <<-'end;') # do + + require '-test-/exception' + + module Bug + class Bug7802 < RuntimeError + def try_method + raise self + end + + def ensured_method + [1].detect {|i| true} + end + end + end + + assert_raise(Bug::Bug7802, '[ruby-core:52022] [Bug #7802]') { + Bug::Exception.ensured(Bug::Bug7802.new) + } + end; + end + end +end