From: "authorNari (Narihiro Nakamura)" Date: 2012-05-28T12:17:39+09:00 Subject: [ruby-dev:45684] [ruby-trunk - Bug #5254][Closed] class オブジェクトの開放時に segv Issue #5254 has been updated by authorNari (Narihiro Nakamura). Status changed from Assigned to Closed % Done changed from 0 to 100 r35827 で修正しました。 ---------------------------------------- Bug #5254: class オブジェクトの開放時に segv https://bugs.ruby-lang.org/issues/5254#change-26869 Author: Anonymous Status: Closed Priority: Normal Assignee: authorNari (Narihiro Nakamura) Category: core Target version: 2.0.0 ruby -v: - 芝と申します。 次のようなコードを実行すると、gc の sweep フェーズで segv します。 # 再現コード #################################### class BasicObject def singleton_method_added(mid) raise end end b = proc {} class << b; end b.clone #################################### b.clone では、class.c 内の rb_singleton_class_clone を呼び出し、class オ ブジェクトの複製をします。このとき、class_alloc を呼び出して生の class オブジェクトを割り当てるんですが、メソッドテーブルの割り当てを行う前に singleton_method_added のコールバックを呼び出しています。このため、 singleton_method_added のコールバックで例外を吐いたときに、メソッドテー ブルの割り当てが行われていない class オブジェクトが出来てしまっています。 obj_free では、class オブジェクトの開放時に、メソッドテーブルが割り当て られているかどうかのチェック無しに、rb_free_m_table(RCLASS_M_TBL(obj)); とし、メソッドテーブルを開放しようとします。rb_free_m_table は、引数とし てわたってくるハッシュテーブルが NULL ではないものとして処理を進めている ため、上に記述したような、メソッドテーブルの割り当てが行われていない class オブジェクトを開放しようとしたときに、segv を吐いてしまうようです。 obj_free からの呼び出し関係と segv の位置は次のような感じです。 obj_free rb_free_m_table st_foreach if (table->entries_packed) { <= ここで segv これに対する対処としては、rb_singleton_class_clone のメソッドテーブル初 期化の位置をずらすか、obj_free でメソッドテーブルの解放前にメソッドテー ブルが割り当てられているかどうかのチェックをするかの2つがあります。 rb_singleton_class_clone のように、class オブジェクトの初期化とコール バックの呼び出しを共に行うような処理が他に無いとも限らないので、obj_free 側に手を加えるのがいいと思います。本メール末尾にそのようなパッチを添付し ておきます。 参考にしていただければ幸いです。 よろしくお願いいたします。 # パッチ Index: gc.c =================================================================== --- gc.c (revision 33101) +++ gc.c (working copy) @@ -2273,7 +2273,9 @@ case T_MODULE: case T_CLASS: rb_clear_cache_by_class((VALUE)obj); - rb_free_m_table(RCLASS_M_TBL(obj)); + if (RCLASS_M_TBL(obj)) { + rb_free_m_table(RCLASS_M_TBL(obj)); + } if (RCLASS_IV_TBL(obj)) { st_free_table(RCLASS_IV_TBL(obj)); } -- http://bugs.ruby-lang.org/