From: Toshio Maki Date: 2010-03-29T10:31:51+09:00 Subject: [ruby-dev:40823] Re: Ruby+SWIGでGC実行時に不正なマークをしている可能性があります  牧です。お世話になっております。  連絡が遅れましたが、本件無事に解決したので報告させていただきます。  本件は金田様のご指摘の通り、SWIGのバグが原因で発生するものでした。  gc.cのマーク処理において配列の長さまでのマークしか行わないため、元のコー ドのようにループの最後でサイズを変更するような処理だと、ループ中に作成し たオブジェクトにはマークが行われないため、gcによって削除されるようです。  そこで、今回は修正としてswig/1.3.36/ruby/rubycontainer.swgに対して以下 のような修正を行いました。これによってswigの生成するコードが正しく生成さ れ、問題が解決することを確認しました。 --- Lib/ruby/rubycontainer.swg.bak 2010-03-19 10:42:30.000000000 +0900 +++ Lib/ruby/rubycontainer.swg 2010-03-19 10:55:22.000000000 +0900 @@ -1089,9 +1089,8 @@ int i = 0; for (const_iterator it = seq.begin(); it != seq.end(); ++it, ++i) { - RARRAY_PTR(obj)[i] = swig::from< value_type >(*it); + rb_ary_push(obj, swig::from< value_type >(*it)); } - RARRAY_LEN(obj) = size; rb_obj_freeze(obj); // treat as immutable result return obj; } else {  今回はrb_ary_pushによる修正を行いましたが、金田様のご指摘の通り、初め に配列をQnilで初期化しておいた方が高速だと思います。  本件の問題解決にご協力していただき、ありがとうございました。 > 金田と申します。 > > 下記の件ですがSWIGが生成するコードが不適切なのが原因の可能性があります。 > SWIG Version 1.3.36 > で添付ファイルの.iファイルから external_lib_wrap.cxx を生成すると > 次のようなコードが 3890行目付近で生成されます。 > > > VALUE obj = rb_ary_new2((int)size); > int i = 0; > for (const_iterator it = seq.begin(); > it != seq.end(); ++it, ++i) { > RARRAY_PTR(obj)[i] = swig::from< value_type >(*it); > } > RARRAY_LEN(obj) = size; > rb_obj_freeze(obj); // treat as immutable result > > この処理は不適切です。 > swig::from< value_type >(*it) でオブジェクトを > 生成した際にGCが発生した場合、 obj の配列に格納済みのオブジェクトが > GC で回収されてしまい不正となります。これは上記の処理では配列に > 格納済みのオブジェクトが GC の mark対象とならないためです。 > > 実際、この処理の前後に rb_gc_disable(); / rb_gc_enable(); を加えると > 正常に処理が進みます。 > > もしくは > RARRAY_PTR(obj)[i] = swig::from< value_type >(*it); > の代わりに > rb_ary_push(obj, swig::from< value_type >(*it)); > を使ってももよいようです。 > この場合 RARRAY_LEN(obj) = size; は削除しておく必要があります。 > > rb_gc_disable() や rb_ary_pushを使うよりは > 最初に全て Qnil を配列に埋めてからオブジェクトを > 格納した方が高速化もしれませんがこちらは試していません。 > > ----- Original Message ----- > 送信者: Toshio Maki > 宛先: ruby-dev@ruby-lang.org > 日付:Thursday, March, 18, 2010, 02:57 PM > 件名: [ruby-dev:40694] Ruby+SWIGでGC実行時に不正なマークをしている可能性があります > > >  初めまして。牧と申します。 > > > >  Ruby+SWIGを用いたプログラムでSIGSEGVが発生するので、原因を調査していた > > のですが、gc_mark付近が怪しいので、報告させていただきます。 > > > > 現象 > >  SWIGでSTLをラップした関数を自動生成し、Ruby側から呼び出したときに、 > > SIGSEGVやNotImplementedErrorが発生します。 > > > > その1 > >  SIGSEGVでアボートするケース。コアのスタックトレースは以下の通りです。 > > > > #0 0x000000337b030265 in raise () from /lib64/libc.so.6 > > #1 0x000000337b031d10 in abort () from /lib64/libc.so.6 > > #2 0x0000000000499878 in rb_bug (fmt=0x4b5f0d "Segmentation fault") at error.c:213 > > #3 0x00000000004706aa in sigsegv (sig=) at signal.c:634 > > #4 > > #5 st_lookup (table=0x0, key=3137, value=0x7fff3d254a40) at st.c:250 > > #6 0x0000000000411595 in search_method (klass=47793957212960, id=3137, origin=0x7fff3d254 > a78) at eval.c:486 > > #7 0x0000000000411607 in rb_get_method_body (klassp=0x7fff3d254ac0, idp=0x7fff3d254ac8, n > oexp=0x7fff3d254ad4) at eval.c:507 > > #8 0x000000000041c205 in rb_call (klass=47793957212960, recv=47793957213000, mid=3137, ar > gc=0, argv=0x0, scope=1, self=6) at eval.c:6150 > > #9 0x000000000041c7e8 in vafuncall (recv=47793957213000, mid=3137, n=7219792, ar= ptimized out>) at eval.c:6253 > > #10 0x000000000041ca73 in rb_funcall (recv=0, mid=3137, n=1025854016) at eval.c:6270 > > > > その2 > >  NotImplementedErrorが発生する。(添付のソースは以下の現象が発生) > > > > call_external_lib.rb:6:in `p': method `inspect' called on terminated object (0x2b1a83bc88d > 8) (NotImplementedError) > > from call_external_lib.rb:6 > > from call_external_lib.rb:5:in `each' > > from call_external_lib.rb:5 > > from call_external_lib.rb:4:in `each' > > from call_external_lib.rb:4 > > > > > >  再現環境 > >  gcc バージョン 4.1.2 20080704 (Red Hat 4.1.2-46) > >  ruby 1.8.7 (2009-12-24 patchlevel 249) [x86_64-linux] > >  SWIG Version 1.3.29 Compiled with g++ [i686-redhat-linux-gnu] > > > >  また環境依存のせいか、発生しないケースもあります。 > > > > ・再現した > >  Red Hat Enterprise Linux Server release 5.4 (Tikanga) x86_64 > >  Ubuntu 09-10 32bit > > > > ・再現しない > >  CentOS release 5.4 (Final) 32bit > > > > > > 原因? > >  C側で生成したvectorのポインタをData_Wrap_structでRubyのVALUEに変換する > > 際に、rb_newobjがGCを呼ぶので、その際に呼ばれたgc_markやmark_tblが何かやっ > > ているのではないかと考えています。ruby側でGC.disableやC側でrb_gc_disable > > を実行しておくと発生しません。 > > > > 類似? > >  同じ現象かどうかは分かりませんが、以前にも似たような報告があったようで > > す。 > > Segmentation fault in garbage collector ruby 1.8.7 (2008-10-31 revision 0) [x86_64-linux] > >  http://redmine.ruby-lang.org/issues/show/706 > > > > /***************************************************/ > > 日立ソフトウェアエンジニアリング株式会社 > > 技術開発本部 Rubyセンタ > > > > 牧 俊男 > > /***************************************************/ > > /***************************************************/ 日立ソフトウェアエンジニアリング株式会社 技術開発本部 Rubyセンタ 牧 俊男 /***************************************************/