ささだです。

 Lazy sweep 中に ObjectSpace.each_object(相当)を行うと、SEGV するの
で、下記のようなパッチを作成しました。

# 32bit 環境の test-all で、最近 sdbm で SEGV してたのは多分これが問題。
# ObjectSpace.each_object を使っているので。


 推測ですが、下記のような原因ではないかと思います。

(1) GC mark 終了時、オブジェクト o1 と、そこから参照される o2 が
    mark されず、sweep 対象になる
(2) lazy sweep により、o2 が回収される
(3) ObjectSpace.each_object により、o1 へアクセスする
(4) o1 から o2 を参照しようとして SEGV

 解決策として、中田さんに ObjectSpace.each_object に相当する関数
rb_objspace_each_objects を実行する前に sweep を完全に終了させる、という
方法を教えてもらいました。

 バグの確認コードとパッチをお送りします。もし、適当でしたら取り込んで頂
けると幸いです。


確認コード:

loop{
  cls = (0..10_000).map{Class.new}
  cls.each{|c| c.new}
  ObjectSpace.each_object{|e| e.object_id; ''}
}

パッチ:

Index: gc.c
===================================================================
--- gc.c	(revision 29471)
+++ gc.c	(working copy)
@@ -2040,6 +2040,17 @@
     return FALSE;
 }

+static void
+rest_sweep(rb_objspace_t *objspace)
+{
+    if (objspace->heap.sweep_slots) {
+	while (objspace->heap.sweep_slots) {
+	    lazy_sweep(objspace);
+	}
+	after_gc_sweep(objspace);
+    }
+}
+
 static void gc_marks(rb_objspace_t *objspace);

 static int
@@ -2536,6 +2547,8 @@
     rb_objspace_t *objspace = &rb_objspace;
     volatile VALUE v;

+    rest_sweep(objspace);
+
     i = 0;
     while (i < heaps_used) {
 	while (0 < i && (uintptr_t)membase <
(uintptr_t)objspace->heap.sorted[i-1].slot->membase)

-- 
// SASADA Koichi at atdot dot net