From: Tanaka Akira Date: 2005-04-30T15:00:59+09:00 Subject: [ruby-dev:26113] race condition in fixnum..fixnum ? 例によってとあるソフトウェアで core を吐いたので調べたところ、 fixnum..fixnum に race condition があるのではないかという気がしてきた のですが、実際のところどうなんでしょう? % gdb =ruby core-20050430-101106 GNU gdb 6.3-debian Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-linux"...Using host libthread_db library "/lib/libthread_db.so.1". Core was generated by `/home/akr/ruby/ruby/ruby -v ./main.rb -v'. Program terminated with signal 6, Aborted. Reading symbols from /lib/libdl.so.2...done. Loaded symbols for /lib/libdl.so.2 Reading symbols from /lib/libcrypt.so.1...done. Loaded symbols for /lib/libcrypt.so.1 Reading symbols from /lib/libm.so.6...done. Loaded symbols for /lib/libm.so.6 Reading symbols from /lib/libc.so.6...done. Loaded symbols for /lib/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 Reading symbols from /home/akr/ruby/lib/ruby/1.9/i686-linux/stringio.so...done. Loaded symbols for /home/akr/ruby/lib/ruby/1.9/i686-linux/stringio.so Reading symbols from /home/akr/ruby/lib/ruby/1.9/i686-linux/syck.so...done. Loaded symbols for /home/akr/ruby/lib/ruby/1.9/i686-linux/syck.so Reading symbols from /home/akr/ruby/lib/ruby/1.9/i686-linux/iconv.so...done. Loaded symbols for /home/akr/ruby/lib/ruby/1.9/i686-linux/iconv.so Reading symbols from /home/akr/ruby/lib/ruby/1.9/i686-linux/socket.so...done. Loaded symbols for /home/akr/ruby/lib/ruby/1.9/i686-linux/socket.so Reading symbols from /home/akr/ruby/lib/ruby/1.9/i686-linux/zlib.so...done. Loaded symbols for /home/akr/ruby/lib/ruby/1.9/i686-linux/zlib.so Reading symbols from /usr/lib/libz.so.1...done. Loaded symbols for /usr/lib/libz.so.1 Reading symbols from /home/akr/ruby/lib/ruby/1.9/i686-linux/etc.so...done. Loaded symbols for /home/akr/ruby/lib/ruby/1.9/i686-linux/etc.so Reading symbols from /home/akr/ruby/lib/ruby/1.9/i686-linux/fcntl.so...done. Loaded symbols for /home/akr/ruby/lib/ruby/1.9/i686-linux/fcntl.so #0 0x4009e741 in kill () from /lib/libc.so.6 (gdb) bt #0 0x4009e741 in kill () from /lib/libc.so.6 #1 0x4009e4c5 in raise () from /lib/libc.so.6 #2 0x4009fa08 in abort () from /lib/libc.so.6 #3 0x08103d4b in rb_bug (fmt=0x0) at error.c:214 #4 0x0805a2dd in rb_eval (self=1075930120, n=0x0) at eval.c:4006 #5 0x080597ca in rb_eval (self=1075930120, n=0x0) at eval.c:3226 #6 0x08057e12 in rb_eval (self=1075930120, n=0x0) at ruby.h:664 #7 0x08058c22 in rb_eval (self=1075930120, n=0x0) at eval.c:3116 #8 0x080574f9 in rb_eval (self=1075930120, n=0x0) at eval.c:3512 #9 0x0805663e in rb_eval (self=1075930120, n=0x0) at eval.c:2791 #10 0x08068cd3 in rb_call0 (klass=1075880280, recv=1075930120, id=4465, oid=0, argc=0, argv=0xbfff631c, body=0x4020cc3c, nosuper=0) at eval.c:5818 #11 0x0805c619 in rb_call (klass=1075880280, recv=1075930120, mid=1075880280, argc=1, argv=0xbfff6318, scope=0) at eval.c:5911 #12 0x08057d3b in rb_eval (self=1075930120, n=0x0) at ruby.h:635 #13 0x08058c22 in rb_eval (self=1075930120, n=0x0) at eval.c:3116 #14 0x080574f9 in rb_eval (self=1075930120, n=0x0) at eval.c:3512 #15 0x08068cd3 in rb_call0 (klass=1075880280, recv=1075930120, id=10505, oid=0, argc=0, argv=0xbfff784c, body=0x4020bf44, nosuper=0) at eval.c:5818 #16 0x0805c619 in rb_call (klass=1075880280, recv=1075930120, mid=1075880280, argc=1, argv=0xbfff7848, scope=0) at eval.c:5911 #17 0x08057d3b in rb_eval (self=1078604236, n=0x0) at ruby.h:635 #18 0x08057c0a in rb_eval (self=1078604236, n=0x0) at eval.c:3331 #19 0x0805ad78 in rb_yield_0 (val=401, self=1078604236, klass=0, flags=0, avalue=0) at eval.c:4881 #20 0x08058590 in rb_eval (self=1076335208, n=0x0) at eval.c:3133 #21 0x08057459 in rb_eval (self=1076335208, n=0x0) at eval.c:3193 #22 0x08068cd3 in rb_call0 (klass=1076335008, recv=1076335208, id=10937, oid=0, argc=0, argv=0xbfff95d0, body=0x4027a168, nosuper=0) at eval.c:5818 #23 0x0805c619 in rb_call (klass=1076335008, recv=1076335208, mid=1076335008, argc=2, argv=0xbfff95c8, scope=0) at eval.c:5911 #24 0x08057d3b in rb_eval (self=1078604236, n=0x0) at ruby.h:635 #25 0x0806c3fa in call_block (arg=0x401a45e0) at eval.c:8766 #26 0x0806c1ff in rb_block_pass (func=0x806c3e0 , arg=3221200384, proc=1079417616) at eval.c:8704 #27 0x0805fa6b in block_pass (self=6, node=0x401a45e0) at eval.c:8777 #28 0x08058cb2 in rb_eval (self=1078604236, n=0x0) at eval.c:3038 #29 0x08068cd3 in rb_call0 (klass=1075678496, recv=1078604236, id=10937, oid=0, argc=0, argv=0xbfffa66c, body=0x40279aec, nosuper=0) at eval.c:5818 #30 0x0805c619 in rb_call (klass=1075678496, recv=1078604236, mid=1075678496, argc=1, argv=0xbfffa668, scope=1) at eval.c:5911 ---Type to continue, or q to quit--- #31 0x08057d3b in rb_eval (self=1078604236, n=0x0) at ruby.h:635 #32 0x0805a1ba in rb_eval (self=1078604236, n=0x0) at eval.c:3053 #33 0x0805753a in rb_eval (self=1078604236, n=0x0) at eval.c:3518 #34 0x0805730c in rb_eval (self=1078604236, n=0x0) at eval.c:3144 #35 0x08068cd3 in rb_call0 (klass=1077341436, recv=1078604236, id=6617, oid=0, argc=0, argv=0xbfffc1fc, body=0x401c13dc, nosuper=0) at eval.c:5818 #36 0x0805c619 in rb_call (klass=1077341436, recv=1078604236, mid=1077341436, argc=1, argv=0xbfffc1f8, scope=1) at eval.c:5911 #37 0x08057d3b in rb_eval (self=1078604236, n=0x0) at ruby.h:635 #38 0x08058c22 in rb_eval (self=1078604236, n=0x0) at eval.c:3116 #39 0x080574f9 in rb_eval (self=1078604236, n=0x0) at eval.c:3512 #40 0x08068cd3 in rb_call0 (klass=1077341436, recv=1078604236, id=10841, oid=0, argc=0, argv=0x0, body=0x401c3204, nosuper=0) at eval.c:5818 #41 0x0805c619 in rb_call (klass=1077341436, recv=1078604236, mid=1077341436, argc=0, argv=0x0, scope=0) at eval.c:5911 #42 0x08057d3b in rb_eval (self=1077338596, n=0x0) at ruby.h:635 #43 0x0805ad78 in rb_yield_0 (val=1078604236, self=1077338596, klass=0, flags=0, avalue=0) at eval.c:4881 #44 0x08058590 in rb_eval (self=1078851976, n=0x0) at eval.c:3133 #45 0x08059e17 in rb_eval (self=1078851976, n=0x0) at ruby.h:664 #46 0x08056ef1 in rb_eval (self=1078851976, n=0x0) at eval.c:2976 #47 0x0805ad78 in rb_yield_0 (val=1079570576, self=1078851976, klass=0, flags=1, avalue=2) at eval.c:4881 #48 0x0806e259 in rb_thread_yield_0 (arg=0) at eval.c:11948 #49 0x0806c0e5 in rb_block_pass (func=0x806e130 , arg=1079570576, proc=1079570516) at eval.c:8728 #50 0x080623c1 in rb_thread_start_1 () at eval.c:11902 #51 0x080677be in ruby_exec_internal () at eval.c:1538 #52 0x0806455c in ruby_run () at eval.c:1550 #53 0x08053f4e in main (argc=0, argv=0x0, envp=0xbffff9a8) at main.c:46 (gdb) up #1 0x4009e4c5 in raise () from /lib/libc.so.6 (gdb) #2 0x4009fa08 in abort () from /lib/libc.so.6 (gdb) #3 0x08103d4b in rb_bug (fmt=0x0) at error.c:214 214 abort(); (gdb) #4 0x0805a2dd in rb_eval (self=1075930120, n=0x0) at eval.c:4006 4006 rb_bug("unknown node type %d (0x%lx)", nd_type(node), (long)node); 個人的に、ここで node を表示させていて、core dump 時の出力に [BUG] unknown node type 0 (0x405417c8) と出てきているので、怪しいのは 0x405417c8 というものらしいです。 (gdb) rp 0x405417c8 T_OBJECT(0x405417c8) rp というのは個人的に持っている gdb マクロですがそれはそれとして、なん か T_NODE じゃなくて T_OBJECT が出てきています。 (gdb) up #5 0x080597ca in rb_eval (self=1075930120, n=0x0) at eval.c:3226 3226 result = rb_range_new(rb_eval(self, node->nd_beg), どうも NODE_DOT2 もしくは NODE_DOT3 の実行で変になっているようです。 (gdb) p node $1 = (NODE * volatile) 0x4020d920 (gdb) p *(struct RNode *)node $2 = {flags = 12565279, nd_file = 0x81b07f9 "/home/akr/ruby/lib/ruby/1.9/uri/common.rb", u1 = {node = 0x405417c8, id = 1079252936, value = 1079252936, cfunc = 0x405417c8, tbl = 0x405417c8}, u2 = {node = 0x4020d934, id = 1075894580, argc = 1075894580, value = 1075894580}, u3 = {node = 0x0, id = 0, state = 0, entry = 0x0, cnt = 0, value = 0}} (gdb) rp 0x405417c8 T_OBJECT(0x405417c8) (gdb) rp 0x4020d934 T_NODE(0x4020d934) $3 = 247 nd_beg が T_OBJECT になっているようです。 (gdb) p *(struct RObject *)0x405417c8 $4 = {basic = {flags = 2, klass = 1075638456}, iv_tbl = 0x87f2ef8} (gdb) p rb_cRange $5 = 1075638456 (gdb) 問題のオブジェクトは Range オブジェクトのようです。 というような症状で、原因を考えたところ、NODE_DOT から NODE_LIT に置換 するところで怪しげなことが起こっているのではないかと推測しました。 つまり、 case NODE_DOT2: case NODE_DOT3: result = rb_range_new(rb_eval(self, node->nd_beg), rb_eval(self, node->nd_end), nd_type(node) == NODE_DOT3); if (node->nd_state) break; if (nd_type(node->nd_beg) == NODE_LIT && FIXNUM_P(node->nd_beg->nd_lit) && nd_type(node->nd_end) == NODE_LIT && FIXNUM_P(node->nd_end->nd_lit)) { nd_set_type(node, NODE_LIT); node->nd_lit = result; } else { node->nd_state = 1; } break; というコードが、nd_lit に result が代入された後にまた実行されるという 想定です。 とりあえず、スレッドではないかと見当をつけて、 Index: eval.c =================================================================== RCS file: /src/ruby/eval.c,v retrieving revision 1.776 diff -u -p -r1.776 eval.c --- eval.c 30 Apr 2005 02:59:41 -0000 1.776 +++ eval.c 30 Apr 2005 05:45:41 -0000 @@ -3223,6 +3223,7 @@ rb_eval(self, n) case NODE_DOT2: case NODE_DOT3: + rb_thread_schedule(); result = rb_range_new(rb_eval(self, node->nd_beg), rb_eval(self, node->nd_end), nd_type(node) == NODE_DOT3); というパッチを当ててそこでコンテキストスイッチが確実に起こるようにした ところ、 % ./ruby -e ' def m 0..1 end t1 = Thread.new { m } t2 = Thread.new { m } t1.join t2.join ' : [BUG] unknown node type 0 ruby 1.9.0 (2005-04-30) [i686-linux] というように再現した感じです。 で、実際のところどうなんでしょう? 変更を加えなくても推測した問題は起きうるものでしょうか? -- [田中 哲][たなか あきら][Tanaka Akira]