aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippo Valsorda <filippo@golang.org>2020-04-13 19:39:17 -0400
committerFilippo Valsorda <filippo@golang.org>2020-04-13 19:39:17 -0400
commitb129f40bb33f0061f2820553a6d168a9ef1d2405 (patch)
tree3dcf20d733182fbc7534c5e69291f4a90e67d2ad
parentbb8a1014a32c6f6741ca411fae78392edb83b75b (diff)
parenta57f07aac237d366630e85d080ef1ce0c34f0d09 (diff)
downloadgo-b129f40bb33f0061f2820553a6d168a9ef1d2405.tar.gz
go-b129f40bb33f0061f2820553a6d168a9ef1d2405.zip
[dev.boringcrypto.go1.13] all: merge go1.13.10 into dev.boringcrypto.go1.13
Change-Id: I70aa2adce503fb9119e947b5868a0aa5427b808b
-rw-r--r--src/cmd/compile/internal/syntax/parser_test.go2
-rw-r--r--src/cmd/doc/doc_test.go3
-rw-r--r--src/cmd/go/internal/generate/generate.go3
-rw-r--r--src/cmd/go/internal/modcmd/verify.go11
-rw-r--r--src/cmd/go/internal/modfetch/cache.go40
-rw-r--r--src/cmd/go/internal/modfetch/fetch.go62
-rw-r--r--src/cmd/go/internal/modload/build.go4
-rw-r--r--src/cmd/go/internal/robustio/robustio_windows.go2
-rw-r--r--src/cmd/go/internal/test/test.go2
-rw-r--r--src/cmd/go/testdata/script/build_trimpath.txt103
-rw-r--r--src/cmd/go/testdata/script/mod_download_partial.txt56
-rw-r--r--src/cmd/go/testdata/script/mod_list_dir.txt1
-rw-r--r--src/cmd/go/testdata/script/version.txt5
-rw-r--r--src/go/build/deps_test.go5
-rw-r--r--src/internal/syscall/execenv/execenv_default.go19
-rw-r--r--src/internal/syscall/execenv/execenv_windows.go (renamed from src/os/env_windows.go)18
-rw-r--r--src/net/http/main_test.go2
-rw-r--r--src/os/env_default.go13
-rw-r--r--src/os/exec/exec.go15
-rw-r--r--src/os/exec_posix.go3
-rw-r--r--src/os/export_test.go1
-rw-r--r--src/os/path.go3
-rw-r--r--src/os/removeall_at.go1
-rw-r--r--src/os/removeall_noat.go1
-rw-r--r--src/os/removeall_test.go50
-rw-r--r--src/runtime/mbitmap.go6
-rw-r--r--src/runtime/os_windows.go23
-rw-r--r--src/runtime/stubs.go7
-rw-r--r--src/runtime/sys_linux_ppc64x.s2
29 files changed, 328 insertions, 135 deletions
diff --git a/src/cmd/compile/internal/syntax/parser_test.go b/src/cmd/compile/internal/syntax/parser_test.go
index 3cf55defc7..673339d667 100644
--- a/src/cmd/compile/internal/syntax/parser_test.go
+++ b/src/cmd/compile/internal/syntax/parser_test.go
@@ -96,7 +96,7 @@ func walkDirs(t *testing.T, dir string, action func(string)) {
}
} else if fi.IsDir() && fi.Name() != "testdata" {
path := filepath.Join(dir, fi.Name())
- if !strings.HasSuffix(path, "/test") {
+ if !strings.HasSuffix(path, string(filepath.Separator)+"test") {
dirs = append(dirs, path)
}
}
diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go
index 11d0bdafd9..9a5c04fe4c 100644
--- a/src/cmd/doc/doc_test.go
+++ b/src/cmd/doc/doc_test.go
@@ -920,6 +920,9 @@ func TestDotSlashLookup(t *testing.T) {
t.Skip("scanning file system takes too long")
}
maybeSkip(t)
+ if runtime.GOOS == "windows" {
+ t.Skip("known Windows test failure on release-branch.go1.13; fix is in CL 204442 but requires non-test code changes unlikely to be appropriate for backporting this late")
+ }
where, err := os.Getwd()
if err != nil {
t.Fatal(err)
diff --git a/src/cmd/go/internal/generate/generate.go b/src/cmd/go/internal/generate/generate.go
index f2ae80e5dc..317d802040 100644
--- a/src/cmd/go/internal/generate/generate.go
+++ b/src/cmd/go/internal/generate/generate.go
@@ -22,6 +22,7 @@ import (
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/modload"
+ "cmd/go/internal/str"
"cmd/go/internal/work"
)
@@ -438,7 +439,7 @@ func (g *Generator) exec(words []string) {
cmd.Stderr = os.Stderr
// Run the command in the package directory.
cmd.Dir = g.dir
- cmd.Env = append(cfg.OrigEnv, g.env...)
+ cmd.Env = str.StringList(cfg.OrigEnv, g.env)
err := cmd.Run()
if err != nil {
g.errorf("running %q: %s", words[0], err)
diff --git a/src/cmd/go/internal/modcmd/verify.go b/src/cmd/go/internal/modcmd/verify.go
index 81fc44dc97..dd1665619b 100644
--- a/src/cmd/go/internal/modcmd/verify.go
+++ b/src/cmd/go/internal/modcmd/verify.go
@@ -7,6 +7,7 @@ package modcmd
import (
"bytes"
"cmd/go/internal/cfg"
+ "errors"
"fmt"
"io/ioutil"
"os"
@@ -61,12 +62,10 @@ func verifyMod(mod module.Version) bool {
_, zipErr = os.Stat(zip)
}
dir, dirErr := modfetch.DownloadDir(mod)
- if dirErr == nil {
- _, dirErr = os.Stat(dir)
- }
data, err := ioutil.ReadFile(zip + "hash")
if err != nil {
- if zipErr != nil && os.IsNotExist(zipErr) && dirErr != nil && os.IsNotExist(dirErr) {
+ if zipErr != nil && errors.Is(zipErr, os.ErrNotExist) &&
+ dirErr != nil && errors.Is(dirErr, os.ErrNotExist) {
// Nothing downloaded yet. Nothing to verify.
return true
}
@@ -75,7 +74,7 @@ func verifyMod(mod module.Version) bool {
}
h := string(bytes.TrimSpace(data))
- if zipErr != nil && os.IsNotExist(zipErr) {
+ if zipErr != nil && errors.Is(zipErr, os.ErrNotExist) {
// ok
} else {
hZ, err := dirhash.HashZip(zip, dirhash.DefaultHash)
@@ -87,7 +86,7 @@ func verifyMod(mod module.Version) bool {
ok = false
}
}
- if dirErr != nil && os.IsNotExist(dirErr) {
+ if dirErr != nil && errors.Is(dirErr, os.ErrNotExist) {
// ok
} else {
hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash)
diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go
index c0062809d1..446c8fec8b 100644
--- a/src/cmd/go/internal/modfetch/cache.go
+++ b/src/cmd/go/internal/modfetch/cache.go
@@ -7,6 +7,7 @@ package modfetch
import (
"bytes"
"encoding/json"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -57,8 +58,11 @@ func CachePath(m module.Version, suffix string) (string, error) {
return filepath.Join(dir, encVer+"."+suffix), nil
}
-// DownloadDir returns the directory to which m should be downloaded.
-// Note that the directory may not yet exist.
+// DownloadDir returns the directory to which m should have been downloaded.
+// An error will be returned if the module path or version cannot be escaped.
+// An error satisfying errors.Is(err, os.ErrNotExist) will be returned
+// along with the directory if the directory does not exist or if the directory
+// is not completely populated.
func DownloadDir(m module.Version) (string, error) {
if PkgMod == "" {
return "", fmt.Errorf("internal error: modfetch.PkgMod not set")
@@ -77,9 +81,39 @@ func DownloadDir(m module.Version) (string, error) {
if err != nil {
return "", err
}
- return filepath.Join(PkgMod, enc+"@"+encVer), nil
+
+ dir := filepath.Join(PkgMod, enc+"@"+encVer)
+ if fi, err := os.Stat(dir); os.IsNotExist(err) {
+ return dir, err
+ } else if err != nil {
+ return dir, &DownloadDirPartialError{dir, err}
+ } else if !fi.IsDir() {
+ return dir, &DownloadDirPartialError{dir, errors.New("not a directory")}
+ }
+ partialPath, err := CachePath(m, "partial")
+ if err != nil {
+ return dir, err
+ }
+ if _, err := os.Stat(partialPath); err == nil {
+ return dir, &DownloadDirPartialError{dir, errors.New("not completely extracted")}
+ } else if !os.IsNotExist(err) {
+ return dir, err
+ }
+ return dir, nil
+}
+
+// DownloadDirPartialError is returned by DownloadDir if a module directory
+// exists but was not completely populated.
+//
+// DownloadDirPartialError is equivalent to os.ErrNotExist.
+type DownloadDirPartialError struct {
+ Dir string
+ Err error
}
+func (e *DownloadDirPartialError) Error() string { return fmt.Sprintf("%s: %v", e.Dir, e.Err) }
+func (e *DownloadDirPartialError) Is(err error) bool { return err == os.ErrNotExist }
+
// lockVersion locks a file within the module cache that guards the downloading
// and extraction of the zipfile for the given module version.
func lockVersion(mod module.Version) (unlock func(), err error) {
diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go
index 51a56028c4..d5516dd8d9 100644
--- a/src/cmd/go/internal/modfetch/fetch.go
+++ b/src/cmd/go/internal/modfetch/fetch.go
@@ -7,6 +7,7 @@ package modfetch
import (
"archive/zip"
"bytes"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -22,6 +23,7 @@ import (
"cmd/go/internal/module"
"cmd/go/internal/par"
"cmd/go/internal/renameio"
+ "cmd/go/internal/robustio"
)
var downloadCache par.Cache
@@ -41,24 +43,27 @@ func Download(mod module.Version) (dir string, err error) {
err error
}
c := downloadCache.Do(mod, func() interface{} {
- dir, err := DownloadDir(mod)
+ dir, err := download(mod)
if err != nil {
return cached{"", err}
}
- if err := download(mod, dir); err != nil {
- return cached{"", err}
- }
checkMod(mod)
return cached{dir, nil}
}).(cached)
return c.dir, c.err
}
-func download(mod module.Version, dir string) (err error) {
- // If the directory exists, the module has already been extracted.
- fi, err := os.Stat(dir)
- if err == nil && fi.IsDir() {
- return nil
+func download(mod module.Version) (dir string, err error) {
+ // If the directory exists, and no .partial file exists,
+ // the module has already been completely extracted.
+ // .partial files may be created when future versions of cmd/go
+ // extract module zip directories in place instead of extracting
+ // to a random temporary directory and renaming.
+ dir, err = DownloadDir(mod)
+ if err == nil {
+ return dir, nil
+ } else if dir == "" || !errors.Is(err, os.ErrNotExist) {
+ return "", err
}
// To avoid cluttering the cache with extraneous files,
@@ -66,7 +71,7 @@ func download(mod module.Version, dir string) (err error) {
// Invoke DownloadZip before locking the file.
zipfile, err := DownloadZip(mod)
if err != nil {
- return err
+ return "", err
}
if cfg.CmdName != "mod download" {
@@ -75,17 +80,19 @@ func download(mod module.Version, dir string) (err error) {
unlock, err := lockVersion(mod)
if err != nil {
- return err
+ return "", err
}
defer unlock()
// Check whether the directory was populated while we were waiting on the lock.
- fi, err = os.Stat(dir)
- if err == nil && fi.IsDir() {
- return nil
+ _, dirErr := DownloadDir(mod)
+ if dirErr == nil {
+ return dir, nil
}
+ _, dirExists := dirErr.(*DownloadDirPartialError)
- // Clean up any remaining temporary directories from previous runs.
+ // Clean up any remaining temporary directories from previous runs, as well
+ // as partially extracted diectories created by future versions of cmd/go.
// This is only safe to do because the lock file ensures that their writers
// are no longer active.
parentDir := filepath.Dir(dir)
@@ -95,6 +102,19 @@ func download(mod module.Version, dir string) (err error) {
RemoveAll(path) // best effort
}
}
+ if dirExists {
+ if err := RemoveAll(dir); err != nil {
+ return "", err
+ }
+ }
+
+ partialPath, err := CachePath(mod, "partial")
+ if err != nil {
+ return "", err
+ }
+ if err := os.Remove(partialPath); err != nil && !os.IsNotExist(err) {
+ return "", err
+ }
// Extract the zip file to a temporary directory, then rename it to the
// final path. That way, we can use the existence of the source directory to
@@ -102,11 +122,11 @@ func download(mod module.Version, dir string) (err error) {
// the entire directory (e.g. as an attempt to prune out file corruption)
// the module cache will still be left in a recoverable state.
if err := os.MkdirAll(parentDir, 0777); err != nil {
- return err
+ return "", err
}
tmpDir, err := ioutil.TempDir(parentDir, tmpPrefix)
if err != nil {
- return err
+ return "", err
}
defer func() {
if err != nil {
@@ -117,17 +137,17 @@ func download(mod module.Version, dir string) (err error) {
modpath := mod.Path + "@" + mod.Version
if err := Unzip(tmpDir, zipfile, modpath, 0); err != nil {
fmt.Fprintf(os.Stderr, "-> %s\n", err)
- return err
+ return "", err
}
- if err := os.Rename(tmpDir, dir); err != nil {
- return err
+ if err := robustio.Rename(tmpDir, dir); err != nil {
+ return "", err
}
// Make dir read-only only *after* renaming it.
// os.Rename was observed to fail for read-only directories on macOS.
makeDirsReadOnly(dir)
- return nil
+ return dir, nil
}
var downloadZipCache par.Cache
diff --git a/src/cmd/go/internal/modload/build.go b/src/cmd/go/internal/modload/build.go
index ff42516c80..a0c6b0bf74 100644
--- a/src/cmd/go/internal/modload/build.go
+++ b/src/cmd/go/internal/modload/build.go
@@ -143,9 +143,7 @@ func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic {
}
dir, err := modfetch.DownloadDir(mod)
if err == nil {
- if info, err := os.Stat(dir); err == nil && info.IsDir() {
- m.Dir = dir
- }
+ m.Dir = dir
}
}
}
diff --git a/src/cmd/go/internal/robustio/robustio_windows.go b/src/cmd/go/internal/robustio/robustio_windows.go
index a3d94e566f..1eb8cfbccf 100644
--- a/src/cmd/go/internal/robustio/robustio_windows.go
+++ b/src/cmd/go/internal/robustio/robustio_windows.go
@@ -14,7 +14,7 @@ import (
"time"
)
-const arbitraryTimeout = 500 * time.Millisecond
+const arbitraryTimeout = 2000 * time.Millisecond
// retry retries ephemeral errors from f up to an arbitrary timeout
// to work around spurious filesystem errors on Windows
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
index 8141e31c99..636d2fef55 100644
--- a/src/cmd/go/internal/test/test.go
+++ b/src/cmd/go/internal/test/test.go
@@ -1142,7 +1142,7 @@ func (c *runCache) builderRunTest(b *work.Builder, a *work.Action) error {
cmd := exec.Command(args[0], args[1:]...)
cmd.Dir = a.Package.Dir
- cmd.Env = base.EnvForDir(cmd.Dir, cfg.OrigEnv)
+ cmd.Env = base.EnvForDir(cmd.Dir, cfg.OrigEnv[:len(cfg.OrigEnv):len(cfg.OrigEnv)])
cmd.Stdout = stdout
cmd.Stderr = stdout
diff --git a/src/cmd/go/testdata/script/build_trimpath.txt b/src/cmd/go/testdata/script/build_trimpath.txt
index 668f75599e..ba414372d3 100644
--- a/src/cmd/go/testdata/script/build_trimpath.txt
+++ b/src/cmd/go/testdata/script/build_trimpath.txt
@@ -1,44 +1,93 @@
[short] skip
-
-env -r GOROOT_REGEXP=$GOROOT
-env -r WORK_REGEXP='$WORK' # don't expand $WORK; grep replaces $WORK in text before matching.
-env GOROOT GOROOT_REGEXP WORK WORK_REGEXP
+env GO111MODULE=on
# A binary built without -trimpath should contain the current workspace
# and GOROOT for debugging and stack traces.
cd a
-go build -o hello.exe hello.go
-grep -q $WORK_REGEXP hello.exe
-grep -q $GOROOT_REGEXP hello.exe
+go build -o $WORK/paths-a.exe paths.go
+exec $WORK/paths-a.exe $WORK/paths-a.exe
+stdout 'binary contains GOPATH: true'
+stdout 'binary contains GOROOT: true'
# A binary built with -trimpath should not contain the current workspace
# or GOROOT.
-go build -trimpath -o hello.exe hello.go
-! grep -q $GOROOT_REGEXP hello.exe
-! grep -q $WORK_REGEXP hello.exe
-cd ..
+go build -trimpath -o $WORK/paths-a.exe paths.go
+exec $WORK/paths-a.exe $WORK/paths-a.exe
+stdout 'binary contains GOPATH: false'
+stdout 'binary contains GOROOT: false'
# A binary from an external module built with -trimpath should not contain
# the current workspace or GOROOT.
-env GO111MODULE=on
-go build -trimpath -o fortune.exe rsc.io/fortune
-! grep -q $GOROOT_REGEXP fortune.exe
-! grep -q $WORK_REGEXP fortune.exe
+cd $WORK
+go get -trimpath rsc.io/fortune
+exec $WORK/paths-a.exe $GOPATH/bin/fortune$GOEXE
+stdout 'binary contains GOPATH: false'
+stdout 'binary contains GOROOT: false'
# Two binaries built from identical packages in different directories
# should be identical.
-mkdir b
-cp a/go.mod a/hello.go b
-cd a
-go build -trimpath -o ../a.exe .
-cd ../b
-go build -trimpath -o ../b.exe .
-cd ..
-cmp -q a.exe b.exe
+# TODO(golang.org/issue/35435): at the moment, they are not.
+#mkdir $GOPATH/src/b
+#cp $GOPATH/src/a/go.mod $GOPATH/src/b/go.mod
+#cp $GOPATH/src/a/paths.go $GOPATH/src/b/paths.go
+#cd $GOPATH/src/b
+#go build -trimpath -o $WORK/paths-b.exe .
+#cmp -q $WORK/paths-a.exe $WORK/paths-b.exe
+
+[!exec:gccgo] stop
+
+# A binary built with gccgo without -trimpath should contain the current
+# GOPATH and GOROOT.
+env GO111MODULE=off # The current released gccgo does not support builds in module mode.
+cd $GOPATH/src/a
+go build -compiler=gccgo -o $WORK/gccgo-paths-a.exe .
+exec $WORK/gccgo-paths-a.exe $WORK/gccgo-paths-b.exe
+stdout 'binary contains GOPATH: true'
+stdout 'binary contains GOROOT: true'
+
+# A binary built with gccgo with -trimpath should not contain GOPATH or GOROOT.
+go build -compiler=gccgo -trimpath -o $WORK/gccgo-paths-a.exe .
+exec $WORK/gccgo-paths-a.exe $WORK/gccgo-paths-b.exe
+stdout 'binary contains GOPATH: false'
+stdout 'binary contains GOROOT: false'
--- a/hello.go --
+# Two binaries built from identical packages in different directories
+# should be identical.
+# TODO(golang.org/issue/35435): at the moment, they are not.
+#cd ../b
+#go build -compiler=gccgo -trimpath -o $WORK/gccgo-paths-b.exe .
+#cmp -q $WORK/gccgo-paths-a.exe $WORK/gccgo-paths-b.exe
+
+-- $GOPATH/src/a/paths.go --
package main
-func main() { println("hello") }
--- a/go.mod --
-module m
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+)
+
+func main() {
+ exe := os.Args[1]
+ data, err := ioutil.ReadFile(exe)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ gopath := []byte(filepath.ToSlash(os.Getenv("GOPATH")))
+ if len(gopath) == 0 {
+ log.Fatal("GOPATH not set")
+ }
+ fmt.Printf("binary contains GOPATH: %v\n", bytes.Contains(data, gopath))
+
+ goroot := []byte(filepath.ToSlash(os.Getenv("GOROOT")))
+ if len(goroot) == 0 {
+ log.Fatal("GOROOT not set")
+ }
+ fmt.Printf("binary contains GOROOT: %v\n", bytes.Contains(data, goroot))
+}
+-- $GOPATH/src/a/go.mod --
+module example.com/a
diff --git a/src/cmd/go/testdata/script/mod_download_partial.txt b/src/cmd/go/testdata/script/mod_download_partial.txt
new file mode 100644
index 0000000000..cda358b99f
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_download_partial.txt
@@ -0,0 +1,56 @@
+# Download a module
+go mod download rsc.io/quote
+exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod
+
+# 'go mod verify' should fail if we delete a file.
+go mod verify
+chmod 0755 $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
+rm $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod
+! go mod verify
+
+# Create a .partial file to simulate an failure extracting the zip file.
+cp empty $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.partial
+
+# 'go mod verify' should not fail, since the module hasn't been completely
+# ingested into the cache.
+go mod verify
+
+# 'go list' should not load packages from the directory.
+# NOTE: the message "directory $dir outside available modules" is reported
+# for directories not in the main module, active modules in the module cache,
+# or local replacements. In this case, the directory is in the right place,
+# but it's incomplete, so 'go list' acts as if it's not an active module.
+! go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
+stderr 'outside available modules'
+
+# 'go list -m' should not print the directory.
+go list -m -f '{{.Dir}}' rsc.io/quote
+! stdout .
+
+# 'go mod download' should re-extract the module and remove the .partial file.
+go mod download rsc.io/quote
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.partial
+exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod
+
+# 'go list' should succeed.
+go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
+stdout '^rsc.io/quote$'
+
+# 'go list -m' should print the directory.
+go list -m -f '{{.Dir}}' rsc.io/quote
+stdout 'pkg[/\\]mod[/\\]rsc.io[/\\]quote@v1.5.2'
+
+# go mod verify should fail if we delete a file.
+go mod verify
+chmod 0755 $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
+rm $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod
+! go mod verify
+
+-- go.mod --
+module m
+
+go 1.14
+
+require rsc.io/quote v1.5.2
+
+-- empty --
diff --git a/src/cmd/go/testdata/script/mod_list_dir.txt b/src/cmd/go/testdata/script/mod_list_dir.txt
index a8023cce9c..39834f2249 100644
--- a/src/cmd/go/testdata/script/mod_list_dir.txt
+++ b/src/cmd/go/testdata/script/mod_list_dir.txt
@@ -1,4 +1,5 @@
[short] skip
+[windows] skip # known Windows test failure on release-branch.go1.13; fix is in CL 206144 but requires non-test code changes unlikely to be appropriate for backporting this late
# go list with path to directory should work
diff --git a/src/cmd/go/testdata/script/version.txt b/src/cmd/go/testdata/script/version.txt
index 9086f047e4..42526247f1 100644
--- a/src/cmd/go/testdata/script/version.txt
+++ b/src/cmd/go/testdata/script/version.txt
@@ -1,6 +1,7 @@
env GO111MODULE=on
[short] skip
+# Check that 'go version' and 'go version -m' work on a binary built in module mode.
go build -o fortune.exe rsc.io/fortune
go version fortune.exe
stdout '^fortune.exe: .+'
@@ -8,6 +9,10 @@ go version -m fortune.exe
stdout '^\tpath\trsc.io/fortune'
stdout '^\tmod\trsc.io/fortune\tv1.0.0'
+# Repeat the test with -buildmode=pie.
+# TODO(golang.org/issue/27144): don't skip after -buildmode=pie is implemented
+# on Windows.
+[windows] skip # -buildmode=pie not supported
go build -buildmode=pie -o external.exe rsc.io/fortune
go version external.exe
stdout '^external.exe: .+'
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index b8696ec6f9..55a77c6390 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -159,6 +159,7 @@ var pkgDeps = map[string][]string{
"internal/syscall/unix": {"L0", "syscall"},
"internal/syscall/windows": {"L0", "syscall", "internal/syscall/windows/sysdll"},
"internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"},
+ "internal/syscall/execenv": {"L0", "syscall", "internal/syscall/windows", "unicode/utf16"},
"time": {
// "L0" without the "io" package:
"errors",
@@ -176,10 +177,10 @@ var pkgDeps = map[string][]string{
"internal/cfg": {"L0"},
"internal/poll": {"L0", "internal/oserror", "internal/race", "syscall", "time", "unicode/utf16", "unicode/utf8", "internal/syscall/windows"},
"internal/testlog": {"L0"},
- "os": {"L1", "os", "syscall", "time", "internal/oserror", "internal/poll", "internal/syscall/windows", "internal/syscall/unix", "internal/testlog"},
+ "os": {"L1", "os", "syscall", "time", "internal/oserror", "internal/poll", "internal/syscall/windows", "internal/syscall/unix", "internal/syscall/execenv", "internal/testlog"},
"path/filepath": {"L2", "os", "syscall", "internal/syscall/windows"},
"io/ioutil": {"L2", "os", "path/filepath", "time"},
- "os/exec": {"L2", "os", "context", "path/filepath", "syscall"},
+ "os/exec": {"L2", "os", "context", "path/filepath", "syscall", "internal/syscall/execenv"},
"os/signal": {"L2", "os", "syscall"},
// OS enables basic operating system functionality,
diff --git a/src/internal/syscall/execenv/execenv_default.go b/src/internal/syscall/execenv/execenv_default.go
new file mode 100644
index 0000000000..4bdbb55edb
--- /dev/null
+++ b/src/internal/syscall/execenv/execenv_default.go
@@ -0,0 +1,19 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+package execenv
+
+import "syscall"
+
+// Default will return the default environment
+// variables based on the process attributes
+// provided.
+//
+// Defaults to syscall.Environ() on all platforms
+// other than Windows.
+func Default(sys *syscall.SysProcAttr) ([]string, error) {
+ return syscall.Environ(), nil
+}
diff --git a/src/os/env_windows.go b/src/internal/syscall/execenv/execenv_windows.go
index e8f647e7ac..3a41a7a3fd 100644
--- a/src/os/env_windows.go
+++ b/src/internal/syscall/execenv/execenv_windows.go
@@ -1,8 +1,10 @@
-// Copyright 2019 The Go Authors. All rights reserved.
+// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package os
+// +build windows
+
+package execenv
import (
"internal/syscall/windows"
@@ -11,9 +13,17 @@ import (
"unsafe"
)
-func environForSysProcAttr(sys *syscall.SysProcAttr) (env []string, err error) {
+// Default will return the default environment
+// variables based on the process attributes
+// provided.
+//
+// If the process attributes contain a token, then
+// the environment variables will be sourced from
+// the defaults for that user token, otherwise they
+// will be sourced from syscall.Environ().
+func Default(sys *syscall.SysProcAttr) (env []string, err error) {
if sys == nil || sys.Token == 0 {
- return Environ(), nil
+ return syscall.Environ(), nil
}
var block *uint16
err = windows.CreateEnvironmentBlock(&block, sys.Token, false)
diff --git a/src/net/http/main_test.go b/src/net/http/main_test.go
index 7936fb3044..85aa9096c3 100644
--- a/src/net/http/main_test.go
+++ b/src/net/http/main_test.go
@@ -122,7 +122,7 @@ func afterTest(t testing.TB) {
").noteClientGone(": "a closenotifier sender",
}
var stacks string
- for i := 0; i < 4; i++ {
+ for i := 0; i < 10; i++ {
bad = ""
stacks = strings.Join(interestingGoroutines(), "\n\n")
for substr, what := range badSubstring {
diff --git a/src/os/env_default.go b/src/os/env_default.go
deleted file mode 100644
index c11ccce7e3..0000000000
--- a/src/os/env_default.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !windows
-
-package os
-
-import "syscall"
-
-func environForSysProcAttr(sys *syscall.SysProcAttr) ([]string, error) {
- return Environ(), nil
-}
diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go
index 17ef003eca..5552fd858f 100644
--- a/src/os/exec/exec.go
+++ b/src/os/exec/exec.go
@@ -24,6 +24,7 @@ import (
"bytes"
"context"
"errors"
+ "internal/syscall/execenv"
"io"
"os"
"path/filepath"
@@ -222,11 +223,11 @@ func interfaceEqual(a, b interface{}) bool {
return a == b
}
-func (c *Cmd) envv() []string {
+func (c *Cmd) envv() ([]string, error) {
if c.Env != nil {
- return c.Env
+ return c.Env, nil
}
- return os.Environ()
+ return execenv.Default(c.SysProcAttr)
}
func (c *Cmd) argv() []string {
@@ -412,11 +413,15 @@ func (c *Cmd) Start() error {
}
c.childFiles = append(c.childFiles, c.ExtraFiles...)
- var err error
+ envv, err := c.envv()
+ if err != nil {
+ return err
+ }
+
c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
Dir: c.Dir,
Files: c.childFiles,
- Env: addCriticalEnv(dedupEnv(c.envv())),
+ Env: addCriticalEnv(dedupEnv(envv)),
Sys: c.SysProcAttr,
})
if err != nil {
diff --git a/src/os/exec_posix.go b/src/os/exec_posix.go
index 505931b488..83fdae8514 100644
--- a/src/os/exec_posix.go
+++ b/src/os/exec_posix.go
@@ -7,6 +7,7 @@
package os
import (
+ "internal/syscall/execenv"
"syscall"
)
@@ -38,7 +39,7 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e
Sys: attr.Sys,
}
if sysattr.Env == nil {
- sysattr.Env, err = environForSysProcAttr(sysattr.Sys)
+ sysattr.Env, err = execenv.Default(sysattr.Sys)
if err != nil {
return nil, err
}
diff --git a/src/os/export_test.go b/src/os/export_test.go
index d17d5e6230..812432cee4 100644
--- a/src/os/export_test.go
+++ b/src/os/export_test.go
@@ -9,4 +9,3 @@ package os
var Atime = atime
var LstatP = &lstat
var ErrWriteAtInAppendMode = errWriteAtInAppendMode
-var RemoveAllTestHook = &removeAllTestHook
diff --git a/src/os/path.go b/src/os/path.go
index 9d7ecad792..ba43ea3525 100644
--- a/src/os/path.go
+++ b/src/os/path.go
@@ -58,9 +58,6 @@ func MkdirAll(path string, perm FileMode) error {
return nil
}
-// removeAllTestHook is a hook for testing.
-var removeAllTestHook = func(err error) error { return err }
-
// RemoveAll removes path and any children it contains.
// It removes everything it can but returns the first error
// it encounters. If the path does not exist, RemoveAll
diff --git a/src/os/removeall_at.go b/src/os/removeall_at.go
index bc632f5a75..e619851f9c 100644
--- a/src/os/removeall_at.go
+++ b/src/os/removeall_at.go
@@ -153,7 +153,6 @@ func removeAllFrom(parent *File, base string) error {
// Remove the directory itself.
unlinkError := unix.Unlinkat(parentFd, base, unix.AT_REMOVEDIR)
- unlinkError = removeAllTestHook(unlinkError)
if unlinkError == nil || IsNotExist(unlinkError) {
return nil
}
diff --git a/src/os/removeall_noat.go b/src/os/removeall_noat.go
index a0694fa4ce..32673c0ab0 100644
--- a/src/os/removeall_noat.go
+++ b/src/os/removeall_noat.go
@@ -124,7 +124,6 @@ func removeAll(path string) error {
// Remove directory.
err1 := Remove(path)
- err1 = removeAllTestHook(err1)
if err1 == nil || IsNotExist(err1) {
return nil
}
diff --git a/src/os/removeall_test.go b/src/os/removeall_test.go
index 4d556f977e..050635f533 100644
--- a/src/os/removeall_test.go
+++ b/src/os/removeall_test.go
@@ -5,7 +5,6 @@
package os_test
import (
- "errors"
"fmt"
"io/ioutil"
. "os"
@@ -413,14 +412,6 @@ func TestRemoveAllWithMoreErrorThanReqSize(t *testing.T) {
t.Skip("skipping in short mode")
}
- defer func(oldHook func(error) error) {
- *RemoveAllTestHook = oldHook
- }(*RemoveAllTestHook)
-
- *RemoveAllTestHook = func(err error) error {
- return errors.New("error from RemoveAllTestHook")
- }
-
tmpDir, err := ioutil.TempDir("", "TestRemoveAll-")
if err != nil {
t.Fatal(err)
@@ -429,7 +420,7 @@ func TestRemoveAllWithMoreErrorThanReqSize(t *testing.T) {
path := filepath.Join(tmpDir, "_TestRemoveAllWithMoreErrorThanReqSize_")
- // Make directory with 1025 files and remove.
+ // Make directory with 1025 read-only files.
if err := MkdirAll(path, 0777); err != nil {
t.Fatalf("MkdirAll %q: %s", path, err)
}
@@ -442,13 +433,40 @@ func TestRemoveAllWithMoreErrorThanReqSize(t *testing.T) {
fd.Close()
}
- // This call should not hang
- if err := RemoveAll(path); err == nil {
- t.Fatal("Want error from RemoveAllTestHook, got nil")
+ // Make the parent directory read-only. On some platforms, this is what
+ // prevents os.Remove from removing the files within that directory.
+ if err := Chmod(path, 0555); err != nil {
+ t.Fatal(err)
}
+ defer Chmod(path, 0755)
- // We hook to inject error, but the actual files must be deleted
- if _, err := Lstat(path); err == nil {
- t.Fatal("directory must be deleted even with removeAllTetHook run")
+ // This call should not hang, even on a platform that disallows file deletion
+ // from read-only directories.
+ err = RemoveAll(path)
+
+ if Getuid() == 0 {
+ // On many platforms, root can remove files from read-only directories.
+ return
+ }
+ if err == nil {
+ t.Fatal("RemoveAll(<read-only directory>) = nil; want error")
+ }
+
+ dir, err := Open(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer dir.Close()
+
+ if runtime.GOOS == "windows" {
+ // Marking a directory in Windows does not prevent the os package from
+ // creating or removing files within it.
+ // (See https://golang.org/issue/35042.)
+ return
+ }
+
+ names, _ := dir.Readdirnames(1025)
+ if len(names) < 1025 {
+ t.Fatalf("RemoveAll(<read-only directory>) unexpectedly removed %d read-only files from that directory", 1025-len(names))
}
}
diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go
index 30ec5f1cc9..71efe33741 100644
--- a/src/runtime/mbitmap.go
+++ b/src/runtime/mbitmap.go
@@ -1912,7 +1912,11 @@ Run:
// The bitmask starts at s.startAddr.
// The result must be deallocated with dematerializeGCProg.
func materializeGCProg(ptrdata uintptr, prog *byte) *mspan {
- s := mheap_.allocManual((ptrdata/(8*sys.PtrSize)+pageSize-1)/pageSize, &memstats.gc_sys)
+ // Each word of ptrdata needs one bit in the bitmap.
+ bitmapBytes := divRoundUp(ptrdata, 8*sys.PtrSize)
+ // Compute the number of pages needed for bitmapBytes.
+ pages := divRoundUp(bitmapBytes, pageSize)
+ s := mheap_.allocManual(pages, &memstats.gc_sys)
runGCProg(addb(prog, 4), nil, (*byte)(unsafe.Pointer(s.startAddr)), 1)
return s
}
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 2cf81f61a9..bb631b66a9 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -263,9 +263,7 @@ func loadOptionalSyscalls() {
func monitorSuspendResume() {
const (
- _DEVICE_NOTIFY_CALLBACK = 2
- _ERROR_FILE_NOT_FOUND = 2
- _ERROR_INVALID_PARAMETERS = 87
+ _DEVICE_NOTIFY_CALLBACK = 2
)
type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
callback uintptr
@@ -292,25 +290,8 @@ func monitorSuspendResume() {
callback: compileCallback(*efaceOf(&fn), true),
}
handle := uintptr(0)
- ret := stdcall3(powerRegisterSuspendResumeNotification, _DEVICE_NOTIFY_CALLBACK,
+ stdcall3(powerRegisterSuspendResumeNotification, _DEVICE_NOTIFY_CALLBACK,
uintptr(unsafe.Pointer(&params)), uintptr(unsafe.Pointer(&handle)))
- // This function doesn't use GetLastError(), so we use the return value directly.
- switch ret {
- case 0:
- return // Successful, nothing more to do.
- case _ERROR_FILE_NOT_FOUND:
- // Systems without access to the suspend/resume notifier
- // also have their clock on "program time", and therefore
- // don't want or need this anyway.
- return
- case _ERROR_INVALID_PARAMETERS:
- // This is seen when running in Windows Docker.
- // See issue 36557.
- return
- default:
- println("runtime: PowerRegisterSuspendResumeNotification failed with errno=", ret)
- throw("runtime: PowerRegisterSuspendResumeNotification failure")
- }
}
//go:nosplit
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index 26aaf2224d..8d1c698400 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -295,6 +295,13 @@ func round(n, a uintptr) uintptr {
return (n + a - 1) &^ (a - 1)
}
+// divRoundUp returns ceil(n / a).
+func divRoundUp(n, a uintptr) uintptr {
+ // a is generally a power of two. This will get inlined and
+ // the compiler will optimize the division.
+ return (n + a - 1) / a
+}
+
// checkASM reports whether assembly runtime checks have passed.
func checkASM() bool
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index 13d23156bd..435cc2809a 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -251,7 +251,7 @@ fallback:
ADD $32, R1, R4
SYSCALL $SYS_clock_gettime
MOVD 32(R1), R3
- MOVD 48(R1), R5
+ MOVD 40(R1), R5
JMP finish
TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28