Fork me on GitHub

版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | http://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


如果我的文章对你有帮助,你可以给我打赏以促使我拿出更多的时间和精力来分享我的经验和思考总结。

微信支付码

发表评论

电子邮件地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据