diff options
author | Ian Lance Taylor <iant@golang.org> | 2021-07-30 14:28:58 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-08-12 20:23:07 -0700 |
commit | c5b21c3f4c17b0649155035d2f9aa97b2da8a813 (patch) | |
tree | c6d3a68b503ba5b16182acbb958e3e5dbc95a43b /libgo/go/os | |
parent | 72be20e20299ec57b4bc9ba03d5b7d6bf10e97cc (diff) | |
download | gcc-c5b21c3f4c17b0649155035d2f9aa97b2da8a813.zip gcc-c5b21c3f4c17b0649155035d2f9aa97b2da8a813.tar.gz gcc-c5b21c3f4c17b0649155035d2f9aa97b2da8a813.tar.bz2 |
libgo: update to Go1.17rc2
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/341629
Diffstat (limited to 'libgo/go/os')
86 files changed, 533 insertions, 378 deletions
diff --git a/libgo/go/os/env_unix_test.go b/libgo/go/os/env_unix_test.go index fd21ddd..0336323 100644 --- a/libgo/go/os/env_unix_test.go +++ b/libgo/go/os/env_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris package os_test diff --git a/libgo/go/os/error.go b/libgo/go/os/error.go index 704a6fb..fe8f2a8 100644 --- a/libgo/go/os/error.go +++ b/libgo/go/os/error.go @@ -78,7 +78,7 @@ func NewSyscallError(syscall string, err error) error { // well as some syscall errors. // // This function predates errors.Is. It only supports errors returned by -// the os package. New code should use errors.Is(err, os.ErrExist). +// the os package. New code should use errors.Is(err, fs.ErrExist). func IsExist(err error) bool { return underlyingErrorIs(err, ErrExist) } @@ -88,7 +88,7 @@ func IsExist(err error) bool { // ErrNotExist as well as some syscall errors. // // This function predates errors.Is. It only supports errors returned by -// the os package. New code should use errors.Is(err, os.ErrNotExist). +// the os package. New code should use errors.Is(err, fs.ErrNotExist). func IsNotExist(err error) bool { return underlyingErrorIs(err, ErrNotExist) } @@ -98,7 +98,7 @@ func IsNotExist(err error) bool { // as some syscall errors. // // This function predates errors.Is. It only supports errors returned by -// the os package. New code should use errors.Is(err, os.ErrPermission). +// the os package. New code should use errors.Is(err, fs.ErrPermission). func IsPermission(err error) bool { return underlyingErrorIs(err, ErrPermission) } diff --git a/libgo/go/os/error_errno.go b/libgo/go/os/error_errno.go index 31ae05a..580e915 100644 --- a/libgo/go/os/error_errno.go +++ b/libgo/go/os/error_errno.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 // +build !plan9 package os diff --git a/libgo/go/os/error_posix.go b/libgo/go/os/error_posix.go index 7d5a19c..7a7c860 100644 --- a/libgo/go/os/error_posix.go +++ b/libgo/go/os/error_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows package os diff --git a/libgo/go/os/error_test.go b/libgo/go/os/error_test.go index 6264ccc..4ab6246 100644 --- a/libgo/go/os/error_test.go +++ b/libgo/go/os/error_test.go @@ -33,7 +33,12 @@ func TestErrIsExist(t *testing.T) { } } -func testErrNotExist(name string) string { +func testErrNotExist(t *testing.T, name string) string { + originalWD, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + f, err := os.Open(name) if err == nil { f.Close() @@ -45,7 +50,10 @@ func testErrNotExist(name string) string { err = os.Chdir(name) if err == nil { - return "Chdir should have failed" + if err := os.Chdir(originalWD); err != nil { + t.Fatalf("Chdir should have failed, failed to restore original working directory: %v", err) + } + return "Chdir should have failed, restored original working directory" } if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err, fs.ErrNotExist); s != "" { return s @@ -54,21 +62,15 @@ func testErrNotExist(name string) string { } func TestErrIsNotExist(t *testing.T) { - tmpDir, err := os.MkdirTemp("", "_Go_ErrIsNotExist") - if err != nil { - t.Fatalf("create ErrIsNotExist tempdir: %s", err) - return - } - defer os.RemoveAll(tmpDir) - + tmpDir := t.TempDir() name := filepath.Join(tmpDir, "NotExists") - if s := testErrNotExist(name); s != "" { + if s := testErrNotExist(t, name); s != "" { t.Fatal(s) return } name = filepath.Join(name, "NotExists2") - if s := testErrNotExist(name); s != "" { + if s := testErrNotExist(t, name); s != "" { t.Fatal(s) return } diff --git a/libgo/go/os/error_unix_test.go b/libgo/go/os/error_unix_test.go index dd9f317..3f419d5 100644 --- a/libgo/go/os/error_unix_test.go +++ b/libgo/go/os/error_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris package os_test diff --git a/libgo/go/os/error_windows_test.go b/libgo/go/os/error_windows_test.go index b8191c5..aa0c14b 100644 --- a/libgo/go/os/error_windows_test.go +++ b/libgo/go/os/error_windows_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package os_test diff --git a/libgo/go/os/example_test.go b/libgo/go/os/example_test.go index 3adce51..e8554b0 100644 --- a/libgo/go/os/example_test.go +++ b/libgo/go/os/example_test.go @@ -5,6 +5,7 @@ package os_test import ( + "errors" "fmt" "io/fs" "log" @@ -71,9 +72,9 @@ func ExampleFileMode() { } } -func ExampleIsNotExist() { +func ExampleErrNotExist() { filename := "a-nonexistent-file" - if _, err := os.Stat(filename); os.IsNotExist(err) { + if _, err := os.Stat(filename); errors.Is(err, fs.ErrNotExist) { fmt.Println("file does not exist") } // Output: diff --git a/libgo/go/os/exec.go b/libgo/go/os/exec.go index edb773a..bc75d4d 100644 --- a/libgo/go/os/exec.go +++ b/libgo/go/os/exec.go @@ -54,6 +54,9 @@ type ProcAttr struct { // standard error. An implementation may support additional entries, // depending on the underlying operating system. A nil entry corresponds // to that file being closed when the process starts. + // On Unix systems, StartProcess will change these File values + // to blocking mode, which means that SetDeadline will stop working + // and calling Close will not interrupt a Read or Write. Files []*File // Operating system-specific process creation attributes. diff --git a/libgo/go/os/exec/exec_linux_test.go b/libgo/go/os/exec/exec_linux_test.go index 6f85020..3cfa30e 100644 --- a/libgo/go/os/exec/exec_linux_test.go +++ b/libgo/go/os/exec/exec_linux_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && cgo // +build linux,cgo // On systems that use glibc, calling malloc can create a new arena, diff --git a/libgo/go/os/exec/exec_posix_test.go b/libgo/go/os/exec/exec_posix_test.go index d4d67ac..7b2c0c0 100644 --- a/libgo/go/os/exec/exec_posix_test.go +++ b/libgo/go/os/exec/exec_posix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package exec_test diff --git a/libgo/go/os/exec/exec_test.go b/libgo/go/os/exec/exec_test.go index 8b0c93f..d854e0d 100644 --- a/libgo/go/os/exec/exec_test.go +++ b/libgo/go/os/exec/exec_test.go @@ -488,7 +488,7 @@ func numOpenFDsAndroid(t *testing.T) (n int, lsof []byte) { } func TestExtraFilesFDShuffle(t *testing.T) { - t.Skip("flaky test; see https://golang.org/issue/5780") + testenv.SkipFlaky(t, 5780) switch runtime.GOOS { case "windows": t.Skip("no operating system support; skipping") @@ -915,6 +915,16 @@ func TestHelperProcess(*testing.T) { case "sleep": time.Sleep(3 * time.Second) os.Exit(0) + case "pipehandle": + handle, _ := strconv.ParseUint(args[0], 16, 64) + pipe := os.NewFile(uintptr(handle), "") + _, err := fmt.Fprint(pipe, args[1]) + if err != nil { + fmt.Fprintf(os.Stderr, "writing to pipe failed: %v\n", err) + os.Exit(1) + } + pipe.Close() + os.Exit(0) default: fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd) os.Exit(2) @@ -1042,41 +1052,18 @@ func TestContextCancel(t *testing.T) { defer cancel() c := helperCommandContext(t, ctx, "cat") - r, w, err := os.Pipe() - if err != nil { - t.Fatal(err) - } - c.Stdin = r - - stdout, err := c.StdoutPipe() + stdin, err := c.StdinPipe() if err != nil { t.Fatal(err) } - readDone := make(chan struct{}) - go func() { - defer close(readDone) - var a [1024]byte - for { - n, err := stdout.Read(a[:]) - if err != nil { - if err != io.EOF { - t.Errorf("unexpected read error: %v", err) - } - return - } - t.Logf("%s", a[:n]) - } - }() + defer stdin.Close() if err := c.Start(); err != nil { t.Fatal(err) } - if err := r.Close(); err != nil { - t.Fatal(err) - } - - if _, err := io.WriteString(w, "echo"); err != nil { + // At this point the process is alive. Ensure it by sending data to stdin. + if _, err := io.WriteString(stdin, "echo"); err != nil { t.Fatal(err) } @@ -1086,20 +1073,15 @@ func TestContextCancel(t *testing.T) { // should now fail. Give the process a little while to die. start := time.Now() for { - if _, err := io.WriteString(w, "echo"); err != nil { + if _, err := io.WriteString(stdin, "echo"); err != nil { break } - if time.Since(start) > time.Second { + if time.Since(start) > time.Minute { t.Fatal("canceling context did not stop program") } time.Sleep(time.Millisecond) } - if err := w.Close(); err != nil { - t.Errorf("error closing write end of pipe: %v", err) - } - <-readDone - if err := c.Wait(); err == nil { t.Error("program unexpectedly exited successfully") } else { diff --git a/libgo/go/os/exec/exec_unix.go b/libgo/go/os/exec/exec_unix.go index 51c5242..467c069 100644 --- a/libgo/go/os/exec/exec_unix.go +++ b/libgo/go/os/exec/exec_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 && !windows // +build !plan9,!windows package exec diff --git a/libgo/go/os/exec/exec_windows_test.go b/libgo/go/os/exec/exec_windows_test.go new file mode 100644 index 0000000..fbccffe --- /dev/null +++ b/libgo/go/os/exec/exec_windows_test.go @@ -0,0 +1,43 @@ +// Copyright 2021 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. + +//go:build windows +// +build windows + +package exec_test + +import ( + "io" + "os" + "strconv" + "syscall" + "testing" +) + +func TestPipePassing(t *testing.T) { + r, w, err := os.Pipe() + if err != nil { + t.Error(err) + } + const marker = "arrakis, dune, desert planet" + childProc := helperCommand(t, "pipehandle", strconv.FormatUint(uint64(w.Fd()), 16), marker) + childProc.SysProcAttr = &syscall.SysProcAttr{AdditionalInheritedHandles: []syscall.Handle{syscall.Handle(w.Fd())}} + err = childProc.Start() + if err != nil { + t.Error(err) + } + w.Close() + response, err := io.ReadAll(r) + if err != nil { + t.Error(err) + } + r.Close() + if string(response) != marker { + t.Errorf("got %q; want %q", string(response), marker) + } + err = childProc.Wait() + if err != nil { + t.Error(err) + } +} diff --git a/libgo/go/os/exec/lp_js.go b/libgo/go/os/exec/lp_js.go index 6750fb9..4eac25f 100644 --- a/libgo/go/os/exec/lp_js.go +++ b/libgo/go/os/exec/lp_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package exec diff --git a/libgo/go/os/exec/lp_unix.go b/libgo/go/os/exec/lp_unix.go index bb5a3ec..ebecc74 100644 --- a/libgo/go/os/exec/lp_unix.go +++ b/libgo/go/os/exec/lp_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris package exec diff --git a/libgo/go/os/exec/lp_unix_test.go b/libgo/go/os/exec/lp_unix_test.go index 23d1506..fe4df1a 100644 --- a/libgo/go/os/exec/lp_unix_test.go +++ b/libgo/go/os/exec/lp_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris package exec @@ -36,13 +37,7 @@ func TestLookPathUnixEmptyPath(t *testing.T) { t.Fatal("Close failed: ", err) } - pathenv := os.Getenv("PATH") - defer os.Setenv("PATH", pathenv) - - err = os.Setenv("PATH", "") - if err != nil { - t.Fatal("Setenv failed: ", err) - } + t.Setenv("PATH", "") path, err := LookPath("exec_me") if err == nil { diff --git a/libgo/go/os/exec/read3.go b/libgo/go/os/exec/read3.go index 8cc24da..a8c7183 100644 --- a/libgo/go/os/exec/read3.go +++ b/libgo/go/os/exec/read3.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // This is a test program that verifies that it can read from diff --git a/libgo/go/os/exec_plan9.go b/libgo/go/os/exec_plan9.go index 8580153..cc84f97 100644 --- a/libgo/go/os/exec_plan9.go +++ b/libgo/go/os/exec_plan9.go @@ -5,6 +5,7 @@ package os import ( + "internal/itoa" "runtime" "syscall" "time" @@ -40,7 +41,7 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e } func (p *Process) writeProcFile(file string, data string) error { - f, e := OpenFile("/proc/"+itoa(p.Pid)+"/"+file, O_WRONLY, 0) + f, e := OpenFile("/proc/"+itoa.Itoa(p.Pid)+"/"+file, O_WRONLY, 0) if e != nil { return e } diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go index aa8dfe0..eb5cbc8 100644 --- a/libgo/go/os/exec_posix.go +++ b/libgo/go/os/exec_posix.go @@ -2,11 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows package os import ( + "internal/itoa" "internal/syscall/execenv" "runtime" "syscall" @@ -102,13 +104,18 @@ func (p *ProcessState) String() string { res := "" switch { case status.Exited(): - res = "exit status " + itoa(status.ExitStatus()) + code := status.ExitStatus() + if runtime.GOOS == "windows" && uint(code) >= 1<<16 { // windows uses large hex numbers + res = "exit status " + uitox(uint(code)) + } else { // unix systems use small decimal integers + res = "exit status " + itoa.Itoa(code) // unix + } case status.Signaled(): res = "signal: " + status.Signal().String() case status.Stopped(): res = "stop signal: " + status.StopSignal().String() if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 { - res += " (trap " + itoa(status.TrapCause()) + ")" + res += " (trap " + itoa.Itoa(status.TrapCause()) + ")" } case status.Continued(): res = "continued" diff --git a/libgo/go/os/exec_unix.go b/libgo/go/os/exec_unix.go index 69eb615..4ada050 100644 --- a/libgo/go/os/exec_unix.go +++ b/libgo/go/os/exec_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris package os diff --git a/libgo/go/os/exec_unix_test.go b/libgo/go/os/exec_unix_test.go index d942cdb..f14b351 100644 --- a/libgo/go/os/exec_unix_test.go +++ b/libgo/go/os/exec_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package os_test diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go index 5710401..239bed1 100644 --- a/libgo/go/os/exec_windows.go +++ b/libgo/go/os/exec_windows.go @@ -45,16 +45,6 @@ func (p *Process) wait() (ps *ProcessState, err error) { return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil } -func terminateProcess(pid, exitcode int) error { - h, e := syscall.OpenProcess(syscall.PROCESS_TERMINATE, false, uint32(pid)) - if e != nil { - return NewSyscallError("OpenProcess", e) - } - defer syscall.CloseHandle(h) - e = syscall.TerminateProcess(h, uint32(exitcode)) - return NewSyscallError("TerminateProcess", e) -} - func (p *Process) signal(sig Signal) error { handle := atomic.LoadUintptr(&p.handle) if handle == uintptr(syscall.InvalidHandle) { @@ -64,16 +54,22 @@ func (p *Process) signal(sig Signal) error { return ErrProcessDone } if sig == Kill { - err := terminateProcess(p.Pid, 1) + var terminationHandle syscall.Handle + e := syscall.DuplicateHandle(^syscall.Handle(0), syscall.Handle(handle), ^syscall.Handle(0), &terminationHandle, syscall.PROCESS_TERMINATE, false, 0) + if e != nil { + return NewSyscallError("DuplicateHandle", e) + } runtime.KeepAlive(p) - return err + defer syscall.CloseHandle(terminationHandle) + e = syscall.TerminateProcess(syscall.Handle(terminationHandle), 1) + return NewSyscallError("TerminateProcess", e) } // TODO(rsc): Handle Interrupt too? return syscall.Errno(syscall.EWINDOWS) } func (p *Process) release() error { - handle := atomic.LoadUintptr(&p.handle) + handle := atomic.SwapUintptr(&p.handle, uintptr(syscall.InvalidHandle)) if handle == uintptr(syscall.InvalidHandle) { return syscall.EINVAL } @@ -81,7 +77,6 @@ func (p *Process) release() error { if e != nil { return NewSyscallError("CloseHandle", e) } - atomic.StoreUintptr(&p.handle, uintptr(syscall.InvalidHandle)) // no need for a finalizer anymore runtime.SetFinalizer(p, nil) return nil diff --git a/libgo/go/os/executable_path.go b/libgo/go/os/executable_path.go index 7b8b836..625430e 100644 --- a/libgo/go/os/executable_path.go +++ b/libgo/go/os/executable_path.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || openbsd // +build aix openbsd package os diff --git a/libgo/go/os/executable_plan9.go b/libgo/go/os/executable_plan9.go index a5947ea..ad7a441 100644 --- a/libgo/go/os/executable_plan9.go +++ b/libgo/go/os/executable_plan9.go @@ -2,14 +2,18 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build plan9 // +build plan9 package os -import "syscall" +import ( + "internal/itoa" + "syscall" +) func executable() (string, error) { - fn := "/proc/" + itoa(Getpid()) + "/text" + fn := "/proc/" + itoa.Itoa(Getpid()) + "/text" f, err := Open(fn) if err != nil { return "", err diff --git a/libgo/go/os/executable_procfs.go b/libgo/go/os/executable_procfs.go index 989a220..fdb2394 100644 --- a/libgo/go/os/executable_procfs.go +++ b/libgo/go/os/executable_procfs.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build hurd || linux || netbsd || (js && wasm) // +build hurd linux netbsd js,wasm package os @@ -11,10 +12,7 @@ import ( "runtime" ) -// We query the executable path at init time to avoid the problem of -// readlink returns a path appended with " (deleted)" when the original -// binary gets deleted. -var executablePath, executablePathErr = func() (string, error) { +func executable() (string, error) { var procfn string switch runtime.GOOS { default: @@ -24,9 +22,17 @@ var executablePath, executablePathErr = func() (string, error) { case "netbsd": procfn = "/proc/curproc/exe" } - return Readlink(procfn) -}() + path, err := Readlink(procfn) -func executable() (string, error) { - return executablePath, executablePathErr + // When the executable has been deleted then Readlink returns a + // path appended with " (deleted)". + return stringsTrimSuffix(path, " (deleted)"), err +} + +// stringsTrimSuffix is the same as strings.TrimSuffix. +func stringsTrimSuffix(s, suffix string) string { + if len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix { + return s[:len(s)-len(suffix)] + } + return s } diff --git a/libgo/go/os/executable_sysctl.go b/libgo/go/os/executable_sysctl.go index f9a4b18..039448b 100644 --- a/libgo/go/os/executable_sysctl.go +++ b/libgo/go/os/executable_sysctl.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build freebsd || dragonfly // +build freebsd dragonfly package os diff --git a/libgo/go/os/executable_test.go b/libgo/go/os/executable_test.go index f25ee0c..719d6a6 100644 --- a/libgo/go/os/executable_test.go +++ b/libgo/go/os/executable_test.go @@ -86,3 +86,68 @@ func init() { os.Exit(0) } } + +func TestExecutableDeleted(t *testing.T) { + testenv.MustHaveExec(t) + switch runtime.GOOS { + case "windows", "plan9": + t.Skipf("%v does not support deleting running binary", runtime.GOOS) + case "openbsd", "freebsd", "aix": + t.Skipf("%v does not support reading deleted binary name", runtime.GOOS) + } + + dir := t.TempDir() + + src := filepath.Join(dir, "testdel.go") + exe := filepath.Join(dir, "testdel.exe") + + err := os.WriteFile(src, []byte(testExecutableDeletion), 0666) + if err != nil { + t.Fatal(err) + } + + out, err := osexec.Command(testenv.GoToolPath(t), "build", "-o", exe, src).CombinedOutput() + t.Logf("build output:\n%s", out) + if err != nil { + t.Fatal(err) + } + + out, err = osexec.Command(exe).CombinedOutput() + t.Logf("exec output:\n%s", out) + if err != nil { + t.Fatal(err) + } +} + +const testExecutableDeletion = `package main + +import ( + "fmt" + "os" +) + +func main() { + before, err := os.Executable() + if err != nil { + fmt.Fprintf(os.Stderr, "failed to read executable name before deletion: %v\n", err) + os.Exit(1) + } + + err = os.Remove(before) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to remove executable: %v\n", err) + os.Exit(1) + } + + after, err := os.Executable() + if err != nil { + fmt.Fprintf(os.Stderr, "failed to read executable name after deletion: %v\n", err) + os.Exit(1) + } + + if before != after { + fmt.Fprintf(os.Stderr, "before and after do not match: %v != %v\n", before, after) + os.Exit(1) + } +} +` diff --git a/libgo/go/os/export_unix_test.go b/libgo/go/os/export_unix_test.go index f4d399d..dd2f8ec 100644 --- a/libgo/go/os/export_unix_test.go +++ b/libgo/go/os/export_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris package os diff --git a/libgo/go/os/export_windows_test.go b/libgo/go/os/export_windows_test.go index f36fadb..ff4f899 100644 --- a/libgo/go/os/export_windows_test.go +++ b/libgo/go/os/export_windows_test.go @@ -8,6 +8,7 @@ package os var ( FixLongPath = fixLongPath + CanUseLongPaths = canUseLongPaths NewConsoleFile = newConsoleFile CommandLineToArgv = commandLineToArgv ) diff --git a/libgo/go/os/fifo_test.go b/libgo/go/os/fifo_test.go index 2439192..007ed29 100644 --- a/libgo/go/os/fifo_test.go +++ b/libgo/go/os/fifo_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd // +build darwin dragonfly freebsd linux netbsd openbsd package os_test @@ -25,17 +26,9 @@ func TestFifoEOF(t *testing.T) { switch runtime.GOOS { case "android": t.Skip("skipping on Android; mkfifo syscall not available") - case "openbsd": - // On OpenBSD 6.2 this test just hangs for some reason. - t.Skip("skipping on OpenBSD; issue 25877") } - dir, err := os.MkdirTemp("", "TestFifoEOF") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - + dir := t.TempDir() fifoName := filepath.Join(dir, "fifo") if err := syscall.Mkfifo(fifoName, 0600); err != nil { t.Fatal(err) diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go index 52dd943..e717f17 100644 --- a/libgo/go/os/file.go +++ b/libgo/go/os/file.go @@ -44,11 +44,13 @@ import ( "errors" "internal/poll" "internal/testlog" + "internal/unsafeheader" "io" "io/fs" "runtime" "syscall" "time" + "unsafe" ) // Name returns the name of the file as presented to Open. @@ -246,7 +248,12 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) { // WriteString is like Write, but writes the contents of string s rather than // a slice of bytes. func (f *File) WriteString(s string) (n int, err error) { - return f.Write([]byte(s)) + var b []byte + hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b)) + hdr.Data = (*unsafeheader.String)(unsafe.Pointer(&s)).Data + hdr.Cap = len(s) + hdr.Len = len(s) + return f.Write(b) } // Mkdir creates a new directory with the specified name and permission @@ -644,6 +651,17 @@ func (dir dirFS) Open(name string) (fs.File, error) { return f, nil } +func (dir dirFS) Stat(name string) (fs.FileInfo, error) { + if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) { + return nil, &PathError{Op: "stat", Path: name, Err: ErrInvalid} + } + f, err := Stat(string(dir) + "/" + name) + if err != nil { + return nil, err + } + return f, nil +} + // ReadFile reads the named file and returns the contents. // A successful call returns err == nil, not err == EOF. // Because ReadFile reads the whole file, it does not treat an EOF from Read diff --git a/libgo/go/os/file_plan9.go b/libgo/go/os/file_plan9.go index 4f384e9..604aea6 100644 --- a/libgo/go/os/file_plan9.go +++ b/libgo/go/os/file_plan9.go @@ -440,6 +440,8 @@ func Link(oldname, newname string) error { } // Symlink creates newname as a symbolic link to oldname. +// On Windows, a symlink to a non-existent oldname creates a file symlink; +// if oldname is later created as a directory the symlink will not work. // If there is an error, it will be of type *LinkError. func Symlink(oldname, newname string) error { return &LinkError{"symlink", oldname, newname, syscall.EPLAN9} diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go index 95bf9e7..21831a7 100644 --- a/libgo/go/os/file_posix.go +++ b/libgo/go/os/file_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows package os diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go index 5888d48..a31800bd 100644 --- a/libgo/go/os/file_unix.go +++ b/libgo/go/os/file_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris package os @@ -173,7 +174,7 @@ func newFile(fd uintptr, name string, kind newFileKind) *File { // with the netpoll system. That can happen for // a file descriptor that is not supported by // epoll/kqueue; for example, disk files on - // GNU/Linux systems. We assume that any real error + // Linux systems. We assume that any real error // will show up in later I/O. } else if pollable { // We successfully registered with netpoll, so put @@ -261,6 +262,7 @@ func (file *file) close() error { var err error if file.dirinfo != nil { file.dirinfo.close() + file.dirinfo = nil } if e := file.pfd.Close(); e != nil { if e == poll.ErrFileClosing { @@ -363,6 +365,8 @@ func Link(oldname, newname string) error { } // Symlink creates newname as a symbolic link to oldname. +// On Windows, a symlink to a non-existent oldname creates a file symlink; +// if oldname is later created as a directory the symlink will not work. // If there is an error, it will be of type *LinkError. func Symlink(oldname, newname string) error { e := ignoringEINTR(func() error { diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go index 734c655..0cde454 100644 --- a/libgo/go/os/os_test.go +++ b/libgo/go/os/os_test.go @@ -615,11 +615,7 @@ func TestReaddirNValues(t *testing.T) { if testing.Short() { t.Skip("test.short; skipping") } - dir, err := os.MkdirTemp("", "") - if err != nil { - t.Fatalf("TempDir: %v", err) - } - defer RemoveAll(dir) + dir := t.TempDir() for i := 1; i <= 105; i++ { f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i))) if err != nil { @@ -714,11 +710,7 @@ func TestReaddirStatFailures(t *testing.T) { // testing it wouldn't work. t.Skipf("skipping test on %v", runtime.GOOS) } - dir, err := os.MkdirTemp("", "") - if err != nil { - t.Fatalf("TempDir: %v", err) - } - defer RemoveAll(dir) + dir := t.TempDir() touch(t, filepath.Join(dir, "good1")) touch(t, filepath.Join(dir, "x")) // will disappear or have an error touch(t, filepath.Join(dir, "good2")) @@ -1951,22 +1943,16 @@ func TestAppend(t *testing.T) { func TestStatDirWithTrailingSlash(t *testing.T) { // Create new temporary directory and arrange to clean it up. - path, err := os.MkdirTemp("", "_TestStatDirWithSlash_") - if err != nil { - t.Fatalf("TempDir: %s", err) - } - defer RemoveAll(path) + path := t.TempDir() // Stat of path should succeed. - _, err = Stat(path) - if err != nil { + if _, err := Stat(path); err != nil { t.Fatalf("stat %s failed: %s", path, err) } // Stat of path+"/" should succeed too. path += "/" - _, err = Stat(path) - if err != nil { + if _, err := Stat(path); err != nil { t.Fatalf("stat %s failed: %s", path, err) } } @@ -2093,12 +2079,7 @@ func TestLargeWriteToConsole(t *testing.T) { func TestStatDirModeExec(t *testing.T) { const mode = 0111 - path, err := os.MkdirTemp("", "go-build") - if err != nil { - t.Fatalf("Failed to create temp directory: %v", err) - } - defer RemoveAll(path) - + path := t.TempDir() if err := Chmod(path, 0777); err != nil { t.Fatalf("Chmod %q 0777: %v", path, err) } @@ -2162,12 +2143,7 @@ func TestStatStdin(t *testing.T) { func TestStatRelativeSymlink(t *testing.T) { testenv.MustHaveSymlink(t) - tmpdir, err := os.MkdirTemp("", "TestStatRelativeSymlink") - if err != nil { - t.Fatal(err) - } - defer RemoveAll(tmpdir) - + tmpdir := t.TempDir() target := filepath.Join(tmpdir, "target") f, err := Create(target) if err != nil { @@ -2775,3 +2751,21 @@ func TestReadFileProc(t *testing.T) { t.Fatalf("read %s: not newline-terminated: %q", name, data) } } + +func TestWriteStringAlloc(t *testing.T) { + if runtime.GOOS == "js" { + t.Skip("js allocates a lot during File.WriteString") + } + d := t.TempDir() + f, err := Create(filepath.Join(d, "whiteboard.txt")) + if err != nil { + t.Fatal(err) + } + defer f.Close() + allocs := testing.AllocsPerRun(100, func() { + f.WriteString("I will not allocate when passed a string longer than 32 bytes.\n") + }) + if allocs != 0 { + t.Errorf("expected 0 allocs for File.WriteString, got %v", allocs) + } +} diff --git a/libgo/go/os/os_unix_test.go b/libgo/go/os/os_unix_test.go index 9a5d7bf..95ceb0d 100644 --- a/libgo/go/os/os_unix_test.go +++ b/libgo/go/os/os_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris package os_test diff --git a/libgo/go/os/os_windows_test.go b/libgo/go/os/os_windows_test.go index b0929b4..195c30f 100644 --- a/libgo/go/os/os_windows_test.go +++ b/libgo/go/os/os_windows_test.go @@ -29,22 +29,32 @@ import ( // For TestRawConnReadWrite. type syscallDescriptor = syscall.Handle -func TestSameWindowsFile(t *testing.T) { - temp, err := os.MkdirTemp("", "TestSameWindowsFile") +// chdir changes the current working directory to the named directory, +// and then restore the original working directory at the end of the test. +func chdir(t *testing.T, dir string) { + olddir, err := os.Getwd() if err != nil { - t.Fatal(err) + t.Fatalf("chdir: %v", err) } - defer os.RemoveAll(temp) - - wd, err := os.Getwd() - if err != nil { - t.Fatal(err) + if err := os.Chdir(dir); err != nil { + t.Fatalf("chdir %s: %v", dir, err) } - err = os.Chdir(temp) + + t.Cleanup(func() { + if err := os.Chdir(olddir); err != nil { + t.Errorf("chdir to original working directory %s: %v", olddir, err) + os.Exit(1) + } + }) +} + +func TestSameWindowsFile(t *testing.T) { + temp, err := os.MkdirTemp("", "TestSameWindowsFile") if err != nil { t.Fatal(err) } - defer os.Chdir(wd) + defer os.RemoveAll(temp) + chdir(t, temp) f, err := os.Create("a") if err != nil { @@ -94,16 +104,7 @@ func testDirLinks(t *testing.T, tests []dirLinkTest) { t.Fatal(err) } defer os.RemoveAll(tmpdir) - - oldwd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - err = os.Chdir(tmpdir) - if err != nil { - t.Fatal(err) - } - defer os.Chdir(oldwd) + chdir(t, tmpdir) dir := filepath.Join(tmpdir, "dir") err = os.Mkdir(dir, 0777) @@ -444,15 +445,7 @@ func TestNetworkSymbolicLink(t *testing.T) { } defer os.RemoveAll(dir) - oldwd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - err = os.Chdir(dir) - if err != nil { - t.Fatal(err) - } - defer os.Chdir(oldwd) + chdir(t, dir) shareName := "GoSymbolicLinkTestShare" // hope no conflictions sharePath := filepath.Join(dir, shareName) @@ -604,16 +597,7 @@ func TestOpenVolumeName(t *testing.T) { t.Fatal(err) } defer os.RemoveAll(tmpdir) - - wd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - err = os.Chdir(tmpdir) - if err != nil { - t.Fatal(err) - } - defer os.Chdir(wd) + chdir(t, tmpdir) want := []string{"file1", "file2", "file3", "gopher.txt"} sort.Strings(want) @@ -642,11 +626,7 @@ func TestOpenVolumeName(t *testing.T) { } func TestDeleteReadOnly(t *testing.T) { - tmpdir, err := os.MkdirTemp("", "TestDeleteReadOnly") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() p := filepath.Join(tmpdir, "a") // This sets FILE_ATTRIBUTE_READONLY. f, err := os.OpenFile(p, os.O_CREATE, 0400) @@ -812,11 +792,7 @@ func compareCommandLineToArgvWithSyscall(t *testing.T, cmd string) { } func TestCmdArgs(t *testing.T) { - tmpdir, err := os.MkdirTemp("", "TestCmdArgs") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() const prog = ` package main @@ -831,8 +807,7 @@ func main() { } ` src := filepath.Join(tmpdir, "main.go") - err = os.WriteFile(src, []byte(prog), 0666) - if err != nil { + if err := os.WriteFile(src, []byte(prog), 0666); err != nil { t.Fatal(err) } @@ -979,21 +954,14 @@ func TestSymlinkCreation(t *testing.T) { } t.Parallel() - temp, err := os.MkdirTemp("", "TestSymlinkCreation") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(temp) - + temp := t.TempDir() dummyFile := filepath.Join(temp, "file") - err = os.WriteFile(dummyFile, []byte(""), 0644) - if err != nil { + if err := os.WriteFile(dummyFile, []byte(""), 0644); err != nil { t.Fatal(err) } linkFile := filepath.Join(temp, "link") - err = os.Symlink(dummyFile, linkFile) - if err != nil { + if err := os.Symlink(dummyFile, linkFile); err != nil { t.Fatal(err) } } @@ -1226,16 +1194,7 @@ func TestWindowsReadlink(t *testing.T) { if err != nil { t.Fatal(err) } - - wd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - err = os.Chdir(tmpdir) - if err != nil { - t.Fatal(err) - } - defer os.Chdir(wd) + chdir(t, tmpdir) vol := filepath.VolumeName(tmpdir) output, err := osexec.Command("cmd", "/c", "mountvol", vol, "/L").CombinedOutput() diff --git a/libgo/go/os/path_test.go b/libgo/go/os/path_test.go index b79d958..4535abb 100644 --- a/libgo/go/os/path_test.go +++ b/libgo/go/os/path_test.go @@ -6,7 +6,6 @@ package os_test import ( "internal/testenv" - "os" . "os" "path/filepath" "runtime" @@ -78,27 +77,19 @@ func TestMkdirAll(t *testing.T) { func TestMkdirAllWithSymlink(t *testing.T) { testenv.MustHaveSymlink(t) - tmpDir, err := os.MkdirTemp("", "TestMkdirAllWithSymlink-") - if err != nil { - t.Fatal(err) - } - defer RemoveAll(tmpDir) - + tmpDir := t.TempDir() dir := tmpDir + "/dir" - err = Mkdir(dir, 0755) - if err != nil { + if err := Mkdir(dir, 0755); err != nil { t.Fatalf("Mkdir %s: %s", dir, err) } link := tmpDir + "/link" - err = Symlink("dir", link) - if err != nil { + if err := Symlink("dir", link); err != nil { t.Fatalf("Symlink %s: %s", link, err) } path := link + "/foo" - err = MkdirAll(path, 0755) - if err != nil { + if err := MkdirAll(path, 0755); err != nil { t.Errorf("MkdirAll %q: %s", path, err) } } diff --git a/libgo/go/os/path_unix.go b/libgo/go/os/path_unix.go index 6ef6560..bb0b0a0 100644 --- a/libgo/go/os/path_unix.go +++ b/libgo/go/os/path_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris package os diff --git a/libgo/go/os/path_windows.go b/libgo/go/os/path_windows.go index 87b1cac..a96245f 100644 --- a/libgo/go/os/path_windows.go +++ b/libgo/go/os/path_windows.go @@ -128,6 +128,10 @@ func dirname(path string) string { return vol + dir } +// This is set via go:linkname on runtime.canUseLongPaths, and is true when the OS +// supports opting into proper long path handling without the need for fixups. +var canUseLongPaths bool + // fixLongPath returns the extended-length (\\?\-prefixed) form of // path when needed, in order to avoid the default 260 character file // path limit imposed by Windows. If path is not easily converted to @@ -137,6 +141,9 @@ func dirname(path string) string { // // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath func fixLongPath(path string) string { + if canUseLongPaths { + return path + } // Do nothing (and don't allocate) if the path is "short". // Empirically (at least on the Windows Server 2013 builder), // the kernel is arbitrarily okay with < 248 bytes. That diff --git a/libgo/go/os/path_windows_test.go b/libgo/go/os/path_windows_test.go index 869db8f..e960bcb 100644 --- a/libgo/go/os/path_windows_test.go +++ b/libgo/go/os/path_windows_test.go @@ -12,6 +12,9 @@ import ( ) func TestFixLongPath(t *testing.T) { + if os.CanUseLongPaths { + return + } // 248 is long enough to trigger the longer-than-248 checks in // fixLongPath, but short enough not to make a path component // longer than 255, which is illegal on Windows. (which @@ -46,12 +49,22 @@ func TestFixLongPath(t *testing.T) { } } -func TestMkdirAllExtendedLength(t *testing.T) { - tmpDir, err := os.MkdirTemp("", "TestMkdirAllExtendedLength") - if err != nil { - t.Fatal(err) +func TestMkdirAllLongPath(t *testing.T) { + tmpDir := t.TempDir() + path := tmpDir + for i := 0; i < 100; i++ { + path += `\another-path-component` + } + if err := os.MkdirAll(path, 0777); err != nil { + t.Fatalf("MkdirAll(%q) failed; %v", path, err) + } + if err := os.RemoveAll(tmpDir); err != nil { + t.Fatalf("RemoveAll(%q) failed; %v", tmpDir, err) } - defer os.RemoveAll(tmpDir) +} + +func TestMkdirAllExtendedLength(t *testing.T) { + tmpDir := t.TempDir() const prefix = `\\?\` if len(tmpDir) < 4 || tmpDir[:4] != prefix { @@ -62,14 +75,12 @@ func TestMkdirAllExtendedLength(t *testing.T) { tmpDir = prefix + fullPath } path := tmpDir + `\dir\` - err = os.MkdirAll(path, 0777) - if err != nil { + if err := os.MkdirAll(path, 0777); err != nil { t.Fatalf("MkdirAll(%q) failed: %v", path, err) } path = path + `.\dir2` - err = os.MkdirAll(path, 0777) - if err == nil { + if err := os.MkdirAll(path, 0777); err == nil { t.Fatalf("MkdirAll(%q) should have failed, but did not", path) } } diff --git a/libgo/go/os/pipe2_bsd.go b/libgo/go/os/pipe2_bsd.go index 0ef894b..bf6d081 100644 --- a/libgo/go/os/pipe2_bsd.go +++ b/libgo/go/os/pipe2_bsd.go @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build freebsd netbsd openbsd +//go:build dragonfly || freebsd || netbsd || openbsd +// +build dragonfly freebsd netbsd openbsd package os diff --git a/libgo/go/os/pipe2_illumos.go b/libgo/go/os/pipe2_illumos.go index 026ce62..71b8cb8 100644 --- a/libgo/go/os/pipe2_illumos.go +++ b/libgo/go/os/pipe2_illumos.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build illumos // +build illumos package os diff --git a/libgo/go/os/pipe_bsd.go b/libgo/go/os/pipe_bsd.go index 115d6ba..097b32e 100644 --- a/libgo/go/os/pipe_bsd.go +++ b/libgo/go/os/pipe_bsd.go @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build aix darwin dragonfly js,wasm solaris,!illumos +//go:build aix || darwin || (js && wasm) || (solaris && !illumos) +// +build aix darwin js,wasm solaris,!illumos package os diff --git a/libgo/go/os/pipe_test.go b/libgo/go/os/pipe_test.go index b98e538..41a1e9c 100644 --- a/libgo/go/os/pipe_test.go +++ b/libgo/go/os/pipe_test.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // Test broken pipes on Unix systems. +//go:build !plan9 && !js // +build !plan9,!js package os_test @@ -441,12 +442,14 @@ func TestFdReadRace(t *testing.T) { defer r.Close() defer w.Close() - c := make(chan bool) + const count = 10 + + c := make(chan bool, 1) var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() - var buf [10]byte + var buf [count]byte r.SetReadDeadline(time.Now().Add(time.Minute)) c <- true if _, err := r.Read(buf[:]); os.IsTimeout(err) { @@ -465,8 +468,9 @@ func TestFdReadRace(t *testing.T) { r.Fd() // The bug was that Fd would hang until Read timed out. - // If the bug is fixed, then closing r here will cause - // the Read to exit before the timeout expires. + // If the bug is fixed, then writing to w and closing r here + // will cause the Read to exit before the timeout expires. + w.Write(make([]byte, count)) r.Close() }() diff --git a/libgo/go/os/rawconn.go b/libgo/go/os/rawconn.go index 9e11cda..ffc598b 100644 --- a/libgo/go/os/rawconn.go +++ b/libgo/go/os/rawconn.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 // +build !plan9 package os diff --git a/libgo/go/os/rawconn_test.go b/libgo/go/os/rawconn_test.go index 2554f5b..8aebaf8 100644 --- a/libgo/go/os/rawconn_test.go +++ b/libgo/go/os/rawconn_test.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // Test use of raw connections. +//go:build !plan9 && !js // +build !plan9,!js package os_test diff --git a/libgo/go/os/readfrom_linux_test.go b/libgo/go/os/readfrom_linux_test.go index 1d145da..cb6a59a 100644 --- a/libgo/go/os/readfrom_linux_test.go +++ b/libgo/go/os/readfrom_linux_test.go @@ -106,7 +106,7 @@ func TestCopyFileRange(t *testing.T) { t.Fatal(err) } if n != int64(len(data)) { - t.Fatalf("transfered %d, want %d", n, len(data)) + t.Fatalf("transferred %d, want %d", n, len(data)) } if !hook.called { t.Fatalf("should have called poll.CopyFileRange") @@ -130,7 +130,7 @@ func TestCopyFileRange(t *testing.T) { t.Fatal(err) } if n != int64(len(data)) { - t.Fatalf("transfered %d, want %d", n, len(data)) + t.Fatalf("transferred %d, want %d", n, len(data)) } if !hook.called { t.Fatalf("should have called poll.CopyFileRange") @@ -162,7 +162,7 @@ func TestCopyFileRange(t *testing.T) { t.Fatal(err) } if n != int64(len(data)) { - t.Fatalf("transfered %d, want %d", n, len(data)) + t.Fatalf("transferred %d, want %d", n, len(data)) } if !hook.called { t.Fatalf("should have called poll.CopyFileRange") diff --git a/libgo/go/os/readfrom_stub.go b/libgo/go/os/readfrom_stub.go index 65429d0..826760f 100644 --- a/libgo/go/os/readfrom_stub.go +++ b/libgo/go/os/readfrom_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !linux // +build !linux package os diff --git a/libgo/go/os/removeall_at.go b/libgo/go/os/removeall_at.go index f9eafa1..4e55577 100644 --- a/libgo/go/os/removeall_at.go +++ b/libgo/go/os/removeall_at.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris package os diff --git a/libgo/go/os/removeall_noat.go b/libgo/go/os/removeall_noat.go index a4cde5a..966f3f5 100644 --- a/libgo/go/os/removeall_noat.go +++ b/libgo/go/os/removeall_noat.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !aix && !darwin && !dragonfly && !freebsd && !hurd && !linux && !netbsd && !openbsd && !solaris // +build !aix,!darwin,!dragonfly,!freebsd,!hurd,!linux,!netbsd,!openbsd,!solaris package os diff --git a/libgo/go/os/removeall_test.go b/libgo/go/os/removeall_test.go index 3a2f6e3..08dfdd8 100644 --- a/libgo/go/os/removeall_test.go +++ b/libgo/go/os/removeall_test.go @@ -15,12 +15,7 @@ import ( ) func TestRemoveAll(t *testing.T) { - tmpDir, err := os.MkdirTemp("", "TestRemoveAll-") - if err != nil { - t.Fatal(err) - } - defer RemoveAll(tmpDir) - + tmpDir := t.TempDir() if err := RemoveAll(""); err != nil { t.Errorf("RemoveAll(\"\"): %v; want nil", err) } @@ -128,12 +123,7 @@ func TestRemoveAllLarge(t *testing.T) { t.Skip("skipping in short mode") } - tmpDir, err := os.MkdirTemp("", "TestRemoveAll-") - if err != nil { - t.Fatal(err) - } - defer RemoveAll(tmpDir) - + tmpDir := t.TempDir() path := filepath.Join(tmpDir, "_TestRemoveAllLarge_") // Make directory with 1000 files and remove. @@ -236,12 +226,7 @@ func TestRemoveAllDot(t *testing.T) { func TestRemoveAllDotDot(t *testing.T) { t.Parallel() - tempDir, err := os.MkdirTemp("", "TestRemoveAllDotDot-") - if err != nil { - t.Fatal(err) - } - defer RemoveAll(tempDir) - + tempDir := t.TempDir() subdir := filepath.Join(tempDir, "x") subsubdir := filepath.Join(subdir, "y") if err := MkdirAll(subsubdir, 0777); err != nil { @@ -261,12 +246,7 @@ func TestRemoveAllDotDot(t *testing.T) { func TestRemoveReadOnlyDir(t *testing.T) { t.Parallel() - tempDir, err := os.MkdirTemp("", "TestRemoveReadOnlyDir-") - if err != nil { - t.Fatal(err) - } - defer RemoveAll(tempDir) - + tempDir := t.TempDir() subdir := filepath.Join(tempDir, "x") if err := Mkdir(subdir, 0); err != nil { t.Fatal(err) @@ -298,12 +278,7 @@ func TestRemoveAllButReadOnlyAndPathError(t *testing.T) { t.Parallel() - tempDir, err := os.MkdirTemp("", "TestRemoveAllButReadOnly-") - if err != nil { - t.Fatal(err) - } - defer RemoveAll(tempDir) - + tempDir := t.TempDir() dirs := []string{ "a", "a/x", @@ -347,7 +322,7 @@ func TestRemoveAllButReadOnlyAndPathError(t *testing.T) { defer Chmod(d, 0777) } - err = RemoveAll(tempDir) + err := RemoveAll(tempDir) if err == nil { t.Fatal("RemoveAll succeeded unexpectedly") } @@ -389,12 +364,7 @@ func TestRemoveUnreadableDir(t *testing.T) { t.Parallel() - tempDir, err := os.MkdirTemp("", "TestRemoveAllButReadOnly-") - if err != nil { - t.Fatal(err) - } - defer RemoveAll(tempDir) - + tempDir := t.TempDir() target := filepath.Join(tempDir, "d0", "d1", "d2") if err := MkdirAll(target, 0755); err != nil { t.Fatal(err) @@ -413,12 +383,7 @@ func TestRemoveAllWithMoreErrorThanReqSize(t *testing.T) { t.Skip("skipping in short mode") } - tmpDir, err := os.MkdirTemp("", "TestRemoveAll-") - if err != nil { - t.Fatal(err) - } - defer RemoveAll(tmpDir) - + tmpDir := t.TempDir() path := filepath.Join(tmpDir, "_TestRemoveAllWithMoreErrorThanReqSize_") // Make directory with 1025 read-only files. @@ -443,7 +408,7 @@ func TestRemoveAllWithMoreErrorThanReqSize(t *testing.T) { // This call should not hang, even on a platform that disallows file deletion // from read-only directories. - err = RemoveAll(path) + err := RemoveAll(path) if Getuid() == 0 { // On many platforms, root can remove files from read-only directories. diff --git a/libgo/go/os/signal/doc.go b/libgo/go/os/signal/doc.go index 2229d36..7af61d2 100644 --- a/libgo/go/os/signal/doc.go +++ b/libgo/go/os/signal/doc.go @@ -50,7 +50,7 @@ If the Go program is started with either SIGHUP or SIGINT ignored If the Go program is started with a non-empty signal mask, that will generally be honored. However, some signals are explicitly unblocked: the synchronous signals, SIGILL, SIGTRAP, SIGSTKFLT, SIGCHLD, SIGPROF, -and, on GNU/Linux, signals 32 (SIGCANCEL) and 33 (SIGSETXID) +and, on Linux, signals 32 (SIGCANCEL) and 33 (SIGSETXID) (SIGCANCEL and SIGSETXID are used internally by glibc). Subprocesses started by os.Exec, or by the os/exec package, will inherit the modified signal mask. @@ -129,9 +129,7 @@ If the non-Go code installs any signal handlers, it must use the SA_ONSTACK flag with sigaction. Failing to do so is likely to cause the program to crash if the signal is received. Go programs routinely run with a limited stack, and therefore set up an alternate signal -stack. Also, the Go standard library expects that any signal handlers -will use the SA_RESTART flag. Failing to do so may cause some library -calls to return "interrupted system call" errors. +stack. If the non-Go code installs a signal handler for any of the synchronous signals (SIGBUS, SIGFPE, SIGSEGV), then it should record @@ -178,7 +176,7 @@ will initialize signals at global constructor time. For shared library is loaded. If the Go runtime sees an existing signal handler for the SIGCANCEL or -SIGSETXID signals (which are used only on GNU/Linux), it will turn on +SIGSETXID signals (which are used only on Linux), it will turn on the SA_ONSTACK flag and otherwise keep the signal handler. For the synchronous signals and SIGPIPE, the Go runtime will install a diff --git a/libgo/go/os/signal/example_unix_test.go b/libgo/go/os/signal/example_unix_test.go index a0af37a..3f7795b 100644 --- a/libgo/go/os/signal/example_unix_test.go +++ b/libgo/go/os/signal/example_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package signal_test diff --git a/libgo/go/os/signal/internal/pty/pty.go b/libgo/go/os/signal/internal/pty/pty.go index dd0aee1..4ed3eb4 100644 --- a/libgo/go/os/signal/internal/pty/pty.go +++ b/libgo/go/os/signal/internal/pty/pty.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (aix || darwin || dragonfly || freebsd || hurd || (linux && !android) || netbsd || openbsd || solaris) && cgo // +build aix darwin dragonfly freebsd hurd linux,!android netbsd openbsd solaris // +build cgo diff --git a/libgo/go/os/signal/signal_cgo_test.go b/libgo/go/os/signal/signal_cgo_test.go index a8a4856..e1e4509 100644 --- a/libgo/go/os/signal/signal_cgo_test.go +++ b/libgo/go/os/signal/signal_cgo_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (darwin || dragonfly || freebsd || (linux && !android) || netbsd || openbsd) && cgo // +build darwin dragonfly freebsd linux,!android netbsd openbsd // +build cgo diff --git a/libgo/go/os/signal/signal_linux_test.go b/libgo/go/os/signal/signal_linux_test.go index 2e553d0..7abe1ec 100644 --- a/libgo/go/os/signal/signal_linux_test.go +++ b/libgo/go/os/signal/signal_linux_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux // +build linux package signal diff --git a/libgo/go/os/signal/signal_plan9_test.go b/libgo/go/os/signal/signal_plan9_test.go index 10bfdc3..8357199 100644 --- a/libgo/go/os/signal/signal_plan9_test.go +++ b/libgo/go/os/signal/signal_plan9_test.go @@ -5,6 +5,7 @@ package signal import ( + "internal/itoa" "os" "runtime" "syscall" @@ -155,23 +156,8 @@ func TestStop(t *testing.T) { } } -func itoa(val int) string { - if val < 0 { - return "-" + itoa(-val) - } - var buf [32]byte // big enough for int64 - i := len(buf) - 1 - for val >= 10 { - buf[i] = byte(val%10 + '0') - i-- - val /= 10 - } - buf[i] = byte(val + '0') - return string(buf[i:]) -} - func postNote(pid int, note string) error { - f, err := os.OpenFile("/proc/"+itoa(pid)+"/note", os.O_WRONLY, 0) + f, err := os.OpenFile("/proc/"+itoa.Itoa(pid)+"/note", os.O_WRONLY, 0) if err != nil { return err } diff --git a/libgo/go/os/signal/signal_test.go b/libgo/go/os/signal/signal_test.go index 1f89780..c653c34 100644 --- a/libgo/go/os/signal/signal_test.go +++ b/libgo/go/os/signal/signal_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris package signal @@ -17,6 +18,7 @@ import ( "runtime" "runtime/trace" "strconv" + "strings" "sync" "syscall" "testing" @@ -30,6 +32,11 @@ import ( // The current value is set based on flakes observed in the Go builders. var settleTime = 100 * time.Millisecond +// fatalWaitingTime is an absurdly long time to wait for signals to be +// delivered but, using it, we (hopefully) eliminate test flakes on the +// build servers. See #46736 for discussion. +var fatalWaitingTime = 30 * time.Second + func init() { if testenv.Builder() == "solaris-amd64-oraclerel" { // The solaris-amd64-oraclerel builder has been observed to time out in @@ -46,6 +53,13 @@ func init() { // // See https://golang.org/issue/33174. settleTime = 11 * time.Second + } else if runtime.GOOS == "linux" && strings.HasPrefix(runtime.GOARCH, "ppc64") { + // Older linux kernels seem to have some hiccups delivering the signal + // in a timely manner on ppc64 and ppc64le. When running on a + // ppc64le/ubuntu 16.04/linux 4.4 host the time can vary quite + // substantially even on a idle system. 5 seconds is twice any value + // observed when running 10000 tests on such a system. + settleTime = 5 * time.Second } else if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" { if scale, err := strconv.Atoi(s); err == nil { settleTime *= time.Duration(scale) @@ -75,7 +89,7 @@ func waitSig1(t *testing.T, c <-chan os.Signal, sig os.Signal, all bool) { // General user code should filter out all unexpected signals instead of just // SIGURG, but since os/signal is tightly coupled to the runtime it seems // appropriate to be stricter here. - for time.Since(start) < settleTime { + for time.Since(start) < fatalWaitingTime { select { case s := <-c: if s == sig { @@ -88,7 +102,7 @@ func waitSig1(t *testing.T, c <-chan os.Signal, sig os.Signal, all bool) { timer.Reset(settleTime / 10) } } - t.Fatalf("timeout after %v waiting for %v", settleTime, sig) + t.Fatalf("timeout after %v waiting for %v", fatalWaitingTime, sig) } // quiesce waits until we can be reasonably confident that all pending signals diff --git a/libgo/go/os/signal/signal_unix.go b/libgo/go/os/signal/signal_unix.go index c18db0c..a0c7ffb 100644 --- a/libgo/go/os/signal/signal_unix.go +++ b/libgo/go/os/signal/signal_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows package signal diff --git a/libgo/go/os/stat_js.go b/libgo/go/os/stat_js.go index 8d20ccd..3badf5b 100644 --- a/libgo/go/os/stat_js.go +++ b/libgo/go/os/stat_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package os diff --git a/libgo/go/os/stat_test.go b/libgo/go/os/stat_test.go index c409f0f..8d99f64 100644 --- a/libgo/go/os/stat_test.go +++ b/libgo/go/os/stat_test.go @@ -185,30 +185,22 @@ func testSymlinkSameFile(t *testing.T, path, link string) { func TestDirAndSymlinkStats(t *testing.T) { testenv.MustHaveSymlink(t) - tmpdir, err := os.MkdirTemp("", "TestDirAndSymlinkStats") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - + tmpdir := t.TempDir() dir := filepath.Join(tmpdir, "dir") - err = os.Mkdir(dir, 0777) - if err != nil { + if err := os.Mkdir(dir, 0777); err != nil { t.Fatal(err) } testDirStats(t, dir) dirlink := filepath.Join(tmpdir, "link") - err = os.Symlink(dir, dirlink) - if err != nil { + if err := os.Symlink(dir, dirlink); err != nil { t.Fatal(err) } testSymlinkStats(t, dirlink, true) testSymlinkSameFile(t, dir, dirlink) linklink := filepath.Join(tmpdir, "linklink") - err = os.Symlink(dirlink, linklink) - if err != nil { + if err := os.Symlink(dirlink, linklink); err != nil { t.Fatal(err) } testSymlinkStats(t, linklink, true) @@ -218,30 +210,22 @@ func TestDirAndSymlinkStats(t *testing.T) { func TestFileAndSymlinkStats(t *testing.T) { testenv.MustHaveSymlink(t) - tmpdir, err := os.MkdirTemp("", "TestFileAndSymlinkStats") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - + tmpdir := t.TempDir() file := filepath.Join(tmpdir, "file") - err = os.WriteFile(file, []byte(""), 0644) - if err != nil { + if err := os.WriteFile(file, []byte(""), 0644); err != nil { t.Fatal(err) } testFileStats(t, file) filelink := filepath.Join(tmpdir, "link") - err = os.Symlink(file, filelink) - if err != nil { + if err := os.Symlink(file, filelink); err != nil { t.Fatal(err) } testSymlinkStats(t, filelink, false) testSymlinkSameFile(t, file, filelink) linklink := filepath.Join(tmpdir, "linklink") - err = os.Symlink(filelink, linklink) - if err != nil { + if err := os.Symlink(filelink, linklink); err != nil { t.Fatal(err) } testSymlinkStats(t, linklink, false) @@ -252,20 +236,13 @@ func TestFileAndSymlinkStats(t *testing.T) { func TestSymlinkWithTrailingSlash(t *testing.T) { testenv.MustHaveSymlink(t) - tmpdir, err := os.MkdirTemp("", "TestSymlinkWithTrailingSlash") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - + tmpdir := t.TempDir() dir := filepath.Join(tmpdir, "dir") - err = os.Mkdir(dir, 0777) - if err != nil { + if err := os.Mkdir(dir, 0777); err != nil { t.Fatal(err) } dirlink := filepath.Join(tmpdir, "link") - err = os.Symlink(dir, dirlink) - if err != nil { + if err := os.Symlink(dir, dirlink); err != nil { t.Fatal(err) } dirlinkWithSlash := dirlink + string(os.PathSeparator) diff --git a/libgo/go/os/stat_unix.go b/libgo/go/os/stat_unix.go index 7873bf9..6ae26ad 100644 --- a/libgo/go/os/stat_unix.go +++ b/libgo/go/os/stat_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris package os diff --git a/libgo/go/os/sticky_bsd.go b/libgo/go/os/sticky_bsd.go index c09b1ac..ab23d81 100644 --- a/libgo/go/os/sticky_bsd.go +++ b/libgo/go/os/sticky_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm netbsd openbsd solaris package os diff --git a/libgo/go/os/sticky_notbsd.go b/libgo/go/os/sticky_notbsd.go index c158506..9979b43 100644 --- a/libgo/go/os/sticky_notbsd.go +++ b/libgo/go/os/sticky_notbsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !aix && !darwin && !dragonfly && !freebsd && (!js || !wasm) && !netbsd && !openbsd && !solaris // +build !aix // +build !darwin // +build !dragonfly diff --git a/libgo/go/os/str.go b/libgo/go/os/str.go index cba9fa3..35643e0 100644 --- a/libgo/go/os/str.go +++ b/libgo/go/os/str.go @@ -6,28 +6,34 @@ package os -// Convert integer to decimal string -func itoa(val int) string { +// itox converts val (an int) to a hexdecimal string. +func itox(val int) string { if val < 0 { - return "-" + uitoa(uint(-val)) + return "-" + uitox(uint(-val)) } - return uitoa(uint(val)) + return uitox(uint(val)) } -// Convert unsigned integer to decimal string -func uitoa(val uint) string { +const hex = "0123456789abcdef" + +// uitox converts val (a uint) to a hexdecimal string. +func uitox(val uint) string { if val == 0 { // avoid string allocation - return "0" + return "0x0" } - var buf [20]byte // big enough for 64bit value base 10 + var buf [20]byte // big enough for 64bit value base 16 + 0x i := len(buf) - 1 - for val >= 10 { - q := val / 10 - buf[i] = byte('0' + val - q*10) + for val >= 16 { + q := val / 16 + buf[i] = hex[val%16] i-- val = q } - // val < 10 - buf[i] = byte('0' + val) + // val < 16 + buf[i] = hex[val%16] + i-- + buf[i] = 'x' + i-- + buf[i] = '0' return string(buf[i:]) } diff --git a/libgo/go/os/sys_bsd.go b/libgo/go/os/sys_bsd.go index b1698f5..1e245eb 100644 --- a/libgo/go/os/sys_bsd.go +++ b/libgo/go/os/sys_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || (js && wasm) || netbsd || openbsd // +build darwin dragonfly freebsd js,wasm netbsd openbsd package os diff --git a/libgo/go/os/sys_js.go b/libgo/go/os/sys_js.go index e860654..4d6a64e 100644 --- a/libgo/go/os/sys_js.go +++ b/libgo/go/os/sys_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package os diff --git a/libgo/go/os/sys_unix.go b/libgo/go/os/sys_unix.go index 37b5a47..aab683e 100644 --- a/libgo/go/os/sys_unix.go +++ b/libgo/go/os/sys_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris package os diff --git a/libgo/go/os/tempfile.go b/libgo/go/os/tempfile.go index 1ad44f1..5b681fc 100644 --- a/libgo/go/os/tempfile.go +++ b/libgo/go/os/tempfile.go @@ -4,7 +4,10 @@ package os -import "errors" +import ( + "errors" + "internal/itoa" +) // fastrand provided by runtime. // We generate random temporary file names so that there's a good @@ -13,7 +16,7 @@ import "errors" func fastrand() uint32 func nextRandom() string { - return uitoa(uint(fastrand())) + return itoa.Uitoa(uint(fastrand())) } // CreateTemp creates a new temporary file in the directory dir, diff --git a/libgo/go/os/timeout_test.go b/libgo/go/os/timeout_test.go index 0a39f46..6d65e42 100644 --- a/libgo/go/os/timeout_test.go +++ b/libgo/go/os/timeout_test.go @@ -2,9 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !js -// +build !plan9 -// +build !windows +//go:build !js && !plan9 && !windows +// +build !js,!plan9,!windows package os_test diff --git a/libgo/go/os/types_unix.go b/libgo/go/os/types_unix.go index c0259ae..e9b8b8b 100644 --- a/libgo/go/os/types_unix.go +++ b/libgo/go/os/types_unix.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !windows -// +build !plan9 +//go:build !windows && !plan9 +// +build !windows,!plan9 package os diff --git a/libgo/go/os/user/cgo_lookup_unix.go b/libgo/go/os/user/cgo_lookup_unix.go index eb6ab50..3f4014c 100644 --- a/libgo/go/os/user/cgo_lookup_unix.go +++ b/libgo/go/os/user/cgo_lookup_unix.go @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (aix || darwin || dragonfly || freebsd || hurd || (!android && linux) || netbsd || openbsd || solaris) && cgo && !osusergo // +build aix darwin dragonfly freebsd hurd !android,linux netbsd openbsd solaris -// +build cgo,!osusergo +// +build cgo +// +build !osusergo package user diff --git a/libgo/go/os/user/cgo_unix_test.go b/libgo/go/os/user/cgo_unix_test.go index 1d341aa..9ec32b3 100644 --- a/libgo/go/os/user/cgo_unix_test.go +++ b/libgo/go/os/user/cgo_unix_test.go @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (darwin || dragonfly || freebsd || (!android && linux) || netbsd || openbsd || solaris) && cgo && !osusergo // +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris -// +build cgo,!osusergo +// +build cgo +// +build !osusergo package user diff --git a/libgo/go/os/user/listgroups_aix.go b/libgo/go/os/user/listgroups_aix.go index 5b9f3f9..93feb80 100644 --- a/libgo/go/os/user/listgroups_aix.go +++ b/libgo/go/os/user/listgroups_aix.go @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo && !osusergo +// +build cgo,!osusergo + package user import "fmt" diff --git a/libgo/go/os/user/listgroups_solaris.go b/libgo/go/os/user/listgroups_illumos.go index f3cbf6c..d25e033 100644 --- a/libgo/go/os/user/listgroups_solaris.go +++ b/libgo/go/os/user/listgroups_illumos.go @@ -1,11 +1,12 @@ -// Copyright 2016 The Go Authors. All rights reserved. +// Copyright 2021 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. +//go:build cgo && !osusergo // +build cgo,!osusergo // Even though this file requires no C, it is used to provide a -// listGroup stub because all the other Solaris calls work. Otherwise, +// listGroup stub because all the other illumos calls work. Otherwise, // this stub will conflict with the lookup_stubs.go fallback. package user @@ -13,5 +14,5 @@ package user import "fmt" func listGroups(u *User) ([]string, error) { - return nil, fmt.Errorf("user: list groups for %s: not supported on Solaris", u.Username) + return nil, fmt.Errorf("user: list groups for %s: not supported on illumos", u.Username) } diff --git a/libgo/go/os/user/listgroups_unix.go b/libgo/go/os/user/listgroups_unix.go index af04c05..38bf807 100644 --- a/libgo/go/os/user/listgroups_unix.go +++ b/libgo/go/os/user/listgroups_unix.go @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build dragonfly darwin freebsd hurd !android,linux netbsd openbsd -// +build cgo,!osusergo +//go:build (dragonfly || darwin || freebsd || hurd || (!android && linux) || netbsd || openbsd || (solaris && !illumos)) && cgo && !osusergo +// +build dragonfly darwin freebsd hurd !android,linux netbsd openbsd solaris,!illumos +// +build cgo +// +build !osusergo package user diff --git a/libgo/go/os/user/lookup_android.go b/libgo/go/os/user/lookup_android.go index 8ca30b8..151aab4 100644 --- a/libgo/go/os/user/lookup_android.go +++ b/libgo/go/os/user/lookup_android.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build android // +build android package user diff --git a/libgo/go/os/user/lookup_stubs.go b/libgo/go/os/user/lookup_stubs.go index 178d814..c975a11 100644 --- a/libgo/go/os/user/lookup_stubs.go +++ b/libgo/go/os/user/lookup_stubs.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (!cgo && !windows && !plan9) || android || (osusergo && !windows && !plan9) // +build !cgo,!windows,!plan9 android osusergo,!windows,!plan9 package user diff --git a/libgo/go/os/user/lookup_unix.go b/libgo/go/os/user/lookup_unix.go index 0f5e82d..28b9634 100644 --- a/libgo/go/os/user/lookup_unix.go +++ b/libgo/go/os/user/lookup_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || (!android && linux) || netbsd || openbsd || solaris) && (!cgo || osusergo) // +build aix darwin dragonfly freebsd hurd js,wasm !android,linux netbsd openbsd solaris // +build !cgo osusergo @@ -32,23 +33,72 @@ type lineFunc func(line []byte) (v interface{}, err error) // readColonFile parses r as an /etc/group or /etc/passwd style file, running // fn for each row. readColonFile returns a value, an error, or (nil, nil) if // the end of the file is reached without a match. -func readColonFile(r io.Reader, fn lineFunc) (v interface{}, err error) { - bs := bufio.NewScanner(r) - for bs.Scan() { - line := bs.Bytes() +// +// readCols is the minimum number of colon-separated fields that will be passed +// to fn; in a long line additional fields may be silently discarded. +func readColonFile(r io.Reader, fn lineFunc, readCols int) (v interface{}, err error) { + rd := bufio.NewReader(r) + + // Read the file line-by-line. + for { + var isPrefix bool + var wholeLine []byte + + // Read the next line. We do so in chunks (as much as reader's + // buffer is able to keep), check if we read enough columns + // already on each step and store final result in wholeLine. + for { + var line []byte + line, isPrefix, err = rd.ReadLine() + + if err != nil { + // We should return (nil, nil) if EOF is reached + // without a match. + if err == io.EOF { + err = nil + } + return nil, err + } + + // Simple common case: line is short enough to fit in a + // single reader's buffer. + if !isPrefix && len(wholeLine) == 0 { + wholeLine = line + break + } + + wholeLine = append(wholeLine, line...) + + // Check if we read the whole line (or enough columns) + // already. + if !isPrefix || bytes.Count(wholeLine, []byte{':'}) >= readCols { + break + } + } + // There's no spec for /etc/passwd or /etc/group, but we try to follow // the same rules as the glibc parser, which allows comments and blank // space at the beginning of a line. - line = bytes.TrimSpace(line) - if len(line) == 0 || line[0] == '#' { + wholeLine = bytes.TrimSpace(wholeLine) + if len(wholeLine) == 0 || wholeLine[0] == '#' { continue } - v, err = fn(line) + v, err = fn(wholeLine) if v != nil || err != nil { return } + + // If necessary, skip the rest of the line + for ; isPrefix; _, isPrefix, err = rd.ReadLine() { + if err != nil { + // We should return (nil, nil) if EOF is reached without a match. + if err == io.EOF { + err = nil + } + return nil, err + } + } } - return nil, bs.Err() } func matchGroupIndexValue(value string, idx int) lineFunc { @@ -79,7 +129,7 @@ func matchGroupIndexValue(value string, idx int) lineFunc { } func findGroupId(id string, r io.Reader) (*Group, error) { - if v, err := readColonFile(r, matchGroupIndexValue(id, 2)); err != nil { + if v, err := readColonFile(r, matchGroupIndexValue(id, 2), 3); err != nil { return nil, err } else if v != nil { return v.(*Group), nil @@ -88,7 +138,7 @@ func findGroupId(id string, r io.Reader) (*Group, error) { } func findGroupName(name string, r io.Reader) (*Group, error) { - if v, err := readColonFile(r, matchGroupIndexValue(name, 0)); err != nil { + if v, err := readColonFile(r, matchGroupIndexValue(name, 0), 3); err != nil { return nil, err } else if v != nil { return v.(*Group), nil @@ -143,7 +193,7 @@ func findUserId(uid string, r io.Reader) (*User, error) { if e != nil { return nil, errors.New("user: invalid userid " + uid) } - if v, err := readColonFile(r, matchUserIndexValue(uid, 2)); err != nil { + if v, err := readColonFile(r, matchUserIndexValue(uid, 2), 6); err != nil { return nil, err } else if v != nil { return v.(*User), nil @@ -152,7 +202,7 @@ func findUserId(uid string, r io.Reader) (*User, error) { } func findUsername(name string, r io.Reader) (*User, error) { - if v, err := readColonFile(r, matchUserIndexValue(name, 0)); err != nil { + if v, err := readColonFile(r, matchUserIndexValue(name, 0), 6); err != nil { return nil, err } else if v != nil { return v.(*User), nil diff --git a/libgo/go/os/user/lookup_unix_test.go b/libgo/go/os/user/lookup_unix_test.go index 72d3b47..060cfe1 100644 --- a/libgo/go/os/user/lookup_unix_test.go +++ b/libgo/go/os/user/lookup_unix_test.go @@ -2,18 +2,20 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (aix || darwin || dragonfly || freebsd || (!android && linux) || netbsd || openbsd || solaris) && !cgo // +build aix darwin dragonfly freebsd !android,linux netbsd openbsd solaris // +build !cgo package user import ( + "fmt" "reflect" "strings" "testing" ) -const testGroupFile = `# See the opendirectoryd(8) man page for additional +var testGroupFile = `# See the opendirectoryd(8) man page for additional # information about Open Directory. ## nobody:*:-2: @@ -29,7 +31,7 @@ daemon:*:1:root # comment:*:4:found # comment:*:4:found kmem:*:2:root -` +` + largeGroup() var groupTests = []struct { in string @@ -48,9 +50,20 @@ var groupTests = []struct { {testGroupFile, "invalidgid", ""}, {testGroupFile, "indented", "7"}, {testGroupFile, "# comment", ""}, + {testGroupFile, "largegroup", "1000"}, {"", "emptyfile", ""}, } +// Generate a proper "largegroup" entry for testGroupFile string +func largeGroup() (res string) { + var b strings.Builder + b.WriteString("largegroup:x:1000:user1") + for i := 2; i <= 7500; i++ { + fmt.Fprintf(&b, ",user%d", i) + } + return b.String() +} + func TestFindGroupName(t *testing.T) { for _, tt := range groupTests { got, err := findGroupName(tt.name, strings.NewReader(tt.in)) diff --git a/libgo/go/os/user/user_test.go b/libgo/go/os/user/user_test.go index 8c4c817..4992031 100644 --- a/libgo/go/os/user/user_test.go +++ b/libgo/go/os/user/user_test.go @@ -132,7 +132,7 @@ func TestGroupIds(t *testing.T) { if runtime.GOOS == "aix" { t.Skip("skipping GroupIds, see golang.org/issue/30563") } - if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" { + if runtime.GOOS == "illumos" { t.Skip("skipping GroupIds, see golang.org/issue/14709") } user, err := Current() diff --git a/libgo/go/os/wait_unimp.go b/libgo/go/os/wait_unimp.go index cb875ab..783a66f 100644 --- a/libgo/go/os/wait_unimp.go +++ b/libgo/go/os/wait_unimp.go @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build aix darwin dragonfly hurd js,wasm netbsd openbsd solaris +//go:build aix || darwin || hurd || (js && wasm) || openbsd || solaris +// +build aix darwin hurd js,wasm openbsd solaris package os diff --git a/libgo/go/os/wait_wait6.go b/libgo/go/os/wait_wait6.go index 5420b2d..45b370a 100644 --- a/libgo/go/os/wait_wait6.go +++ b/libgo/go/os/wait_wait6.go @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build freebsd +//go:build dragonfly || freebsd || netbsd +// +build dragonfly freebsd netbsd package os @@ -22,9 +23,9 @@ func (p *Process) blockUntilWaitable() (bool, error) { // The arguments on 32-bit FreeBSD look like the following: // - freebsd32_wait6_args{ idtype, id1, id2, status, options, wrusage, info } or // - freebsd32_wait6_args{ idtype, pad, id1, id2, status, options, wrusage, info } when PAD64_REQUIRED=1 on ARM, MIPS or PowerPC - if runtime.GOARCH == "386" { + if runtime.GOOS == "freebsd" && runtime.GOARCH == "386" { _, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0, 0) - } else if runtime.GOARCH == "arm" { + } else if runtime.GOOS == "freebsd" && runtime.GOARCH == "arm" { _, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, 0, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0) } else { _, _, errno = syscall.Syscall6(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0) @@ -34,7 +35,9 @@ func (p *Process) blockUntilWaitable() (bool, error) { } } runtime.KeepAlive(p) - if errno != 0 { + if errno == syscall.ENOSYS { + return false, nil + } else if errno != 0 { return false, NewSyscallError("wait6", errno) } return true, nil diff --git a/libgo/go/os/wait_waitid.go b/libgo/go/os/wait_waitid.go index 2c39f9b..d7c9751 100644 --- a/libgo/go/os/wait_waitid.go +++ b/libgo/go/os/wait_waitid.go @@ -5,6 +5,7 @@ // We used to used this code for Darwin, but according to issue #19314 // waitid returns if the process is stopped, even when using WEXITED. +//go:build linux // +build linux package os @@ -22,7 +23,7 @@ const _P_PID = 1 // It does not actually call p.Wait. func (p *Process) blockUntilWaitable() (bool, error) { // The waitid system call expects a pointer to a siginfo_t, - // which is 128 bytes on all GNU/Linux systems. + // which is 128 bytes on all Linux systems. // On darwin/amd64, it requires 104 bytes. // We don't care about the values it returns. var siginfo [16]uint64 |