48 votes

Comment faire pour obtenir une trace de débogage à partir d'un SystemStackError: niveau de la pile trop profond?

Souvent je reçois difficile à déboguer infini récurrences lors du codage de ruby. Est-il possible d'obtenir une trace d'un SystemStackError pour le savoir, où exactement la boucle infinie se produit?

Exemple

Compte tenu de certaines méthodes d' foo, bar et baz qui s'appellent les uns les autres dans une boucle:

def foo
  bar
end

def bar
  baz
end

def baz
  foo
end

foo

Lorsque j'exécute ce code, je viens d'obtenir le message d' test.rb:6: stack level too deep (SystemStackError). Il serait utile d'obtenir au moins les 100 dernières lignes de la pile, de sorte que je pouvais voir immédiatement ce est une boucle entre foo, bar et baz, comme ceci:

test.rb:6: stack level too deep (SystemStackError)
  test.rb:2:in `foo'
  test.rb:10:in `baz'
  test.rb:6:in `bar'
  test.rb:2:in `foo'
  test.rb:10:in `baz'
  test.rb:6:in `bar'
  test.rb:2:in `foo'
  [...]

Est-il un moyen pour accomplir cette?

EDIT:

Comme vous pouvez le voir à partir de la réponse ci-dessous, Rubinius peut le faire. Malheureusement, certains rubinius bugs m'empêcher de l'utiliser avec le logiciel que j'aimerais debug. Donc, pour être précis, la question est:

Comment puis-je obtenir un backtrace avec l'IRM (la valeur par défaut ruby) 1.9?

42voto

Elliot Nelson Points 4212

Une autre méthode pour ceux qui éprouvent cette question plus tard... Un excellent résumé fournit des instructions sur l'activation d'une fonction de trace dans la console et l'impression de tous les appels de fonction dans un fichier. Juste testé sur 1.9.3-p194 et il a très bien fonctionné.

Y compris ici dans le cas où l'essentiel s'en va un jour:

$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()

20voto

Gerry Gleason Points 126

Cela a été un peu épineux problème que j'ai eu de temps en temps dans le débogage de ruby/rails. Je viens de découvrir une pratique technique pour détecter la pile de plus en plus hors des limites du terrain avant qu'il ne s'est écrasé le système de pile et le réel trace se perd ou tronqués. Le motif de base est:

raise "crash me" if caller.length > 500

remonter les 500 jusqu'à ce qu'il ne se déclenche prématurément et vous aurez une belle trace de votre pile problème.

13voto

Linuxios Points 16966

Ici:

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

La méthode Kernel#caller renvoie un stack trace comme un tableau, ce imprime la première de 0 à 100 entrées dans la trace. Parce qu' caller peut être appelé à tout moment (et utilisé pour des choses assez étranges), même si Ruby n'a pas l'impression backtrace de SystemStackErrors, vous pouvez toujours obtenir une trace.

4voto

Paul Alexander Points 17611

Si vous arrive d'utiliser de levier, ce sera effectivement vous permettre de briser dans l'appel de la méthode de la chaîne qui s'est passé trop de profondeur.

set_trace_func proc { |event, file, line, id, proc_binding, classname|
  if !$pried && proc_binding && proc_binding.eval( "caller.size" ) > 200
    $pried = true
    proc_binding.pry
  end
}

3voto

Andrew Grimm Points 22996

Vous pouvez obtenir ce genre de trace de la pile avec Ruby 1.8. Si la présence de 1,9 style de syntaxe (par exemple, {foo: 42}) est la seule question, puis compiler Ruby 1.8 tête.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X