Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

runtime: goroutine stack exceeds 1000000000-byte limit, fatal error: stack overflow on printing a nested struct

I have a nested struct.

type ConfigOne struct {
    // Daemon section from config file.
    Daemon daemon
}
type daemon struct {
    Loglevel int
    Logfile string
}

And I have a String() string method on that type, which I am trying to return the nested struct elements as

func (c ConfigOne)String()  string{
    return fmt.Sprintf("%+v\n", c)
}

When I am trying to print it as

c := &modules.ConfigOne{}
c.Daemon.Loglevel = 1
c.Daemon.Logfile = "/tmp/test.log"
modules.Logger.Infoln(c.String())

I am getting the error

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

runtime stack: runtime.throw(0x6ea3b7, 0xe) ...

After going through the error, I could see repeated lines similar to the below one

modules/structs.go:31 +0x77 fp=0xc440100398 sp=0xc440100328 go-consume/modules.(*ConfigOne).String(0xc42abcb4e0, 0x70bc08, 0xc42abd6300) :1 +0x64 fp=0xc4401003d8 sp=0xc440100398 fmt.(*pp).handleMethods(0xc42abd6300, 0xc400000076, 0x410301)

and finally, before dying,

modules/structs.go:31 +0xc0 fp=0xc440103d18 sp=0xc440103ca8 ...additional frames elided...

goroutine 17 [syscall, locked to thread]: runtime.goexit()

which I believe is caused by going into some infinite recursion.

I tried my luck to find the cause and reached here, which I believe is the same issue. However I couldn't understand the explanation in that thread.

If I try to print the individual nested struct as

func (c ConfigOne)String() string{
    //return fmt.Sprintf("%+v\n", c.Daemon.Loglevel)
    return fmt.Sprintf("%+v\n", c.Daemon)
}

it is working fine, and log shows the fields as

2017/03/05 01:28:25 go-consume.go:38: INFO: {Loglevel:1 Logfile:/tmp/test.log}

Can someone kindly explain how the former String() method is resulting in an infinite recursion and a stackoverflow, and what is the best way to overcome this?

like image 483
nohup Avatar asked Mar 04 '17 20:03

nohup


1 Answers

The %v and %+v formats use the value of String() if the type implements it. Therefore, using %+v on a type within the String() function for that type causes infinite recursion. Instead of using %+v in the String() function, you'll have to construct your own string, showing the contents of the structure in whatever way you see fit.

like image 197
Andy Schweig Avatar answered Nov 15 '22 18:11

Andy Schweig