如何在Golang中制造stack overflow 故障
版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | https://vearne.cc
大家都知道golang的栈的动态增长的,并且是放在堆上的,理论上可以相当的大,那么怎么才能制造一个stack overflow 故障呢?
其实只要人为的加入循环引用就能做到
package main
import (
//"github.com/json-iterator/go"
"encoding/json"
)
type A struct {
ElementB *B
}
type B struct {
ElementA *A
}
func main(){
a := A{}
b := B{}
a.ElementB = &b
b.ElementA = &a
//var json = jsoniter.ConfigCompatibleWithStandardLibrary
json.Marshal(a)
}
栈溢出,程序奔溃,并输出
╰─$ go run test_stackoverflow2.go
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow
runtime stack:
runtime.throw(0x10e2e65, 0xe)
/usr/local/Cellar/go/1.11.2/libexec/src/runtime/panic.go:608 +0x72
runtime.newstack()
/usr/local/Cellar/go/1.11.2/libexec/src/runtime/stack.go:1008 +0x729
runtime.morestack()
/usr/local/Cellar/go/1.11.2/libexec/src/runtime/asm_amd64.s:429 +0x8f
goroutine 1 [running]:
encoding/json.(*structEncoder).encode(0xc0000642d0, 0xc00007e000, 0x10c8d40, 0xc00000c030, 0x199, 0x100)
- 看来默认栈的最大大小也就1GB。
- 这个例子其实源于真实的线上故障,经过测试无论是标准的Json库,或是jsoniter都无法避免此问题。
- 另外如果Golang编译器,或者Marshal函数能够对递归的深度做出判断,超过一定深度就报错,在栈溢出前,抛出err,避免栈溢出,程序崩溃
后记
已经给json-iterator/go 提了issue,并且提了pull request。
有需要也可以直接使用我个改进库vearne/json-iterator-go
默认递归的最大层级限制是1000