diff options
author | Filippo Valsorda <filippo@golang.org> | 2020-04-13 19:39:17 -0400 |
---|---|---|
committer | Filippo Valsorda <filippo@golang.org> | 2020-04-13 19:39:17 -0400 |
commit | b129f40bb33f0061f2820553a6d168a9ef1d2405 (patch) | |
tree | 3dcf20d733182fbc7534c5e69291f4a90e67d2ad | |
parent | bb8a1014a32c6f6741ca411fae78392edb83b75b (diff) | |
parent | a57f07aac237d366630e85d080ef1ce0c34f0d09 (diff) | |
download | go-b129f40bb33f0061f2820553a6d168a9ef1d2405.tar.gz go-b129f40bb33f0061f2820553a6d168a9ef1d2405.zip |
[dev.boringcrypto.go1.13] all: merge go1.13.10 into dev.boringcrypto.go1.13
Change-Id: I70aa2adce503fb9119e947b5868a0aa5427b808b
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(¶ms)), 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 |