Bug #9205
closedAssertion failed: heap_pages_deferred_final == 0
Added by phasis68 (Heesob Park) almost 12 years ago. Updated almost 12 years ago.
Description
If I run the following code:
raise_proc = proc do |id|
  p "Finalizer one on #{id}" 
end
10000.times do
  ObjectSpace.define_finalizer(Object.new, raise_proc)
end
I can see an assertion failure.
"Finalizer one on 24535120"
Assertion failed: heap_pages_deferred_final == 0, file gc.c, line 2111
Same error with ruby 2.0.0p353 (2013-11-22) [i386-mingw32]
Files
| fix_assertion_fail.patch (981 Bytes) fix_assertion_fail.patch | phasis68 (Heesob Park), 12/04/2013 12:39 PM | 
        
          
          Updated by phasis68 (Heesob Park) almost 12 years ago
          
          
        
        
          
            Actions
          
          #1
            [ruby-core:58844]
        
      
      - File fix_assertion_fail.patch fix_assertion_fail.patch added
 
I found that make_deferred function of gc.c modified the value of heap_pages_deferred_final to nonzero.
I made a draft patch and I am not sure this patch is the best.
Anyway, it fixed the assertion and passed test-all.
        
          
          Updated by nobu (Nobuyoshi Nakada) almost 12 years ago
          
          
        
        
          
            Actions
          
          #2
            [ruby-core:58850]
        
      
      It doesn't seem nice to just ignore finalizers while running other finalizers.
diff --git c/gc.c i/gc.c
index ddf607c..0d18031 100644
--- c/gc.c
+++ i/gc.c
@@ -2055,10 +2055,10 @@ finalize_list(rb_objspace_t *objspace, RVALUE *p)
 static void
 finalize_deferred(rb_objspace_t *objspace)
 {
-    RVALUE *p = heap_pages_deferred_final;
-    heap_pages_deferred_final = 0;
+    RVALUE *p;
 
-    if (p) {
+    while ((p = heap_pages_deferred_final) != 0) {
+	heap_pages_deferred_final = 0;
 	finalize_list(objspace, p);
     }
 }
diff --git c/test/ruby/test_gc.rb i/test/ruby/test_gc.rb
index 034a330..2b1e6a5 100644
--- c/test/ruby/test_gc.rb
+++ i/test/ruby/test_gc.rb
@@ -238,4 +238,19 @@ class TestGc < Test::Unit::TestCase
     assert_not_nil GC::INTERNAL_CONSTANTS[:HEAP_OBJ_LIMIT]
     assert_not_nil GC::INTERNAL_CONSTANTS[:RVALUE_SIZE]
   end
+
+  def test_raise_in_finalizer
+    bug9205 = '[ruby-core:58833] [Bug #9205]'
+    100.times do
+      assert_ruby_status([], <<-'end;', bug9205)
+        STDOUT.sync = true
+        raise_proc = proc do |id|
+          p "Finalizer one on #{id}"
+        end
+        10000.times do
+          ObjectSpace.define_finalizer(Object.new, raise_proc)
+        end
+      end;
+    end
+  end
 end
        
          
          Updated by phasis68 (Heesob Park) almost 12 years ago
          
          
        
        
          
            Actions
          
          #3
            [ruby-core:58851]
        
      
      You are right.
Why not commit your patch?
        
          
          Updated by nobu (Nobuyoshi Nakada) almost 12 years ago
          
          
        
        
          
            Actions
          
          #4
            [ruby-core:58864]
        
      
      I've misread the code, like as raise_proc raises an exception and that triggers the failure.
But the proc raises nothing, then what would trigger it?
        
          
          Updated by phasis68 (Heesob Park) almost 12 years ago
          
          
        
        
          
            Actions
          
          #5
            [ruby-core:58865]
        
      
      My test code is different from Bug #9168.
I guess the name raise_proc made confusion.
It is just repeated finalizer test without raising an exception.
        
          
          Updated by nobu (Nobuyoshi Nakada) almost 12 years ago
          
          
        
        
          
            Actions
          
          #6
        
      
      - Status changed from Open to Closed
 - % Done changed from 0 to 100
 
This issue was solved with changeset r43994.
Heesob, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.
gc.c: flush all deferred finalizers
- gc.c (
finalize_deferred): flush all deferred finalizers while other
finalizers can get ready to run newly by lazy sweep.
[ruby-core:58833] [Bug #9205] 
        
          
          Updated by nagachika (Tomoyuki Chikanaga) almost 12 years ago
          
          
        
        
          
            Actions
          
          #7
            [ruby-core:58871]
        
      
      - Backport changed from 1.9.3: UNKNOWN, 2.0.0: UNKNOWN to 1.9.3: UNKNOWN, 2.0.0: REQUIRED
 
        
          
          Updated by nagachika (Tomoyuki Chikanaga) almost 12 years ago
          
          
        
        
          
            Actions
          
          #8
            [ruby-core:59245]
        
      
      - Backport changed from 1.9.3: UNKNOWN, 2.0.0: REQUIRED to 1.9.3: UNKNOWN, 2.0.0: DONE
 
r43994 was backported to ruby_2_0_0 at r44319.
        
          
          Updated by nagachika (Tomoyuki Chikanaga) almost 12 years ago
          
          
        
        
          
            Actions
          
          #9
            [ruby-core:59249]
        
      
      ... and r44000 was also backported to ruby_2_0_0 at r44322.
        
          
          Updated by usa (Usaku NAKAMURA) almost 12 years ago
          
          
        
        
          
            Actions
          
          #11
            [ruby-core:60339]
        
      
      - Backport changed from 1.9.3: UNKNOWN, 2.0.0: DONE to 1.9.3: DONE, 2.0.0: DONE
 
backported into ruby_1_9_3 at r44764.