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

debug/dwarf: DW_TAG_reference_type causes a panic when encountered by debug/dwarf #29601

Open
ilch1 opened this Issue Jan 7, 2019 · 11 comments

Comments

Projects
None yet
5 participants
@ilch1
Copy link

ilch1 commented Jan 7, 2019

What version of Go are you using (go version)?

$ go version
go version go1.11 darwin/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/ilya/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/ilya/volx/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
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 -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/nk/ft8bd8fx68n2gv_l5ft8yhvw0000gn/T/go-build278199837=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

Tried to parse the dwarf information of an elf file.

Compile the following:

//g++ -g test.cc 
int i = 3;
int &bad = i;

int main() {
        return 0;
}

Then try to parse the DWARF information from the compiled ELF file, using:

//crash.go
package main

import (
        "debug/dwarf"
        "debug/elf"
        "fmt"
        "os"
)

func main() {
        elf_file, err := elf.Open(os.Args[1])
        defer elf_file.Close()
        if err != nil {
                fmt.Fprintf(os.Stderr, "open failed %v", err)
                os.Exit(1)
        }
        data, err := elf_file.DWARF()
        r := data.Reader()
        for {
                e, err := r.Next()
                if err != nil || e == nil {
                        break
                }
                if e.Tag == dwarf.TagVariable {
                        genAttr := e.Val(dwarf.AttrType)
                        typOff, ok := genAttr.(dwarf.Offset)
                        if !ok {
                                fmt.Fprint(os.Stderr, "Bad type")
                                os.Exit(1)
                        }
                        _, err := data.Type(typOff)
                        if err != nil {
                                fmt.Fprint(os.Stderr, "err in type decode: %v\n", err)
                                os.Exit(1)
                        }
                }
        }
}

Run:
<prog> a.out

What did you expect to see?

data.Type() extracting the type of each variable

What did you see instead?

$ ./crash ../a.out
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x10a182e]

goroutine 1 [running]:
debug/dwarf.(*Data).readType(0xc0000ba000, 0x10fd3ae, 0x4, 0x1118540, 0xc0000c0240, 0xc00000005c, 0xc000066c00, 0xc00006e0e0, 0x0, 0x0, ...)
        /usr/local/go/src/debug/dwarf/type.go:703 +0xe1e
debug/dwarf.(*Data).readType.func3(0xc000066db0, 0xc000066c00, 0xc000000062)
        /usr/local/go/src/debug/dwarf/type.go:365 +0x1a0
debug/dwarf.(*Data).readType(0xc0000ba000, 0x10fd3ae, 0x4, 0x1118540, 0xc0000c01b0, 0xc000000062, 0xc000066c00, 0xc00006e0e0, 0x0, 0x0, ...)
        /usr/local/go/src/debug/dwarf/type.go:576 +0x260a
debug/dwarf.(*Data).Type(0xc0000ba000, 0xc000000062, 0x10d1540, 0xc00007f020, 0x0, 0x0)
        /usr/local/go/src/debug/dwarf/type.go:278 +0x85
main.main()
        /Users/ilya/test/crash/example.go:31 +0x1c9

It appears that the switch e.Tag { in debug/dwarf/type.go:readType() does not handle some dwarf tag types. This results in no error generated and use of a uninitialized global variable (that was not initialized in the switch statements), which ultimately causes the nil dereference.

@ianlancetaylor ianlancetaylor added this to the Go1.13 milestone Jan 7, 2019

@gopherbot

This comment has been minimized.

Copy link

gopherbot commented Jan 9, 2019

Change https://golang.org/cl/157177 mentions this issue: debug/dwarf: add minimal support for C++ reference types

@thanm thanm self-assigned this Jan 9, 2019

@thanm

This comment has been minimized.

Copy link
Member

thanm commented Jan 9, 2019

I sent a CL to address this.

@ilch1 please be warned, I suspect that there are other DWARF C++isms that aren't handled by the Go debug/dwarf package. If you are writing a tool that consumes DWARF from a mixed C++/Go binary (and you're interested primarily in the Go or C parts) you might consider adapting your code to skip the those compile units based on producer.

@gopherbot

This comment has been minimized.

Copy link

gopherbot commented Jan 11, 2019

Change https://golang.org/cl/157537 mentions this issue: debug/dwarf: avoid crashing when unknown type tag encountered

@aclements

This comment has been minimized.

Copy link
Member

aclements commented Jan 11, 2019

I wouldn't generally recommend using Data.Type() for arbitrary types. We should fix the crash (and probably return an error), but that was never meant to represent all possible DWARF types. If you want to process the DWARF types, it's better to use the DWARF entries directly.

@ilch1

This comment has been minimized.

Copy link

ilch1 commented Jan 14, 2019

I sent a CL to address this.

@ilch1 please be warned, I suspect that there are other DWARF C++isms that aren't handled by the Go debug/dwarf package. If you are writing a tool that consumes DWARF from a mixed C++/Go binary (and you're interested primarily in the Go or C parts) you might consider adapting your code to skip the those compile units based on producer.

Yes, there are a several C++ DWARF tags that are not handled by the debug/dwarf package. DW_TAG_reference_type was the first one that I happened to have encountered. The proposal of returning an error when an unsupported type is encountered is a good work around.

Is the goal to eventually add support for decoding all of DWARF tags defined in const.go?

@aclements

This comment has been minimized.

Copy link
Member

aclements commented Jan 14, 2019

I have a counter-proposal: add a dwarf.UnsupportedType that simply wraps the *dwarf.Entry of unsupported types and use that where Data.Type encounters things it doesn't know. The advantage of this over returning an error is that Data.Type can still mostly decode a larger compound type, even if it doesn't understand some part of it.

Is the goal to eventually add support for decoding all of DWARF tags defined in const.go?

I think that's an anti-goal. debug/dwarf is basically frozen at this point. The API has many issues and a lot of holes, and there's a general idea that the dwarf package (and maybe all of debug/*?) should move to golang.org/x/debug and possibly get fixed up in many ways.

@ilch1

This comment has been minimized.

Copy link

ilch1 commented Jan 14, 2019

I have a counter-proposal: add a dwarf.UnsupportedType that simply wraps the *dwarf.Entry of unsupported types and use that where Data.Type encounters things it doesn't know. The advantage of this over returning an error is that Data.Type can still mostly decode a larger compound type, even if it doesn't understand some part of it.

I like this approach better. There is dwarf.UnspecifiedType that is used for TagUnspecifiedType -- your proposal would treat unsupported tags in a similar way.

@ilch1

This comment has been minimized.

Copy link

ilch1 commented Jan 14, 2019

Is the goal to eventually add support for decoding all of DWARF tags defined in const.go?

I think that's an anti-goal. debug/dwarf is basically frozen at this point. The API has many issues and a lot of holes, and there's a general idea that the dwarf package (and maybe all of debug/*?) should move to golang.org/x/debug and possibly get fixed up in many ways.

I wasn't aware that debug/* may move to golang.org/x/debug. I agree that debug/dwarf package may have some holes. FWIW, we've been using debug/dwarf package to decode DWARF information from ELF and Mach-O files and have been happy with it. My team would be interested in addressing some of the limitations of debug/dwarf in the future.

@thanm

This comment has been minimized.

Copy link
Member

thanm commented Jan 14, 2019

I am on board for the idea of dwarf.UnsupportedType -- I'll see about creating a patch for that.

@gopherbot

This comment has been minimized.

Copy link

gopherbot commented Jan 21, 2019

Change https://golang.org/cl/158797 mentions this issue: debug/dwarf: more graceful handling of unsupported types

@thanm

This comment has been minimized.

Copy link
Member

thanm commented Jan 21, 2019

Sent a new CL with dwarf.UnsupportedType: https://go-review.googlesource.com/c/go/+/158797

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment