From: Tanaka Akira Date: 2008-01-05T03:28:54+09:00 Subject: [ruby-dev:32922] SEGV by regexp match in while loop Debian GNU/Linux (sarge) の gcc-3.4 を使ってビルドした ruby で、以下のようにすると SEGV します。 % svn co http://svn.ruby-lang.org/repos/ruby/trunk ruby ... % autoconf % ./configure --prefix=/tmp/a CC=gcc-3.4 ... % make ... % ./miniruby -ve 'while true; /a/ =~ "a"; end' ruby 1.9.0 (2008-01-05 revision 0) [i686-linux] zsh: segmentation fault ./miniruby -ve 'while true; /a/ =~ "a"; end' スタックサイズを変えると落ちるまでの時間が変わるのでどうもス タックオーバーフローのようです。 私の試した環境だと、スタックサイズ 8Mbytes の場合数秒で落ち ます。 以下はスタックサイズを 2Mbytes として調べたものです。 % limit cputime unlimited filesize unlimited datasize unlimited stacksize 2MB coredumpsize 0kB memoryuse unlimited maxproc 27643 descriptors 1024 memorylocked 32kB addressspace unlimited maxfilelocks unlimited % gdb miniruby 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/tls/libthread_db.so.1". (gdb) run -ve 'while true; /a/ =~ "a"; end' Starting program: /tmp/a/ruby/miniruby -ve 'while true; /a/ =~ "a"; end' [Thread debugging using libthread_db enabled] [New Thread -1210779968 (LWP 14167)] [New Thread -1211511888 (LWP 14170)] ruby 1.9.0 (2008-01-05 revision 0) [i686-linux] Program received signal SIGSEGV, Segmentation fault. [Switching to Thread -1210779968 (LWP 14167)] match_at (reg=0x81a7f18, str=0xb7ad5958 "a", end=0xb7ad5959 "", sstart=0xb7ad5958 "a", sprev=0x0, msa=0xbf96bda0) at regexec.c:1290 1290 STACK_PUSH_ENSURED(STK_ALT, FinishCode); /* bottom stack */ スタックポインタ近辺を調べてみるとたしかにメモリが途切れてい るようです。 (gdb) p $sp $1 = (void *) 0xbf96afe0 (gdb) x $sp 0xbf96afe0: Cannot access memory at address 0xbf96afe0 (gdb) x $sp+1 0xbf96afe1: Cannot access memory at address 0xbf96afe1 (gdb) x $sp+4 0xbf96afe4: Cannot access memory at address 0xbf96afe4 (gdb) x $sp+10 0xbf96afea: Cannot access memory at address 0xbf96afea (gdb) x $sp+100 0xbf96b044: 0x08164f44 しかし、バックトレースを見るとそれほどスタックを消費している ようには見えません。 (gdb) bt #0 match_at (reg=0x81a7f18, str=0xb7ad5958 "a", end=0xb7ad5959 "", sstart=0xb7ad5958 "a", sprev=0x0, msa=0xbf96bda0) at regexec.c:1290 #1 0x080cd9e5 in onig_search (reg=0x81a7f18, str=0xb7ad5958 "a", end=0xb7ad5959 "", start=0xbf96bda0 "", range=0xb7ad5959 "", region=0x8164f24, option=0) at regexec.c:3608 #2 0x080bdbf3 in rb_reg_search (re=3083514820, str=3081591120, pos=0, reverse=0) at re.c:1069 #3 0x080be85d in reg_match_pos (re=3083514820, strp=0xbf96bed4, pos=0) at re.c:2209 #4 0x080be8c3 in rb_reg_match (re=0, str=3081591120) at re.c:2256 #5 0x08109a85 in vm_eval (th=0x8168160, initial=0) at insns.def:2014 #6 0x0810f3d0 in vm_eval_body (th=0x8168160) at vm.c:1148 #7 0x08110e83 in rb_iseq_eval (iseqval=3083514180) at vm.c:1357 #8 0x08070b9f in ruby_exec_node (n=0xb7cab324, file=0x81a71b1 "-e") at eval.c:229 #9 0x08074099 in ruby_run_node (n=0xb7cab324) at eval.c:259 #10 0x080584f0 in main (argc=3, argv=0xbfb68df4, envp=0xbfb68e04) at main.c:36 各スタックフレームを調べてみると、どうも、vm_eval のスタック フレームが激しく大きいようです。 (gdb) up #1 0x080cd9e5 in onig_search (reg=0x81a7f18, str=0xb7ad5958 "a", end=0xb7ad5959 "", start=0xbf96bda0 "", range=0xb7ad5959 "", region=0x8164f24, option=0) at regexec.c:3608 3608 MATCH_AND_RETURN_CHECK(orig_range); (gdb) #2 0x080bdbf3 in rb_reg_search (re=3083514820, str=3081591120, pos=0, reverse=0) at re.c:1069 1069 result = onig_search(RREGEXP(re)->ptr, (gdb) #3 0x080be85d in reg_match_pos (re=3083514820, strp=0xbf96bed4, pos=0) at re.c:2209 2209 return rb_reg_search(re, str, pos, 0); (gdb) #4 0x080be8c3 in rb_reg_match (re=0, str=3081591120) at re.c:2256 2256 long pos = reg_match_pos(re, &str, 0); (gdb) #5 0x08109a85 in vm_eval (th=0x8168160, initial=0) at insns.def:2014 2014 val = rb_reg_match(r, obj); (gdb) p $sp $3 = (void *) 0xbf96bed0 (gdb) p $fp $4 = (void *) 0xbfb68ab8 (gdb) p $fp-$sp $5 = 2083816 想像するに、vm_eval のループの中でスタックをどんどん動的に確 保していくようなことになっているんじゃないでしょうか。 なお、Debian GNU/Linux (etch) の gcc-3.4 では再現しませんで した。 -- [田中 哲][たなか あきら][Tanaka Akira]