Skip to content

Commit

Permalink
Do not check pending interrupts when running finalizers
Browse files Browse the repository at this point in the history
This fixes cases where exceptions raised using Thread#raise are
swallowed by finalizers and not delivered to the running thread.

This could cause issues with finalizers that rely on pending interrupts,
but that case is expected to be rarer.

Fixes [Bug #13876]
Fixes [Bug #15507]

Co-authored-by: Koichi Sasada <ko1@atdot.net>
  • Loading branch information
jeremyevans and ko1 committed Jul 29, 2021
1 parent 12d4da7 commit 35a6385
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 0 deletions.
4 changes: 4 additions & 0 deletions gc.c
Expand Up @@ -4088,10 +4088,14 @@ static void
finalize_deferred(rb_objspace_t *objspace)
{
VALUE zombie;
rb_execution_context_t *ec = GET_EC();
ec->interrupt_mask |= PENDING_INTERRUPT_MASK;

while ((zombie = ATOMIC_VALUE_EXCHANGE(heap_pages_deferred_final, 0)) != 0) {
finalize_list(objspace, zombie);
}

ec->interrupt_mask &= ~PENDING_INTERRUPT_MASK;
}

static void
Expand Down
25 changes: 25 additions & 0 deletions test/ruby/test_objectspace.rb
Expand Up @@ -168,6 +168,31 @@ def test_exception_in_finalizer
end;
end

def test_finalizer_thread_raise
GC.disable
fzer = proc do |id|
sleep 0.2
end
2.times do
o = Object.new
ObjectSpace.define_finalizer(o, fzer)
end

my_error = Class.new(RuntimeError)
begin
main_th = Thread.current
Thread.new do
sleep 0.1
main_th.raise(my_error)
end
GC.start
puts "After GC"
sleep(10)
assert(false)
rescue my_error
end
end

def test_each_object
klass = Class.new
new_obj = klass.new
Expand Down

0 comments on commit 35a6385

Please sign in to comment.