LoginSignup
5
1

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-04-13

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

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

Go が Go で書かれているのであれば、スタックが可変長なので相当しぶといと予想していた。

で、まずは括弧。

(((((1)))))

ruby
a = [*1..1000000]
p(a.bsearch do  |n|
  exp = "("*n + "1"+")"*n
  File.open( "hoge.go", "w" ){ |f| f.puts( <<"GOLANG" ) }
package main
import (
    "fmt"
)
func main() {
    fmt.Println(#{exp})
}
GOLANG
  begin
    "1" != %x( go run hoge.go ).strip
  rescue
    true
  end
end)
#=>871538

87万。なかなかしぶとい。
もうちょっと(億とか)行くと予想していたので、予想は外れ。

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

ruby
a = [*1..1000000]
p(a.bsearch do  |n|
  exp = "1"+"+1-1"*n
  File.open( "hoge.go", "w" ){ |f| f.puts( <<"GOLANG" ) }
package main
import (
    "fmt"
)
func main() {
    fmt.Println(#{exp})
}
GOLANG
  begin
    "1" != %x( go run hoge.go ).strip
  rescue
    true
  end
end)
#=>68899

7万弱。「1」の数なら14万弱。
括弧よりも 1+1-1... の方がしぶといと予想していたので、こちらも予想は外れ。
そういうものか。

func()int { return func()int { return func()int { return 1}()}()}()

ruby
a = [*1..1000000]
p(a.bsearch do  |n|
  exp = "func()int { return "*n+"1"+"}()"*n
  File.open( "hoge.go", "w" ){ |f| f.puts( <<"GOLANG" ) }
package main
import (
    "fmt"
)
func main() {
    fmt.Println(#{exp})
}
GOLANG
  begin
    "1" != %x( go run hoge.go ).strip
  rescue
    true
  end
end)
#=>102

およそ百。少ない。
まあ、機械生成でもこの文脈で死ぬようなコードは吐きにくいと思うので無害だと思う。いわんや人間に於いてをや。

ちなみに、

runtime.morestack: nosplit stack check too deep
runtime.morestack: nosplit stack overflow

というエラーが出る。
nosplit stack とはなんだろうか。

<-<-<-<-<-<-<-<-<-<-

ruby

a=[*3..10000]

p( a.bsearch do |n|
  types = Array.new(n-1){ |i|
    "type c#{i+1} chan c#{i}"
  }.join("\n")

  makes=Array.new(n){ |i|
    "v#{i} := make(c#{i})"
  }.join("\n")

  funcs=Array.new(n-1){ |i|
    "go func(){ v#{i+1}<-v#{i} }()"
  }.join("\n")
  File.open( "hoge.go", "w") do |f|
    f.puts %Q!package main

    import "fmt"

    type c0 chan int
    #{types}

    func main() {
      #{makes}
      go func(){ v0<-1 }()
      #{funcs}
      fmt.Println(#{"<-"*n}v#{n-1})
    }!
  end
  begin
    ng = "1"!=%x( go run hoge.go ).strip
    p [ n, ng ? "NG" : "okay"]
    ng
  rescue
    p [ n, "NG"]
    true
  end
end)

n=10000 まで試したけど死ななかった。それ以上は実行時間がかかりすぎるので試していない。

ちなみに、n=5 のときのコードは( フォーマットすると )

go
package main

import "fmt"

type c0 chan int
type c1 chan c0
type c2 chan c1
type c3 chan c2
type c4 chan c3

func main() {
    v0 := make(c0)
    v1 := make(c1)
    v2 := make(c2)
    v3 := make(c3)
    v4 := make(c4)
    go func() { v0 <- 1 }()
    go func() { v1 <- v0 }()
    go func() { v2 <- v1 }()
    go func() { v3 <- v2 }()
    go func() { v4 <- v3 }()
    fmt.Println(<-<-<-<-<-v4)
}

こんな感じ。

他の処理系

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1