Skip to content

Commit

Permalink
cmd/go: refactor TestScript/build_issue48319 to check a more general …
Browse files Browse the repository at this point in the history
…property

The test previously checked that the DWARF DW_AT_comp_dir attribute
matched GOROOT_FINAL. However, on further consideration, we believe
that DW_AT_comp_dir should not actually match GOROOT_FINAL: the DWARF
spec says that DW_AT_comp_dir records “the current working directory
of the compilation command that produced this compilation unit”, but
the actual working directory of the compilation command proper is a
throwaway directory in the build cache — it is neither stable nor
meaningful.

However, the test was getting at a real issue that we do care about:
namely, that the binary produced by a 'go build' command with cgo
enabled should not reuse a dependency that embeds a stale
GOROOT_FINAL.

This change refactors the test to verify the latter property instead
of checking DW_AT_comp_dir specifically.

For #50183
Updates #48319

Change-Id: I0b1151d9ba3d0ff903f72e27850306406e5cb518
Reviewed-on: https://go-review.googlesource.com/c/go/+/380914
Trust: Bryan Mills <[email protected]>
Run-TryBot: Bryan Mills <[email protected]>
Reviewed-by: Russ Cox <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
  • Loading branch information
Bryan C. Mills committed Jan 26, 2022
1 parent 5b1b80b commit a9eedc0
Showing 1 changed file with 27 additions and 133 deletions.
160 changes: 27 additions & 133 deletions src/cmd/go/testdata/script/build_issue48319.txt
Original file line number Diff line number Diff line change
@@ -1,50 +1,33 @@
# Regression test for https://go.dev/issue/48319:
# cgo builds should not include debug information from a stale GOROOT_FINAL.

[short] skip
[!cgo] skip
[windows] skip # The Go Windows builders have an extremely out-of-date gcc that does not support reproducible builds; see https://go.dev/issue/50824.

# Set up fresh GOCACHE
# This test is sensitive to cache invalidation,
# so use a separate build cache that we can control.
env GOCACHE=$WORK/gocache
mkdir $GOCACHE

# 1. unset GOROOT_FINAL, Build a simple binary with cgo by origin go.
# The DW_AT_comp_dir of runtime/cgo should have a prefix with origin goroot.
env GOROOT_FINAL=
# If using "go run", it is no debuginfo in binary. So use "go build".
# And we can check the stderr to judge if the cache of "runtime/cgo"
# was used or not.
go build -o binary.exe
exec ./binary.exe $TESTGO_GOROOT
stdout 'cgo DW_AT_comp_dir is right in binary'


# 2. GOROOT_FINAL will be changed, the runtime/cgo will be rebuild.
env GOROOT_FINAL=$WORK/gorootfinal
go build -x -o binary.exe
stderr '(clang|gcc)( |\.exe).*gcc_.*\.c'
exec ./binary.exe $GOROOT_FINAL
stdout 'cgo DW_AT_comp_dir is right in binary'


[!symlink] skip

# Symlink the compiler to another path
env GOROOT=$WORK/goroot
symlink $GOROOT -> $TESTGO_GOROOT

# 3. GOROOT_FINAL is same with 2, build with the other go
# the runtime/cgo will not be rebuild.
go build -x -o binary.exe
! stderr '(clang|gcc)( |\.exe).*gcc_.*\.c'
exec ./binary.exe $GOROOT_FINAL
stdout 'cgo DW_AT_comp_dir is right in binary'


# 4. unset GOROOT_FINAL, build with the other go
# the runtime/cgo will be rebuild.
env GOROOT_FINAL=
go build -x -o binary.exe
stderr '(clang|gcc)( |\.exe).*gcc_.*\.c'
exec ./binary.exe $GOROOT
stdout 'cgo DW_AT_comp_dir is right in binary'
# Build a binary using a specific value of GOROOT_FINAL.
env GOROOT_FINAL=$WORK${/}goroot1
go build -o main.exe
mv main.exe main1.exe

# Now clean the cache and build using a different GOROOT_FINAL.
# The resulting binaries should differ in their debug metadata.
go clean -cache
env GOROOT_FINAL=$WORK${/}goroot2
go build -o main.exe
mv main.exe main2.exe
! cmp main2.exe main1.exe

# Set GOROOT_FINAL back to the first value.
# If the build is properly reproducible, the two binaries should match.
env GOROOT_FINAL=$WORK${/}goroot1
go build -o main.exe
cmp -q main.exe main1.exe

-- go.mod --
module main
Expand All @@ -54,100 +37,11 @@ go 1.18
package main

import "C"
import (
"debug/dwarf"
"fmt"
"log"
"os"
"path/filepath"
"strings"
)

import "runtime"

var _ C.int

func main() {
dwarfData, err := readDWARF(os.Args[0])
if err != nil {
log.Fatal(err)
}
goroot := filepath.Join(os.Args[1], "src")
dwarfReader := dwarfData.Reader()
cgopackage := filepath.Join("runtime", "cgo")
var hascgo bool
for {
e, err := dwarfReader.Next()
if err != nil {
log.Fatal(err)
}
if e == nil {
break
}
field := e.AttrField(dwarf.AttrCompDir)
if field == nil {
continue
}
compdir := field.Val.(string)
if strings.HasSuffix(compdir, cgopackage) {
hascgo = true
if !strings.HasPrefix(compdir, goroot) {
fmt.Printf("cgo DW_AT_comp_dir %s contains incorrect path in binary.\n", compdir)
return
}
}
}
if hascgo {
fmt.Println("cgo DW_AT_comp_dir is right in binary")
} else {
fmt.Println("binary does not contain cgo")
}
}
-- read_darwin.go --
package main

import (
"debug/dwarf"
"debug/macho"
)

func readDWARF(exePath string) (*dwarf.Data, error) {
machoFile, err := macho.Open(exePath)
if err != nil {
return nil, err
}
defer machoFile.Close()
return machoFile.DWARF()
}
-- read_elf.go --
// +build android dragonfly freebsd illumos linux netbsd openbsd solaris

package main

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

func readDWARF(exePath string) (*dwarf.Data, error) {
elfFile, err := elf.Open(exePath)
if err != nil {
return nil, err
}
defer elfFile.Close()
return elfFile.DWARF()
}
-- read_windows.go --
package main

import (
"debug/dwarf"
"debug/pe"
)

func readDWARF(exePath string) (*dwarf.Data, error) {
peFile, err := pe.Open(exePath)
if err != nil {
return nil, err
}
defer peFile.Close()
return peFile.DWARF()
println(runtime.GOROOT())
}

0 comments on commit a9eedc0

Please sign in to comment.