From: "H.Yamamoto" Date: 2006-02-06T19:23:53+09:00 Subject: [ruby-dev:28305] Re: SEGV with zlib 山本です。 >|確保した順番に関係なく、オブジェクトIDの小さいほうから free 関数を >|呼んでいるように見えます。つまり >| >| A(0x03) -> B(0x02) -> C(0x04) >| >|のように参照されていると、B が解放されて A の free 関数が解放済みの B >|にアクセスしてしまうと。 > >そういうことです。で、それは仕様だと思ってます。 ううむ、仕様ですか。 >|zlib.c では gzfile_writer_end で一応 OBJ_IS_FREED という形でチェックしている >|のですが、flags に出鱈目な値が入っているので、意図したように働いていません。 > >開放されてりゃzeroになってるはずなんですがね。デタラメな値が >入っているってことは再利用されちゃってるのかな。 gc_sweep がこうなっているので、 if (!(p->as.basic.flags & FL_MARK)) { if (p->as.basic.flags) { obj_free((VALUE)p); } if (need_call_final && FL_TEST(p, FL_FINALIZE)) { p->as.free.flags = FL_MARK; /* remain marked */ p->as.free.next = final_list; final_list = p; } else { p->as.free.flags = 0; p->as.free.next = freelist; freelist = p; } n++; } 解放された T_DATA も freelist に繋がれて、再利用の対象になっていると思います。 //////////////////////////////////// // 検証用パッチ Index: gc.c =================================================================== RCS file: /src/ruby/gc.c,v retrieving revision 1.232 diff -u -w -b -p -r1.232 gc.c --- gc.c 6 Feb 2006 02:49:14 -0000 1.232 +++ gc.c 6 Feb 2006 10:12:05 -0000 @@ -1061,11 +1061,19 @@ gc_sweep(void) obj_free((VALUE)p); } if (need_call_final && FL_TEST(p, FL_FINALIZE)) { + if ((p->as.basic.flags & T_MASK) == T_DATA) { + printf("final_list =============> %p\n", p); + fflush(stdout); + } p->as.free.flags = FL_MARK; /* remain marked */ p->as.free.next = final_list; final_list = p; } else { + if ((p->as.basic.flags & T_MASK) == T_DATA) { + printf("freelist =============> %p\n", p); + fflush(stdout); + } p->as.free.flags = 0; p->as.free.next = freelist; freelist = p; Index: ext/zlib/zlib.c =================================================================== RCS file: /src/ruby/ext/zlib/zlib.c,v retrieving revision 1.29 diff -u -w -b -p -r1.29 zlib.c --- ext/zlib/zlib.c 14 Dec 2005 16:37:24 -0000 1.29 +++ ext/zlib/zlib.c 6 Feb 2006 10:07:54 -0000 @@ -2284,6 +2284,8 @@ gzfile_writer_end(gz) if (ZSTREAM_IS_FINALIZE(&gz->z)) { if (NIL_P(gz->io)) return; rb_warn("Zlib::GzipWriter object must be closed explicitly."); + printf("zlib -------------> %p, %d\n", gz->io, RBASIC(gz->io)->flags); + fflush(stdout); if (!SPECIAL_CONST_P(gz->io) && OBJ_IS_FREED(gz->io)) { aborted = 1; } //////////////////////////////////////////////////////// // 検証用スクリプト require 'zlib' class C def write(str) end end p o = C.new 100.times { p o = Zlib::GzipWriter.new(o) } o.write "a" $stdout.puts "--------------- 0" $stdout.flush o = nil GC.start $stdout.puts "--------------- 1" $stdout.flush //////////////////////////////////////////////////////// // 結果 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # --------------- 0 zlib -------------> 02AB4378, 18 freelist =============> 02AB4348 zlib -------------> 02AB43A8, 18 freelist =============> 02AB4378 zlib -------------> 02AB43D8, 18 freelist =============> 02AB43A8 zlib -------------> 02AB4408, 18 freelist =============> 02AB43D8 zlib -------------> 02AB4438, 18 freelist =============> 02AB4408 zlib -------------> 02AB4468, 18 freelist =============> 02AB4438 zlib -------------> 02AB4498, 18 freelist =============> 02AB4468 zlib -------------> 02AB44C8, 18 freelist =============> 02AB4498 zlib -------------> 02AB44F8, 18 freelist =============> 02AB44C8 zlib -------------> 02AB4528, 18 freelist =============> 02AB44F8 zlib -------------> 02AB4558, 18 freelist =============> 02AB4528 zlib -------------> 02AB4588, 18 freelist =============> 02AB4558 zlib -------------> 02AB45D0, 18 freelist =============> 02AB4570 zlib -------------> 02AB45B8, 18 freelist =============> 02AB4588 zlib -------------> 02AB4600, 18 freelist =============> 02AB45B8 zlib -------------> 02AB46C0, 18 freelist =============> 02AB45D0 zlib -------------> 02AB4618, 18 freelist =============> 02AB45E8 zlib -------------> 02AB4660, 18 freelist =============> 02AB4600 zlib -------------> 02AB4648, 18 freelist =============> 02AB4618 zlib -------------> 02AB4678, 18 freelist =============> 02AB4648 zlib -------------> 02AB4780, 18 freelist =============> 02AB4660 zlib -------------> 02AB46A8, 18 freelist =============> 02AB4678 zlib -------------> 02AB46F0, 18 freelist =============> 02AB4690 zlib -------------> 02AB46D8, 18 freelist =============> 02AB46A8 zlib -------------> 02AB47E0, 18 freelist =============> 02AB46C0 zlib -------------> 02AB4708, 18 freelist =============> 02AB46D8 zlib -------------> 02AB4750, 18 freelist =============> 02AB46F0 zlib -------------> 02AB4738, 18 freelist =============> 02AB4708 zlib -------------> 02AB4768, 18 freelist =============> 02AB4738 zlib -------------> 02AB47B0, 18 freelist =============> 02AB4750 zlib -------------> 02AB4798, 18 freelist =============> 02AB4768 zlib -------------> 02AB4840, 18 freelist =============> 02AB4780 zlib -------------> 02AB47C8, 18 freelist =============> 02AB4798 zlib -------------> 02AB4810, 18 freelist =============> 02AB47B0 zlib -------------> 02AB47F8, 18 freelist =============> 02AB47C8 zlib -------------> 02AB4960, 18 freelist =============> 02AB47E0 zlib -------------> 02AB4828, 18 freelist =============> 02AB47F8 zlib -------------> 02AB4870, 18 freelist =============> 02AB4810 zlib -------------> 02AB4858, 18 freelist =============> 02AB4828 zlib -------------> 02AB4900, 18 freelist =============> 02AB4840 zlib -------------> 02AB4888, 18 freelist =============> 02AB4858 zlib -------------> 02AB48D0, 18 freelist =============> 02AB4870 zlib -------------> 02AB48B8, 18 freelist =============> 02AB4888 zlib -------------> 02AB48E8, 18 freelist =============> 02AB48B8 zlib -------------> 02AB4930, 18 freelist =============> 02AB48D0 zlib -------------> 02AB4918, 18 freelist =============> 02AB48E8 zlib -------------> 02AB49C0, 18 freelist =============> 02AB4900 zlib -------------> 02AB4948, 18 freelist =============> 02AB4918 zlib -------------> 02AB4990, 18 freelist =============> 02AB4930 zlib -------------> 02AB4978, 18 freelist =============> 02AB4948 zlib -------------> 02AB4AE0, 18 freelist =============> 02AB4960 zlib -------------> 02AB49A8, 18 freelist =============> 02AB4978 zlib -------------> 02AB49F0, 18 freelist =============> 02AB4990 zlib -------------> 02AB49D8, 18 freelist =============> 02AB49A8 zlib -------------> 02AB4A80, 18 freelist =============> 02AB49C0 zlib -------------> 02AB4A08, 18 freelist =============> 02AB49D8 zlib -------------> 02AB4A50, 18 freelist =============> 02AB49F0 zlib -------------> 02AB4A38, 18 freelist =============> 02AB4A08 zlib -------------> 02AB4A68, 18 freelist =============> 02AB4A38 zlib -------------> 02AB4AB0, 18 freelist =============> 02AB4A50 zlib -------------> 02AB4A98, 18 freelist =============> 02AB4A68 zlib -------------> 02AB4B40, 18 freelist =============> 02AB4A80 zlib -------------> 02AB4AC8, 18 freelist =============> 02AB4A98 zlib -------------> 02AB4B10, 18 freelist =============> 02AB4AB0 zlib -------------> 02AB4AF8, 18 freelist =============> 02AB4AC8 zlib -------------> 02AB63E8, 18 freelist =============> 02AB4AE0 zlib -------------> 02AB4B28, 18 freelist =============> 02AB4AF8 zlib -------------> 02AB6370, 18 freelist =============> 02AB4B10 zlib -------------> 02AB4B58, 18 freelist =============> 02AB4B28 zlib -------------> 02AB63B8, 18 freelist =============> 02AB4B40 zlib -------------> 02AB4BE8, 34 freelist =============> 02AB4B58 zlib -------------> 02AB63A0, 18 freelist =============> 02AB6370 zlib -------------> 02AB63D0, 18 freelist =============> 02AB63A0 zlib -------------> 02AB6418, 18 freelist =============> 02AB63B8 zlib -------------> 02AB6400, 18 freelist =============> 02AB63D0 zlib -------------> 02AB6640, 18 freelist =============> 02AB63E8 zlib -------------> 02AB6430, 18 freelist =============> 02AB6400 zlib -------------> 02AB65C8, 18 freelist =============> 02AB6418 zlib -------------> 02AB6568, 18 freelist =============> 02AB6430 zlib -------------> 02AB6628, 18 freelist =============> 02AB6568 zlib -------------> 02AB6748, 18 freelist =============> 02AB65C8 zlib -------------> 02AB66A0, 18 freelist =============> 02AB6628 zlib -------------> 02AB6988, 18 freelist =============> 02AB6640 zlib -------------> 02AB6760, 18 freelist =============> 02AB66A0 zlib -------------> 02AB6928, 18 freelist =============> 02AB6748 zlib -------------> 02AB6838, 18 freelist =============> 02AB6760 zlib -------------> 02AB6940, 18 freelist =============> 02AB6838 zlib -------------> 02AB6AA8, 18 freelist =============> 02AB6928 zlib -------------> 02AB6A30, 18 freelist =============> 02AB6940 zlib -------------> 02AB6BF8, 18 freelist =============> 02AB6988 zlib -------------> 02AB6B38, 18 freelist =============> 02AB6A30 zlib -------------> 02AB6BB0, 18 freelist =============> 02AB6AA8 zlib -------------> 02AB6B98, 18 freelist =============> 02AB6B38 zlib -------------> 02AB6BC8, 18 freelist =============> 02AB6B98 zlib -------------> 02AB6C88, 18 freelist =============> 02AB6BB0 zlib -------------> 02AB6C70, 18 freelist =============> 02AB6BC8 zlib -------------> 02AB4348, 582687 この 02AB4348 は前に freelist ====> に出てくる値です。おそらく、 T_DATA の解放関数でオブジェクトが新規作成され、そのとき再利用 されるのでしょう。(それにしては flag の値がおかしい気もしますが) >|でも、これって zlib.c のバグというより GC のバグのような・・・ > >これをバグ認定するとすると、これから解放するオブジェクトに対 >して、再度マークスイープを実行して...、とかいうようなことを >する必要が出てくるわけなんですが、それだけのGCの速度低下を許 >容できる人はいないように思います。私が思いつかないだけで高速 >な実装が可能なのかもしれませんが。 私も GC に詳しいわけではないのですが、Boehm GC はどうなってる んでしょう。 ># えーと、今思いついたのは、たとえばスイープの前にマークされ ># てないT_DATAでもmark関数を呼んでおく(つまり、T_DATAからマー ># クされていると解放が1GCサイクル遅くなる)という手はあります ># けど、あんまりやりたくないです。 > >ということで、私としてはzlib.cに「finalizeの中で解放されてい >るかもしれないオブジェクトには触らないほうがよい(メソッド呼 >び出すとかもってのほか)」とアドバイスしたいところであります。 解放関数では Ruby オブジェクトを操作できない、ということでしょうか。 それならそれで明快な気もします。(zlib はバッファに RString を 使っているので、C のヒープを使うべきなんでしょうか)