Skip to content

runtime: infinite loop causing stack overflow in bufio #38481

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Nemo-G opened this issue Apr 16, 2020 · 6 comments
Closed

runtime: infinite loop causing stack overflow in bufio #38481

Nemo-G opened this issue Apr 16, 2020 · 6 comments
Labels
FrozenDueToAge WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.

Comments

@Nemo-G
Copy link

Nemo-G commented Apr 16, 2020

What version of Go are you using (go version)?

$ go version
go version go1.13.5 linux/amd64

Does this issue reproduce with the latest release?

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/builds/assetstore/asv2/.go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build762445655=/tmp/go-build -gno-record-gcc-switches"

What did you do?

simply call Write([]byte)

func (b *simpleWriter) writeLine(p []byte) {
	if b.isColored {
		b.wr.Write(p)
		return
	}

	escaped := false
	for i := 0; i < len(p); i++ {
		if !escaped {
			if p[i] == 0x1b && i+1 < len(p) && p[i+1] == '[' {
				escaped = true
			} else {
				err := b.wr.WriteByte(p[i])
				if err != nil {
					fmt.Fprintf(os.Stderr, "[writer] Failed to write to log, %v\n", err)
					b.wr.Reset(b.wr)
					break
				}
			}
		} else {
			if p[i] == 'm' {
				escaped = false
			}
		}
	}
}

What did you expect to see?

We could panic instead.

What did you see instead?

Infinite loop causing stack overflow

runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

runtime stack:
runtime.throw(0x13f9843, 0xe)
    /usr/local/go/src/runtime/panic.go:774 +0x72
runtime.newstack()
    /usr/local/go/src/runtime/stack.go:1046 +0x6e9
runtime.morestack()
    /usr/local/go/src/runtime/asm_amd64.s:449 +0x8f

goroutine 10 [running]:
bufio.(*Writer).Write(0xc000078d40, 0xc0004a0000, 0x10000, 0x10000, 0x0, 0x0, 0x0)
    /usr/local/go/src/bufio/bufio.go:619 +0x246 fp=0xc025ad4320 sp=0xc025ad4318 pc=0x5c1626
bufio.(*Writer).Flush(0xc000078d40, 0x0, 0x0)
    /usr/local/go/src/bufio/bufio.go:593 +0x75 fp=0xc025ad4380 sp=0xc025ad4320 pc=0x5c1255
bufio.(*Writer).Write(0xc000078d40, 0xc0004a0000, 0x10000, 0x10000, 0x0, 0x0, 0x0)
    /usr/local/go/src/bufio/bufio.go:629 +0xe4 fp=0xc025ad43e0 sp=0xc025ad4380 pc=0x5c14c4
bufio.(*Writer).Flush(0xc000078d40, 0x0, 0x0)
    /usr/local/go/src/bufio/bufio.go:593 +0x75 fp=0xc025ad4440 sp=0xc025ad43e0 pc=0x5c1255
bufio.(*Writer).Write(0xc000078d40, 0xc0004a0000, 0x10000, 0x10000, 0x0, 0x0, 0x0)
    /usr/local/go/src/bufio/bufio.go:629 +0xe4 fp=0xc025ad44a0 sp=0xc025ad4440 pc=0x5c14c4
bufio.(*Writer).Flush(0xc000078d40, 0x0, 0x0)
    /usr/local/go/src/bufio/bufio.go:593 +0x75 fp=0xc025ad4500 sp=0xc025ad44a0 pc=0x5c1255
bufio.(*Writer).Write(0xc000078d40, 0xc0004a0000, 0x10000, 0x10000, 0x0, 0x0, 0x0)
    /usr/local/go/src/bufio/bufio.go:629 +0xe4 fp=0xc025ad4560 sp=0xc025ad4500 pc=0x5c14c4
bufio.(*Writer).Flush(0xc000078d40, 0x0, 0x0)
...
@agnivade
Copy link
Contributor

Please show us a working sample that shows the problem. Thanks.

@agnivade agnivade added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Apr 16, 2020
@antong
Copy link
Contributor

antong commented Apr 16, 2020

The only thing I can think of that could lead to this is if you reset a Writer to Write to itself! https://play.golang.org/p/fyrX0v3glpM

If you do that, I think you deserve recursion til stack exhaustion :-)

@antong
Copy link
Contributor

antong commented Apr 16, 2020

Actually, this must have been what @Nemo-G did, as Flush() calls Write() only on the underlying Writer, and the first argument to both Flush() and Write() in the stack trace have the same pointer 0xc000078d40. So, the bufio.Writer has itself as underlying Writer.

@Nemo-G
Copy link
Author

Nemo-G commented Apr 16, 2020

@agnivade Code fragment updated.
@antong Thanks for the updates! I did find such Reset in legacy code I just pasted. This comes from a self-defined writer for logging. I'm not familiar with this package. Could you provide any suggestion regarding my case? How should I do Reset here?

@ianlancetaylor
Copy link
Contributor

A bufio.Writer is a buffer wrapped around a different writer. The Reset method permits you to change the writer that it wraps around. It makes no sense to Reset a bufio.Writer to point to itself.

I'm going to close this issue because it doesn't sound like there is a bug in Go here. Please comment if you disagree.

If you want help with Go, please use a forum. See https://golang.org/wiki/Questions. Thanks.

@Nemo-G
Copy link
Author

Nemo-G commented Apr 17, 2020

@ianlancetaylor Sure. Sorry for the trouble. Thanks for your help!

@golang golang locked and limited conversation to collaborators Apr 17, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Projects
None yet
Development

No branches or pull requests

5 participants