Project

General

Profile

Actions

Bug #10290

closed

segfault when calling a lambda recursively after rescuing SystemStackError

Added by Anonymous about 10 years ago. Updated over 5 years ago.

Status:
Closed
Target version:
-
ruby -v:
ruby 2.1.3p242 (2014-09-19 revision 47629) [x86_64-darwin13.0]
[ruby-core:65254]

Description

The following code segfaults on Ruby 2.1.3:

l = -> { l.() }

begin
  l.()
rescue SystemStackError
  l.() # segfault
end

the issue does not occur on trunk.


Files

ruby_2014-09-25-000925_haswell.log (46.4 KB) ruby_2014-09-25-000925_haswell.log segfault on 2.1.3 Anonymous, 09/25/2014 05:10 AM
ruby_2014-09-25-001644_haswell.log (46.8 KB) ruby_2014-09-25-001644_haswell.log trunk segfault Anonymous, 09/25/2014 05:17 AM

Updated by Anonymous about 10 years ago

The segfault also occurs on the OS X 10.9 system ruby, 2.0.0-p481; not sure about the most recent patch release.

Updated by Anonymous about 10 years ago

I've attached the OS X crash report.

Updated by Anonymous about 10 years ago

As I noted, running the example code on trunk does not segfault (it raises SystemStackError a second time, as I would expect):

$ ruby -ve "l = -> { l.() }; begin; l.(); rescue SystemStackError; l.(); end"
ruby 2.2.0dev (2014-09-25 trunk 47651) [x86_64-darwin13]
-e:1:in `block in <main>': stack level too deep (SystemStackError)
	from -e:1:in `call'
	from -e:1:in `block in <main>'
	from -e:1:in `call'
	from -e:1:in `block in <main>'
	from -e:1:in `call'
	from -e:1:in `block in <main>'
	from -e:1:in `call'
	from -e:1:in `block in <main>'
	 ... 9604 levels...
	from -e:1:in `call'
	from -e:1:in `block in <main>'
	from -e:1:in `call'
	from -e:1:in `<main>'

However, if I run the same code in IRB, it does segfault:

$ irb
irb(main):001:0> RUBY_DESCRIPTION
=> "ruby 2.2.0dev (2014-09-25 trunk 47651) [x86_64-darwin13]"
irb(main):002:0> l = -> { l.() }; begin; l.(); rescue SystemStackError; l.(); end
Segmentation fault: 11

I've attached the crash report for this one as well.

Updated by nobu (Nobuyoshi Nakada) about 10 years ago

I can't reproduce it with irb, but it might access over the top of stack.
Possibly, we need more margin for the guard page.

Updated by hsbt (Hiroshi SHIBATA) about 10 years ago

  • Status changed from Open to Feedback

I can't reproduce following versions:

ruby 1.9.3p548 (2014-09-06) [x86_64-darwin13.4.0]
ruby 2.0.0p576 (2014-09-19 revision 47628) [x86_64-darwin13.4.0]
ruby 2.1.3p242 (2014-09-19 revision 47630) [x86_64-darwin13.0]
ruby 2.2.0preview1 (2014-09-17 trunk 47616) [x86_64-darwin13]
ruby 2.2.0dev (2014-10-13 trunk 47898) [x86_64-darwin13]

Updated by Anonymous about 10 years ago

I can reproduce it on 2.0.0-p576 when compiled with -Os, but not -O2:

$ make clean && ./configure --disable-install-doc CC=clang CFLAGS=-O2 && make -j12
$ ./miniruby -v
ruby 2.0.0p576 (2014-09-19 revision 47627) [x86_64-darwin13.4.0]
$ ./miniruby -e "l = -> { l.() }; begin; l.(); rescue SystemStackError; l.(); end"
-e:1: stack level too deep (SystemStackError)

$ make clean && ./configure --disable-install-doc CC=clang CFLAGS=-Os && make -j12
$ ./miniruby -v
ruby 2.0.0p576 (2014-09-19 revision 47627) [x86_64-darwin13.4.0]
$ ./miniruby -e "l = -> { l.() }; begin; l.(); rescue SystemStackError; l.(); end"
Segmentation fault: 11

On 2.1.3, it does not happen when compiled without optimizations, but even using -O1 is enough to trigger it:

$ make clean && ./configure --disable-install-doc CC=clang && make -j12
$ ./miniruby -v
ruby 2.1.3p242 (2014-09-19 revision 47629) [x86_64-darwin13.0]
$ ./miniruby -e "l = -> { l.() }; begin; l.(); rescue SystemStackError; l.(); end"
-e:1: stack level too deep (SystemStackError)

$ make clean && ./configure --disable-install-doc CC=clang CFLAGS=-O1 && make -j12
$ ./miniruby -v
ruby 2.1.3p242 (2014-09-19 revision 47629) [x86_64-darwin13.0]
$ ./miniruby -e "l = -> { l.() }; begin; l.(); rescue SystemStackError; l.(); end"
Segmentation fault: 11

And similarly on trunk, it is triggered with -O1 or higher:

$ make clean && ./configure --disable-install-doc CC=clang && make -j12
$ ./miniruby -v
ruby 2.2.0dev (2014-10-14 trunk 47906) [x86_64-darwin13]
$ ./miniruby -e "l = -> { l.() }; begin; l.(); rescue SystemStackError; l.(); end"
-e:1:in `call': stack level too deep (SystemStackError)

make clean && ./configure --disable-install-doc CC=clang CFLAGS=-O1 && make -j12
$ ./miniruby -v
ruby 2.2.0dev (2014-10-14 trunk 47906) [x86_64-darwin13]
$ ./miniruby -e "l = -> { l.() }; begin; l.(); rescue SystemStackError; l.(); end"
Segmentation fault: 11

I'm using the latest Apple clang:

$ clang --version
Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix

Updated by hsbt (Hiroshi SHIBATA) about 10 years ago

I can't reproduce with gcc-4.9(not clang).

Updated by hsbt (Hiroshi SHIBATA) about 10 years ago

I can reproduce clang on linux.

[hsbt@chkbuild001 ~]$ clang -v
clang version 3.5.0 (tags/RELEASE_350/final)
Target: x86_64-amazon-linux-gnu
Thread model: posix
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-amazon-linux/4.8.2
Found candidate GCC installation: /usr/lib/gcc/x86_64-amazon-linux/4.8.2
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-amazon-linux/4.8.2
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Selected multilib: .;@m64

Updated by Anonymous about 10 years ago

I can reproduce it with gcc 4.9.1 at -Os:

 $ gcc-4.9 --version
gcc-4.9 (Homebrew gcc 4.9.1) 4.9.1
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ make clean && ./configure --disable-install-doc CC=gcc-4.9 CFLAGS=-Os && make -j12
$ ./miniruby -v
ruby 2.2.0dev (2014-10-16 trunk 47971) [x86_64-darwin13]
$ ./miniruby -e "l = -> { l.() }; begin; l.(); rescue SystemStackError; l.(); end"
Segmentation fault: 11

Updated by nobu (Nobuyoshi Nakada) about 10 years ago

  • Description updated (diff)

I could reproduce it with gcc-4.9 on either Linux and OS X.
On Linux, SIGSEGV seems masked after the first stack overflow occurred, and it seems working by enabling interrupts.

diff --git c/eval.c i/eval.c
index 3e4ea16..6bd6ac9 100644
--- c/eval.c
+++ i/eval.c
@@ -500,7 +500,6 @@ setup_exception(rb_thread_t *th, int tag, volatile VALUE mesg, VALUE cause)
     if (cause == Qundef) {
 	cause = nocause ? Qnil : get_thread_errinfo(th);
     }
-    exc_setup_cause(mesg, cause);
 
     file = rb_sourcefile();
     if (file) line = rb_sourceline();
@@ -526,6 +525,7 @@ setup_exception(rb_thread_t *th, int tag, volatile VALUE mesg, VALUE cause)
 	    set_backtrace(mesg, at);
 	}
     }
+    exc_setup_cause(mesg, cause);
 
     if (!NIL_P(mesg)) {
 	th->errinfo = mesg;
diff --git c/signal.c i/signal.c
index d3c7cb8..b939930 100644
--- c/signal.c
+++ i/signal.c
@@ -767,6 +767,7 @@ check_stack_overflow(const uintptr_t addr, const ucontext_t *ctx)
 	     * place. */
 	    th->tag = th->tag->prev;
 	}
+	rb_enable_interrupt();
 	ruby_thread_stack_overflow(th);
     }
 }

However, on OS X it makes the second stack overflow SIGILL, with no outputs.
I have no idea what happens there.

Updated by backus (John Backus) over 8 years ago

Any update on this issue? I ran into this bug yesterday and spent hours investigating the source of the segfault. Here is the code that caused the issue for me:

def foo
  define_singleton_method(:method_missing)          { |*| invalid_method }
  define_singleton_method(:define_singleton_method) { |*| invalid_method }
end

foo

begin
  do_not_segfault
rescue SystemStackError
end

do_not_segfault

Updated by nobu (Nobuyoshi Nakada) over 8 years ago

It causes SystemStackError as expected, with ruby 2.3.

Updated by backus (John Backus) over 8 years ago

Nobuyoshi Nakada wrote:

It causes SystemStackError as expected, with ruby 2.3.

No it definitely segfaults for me:

$ cat ex.rb
l = -> { l.() }

begin
  l.()
rescue SystemStackError
  l.() # segfault
end
$ which ruby
/Users/johnbackus/.rubies/ruby-2.3.1/bin/ruby
$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]
$ ruby ex.rb
[1]    82276 segmentation fault  ruby ex.rb

anything I can run to help you reproduce for 2.3 on OS X?

Updated by shyouhei (Shyouhei Urabe) about 8 years ago

  • Status changed from Feedback to Assigned
  • Assignee set to nobu (Nobuyoshi Nakada)

ping nobu.

Updated by nobu (Nobuyoshi Nakada) over 7 years ago

On macOS, --with-setjmp-type=setjmp configuration option may fix it.

Updated by backus (John Backus) over 7 years ago

nobu (Nobuyoshi Nakada) wrote:

On macOS, --with-setjmp-type=setjmp configuration option may fix it.

This does fix the issue on macOS for me, thank you. Maybe this should be the macOS default?

Updated by nobu (Nobuyoshi Nakada) over 7 years ago

SystemStackError seems uncatchable since r58492.

Updated by jeremyevans0 (Jeremy Evans) over 5 years ago

  • Status changed from Assigned to Closed

I was able to reproduce the segfault in ruby 2.3 and 2.4, but not in 2.5, 2.6, 2.7.0-preview1, or the master branch, so I think this problem is fixed. If this problem still occurs for you, please reply with your environment details.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0