Ruby

ruby にとても長い式を食べさせると死ぬ

整数を419378回インクリメントするとMacのg++が死ぬ

C++でアスタリスクをつけすぎると端末が落ちる
にインスパイアされて。

ruby で

(((((1)))))
[[[[[1]]]]].flatten[0]
1+1-1+1-1+1-1+1-1+1-1
1.to_s.to_s.to_s.to_s.to_s
p(aaaaaaaaaaaaaaaaaa=1)
!!!!!!!!!1
のような式を食べさせて、どれぐらいで死ぬのか調べてみた。

環境は macOS High Sierra。メモリ 16GB。
ruby は ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin17]。

(((((1)))))

ruby2.5
a = [*1..20000]
p(a.bsearch do  |n|
  s="p"+"("*n+"1"+")"*n
  puts "#{n}"
  "1" != %x( ruby -e "#{s}" ).strip
end)
#=>9995

死ぬときは memory exhausted で死ぬ。
何かが一万ピッタリになって死んでいるのかもしれないと思わせる感じだけど、どうなんだろう。

[[[[[1]]]]].flatten[0]

ruby2.5
a = [*1..20000]
p(a.bsearch do  |n|
  s="p "+"["*n+"1"+"]"*n + ".flatten[0]"
  puts "#{n}"
  "1" != %x( ruby -e "#{s}" ).strip
end)
#=>9994

死ぬときは memory exhausted で死ぬ。

(((((1))))) よりひとつ少ないのは、余計な .flatten[0] がついているからかな。

[] の方が重そうな感じがしたけど、() と同じだったということだと思う。

1+1-1+1-1+1-1+1-1+1-1

ruby2.5
a = [*1..20000]
p(a.bsearch do  |n|
  s="p( 1" + "+1-1"*n + ")"
  puts "#{n}"
  "1" != %x( ruby -e "#{s}" ).strip
end)
#=>10027

一万を僅かに超えてきた。というか、"1" や 演算子の数で言うと二万ちょっと。
死んだ理由は stack level too deep (SystemStackError) なので、設定を変えるともっと行けるんだと思う。

1.to_s.to_s.to_s.to_s.to_s

ruby2.5
a = [*1..20000]
p(a.bsearch do  |n|
  s="puts(1"+".to_s"*n+")"
  puts "#{n}"
  "1" != %x( ruby -e "#{s}" ).strip
end)
#=> 19911

こちらも死んだ理由は stack level too deep (SystemStackError)
+1 などがメソッド呼び出しであることを思うと .to_s の数は 10027×2 ぐらいになるかと思ったんだけど、そうでもない。オーダーとしてはその程度だけど、誤差が大きい気がする。
謎。

長い変数名

ruby2.5
a = [*1..100000000]
p(a.bsearch do  |n|
  File.open( "hoge.rb", "w" ){ |f| f.puts( "p("+"a"*n+"=1)" ) }
  puts "#{n}"
  begin
    "1" != %x( ruby hoge.rb ).strip
  rescue
    true
  end
end)
#=> nil

変数名の長さ一億文字でも大丈夫だった。
それ以上は試していない。

!!!!!1

ruby2.5
a = [*1..1000_0000]
p(a.bsearch do  |n|
  s="p "+"!"*n+"1"
  puts "#{n}"
  begin
    File.open( "hoge.rb", "w" ){ |f| f.puts(s) }
    !(/true|false/=== %x( ruby hoge.rb ).strip)
  rescue
    true
  end
end)
#=>9995

(((((1))))) と同じ個数になった。
そういうものか。

出るエラーも「memory exhausted」で同じ。面白い。

当初は

ruby2.5
a = [*1..20000]
p(a.bsearch do  |n|
  s="("*n+"1"+")"*n
  puts "#{n}"
  begin
    eval( "#{s}" )
    false
  rescue
    true
  end
end)

というコードを書いたんだけど、 evalmemory exhausted (SyntaxError) になると、rescue できずに死んでしまって測れなかった。

いずれにせよ

いずれにせよ、現実的なソースコードでは死なないので心配ない。

それと。
端末は死なない。 ruby が死ぬだけ。

それとはあまり関係なく。
ruby 25周年おめでとうございます。
今までありがとうございます。
これからもよろしくお願いします。