How to get a backtrace from a SystemStackError: stack level too deep?

Solution 1:

Another method for those finding this question later... An excellent gist provides instructions on enabling a trace function in the console and printing all function calls to a file. Just tested on 1.9.3-p194 and it worked great.

Including here in case the gist goes away someday:

$enable_tracing = false
$trace_out = open('trace.txt', 'w')

set_trace_func proc { |event, file, line, id, binding, classname|
  if $enable_tracing && event == 'call'
    $trace_out.puts "#{file}:#{line} #{classname}##{id}"
  end
}

$enable_tracing = true
a_method_that_causes_infinite_recursion_in_a_not_obvious_way()

Solution 2:

This has been a somewhat vexing problem that I've had from time to time in debugging ruby/rails. I just discovered a workable technique to detect the stack growing out of bounds before it crashed the system stack and the real backtrace gets lost or garbled. The basic pattern is:

raise "crash me" if caller.length > 500

bump up the 500 until it doesn't fire prematurely and you will have a nice trace of your growing stack problem.

Solution 3:

Here:

begin
  foo
rescue SystemStackError
  puts $!
  puts caller[0..100]
end

The method Kernel#caller returns a stack backtrace as an array, so this prints the first 0 to 100 entries in the backtrace. Because caller can be called at any time (and used for some pretty weird things) even if Ruby doesn't print backtrace for SystemStackErrors, you can still get a backtrace.

Solution 4:

Combining suggestions from several answers, this will throw an error (with stack trace) when your call stack gets too deep. This will slow down all method calls, so you should try to put it as close to where you think the infinite loop is happening as you can.

set_trace_func proc {
  |event, file, line, id, binding, classname| 
  if event == "call"  && caller_locations.length > 500
    fail "stack level too deep"
  end
}