Skip to content
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

Closed
ilch1 opened this issue Jan 7, 2019 · 11 comments
Closed
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@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 the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jan 7, 2019
@ianlancetaylor ianlancetaylor added this to the Go1.13 milestone Jan 7, 2019
@gopherbot
Copy link

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
Copy link
Contributor

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
Copy link

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

@aclements
Copy link
Member

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
Copy link
Author

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
Copy link
Member

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
Copy link
Author

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
Copy link
Author

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
Copy link
Contributor

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
Copy link

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

@thanm
Copy link
Contributor

thanm commented Jan 21, 2019

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

@golang golang locked and limited conversation to collaborators Mar 14, 2020
@rsc rsc unassigned thanm Jun 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

5 participants