Project

General

Profile

Bug #3940

Lazy sweep and ObjectSpace.each_object

Added by ko1 (Koichi Sasada) almost 10 years ago. Updated over 9 years ago.

Status:
Closed
Priority:
Normal
Target version:
ruby -v:
ruby 1.9.3dev (2010-10-13 trunk 29477)
Backport:
[ruby-dev:42369]

Description

=begin
 ささだです。

 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
=end

Also available in: Atom PDF