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

cmd/link: nil pointer dereference #34249

Open
meme opened this issue Sep 12, 2019 · 7 comments

Comments

@meme
Copy link

commented Sep 12, 2019

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

$ go version
go version devel +e7e2b1c2b9 Wed Sep 11 23:01:45 2019 +0000 linux/amd64

(the latest master)

Does this issue reproduce with the latest release?

Exists on 1.13, master and 1.12.9

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

go env Output
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/keegan/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/keegan/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/lib/go"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
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 -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build542873266=/tmp/go-build -gno-record-gcc-switches"

What did you do?

Created a file called main.go, with the following contents:

package main

func main() {

}

Then ran the following commands:

$ go tool compile main.go
$ go tool link -buildmode=plugin main.o

What did you expect to see?

As is the case with go tool link main.o, no output is produced and a .so file will be created.

What did you see instead?

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x30 pc=0x4f80e7]

goroutine 1 [running]:
cmd/link/internal/sym.(*Symbol).AddUintXX(0x0, 0x83dda0, 0x0, 0x4, 0x80e9)
        /go/src/cmd/link/internal/sym/symbol.go:293 +0x47
cmd/link/internal/sym.(*Symbol).AddUint32(...)
        /go/src/cmd/link/internal/sym/symbol.go:149
cmd/link/internal/ld.addDwarfAddrField(0xc000056000, 0x0, 0x0)
        /go/src/cmd/link/internal/ld/dwarf.go:920 +0x88
cmd/link/internal/ld.createUnitLength(0xc000056000, 0x0, 0x0)
        /go/src/cmd/link/internal/ld/dwarf.go:912 +0x45
cmd/link/internal/ld.writeinfo(0xc000056000, 0x0, 0x852, 0x900, 0xc000080e80, 0x8, 0x8, 0xc0010ecff0, 0xc000464d08, 0xc000464cd8, ...)
        /go/src/cmd/link/internal/ld/dwarf.go:1572 +0x19c
cmd/link/internal/ld.dwarfGenerateDebugSyms(0xc000056000)
        /go/src/cmd/link/internal/ld/dwarf.go:1971 +0x517
cmd/link/internal/ld.(*Link).dodata(0xc000056000)
        /go/src/cmd/link/internal/ld/data.go:1753 +0x3491
cmd/link/internal/ld.Main(0x83dda0, 0x10, 0x20, 0x1, 0x7, 0x10, 0x692098, 0x1b, 0x68eb4d, 0x14, ...)
        /go/src/cmd/link/internal/ld/main.go:249 +0xcbb
main.main()
        /go/src/cmd/link/main.go:65 +0x1d6

At https://github.com/golang/go/blob/master/src/cmd/link/internal/sym/symbol.go#L289, s or, self, is nil and at https://github.com/golang/go/blob/master/src/cmd/link/internal/ld/dwarf.go#L1556 the nil symbol is loaded from the dwarf information. Strangely enough, disabling dwarf with -dwarf=false does not prevent this crash.

Furthermore, when inserting the following code at the location above in dwarf.go to skip nil sections:

if s == nil {
  continue
}

It will then trigger the following error when linking:

/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/usr/bin/ld: /tmp/go-link-502601380/go.o: relocation R_X86_64_TPOFF32 against symbol `runtime.tlsg' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: nonrepresentable section on output
collect2: error: ld returned 1 exit status
@agnivade

This comment has been minimized.

Copy link
Member

commented Sep 12, 2019

@thanm

This comment has been minimized.

Copy link
Member

commented Sep 12, 2019

When I do a build of your code using the "go" command (as opposed to raw 'go tool compile' and 'go tool link' invocations), it seems to work fine:

$ go build -o tiny -buildmode=plugin tiny.go
$

When I run the same build using "-x" I can see that the Go command is using a number of other important compiler and linker flags needed for the plugin to work (for example, the '-dynlink' compiler option, which would seem to be mandatory given how plugins are supposed to be used).

Is there a reason why you're not using these options in your 'go tool compile/link' invocations? Thanks.

@meme

This comment has been minimized.

Copy link
Author

commented Sep 12, 2019

I was not aware of the -dynlink option being required, my assumption was that go tool link would manage all the details for me when I set the build mode. Does passing -dynlink to go tool link fix this crash and produce the shared object? If so I'd expect at least a warning or error if the configuration is invalid.

@thanm

This comment has been minimized.

Copy link
Member

commented Sep 12, 2019

I think it is safe to say that that users are expected to build their code "go build" as opposed to raw "go tool compile" and "go tool link" invocations (unlike, say, a C compiler, where you can do just fine with a strategy like "cc -c myfile.c ; cc -o myprog myfile.o").

There may have been a time many releases ago when you could get by on just "go tool compile" and "go tool link", but those days are gone at this point -- the Go command does a lot of careful orchestration of the compiler and linker options depending on what and how you are building. You can see this in action by looking at the output of "go build -x -buildmode=... ...".

@meme

This comment has been minimized.

Copy link
Author

commented Sep 13, 2019

I imagine that a compiler crash is not the intended behaviour when incorrect linker flags are passed though, yes? Additionally, if such is the case, why are these utilities exposed as go subcommands? Is there documentation hinting against the use of these utilities?

@thanm

This comment has been minimized.

Copy link
Member

commented Sep 19, 2019

Many programming tools expose features to make life easier for the developers of those tools. Consider GDB's "maintenance info program-spaces" command, or GCC's "-fdump-tree-all-all" command line options -- yes, they are exposed, but it's not expected that they be used by anyone other than developers of GCC or GDB. The go tool commands fall into the same category.

Regarding the crash on a weird combination of options -- this is surely a bug of some sort... would you like to send a patch?

@meme

This comment has been minimized.

Copy link
Author

commented Sep 19, 2019

Thank you for the elaboration, I understand what you meant now.

I suggested a patch that simply checks for nil before handling the symbol -- that seems to fix the issue. Though the program will still fail to link in the end (see the bottom of the original issue), so I am unable to verify that the resultant program is in working order (and that the nil check is an adequate one as a result). Suggestions are appreciated, else I am willing to just submit the check and assume that the linking error is a result of misuse of the tool (at least it's not a crash)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.