例によってとあるソフトウェアで 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 <call_block>, 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 <return> to continue, or q <return> 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 <rb_thread_yield_0>, 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]