Fork me on GitHub

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


请我喝瓶饮料

微信支付码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注