How to interpret Go stacktrace

huangapple go评论81阅读模式
英文:

How to interpret Go stacktrace

问题

当运行Go程序时,我遇到了以下堆栈跟踪:

        /home/travis/.gimme/versions/go1.6.linux.amd64/src/runtime/panic.go:464 +0x3e6
github.com/DataDog/datadog-go/statsd.(*Client).Event(0x0, 0xc8200c7ec8, 0x0, 0x0)
        /home/travis/gopath/src/github.com/DataDog/datadog-go/statsd/statsd.go:286 +0x11f
github.com/some/path/server.(*Server).buildAndUpdate(0xc820024068, 0xc820064600, 0x0, 0x0)
        /home/travis/gopath/src/github.com/some/path/server/http.go:86 +0xf9f
created by github.com/some/path/server.(*Server).processPullRequestEvent
        /home/travis/gopath/src/github.com/some/path/server/http.go:169 +0x53f

Event函数的签名是:

func (c *Client) Event(e *Event) error

可以在这里查看:https://github.com/DataDog/datadog-go/blob/cc2f4770f4d61871e19bfee967bc767fe730b0d9/statsd/statsd.go#L285

Event的类型定义可以在这里查看:https://github.com/DataDog/datadog-go/blob/cc2f4770f4d61871e19bfee967bc767fe730b0d9/statsd/statsd.go#L333

Client的类型定义可以在这里查看:https://github.com/DataDog/datadog-go/blob/cc2f4770f4d61871e19bfee967bc767fe730b0d9/statsd/statsd.go#L59

我的问题是,我如何解释这行代码中的内存地址,以及更一般地说,涉及到类型变量作为目标和参数的堆栈跟踪?

github.com/DataDog/datadog-go/statsd.(*Client).Event(0x0, 0xc8200c7ec8, 0x0, 0x0)

当我查看了http://www.goinggo.net/2015/01/stack-traces-in-go.html(这是我能找到的唯一关于此主题的信息)时,我没有看到任何关于如何解释涉及结构体的输出的内容。

英文:

I am getting this stacktrace when running a go program:

        /home/travis/.gimme/versions/go1.6.linux.amd64/src/runtime/panic.go:464 +0x3e6
github.com/DataDog/datadog-go/statsd.(*Client).Event(0x0, 0xc8200c7ec8, 0x0, 0x0)
        /home/travis/gopath/src/github.com/DataDog/datadog-go/statsd/statsd.go:286 +0x11f
github.com/some/path/server.(*Server).buildAndUpdate(0xc820024068, 0xc820064600, 0x0, 0x0)
        /home/travis/gopath/src/github.com/some/path/server/http.go:86 +0xf9f
created by github.com/some/path/server.(*Server).processPullRequestEvent
        /home/travis/gopath/src/github.com/some/path/server/http.go:169 +0x53f

The signature of the Event function is:

func (c *Client) Event(e *Event) error

which can also be seen here: https://github.com/DataDog/datadog-go/blob/cc2f4770f4d61871e19bfee967bc767fe730b0d9/statsd/statsd.go#L285

The type definition for Event can be seen here: https://github.com/DataDog/datadog-go/blob/cc2f4770f4d61871e19bfee967bc767fe730b0d9/statsd/statsd.go#L333

The type definition for Client can be seen here: https://github.com/DataDog/datadog-go/blob/cc2f4770f4d61871e19bfee967bc767fe730b0d9/statsd/statsd.go#L59

My question is, how do I interpret the memory addresses on this line, and more generally, any stack traces which involve typed variables as targets and as arguments?

github.com/DataDog/datadog-go/statsd.(*Client).Event(0x0, 0xc8200c7ec8, 0x0, 0x0)

When I looked at http://www.goinggo.net/2015/01/stack-traces-in-go.html (which is the only information I was able to find on the subject), I didn't see anything about how to interpret the output when structs were involved.

答案1

得分: 27

感谢@twotwotwo的评论,我想我找到了答案。

在这行代码中:

github.com/DataDog/datadog-go/statsd.(*Client).Event(0x0, 0xc8200c7ec8, 0x0, 0x0)
  • 第一个0x0*Client,确实是nil。
  • 0xc8200c7ec8*Event
  • 接下来的0x0, 0x0表示返回类型为error的返回值。根据http://blog.golang.org/error-handling-and-go的说明,error是一个接口。根据http://research.swtch.com/interfaces的说明,接口被存储为两个指针。第一个指针指向接口中存储的类型信息,第二个指针指向接口中存储的数据。

我编写了以下程序,以向自己演示不同函数签名在堆栈跟踪中的显示方式:

package main

import "errors"

type X struct {
        i int
}

type Y struct {
}

func (y *Y) foo(x *X) {
        panic("panic in foo")
}

func (y *Y) bar(x *X) (*Y) {
        panic("panic in bar")
        return y
}

func (y *Y) baz(x *X) (error) {
        panic("panic in baz")
        return errors.New("error in baz")
}

func (y *Y) bam() {
        panic("panic in bam")
}

func main() {
        y := new(Y)
        x := new(X)
        // comment out the ones you don't want to check
        y.foo(x)
        y.bar(x)
        y.baz(x)
        y.bam()
}

当调用bam函数时,它作用于*Y类型,没有参数或返回值,输出包含:

main.(*Y).bam(0xc82002df48)

当调用foo函数时,它作用于*Y类型,接受一个*X类型的参数,没有返回值,输出包含:

main.(*Y).foo(0xc820033f30, 0xc820033f30)

当调用bar函数时,它作用于*Y类型,接受一个*X类型的参数,并返回一个*Y类型的值,输出包含:

main.(*Y).bar(0xc820033f30, 0xc820033f30, 0x40fb46)

当调用baz函数时,它作用于*Y类型,接受一个*X类型的参数,并返回一个error类型的值(它是一个接口),输出包含:

main.(*Y).baz(0xc820033f38, 0xc820033f38, 0x0, 0x0)
英文:

Thanks to a comment from @twotwotwo, I think I figured this out.

In this line

github.com/DataDog/datadog-go/statsd.(*Client).Event(0x0, 0xc8200c7ec8, 0x0, 0x0)
  • the first 0x0 is the *Client, which is indeed nil.
  • 0xc8200c7ec8 is *Event
  • the following 0x0, 0x0 represent the return value of type error. error, according to http://blog.golang.org/error-handling-and-go, is an interface. According to http://research.swtch.com/interfaces, interfaces are stored as two pointers. The first pointer points to the type information stored in the interface, and the second pointer points to the data stored in the interface.

I wrote the following program to demonstrate to myself how different function signatures appear in a stack trace:

package main

import "errors"

type X struct {
        i int
}

type Y struct {
}

func (y *Y) foo(x *X) {
        panic("panic in foo")
}

func (y *Y) bar(x *X) (*Y) {
        panic("panic in bar")
        return y
}

func (y *Y) baz(x *X) (error) {
        panic("panic in baz")
        return errors.New("error in baz")
}

func (y *Y) bam() {
        panic("panic in bam")
}

func main() {
        y := new(Y)
        x := new(X)
        // comment out the ones you don't want to check
        y.foo(x)
        y.bar(x)
        y.baz(x)
        y.bam()
}

When bam is called, which acts on *Y but has no arguments or return value, the output contains:

main.(*Y).bam(0xc82002df48)

When foo is called, which acts on *Y and takes a *X as argument, but has no return value, the output contains:

main.(*Y).foo(0xc820033f30, 0xc820033f30)

When bar is called, which acts on *Y, takes a *X as argument, and returns a *Y, the output contains:

main.(*Y).bar(0xc820033f30, 0xc820033f30, 0x40fb46)

When baz is called, which acts on *Y, takes *X as argument, and returns an error (which is an interface), the output contains:

main.(*Y).baz(0xc820033f38, 0xc820033f38, 0x0, 0x0)

答案2

得分: 2

你遇到的是空指针解引用错误(nil pointer dereference)。(除非你正在使用unsafe包,但你可能不应该去碰它,所以我假设你没有使用。)

github.com/some/path/server/http.go:86调用func (c *Client) Event(e *Event) error时,看起来e参数是nil

英文:

What you have is a nil pointer dereference. (Unless you are using package unsafe, which you probably shouldn't touch, so I'm assuming you're not.)

It looks like the e argument to func (c *Client) Event(e *Event) error is nil when called from github.com/some/path/server/http.go:86.

答案3

得分: 1

基本上:方法接收器(如果有),显式参数(如果有),返回值(如果有)。

要理解堆栈跟踪,首先需要了解Go的数据结构的内部表示。例如,切片类型的参数在函数的堆栈跟踪中有三个组成部分,因此有三个值:data(一个指针),len(一个int),cap(一个int)。

你可能会发现这篇文章有用。

英文:

Basicly: method receiver(if any), explicit arguments(if any), return values(if any).

To understand the stack traces, you need to first understand Go's data structures' internal representation. For example, arguments of slice type have three components thus three values in the stack trace of the func: data(a pointer), len(an int), cap(an int).

You might find this article useful.

huangapple
  • 本文由 发表于 2016年4月7日 02:47:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/36459827.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定