Skip to content
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

runtime: infinite loop causing stack overflow in bufio #38481

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

Comments

@Nemo-G
Copy link

@Nemo-G 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

@agnivade agnivade commented Apr 16, 2020

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

@antong
Copy link
Contributor

@antong 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 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 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

@ianlancetaylor ianlancetaylor commented Apr 17, 2020

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 Nemo-G commented Apr 17, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.