Project

General

Profile

Bug #13596

Segfault when catching SystemStackError in eval

Added by mjones (Morgan Jones) over 2 years ago. Updated over 2 years ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
-
ruby -v:
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]
[ruby-core:81366]

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>

Related issues

Is duplicate of Ruby master - Bug #13164: A second `SystemStackError` exception results in `Segmentation fault (core dumped)`OpenActions

History

Updated by mjones (Morgan Jones) over 2 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
#2

Updated by mjones (Morgan Jones) over 2 years ago

  • Description updated (diff)
#3

Updated by mjones (Morgan Jones) over 2 years ago

  • Description updated (diff)
#4

Updated by mjones (Morgan Jones) over 2 years ago

  • Description updated (diff)
#5

Updated by mjones (Morgan Jones) over 2 years ago

  • Description updated (diff)

Updated by mjones (Morgan Jones) over 2 years ago

Updated description to add a successful testcase.

#7

Updated by nobu (Nobuyoshi Nakada) over 2 years ago

  • Is duplicate of Bug #13164: A second `SystemStackError` exception results in `Segmentation fault (core dumped)` added
#8

Updated by nobu (Nobuyoshi Nakada) over 2 years ago

  • Status changed from Open to Closed

Also available in: Atom PDF