aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/syscall
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2020-01-02 15:05:27 -0800
committerIan Lance Taylor <iant@golang.org>2020-01-21 23:53:22 -0800
commit5a8ea165926cb0737ab03bc48c18dc5198ab5305 (patch)
tree962dc3357c57f019f85658f99e2e753e30201c27 /libgo/go/syscall
parent6ac6529e155c9baa0aaaed7aca06bd38ebda5b43 (diff)
downloadgcc-5a8ea165926cb0737ab03bc48c18dc5198ab5305.zip
gcc-5a8ea165926cb0737ab03bc48c18dc5198ab5305.tar.gz
gcc-5a8ea165926cb0737ab03bc48c18dc5198ab5305.tar.bz2
libgo: update to Go1.14beta1
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/214297
Diffstat (limited to 'libgo/go/syscall')
-rw-r--r--libgo/go/syscall/dirent.go2
-rw-r--r--libgo/go/syscall/dirent_test.go (renamed from libgo/go/syscall/dirent_bsd_test.go)2
-rw-r--r--libgo/go/syscall/env_plan9.go16
-rw-r--r--libgo/go/syscall/env_unix.go2
-rw-r--r--libgo/go/syscall/exec_linux_test.go56
-rw-r--r--libgo/go/syscall/fs_js.go20
-rw-r--r--libgo/go/syscall/getdirentries_test.go6
-rw-r--r--libgo/go/syscall/js/export_test.go9
-rw-r--r--libgo/go/syscall/js/func.go2
-rw-r--r--libgo/go/syscall/js/js.go164
-rw-r--r--libgo/go/syscall/js/js_test.go143
-rw-r--r--libgo/go/syscall/lsf_linux.go4
-rw-r--r--libgo/go/syscall/net_js.go2
-rw-r--r--libgo/go/syscall/netlink_linux.go2
-rw-r--r--libgo/go/syscall/route_freebsd_64bit.go2
-rw-r--r--libgo/go/syscall/security_windows.go2
-rw-r--r--libgo/go/syscall/sock_cloexec_linux.go29
-rw-r--r--libgo/go/syscall/sockcmsg_dragonfly.go16
-rw-r--r--libgo/go/syscall/sockcmsg_linux.go2
-rw-r--r--libgo/go/syscall/sockcmsg_unix.go36
-rw-r--r--libgo/go/syscall/sockcmsg_unix_other.go38
-rw-r--r--libgo/go/syscall/syscall.go2
-rw-r--r--libgo/go/syscall/syscall_aix.go6
-rw-r--r--libgo/go/syscall/syscall_dragonfly.go20
-rw-r--r--libgo/go/syscall/syscall_errno.go8
-rw-r--r--libgo/go/syscall/syscall_freebsd_arm64.go33
-rw-r--r--libgo/go/syscall/syscall_js.go11
-rw-r--r--libgo/go/syscall/syscall_linux_riscv64.go23
-rw-r--r--libgo/go/syscall/syscall_linux_test.go11
-rw-r--r--libgo/go/syscall/syscall_test.go2
-rw-r--r--libgo/go/syscall/syscall_unix.go9
-rw-r--r--libgo/go/syscall/syscall_unix_test.go6
-rw-r--r--libgo/go/syscall/tables_js.go (renamed from libgo/go/syscall/tables_nacljs.go)8
-rw-r--r--libgo/go/syscall/time_fake.go26
-rw-r--r--libgo/go/syscall/time_nofake.go14
-rw-r--r--libgo/go/syscall/timestruct.go6
36 files changed, 589 insertions, 151 deletions
diff --git a/libgo/go/syscall/dirent.go b/libgo/go/syscall/dirent.go
index 58c34c3..5726449 100644
--- a/libgo/go/syscall/dirent.go
+++ b/libgo/go/syscall/dirent.go
@@ -2,7 +2,7 @@
// 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 nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris
package syscall
diff --git a/libgo/go/syscall/dirent_bsd_test.go b/libgo/go/syscall/dirent_test.go
index 43b667b..f631533 100644
--- a/libgo/go/syscall/dirent_bsd_test.go
+++ b/libgo/go/syscall/dirent_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package syscall_test
diff --git a/libgo/go/syscall/env_plan9.go b/libgo/go/syscall/env_plan9.go
index 9a8a837..e403a25 100644
--- a/libgo/go/syscall/env_plan9.go
+++ b/libgo/go/syscall/env_plan9.go
@@ -74,7 +74,21 @@ func Setenv(key, value string) error {
}
func Clearenv() {
- RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
+ // 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 {
diff --git a/libgo/go/syscall/env_unix.go b/libgo/go/syscall/env_unix.go
index c22af18..3564f7f 100644
--- a/libgo/go/syscall/env_unix.go
+++ b/libgo/go/syscall/env_unix.go
@@ -2,7 +2,7 @@
// 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 nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris
// Unix environment variables.
diff --git a/libgo/go/syscall/exec_linux_test.go b/libgo/go/syscall/exec_linux_test.go
index 7bd3910..1a44f04 100644
--- a/libgo/go/syscall/exec_linux_test.go
+++ b/libgo/go/syscall/exec_linux_test.go
@@ -34,6 +34,14 @@ func isLXC() bool {
}
func skipInContainer(t *testing.T) {
+ // TODO: the callers of this func are using this func to skip
+ // tests when running as some sort of "fake root" that's uid 0
+ // but lacks certain Linux capabilities. Most of the Go builds
+ // run in privileged containers, though, where root is much
+ // closer (if not identical) to the real root. We should test
+ // for what we need exactly (which capabilities are active?),
+ // instead of just assuming "docker == bad". Then we'd get more test
+ // coverage on a bunch of builders too.
if isDocker() {
t.Skip("skip this test in Docker container")
}
@@ -42,6 +50,18 @@ func skipInContainer(t *testing.T) {
}
}
+func skipNoUserNamespaces(t *testing.T) {
+ if _, err := os.Stat("/proc/self/ns/user"); err != nil {
+ if os.IsNotExist(err) {
+ t.Skip("kernel doesn't support user namespaces")
+ }
+ if os.IsPermission(err) {
+ t.Skip("unable to test user namespaces due to permissions")
+ }
+ t.Fatalf("Failed to stat /proc/self/ns/user: %v", err)
+ }
+}
+
func skipUnprivilegedUserClone(t *testing.T) {
// Skip the test if the sysctl that prevents unprivileged user
// from creating user namespaces is enabled.
@@ -64,15 +84,7 @@ func isChrooted(t *testing.T) bool {
func checkUserNS(t *testing.T) {
skipInContainer(t)
- if _, err := os.Stat("/proc/self/ns/user"); err != nil {
- if os.IsNotExist(err) {
- t.Skip("kernel doesn't support user namespaces")
- }
- if os.IsPermission(err) {
- t.Skip("unable to test user namespaces due to permissions")
- }
- t.Fatalf("Failed to stat /proc/self/ns/user: %v", err)
- }
+ skipNoUserNamespaces(t)
if isChrooted(t) {
// create_user_ns in the kernel (see
// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/user_namespace.c)
@@ -305,6 +317,7 @@ func TestGroupCleanupUserNamespace(t *testing.T) {
"uid=0(root) gid=0(root) groups=0(root),65534(nogroup)",
"uid=0(root) gid=0(root) groups=0(root),65534",
"uid=0(root) gid=0(root) groups=0(root),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody)", // Alpine; see https://golang.org/issue/19938
+ "uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023", // CentOS with SELinux context, see https://golang.org/issue/34547
}
for _, e := range expected {
if strOut == e {
@@ -336,14 +349,6 @@ func TestUnshareMountNameSpace(t *testing.T) {
t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
}
- // When running under the Go continuous build, skip tests for
- // now when under Kubernetes. (where things are root but not quite)
- // Both of these are our own environment variables.
- // See Issue 12815.
- if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
- t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
- }
-
d, err := ioutil.TempDir("", "unshare")
if err != nil {
t.Fatalf("tempdir: %v", err)
@@ -386,14 +391,6 @@ func TestUnshareMountNameSpaceChroot(t *testing.T) {
t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
}
- // When running under the Go continuous build, skip tests for
- // now when under Kubernetes. (where things are root but not quite)
- // Both of these are our own environment variables.
- // See Issue 12815.
- if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
- t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
- }
-
d, err := ioutil.TempDir("", "unshare")
if err != nil {
t.Fatalf("tempdir: %v", err)
@@ -573,6 +570,7 @@ func TestAmbientCaps(t *testing.T) {
}
func TestAmbientCapsUserns(t *testing.T) {
+ checkUserNS(t)
testAmbientCaps(t, true)
}
@@ -580,14 +578,6 @@ func testAmbientCaps(t *testing.T, userns bool) {
skipInContainer(t)
mustSupportAmbientCaps(t)
- // When running under the Go continuous build, skip tests for
- // now when under Kubernetes. (where things are root but not quite)
- // Both of these are our own environment variables.
- // See Issue 12815.
- if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
- t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
- }
-
skipUnprivilegedUserClone(t)
// skip on android, due to lack of lookup support
diff --git a/libgo/go/syscall/fs_js.go b/libgo/go/syscall/fs_js.go
index 1b835c5..16d9f58 100644
--- a/libgo/go/syscall/fs_js.go
+++ b/libgo/go/syscall/fs_js.go
@@ -34,6 +34,7 @@ var (
type jsFile struct {
path string
entries []string
+ dirIdx int // entries[:dirIdx] have already been returned in ReadDirent
pos int64
seeked bool
}
@@ -141,8 +142,8 @@ func ReadDirent(fd int, buf []byte) (int, error) {
}
n := 0
- for len(f.entries) > 0 {
- entry := f.entries[0]
+ for f.dirIdx < len(f.entries) {
+ entry := f.entries[f.dirIdx]
l := 2 + len(entry)
if l > len(buf) {
break
@@ -152,7 +153,7 @@ func ReadDirent(fd int, buf []byte) (int, error) {
copy(buf[2:], entry)
buf = buf[l:]
n += l
- f.entries = f.entries[1:]
+ f.dirIdx++
}
return n, nil
@@ -259,7 +260,7 @@ func Lchown(path string, uid, gid int) error {
if err := checkPath(path); err != nil {
return err
}
- if jsFS.Get("lchown") == js.Undefined() {
+ if jsFS.Get("lchown").IsUndefined() {
// fs.lchown is unavailable on Linux until Node.js 10.6.0
// TODO(neelance): remove when we require at least this Node.js version
return ENOSYS
@@ -404,6 +405,14 @@ func Write(fd int, b []byte) (int, error) {
return n, err
}
+ if faketime && (fd == 1 || fd == 2) {
+ n := faketimeWrite(fd, b)
+ if n < 0 {
+ return 0, errnoErr(Errno(-n))
+ }
+ return n, nil
+ }
+
buf := uint8Array.New(len(b))
js.CopyBytesToJS(buf, b)
n, err := fsCall("write", fd, buf, 0, len(b), nil)
@@ -462,6 +471,7 @@ func Seek(fd int, offset int64, whence int) (int64, error) {
}
f.seeked = true
+ f.dirIdx = 0 // Reset directory read position. See issue 35767.
f.pos = newPos
return newPos, nil
}
@@ -489,7 +499,7 @@ func fsCall(name string, args ...interface{}) (js.Value, error) {
var res callResult
if len(args) >= 1 { // on Node.js 8, fs.utimes calls the callback without any arguments
- if jsErr := args[0]; jsErr != js.Null() {
+ if jsErr := args[0]; !jsErr.IsNull() {
res.err = mapJSError(jsErr)
}
}
diff --git a/libgo/go/syscall/getdirentries_test.go b/libgo/go/syscall/getdirentries_test.go
index 8505a0b..2a3419c 100644
--- a/libgo/go/syscall/getdirentries_test.go
+++ b/libgo/go/syscall/getdirentries_test.go
@@ -66,7 +66,11 @@ func testGetdirentries(t *testing.T, count int) {
}
data := buf[:n]
for len(data) > 0 {
- dirent := (*syscall.Dirent)(unsafe.Pointer(&data[0]))
+ // If multiple Dirents are written into buf, sometimes when we reach the final one,
+ // we have cap(buf) < Sizeof(Dirent). So use an appropriate slice to copy from data.
+ var dirent syscall.Dirent
+ copy((*[unsafe.Sizeof(dirent)]byte)(unsafe.Pointer(&dirent))[:], data)
+
data = data[dirent.Reclen:]
name := make([]byte, dirent.Namlen)
for i := 0; i < int(dirent.Namlen); i++ {
diff --git a/libgo/go/syscall/js/export_test.go b/libgo/go/syscall/js/export_test.go
new file mode 100644
index 0000000..1b5ed3c
--- /dev/null
+++ b/libgo/go/syscall/js/export_test.go
@@ -0,0 +1,9 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build js,wasm
+
+package js
+
+var JSGo = jsGo
diff --git a/libgo/go/syscall/js/func.go b/libgo/go/syscall/js/func.go
index 6b7f39b..6c145c9 100644
--- a/libgo/go/syscall/js/func.go
+++ b/libgo/go/syscall/js/func.go
@@ -64,7 +64,7 @@ func init() {
func handleEvent() {
cb := jsGo.Get("_pendingEvent")
- if cb == Null() {
+ if cb.IsNull() {
return
}
jsGo.Set("_pendingEvent", Null())
diff --git a/libgo/go/syscall/js/js.go b/libgo/go/syscall/js/js.go
index 7300d2c..8a04399 100644
--- a/libgo/go/syscall/js/js.go
+++ b/libgo/go/syscall/js/js.go
@@ -12,6 +12,7 @@
package js
import (
+ "runtime"
"unsafe"
)
@@ -20,7 +21,7 @@ import (
// The JavaScript value "undefined" is represented by the value 0.
// A JavaScript number (64-bit float, except 0 and NaN) is represented by its IEEE 754 binary representation.
// All other values are represented as an IEEE 754 binary representation of NaN with bits 0-31 used as
-// an ID and bits 32-33 used to differentiate between string, symbol, function and object.
+// an ID and bits 32-34 used to differentiate between string, symbol, function and object.
type ref uint64
// nanHead are the upper 32 bits of a ref which are set if the value is not encoded as an IEEE 754 number (see above).
@@ -33,21 +34,45 @@ type Wrapper interface {
}
// Value represents a JavaScript value. The zero value is the JavaScript value "undefined".
+// Values can be checked for equality with the Equal method.
type Value struct {
- ref ref
+ _ [0]func() // uncomparable; to make == not compile
+ ref ref // identifies a JavaScript value, see ref type
+ gcPtr *ref // used to trigger the finalizer when the Value is not referenced any more
}
+const (
+ // the type flags need to be in sync with wasm_exec.js
+ typeFlagNone = iota
+ typeFlagObject
+ typeFlagString
+ typeFlagSymbol
+ typeFlagFunction
+)
+
// JSValue implements Wrapper interface.
func (v Value) JSValue() Value {
return v
}
-func makeValue(v ref) Value {
- return Value{ref: v}
+func makeValue(r ref) Value {
+ var gcPtr *ref
+ typeFlag := (r >> 32) & 7
+ if (r>>32)&nanHead == nanHead && typeFlag != typeFlagNone {
+ gcPtr = new(ref)
+ *gcPtr = r
+ runtime.SetFinalizer(gcPtr, func(p *ref) {
+ finalizeRef(*p)
+ })
+ }
+
+ return Value{ref: r, gcPtr: gcPtr}
}
-func predefValue(id uint32) Value {
- return Value{ref: nanHead<<32 | ref(id)}
+func finalizeRef(r ref)
+
+func predefValue(id uint32, typeFlag byte) Value {
+ return Value{ref: (nanHead|ref(typeFlag))<<32 | ref(id)}
}
func floatValue(f float64) Value {
@@ -73,28 +98,48 @@ func (e Error) Error() string {
var (
valueUndefined = Value{ref: 0}
- valueNaN = predefValue(0)
- valueZero = predefValue(1)
- valueNull = predefValue(2)
- valueTrue = predefValue(3)
- valueFalse = predefValue(4)
- valueGlobal = predefValue(5)
- jsGo = predefValue(6) // instance of the Go class in JavaScript
+ valueNaN = predefValue(0, typeFlagNone)
+ valueZero = predefValue(1, typeFlagNone)
+ valueNull = predefValue(2, typeFlagNone)
+ valueTrue = predefValue(3, typeFlagNone)
+ valueFalse = predefValue(4, typeFlagNone)
+ valueGlobal = predefValue(5, typeFlagObject)
+ jsGo = predefValue(6, typeFlagObject) // instance of the Go class in JavaScript
objectConstructor = valueGlobal.Get("Object")
arrayConstructor = valueGlobal.Get("Array")
)
+// Equal reports whether v and w are equal according to JavaScript's === operator.
+func (v Value) Equal(w Value) bool {
+ return v.ref == w.ref && v.ref != valueNaN.ref
+}
+
// Undefined returns the JavaScript value "undefined".
func Undefined() Value {
return valueUndefined
}
+// IsUndefined reports whether v is the JavaScript value "undefined".
+func (v Value) IsUndefined() bool {
+ return v.ref == valueUndefined.ref
+}
+
// Null returns the JavaScript value "null".
func Null() Value {
return valueNull
}
+// IsNull reports whether v is the JavaScript value "null".
+func (v Value) IsNull() bool {
+ return v.ref == valueNull.ref
+}
+
+// IsNaN reports whether v is the JavaScript value "NaN".
+func (v Value) IsNaN() bool {
+ return v.ref == valueNaN.ref
+}
+
// Global returns the JavaScript global object, usually "window" or "global".
func Global() Value {
return valueGlobal
@@ -232,16 +277,18 @@ func (v Value) Type() Type {
if v.isNumber() {
return TypeNumber
}
- typeFlag := v.ref >> 32 & 3
+ typeFlag := (v.ref >> 32) & 7
switch typeFlag {
- case 1:
+ case typeFlagObject:
+ return TypeObject
+ case typeFlagString:
return TypeString
- case 2:
+ case typeFlagSymbol:
return TypeSymbol
- case 3:
+ case typeFlagFunction:
return TypeFunction
default:
- return TypeObject
+ panic("bad type flag")
}
}
@@ -251,7 +298,9 @@ func (v Value) Get(p string) Value {
if vType := v.Type(); !vType.isObject() {
panic(&ValueError{"Value.Get", vType})
}
- return makeValue(valueGet(v.ref, p))
+ r := makeValue(valueGet(v.ref, p))
+ runtime.KeepAlive(v)
+ return r
}
func valueGet(v ref, p string) ref
@@ -262,18 +311,35 @@ func (v Value) Set(p string, x interface{}) {
if vType := v.Type(); !vType.isObject() {
panic(&ValueError{"Value.Set", vType})
}
- valueSet(v.ref, p, ValueOf(x).ref)
+ xv := ValueOf(x)
+ valueSet(v.ref, p, xv.ref)
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(xv)
}
func valueSet(v ref, p string, x ref)
+// Delete deletes the JavaScript property p of value v.
+// It panics if v is not a JavaScript object.
+func (v Value) Delete(p string) {
+ if vType := v.Type(); !vType.isObject() {
+ panic(&ValueError{"Value.Delete", vType})
+ }
+ valueDelete(v.ref, p)
+ runtime.KeepAlive(v)
+}
+
+func valueDelete(v ref, p string)
+
// Index returns JavaScript index i of value v.
// It panics if v is not a JavaScript object.
func (v Value) Index(i int) Value {
if vType := v.Type(); !vType.isObject() {
panic(&ValueError{"Value.Index", vType})
}
- return makeValue(valueIndex(v.ref, i))
+ r := makeValue(valueIndex(v.ref, i))
+ runtime.KeepAlive(v)
+ return r
}
func valueIndex(v ref, i int) ref
@@ -284,17 +350,23 @@ func (v Value) SetIndex(i int, x interface{}) {
if vType := v.Type(); !vType.isObject() {
panic(&ValueError{"Value.SetIndex", vType})
}
- valueSetIndex(v.ref, i, ValueOf(x).ref)
+ xv := ValueOf(x)
+ valueSetIndex(v.ref, i, xv.ref)
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(xv)
}
func valueSetIndex(v ref, i int, x ref)
-func makeArgs(args []interface{}) []ref {
- argVals := make([]ref, len(args))
+func makeArgs(args []interface{}) ([]Value, []ref) {
+ argVals := make([]Value, len(args))
+ argRefs := make([]ref, len(args))
for i, arg := range args {
- argVals[i] = ValueOf(arg).ref
+ v := ValueOf(arg)
+ argVals[i] = v
+ argRefs[i] = v.ref
}
- return argVals
+ return argVals, argRefs
}
// Length returns the JavaScript property "length" of v.
@@ -303,7 +375,9 @@ func (v Value) Length() int {
if vType := v.Type(); !vType.isObject() {
panic(&ValueError{"Value.SetIndex", vType})
}
- return valueLength(v.ref)
+ r := valueLength(v.ref)
+ runtime.KeepAlive(v)
+ return r
}
func valueLength(v ref) int
@@ -312,7 +386,10 @@ func valueLength(v ref) int
// It panics if v has no method m.
// The arguments get mapped to JavaScript values according to the ValueOf function.
func (v Value) Call(m string, args ...interface{}) Value {
- res, ok := valueCall(v.ref, m, makeArgs(args))
+ argVals, argRefs := makeArgs(args)
+ res, ok := valueCall(v.ref, m, argRefs)
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(argVals)
if !ok {
if vType := v.Type(); !vType.isObject() { // check here to avoid overhead in success case
panic(&ValueError{"Value.Call", vType})
@@ -331,7 +408,10 @@ func valueCall(v ref, m string, args []ref) (ref, bool)
// It panics if v is not a JavaScript function.
// The arguments get mapped to JavaScript values according to the ValueOf function.
func (v Value) Invoke(args ...interface{}) Value {
- res, ok := valueInvoke(v.ref, makeArgs(args))
+ argVals, argRefs := makeArgs(args)
+ res, ok := valueInvoke(v.ref, argRefs)
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(argVals)
if !ok {
if vType := v.Type(); vType != TypeFunction { // check here to avoid overhead in success case
panic(&ValueError{"Value.Invoke", vType})
@@ -347,7 +427,10 @@ func valueInvoke(v ref, args []ref) (ref, bool)
// It panics if v is not a JavaScript function.
// The arguments get mapped to JavaScript values according to the ValueOf function.
func (v Value) New(args ...interface{}) Value {
- res, ok := valueNew(v.ref, makeArgs(args))
+ argVals, argRefs := makeArgs(args)
+ res, ok := valueNew(v.ref, argRefs)
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(argVals)
if !ok {
if vType := v.Type(); vType != TypeFunction { // check here to avoid overhead in success case
panic(&ValueError{"Value.Invoke", vType})
@@ -362,7 +445,7 @@ func valueNew(v ref, args []ref) (ref, bool)
func (v Value) isNumber() bool {
return v.ref == valueZero.ref ||
v.ref == valueNaN.ref ||
- (v.ref != valueUndefined.ref && v.ref>>32&nanHead != nanHead)
+ (v.ref != valueUndefined.ref && (v.ref>>32)&nanHead != nanHead)
}
func (v Value) float(method string) float64 {
@@ -427,15 +510,15 @@ func (v Value) Truthy() bool {
func (v Value) String() string {
switch v.Type() {
case TypeString:
- return jsString(v.ref)
+ return jsString(v)
case TypeUndefined:
return "<undefined>"
case TypeNull:
return "<null>"
case TypeBoolean:
- return "<boolean: " + jsString(v.ref) + ">"
+ return "<boolean: " + jsString(v) + ">"
case TypeNumber:
- return "<number: " + jsString(v.ref) + ">"
+ return "<number: " + jsString(v) + ">"
case TypeSymbol:
return "<symbol>"
case TypeObject:
@@ -447,10 +530,12 @@ func (v Value) String() string {
}
}
-func jsString(v ref) string {
- str, length := valuePrepareString(v)
+func jsString(v Value) string {
+ str, length := valuePrepareString(v.ref)
+ runtime.KeepAlive(v)
b := make([]byte, length)
valueLoadString(str, b)
+ finalizeRef(str)
return string(b)
}
@@ -460,7 +545,10 @@ func valueLoadString(v ref, b []byte)
// InstanceOf reports whether v is an instance of type t according to JavaScript's instanceof operator.
func (v Value) InstanceOf(t Value) bool {
- return valueInstanceOf(v.ref, t.ref)
+ r := valueInstanceOf(v.ref, t.ref)
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(t)
+ return r
}
func valueInstanceOf(v ref, t ref) bool
@@ -482,6 +570,7 @@ func (e *ValueError) Error() string {
// 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")
}
@@ -495,6 +584,7 @@ func copyBytesToGo(dst []byte, src ref) (int, bool)
// 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")
}
diff --git a/libgo/go/syscall/js/js_test.go b/libgo/go/syscall/js/js_test.go
index 7a1e346..fea4c13 100644
--- a/libgo/go/syscall/js/js_test.go
+++ b/libgo/go/syscall/js/js_test.go
@@ -18,6 +18,7 @@ package js_test
import (
"fmt"
"math"
+ "runtime"
"syscall/js"
"testing"
)
@@ -53,7 +54,7 @@ func TestBool(t *testing.T) {
if got := dummys.Get("otherBool").Bool(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
- if dummys.Get("someBool") != dummys.Get("someBool") {
+ if !dummys.Get("someBool").Equal(dummys.Get("someBool")) {
t.Errorf("same value not equal")
}
}
@@ -68,7 +69,7 @@ func TestString(t *testing.T) {
if got := dummys.Get("otherString").String(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
- if dummys.Get("someString") != dummys.Get("someString") {
+ if !dummys.Get("someString").Equal(dummys.Get("someString")) {
t.Errorf("same value not equal")
}
@@ -105,7 +106,7 @@ func TestInt(t *testing.T) {
if got := dummys.Get("otherInt").Int(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
- if dummys.Get("someInt") != dummys.Get("someInt") {
+ if !dummys.Get("someInt").Equal(dummys.Get("someInt")) {
t.Errorf("same value not equal")
}
if got := dummys.Get("zero").Int(); got != 0 {
@@ -141,20 +142,20 @@ func TestFloat(t *testing.T) {
if got := dummys.Get("otherFloat").Float(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
- if dummys.Get("someFloat") != dummys.Get("someFloat") {
+ if !dummys.Get("someFloat").Equal(dummys.Get("someFloat")) {
t.Errorf("same value not equal")
}
}
func TestObject(t *testing.T) {
- if dummys.Get("someArray") != dummys.Get("someArray") {
+ if !dummys.Get("someArray").Equal(dummys.Get("someArray")) {
t.Errorf("same value not equal")
}
// An object and its prototype should not be equal.
proto := js.Global().Get("Object").Get("prototype")
o := js.Global().Call("eval", "new Object()")
- if proto == o {
+ if proto.Equal(o) {
t.Errorf("object equals to its prototype")
}
}
@@ -167,26 +168,66 @@ func TestFrozenObject(t *testing.T) {
}
}
+func TestEqual(t *testing.T) {
+ if !dummys.Get("someFloat").Equal(dummys.Get("someFloat")) {
+ t.Errorf("same float is not equal")
+ }
+ if !dummys.Get("emptyObj").Equal(dummys.Get("emptyObj")) {
+ t.Errorf("same object is not equal")
+ }
+ if dummys.Get("someFloat").Equal(dummys.Get("someInt")) {
+ t.Errorf("different values are not unequal")
+ }
+}
+
func TestNaN(t *testing.T) {
- want := js.ValueOf(math.NaN())
- got := dummys.Get("NaN")
- if got != want {
- t.Errorf("got %#v, want %#v", got, want)
+ if !dummys.Get("NaN").IsNaN() {
+ t.Errorf("JS NaN is not NaN")
+ }
+ if !js.ValueOf(math.NaN()).IsNaN() {
+ t.Errorf("Go NaN is not NaN")
+ }
+ if dummys.Get("NaN").Equal(dummys.Get("NaN")) {
+ t.Errorf("NaN is equal to NaN")
}
}
func TestUndefined(t *testing.T) {
- dummys.Set("test", js.Undefined())
- if dummys == js.Undefined() || dummys.Get("test") != js.Undefined() || dummys.Get("xyz") != js.Undefined() {
- t.Errorf("js.Undefined expected")
+ if !js.Undefined().IsUndefined() {
+ t.Errorf("undefined is not undefined")
+ }
+ if !js.Undefined().Equal(js.Undefined()) {
+ t.Errorf("undefined is not equal to undefined")
+ }
+ if dummys.IsUndefined() {
+ t.Errorf("object is undefined")
+ }
+ if js.Undefined().IsNull() {
+ t.Errorf("undefined is null")
+ }
+ if dummys.Set("test", js.Undefined()); !dummys.Get("test").IsUndefined() {
+ t.Errorf("could not set undefined")
}
}
func TestNull(t *testing.T) {
- dummys.Set("test1", nil)
- dummys.Set("test2", js.Null())
- if dummys == js.Null() || dummys.Get("test1") != js.Null() || dummys.Get("test2") != js.Null() {
- t.Errorf("js.Null expected")
+ if !js.Null().IsNull() {
+ t.Errorf("null is not null")
+ }
+ if !js.Null().Equal(js.Null()) {
+ t.Errorf("null is not equal to null")
+ }
+ if dummys.IsNull() {
+ t.Errorf("object is null")
+ }
+ if js.Null().IsUndefined() {
+ t.Errorf("null is undefined")
+ }
+ if dummys.Set("test", js.Null()); !dummys.Get("test").IsNull() {
+ t.Errorf("could not set null")
+ }
+ if dummys.Set("test", nil); !dummys.Get("test").IsNull() {
+ t.Errorf("could not set nil")
}
}
@@ -212,6 +253,18 @@ func TestSet(t *testing.T) {
})
}
+func TestDelete(t *testing.T) {
+ dummys.Set("test", 42)
+ dummys.Delete("test")
+ if dummys.Call("hasOwnProperty", "test").Bool() {
+ t.Errorf("property still exists")
+ }
+
+ expectValueError(t, func() {
+ dummys.Get("zero").Delete("badField")
+ })
+}
+
func TestIndex(t *testing.T) {
if got := dummys.Get("someArray").Index(1).Int(); got != 42 {
t.Errorf("got %#v, want %#v", got, 42)
@@ -328,7 +381,7 @@ func TestValueOf(t *testing.T) {
func TestZeroValue(t *testing.T) {
var v js.Value
- if v != js.Undefined() {
+ if !v.IsUndefined() {
t.Error("zero js.Value is not js.Undefined()")
}
}
@@ -366,6 +419,25 @@ func TestInvokeFunction(t *testing.T) {
}
}
+func TestInterleavedFunctions(t *testing.T) {
+ c1 := make(chan struct{})
+ c2 := make(chan struct{})
+
+ js.Global().Get("setTimeout").Invoke(js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ c1 <- struct{}{}
+ <-c2
+ return nil
+ }), 0)
+
+ <-c1
+ c2 <- struct{}{}
+ // this goroutine is running, but the callback of setTimeout did not return yet, invoke another function now
+ f := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ return nil
+ })
+ f.Invoke()
+}
+
func ExampleFuncOf() {
var cb js.Func
cb = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
@@ -484,3 +556,38 @@ func TestCopyBytesToJS(t *testing.T) {
})
}
}
+
+func TestGarbageCollection(t *testing.T) {
+ before := js.JSGo.Get("_values").Length()
+ for i := 0; i < 1000; i++ {
+ _ = js.Global().Get("Object").New().Call("toString").String()
+ runtime.GC()
+ }
+ after := js.JSGo.Get("_values").Length()
+ if after-before > 500 {
+ t.Errorf("garbage collection ineffective")
+ }
+}
+
+// BenchmarkDOM is a simple benchmark which emulates a webapp making DOM operations.
+// It creates a div, and sets its id. Then searches by that id and sets some data.
+// Finally it removes that div.
+func BenchmarkDOM(b *testing.B) {
+ document := js.Global().Get("document")
+ if document.IsUndefined() {
+ b.Skip("Not a browser environment. Skipping.")
+ }
+ const data = "someString"
+ for i := 0; i < b.N; i++ {
+ div := document.Call("createElement", "div")
+ div.Call("setAttribute", "id", "myDiv")
+ document.Get("body").Call("appendChild", div)
+ myDiv := document.Call("getElementById", "myDiv")
+ myDiv.Set("innerHTML", data)
+
+ if got, want := myDiv.Get("innerHTML").String(), data; got != want {
+ b.Errorf("got %s, want %s", got, want)
+ }
+ document.Get("body").Call("removeChild", div)
+ }
+}
diff --git a/libgo/go/syscall/lsf_linux.go b/libgo/go/syscall/lsf_linux.go
index 16b702a..f38de62 100644
--- a/libgo/go/syscall/lsf_linux.go
+++ b/libgo/go/syscall/lsf_linux.go
@@ -23,6 +23,8 @@ func LsfJump(code, k, jt, jf int) *SockFilter {
// Deprecated: Use golang.org/x/net/bpf instead.
func LsfSocket(ifindex, proto int) (int, error) {
var lsall SockaddrLinklayer
+ // This is missing SOCK_CLOEXEC, but adding the flag
+ // could break callers.
s, e := Socket(AF_PACKET, SOCK_RAW, proto)
if e != nil {
return 0, e
@@ -46,7 +48,7 @@ type iflags struct {
// Deprecated: Use golang.org/x/net/bpf instead.
func SetLsfPromisc(name string, m bool) error {
- s, e := Socket(AF_INET, SOCK_DGRAM, 0)
+ s, e := cloexecSocket(AF_INET, SOCK_DGRAM, 0)
if e != nil {
return e
}
diff --git a/libgo/go/syscall/net_js.go b/libgo/go/syscall/net_js.go
index d5bf1f4..25f171b 100644
--- a/libgo/go/syscall/net_js.go
+++ b/libgo/go/syscall/net_js.go
@@ -42,7 +42,7 @@ const (
const (
_ = iota
F_DUPFD_CLOEXEC
- SYS_FCNTL = 500 // unsupported; same value as net_nacl.go
+ SYS_FCNTL = 500 // unsupported
)
type Sockaddr interface {
diff --git a/libgo/go/syscall/netlink_linux.go b/libgo/go/syscall/netlink_linux.go
index 1cda8c7..0937ff7 100644
--- a/libgo/go/syscall/netlink_linux.go
+++ b/libgo/go/syscall/netlink_linux.go
@@ -50,7 +50,7 @@ func newNetlinkRouteRequest(proto, seq, family int) []byte {
// NetlinkRIB returns routing information base, as known as RIB, which
// consists of network facility information, states and parameters.
func NetlinkRIB(proto, family int) ([]byte, error) {
- s, err := Socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)
+ s, err := cloexecSocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)
if err != nil {
return nil, err
}
diff --git a/libgo/go/syscall/route_freebsd_64bit.go b/libgo/go/syscall/route_freebsd_64bit.go
index 728837e..e70ba3d 100644
--- a/libgo/go/syscall/route_freebsd_64bit.go
+++ b/libgo/go/syscall/route_freebsd_64bit.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build freebsd,amd64
+// +build freebsd,amd64 freebsd,arm64
package syscall
diff --git a/libgo/go/syscall/security_windows.go b/libgo/go/syscall/security_windows.go
index db80d98..3a75759 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 UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil
+ return utf16PtrToString(s, 256), nil
}
// Len returns the length, in bytes, of a valid security identifier sid.
diff --git a/libgo/go/syscall/sock_cloexec_linux.go b/libgo/go/syscall/sock_cloexec_linux.go
new file mode 100644
index 0000000..600cf25
--- /dev/null
+++ b/libgo/go/syscall/sock_cloexec_linux.go
@@ -0,0 +1,29 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+// This is a stripped down version of sysSocket from net/sock_cloexec.go.
+func cloexecSocket(family, sotype, proto int) (int, error) {
+ s, err := Socket(family, sotype|SOCK_CLOEXEC, proto)
+ switch err {
+ case nil:
+ return s, nil
+ default:
+ return -1, err
+ case EINVAL:
+ }
+
+ ForkLock.RLock()
+ s, err = Socket(family, sotype, proto)
+ if err == nil {
+ CloseOnExec(s)
+ }
+ ForkLock.RUnlock()
+ if err != nil {
+ Close(s)
+ return -1, err
+ }
+ return s, nil
+}
diff --git a/libgo/go/syscall/sockcmsg_dragonfly.go b/libgo/go/syscall/sockcmsg_dragonfly.go
new file mode 100644
index 0000000..d217d9e
--- /dev/null
+++ b/libgo/go/syscall/sockcmsg_dragonfly.go
@@ -0,0 +1,16 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+// Round the length of a raw sockaddr up to align it properly.
+func cmsgAlignOf(salen int) int {
+ salign := sizeofPtr
+ if sizeofPtr == 8 && !supportsABI(_dragonflyABIChangeVersion) {
+ // 64-bit Dragonfly before the September 2019 ABI changes still requires
+ // 32-bit aligned access to network subsystem.
+ salign = 4
+ }
+ return (salen + salign - 1) & ^(salign - 1)
+}
diff --git a/libgo/go/syscall/sockcmsg_linux.go b/libgo/go/syscall/sockcmsg_linux.go
index 4cb9075..d97667c 100644
--- a/libgo/go/syscall/sockcmsg_linux.go
+++ b/libgo/go/syscall/sockcmsg_linux.go
@@ -17,7 +17,7 @@ func UnixCredentials(ucred *Ucred) []byte {
h.Level = SOL_SOCKET
h.Type = SCM_CREDENTIALS
h.SetLen(CmsgLen(SizeofUcred))
- *((*Ucred)(cmsgData(h))) = *ucred
+ *(*Ucred)(h.data(0)) = *ucred
return b
}
diff --git a/libgo/go/syscall/sockcmsg_unix.go b/libgo/go/syscall/sockcmsg_unix.go
index dd74417..6530bea 100644
--- a/libgo/go/syscall/sockcmsg_unix.go
+++ b/libgo/go/syscall/sockcmsg_unix.go
@@ -9,35 +9,9 @@
package syscall
import (
- "runtime"
"unsafe"
)
-// Round the length of a raw sockaddr up to align it properly.
-func cmsgAlignOf(salen int) int {
- salign := int(sizeofPtr)
-
- switch runtime.GOOS {
- case "aix":
- // There is no alignment on AIX.
- salign = 1
- case "darwin", "dragonfly", "illumos", "solaris":
- // NOTE: It seems like 64-bit Darwin, DragonFly BSD and
- // Solaris kernels still require 32-bit aligned access to
- // network subsystem.
- if sizeofPtr == 8 {
- salign = 4
- }
- case "netbsd", "openbsd":
- // NetBSD and OpenBSD armv7 require 64-bit alignment.
- if runtime.GOARCH == "arm" {
- salign = 8
- }
- }
-
- return (salen + salign - 1) & ^(salign - 1)
-}
-
// CmsgLen returns the value to store in the Len field of the Cmsghdr
// structure, taking into account any necessary alignment.
func CmsgLen(datalen int) int {
@@ -50,8 +24,8 @@ func CmsgSpace(datalen int) int {
return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen)
}
-func cmsgData(h *Cmsghdr) unsafe.Pointer {
- return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)))
+func (h *Cmsghdr) data(offset uintptr) unsafe.Pointer {
+ return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)) + offset)
}
// SocketControlMessage represents a socket control message.
@@ -94,10 +68,8 @@ func UnixRights(fds ...int) []byte {
h.Level = SOL_SOCKET
h.Type = SCM_RIGHTS
h.SetLen(CmsgLen(datalen))
- data := cmsgData(h)
- for _, fd := range fds {
- *(*int32)(data) = int32(fd)
- data = unsafe.Pointer(uintptr(data) + 4)
+ for i, fd := range fds {
+ *(*int32)(h.data(4 * uintptr(i))) = int32(fd)
}
return b
}
diff --git a/libgo/go/syscall/sockcmsg_unix_other.go b/libgo/go/syscall/sockcmsg_unix_other.go
new file mode 100644
index 0000000..65d9f18
--- /dev/null
+++ b/libgo/go/syscall/sockcmsg_unix_other.go
@@ -0,0 +1,38 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix darwin freebsd linux netbsd openbsd solaris
+
+package syscall
+
+import (
+ "runtime"
+)
+
+// Round the length of a raw sockaddr up to align it properly.
+func cmsgAlignOf(salen int) int {
+ salign := int(sizeofPtr)
+
+ // dragonfly needs to check ABI version at runtime, see cmsgAlignOf in
+ // sockcmsg_dragonfly.go
+ switch runtime.GOOS {
+ case "aix":
+ // There is no alignment on AIX.
+ salign = 1
+ case "darwin", "illumos", "solaris":
+ // NOTE: It seems like 64-bit Darwin, Illumos and Solaris
+ // kernels still require 32-bit aligned access to network
+ // subsystem.
+ if sizeofPtr == 8 {
+ salign = 4
+ }
+ case "netbsd", "openbsd":
+ // NetBSD and OpenBSD armv7 require 64-bit alignment.
+ if runtime.GOARCH == "arm" {
+ salign = 8
+ }
+ }
+
+ return (salen + salign - 1) & ^(salign - 1)
+}
diff --git a/libgo/go/syscall/syscall.go b/libgo/go/syscall/syscall.go
index 9b74afe..4e1187b 100644
--- a/libgo/go/syscall/syscall.go
+++ b/libgo/go/syscall/syscall.go
@@ -28,7 +28,7 @@ package syscall
import "unsafe"
-//go:generate go run mksyscall_windows.go -systemdll -output zsyscall_windows.go syscall_windows.go security_windows.go
+//go:generate go run golang.org/x/sys/windows/mkwinsyscall -systemdll -output zsyscall_windows.go syscall_windows.go security_windows.go
// StringByteSlice converts a string to a NUL-terminated []byte,
// If s contains a NUL byte this function panics instead of
diff --git a/libgo/go/syscall/syscall_aix.go b/libgo/go/syscall/syscall_aix.go
index 231ff40..f4cac01 100644
--- a/libgo/go/syscall/syscall_aix.go
+++ b/libgo/go/syscall/syscall_aix.go
@@ -23,5 +23,9 @@ func direntReclen(buf []byte) (uint64, bool) {
}
func direntNamlen(buf []byte) (uint64, bool) {
- return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
+ reclen, ok := direntReclen(buf)
+ if !ok {
+ return 0, false
+ }
+ return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
}
diff --git a/libgo/go/syscall/syscall_dragonfly.go b/libgo/go/syscall/syscall_dragonfly.go
index 3e6617c..930bb46 100644
--- a/libgo/go/syscall/syscall_dragonfly.go
+++ b/libgo/go/syscall/syscall_dragonfly.go
@@ -4,7 +4,25 @@
package syscall
-import "unsafe"
+import (
+ "sync"
+ "unsafe"
+)
+
+// See version list in https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/param.h
+var (
+ osreldateOnce sync.Once
+ osreldate uint32
+)
+
+// First __DragonFly_version after September 2019 ABI changes
+// http://lists.dragonflybsd.org/pipermail/users/2019-September/358280.html
+const _dragonflyABIChangeVersion = 500705
+
+func supportsABI(ver uint32) bool {
+ osreldateOnce.Do(func() { osreldate, _ = SysctlUint32("kern.osreldate") })
+ return osreldate >= ver
+}
func direntIno(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
diff --git a/libgo/go/syscall/syscall_errno.go b/libgo/go/syscall/syscall_errno.go
index a339ae8..0d781de 100644
--- a/libgo/go/syscall/syscall_errno.go
+++ b/libgo/go/syscall/syscall_errno.go
@@ -13,6 +13,12 @@ import "internal/oserror"
// if errno != 0 {
// err = errno
// }
+//
+// Errno values can be tested against error values from the os package
+// using errors.Is. For example:
+//
+// _, _, err := syscall.Syscall(...)
+// if errors.Is(err, os.ErrNotExist) ...
type Errno uintptr
func (e Errno) Error() string {
@@ -32,7 +38,7 @@ func (e Errno) Is(target error) bool {
}
func (e Errno) Temporary() bool {
- return e == EINTR || e == EMFILE || e.Timeout()
+ return e == EINTR || e == EMFILE || e == ENFILE || e.Timeout()
}
func (e Errno) Timeout() bool {
diff --git a/libgo/go/syscall/syscall_freebsd_arm64.go b/libgo/go/syscall/syscall_freebsd_arm64.go
new file mode 100644
index 0000000..b561141
--- /dev/null
+++ b/libgo/go/syscall/syscall_freebsd_arm64.go
@@ -0,0 +1,33 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "unsafe"
+
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
+}
+
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+ k.Ident = uint64(fd)
+ k.Filter = int16(mode)
+ k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
diff --git a/libgo/go/syscall/syscall_js.go b/libgo/go/syscall/syscall_js.go
index 175fe47..dfb4a27 100644
--- a/libgo/go/syscall/syscall_js.go
+++ b/libgo/go/syscall/syscall_js.go
@@ -44,6 +44,12 @@ const PathMax = 256
// if errno != 0 {
// err = errno
// }
+//
+// Errno values can be tested against error values from the os package
+// using errors.Is. For example:
+//
+// _, _, err := syscall.Syscall(...)
+// if errors.Is(err, os.ErrNotExist) ...
type Errno uintptr
func (e Errno) Error() string {
@@ -297,9 +303,10 @@ func Getegid() int {
return jsProcess.Call("getegid").Int()
}
-func Getgroups() ([]int, error) {
+func Getgroups() (groups []int, err error) {
+ defer recoverErr(&err)
array := jsProcess.Call("getgroups")
- groups := make([]int, array.Length())
+ groups = make([]int, array.Length())
for i := range groups {
groups[i] = array.Index(i).Int()
}
diff --git a/libgo/go/syscall/syscall_linux_riscv64.go b/libgo/go/syscall/syscall_linux_riscv64.go
new file mode 100644
index 0000000..e9aab94
--- /dev/null
+++ b/libgo/go/syscall/syscall_linux_riscv64.go
@@ -0,0 +1,23 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "unsafe"
+
+func (r *PtraceRegs) PC() uint64 { return r.Pc }
+
+func (r *PtraceRegs) SetPC(pc uint64) { r.Pc = pc }
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint64(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint64(length)
+}
diff --git a/libgo/go/syscall/syscall_linux_test.go b/libgo/go/syscall/syscall_linux_test.go
index 2ad2365..97059c8 100644
--- a/libgo/go/syscall/syscall_linux_test.go
+++ b/libgo/go/syscall/syscall_linux_test.go
@@ -299,6 +299,14 @@ func TestSyscallNoError(t *testing.T) {
t.Skip("skipping on non-32bit architecture")
}
+ // See https://golang.org/issue/35422
+ // On MIPS, Linux returns whether the syscall had an error in a separate
+ // register (R7), not using a negative return value as on other
+ // architectures.
+ if runtime.GOARCH == "mips" || runtime.GOARCH == "mipsle" {
+ t.Skipf("skipping on %s", runtime.GOARCH)
+ }
+
if os.Getuid() != 0 {
t.Skip("skipping root only test")
}
@@ -367,7 +375,8 @@ func TestSyscallNoError(t *testing.T) {
if filesystemIsNoSUID(tmpBinary) {
t.Skip("skipping test when temp dir is mounted nosuid")
}
- t.Errorf("expected %s, got %s", want, got)
+ // formatted so the values are aligned for easier comparison
+ t.Errorf("expected %s,\ngot %s", want, got)
}
}
diff --git a/libgo/go/syscall/syscall_test.go b/libgo/go/syscall/syscall_test.go
index 2a9d90e..5390f8a 100644
--- a/libgo/go/syscall/syscall_test.go
+++ b/libgo/go/syscall/syscall_test.go
@@ -62,7 +62,7 @@ func TestExecErrPermutedFds(t *testing.T) {
}
func TestGettimeofday(t *testing.T) {
- if runtime.GOOS == "nacl" || runtime.GOOS == "js" {
+ if runtime.GOOS == "js" {
t.Skip("not implemented on " + runtime.GOOS)
}
tv := &syscall.Timeval{}
diff --git a/libgo/go/syscall/syscall_unix.go b/libgo/go/syscall/syscall_unix.go
index 37999a2..16e4d480 100644
--- a/libgo/go/syscall/syscall_unix.go
+++ b/libgo/go/syscall/syscall_unix.go
@@ -165,7 +165,14 @@ func Write(fd int, p []byte) (n int, err error) {
if race.Enabled {
race.ReleaseMerge(unsafe.Pointer(&ioSync))
}
- n, err = write(fd, p)
+ if faketime && (fd == 1 || fd == 2) {
+ n = faketimeWrite(fd, p)
+ if n < 0 {
+ n, err = 0, errnoErr(Errno(-n))
+ }
+ } else {
+ n, err = write(fd, p)
+ }
if race.Enabled && n > 0 {
race.ReadRange(unsafe.Pointer(&p[0]), n)
}
diff --git a/libgo/go/syscall/syscall_unix_test.go b/libgo/go/syscall/syscall_unix_test.go
index da259b9..b99e07d 100644
--- a/libgo/go/syscall/syscall_unix_test.go
+++ b/libgo/go/syscall/syscall_unix_test.go
@@ -386,3 +386,9 @@ func TestSetsockoptString(t *testing.T) {
t.Fatalf("SetsockoptString: did not fail")
}
}
+
+func TestENFILETemporary(t *testing.T) {
+ if !syscall.ENFILE.Temporary() {
+ t.Error("ENFILE is not treated as a temporary error")
+ }
+}
diff --git a/libgo/go/syscall/tables_nacljs.go b/libgo/go/syscall/tables_js.go
index 1c265f2..a7c4f8c 100644
--- a/libgo/go/syscall/tables_nacljs.go
+++ b/libgo/go/syscall/tables_js.go
@@ -2,13 +2,17 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build nacl js,wasm
+// +build js,wasm
package syscall
import "runtime"
-// TODO: generate with runtime/mknacl.sh, allow override with IRT.
+// These were originally used by Nacl, then later also used by
+// js/wasm. Now that they're only used by js/wasm, these numbers are
+// just arbitrary.
+//
+// TODO: delete? replace with something meaningful?
const (
sys_null = 1
sys_nameservice = 2
diff --git a/libgo/go/syscall/time_fake.go b/libgo/go/syscall/time_fake.go
new file mode 100644
index 0000000..5dec57a
--- /dev/null
+++ b/libgo/go/syscall/time_fake.go
@@ -0,0 +1,26 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build faketime
+
+package syscall
+
+import "unsafe"
+
+const faketime = true
+
+// When faketime is enabled, we redirect writes to FDs 1 and 2 through
+// the runtime's write function, since that adds the framing that
+// reports the emulated time.
+
+//go:linkname runtimeWrite runtime.write
+func runtimeWrite(fd uintptr, p unsafe.Pointer, n int32) int32
+
+func faketimeWrite(fd int, p []byte) int {
+ var pp *byte
+ if len(p) > 0 {
+ pp = &p[0]
+ }
+ return int(runtimeWrite(uintptr(fd), unsafe.Pointer(pp), int32(len(p))))
+}
diff --git a/libgo/go/syscall/time_nofake.go b/libgo/go/syscall/time_nofake.go
new file mode 100644
index 0000000..c94cef8
--- /dev/null
+++ b/libgo/go/syscall/time_nofake.go
@@ -0,0 +1,14 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !faketime
+
+package syscall
+
+const faketime = false
+
+func faketimeWrite(fd int, p []byte) int {
+ // This should never be called since faketime is false.
+ panic("not implemented")
+}
diff --git a/libgo/go/syscall/timestruct.go b/libgo/go/syscall/timestruct.go
index e2b7704..bd0b3de 100644
--- a/libgo/go/syscall/timestruct.go
+++ b/libgo/go/syscall/timestruct.go
@@ -2,13 +2,13 @@
// 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 nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris
package syscall
// TimespecToNsec converts a Timespec value into a number of
// nanoseconds since the Unix epoch.
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+func TimespecToNsec(ts Timespec) int64 { return ts.Nano() }
// NsecToTimespec takes a number of nanoseconds since the Unix epoch
// and returns the corresponding Timespec value.
@@ -24,7 +24,7 @@ func NsecToTimespec(nsec int64) Timespec {
// TimevalToNsec converts a Timeval value into a number of nanoseconds
// since the Unix epoch.
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+func TimevalToNsec(tv Timeval) int64 { return tv.Nano() }
// NsecToTimeval takes a number of nanoseconds since the Unix epoch
// and returns the corresponding Timeval value.