cmd/link: avoid stamping runtime.defaultGOROOT when paths are being trimmed

Previously, runtime.GOROOT() would return the string "go" in a binary
build with -trimpath. This change stamps the empty string instead,
using a sentinel value passed from cmd/go that looks like the GOROOT
environment variable (either "$GOROOT" or "%GOROOT%", depending on the
platform).

Fixes #51461

Change-Id: I1f10ef2435016a7b6213bd8c547df911f7feeae7
Reviewed-on: https://go-review.googlesource.com/c/go/+/390024
Trust: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
Reviewed-by: Russ Cox <rsc@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Bryan C. Mills 2022-03-15 16:37:50 -04:00 committed by Bryan Mills
parent 9a932c5712
commit 9ac75d3951
4 changed files with 74 additions and 4 deletions

View File

@ -27,7 +27,7 @@ import (
)
// The 'path' used for GOROOT_FINAL when -trimpath is specified
const trimPathGoRootFinal = "go"
const trimPathGoRootFinal string = "$GOROOT"
var runtimePackages = map[string]struct{}{
"internal/abi": struct{}{},

View File

@ -0,0 +1,63 @@
# Regression test for https://go.dev/issue/51461 and https://go.dev/issue/51483.
#
# When built with -trimpath, runtime.GOROOT() returned the bogus string "go"
# if GOROOT was not set explicitly in the environment.
# It should instead return the empty string, since we know that we don't
# have a valid path to return.
#
# TODO(#51483): when runtime.GOROOT() returns the empty string,
# go/build should default to 'go env GOROOT' instead.
[short] skip
env GOROOT=
env GOROOT_FINAL=
go run .
stdout '^GOROOT '$TESTGO_GOROOT'$'
stdout '^runtime '$TESTGO_GOROOT${/}src${/}runtime'$'
go test -v .
stdout '^GOROOT '$TESTGO_GOROOT'$'
stdout '^runtime '$TESTGO_GOROOT${/}src${/}runtime'$'
! go run -trimpath .
stdout '^GOROOT $'
stderr '^package runtime is not in GOROOT \(src'${/}'runtime\)$'
! go test -trimpath -v .
stdout '^GOROOT $'
stdout '^package runtime is not in GOROOT \(src'${/}'runtime\)$'
-- go.mod --
module example
go 1.19
-- main.go --
package main
import (
"fmt"
"go/build"
"os"
"runtime"
)
func main() {
fmt.Println("GOROOT", runtime.GOROOT())
p, err := build.Default.Import("runtime", "", build.FindOnly)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Println("runtime", p.Dir)
}
-- main_test.go --
package main
import "testing"
func TestMain(*testing.M) {
main()
}

View File

@ -119,8 +119,13 @@ func Main(arch *sys.Arch, theArch Arch) {
}
}
final := gorootFinal()
addstrdata1(ctxt, "runtime.defaultGOROOT="+final)
if final := gorootFinal(); final == "$GOROOT" {
// cmd/go sets GOROOT_FINAL to the dummy value "$GOROOT" when -trimpath is set,
// but runtime.GOROOT() should return the empty string, not a bogus value.
// (See https://go.dev/issue/51461.)
} else {
addstrdata1(ctxt, "runtime.defaultGOROOT="+final)
}
buildVersion := buildcfg.Version
if goexperiment := buildcfg.Experiment.String(); goexperiment != "" {

View File

@ -804,7 +804,9 @@ func gorootFinal() string {
func expandGoroot(s string) string {
const n = len("$GOROOT")
if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') {
return filepath.ToSlash(filepath.Join(gorootFinal(), s[n:]))
if final := gorootFinal(); final != "" {
return filepath.ToSlash(filepath.Join(final, s[n:]))
}
}
return s
}