davecgh / go-spew

Implements a deep pretty printer for Go data structures to aid in debugging
ISC License
6.09k stars 366 forks source link

fatal error: stack overflow #44

Closed bezigon closed 7 years ago

bezigon commented 8 years ago

I used a Delve debugger and go version go1.6.2 darwin/amd64. When tried to log token's struct I got this message

(*oauth2.token)(0xc82006cea0)(
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

whereas using another method fmt.Printf I get the following

&oauth2.token{Token:oauth2.Token{AccessToken:"(redacted)", TokenType:"", RefreshToken:"", Expiry:time.Time{sec:0, nsec:0, loc:(*time.Location)(0x8ccd80)}, raw:interface {}(nil)}}

Setting the MaxDepth limit doesn't work.

davecgh commented 8 years ago

Thanks for the report.

Can you provide code for a simple reproduction case? It looks to me like it's not seeing that it's a recursive structure for some reason, however the tests include tests for both self-referential structs and transitively self-referential structs, so without solid reproduction code it's going to be pretty difficult to hunt this down.

bezigon commented 8 years ago

Sorry for the delay, here is my repo to reproduce the problem.

dmitshur commented 8 years ago

Also, what version of spew are you using? Is it the latest?

It's hard to reproduce the problem with your sample because to trigger the spew call, one must be logged in. Do you have a testing vk account to share to make it easier?

bezigon commented 8 years ago

Yes, of course. (redacted) Such a kind of security through obscurity :)

dmitshur commented 8 years ago

Not sure how to use that, is there a username and password combination? Never mind, I understood what you meant. I hope this is a testing/dummy account because it's not very obscure. :)

Alternatively, if you can post a reproduce sample that doesn't require logging in, that'd work too.

Also, what version of spew are you using? Is it the latest?

Have you checked if that was the case?

dmitshur commented 8 years ago

Ok, I can reproduce this with latest version of go-spew. /cc @davecgh

dmitshur commented 8 years ago

go-goon worked okay on it, this was the result of goon.DumpExpr(token):

token = (*oauth2.token)(&oauth2.token{
    Token: (oauth2.Token)(oauth2.Token{
        AccessToken:  (string)("<redacted>"),
        TokenType:    (string)(""),
        RefreshToken: (string)(""),
        Expiry: (time.Time)(time.Time{
            sec:  (int64)(0),
            nsec: (int32)(0),
            loc: (*time.Location)(&time.Location{
                name:       (string)("UTC"),
                zone:       ([]time.zone)(nil),
                tx:         ([]time.zoneTrans)(nil),
                cacheStart: (int64)(0),
                cacheEnd:   (int64)(0),
                cacheZone:  (*time.zone)(nil),
            }),
        }),
        raw: (interface{})(nil),
    }),
})

From there, I was able to figure out that it's an issue in github.com/GoIncremental/negroni-oauth2 package itself, and not in spew. It can be reproduced with fmt.Println.

fmt.Println(token)

Simply doing that also causes the same stack overflow:

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

runtime stack:
runtime.throw(0x4888a0, 0xe)
    /usr/local/go/src/runtime/panic.go:547 +0x90
runtime.newstack()
    /usr/local/go/src/runtime/stack.go:940 +0xb11
runtime.morestack()
    /usr/local/go/src/runtime/asm_amd64.s:359 +0x7f

goroutine 5 [stack growth]:
runtime.rawmem(0x8, 0x0)
    /usr/local/go/src/runtime/malloc.go:808 fp=0xc840500298 sp=0xc840500290
runtime.growslice(0x34aa40, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0)
    /usr/local/go/src/runtime/slice.go:95 +0x233 fp=0xc840500308 sp=0xc840500298
runtime.growslice_n(0x34aa40, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0)
    /usr/local/go/src/runtime/slice.go:44 +0xc7 fp=0xc840500360 sp=0xc840500308
fmt.(*pp).doPrintf(0xc825c12270, 0x4893d0, 0xa, 0xc840500780, 0x1, 0x1)
    /usr/local/go/src/fmt/print.go:1113 +0x1a1 fp=0xc8405006e8 sp=0xc840500360
fmt.Sprintf(0x4893d0, 0xa, 0xc840500780, 0x1, 0x1, 0x0, 0x0)
    /usr/local/go/src/fmt/print.go:203 +0x6f fp=0xc840500738 sp=0xc8405006e8
github.com/goincremental/negroni-oauth2.(*token).String(0xc8201daa20, 0x0, 0x0)
    /tmp/foofweefvkkkkkke/src/github.com/goincremental/negroni-oauth2/oauth2.go:103 +0xb3 fp=0xc8405007b0 sp=0xc840500738
fmt.(*pp).handleMethods(0xc825c121a0, 0xc800000076, 0x0, 0x1)
    /usr/local/go/src/fmt/print.go:730 +0x62a fp=0xc840500890 sp=0xc8405007b0
fmt.(*pp).printArg(0xc825c121a0, 0x453a40, 0xc8201daa20, 0x76, 0x0, 0x0)
    /usr/local/go/src/fmt/print.go:806 +0x4a9 fp=0xc840500a18 sp=0xc840500890
fmt.(*pp).doPrintf(0xc825c121a0, 0x4893d0, 0xa, 0xc840500e38, 0x1, 0x1)
    /usr/local/go/src/fmt/print.go:1238 +0x1dcd fp=0xc840500da0 sp=0xc840500a18
fmt.Sprintf(0x4893d0, 0xa, 0xc840500e38, 0x1, 0x1, 0x0, 0x0)
    /usr/local/go/src/fmt/print.go:203 +0x6f fp=0xc840500df0 sp=0xc840500da0
github.com/goincremental/negroni-oauth2.(*token).String(0xc8201daa20, 0x0, 0x0)
    /tmp/foofweefvkkkkkke/src/github.com/goincremental/negroni-oauth2/oauth2.go:103 +0xb3 fp=0xc840500e68 sp=0xc840500df0
...

See the bug at https://github.com/GoIncremental/negroni-oauth2/blob/master/oauth2.go#L102-L104, that is an invalid implementation of String() string method since it results in an infinite recursion.

It's related to https://github.com/davecgh/go-spew/issues/45#issuecomment-222380781, except spew is less involved here.

bezigon commented 8 years ago

We just killed two birds with one stone. :D

dmitshur commented 7 years ago

@davecgh I think this issue can be closed. It was a faulty fmt.Stringer implementation in an external library, not go-spew's fault.

Unless you think there's something to be done here?

davecgh commented 7 years ago

Agreed. Thanks for reminding me!