Calling closure breaks the stack

102 views
Skip to first unread message

Sergei Skorobogatov

unread,
Mar 2, 2010, 8:42:27 PM3/2/10
to golang-nuts
Hi all.

I use a lot of recursive closures in my experimental Go project.
And my program terminates with runtime error

SIGSEGV: segmentation violation

The error seems to be in Go runtime (or in Go compiler), because the
calling stacks in running goroutines are not printed.

I wrote a simple stack printer:

func stacktrace(name string) {
ok := true
var line int
fmt.Printf("%s: ", name)
for i := 1; ok; i++ {
if _, _, line, ok = runtime.Caller(i); ok {
fmt.Printf("%d ",line)
}
}
fmt.Printf("\n")
}

It walks through call stack and prints a line number for every
function frame.

I inserted calls to this stacktrace in some points in my code and I
found the place, where calling a closure breaks the stack. The code
looks like this:
...
next := func() {
stacktrace("next")
...
}
...
term = func() {
...
stacktrace("term")
next() // calling "next" breaks the stack
...
}

It outputs the following:

term: 716 677 736 677 736 677 736 677 736 677 736 677 736 677 736 677
736 677 630 616 602 563 538 490 391 349 324 812 140
next: 171
SIGSEGV: segmentation violation
Faulting address: 0x7d400014bb7
PC=0x40cade

(There is closure "term" somewhere deep in the stack, and it calls
closure "next". And suddenly stack becomes broken.)

My project is rather large (about 3500 lines of code), and I can't
reproduce the bug in a little sample :-(
Should I send all the sources to the developers of Go compiler?

Russ Cox

unread,
Mar 2, 2010, 8:51:26 PM3/2/10
to Sergei Skorobogatov, golang-nuts
In general the stack trace code has a tough time
tracing through closures, because closure functions
are allocated at run time and so there's no debug
info in the binary for them. So it's common for stack
traces to stop at closures. runtime.Caller should not
seg fault, but it's not too surprising that it did.

Was the original crash also in runtime.Caller, or
were you trying to find a location in your own code
where a different crash happened?

Russ

Sergei Skorobogatov

unread,
Mar 2, 2010, 9:04:27 PM3/2/10
to golang-nuts
The crash is not in runtime.Caller.
When I modify the code as follows:

...
next := func() {
stacktrace("next")

fmt.Printf("stacktrace succeded\n")
...
}

...
term = func() {
...
stacktrace("term")
next() // calling "next" breaks the stack
...
}

it outputs:

term: 717 678 737 678 737 678 737 678 737 678 737 678 737 678 737 678
737 678 631 617 603 564 539 491 392 350 325 813 140
next: 171
stacktrace succeded


SIGSEGV: segmentation violation
Faulting address: 0x7d400014bb7
PC=0x40cade

So it is not the fault of runtime.Caller.
I know the place where crash happens. Closure "next" attemps to use
channel "ts", that contains garbage due to broken stack.

next := func() {
stacktrace("next")

fmt.Printf("stacktrace succeded\n")

tok = <-ts // here we crash

Michael Antonelli

unread,
Mar 2, 2010, 10:02:07 PM3/2/10
to golang-nuts
Is your channel initialized properly.
I had a similar issue, i had a global/package variable declared like
this

var Ch chan string

and in main
func main (){
....
Ch := logger.Start()//returns a chan string
}

Because of using := to assign the channel, that assignment was only
valid inside of main, everywhere else, it was still uninitialized.
This caused a segfault.
If your channel is predeclared with var, make sure you do not use :=
to assign it

Sergei Skorobogatov

unread,
Mar 3, 2010, 6:19:30 AM3/3/10
to golang-nuts
Everything is initialized properly, and program works quite well, if I
modify closures to be usual functions.

Moreover, as Go is safe language, I can't destroy memory by myself. If
it becomes destroyed, it means there is a bug in Go runtime (or in Go
compiler).

On Mar 3, 6:02 am, Michael Antonelli <michael.k.antone...@gmail.com>
wrote:

Russ Cox

unread,
Mar 4, 2010, 7:17:53 PM3/4/10
to Sergei Skorobogatov, golang-nuts
This ended up not having to do with closures directly.
It was a stack splitting bug tickled by slightly different
stack frame sizes depending on whether closures
were being used. It's fixed in tip and will be in the
next release.

Russ

Reply all
Reply to author
Forward
0 new messages