diff options
Diffstat (limited to 'libgo/go/syscall')
-rw-r--r-- | libgo/go/syscall/env_plan9.go | 122 | ||||
-rw-r--r-- | libgo/go/syscall/env_unix.go | 16 | ||||
-rw-r--r-- | libgo/go/syscall/exec_bsd.go | 23 | ||||
-rw-r--r-- | libgo/go/syscall/exec_darwin.go | 23 | ||||
-rw-r--r-- | libgo/go/syscall/exec_linux.go | 47 | ||||
-rw-r--r-- | libgo/go/syscall/exec_unix.go | 20 | ||||
-rw-r--r-- | libgo/go/syscall/exec_unix_test.go | 28 | ||||
-rw-r--r-- | libgo/go/syscall/fs_js.go | 10 | ||||
-rw-r--r-- | libgo/go/syscall/js/func.go | 26 | ||||
-rw-r--r-- | libgo/go/syscall/js/js.go | 12 | ||||
-rw-r--r-- | libgo/go/syscall/js/js_test.go | 11 | ||||
-rw-r--r-- | libgo/go/syscall/security_windows.go | 2 | ||||
-rw-r--r-- | libgo/go/syscall/syscall_linux_test.go | 9 | ||||
-rw-r--r-- | libgo/go/syscall/syscall_unix.go | 16 | ||||
-rw-r--r-- | libgo/go/syscall/syscall_unix_test.go | 2 |
15 files changed, 182 insertions, 185 deletions
diff --git a/libgo/go/syscall/env_plan9.go b/libgo/go/syscall/env_plan9.go deleted file mode 100644 index e403a25..0000000 --- a/libgo/go/syscall/env_plan9.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2011 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. - -// Plan 9 environment variables. - -package syscall - -import ( - "errors" -) - -var ( - errZeroLengthKey = errors.New("zero length key") - errShortWrite = errors.New("i/o count too small") -) - -func readenv(key string) (string, error) { - fd, err := open("/env/"+key, O_RDONLY) - if err != nil { - return "", err - } - defer Close(fd) - l, _ := Seek(fd, 0, 2) - Seek(fd, 0, 0) - buf := make([]byte, l) - n, err := Read(fd, buf) - if err != nil { - return "", err - } - if n > 0 && buf[n-1] == 0 { - buf = buf[:n-1] - } - return string(buf), nil -} - -func writeenv(key, value string) error { - fd, err := create("/env/"+key, O_RDWR, 0666) - if err != nil { - return err - } - defer Close(fd) - b := []byte(value) - n, err := Write(fd, b) - if err != nil { - return err - } - if n != len(b) { - return errShortWrite - } - return nil -} - -func Getenv(key string) (value string, found bool) { - if len(key) == 0 { - return "", false - } - v, err := readenv(key) - if err != nil { - return "", false - } - return v, true -} - -func Setenv(key, value string) error { - if len(key) == 0 { - return errZeroLengthKey - } - err := writeenv(key, value) - if err != nil { - return err - } - return nil -} - -func Clearenv() { - // Creating a new environment group using rfork(RFCENVG) can race - // with access to files in /env (e.g. from Setenv or Getenv). - // Remove all environment variables in current environment group instead. - fd, err := open("/env", O_RDONLY) - if err != nil { - return - } - defer Close(fd) - files, err := readdirnames(fd) - if err != nil { - return - } - for _, key := range files { - Remove("/env/" + key) - } -} - -func Unsetenv(key string) error { - if len(key) == 0 { - return errZeroLengthKey - } - Remove("/env/" + key) - return nil -} - -func Environ() []string { - fd, err := open("/env", O_RDONLY) - if err != nil { - return nil - } - defer Close(fd) - files, err := readdirnames(fd) - if err != nil { - return nil - } - ret := make([]string, 0, len(files)) - - for _, key := range files { - v, err := readenv(key) - if err != nil { - continue - } - ret = append(ret, key+"="+v) - } - return ret -} diff --git a/libgo/go/syscall/env_unix.go b/libgo/go/syscall/env_unix.go index 3564f7f..c56b6b8 100644 --- a/libgo/go/syscall/env_unix.go +++ b/libgo/go/syscall/env_unix.go @@ -2,13 +2,16 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris +// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris plan9 // Unix environment variables. package syscall -import "sync" +import ( + "runtime" + "sync" +) var ( // envOnce guards initialization by copyenv, which populates env. @@ -100,9 +103,12 @@ func Setenv(key, value string) error { return EINVAL } } - for i := 0; i < len(value); i++ { - if value[i] == 0 { - return EINVAL + // On Plan 9, null is used as a separator, eg in $path. + if runtime.GOOS != "plan9" { + for i := 0; i < len(value); i++ { + if value[i] == 0 { + return EINVAL + } } } diff --git a/libgo/go/syscall/exec_bsd.go b/libgo/go/syscall/exec_bsd.go index a241e21..7e06943 100644 --- a/libgo/go/syscall/exec_bsd.go +++ b/libgo/go/syscall/exec_bsd.go @@ -15,12 +15,23 @@ type SysProcAttr struct { Credential *Credential // Credential. Ptrace bool // Enable tracing. Setsid bool // Create session. - Setpgid bool // Set process group ID to Pgid, or, if Pgid == 0, to new pid. - Setctty bool // Set controlling terminal to fd Ctty - Noctty bool // Detach fd 0 from controlling terminal - Ctty int // Controlling TTY fd - Foreground bool // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY) - Pgid int // Child's process group ID if Setpgid. + // Setpgid sets the process group ID of the child to Pgid, + // or, if Pgid == 0, to the new child's process ID. + Setpgid bool + // Setctty sets the controlling terminal of the child to + // file descriptor Ctty. Ctty must be a descriptor number + // in the child process: an index into ProcAttr.Files. + // This is only meaningful if Setsid is true. + Setctty bool + Noctty bool // Detach fd 0 from controlling terminal + Ctty int // Controlling TTY fd + // Foreground places the child process group in the foreground. + // This implies Setpgid. The Ctty field must be set to + // the descriptor of the controlling TTY. + // Unlike Setctty, in this case Ctty must be a descriptor + // number in the parent process. + Foreground bool + Pgid int // Child's process group ID if Setpgid. } // Implemented in runtime package. diff --git a/libgo/go/syscall/exec_darwin.go b/libgo/go/syscall/exec_darwin.go index ac1ead3..f035d55 100644 --- a/libgo/go/syscall/exec_darwin.go +++ b/libgo/go/syscall/exec_darwin.go @@ -13,12 +13,23 @@ type SysProcAttr struct { Credential *Credential // Credential. Ptrace bool // Enable tracing. Setsid bool // Create session. - Setpgid bool // Set process group ID to Pgid, or, if Pgid == 0, to new pid. - Setctty bool // Set controlling terminal to fd Ctty - Noctty bool // Detach fd 0 from controlling terminal - Ctty int // Controlling TTY fd - Foreground bool // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY) - Pgid int // Child's process group ID if Setpgid. + // Setpgid sets the process group ID of the child to Pgid, + // or, if Pgid == 0, to the new child's process ID. + Setpgid bool + // Setctty sets the controlling terminal of the child to + // file descriptor Ctty. Ctty must be a descriptor number + // in the child process: an index into ProcAttr.Files. + // This is only meaningful if Setsid is true. + Setctty bool + Noctty bool // Detach fd 0 from controlling terminal + Ctty int // Controlling TTY fd + // Foreground places the child process group in the foreground. + // This implies Setpgid. The Ctty field must be set to + // the descriptor of the controlling TTY. + // Unlike Setctty, in this case Ctty must be a descriptor + // number in the parent process. + Foreground bool + Pgid int // Child's process group ID if Setpgid. } // Implemented in runtime package. diff --git a/libgo/go/syscall/exec_linux.go b/libgo/go/syscall/exec_linux.go index f842cdc..2f0a34f 100644 --- a/libgo/go/syscall/exec_linux.go +++ b/libgo/go/syscall/exec_linux.go @@ -36,13 +36,24 @@ type SysProcAttr struct { // Ptrace tells the child to call ptrace(PTRACE_TRACEME). // Call runtime.LockOSThread before starting a process with this set, // and don't call UnlockOSThread until done with PtraceSyscall calls. - Ptrace bool - Setsid bool // Create session. - Setpgid bool // Set process group ID to Pgid, or, if Pgid == 0, to new pid. - Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set) - Noctty bool // Detach fd 0 from controlling terminal - Ctty int // Controlling TTY fd - Foreground bool // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY) + Ptrace bool + Setsid bool // Create session. + // Setpgid sets the process group ID of the child to Pgid, + // or, if Pgid == 0, to the new child's process ID. + Setpgid bool + // Setctty sets the controlling terminal of the child to + // file descriptor Ctty. Ctty must be a descriptor number + // in the child process: an index into ProcAttr.Files. + // This is only meaningful if Setsid is true. + Setctty bool + Noctty bool // Detach fd 0 from controlling terminal + Ctty int // Controlling TTY fd + // Foreground places the child process group in the foreground. + // This implies Setpgid. The Ctty field must be set to + // the descriptor of the controlling TTY. + // Unlike Setctty, in this case Ctty must be a descriptor + // number in the parent process. + Foreground bool Pgid int // Child's process group ID if Setpgid. Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only) Cloneflags uintptr // Flags for clone calls (Linux only) @@ -443,11 +454,16 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att // Pass 1: look for fd[i] < i and move those up above len(fd) // so that pass 2 won't stomp on an fd it needs later. if pipe < nextfd { - err1 = raw_dup2(pipe, nextfd) - if err1 != 0 { + err1 = raw_dup3(pipe, nextfd, O_CLOEXEC) + if err1 == ENOSYS { + err1 = raw_dup2(pipe, nextfd) + if err1 != 0 { + goto childerror + } + raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC) + } else if err1 != 0 { goto childerror } - raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC) pipe = nextfd nextfd++ } @@ -456,11 +472,16 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att if nextfd == pipe { // don't stomp on pipe nextfd++ } - err1 = raw_dup2(fd[i], nextfd) - if err1 != 0 { + err1 = raw_dup3(fd[i], nextfd, O_CLOEXEC) + if err1 == ENOSYS { + err1 = raw_dup2(fd[i], nextfd) + if err1 != 0 { + goto childerror + } + raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC) + } else if err1 != 0 { goto childerror } - raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC) fd[i] = nextfd nextfd++ } diff --git a/libgo/go/syscall/exec_unix.go b/libgo/go/syscall/exec_unix.go index e6e4ae2..7c6d942 100644 --- a/libgo/go/syscall/exec_unix.go +++ b/libgo/go/syscall/exec_unix.go @@ -9,6 +9,7 @@ package syscall import ( + errorspkg "errors" "internal/bytealg" "runtime" "sync" @@ -63,6 +64,9 @@ import ( //sysnb raw_dup2(oldfd int, newfd int) (err Errno) //dup2(oldfd _C_int, newfd _C_int) _C_int +//sysnb raw_dup3(oldfd int, newfd int, flags int) (err Errno) +//dup3(oldfd _C_int, newfd _C_int, flags _C_int) _C_int + //sysnb raw_kill(pid Pid_t, sig Signal) (err Errno) //kill(pid Pid_t, sig _C_int) _C_int @@ -241,6 +245,15 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) } } + // Both Setctty and Foreground use the Ctty field, + // but they give it slightly different meanings. + if sys.Setctty && sys.Foreground { + return 0, errorspkg.New("both Setctty and Foreground set in SysProcAttr") + } + if sys.Setctty && sys.Ctty >= len(attr.Files) { + return 0, errorspkg.New("Setctty set but Ctty not valid in child") + } + // Acquire the fork lock so that no other threads // create new fds that are not yet close-on-exec // before we fork. @@ -261,7 +274,12 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) // Read child error status from pipe. Close(p[1]) - n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1))) + for { + n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1))) + if err != EINTR { + break + } + } Close(p[0]) if err != nil || n != 0 { if n == int(unsafe.Sizeof(err1)) { diff --git a/libgo/go/syscall/exec_unix_test.go b/libgo/go/syscall/exec_unix_test.go index 3bd95bd..fab80e7 100644 --- a/libgo/go/syscall/exec_unix_test.go +++ b/libgo/go/syscall/exec_unix_test.go @@ -217,3 +217,31 @@ func TestForeground(t *testing.T) { signal.Reset() } + +// Test a couple of cases that SysProcAttr can't handle. Issue 29458. +func TestInvalidExec(t *testing.T) { + t.Parallel() + t.Run("SetCtty-Foreground", func(t *testing.T) { + t.Parallel() + cmd := create(t) + cmd.proc.SysProcAttr = &syscall.SysProcAttr{ + Setctty: true, + Foreground: true, + Ctty: 0, + } + if err := cmd.proc.Start(); err == nil { + t.Error("expected error setting both SetCtty and Foreground") + } + }) + t.Run("invalid-Ctty", func(t *testing.T) { + t.Parallel() + cmd := create(t) + cmd.proc.SysProcAttr = &syscall.SysProcAttr{ + Setctty: true, + Ctty: 3, + } + if err := cmd.proc.Start(); err == nil { + t.Error("expected error with invalid Ctty value") + } + }) +} diff --git a/libgo/go/syscall/fs_js.go b/libgo/go/syscall/fs_js.go index 16d9f58..262ec28 100644 --- a/libgo/go/syscall/fs_js.go +++ b/libgo/go/syscall/fs_js.go @@ -102,6 +102,10 @@ func Open(path string, openmode int, perm uint32) (int, error) { } } + if path[0] != '/' { + cwd := jsProcess.Call("cwd").String() + path = cwd + "/" + path + } f := &jsFile{ path: path, entries: entries, @@ -495,7 +499,7 @@ func fsCall(name string, args ...interface{}) (js.Value, error) { } c := make(chan callResult, 1) - jsFS.Call(name, append(args, js.FuncOf(func(this js.Value, args []js.Value) interface{} { + f := js.FuncOf(func(this js.Value, args []js.Value) interface{} { var res callResult if len(args) >= 1 { // on Node.js 8, fs.utimes calls the callback without any arguments @@ -511,7 +515,9 @@ func fsCall(name string, args ...interface{}) (js.Value, error) { c <- res return nil - }))...) + }) + defer f.Release() + jsFS.Call(name, append(args, f)...) res := <-c return res.val, res.err } diff --git a/libgo/go/syscall/js/func.go b/libgo/go/syscall/js/func.go index 6c145c9..da4cf68 100644 --- a/libgo/go/syscall/js/func.go +++ b/libgo/go/syscall/js/func.go @@ -22,19 +22,24 @@ type Func struct { id uint32 } -// FuncOf returns a wrapped function. +// FuncOf returns a function to be used by JavaScript. // -// Invoking the JavaScript function will synchronously call the Go function fn with the value of JavaScript's -// "this" keyword and the arguments of the invocation. -// The return value of the invocation is the result of the Go function mapped back to JavaScript according to ValueOf. +// The Go function fn is called with the value of JavaScript's "this" keyword and the +// arguments of the invocation. The return value of the invocation is +// the result of the Go function mapped back to JavaScript according to ValueOf. // -// A wrapped function triggered during a call from Go to JavaScript gets executed on the same goroutine. -// A wrapped function triggered by JavaScript's event loop gets executed on an extra goroutine. -// Blocking operations in the wrapped function will block the event loop. -// As a consequence, if one wrapped function blocks, other wrapped funcs will not be processed. -// A blocking function should therefore explicitly start a new goroutine. +// Invoking the wrapped Go function from JavaScript will +// pause the event loop and spawn a new goroutine. +// Other wrapped functions which are triggered during a call from Go to JavaScript +// get executed on the same goroutine. // -// Func.Release must be called to free up resources when the function will not be used any more. +// As a consequence, if one wrapped function blocks, JavaScript's event loop +// is blocked until that function returns. Hence, calling any async JavaScript +// API, which requires the event loop, like fetch (http.Client), will cause an +// immediate deadlock. Therefore a blocking function should explicitly start a +// new goroutine. +// +// Func.Release must be called to free up resources when the function will not be invoked any more. func FuncOf(fn func(this Value, args []Value) interface{}) Func { funcsMu.Lock() id := nextFuncID @@ -49,6 +54,7 @@ func FuncOf(fn func(this Value, args []Value) interface{}) Func { // Release frees up resources allocated for the function. // The function must not be invoked after calling Release. +// It is allowed to call Release while the function is still running. func (c Func) Release() { funcsMu.Lock() delete(funcs, c.id) diff --git a/libgo/go/syscall/js/js.go b/libgo/go/syscall/js/js.go index 8a04399..a48bbd4 100644 --- a/libgo/go/syscall/js/js.go +++ b/libgo/go/syscall/js/js.go @@ -565,28 +565,28 @@ func (e *ValueError) Error() string { return "syscall/js: call of " + e.Method + " on " + e.Type.String() } -// CopyBytesToGo copies bytes from the Uint8Array src to dst. +// CopyBytesToGo copies bytes from src to dst. +// It panics if src is not an Uint8Array or Uint8ClampedArray. // It returns the number of bytes copied, which will be the minimum of the lengths of src and dst. -// CopyBytesToGo panics if src is not an Uint8Array. func CopyBytesToGo(dst []byte, src Value) int { n, ok := copyBytesToGo(dst, src.ref) runtime.KeepAlive(src) if !ok { - panic("syscall/js: CopyBytesToGo: expected src to be an Uint8Array") + panic("syscall/js: CopyBytesToGo: expected src to be an Uint8Array or Uint8ClampedArray") } return n } func copyBytesToGo(dst []byte, src ref) (int, bool) -// CopyBytesToJS copies bytes from src to the Uint8Array dst. +// CopyBytesToJS copies bytes from src to dst. +// It panics if dst is not an Uint8Array or Uint8ClampedArray. // It returns the number of bytes copied, which will be the minimum of the lengths of src and dst. -// CopyBytesToJS panics if dst is not an Uint8Array. func CopyBytesToJS(dst Value, src []byte) int { n, ok := copyBytesToJS(dst.ref, src) runtime.KeepAlive(dst) if !ok { - panic("syscall/js: CopyBytesToJS: expected dst to be an Uint8Array") + panic("syscall/js: CopyBytesToJS: expected dst to be an Uint8Array or Uint8ClampedArray") } return n } diff --git a/libgo/go/syscall/js/js_test.go b/libgo/go/syscall/js/js_test.go index fea4c13..5fc9107 100644 --- a/libgo/go/syscall/js/js_test.go +++ b/libgo/go/syscall/js/js_test.go @@ -591,3 +591,14 @@ func BenchmarkDOM(b *testing.B) { document.Get("body").Call("removeChild", div) } } + +func TestGlobal(t *testing.T) { + ident := js.FuncOf(func(this js.Value, args []js.Value) interface{} { + return args[0] + }) + defer ident.Release() + + if got := ident.Invoke(js.Global()); !got.Equal(js.Global()) { + t.Errorf("got %#v, want %#v", got, js.Global()) + } +} diff --git a/libgo/go/syscall/security_windows.go b/libgo/go/syscall/security_windows.go index 3a75759..67102b6 100644 --- a/libgo/go/syscall/security_windows.go +++ b/libgo/go/syscall/security_windows.go @@ -163,7 +163,7 @@ func (sid *SID) String() (string, error) { return "", e } defer LocalFree((Handle)(unsafe.Pointer(s))) - return utf16PtrToString(s, 256), nil + return utf16PtrToString(s), nil } // Len returns the length, in bytes, of a valid security identifier sid. diff --git a/libgo/go/syscall/syscall_linux_test.go b/libgo/go/syscall/syscall_linux_test.go index 97059c8..c12df4c 100644 --- a/libgo/go/syscall/syscall_linux_test.go +++ b/libgo/go/syscall/syscall_linux_test.go @@ -187,7 +187,7 @@ func TestLinuxDeathSignal(t *testing.T) { } cmd := exec.Command(tmpBinary) - cmd.Env = []string{"GO_DEATHSIG_PARENT=1"} + cmd.Env = append(os.Environ(), "GO_DEATHSIG_PARENT=1") chldStdin, err := cmd.StdinPipe() if err != nil { t.Fatalf("failed to create new stdin pipe: %v", err) @@ -225,7 +225,10 @@ func TestLinuxDeathSignal(t *testing.T) { func deathSignalParent() { cmd := exec.Command(os.Args[0]) - cmd.Env = []string{"GO_DEATHSIG_CHILD=1"} + cmd.Env = append(os.Environ(), + "GO_DEATHSIG_PARENT=", + "GO_DEATHSIG_CHILD=1", + ) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout attrs := syscall.SysProcAttr{ @@ -360,7 +363,7 @@ func TestSyscallNoError(t *testing.T) { } cmd := exec.Command(tmpBinary) - cmd.Env = []string{"GO_SYSCALL_NOERROR=1"} + cmd.Env = append(os.Environ(), "GO_SYSCALL_NOERROR=1") out, err := cmd.CombinedOutput() if err != nil { diff --git a/libgo/go/syscall/syscall_unix.go b/libgo/go/syscall/syscall_unix.go index 16e4d480..4d963fb 100644 --- a/libgo/go/syscall/syscall_unix.go +++ b/libgo/go/syscall/syscall_unix.go @@ -8,6 +8,7 @@ package syscall import ( "internal/race" + "internal/unsafeheader" "runtime" "sync" "unsafe" @@ -55,15 +56,12 @@ func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (d return nil, errno } - // Slice memory layout - var sl = struct { - addr uintptr - len int - cap int - }{addr, length, length} - - // Use unsafe to turn sl into a []byte. - b := *(*[]byte)(unsafe.Pointer(&sl)) + // Use unsafe to turn addr into a []byte. + var b []byte + hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b)) + hdr.Data = unsafe.Pointer(addr) + hdr.Cap = length + hdr.Len = length // Register mapping in m and return it. p := &b[cap(b)-1] diff --git a/libgo/go/syscall/syscall_unix_test.go b/libgo/go/syscall/syscall_unix_test.go index b99e07d..a6b70d4 100644 --- a/libgo/go/syscall/syscall_unix_test.go +++ b/libgo/go/syscall/syscall_unix_test.go @@ -72,7 +72,7 @@ func _() { // Thus this test also verifies that the Flock_t structure can be // roundtripped with F_SETLK and F_GETLK. func TestFcntlFlock(t *testing.T) { - if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { t.Skip("skipping; no child processes allowed on iOS") } flock := syscall.Flock_t{ |