diff options
-rw-r--r-- | gc.c | 15 | ||||
-rw-r--r-- | test/ruby/test_objectspace.rb | 7 |
2 files changed, 21 insertions, 1 deletions
@@ -3988,6 +3988,16 @@ run_single_final(VALUE cmd, VALUE objid) } static void +warn_exception_in_finalizer(rb_execution_context_t *ec, VALUE final) +{ + if (final != Qundef) { + VALUE errinfo = ec->errinfo; + rb_warn("Exception in finalizer %+"PRIsVALUE, final); + rb_ec_error_print(ec, errinfo); + } +} + +static void run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE table) { long i; @@ -3995,6 +4005,7 @@ run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE table) volatile struct { VALUE errinfo; VALUE objid; + VALUE final; rb_control_frame_t *cfp; long finished; } saved; @@ -4007,16 +4018,18 @@ run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE table) saved.objid = rb_obj_id(obj); saved.cfp = ec->cfp; saved.finished = 0; + saved.final = Qundef; EC_PUSH_TAG(ec); state = EC_EXEC_TAG(); if (state != TAG_NONE) { ++saved.finished; /* skip failed finalizer */ + warn_exception_in_finalizer(ec, ATOMIC_VALUE_EXCHANGE(saved.final, Qundef)); } for (i = saved.finished; RESTORE_FINALIZER(), i<RARRAY_LEN(table); saved.finished = ++i) { - run_single_final(RARRAY_AREF(table, i), saved.objid); + run_single_final(saved.final = RARRAY_AREF(table, i), saved.objid); } EC_POP_TAG(); #undef RESTORE_FINALIZER diff --git a/test/ruby/test_objectspace.rb b/test/ruby/test_objectspace.rb index b48fbc1c15..c26748f516 100644 --- a/test/ruby/test_objectspace.rb +++ b/test/ruby/test_objectspace.rb @@ -161,6 +161,13 @@ End END end + def test_exception_in_finalizer + assert_in_out_err([], "#{<<~"begin;"}\n#{<<~'end;'}", [], /finalizing \(RuntimeError\)/) + begin; + ObjectSpace.define_finalizer(Object.new) {raise "finalizing"} + end; + end + def test_each_object klass = Class.new new_obj = klass.new |