Bug #13596
closedSegfault when catching SystemStackError in eval
Added by mjones (Morgan Jones) over 7 years ago. Updated over 7 years ago.
Description
This minimal testcase will crash most ruby versions with a SIGSEGV (though it's likely that other constructions could trigger the same behavior). Effectively, after the first SystemStackError that is caught from eval, a subsequent stack overflow will crash ruby rather than triggering another SystemStackError.
Failing testcase:
ruby -e "code = '+1' * 100000; 2.times {begin; eval code; rescue SystemStackError => e; p e; end}"
#<SystemStackError: stack level too deep>
[1] 23587 segmentation fault (core dumped) ruby -e
Succeeding testcase:
ruby -e "def x; x; end; 2.times {begin; x; rescue SystemStackError => e; p e; end}"
#<SystemStackError: stack level too deep>
#<SystemStackError: stack level too deep>
Updated by mjones (Morgan Jones) over 7 years ago
Here's a GDB trace with VMDEBUG=1 for a Ruby 2.4.1 checkout. It appears that the crash occurs when setting up the frame in iseq_compile_each, when the application tries to access rsp+8 (0x7fffff7fed50+8). This lands in the redzone page, and a segfault occurs.
$ gdb --args ./miniruby -e "code = '+1' * 100000; 2.times {begin; eval(code); rescue SystemStackError; end}"
GNU gdb (GDB) 7.12.1
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./miniruby...done.
warning: File "/home/numinit/ruby/.gdbinit" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
add-auto-load-safe-path /home/numinit/ruby/.gdbinit
line to your configuration file "/home/numinit/.gdbinit".
To completely disable this security protection add
set auto-load safe-path /
line to your configuration file "/home/numinit/.gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual. E.g., run from the shell:
info "(gdb)Auto-loading safe path"
(gdb) run
Starting program: /home/numinit/ruby/miniruby -e code\ =\ \'+1\'\ \*\ 100000\;\ 2.times\ \{begin\;\ eval\(code\)\;\ rescue\ SystemStackError\;\ end\}
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".
[New Thread 0x7ffff7e59700 (LWP 16284)]
| 0000 trace 1 ( 1)
| 0002 putstring "+1"
| 0004 putobject 100000
| 0006 opt_mult <callinfo!mid:*, argc:1, ARGS_SIMPLE>, <callcache>
| 0009 setlocal_OP__WC__0 3
| 0011 putobject 2
| 0013 send <callinfo!mid:times, argc:0>, <callcache>, block in <main>
| 0000 trace 256 ( 1)
| 0002 trace 1
| 0004 putself
| 0005 getlocal_OP__WC__1 3
| 0007 opt_send_without_block <callinfo!mid:eval, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
Thread 1 "miniruby" received signal SIGSEGV, Segmentation fault.
iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff7ff0d0, node=0x5555565c45f8,
popped=popped@entry=0) at compile.c:3961
3961 {
=> 0x00005555555afeea <iseq_compile_each+26>: 89 4c 24 08 mov DWORD PTR [rsp+0x8],ecx
(gdb) list
3956 node: Ruby compiled node
3957 popped: This node will be popped
3958 */
3959 static int
3960 iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popped)
3961 {
3962 enum node_type type;
3963 LINK_ELEMENT *saved_last_element = 0;
3964 int line;
3965
(gdb) info reg
rax 0x7fffff7ff130 140737479962928
rbx 0x555556709bc0 93825010801600
rcx 0x0 0
rdx 0x5555565c45f8 93825009468920
rsi 0x7fffff7ff0d0 140737479962832
rdi 0x555556709bc0 93825010801600
rbp 0x1 0x1
rsp 0x7fffff7fed50 0x7fffff7fed50
r8 0x3 3
r9 0x23 35
r10 0x0 0
r11 0x7ffff6fa64c0 140737336992960
r12 0x1 1
r13 0x5555565c4580 93825009468800
r14 0x7fffff7ff0d0 140737479962832
r15 0xa31b 41755
rip 0x5555555afeea 0x5555555afeea <iseq_compile_each+26>
eflags 0x10202 [ IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) info proc map
process 16280
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x555555554000 0x555555853000 0x2ff000 0x0 /home/numinit/ruby/miniruby
0x555555a53000 0x555555a58000 0x5000 0x2ff000 /home/numinit/ruby/miniruby
0x555555a58000 0x555555a59000 0x1000 0x304000 /home/numinit/ruby/miniruby
0x555555a59000 0x555556720000 0xcc7000 0x0 [heap]
0x7ffff6d35000 0x7ffff6e36000 0x101000 0x0
0x7ffff6e36000 0x7ffff6fd1000 0x19b000 0x0 /usr/lib/libc-2.25.so
0x7ffff6fd1000 0x7ffff71d0000 0x1ff000 0x19b000 /usr/lib/libc-2.25.so
0x7ffff71d0000 0x7ffff71d4000 0x4000 0x19a000 /usr/lib/libc-2.25.so
0x7ffff71d4000 0x7ffff71d6000 0x2000 0x19e000 /usr/lib/libc-2.25.so
0x7ffff71d6000 0x7ffff71da000 0x4000 0x0
0x7ffff71da000 0x7ffff72ec000 0x112000 0x0 /usr/lib/libm-2.25.so
0x7ffff72ec000 0x7ffff74eb000 0x1ff000 0x112000 /usr/lib/libm-2.25.so
0x7ffff74eb000 0x7ffff74ec000 0x1000 0x111000 /usr/lib/libm-2.25.so
0x7ffff74ec000 0x7ffff74ed000 0x1000 0x112000 /usr/lib/libm-2.25.so
0x7ffff74ed000 0x7ffff74f5000 0x8000 0x0 /usr/lib/libcrypt-2.25.so
0x7ffff74f5000 0x7ffff76f5000 0x200000 0x8000 /usr/lib/libcrypt-2.25.so
0x7ffff76f5000 0x7ffff76f6000 0x1000 0x8000 /usr/lib/libcrypt-2.25.so
0x7ffff76f6000 0x7ffff76f7000 0x1000 0x9000 /usr/lib/libcrypt-2.25.so
0x7ffff76f7000 0x7ffff7725000 0x2e000 0x0
0x7ffff7725000 0x7ffff7728000 0x3000 0x0 /usr/lib/libdl-2.25.so
0x7ffff7728000 0x7ffff7927000 0x1ff000 0x3000 /usr/lib/libdl-2.25.so
0x7ffff7927000 0x7ffff7928000 0x1000 0x2000 /usr/lib/libdl-2.25.so
0x7ffff7928000 0x7ffff7929000 0x1000 0x3000 /usr/lib/libdl-2.25.so
0x7ffff7929000 0x7ffff79bb000 0x92000 0x0 /usr/lib/libgmp.so.10.3.2
0x7ffff79bb000 0x7ffff7bba000 0x1ff000 0x92000 /usr/lib/libgmp.so.10.3.2
0x7ffff7bba000 0x7ffff7bbb000 0x1000 0x91000 /usr/lib/libgmp.so.10.3.2
0x7ffff7bbb000 0x7ffff7bbc000 0x1000 0x92000 /usr/lib/libgmp.so.10.3.2
0x7ffff7bbc000 0x7ffff7bd5000 0x19000 0x0 /usr/lib/libpthread-2.25.so
0x7ffff7bd5000 0x7ffff7dd4000 0x1ff000 0x19000 /usr/lib/libpthread-2.25.so
0x7ffff7dd4000 0x7ffff7dd5000 0x1000 0x18000 /usr/lib/libpthread-2.25.so
0x7ffff7dd5000 0x7ffff7dd6000 0x1000 0x19000 /usr/lib/libpthread-2.25.so
0x7ffff7dd6000 0x7ffff7dda000 0x4000 0x0
0x7ffff7dda000 0x7ffff7dfd000 0x23000 0x0 /usr/lib/ld-2.25.so
0x7ffff7e25000 0x7ffff7e56000 0x31000 0x0
0x7ffff7e56000 0x7ffff7e57000 0x1000 0x0
0x7ffff7e57000 0x7ffff7e5a000 0x3000 0x0
0x7ffff7e5a000 0x7ffff7ff2000 0x198000 0x0 /usr/lib/locale/locale-archive
0x7ffff7ff2000 0x7ffff7ff8000 0x6000 0x0
0x7ffff7ff8000 0x7ffff7ffa000 0x2000 0x0 [vvar]
0x7ffff7ffa000 0x7ffff7ffc000 0x2000 0x0 [vdso]
0x7ffff7ffc000 0x7ffff7ffd000 0x1000 0x22000 /usr/lib/ld-2.25.so
0x7ffff7ffd000 0x7ffff7ffe000 0x1000 0x23000 /usr/lib/ld-2.25.so
0x7ffff7ffe000 0x7ffff7fff000 0x1000 0x0
0x7fffff7ff000 0x7ffffffff000 0x800000 0x0 [stack]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]
(gdb) bt
#0 iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff7ff0d0, node=0x5555565c45f8,
popped=popped@entry=0) at compile.c:3961
#1 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff7ff3e0,
node=0x5555565c4580, popped=popped@entry=0) at compile.c:5265
#2 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff7ff6f0,
node=0x5555565c4508, popped=popped@entry=0) at compile.c:5265
#3 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff7ffa00,
node=0x5555565c4490, popped=popped@entry=0) at compile.c:5265
#4 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff7ffd10,
node=0x5555565c4418, popped=popped@entry=0) at compile.c:5265
#5 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff800020,
node=0x5555565c43a0, popped=popped@entry=0) at compile.c:5265
#6 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff800330,
node=0x5555565c4328, popped=popped@entry=0) at compile.c:5265
#7 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff800640,
node=0x5555565c42b0, popped=popped@entry=0) at compile.c:5265
#8 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff800950,
node=0x5555565c4238, popped=popped@entry=0) at compile.c:5265
#9 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff800c60,
node=0x5555565c41c0, popped=popped@entry=0) at compile.c:5265
#10 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff800f70,
node=0x5555565c4148, popped=popped@entry=0) at compile.c:5265
#11 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff801280,
node=0x5555565c40d0, popped=popped@entry=0) at compile.c:5265
#12 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff801590,
node=0x5555565c4058, popped=popped@entry=0) at compile.c:5265
#13 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffff8018a0,
node=0x5555565cbfb0, popped=popped@entry=0) at compile.c:5265
*snip*
#10682 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffffffba70, node=0x555556709e40, popped=popped@entry=0) at compile.c:5265
#10683 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffffffbd80, node=0x555556709dc8, popped=popped@entry=0) at compile.c:5265
#10684 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffffffc090, node=0x555556709d50, popped=popped@entry=0) at compile.c:5265
#10685 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffffffc3a0, node=0x555556709cd8, popped=popped@entry=0) at compile.c:5265
#10686 0x00005555555b08cf in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffffffc9a0, node=0x555556709c60, popped=popped@entry=0) at compile.c:5265
#10687 0x00005555555b301f in iseq_compile_each (iseq=iseq@entry=0x555556709bc0, ret=ret@entry=0x7fffffffc9a0, node=0x555556709be8, popped=0) at compile.c:6280
#10688 0x00005555555bc791 in rb_iseq_compile_node (iseq=iseq@entry=0x555556709bc0, node=node@entry=0x555556709c38) at compile.c:651
#10689 0x000055555563cb94 in rb_iseq_new_with_opt (node=node@entry=0x555556709c38, name=93824997742080, path=93824997738840, absolute_path=absolute_path@entry=8, first_lineno=first_lineno@entry=3, parent=parent@entry=0x555555a955d8, type=ISEQ_TYPE_EVAL, option=0x7fffffffcae0) at iseq.c:483
#10690 0x000055555563dc04 in rb_iseq_compile_with_option (src=<optimized out>, src@entry=93824997740280, file=<optimized out>, file@entry=93824997738840, absolute_path=absolute_path@entry=8, line=3, base_block=base_block@entry=0x7fffffffcba0, opt=opt@entry=8) at iseq.c:650
#10691 0x000055555576a149 in eval_string_with_cref (self=self@entry=93824997975240, src=93824997740280, scope=8, cref_arg=cref_arg@entry=0x0, filename=<optimized out>, lineno=<optimized out>) at vm_eval.c:1345
#10692 0x000055555576a67e in eval_string (line=<optimized out>, file=<optimized out>, scope=<optimized out>, src=<optimized out>, self=93824997975240) at vm_eval.c:1397
#10693 rb_f_eval (argc=1, argv=<optimized out>, self=93824997975240) at vm_eval.c:1436
#10694 0x000055555575b7e7 in vm_call_cfunc_with_frame (ci=0x555555b846d0, cc=<optimized out>, calling=<optimized out>, reg_cfp=0x7ffff6e34f50, th=0x555555a6d5d0) at vm_insnhelper.c:1752
#10695 vm_call_cfunc (th=0x555555a6d5d0, reg_cfp=0x7ffff6e34f50, calling=<optimized out>, ci=0x555555b846d0, cc=<optimized out>) at vm_insnhelper.c:1847
#10696 0x00005555557697e3 in vm_call_method (th=0x555555a6d5d0, cfp=0x7ffff6e34f50, calling=<optimized out>, ci=<optimized out>, cc=<optimized out>) at vm_insnhelper.c:2292
#10697 0x000055555576286e in vm_exec_core (th=th@entry=0x555555a6d5d0, initial=initial@entry=0) at insns.def:1066
#10698 0x0000555555767dea in vm_exec (th=th@entry=0x555555a6d5d0) at vm.c:1727
#10699 0x0000555555768b34 in invoke_block (captured=<optimized out>, opt_pc=<optimized out>, type=<optimized out>, cref=0x0, self=93824997975240, iseq=<optimized out>, th=0x555555a6d5d0) at vm.c:969
#10700 invoke_iseq_block_from_c (th=0x555555a6d5d0, captured=<optimized out>, self=93824997975240, argc=<optimized out>, argv=<optimized out>, passed_block_handler=<optimized out>, cref=0x0, splattable=0, is_lambda=0) at vm.c:1014
#10701 0x0000555555770048 in invoke_block_from_c_splattable (argc=<optimized out>, passed_block_handler=<optimized out>, cref=<optimized out>, is_lambda=<optimized out>, splattable=<optimized out>, argv=<optimized out>, block_handler=<optimized out>, th=<optimized out>) at vm.c:1032
#10702 vm_yield (argc=1, argv=0x7fffffffd4f8, th=0x555555a6d5d0) at vm.c:1074
#10703 rb_yield_0 (argv=0x7fffffffd4f8, argc=1) at vm_eval.c:1010
#10704 rb_yield_1 (val=<optimized out>, val@entry=1) at vm_eval.c:1016
#10705 0x00005555556574a0 in int_dotimes (num=5) at numeric.c:4977
#10706 0x000055555575b7e7 in vm_call_cfunc_with_frame (ci=0x555555b842e0, cc=<optimized out>, calling=<optimized out>, reg_cfp=0x7ffff6e34fb0, th=0x555555a6d5d0) at vm_insnhelper.c:1752
#10707 vm_call_cfunc (th=0x555555a6d5d0, reg_cfp=0x7ffff6e34fb0, calling=<optimized out>, ci=0x555555b842e0, cc=<optimized out>) at vm_insnhelper.c:1847
#10708 0x00005555557697e3 in vm_call_method (th=0x555555a6d5d0, cfp=0x7ffff6e34fb0, calling=<optimized out>, ci=<optimized out>, cc=<optimized out>) at vm_insnhelper.c:2292
#10709 0x000055555576246a in vm_exec_core (th=th@entry=0x555555a6d5d0, initial=initial@entry=0) at insns.def:967
#10710 0x0000555555767dea in vm_exec (th=0x555555a6d5d0) at vm.c:1727
#10711 0x00005555557718ae in rb_iseq_eval_main (iseq=iseq@entry=0x555555a95a88) at vm.c:1973
#10712 0x00005555555f8a5d in ruby_exec_internal (n=0x555555a95a88) at eval.c:244
#10713 0x00005555555fc2bf in ruby_exec_node (n=<optimized out>) at eval.c:308
#10714 ruby_run_node (n=<optimized out>) at eval.c:300
#10715 0x0000555555578dcb in main (argc=<optimized out>, argv=<optimized out>) at main.c:36
Updated by mjones (Morgan Jones) over 7 years ago
Updated description to add a successful testcase.
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
- Is duplicate of Bug #13164: A second `SystemStackError` exception results in `Segmentation fault (core dumped)` added
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
- Status changed from Open to Closed