50

Ruby をコーディングしていると、無限再帰のデバッグに苦労することがよくあります。SystemStackError無限ループが正確に発生する場所を見つけるために a からバックトレースを取得する方法はありますか?

いくつかのメソッドが与えられfoo、それらはループ内barbaz互いに呼び出します:

def foo
  bar
end

def bar
  baz
end

def baz
  foo
end

foo

このコードを実行すると、メッセージが表示されますtest.rb:6: stack level too deep (SystemStackError)。スタックの最後の 100 行を取得すると便利なため、次のようfoobarとの間のループであることがすぐにわかりますbaz

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'
  [...]

これを達成する方法はありますか?

編集:

以下の回答からわかるように、ルビニウスはそれを行うことができます。残念ながら、いくつかのrubinius のバグにより、デバッグしたいソフトウェアで rubinius を使用できません。正確に言うと、質問は次のとおりです。

MRI (デフォルトの Ruby) 1.9 でバックトレースを取得するにはどうすればよいですか?

4

8 に答える 8

20

これは、Ruby/Rails のデバッグでときどき発生したやや厄介な問題でした。システムスタックがクラッシュし、実際のバックトレースが失われたり文字化けしたりする前に、スタックが範囲外に成長していることを検出するための実行可能な手法を発見しました。基本的なパターンは次のとおりです。

raise "crash me" if caller.length > 500

時期尚早に起動しなくなるまで 500 を増やしてください。これにより、増大するスタックの問題の良い痕跡が得られます。

于 2012-11-13T15:03:42.147 に答える
14

ここ:

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

このメソッドKernel#callerはスタック バックトレースを配列として返すため、これはバックトレースの最初の 0 ~ 100 エントリを出力します。Ruby がSystemStackErrorscallerのバックトレースを出力しない場合でも、いつでも呼び出すことができる (そしてかなり奇妙なことに使用できる) ため、バックトレースを取得できます。

于 2012-07-18T15:08:37.643 に答える
6

いくつかの回答からの提案を組み合わせると、呼び出しスタックが深くなりすぎると、(スタック トレースを使用して) エラーがスローされます。これにより、すべてのメソッド呼び出しが遅くなるため、無限ループが発生していると思われる場所にできるだけ近づけるようにしてください。

set_trace_func proc {
  |event, file, line, id, binding, classname| 
  if event == "call"  && caller_locations.length > 500
    fail "stack level too deep"
  end
}
于 2015-02-23T17:47:32.960 に答える
3

どうやらこれは機能 6216として追跡され、Ruby 2.2 で修正されたようです。

$ ruby system-stack-error.rb
system-stack-error.rb:6:in `bar': stack level too deep (SystemStackError)
        from system-stack-error.rb:2:in `foo'
        from system-stack-error.rb:10:in `baz'
        from system-stack-error.rb:6:in `bar'
        from system-stack-error.rb:2:in `foo'
        from system-stack-error.rb:10:in `baz'
        from system-stack-error.rb:6:in `bar'
        from system-stack-error.rb:2:in `foo'
        from system-stack-error.rb:10:in `baz'
         ... 10067 levels...
        from system-stack-error.rb:10:in `baz'
        from system-stack-error.rb:6:in `bar'
        from system-stack-error.rb:2:in `foo'
        from system-stack-error.rb:13:in `<main>'
于 2015-08-05T14:13:15.007 に答える
3

Ruby 1.8 では、このようなスタック トレースを取得できます。1.9 スタイルの構文 (例: ) の存在が唯一の問題である場合は、 Ruby 1.8 head{foo: 42}をコンパイルします。

于 2012-07-18T23:14:44.670 に答える