diff options
author | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2021-07-23 00:32:09 +0900 |
---|---|---|
committer | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2021-07-23 12:01:15 +0900 |
commit | fc4dd45d0142221880d1b2c9b54dee0597be2b78 (patch) | |
tree | f0defbf6005cabb4fb05a0e51e620fb2ad21f49e | |
parent | 63e5f4df387ba24b561c304c56a2f4357de15fe3 (diff) |
Show exception in finalizer [Feature #17798]
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/4670
-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 |