compress/flate: Write() causes large and unshrinkable stack growth · Issue #18625 · golang/go (original) (raw)
Please answer these questions before submitting your issue. Thanks!
What version of Go are you using (go version
)?
go version go1.7.1 linux/amd64
What operating system and processor architecture are you using (go env
)?
GOARCH="amd64"
GOBIN="/home/cy/go/go-1.7.1/gopath/bin"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/cy/go/go-1.7.1/gopath"
GORACE=""
GOROOT="/home/cy/go/go-1.7.1"
GOTOOLDIR="/home/cy/go/go-1.7.1/pkg/tool/linux_amd64"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build525622235=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
What did you do?
package main
import (
"compress/flate"
"fmt"
"io/ioutil"
"runtime"
"runtime/debug"
)
const limit = 1024 * 16
func printss() {
m := runtime.MemStats{}
runtime.ReadMemStats(&m)
fmt.Printf("inuse: %d sys: %d\n", m.StackInuse, m.StackSys)
}
func doflate() {
z := make([]byte, limit*1000, limit*1000)
fl, _ := flate.NewWriter(ioutil.Discard, 3)
printss()
fl.Write(z) // boom.
}
func main() {
fmt.Println("hi")
debug.SetMaxStack(limit) // comment out for more detail.
doflate() // boom.
printss()
runtime.GC()
printss()
}
What did you expect to see?
Passing a large input to flate.Write() would not cause the stack to grow beyond the limit provided.
What did you see instead?
The stack grows very large.
Also, if I comment out this line:debug.SetMaxStack(limit)
I get the following output:
hi
inuse: 393216 sys: 393216
inuse: 1474560 sys: 1474560
inuse: 950272 sys: 950272
Which suggests the runtime managed to shrink the stack a bit, but not nearly close enough to the original size.
Now imagine you have written a server that has lots of long running goroutines that occasionally compress a large blob. After introducing this code path, our stack usage increased ~10x.