シグナルハンドラが呼ぶvfprintfとかfprintf。
AIXでのバグをいくつかあげてくれたPerryさんから私信があって、情報を送ってくれたりしていたのですが、そのなかで[ruby-core:29497]の話がありました。
たとえばテストの中にある
% cat fail.rb begin 10000.times { Thread.new(true) {|x| x == false } } rescue NoMemoryError, StandardError end p :ok
ですが、たまにとまってしまいます。これだけ実行すると
% ruby fail.rb
fail.rb:2: [BUG]
こんな感じで止まります。デバッガでアタッチすると、
ptrgl.$PTRGL() at 0xd0344750 malloc_y.malloc_y(0xc, 0x0, 0x20035870, 0x0, 0x0, 0x6c740049, 0x6d, 0x101f7550) at 0xd03c5b80 malloc_common.malloc_common_80_63(??) at 0xd0351634 _cleanup_push_72_6(??, ??, ??, ??) at 0xd01177b4 fwrite.fwrite_5_4(??, ??, ??, ??) at 0xd035ba94 doprnt._doprnt(??, ??, ??) at 0xd0353774 printf.vfprintf(??, ??, ??) at 0xd0352fc4 report_bug(file = (nil), line = 0, fmt = (nil), args = (nil)), line 225 in "error.c" rb_bug(fmt = "Segmentation fault", ... = 0x200028b8, 0x2e022a20, 0x100000, 0x633333, 0xd032, 0x20456000, 0x3002f0b0), li ne 245 in "error.c" sigsegv(sig = 0, info = (nil), ctx = (nil)), line 617 in "signal.c"
で、ためしに配列を自動変数で取っておいて、vsnprintfしてfputsすると進むことがわかりました。malloc()しなそうな気がしただけです。
この先にもあるいくつかの関数でfprintfをsnprintf&fputsに摩り替えたりしていくと、ハングするまで出るものが増えます。
% ruby fail.rb fail.rb:2: [BUG] Segmentation fault ruby 1.9.2dev (2010-04-13 trunk 27329) [powerpc-aix5.3.0.0] -- control frame ---------- c:0007 p:---- s:0017 b:0017 l:000016 d:000016 CFUNC :new c:0006 p:0017 s:0013 b:0013 l:001e3c d:000012 BLOCK fail.rb:2 c:0005 p:---- s:0011 b:0011 l:000010 d:000010 FINISH c:0004 p:---- s:0009 b:0009 l:000008 d:000008 CFUNC :times c:0003 p:0012 s:0006 b:0006 l:001e3c d:001d7c EVAL fail.rb:2 c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH c:0001 p:0000 s:0002 b:0002 l:001e3c d:001e3c TOP --------------------------- -- Ruby level backtrace information ---------------------------------------- fail.rb:2:in `<main>' fail.rb:2:in `times' fail.rb:2:in `block in <main>' fail.rb:2:in `new' [NOTE] You may have encountered a bug in the Ruby interpreter or extension libraries. Bug reports are welcome. For details: http://www.ruby-lang.org/bugreport.html
が、しかし!ここでまだハング。
ptrgl._ptrgl() at 0xd0344750 malloc_y.malloc_y(0xc, 0x0, 0x20035c30, 0x0, 0x0, 0x101b2051, 0x0, 0x0) at 0xd03c5b80 malloc_common.malloc_common_80_63(??) at 0xd0351634 _cleanup_push_72_6(??, ??, ??, ??) at 0xd01177b4 flsbuf._cleanup() at 0xd035c6f8 abort.abort() at 0xd03c8b2c rb_bug(fmt = "Segmentation fault", ... = 0x20002c70, 0x2e022a20, 0x100000, 0x633333, 0xd032, 0x2b2bb400, 0x3002f0b0), line 261 in "error.c" sigsegv(sig = 0, info = (nil), ctx = (nil)), line 617 in "signal.c"
abort()のなかでもやっちまっているみたいで、手の施しようがありません。
たとえばこことかみると、abort()は非同期シグナルセーフなはずなんですが。AIXではSIGSEGVのハンドラを入れないぐらいしか思いつきません。ほかのOSでハングしないかと思ってとりあえずnetbsdを入れたりしています。