Navigation Menu

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: linker produces invalid binaries on FreeBSD when cgo is used and linkflag -X passed twice #23273

Closed
knz opened this issue Dec 28, 2017 · 4 comments
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. release-blocker
Milestone

Comments

@knz
Copy link

knz commented Dec 28, 2017

tl;dr: generated binary segfaults on init if both 1) uses cgo and 2) -X is passed twice in -ldflags

  • What version of Go are you using (go version)?
go version go1.9.2 freebsd/amd64
  • Does this issue reproduce with the latest release?

yes

  • What operating system and processor architecture are you using (go env)?
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="freebsd"
GOOS="freebsd"
GOPATH="/data/home/kena/src/go"
GORACE=""
GOROOT="/data/home/kena/src/go1.9.2"
GOTOOLDIR="/data/home/kena/src/go1.9.2/pkg/tool/freebsd_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build623559632=/tmp/go-build -gno-record-gcc-switches"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
  • What did you do?

Using the following file test.go:

package main

import "fmt"

// #include <stdio.h>
// int x = 42;
import "C"

var test string

func init() {
        fmt.Println(test, C.x)
}

func main() {
        fmt.Println("world")
}

I ran:

go build -x -ldflags='-X main.test=hello -X main.test=hello'
./test
  • What did you expect to see?
hello 42
world
  • What did you see instead?
unexpected fault address 0x98b270
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x1 addr=0x98b270 pc=0x450982]

goroutine 1 [running, locked to thread]:
runtime.throw(0x4b4dae, 0x5)
        /data/home/kena/src/go1.9.2/src/runtime/panic.go:605 +0x95 fp=0xc42005bbf8 sp=0xc42005bbd8 pc=0x426c95
runtime.sigpanic()
        /data/home/kena/src/go1.9.2/src/runtime/signal_unix.go:374 +0x227 fp=0xc42005bc48 sp=0xc42005bbf8 pc=0x439b97
runtime.memmove(0xc42008c038, 0x98b270, 0x5)
        /data/home/kena/src/go1.9.2/src/runtime/memmove_amd64.s:161 +0x122 fp=0xc42005bc50 sp=0xc42005bc48 pc=0x450982
fmt.(*buffer).WriteString(...)
        /data/home/kena/src/go1.9.2/src/fmt/print.go:82
fmt.(*fmt).padString(0xc4200b0040, 0x98b270, 0x5)
        /data/home/kena/src/go1.9.2/src/fmt/format.go:110 +0x9c fp=0xc42005bcd8 sp=0xc42005bc50 pc=0x47ce2c
fmt.(*fmt).fmt_s(0xc4200b0040, 0x98b270, 0x5)
        /data/home/kena/src/go1.9.2/src/fmt/format.go:328 +0x61 fp=0xc42005bd10 sp=0xc42005bcd8 pc=0x47dbd1
fmt.(*pp).fmtString(0xc4200b0000, 0x98b270, 0x5, 0x76)
        /data/home/kena/src/go1.9.2/src/fmt/print.go:430 +0x11f fp=0xc42005bd48 sp=0xc42005bd10 pc=0x480d6f
fmt.(*pp).printArg(0xc4200b0000, 0x4965e0, 0xc4200841b0, 0x76)
        /data/home/kena/src/go1.9.2/src/fmt/print.go:664 +0x7b5 fp=0xc42005bdc8 sp=0xc42005bd48 pc=0x4830c5
fmt.(*pp).doPrintln(0xc4200b0000, 0xc42005bf40, 0x2, 0x2)
        /data/home/kena/src/go1.9.2/src/fmt/print.go:1136 +0x56 fp=0xc42005be58 sp=0xc42005bdc8 pc=0x486166
fmt.Fprintln(0x71c800, 0xc420094008, 0xc42005bf40, 0x2, 0x2, 0x4960a0, 0xc420084100, 0xc42008c030)
        /data/home/kena/src/go1.9.2/src/fmt/print.go:247 +0x58 fp=0xc42005bec0 sp=0xc42005be58 pc=0x47f568
fmt.Println(0xc42005bf40, 0x2, 0x2, 0xc42008c030, 0xc42005bf60, 0x486478)
        /data/home/kena/src/go1.9.2/src/fmt/print.go:257 +0x57 fp=0xc42005bf10 sp=0xc42005bec0 pc=0x47f667
main.init.0()
        /data/home/kena/src/go/src/github.com/cockroachdb/cockroach/t/test.go:12 +0xc7 fp=0xc42005bf70 sp=0xc42005bf10 pc=0x4866e7
main.init()
        <autogenerated>:1 +0x4e fp=0xc42005bf80 sp=0xc42005bf70 pc=0x4867ce
runtime.main()
        /data/home/kena/src/go1.9.2/src/runtime/proc.go:173 +0x1c5 fp=0xc42005bfe0 sp=0xc42005bf80 pc=0x428325
runtime.goexit()
        /data/home/kena/src/go1.9.2/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42005bfe8 sp=0xc42005bfe0 pc=0x4500b1

If I either remove the cgo usage in test.go or remove the duplicate -X flag in the link flags, the problem goes away and the program runs successfully.

@ianlancetaylor ianlancetaylor added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. release-blocker labels Dec 28, 2017
@ianlancetaylor ianlancetaylor added this to the Go1.11 milestone Dec 28, 2017
@paulzhol
Copy link
Member

This reproduces on linux amd64 with go 1.9.2 as well, here's a minimal version:

package main

// int x = 42;
import "C"

var test string

func main() {
        println(test)
}

The relevant code is this, I think:

func addstrdata(ctxt *Link, name string, value string) {
p := fmt.Sprintf("%s.str", name)
sp := ctxt.Syms.Lookup(p, 0)
Addstring(sp, value)
sp.Type = SRODATA
s := ctxt.Syms.Lookup(name, 0)
s.Size = 0
s.Attr |= AttrDuplicateOK
reachable := s.Attr.Reachable()
Addaddr(ctxt, s, sp)
adduintxx(ctxt, s, uint64(len(value)), SysArch.PtrSize)
// addstring, addaddr, etc., mark the symbols as reachable.
// In this case that is not necessarily true, so stick to what
// we know before entering this function.
s.Attr.Set(AttrReachable, reachable)
strdata = append(strdata, s)
sp.Attr.Set(AttrReachable, reachable)
}

When called multiple times with the same symbol name, the second call will append the string value to main.test.str, as can be seen from objdump.

objdump -t test.ok (single -X arg):

000000000047cee0 l     O .rodata        0000000000000006              main.test.str
00000000006af170 l     O .data  0000000000000010              main.test
0

objdump -t test (two -X args):

000000000047d178 l     O .rodata        000000000000000c              main.test.str
00000000006af170 l     O .data  0000000000000010              main.test

Also the recorded address of main.test is made to no longer point to main.test.str, but to some inaccessible address, which triggers the panic.

@gopherbot
Copy link

Change https://golang.org/cl/85835 mentions this issue: cmd/link: make addstrdata overwrite the same symbol instead of appending

@rsc
Copy link
Contributor

rsc commented Jan 9, 2018

golang.org/cl/86915 will fix this.

@gopherbot
Copy link

Change https://golang.org/cl/86915 mentions this issue: cmd/link: apply -X options after loading symbols

@golang golang locked and limited conversation to collaborators Jan 9, 2019
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. release-blocker
Projects
None yet
Development

No branches or pull requests

5 participants