From 72b38338228b3e90879828c0bb059603f683d98b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Wed, 7 Oct 2020 15:47:45 +0200 Subject: reflect: ensure uniqueness of type descriptors on AIX. On AIX, duplication of type descriptors can occur if one is declared in the libgo and one in the Go program being compiled. The AIX linker isn't able to merge them together as Linux one does. One solution is to always load libgo first but that needs a huge mechanism in gcc core. Thus, this patch ensures that the duplication isn't visible for the end user. In reflect and internal/reflectlite, the comparison of rtypes is made on their name and not only on their addresses. In reflect, toType() function is using a canonicalization map to force rtypes having the same rtype.String() to return the same Type. This can't be made in internal/reflectlite as it needs sync package. But, for now, it doesn't matter as internal/reflectlite is not widely used. Fixes golang/go#39276 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/260158 --- libgo/go/internal/reflectlite/eqtype.go | 12 ++++ libgo/go/internal/reflectlite/eqtype_aix_gccgo.go | 26 ++++++++ libgo/go/internal/reflectlite/type.go | 8 +-- libgo/go/reflect/eqtype.go | 24 ++++++++ libgo/go/reflect/eqtype_aix_gccgo.go | 74 +++++++++++++++++++++++ libgo/go/reflect/type.go | 40 +++++------- libgo/go/reflect/value.go | 2 +- 7 files changed, 157 insertions(+), 29 deletions(-) create mode 100644 libgo/go/internal/reflectlite/eqtype.go create mode 100644 libgo/go/internal/reflectlite/eqtype_aix_gccgo.go create mode 100644 libgo/go/reflect/eqtype.go create mode 100644 libgo/go/reflect/eqtype_aix_gccgo.go (limited to 'libgo/go') diff --git a/libgo/go/internal/reflectlite/eqtype.go b/libgo/go/internal/reflectlite/eqtype.go new file mode 100644 index 0000000..a03cf1c --- /dev/null +++ b/libgo/go/internal/reflectlite/eqtype.go @@ -0,0 +1,12 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//+build !aix !gccgo + +package reflectlite + +// rtypeEqual returns true if both types are identical. +func rtypeEqual(t1, t2 *rtype) bool { + return t1 == t2 +} diff --git a/libgo/go/internal/reflectlite/eqtype_aix_gccgo.go b/libgo/go/internal/reflectlite/eqtype_aix_gccgo.go new file mode 100644 index 0000000..38b507f --- /dev/null +++ b/libgo/go/internal/reflectlite/eqtype_aix_gccgo.go @@ -0,0 +1,26 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//+build aix,gccgo + +// AIX linker isn't able to merge identical type descriptors coming from +// different objects. Thus, two rtypes might have two different pointers +// even if they are the same. Thus, instead of pointer equality, string +// field is checked. + +package reflectlite + +// rtypeEqual returns true if both types are identical. +func rtypeEqual(t1, t2 *rtype) bool { + switch { + case t1 == t2: + return true + case t1 == nil || t2 == nil: + return false + case t1.kind != t2.kind || t1.hash != t2.hash: + return false + default: + return t1.String() == t2.String() + } +} diff --git a/libgo/go/internal/reflectlite/type.go b/libgo/go/internal/reflectlite/type.go index e700a55..1609a06 100644 --- a/libgo/go/internal/reflectlite/type.go +++ b/libgo/go/internal/reflectlite/type.go @@ -539,7 +539,7 @@ func implements(T, V *rtype) bool { for j := 0; j < len(v.methods); j++ { tm := &t.methods[i] vm := &v.methods[j] - if *vm.name == *tm.name && (vm.pkgPath == tm.pkgPath || (vm.pkgPath != nil && tm.pkgPath != nil && *vm.pkgPath == *tm.pkgPath)) && toType(vm.typ).common() == toType(tm.typ).common() { + if *vm.name == *tm.name && (vm.pkgPath == tm.pkgPath || (vm.pkgPath != nil && tm.pkgPath != nil && *vm.pkgPath == *tm.pkgPath)) && rtypeEqual(toType(vm.typ).common(), toType(tm.typ).common()) { if i++; i >= len(t.methods) { return true } @@ -556,7 +556,7 @@ func implements(T, V *rtype) bool { for j := 0; j < len(v.methods); j++ { tm := &t.methods[i] vm := &v.methods[j] - if *vm.name == *tm.name && (vm.pkgPath == tm.pkgPath || (vm.pkgPath != nil && tm.pkgPath != nil && *vm.pkgPath == *tm.pkgPath)) && toType(vm.mtyp).common() == toType(tm.typ).common() { + if *vm.name == *tm.name && (vm.pkgPath == tm.pkgPath || (vm.pkgPath != nil && tm.pkgPath != nil && *vm.pkgPath == *tm.pkgPath)) && rtypeEqual(toType(vm.mtyp).common(), toType(tm.typ).common()) { if i++; i >= len(t.methods) { return true } @@ -572,7 +572,7 @@ func implements(T, V *rtype) bool { // and the ideal constant rules (no ideal constants at run time). func directlyAssignable(T, V *rtype) bool { // x's type V is identical to T? - if T == V { + if rtypeEqual(T, V) { return true } @@ -599,7 +599,7 @@ func haveIdenticalType(T, V Type, cmpTags bool) bool { } func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool { - if T == V { + if rtypeEqual(T, V) { return true } diff --git a/libgo/go/reflect/eqtype.go b/libgo/go/reflect/eqtype.go new file mode 100644 index 0000000..5639bc5 --- /dev/null +++ b/libgo/go/reflect/eqtype.go @@ -0,0 +1,24 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !aix !gccgo + +package reflect + +// rtypeEqual returns true if both rtypes are identical. +func rtypeEqual(t1, t2 *rtype) bool { + return t1 == t2 +} + +// typeEqual returns true if both Types are identical. +func typeEqual(t1, t2 Type) bool { + return t1 == t2 +} + +func toType(p *rtype) Type { + if p == nil { + return nil + } + return p +} diff --git a/libgo/go/reflect/eqtype_aix_gccgo.go b/libgo/go/reflect/eqtype_aix_gccgo.go new file mode 100644 index 0000000..7afbf10 --- /dev/null +++ b/libgo/go/reflect/eqtype_aix_gccgo.go @@ -0,0 +1,74 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//+build aix,gccgo + +// AIX linker isn't able to merge identical type descriptors coming from +// different objects. Thus, two rtypes might have two different pointers +// even if they are the same. Thus, instead of pointer equality, string +// field is checked. + +package reflect + +import ( + "sync" +) + +// rtypeEqual returns true if both rtypes are identical. +func rtypeEqual(t1, t2 *rtype) bool { + switch { + case t1 == t2: + return true + case t1 == nil || t2 == nil: + return false + case t1.kind != t2.kind || t1.hash != t2.hash: + return false + default: + return t1.String() == t2.String() + } +} + +// typeEqual returns true if both Types are identical. +func typeEqual(t1, t2 Type) bool { + return rtypeEqual(t1.common(), t2.common()) +} + +// toType converts from a *rtype to a Type that can be returned +// to the client of package reflect. The only concern is that +// a nil *rtype must be replaced by a nil Type. +// On AIX, as type duplications can occur, it also ensure that +// multiple *rtype for the same type are coalesced into a single +// Type. + +var canonicalType = make(map[string]Type) + +var canonicalTypeLock sync.RWMutex + +func canonicalize(t Type) Type { + if t == nil { + return nil + } + s := t.rawString() + canonicalTypeLock.RLock() + if r, ok := canonicalType[s]; ok { + canonicalTypeLock.RUnlock() + return r + } + canonicalTypeLock.RUnlock() + canonicalTypeLock.Lock() + if r, ok := canonicalType[s]; ok { + canonicalTypeLock.Unlock() + return r + } + canonicalType[s] = t + canonicalTypeLock.Unlock() + return t +} + +func toType(p *rtype) Type { + if p == nil { + return nil + } + return canonicalize(p) +} diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index 2ce1901f..73c09d4 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -1129,7 +1129,7 @@ func (t *rtype) ptrTo() *rtype { // Look in known types. s := "*" + *t.string if tt := lookupType(s); tt != nil { - p := (*ptrType)(unsafe.Pointer(tt)) + p := (*ptrType)(unsafe.Pointer(toType(tt).(*rtype))) if p.elem == t { pi, _ := ptrMap.LoadOrStore(t, p) return &pi.(*ptrType).rtype @@ -1158,7 +1158,9 @@ func (t *rtype) ptrTo() *rtype { pp.ptrToThis = nil pp.elem = t - pi, _ := ptrMap.LoadOrStore(t, &pp) + q := toType(&pp.rtype).(*rtype) + p := (*ptrType)(unsafe.Pointer(q)) + pi, _ := ptrMap.LoadOrStore(t, p) return &pi.(*ptrType).rtype } @@ -1273,7 +1275,7 @@ func specialChannelAssignability(T, V *rtype) bool { // and the ideal constant rules (no ideal constants at run time). func directlyAssignable(T, V *rtype) bool { // x's type V is identical to T? - if T == V { + if rtypeEqual(T, V) { return true } @@ -1304,7 +1306,7 @@ func haveIdenticalType(T, V Type, cmpTags bool) bool { } func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool { - if T == V { + if rtypeEqual(T, V) { return true } @@ -1449,7 +1451,7 @@ func ChanOf(dir ChanDir, t Type) Type { s = "chan " + *typ.string } if tt := lookupType(s); tt != nil { - ch := (*chanType)(unsafe.Pointer(tt)) + ch := (*chanType)(unsafe.Pointer(toType(tt).(*rtype))) if ch.elem == typ && ch.dir == uintptr(dir) { ti, _ := lookupCache.LoadOrStore(ckey, tt) return ti.(Type) @@ -1481,7 +1483,7 @@ func ChanOf(dir ChanDir, t Type) Type { ch.uncommonType = nil ch.ptrToThis = nil - ti, _ := lookupCache.LoadOrStore(ckey, &ch.rtype) + ti, _ := lookupCache.LoadOrStore(ckey, toType(&ch.rtype).(*rtype)) return ti.(Type) } @@ -1508,7 +1510,7 @@ func MapOf(key, elem Type) Type { // Look in known types. s := "map[" + *ktyp.string + "]" + *etyp.string if tt := lookupType(s); tt != nil { - mt := (*mapType)(unsafe.Pointer(tt)) + mt := (*mapType)(unsafe.Pointer(toType(tt).(*rtype))) if mt.key == ktyp && mt.elem == etyp { ti, _ := lookupCache.LoadOrStore(ckey, tt) return ti.(Type) @@ -1559,7 +1561,7 @@ func MapOf(key, elem Type) Type { mt.flags |= 16 } - ti, _ := lookupCache.LoadOrStore(ckey, &mt.rtype) + ti, _ := lookupCache.LoadOrStore(ckey, toType(&mt.rtype).(*rtype)) return ti.(Type) } @@ -1648,7 +1650,7 @@ func FuncOf(in, out []Type, variadic bool) Type { ft.string = &str ft.uncommonType = nil ft.ptrToThis = nil - return addToCache(&ft.rtype) + return addToCache(toType(&ft.rtype).(*rtype)) } // funcStr builds a string representation of a funcType. @@ -1909,7 +1911,7 @@ func SliceOf(t Type) Type { // Look in known types. s := "[]" + *typ.string if tt := lookupType(s); tt != nil { - slice := (*sliceType)(unsafe.Pointer(tt)) + slice := (*sliceType)(unsafe.Pointer(toType(tt).(*rtype))) if slice.elem == typ { ti, _ := lookupCache.LoadOrStore(ckey, tt) return ti.(Type) @@ -1930,7 +1932,7 @@ func SliceOf(t Type) Type { slice.uncommonType = nil slice.ptrToThis = nil - ti, _ := lookupCache.LoadOrStore(ckey, &slice.rtype) + ti, _ := lookupCache.LoadOrStore(ckey, toType(&slice.rtype).(*rtype)) return ti.(Type) } @@ -2234,7 +2236,7 @@ func StructOf(fields []StructField) Type { typ.uncommonType = nil typ.ptrToThis = nil - return addToCache(&typ.rtype) + return addToCache(toType(&typ.rtype).(*rtype)) } // runtimeStructField takes a StructField value passed to StructOf and @@ -2330,7 +2332,7 @@ func ArrayOf(count int, elem Type) Type { // Look in known types. s := "[" + strconv.Itoa(count) + "]" + *typ.string if tt := lookupType(s); tt != nil { - array := (*arrayType)(unsafe.Pointer(tt)) + array := (*arrayType)(unsafe.Pointer(toType(tt).(*rtype))) if array.elem == typ { ti, _ := lookupCache.LoadOrStore(ckey, tt) return ti.(Type) @@ -2446,7 +2448,7 @@ func ArrayOf(count int, elem Type) Type { array.kind &^= kindDirectIface } - ti, _ := lookupCache.LoadOrStore(ckey, &array.rtype) + ti, _ := lookupCache.LoadOrStore(ckey, toType(&array.rtype).(*rtype)) return ti.(Type) } @@ -2458,16 +2460,6 @@ func appendVarint(x []byte, v uintptr) []byte { return x } -// toType converts from a *rtype to a Type that can be returned -// to the client of package reflect. The only concern is that -// a nil *rtype must be replaced by a nil Type. -func toType(p *rtype) Type { - if p == nil { - return nil - } - return p -} - // Look up a compiler-generated type descriptor. // Implemented in runtime. func lookupType(s string) *rtype diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index e60f84f..64f7432 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -1785,7 +1785,7 @@ type SliceHeader struct { } func typesMustMatch(what string, t1, t2 Type) { - if t1 != t2 { + if !typeEqual(t1, t2) { panic(what + ": " + t1.String() + " != " + t2.String()) } } -- cgit v1.1 From 7355c1df55e28f3298b14a621968f9a27fdcd2bf Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Tue, 13 Oct 2020 07:06:11 +0000 Subject: syscall: port fix for netbsd unix sockets from upstream NetBSD does not include the null terminator when in its reported socket length. Port the upstream bugfix for the issue (#6627). This was likely missed during the usual upstream merge because the gc and gccgo socket implementations have diverged quite a bit. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/261741 --- libgo/go/syscall/socket_bsd.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'libgo/go') diff --git a/libgo/go/syscall/socket_bsd.go b/libgo/go/syscall/socket_bsd.go index f62457f..40637bc 100644 --- a/libgo/go/syscall/socket_bsd.go +++ b/libgo/go/syscall/socket_bsd.go @@ -52,13 +52,19 @@ func (sa *RawSockaddrUnix) setLen(n int) { } func (sa *RawSockaddrUnix) getLen() (int, error) { - if sa.Len < 3 || sa.Len > SizeofSockaddrUnix { + if sa.Len < 2 || sa.Len > SizeofSockaddrUnix { return 0, EINVAL } - n := int(sa.Len) - 3 // subtract leading Family, Len, terminating NUL. + + // Some BSDs include the trailing NUL in the length, whereas + // others do not. Work around this by subtracting the leading + // family and len. The path is then scanned to see if a NUL + // terminator still exists within the length. + n := int(sa.Len) - 2 // subtract leading Family, Len for i := 0; i < n; i++ { if sa.Path[i] == 0 { - // found early NUL; assume Len is overestimating. + // found early NUL; assume Len included the NUL + // or was overestimating. n = i break } -- cgit v1.1 From ca56d576241c6783eb36eea526b42c4f3fbf697b Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Tue, 13 Oct 2020 07:17:55 +0000 Subject: runtime: correct semaphore implementation on netbsd NetBSD's semaphores use the underlying lighweight process mechanism (LWP) on NetBSD, rather than pthreads. This means the m.prodcid needs to be set to the LWP ID rather than the pthread ID in order for unpark notifications to get sent to the right place. Introduce a new getProcID() method that selects the correct ID for the platform. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/261742 --- libgo/go/runtime/os_aix.go | 4 ++++ libgo/go/runtime/os_gccgo.go | 3 +-- libgo/go/runtime/os_hurd.go | 4 ++++ libgo/go/runtime/os_linux.go | 4 ++++ libgo/go/runtime/os_netbsd.go | 17 ++++++++++++----- libgo/go/runtime/os_solaris.go | 4 ++++ 6 files changed, 29 insertions(+), 7 deletions(-) (limited to 'libgo/go') diff --git a/libgo/go/runtime/os_aix.go b/libgo/go/runtime/os_aix.go index 951aeb6..f49b83c 100644 --- a/libgo/go/runtime/os_aix.go +++ b/libgo/go/runtime/os_aix.go @@ -21,6 +21,10 @@ type mOS struct { waitsema uintptr // semaphore for parking on locks } +func getProcID() uint64 { + return uint64(gettid()) +} + //extern malloc func libc_malloc(uintptr) unsafe.Pointer diff --git a/libgo/go/runtime/os_gccgo.go b/libgo/go/runtime/os_gccgo.go index ab19022..a8859c0 100644 --- a/libgo/go/runtime/os_gccgo.go +++ b/libgo/go/runtime/os_gccgo.go @@ -27,8 +27,7 @@ func mpreinit(mp *m) { func minit() { minitSignals() - // FIXME: only works on linux for now. - getg().m.procid = uint64(gettid()) + getg().m.procid = getProcID() } // Called from dropm to undo the effect of an minit. diff --git a/libgo/go/runtime/os_hurd.go b/libgo/go/runtime/os_hurd.go index b3c6f80..1613b41 100644 --- a/libgo/go/runtime/os_hurd.go +++ b/libgo/go/runtime/os_hurd.go @@ -18,6 +18,10 @@ type mOS struct { waitsema uintptr // semaphore for parking on locks } +func getProcID() uint64 { + return uint64(gettid()) +} + //extern malloc func libc_malloc(uintptr) unsafe.Pointer diff --git a/libgo/go/runtime/os_linux.go b/libgo/go/runtime/os_linux.go index 5d55064..627b6d6 100644 --- a/libgo/go/runtime/os_linux.go +++ b/libgo/go/runtime/os_linux.go @@ -13,6 +13,10 @@ type mOS struct { unused byte } +func getProcID() uint64 { + return uint64(gettid()) +} + func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32 { return int32(syscall(_SYS_futex, uintptr(addr), uintptr(op), uintptr(val), uintptr(ts), uintptr(addr2), uintptr(val3))) } diff --git a/libgo/go/runtime/os_netbsd.go b/libgo/go/runtime/os_netbsd.go index 69d2c71..89a8d07 100644 --- a/libgo/go/runtime/os_netbsd.go +++ b/libgo/go/runtime/os_netbsd.go @@ -14,12 +14,19 @@ type mOS struct { waitsemacount uint32 } +func getProcID() uint64 { + return uint64(lwp_self()) +} + +//extern _lwp_self +func lwp_self() int32 + //go:noescape -//extern lwp_park +//extern _lwp_park func lwp_park(ts int32, rel int32, abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32 //go:noescape -//extern lwp_unpark +//extern _lwp_unpark func lwp_unpark(lwp int32, hint unsafe.Pointer) int32 //go:noescape @@ -88,7 +95,7 @@ func semasleep(ns int64) int32 { tsp = &ts } ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) - if ret == _ETIMEDOUT { + if ret != 0 && errno() == _ETIMEDOUT { return -1 } } @@ -101,10 +108,10 @@ func semawakeup(mp *m) { // "If the target LWP is not currently waiting, it will return // immediately upon the next call to _lwp_park()." ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount)) - if ret != 0 && ret != _ESRCH { + if ret != 0 && errno() != _ESRCH { // semawakeup can be called on signal stack. systemstack(func() { - print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") + print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " errno=", errno(), "\n") }) } } diff --git a/libgo/go/runtime/os_solaris.go b/libgo/go/runtime/os_solaris.go index 63b5cd7..c568629 100644 --- a/libgo/go/runtime/os_solaris.go +++ b/libgo/go/runtime/os_solaris.go @@ -10,6 +10,10 @@ type mOS struct { waitsema uintptr // semaphore for parking on locks } +func getProcID() uint64 { + return uint64(gettid()) +} + //extern malloc func libc_malloc(uintptr) unsafe.Pointer -- cgit v1.1 From dc570700beab4080040884690deb6016090b4fa8 Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Tue, 13 Oct 2020 06:36:43 +0000 Subject: libgo: export NetBSD-specific types in mksysinfo.sh The syscall package depends on many NetBSD-specific types on NetBSD. Teach mksysinfo.sh to export these types. This alone is not sufficient to get the syscall package to compile on NetBSD, but it's a start. Note that the IfMsgHdr type is recapitalized to IfMsghdr, which requires changes in the AIX port. The new capitalization is what's used by upstream in existing NetBSD-specific code and is more consistent with the capitalization of other C structs with the "hdr" suffix. Updates golang/go#38538. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/261739 --- libgo/go/runtime/os_netbsd.go | 7 ------- 1 file changed, 7 deletions(-) (limited to 'libgo/go') diff --git a/libgo/go/runtime/os_netbsd.go b/libgo/go/runtime/os_netbsd.go index 89a8d07..9ebb652 100644 --- a/libgo/go/runtime/os_netbsd.go +++ b/libgo/go/runtime/os_netbsd.go @@ -33,13 +33,6 @@ func lwp_unpark(lwp int32, hint unsafe.Pointer) int32 //extern sysctl func sysctl(*uint32, uint32, *byte, *uintptr, *byte, uintptr) int32 -// From NetBSD's -const ( - _CTL_HW = 6 - _HW_NCPU = 3 - _HW_PAGESIZE = 7 -) - func getncpu() int32 { mib := [2]uint32{_CTL_HW, _HW_NCPU} out := uint32(0) -- cgit v1.1 From 522307281ce9042e0bb3044f4a162adcdee0f9f6 Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Mon, 19 Oct 2020 02:19:04 +0000 Subject: syscall: remove Sendfile on NetBSD NetBSD does not support the sendfile syscall. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/263521 --- libgo/go/syscall/libcall_bsd.go | 31 ------------------------------- libgo/go/syscall/libcall_bsd_regfile.go | 2 +- libgo/go/syscall/libcall_bsd_sendfile.go | 31 +++++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 32 deletions(-) delete mode 100644 libgo/go/syscall/libcall_bsd.go create mode 100644 libgo/go/syscall/libcall_bsd_sendfile.go (limited to 'libgo/go') diff --git a/libgo/go/syscall/libcall_bsd.go b/libgo/go/syscall/libcall_bsd.go deleted file mode 100644 index 93f5710..0000000 --- a/libgo/go/syscall/libcall_bsd.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2015 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 darwin dragonfly freebsd netbsd openbsd solaris - -// BSD library calls. - -package syscall - -import ( - "internal/race" - "unsafe" -) - -func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { - if race.Enabled { - race.ReleaseMerge(unsafe.Pointer(&ioSync)) - } - var soff Offset_t - var psoff *Offset_t - if offset != nil { - soff = Offset_t(*offset) - psoff = &soff - } - written, err = sendfile(outfd, infd, psoff, count) - if offset != nil { - *offset = int64(soff) - } - return -} diff --git a/libgo/go/syscall/libcall_bsd_regfile.go b/libgo/go/syscall/libcall_bsd_regfile.go index 388c8a7..0b9d01f 100644 --- a/libgo/go/syscall/libcall_bsd_regfile.go +++ b/libgo/go/syscall/libcall_bsd_regfile.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 solaris,amd64 solaris,sparc64 +// +build darwin dragonfly freebsd openbsd solaris,amd64 solaris,sparc64 package syscall diff --git a/libgo/go/syscall/libcall_bsd_sendfile.go b/libgo/go/syscall/libcall_bsd_sendfile.go new file mode 100644 index 0000000..295a1f4 --- /dev/null +++ b/libgo/go/syscall/libcall_bsd_sendfile.go @@ -0,0 +1,31 @@ +// Copyright 2015 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 darwin dragonfly freebsd openbsd solaris + +// BSD sendfile support. + +package syscall + +import ( + "internal/race" + "unsafe" +) + +func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + if race.Enabled { + race.ReleaseMerge(unsafe.Pointer(&ioSync)) + } + var soff Offset_t + var psoff *Offset_t + if offset != nil { + soff = Offset_t(*offset) + psoff = &soff + } + written, err = sendfile(outfd, infd, psoff, count) + if offset != nil { + *offset = int64(soff) + } + return +} -- cgit v1.1 From 2ab1fc7a322e2582772f0e4ed916508c890175e3 Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Sat, 10 Oct 2020 00:06:36 +0000 Subject: syscall: import upstream code for BSD sockets and sysctls Import some missing upstream code for BSD sockets and sysctls and adapt it for gccgo. Updates golang/go#38538. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/261137 --- libgo/go/syscall/route_bsd.go | 2 +- libgo/go/syscall/socket_bsd.go | 41 +++++++++++++++++++++++++ libgo/go/syscall/syscall_netbsd.go | 61 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 1 deletion(-) (limited to 'libgo/go') diff --git a/libgo/go/syscall/route_bsd.go b/libgo/go/syscall/route_bsd.go index b364eea..0c32594 100644 --- a/libgo/go/syscall/route_bsd.go +++ b/libgo/go/syscall/route_bsd.go @@ -18,7 +18,7 @@ var ( // Round the length of a raw sockaddr up to align it properly. func rsaAlignOf(salen int) int { - salign := sizeofPtr + salign := int(sizeofPtr) if darwin64Bit { // Darwin kernels require 32-bit aligned access to // routing facilities. diff --git a/libgo/go/syscall/socket_bsd.go b/libgo/go/syscall/socket_bsd.go index 40637bc..b230a32 100644 --- a/libgo/go/syscall/socket_bsd.go +++ b/libgo/go/syscall/socket_bsd.go @@ -13,6 +13,7 @@ import "unsafe" const SizeofSockaddrInet4 = 16 const SizeofSockaddrInet6 = 28 const SizeofSockaddrUnix = 110 +const SizeofSockaddrDatalink = 20 type RawSockaddrInet4 struct { Len uint8 @@ -76,6 +77,46 @@ func (sa *RawSockaddrUnix) adjustAbstract(sl Socklen_t) Socklen_t { return sl } +type SockaddrDatalink struct { + Len uint8 + Family uint8 + Index uint16 + Type uint8 + Nlen uint8 + Alen uint8 + Slen uint8 + Data [12]int8 + raw RawSockaddrDatalink +} + +func (sa *SockaddrDatalink) sockaddr() (*RawSockaddrAny, Socklen_t, error) { + if sa.Index == 0 { + return nil, 0, EINVAL + } + sa.raw.Len = sa.Len + sa.raw.Family = AF_LINK + sa.raw.Index = sa.Index + sa.raw.Type = sa.Type + sa.raw.Nlen = sa.Nlen + sa.raw.Alen = sa.Alen + sa.raw.Slen = sa.Slen + for i := 0; i < len(sa.raw.Data); i++ { + sa.raw.Data[i] = sa.Data[i] + } + return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), SizeofSockaddrDatalink, nil +} + +type RawSockaddrDatalink struct { + Len uint8 + Family uint8 + Index uint16 + Type uint8 + Nlen uint8 + Alen uint8 + Slen uint8 + Data [12]int8 +} + type RawSockaddr struct { Len uint8 Family uint8 diff --git a/libgo/go/syscall/syscall_netbsd.go b/libgo/go/syscall/syscall_netbsd.go index c67550a..bbc6799 100644 --- a/libgo/go/syscall/syscall_netbsd.go +++ b/libgo/go/syscall/syscall_netbsd.go @@ -17,3 +17,64 @@ func direntReclen(buf []byte) (uint64, bool) { func direntNamlen(buf []byte) (uint64, bool) { return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) } + +func sysctlNodes(mib []_C_int) (nodes []Sysctlnode, err error) { + var olen uintptr + + // Get a list of all sysctl nodes below the given MIB by performing + // a sysctl for the given MIB with CTL_QUERY appended. + mib = append(mib, CTL_QUERY) + qnode := Sysctlnode{Flags: SYSCTL_VERS_1} + qp := (*byte)(unsafe.Pointer(&qnode)) + sz := unsafe.Sizeof(qnode) + if err = sysctl(mib, nil, &olen, qp, sz); err != nil { + return nil, err + } + + // Now that we know the size, get the actual nodes. + nodes = make([]Sysctlnode, olen/sz) + np := (*byte)(unsafe.Pointer(&nodes[0])) + if err = sysctl(mib, np, &olen, qp, sz); err != nil { + return nil, err + } + + return nodes, nil +} + +func nametomib(name string) (mib []_C_int, err error) { + // Split name into components. + var parts []string + last := 0 + for i := 0; i < len(name); i++ { + if name[i] == '.' { + parts = append(parts, name[last:i]) + last = i + 1 + } + } + parts = append(parts, name[last:]) + + // Discover the nodes and construct the MIB OID. + for partno, part := range parts { + nodes, err := sysctlNodes(mib) + if err != nil { + return nil, err + } + for _, node := range nodes { + n := make([]byte, 0) + for i := range node.Name { + if node.Name[i] != 0 { + n = append(n, byte(node.Name[i])) + } + } + if string(n) == part { + mib = append(mib, _C_int(node.Num)) + break + } + } + if len(mib) != partno+1 { + return nil, EINVAL + } + } + + return mib, nil +} -- cgit v1.1 From 439407aa2c678a96bd5b430ab9c335e65beb5751 Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Sun, 18 Oct 2020 19:28:54 +0000 Subject: syscall: only compile ptrace varargs shim on Linux Only compile the __go_ptrace varargs shim on Linux to avoid compilation failures on some other platforms. The C ptrace function is not entirely portable (e.g., NetBSD has `int data` instead of `void* data`), and so far Linux is the only platform that needs the varargs shim. Additionally, make the types in the ptrace and raw_ptrace function declarations match. This makes it more clear that the only difference between the two is that calls via the former are allowed to block while calls via the latter are not. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/263517 --- libgo/go/syscall/exec_bsd.go | 2 +- libgo/go/syscall/exec_linux.go | 2 +- libgo/go/syscall/exec_stubs.go | 2 +- libgo/go/syscall/libcall_aix.go | 2 +- libgo/go/syscall/libcall_glibc.go | 3 --- libgo/go/syscall/libcall_hurd.go | 2 +- libgo/go/syscall/libcall_irix.go | 2 +- libgo/go/syscall/libcall_linux.go | 5 ++++- libgo/go/syscall/libcall_solaris_386.go | 2 +- libgo/go/syscall/libcall_solaris_amd64.go | 2 +- libgo/go/syscall/libcall_solaris_sparc.go | 2 +- libgo/go/syscall/libcall_solaris_sparc64.go | 2 +- 12 files changed, 14 insertions(+), 14 deletions(-) (limited to 'libgo/go') diff --git a/libgo/go/syscall/exec_bsd.go b/libgo/go/syscall/exec_bsd.go index 7e06943..ca7fdc0 100644 --- a/libgo/go/syscall/exec_bsd.go +++ b/libgo/go/syscall/exec_bsd.go @@ -93,7 +93,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr // Enable tracing if requested. if sys.Ptrace { - err1 = raw_ptrace(_PTRACE_TRACEME, 0, nil, nil) + err1 = raw_ptrace(_PTRACE_TRACEME, 0, 0, 0) if err1 != 0 { goto childerror } diff --git a/libgo/go/syscall/exec_linux.go b/libgo/go/syscall/exec_linux.go index 2f0a34f..3897581 100644 --- a/libgo/go/syscall/exec_linux.go +++ b/libgo/go/syscall/exec_linux.go @@ -538,7 +538,7 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att // Do this right before exec so that we don't unnecessarily trace the runtime // setting up after the fork. See issue #21428. if sys.Ptrace { - err1 = raw_ptrace(_PTRACE_TRACEME, 0, nil, nil) + err1 = raw_ptrace(_PTRACE_TRACEME, 0, 0, 0) if err1 != 0 { goto childerror } diff --git a/libgo/go/syscall/exec_stubs.go b/libgo/go/syscall/exec_stubs.go index e95b415..c837cf7 100644 --- a/libgo/go/syscall/exec_stubs.go +++ b/libgo/go/syscall/exec_stubs.go @@ -30,6 +30,6 @@ func (w WaitStatus) Signal() int { return 0 } func (w WaitStatus) StopSignal() int { return 0 } func (w WaitStatus) TrapCause() int { return 0 } -func raw_ptrace(request int, pid int, addr *byte, data *byte) Errno { +func raw_ptrace(request int, pid int, addr uintptr, data uintptr) Errno { return ENOSYS } diff --git a/libgo/go/syscall/libcall_aix.go b/libgo/go/syscall/libcall_aix.go index 27b469e..92c7f3c 100644 --- a/libgo/go/syscall/libcall_aix.go +++ b/libgo/go/syscall/libcall_aix.go @@ -19,7 +19,7 @@ const SYS_EXECVE = 0 //sys ptrace64(request int, id int64, addr int64, data int, buff uintptr) (err error) //ptrace64(request _C_int, id int64, addr int64, data _C_int, buff *byte) _C_int -func raw_ptrace(request int, pid int, addr *byte, data *byte) Errno { +func raw_ptrace(request int, pid int, addr uintptr, data uintptr) Errno { if request == _PTRACE_TRACEME { // Convert to AIX ptrace call. err := ptrace64(_PT_TRACE_ME, 0, 0, 0, 0) diff --git a/libgo/go/syscall/libcall_glibc.go b/libgo/go/syscall/libcall_glibc.go index 823343d..a32d696 100644 --- a/libgo/go/syscall/libcall_glibc.go +++ b/libgo/go/syscall/libcall_glibc.go @@ -31,9 +31,6 @@ func Futimes(fd int, tv []Timeval) (err error) { return Utimes("/proc/self/fd/"+itoa(fd), tv) } -//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error) -//__go_ptrace(request _C_int, pid Pid_t, addr *byte, data *byte) _C_long - //sys accept4(fd int, sa *RawSockaddrAny, len *Socklen_t, flags int) (nfd int, err error) //accept4(fd _C_int, sa *RawSockaddrAny, len *Socklen_t, flags _C_int) _C_int diff --git a/libgo/go/syscall/libcall_hurd.go b/libgo/go/syscall/libcall_hurd.go index f0e038c..44ff46d 100644 --- a/libgo/go/syscall/libcall_hurd.go +++ b/libgo/go/syscall/libcall_hurd.go @@ -7,7 +7,7 @@ package syscall // Dummy function -func raw_ptrace(request int, pid int, addr *byte, data *byte) Errno { +func raw_ptrace(request int, pid int, addr uintptr, data uintptr) Errno { return ENOSYS } diff --git a/libgo/go/syscall/libcall_irix.go b/libgo/go/syscall/libcall_irix.go index 9b6cdcc..9880766 100644 --- a/libgo/go/syscall/libcall_irix.go +++ b/libgo/go/syscall/libcall_irix.go @@ -6,5 +6,5 @@ package syscall -//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (err Errno) +//sysnb raw_ptrace(request int, pid int, addr uintptr, data uintptr) (err Errno) //ptrace(request _C_int, pid Pid_t, addr *byte, data *byte) _C_long diff --git a/libgo/go/syscall/libcall_linux.go b/libgo/go/syscall/libcall_linux.go index 78fda0e..96974bd 100644 --- a/libgo/go/syscall/libcall_linux.go +++ b/libgo/go/syscall/libcall_linux.go @@ -10,7 +10,10 @@ import ( "unsafe" ) -//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (err Errno) +//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err Errno) +//__go_ptrace(request _C_int, pid Pid_t, addr *byte, data *byte) _C_long + +//sysnb raw_ptrace(request int, pid int, addr uintptr, data uintptr) (err Errno) //__go_ptrace(request _C_int, pid Pid_t, addr *byte, data *byte) _C_long func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err error) { diff --git a/libgo/go/syscall/libcall_solaris_386.go b/libgo/go/syscall/libcall_solaris_386.go index 20eba22..ef86f09 100644 --- a/libgo/go/syscall/libcall_solaris_386.go +++ b/libgo/go/syscall/libcall_solaris_386.go @@ -8,5 +8,5 @@ package syscall //sysnb Uname(buf *Utsname) (err error) //_nuname(buf *Utsname) _C_int -//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (err Errno) +//sysnb raw_ptrace(request int, pid int, addr uintptr, data uintptr) (err Errno) //ptrace(request _C_int, pid Pid_t, addr *byte, data *byte) _C_long diff --git a/libgo/go/syscall/libcall_solaris_amd64.go b/libgo/go/syscall/libcall_solaris_amd64.go index 69b11ba..f44025e 100644 --- a/libgo/go/syscall/libcall_solaris_amd64.go +++ b/libgo/go/syscall/libcall_solaris_amd64.go @@ -5,6 +5,6 @@ package syscall // 64-bit ptrace(3C) doesn't exist -func raw_ptrace(request int, pid int, addr *byte, data *byte) Errno { +func raw_ptrace(request int, pid int, addr uintptr, data uintptr) Errno { return ENOSYS } diff --git a/libgo/go/syscall/libcall_solaris_sparc.go b/libgo/go/syscall/libcall_solaris_sparc.go index 50863fa..3d50309 100644 --- a/libgo/go/syscall/libcall_solaris_sparc.go +++ b/libgo/go/syscall/libcall_solaris_sparc.go @@ -4,5 +4,5 @@ package syscall -//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (err Errno) +//sysnb raw_ptrace(request int, pid int, addr uintptr, data uintptr) (err Errno) //ptrace(request _C_int, pid Pid_t, addr *byte, data *byte) _C_long diff --git a/libgo/go/syscall/libcall_solaris_sparc64.go b/libgo/go/syscall/libcall_solaris_sparc64.go index 69b11ba..f44025e 100644 --- a/libgo/go/syscall/libcall_solaris_sparc64.go +++ b/libgo/go/syscall/libcall_solaris_sparc64.go @@ -5,6 +5,6 @@ package syscall // 64-bit ptrace(3C) doesn't exist -func raw_ptrace(request int, pid int, addr *byte, data *byte) Errno { +func raw_ptrace(request int, pid int, addr uintptr, data uintptr) Errno { return ENOSYS } -- cgit v1.1 From 27f7ab27d1a514eaf538ae01840b42c6d12cb28f Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Wed, 21 Oct 2020 03:00:04 -0400 Subject: net/http/cgi: merge upstream changes to default env vars Incorporate upstream modifications to the cgi package's set of rules about which environment variables should be inherited by child processes by default on each platform. In particular this permits tests to pass on NetBSD by preserving the value of the LD_LIBRARY_PATH environment variable. This is a partial backport of the following upstream CLs: https://golang.org/cl/263802 https://golang.org/cl/263577 https://golang.org/cl/254740 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/264097 --- libgo/go/net/http/cgi/host.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libgo/go') diff --git a/libgo/go/net/http/cgi/host.go b/libgo/go/net/http/cgi/host.go index 863f406..eff67ca 100644 --- a/libgo/go/net/http/cgi/host.go +++ b/libgo/go/net/http/cgi/host.go @@ -37,15 +37,15 @@ var trailingPort = regexp.MustCompile(`:([0-9]+)$`) var osDefaultInheritEnv = func() []string { switch runtime.GOOS { - case "darwin": + case "darwin", "ios": return []string{"DYLD_LIBRARY_PATH"} - case "linux", "freebsd", "openbsd": + case "linux", "freebsd", "netbsd", "openbsd": return []string{"LD_LIBRARY_PATH"} case "hpux": return []string{"LD_LIBRARY_PATH", "SHLIB_PATH"} case "irix": return []string{"LD_LIBRARY_PATH", "LD_LIBRARYN32_PATH", "LD_LIBRARY64_PATH"} - case "solaris": + case "illumos", "solaris": return []string{"LD_LIBRARY_PATH", "LD_LIBRARY_PATH_32", "LD_LIBRARY_PATH_64"} case "windows": return []string{"SystemRoot", "COMSPEC", "PATHEXT", "WINDIR"} -- cgit v1.1 From a573530d500d7c22e27c0727b1f7abcbc0b73e1d Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Mon, 26 Oct 2020 17:48:32 +0000 Subject: syscall: import additional BSD-specific syscall wrappers Import additional code from upstream for handing system calls on BSD systems. This makes the syscall package on NetBSD complete enough to compile the standard library. Updates golang/go#38538. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/265123 --- libgo/go/syscall/libcall_bsd.go | 113 +++++++++++++++++++++++++++++++++++++ libgo/go/syscall/syscall_netbsd.go | 28 +++++++++ 2 files changed, 141 insertions(+) create mode 100644 libgo/go/syscall/libcall_bsd.go (limited to 'libgo/go') diff --git a/libgo/go/syscall/libcall_bsd.go b/libgo/go/syscall/libcall_bsd.go new file mode 100644 index 0000000..f13d3bc --- /dev/null +++ b/libgo/go/syscall/libcall_bsd.go @@ -0,0 +1,113 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd solaris + +// BSD library calls. + +package syscall + +import ( + "unsafe" +) + +//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) +//sysctl(mib *_C_int, miblen uintptr, old *byte, oldlen *uintptr, new *byte, newlen uintptr) _C_int + +//sysnb raw_ptrace(request int, pid int, addr uintptr, data uintptr) (err Errno) +//ptrace(request _C_int, pid Pid_t, addr *byte, data _C_int) _C_int + +//sys paccept(fd int, rsa *RawSockaddrAny, addrlen *Socklen_t, sigmask *_sigset_t, flags int) (nfd int, err error) +//paccept(s _C_int, rsa *RawSockaddrAny, addrlen *Socklen_t, sigmask *_sigset_t, flags int) _C_int + +//sys Flock(fd int, how int) (err error) +//flock(fd _C_int, how _C_int) _C_int + +func ReadDirent(fd int, buf []byte) (n int, err error) { + // Final argument is (basep *uintptr) and the syscall doesn't take nil. + // 64 bits should be enough. (32 bits isn't even on 386). Since the + // actual system call is getdirentries64, 64 is a good guess. + // TODO(rsc): Can we use a single global basep for all calls? + var base = (*uintptr)(unsafe.Pointer(new(uint64))) + return Getdirentries(fd, buf, base) +} + +func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) { + var rsa RawSockaddrAny + var len Socklen_t = SizeofSockaddrAny + nfd, err = paccept(fd, &rsa, &len, nil, flags) + if err != nil { + return + } + if len > SizeofSockaddrAny { + panic("RawSockaddrAny too small") + } + sa, err = anyToSockaddr(&rsa) + if err != nil { + Close(nfd) + nfd = 0 + } + return +} + +//sysnb pipe2(p *[2]_C_int, flags int) (err error) +//pipe2(p *[2]_C_int, flags _C_int) _C_int +func Pipe2(p []int, flags int) (err error) { + if len(p) != 2 { + return EINVAL + } + var pp [2]_C_int + err = pipe2(&pp, flags) + p[0] = int(pp[0]) + p[1] = int(pp[1]) + return +} + +func Sysctl(name string) (value string, err error) { + // Translate name to mib number. + mib, err := nametomib(name) + if err != nil { + return "", err + } + + // Find size. + n := uintptr(0) + if err = sysctl(mib, nil, &n, nil, 0); err != nil { + return "", err + } + if n == 0 { + return "", nil + } + + // Read into buffer of that size. + buf := make([]byte, n) + if err = sysctl(mib, &buf[0], &n, nil, 0); err != nil { + return "", err + } + + // Throw away terminating NUL. + if n > 0 && buf[n-1] == '\x00' { + n-- + } + return string(buf[0:n]), nil +} + +func SysctlUint32(name string) (value uint32, err error) { + // Translate name to mib number. + mib, err := nametomib(name) + if err != nil { + return 0, err + } + + // Read into buffer of that size. + n := uintptr(4) + buf := make([]byte, 4) + if err = sysctl(mib, &buf[0], &n, nil, 0); err != nil { + return 0, err + } + if n != 4 { + return 0, EIO + } + return *(*uint32)(unsafe.Pointer(&buf[0])), nil +} diff --git a/libgo/go/syscall/syscall_netbsd.go b/libgo/go/syscall/syscall_netbsd.go index bbc6799..c3a79e3 100644 --- a/libgo/go/syscall/syscall_netbsd.go +++ b/libgo/go/syscall/syscall_netbsd.go @@ -18,6 +18,34 @@ func direntNamlen(buf []byte) (uint64, bool) { return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) } +//sys Getdents(fd int, buf []byte) (n int, err error) +//getdents(fd _C_int, buf *byte, nbytes uintptr) _C_int + +func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { + n, err = Getdents(fd, buf) + if err != nil || basep == nil { + return + } + + var off int64 + off, err = Seek(fd, 0, 1 /* SEEK_CUR */) + if err != nil { + *basep = ^uintptr(0) + return + } + *basep = uintptr(off) + if unsafe.Sizeof(*basep) == 8 { + return + } + if off>>32 != 0 { + // We can't stuff the offset back into a uintptr, so any + // future calls would be suspect. Generate an error. + // EIO is allowed by getdirentries. + err = EIO + } + return +} + func sysctlNodes(mib []_C_int) (nodes []Sysctlnode, err error) { var olen uintptr -- cgit v1.1 From b7ac5fdbe7352bd33f6e9f8629d1140f278060cb Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 26 Oct 2020 16:48:03 -0700 Subject: compiler, go/internal/gccgoimporter: export notinheap annotation This is the gofrontend version of https://golang.org/cl/259297. This is required now because that change is in the 1.15.3 release. This requires changing the go/internal/gccgoimporter package, to skip the new annotation. This change will need to be ported to the gc and x/tools repos. For golang/go#41761 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/265258 --- libgo/go/go/internal/gccgoimporter/parser.go | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'libgo/go') diff --git a/libgo/go/go/internal/gccgoimporter/parser.go b/libgo/go/go/internal/gccgoimporter/parser.go index e2ef33f..1b1d07d 100644 --- a/libgo/go/go/internal/gccgoimporter/parser.go +++ b/libgo/go/go/internal/gccgoimporter/parser.go @@ -517,6 +517,13 @@ func (p *parser) parseNamedType(nlist []interface{}) types.Type { p.errorf("%v has nil type", obj) } + if p.tok == scanner.Ident && p.lit == "notinheap" { + p.next() + // The go/types package has no way of recording that + // this type is marked notinheap. Presumably no user + // of this package actually cares. + } + // type alias if p.tok == '=' { p.next() -- cgit v1.1 From 668894d7b584b40ddb46e9e2e2ffa637f4d732e5 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 24 Oct 2020 14:47:44 -0700 Subject: libgo: update to Go 1.15.3 release Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/265717 --- libgo/go/bytes/bytes.go | 50 +++++---- libgo/go/cmd/cgo/gcc.go | 15 +++ libgo/go/cmd/cgo/main.go | 3 +- libgo/go/cmd/cgo/out.go | 3 + libgo/go/cmd/go/internal/base/goflags.go | 17 +++ libgo/go/cmd/go/internal/version/version.go | 9 +- libgo/go/cmd/go/internal/work/init.go | 22 +--- libgo/go/cmd/go/testdata/script/version.txt | 6 ++ libgo/go/internal/bytealg/index_generic.go | 38 +------ libgo/go/internal/poll/fd_unix.go | 12 +-- libgo/go/runtime/chan.go | 22 ++++ libgo/go/runtime/chan_test.go | 56 ++++++++++ libgo/go/runtime/export_test.go | 24 +++-- libgo/go/runtime/internal/atomic/atomic_test.go | 10 ++ libgo/go/runtime/mpagealloc.go | 13 +++ libgo/go/runtime/proc_test.go | 10 +- libgo/go/runtime/runtime2.go | 9 +- libgo/go/runtime/select.go | 19 ++++ libgo/go/runtime/trace/trace_stack_test.go | 1 + libgo/go/testing/benchmark.go | 18 ++-- libgo/go/testing/sub_test.go | 19 +++- libgo/go/testing/testing.go | 138 +++++++++++------------- 22 files changed, 329 insertions(+), 185 deletions(-) (limited to 'libgo/go') diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go index aa07b9f..ce52649f1 100644 --- a/libgo/go/bytes/bytes.go +++ b/libgo/go/bytes/bytes.go @@ -227,19 +227,26 @@ func IndexAny(s []byte, chars string) int { continue } r, width = utf8.DecodeRune(s[i:]) - if r == utf8.RuneError { - for _, r = range chars { - if r == utf8.RuneError { + if r != utf8.RuneError { + // r is 2 to 4 bytes + if len(chars) == width { + if chars == string(r) { return i } + continue + } + // Use bytealg.IndexString for performance if available. + if bytealg.MaxLen >= width { + if bytealg.IndexString(chars, string(r)) >= 0 { + return i + } + continue } - continue } - // r is 2 to 4 bytes. Using strings.Index is more reasonable, but as the bytes - // package should not import the strings package, use bytealg.IndexString - // instead. And this does not seem to lose much performance. - if chars == string(r) || bytealg.IndexString(chars, string(r)) >= 0 { - return i + for _, ch := range chars { + if r == ch { + return i + } } } return -1 @@ -304,19 +311,26 @@ func LastIndexAny(s []byte, chars string) int { } r, size := utf8.DecodeLastRune(s[:i]) i -= size - if r == utf8.RuneError { - for _, r = range chars { - if r == utf8.RuneError { + if r != utf8.RuneError { + // r is 2 to 4 bytes + if len(chars) == size { + if chars == string(r) { return i } + continue + } + // Use bytealg.IndexString for performance if available. + if bytealg.MaxLen >= size { + if bytealg.IndexString(chars, string(r)) >= 0 { + return i + } + continue } - continue } - // r is 2 to 4 bytes. Using strings.Index is more reasonable, but as the bytes - // package should not import the strings package, use bytealg.IndexString - // instead. And this does not seem to lose much performance. - if chars == string(r) || bytealg.IndexString(chars, string(r)) >= 0 { - return i + for _, ch := range chars { + if r == ch { + return i + } } } return -1 diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go index f774cbb..37bafcf 100644 --- a/libgo/go/cmd/cgo/gcc.go +++ b/libgo/go/cmd/cgo/gcc.go @@ -2459,6 +2459,18 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ tt := *t tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}} tt.Go = c.Ident("struct{}") + if dt.Kind == "struct" { + // We don't know what the representation of this struct is, so don't let + // anyone allocate one on the Go side. As a side effect of this annotation, + // pointers to this type will not be considered pointers in Go. They won't + // get writebarrier-ed or adjusted during a stack copy. This should handle + // all the cases badPointerTypedef used to handle, but hopefully will + // continue to work going forward without any more need for cgo changes. + tt.NotInHeap = true + // TODO: we should probably do the same for unions. Unions can't live + // on the Go heap, right? It currently doesn't work for unions because + // they are defined as a type alias for struct{}, not a defined type. + } typedef[name.Name] = &tt break } @@ -2529,6 +2541,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ } t.Go = name t.BadPointer = sub.BadPointer + t.NotInHeap = sub.NotInHeap if unionWithPointer[sub.Go] { unionWithPointer[t.Go] = true } @@ -2539,6 +2552,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ tt := *t tt.Go = sub.Go tt.BadPointer = sub.BadPointer + tt.NotInHeap = sub.NotInHeap typedef[name.Name] = &tt } @@ -3047,6 +3061,7 @@ func (c *typeConv) anonymousStructTypedef(dt *dwarf.TypedefType) bool { // non-pointers in this type. // TODO: Currently our best solution is to find these manually and list them as // they come up. A better solution is desired. +// Note: DEPRECATED. There is now a better solution. Search for NotInHeap in this file. func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool { if c.badCFType(dt) { return true diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go index 6de6d69..7fc2508 100644 --- a/libgo/go/cmd/cgo/main.go +++ b/libgo/go/cmd/cgo/main.go @@ -151,7 +151,8 @@ type Type struct { Go ast.Expr EnumValues map[string]int64 Typedef string - BadPointer bool + BadPointer bool // this pointer type should be represented as a uintptr (deprecated) + NotInHeap bool // this type should have a go:notinheap annotation } // A FuncType collects information about a function type in both the C and Go worlds. diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go index 1d23fc1..dd03f7d 100644 --- a/libgo/go/cmd/cgo/out.go +++ b/libgo/go/cmd/cgo/out.go @@ -113,6 +113,9 @@ func (p *Package) writeDefs() { sort.Strings(typedefNames) for _, name := range typedefNames { def := typedef[name] + if def.NotInHeap { + fmt.Fprintf(fgo2, "//go:notinheap\n") + } fmt.Fprintf(fgo2, "type %s ", name) // We don't have source info for these types, so write them out without source info. // Otherwise types would look like: diff --git a/libgo/go/cmd/go/internal/base/goflags.go b/libgo/go/cmd/go/internal/base/goflags.go index 3476613..f29cc3c 100644 --- a/libgo/go/cmd/go/internal/base/goflags.go +++ b/libgo/go/cmd/go/internal/base/goflags.go @@ -153,3 +153,20 @@ func SetFromGOFLAGS(flags *flag.FlagSet) { } } } + +// InGOFLAGS returns whether GOFLAGS contains the given flag, such as "-mod". +func InGOFLAGS(flag string) bool { + for _, goflag := range GOFLAGS() { + name := goflag + if strings.HasPrefix(name, "--") { + name = name[1:] + } + if i := strings.Index(name, "="); i >= 0 { + name = name[:i] + } + if name == flag { + return true + } + } + return false +} diff --git a/libgo/go/cmd/go/internal/version/version.go b/libgo/go/cmd/go/internal/version/version.go index ac2ae50..a5b1365 100644 --- a/libgo/go/cmd/go/internal/version/version.go +++ b/libgo/go/cmd/go/internal/version/version.go @@ -53,7 +53,14 @@ var ( func runVersion(cmd *base.Command, args []string) { if len(args) == 0 { - if *versionM || *versionV { + // If any of this command's flags were passed explicitly, error + // out, because they only make sense with arguments. + // + // Don't error if the flags came from GOFLAGS, since that can be + // a reasonable use case. For example, imagine GOFLAGS=-v to + // turn "verbose mode" on for all Go commands, which should not + // break "go version". + if (!base.InGOFLAGS("-m") && *versionM) || (!base.InGOFLAGS("-v") && *versionV) { fmt.Fprintf(os.Stderr, "go version: flags can only be used with arguments\n") base.SetExitStatus(2) return diff --git a/libgo/go/cmd/go/internal/work/init.go b/libgo/go/cmd/go/internal/work/init.go index dad3b10..c168364 100644 --- a/libgo/go/cmd/go/internal/work/init.go +++ b/libgo/go/cmd/go/internal/work/init.go @@ -254,34 +254,18 @@ func buildModeInit() { case "": // ok case "readonly", "vendor", "mod": - if !cfg.ModulesEnabled && !inGOFLAGS("-mod") { + if !cfg.ModulesEnabled && !base.InGOFLAGS("-mod") { base.Fatalf("build flag -mod=%s only valid when using modules", cfg.BuildMod) } default: base.Fatalf("-mod=%s not supported (can be '', 'mod', 'readonly', or 'vendor')", cfg.BuildMod) } if !cfg.ModulesEnabled { - if cfg.ModCacheRW && !inGOFLAGS("-modcacherw") { + if cfg.ModCacheRW && !base.InGOFLAGS("-modcacherw") { base.Fatalf("build flag -modcacherw only valid when using modules") } - if cfg.ModFile != "" && !inGOFLAGS("-mod") { + if cfg.ModFile != "" && !base.InGOFLAGS("-mod") { base.Fatalf("build flag -modfile only valid when using modules") } } } - -func inGOFLAGS(flag string) bool { - for _, goflag := range base.GOFLAGS() { - name := goflag - if strings.HasPrefix(name, "--") { - name = name[1:] - } - if i := strings.Index(name, "="); i >= 0 { - name = name[:i] - } - if name == flag { - return true - } - } - return false -} diff --git a/libgo/go/cmd/go/testdata/script/version.txt b/libgo/go/cmd/go/testdata/script/version.txt index 0123ac6..87cb6be 100644 --- a/libgo/go/cmd/go/testdata/script/version.txt +++ b/libgo/go/cmd/go/testdata/script/version.txt @@ -9,6 +9,12 @@ stderr 'with arguments' ! go version -v stderr 'with arguments' +# Neither of the two flags above should be an issue via GOFLAGS. +env GOFLAGS='-m -v' +go version +stdout '^go version' +env GOFLAGS= + env GO111MODULE=on # Skip the builds below if we are running in short mode. [short] skip diff --git a/libgo/go/internal/bytealg/index_generic.go b/libgo/go/internal/bytealg/index_generic.go index 3dc1c6b..c595c23 100644 --- a/libgo/go/internal/bytealg/index_generic.go +++ b/libgo/go/internal/bytealg/index_generic.go @@ -17,42 +17,8 @@ func Index(a, b []byte) int { // IndexString returns the index of the first instance of b in a, or -1 if b is not present in a. // Requires 2 <= len(b) <= MaxLen. -func IndexString(s, substr string) int { - // This is a partial copy of strings.Index, here because bytes.IndexAny and bytes.LastIndexAny - // call bytealg.IndexString. Some platforms have an optimized assembly version of this function. - // This implementation is used for those that do not. Although the pure Go implementation here - // works for the case of len(b) > MaxLen, we do not require that its assembly implementation also - // supports the case of len(b) > MaxLen. And we do not guarantee that this function supports the - // case of len(b) > MaxLen. - n := len(substr) - c0 := substr[0] - c1 := substr[1] - i := 0 - t := len(s) - n + 1 - fails := 0 - for i < t { - if s[i] != c0 { - o := IndexByteString(s[i:t], c0) - if o < 0 { - return -1 - } - i += o - } - if s[i+1] == c1 && s[i:i+n] == substr { - return i - } - i++ - fails++ - if fails >= 4+i>>4 && i < t { - // See comment in src/bytes/bytes.go. - j := IndexRabinKarp(s[i:], substr) - if j < 0 { - return -1 - } - return i + j - } - } - return -1 +func IndexString(a, b string) int { + panic("unimplemented") } // Cutover reports the number of failures of IndexByte we should tolerate diff --git a/libgo/go/internal/poll/fd_unix.go b/libgo/go/internal/poll/fd_unix.go index f177ccf..10cf173 100644 --- a/libgo/go/internal/poll/fd_unix.go +++ b/libgo/go/internal/poll/fd_unix.go @@ -152,7 +152,7 @@ func (fd *FD) Read(p []byte) (int, error) { p = p[:maxRW] } for { - n, err := ignoringEINTR(syscall.Read, fd.Sysfd, p) + n, err := ignoringEINTR(func() (int, error) { return syscall.Read(fd.Sysfd, p) }) if err != nil { n = 0 if err == syscall.EAGAIN && fd.pd.pollable() { @@ -264,7 +264,7 @@ func (fd *FD) Write(p []byte) (int, error) { if fd.IsStream && max-nn > maxRW { max = nn + maxRW } - n, err := ignoringEINTR(syscall.Write, fd.Sysfd, p[nn:max]) + n, err := ignoringEINTR(func() (int, error) { return syscall.Write(fd.Sysfd, p[nn:max]) }) if n > 0 { nn += n } @@ -423,7 +423,7 @@ func (fd *FD) ReadDirent(buf []byte) (int, error) { } defer fd.decref() for { - n, err := ignoringEINTR(syscall.ReadDirent, fd.Sysfd, buf) + n, err := ignoringEINTR(func() (int, error) { return syscall.ReadDirent(fd.Sysfd, buf) }) if err != nil { n = 0 if err == syscall.EAGAIN && fd.pd.pollable() { @@ -514,7 +514,7 @@ func (fd *FD) WriteOnce(p []byte) (int, error) { return 0, err } defer fd.writeUnlock() - return ignoringEINTR(syscall.Write, fd.Sysfd, p) + return ignoringEINTR(func() (int, error) { return syscall.Write(fd.Sysfd, p) }) } // RawRead invokes the user-defined function f for a read operation. @@ -562,9 +562,9 @@ func (fd *FD) RawWrite(f func(uintptr) bool) error { // installed without setting SA_RESTART. None of these are the common case, // but there are enough of them that it seems that we can't avoid // an EINTR loop. -func ignoringEINTR(fn func(fd int, p []byte) (int, error), fd int, p []byte) (int, error) { +func ignoringEINTR(fn func() (int, error)) (int, error) { for { - n, err := fn(fd, p) + n, err := fn() if err != syscall.EINTR { return n, err } diff --git a/libgo/go/runtime/chan.go b/libgo/go/runtime/chan.go index de1d80a..b909d47 100644 --- a/libgo/go/runtime/chan.go +++ b/libgo/go/runtime/chan.go @@ -267,6 +267,11 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool { gp.waiting = mysg gp.param = nil c.sendq.enqueue(mysg) + // Signal to anyone trying to shrink our stack that we're about + // to park on a channel. The window between when this G's status + // changes and when we set gp.activeStackChans is not safe for + // stack shrinking. + atomic.Store8(&gp.parkingOnChan, 1) gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanSend, traceEvGoBlockSend, 2) // Ensure the value being sent is kept alive until the // receiver copies it out. The sudog has a pointer to the @@ -586,6 +591,11 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) mysg.c = c gp.param = nil c.recvq.enqueue(mysg) + // Signal to anyone trying to shrink our stack that we're about + // to park on a channel. The window between when this G's status + // changes and when we set gp.activeStackChans is not safe for + // stack shrinking. + atomic.Store8(&gp.parkingOnChan, 1) gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanReceive, traceEvGoBlockRecv, 2) // someone woke us up @@ -663,7 +673,19 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) { func chanparkcommit(gp *g, chanLock unsafe.Pointer) bool { // There are unlocked sudogs that point into gp's stack. Stack // copying must lock the channels of those sudogs. + // Set activeStackChans here instead of before we try parking + // because we could self-deadlock in stack growth on the + // channel lock. gp.activeStackChans = true + // Mark that it's safe for stack shrinking to occur now, + // because any thread acquiring this G's stack for shrinking + // is guaranteed to observe activeStackChans after this store. + atomic.Store8(&gp.parkingOnChan, 0) + // Make sure we unlock after setting activeStackChans and + // unsetting parkingOnChan. The moment we unlock chanLock + // we risk gp getting readied by a channel operation and + // so gp could continue running before everything before + // the unlock is visible (even to gp itself). unlock((*mutex)(chanLock)) return true } diff --git a/libgo/go/runtime/chan_test.go b/libgo/go/runtime/chan_test.go index ac81d40..85d3e04 100644 --- a/libgo/go/runtime/chan_test.go +++ b/libgo/go/runtime/chan_test.go @@ -628,6 +628,62 @@ func TestShrinkStackDuringBlockedSend(t *testing.T) { <-done } +func TestNoShrinkStackWhileParking(t *testing.T) { + // The goal of this test is to trigger a "racy sudog adjustment" + // throw. Basically, there's a window between when a goroutine + // becomes available for preemption for stack scanning (and thus, + // stack shrinking) but before the goroutine has fully parked on a + // channel. See issue 40641 for more details on the problem. + // + // The way we try to induce this failure is to set up two + // goroutines: a sender and a reciever that communicate across + // a channel. We try to set up a situation where the sender + // grows its stack temporarily then *fully* blocks on a channel + // often. Meanwhile a GC is triggered so that we try to get a + // mark worker to shrink the sender's stack and race with the + // sender parking. + // + // Unfortunately the race window here is so small that we + // either need a ridiculous number of iterations, or we add + // "usleep(1000)" to park_m, just before the unlockf call. + const n = 10 + send := func(c chan<- int, done chan struct{}) { + for i := 0; i < n; i++ { + c <- i + // Use lots of stack briefly so that + // the GC is going to want to shrink us + // when it scans us. Make sure not to + // do any function calls otherwise + // in order to avoid us shrinking ourselves + // when we're preempted. + stackGrowthRecursive(20) + } + done <- struct{}{} + } + recv := func(c <-chan int, done chan struct{}) { + for i := 0; i < n; i++ { + // Sleep here so that the sender always + // fully blocks. + time.Sleep(10 * time.Microsecond) + <-c + } + done <- struct{}{} + } + for i := 0; i < n*20; i++ { + c := make(chan int) + done := make(chan struct{}) + go recv(c, done) + go send(c, done) + // Wait a little bit before triggering + // the GC to make sure the sender and + // reciever have gotten into their groove. + time.Sleep(50 * time.Microsecond) + runtime.GC() + <-done + <-done + } +} + func TestSelectDuplicateChannel(t *testing.T) { // This test makes sure we can queue a G on // the same channel multiple times. diff --git a/libgo/go/runtime/export_test.go b/libgo/go/runtime/export_test.go index 482d014..369230a 100644 --- a/libgo/go/runtime/export_test.go +++ b/libgo/go/runtime/export_test.go @@ -355,7 +355,11 @@ func ReadMemStatsSlow() (base, slow MemStats) { } for i := mheap_.pages.start; i < mheap_.pages.end; i++ { - pg := mheap_.pages.chunkOf(i).scavenged.popcntRange(0, pallocChunkPages) + chunk := mheap_.pages.tryChunkOf(i) + if chunk == nil { + continue + } + pg := chunk.scavenged.popcntRange(0, pallocChunkPages) slow.HeapReleased += uint64(pg) * pageSize } for _, p := range allp { @@ -752,11 +756,7 @@ func (p *PageAlloc) InUse() []AddrRange { // Returns nil if the PallocData's L2 is missing. func (p *PageAlloc) PallocData(i ChunkIdx) *PallocData { ci := chunkIdx(i) - l2 := (*pageAlloc)(p).chunks[ci.l1()] - if l2 == nil { - return nil - } - return (*PallocData)(&l2[ci.l2()]) + return (*PallocData)((*pageAlloc)(p).tryChunkOf(ci)) } // AddrRange represents a range over addresses. @@ -896,7 +896,10 @@ func CheckScavengedBitsCleared(mismatches []BitsMismatch) (n int, ok bool) { lock(&mheap_.lock) chunkLoop: for i := mheap_.pages.start; i < mheap_.pages.end; i++ { - chunk := mheap_.pages.chunkOf(i) + chunk := mheap_.pages.tryChunkOf(i) + if chunk == nil { + continue + } for j := 0; j < pallocChunkPages/64; j++ { // Run over each 64-bit bitmap section and ensure // scavenged is being cleared properly on allocation. @@ -977,10 +980,9 @@ func MapHashCheck(m interface{}, k interface{}) (uintptr, uintptr) { } func MSpanCountAlloc(bits []byte) int { - s := mspan{ - nelems: uintptr(len(bits) * 8), - gcmarkBits: (*gcBits)(unsafe.Pointer(&bits[0])), - } + s := (*mspan)(mheap_.spanalloc.alloc()) + s.nelems = uintptr(len(bits) * 8) + s.gcmarkBits = (*gcBits)(unsafe.Pointer(&bits[0])) return s.countAlloc() } diff --git a/libgo/go/runtime/internal/atomic/atomic_test.go b/libgo/go/runtime/internal/atomic/atomic_test.go index 0c1125c..b0a8fa0 100644 --- a/libgo/go/runtime/internal/atomic/atomic_test.go +++ b/libgo/go/runtime/internal/atomic/atomic_test.go @@ -220,3 +220,13 @@ func TestBitwiseContended(t *testing.T) { } } } + +func TestStorepNoWB(t *testing.T) { + var p [2]*int + for i := range p { + atomic.StorepNoWB(unsafe.Pointer(&p[i]), unsafe.Pointer(new(int))) + } + if p[0] == p[1] { + t.Error("Bad escape analysis of StorepNoWB") + } +} diff --git a/libgo/go/runtime/mpagealloc.go b/libgo/go/runtime/mpagealloc.go index 8b3c62c..c90a637 100644 --- a/libgo/go/runtime/mpagealloc.go +++ b/libgo/go/runtime/mpagealloc.go @@ -326,7 +326,20 @@ func (s *pageAlloc) init(mheapLock *mutex, sysStat *uint64) { s.scav.scavLWM = maxSearchAddr } +// tryChunkOf returns the bitmap data for the given chunk. +// +// Returns nil if the chunk data has not been mapped. +func (s *pageAlloc) tryChunkOf(ci chunkIdx) *pallocData { + l2 := s.chunks[ci.l1()] + if l2 == nil { + return nil + } + return &l2[ci.l2()] +} + // chunkOf returns the chunk at the given chunk index. +// +// The chunk index must be valid or this method may throw. func (s *pageAlloc) chunkOf(ci chunkIdx) *pallocData { return &s.chunks[ci.l1()][ci.l2()] } diff --git a/libgo/go/runtime/proc_test.go b/libgo/go/runtime/proc_test.go index b9828d9..a8f0dc3 100644 --- a/libgo/go/runtime/proc_test.go +++ b/libgo/go/runtime/proc_test.go @@ -529,9 +529,17 @@ func BenchmarkPingPongHog(b *testing.B) { <-done } +var padData [128]uint64 + func stackGrowthRecursive(i int) { var pad [128]uint64 - if i != 0 && pad[0] == 0 { + pad = padData + for j := range pad { + if pad[j] != 0 { + return + } + } + if i != 0 { stackGrowthRecursive(i - 1) } } diff --git a/libgo/go/runtime/runtime2.go b/libgo/go/runtime/runtime2.go index 5029dba..bf3fbac 100644 --- a/libgo/go/runtime/runtime2.go +++ b/libgo/go/runtime/runtime2.go @@ -450,6 +450,10 @@ type g struct { // copying needs to acquire channel locks to protect these // areas of the stack. activeStackChans bool + // parkingOnChan indicates that the goroutine is about to + // park on a chansend or chanrecv. Used to signal an unsafe point + // for stack shrinking. It's a boolean value, but is updated atomically. + parkingOnChan uint8 raceignore int8 // ignore race detection events sysblocktraced bool // StartTrace has emitted EvGoInSyscall about this goroutine @@ -940,11 +944,6 @@ type _defer struct { // panics // This is the gccgo version. -// -// This is marked go:notinheap because _panic values must only ever -// live on the stack. -// -//go:notinheap type _panic struct { // The next entry in the stack. link *_panic diff --git a/libgo/go/runtime/select.go b/libgo/go/runtime/select.go index cf5d0c7..c8910b8 100644 --- a/libgo/go/runtime/select.go +++ b/libgo/go/runtime/select.go @@ -7,6 +7,7 @@ package runtime // This file contains the implementation of Go select statements. import ( + "runtime/internal/atomic" "unsafe" ) @@ -72,7 +73,20 @@ func selunlock(scases []scase, lockorder []uint16) { func selparkcommit(gp *g, _ unsafe.Pointer) bool { // There are unlocked sudogs that point into gp's stack. Stack // copying must lock the channels of those sudogs. + // Set activeStackChans here instead of before we try parking + // because we could self-deadlock in stack growth on a + // channel lock. gp.activeStackChans = true + // Mark that it's safe for stack shrinking to occur now, + // because any thread acquiring this G's stack for shrinking + // is guaranteed to observe activeStackChans after this store. + atomic.Store8(&gp.parkingOnChan, 0) + // Make sure we unlock after setting activeStackChans and + // unsetting parkingOnChan. The moment we unlock any of the + // channel locks we risk gp getting readied by a channel operation + // and so gp could continue running before everything before the + // unlock is visible (even to gp itself). + // This must not access gp's stack (see gopark). In // particular, it must not access the *hselect. That's okay, // because by the time this is called, gp.waiting has all @@ -313,6 +327,11 @@ loop: // wait for someone to wake us up gp.param = nil + // Signal to anyone trying to shrink our stack that we're about + // to park on a channel. The window between when this G's status + // changes and when we set gp.activeStackChans is not safe for + // stack shrinking. + atomic.Store8(&gp.parkingOnChan, 1) gopark(selparkcommit, nil, waitReasonSelect, traceEvGoBlockSelect, 1) gp.activeStackChans = false diff --git a/libgo/go/runtime/trace/trace_stack_test.go b/libgo/go/runtime/trace/trace_stack_test.go index cfc0419..f856fdc 100644 --- a/libgo/go/runtime/trace/trace_stack_test.go +++ b/libgo/go/runtime/trace/trace_stack_test.go @@ -252,6 +252,7 @@ func TestTraceSymbolize(t *testing.T) { {trace.EvGoSysCall, []frame{ {"syscall.read", 0}, {"syscall.Read", 0}, + {"internal/poll.(*FD).Read.func1", 0}, {"internal/poll.ignoringEINTR", 0}, {"internal/poll.(*FD).Read", 0}, {"os.(*File).read", 0}, diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go index 5276600..e9687bf 100644 --- a/libgo/go/testing/benchmark.go +++ b/libgo/go/testing/benchmark.go @@ -242,7 +242,7 @@ func (b *B) run1() bool { if b.skipped { tag = "SKIP" } - if b.chatty && (len(b.output) > 0 || b.finished) { + if b.chatty != nil && (len(b.output) > 0 || b.finished) { b.trimOutput() fmt.Fprintf(b.w, "--- %s: %s\n%s", tag, b.name, b.output) } @@ -523,10 +523,9 @@ func runBenchmarks(importPath string, matchString func(pat, str string) (bool, e } main := &B{ common: common{ - name: "Main", - w: os.Stdout, - chatty: *chatty, - bench: true, + name: "Main", + w: os.Stdout, + bench: true, }, importPath: importPath, benchFunc: func(b *B) { @@ -537,6 +536,9 @@ func runBenchmarks(importPath string, matchString func(pat, str string) (bool, e benchTime: benchTime, context: ctx, } + if Verbose() { + main.chatty = newChattyPrinter(main.w) + } main.runN(1) return !main.failed } @@ -549,7 +551,7 @@ func (ctx *benchContext) processBench(b *B) { benchName := benchmarkName(b.name, procs) // If it's chatty, we've already printed this information. - if !b.chatty { + if b.chatty == nil { fmt.Fprintf(b.w, "%-*s\t", ctx.maxLen, benchName) } // Recompute the running time for all but the first iteration. @@ -576,7 +578,7 @@ func (ctx *benchContext) processBench(b *B) { continue } results := r.String() - if b.chatty { + if b.chatty != nil { fmt.Fprintf(b.w, "%-*s\t", ctx.maxLen, benchName) } if *benchmarkMemory || b.showAllocResult { @@ -639,7 +641,7 @@ func (b *B) Run(name string, f func(b *B)) bool { atomic.StoreInt32(&sub.hasSub, 1) } - if b.chatty { + if b.chatty != nil { labelsOnce.Do(func() { fmt.Printf("goos: %s\n", runtime.GOOS) fmt.Printf("goarch: %s\n", runtime.GOARCH) diff --git a/libgo/go/testing/sub_test.go b/libgo/go/testing/sub_test.go index 8eb0084..5ed3fc4 100644 --- a/libgo/go/testing/sub_test.go +++ b/libgo/go/testing/sub_test.go @@ -483,10 +483,12 @@ func TestTRun(t *T) { signal: make(chan bool), name: "Test", w: buf, - chatty: tc.chatty, }, context: ctx, } + if tc.chatty { + root.chatty = newChattyPrinter(root.w) + } ok := root.Run(tc.desc, tc.f) ctx.release() @@ -665,11 +667,13 @@ func TestBRun(t *T) { signal: make(chan bool), name: "root", w: buf, - chatty: tc.chatty, }, benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure. benchTime: benchTimeFlag{d: 1 * time.Microsecond}, } + if tc.chatty { + root.chatty = newChattyPrinter(root.w) + } root.runN(1) if ok != !tc.failed { t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, !tc.failed) @@ -741,9 +745,13 @@ func TestParallelSub(t *T) { } } -type funcWriter func([]byte) (int, error) +type funcWriter struct { + write func([]byte) (int, error) +} -func (fw funcWriter) Write(b []byte) (int, error) { return fw(b) } +func (fw *funcWriter) Write(b []byte) (int, error) { + return fw.write(b) +} func TestRacyOutput(t *T) { var runs int32 // The number of running Writes @@ -761,9 +769,10 @@ func TestRacyOutput(t *T) { var wg sync.WaitGroup root := &T{ - common: common{w: funcWriter(raceDetector), chatty: true}, + common: common{w: &funcWriter{raceDetector}}, context: newTestContext(1, newMatcher(regexp.MatchString, "", "")), } + root.chatty = newChattyPrinter(root.w) root.Run("", func(t *T) { for i := 0; i < 100; i++ { wg.Add(1) diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go index fe6929d..80282fc 100644 --- a/libgo/go/testing/testing.go +++ b/libgo/go/testing/testing.go @@ -325,7 +325,6 @@ var ( cpuListStr *string parallel *int testlog *string - printer *testPrinter haveExamples bool // are there examples? @@ -335,55 +334,45 @@ var ( numFailed uint32 // number of test failures ) -type testPrinter struct { - chatty bool - +type chattyPrinter struct { + w io.Writer lastNameMu sync.Mutex // guards lastName lastName string // last printed test name in chatty mode } -func newTestPrinter(chatty bool) *testPrinter { - return &testPrinter{ - chatty: chatty, - } +func newChattyPrinter(w io.Writer) *chattyPrinter { + return &chattyPrinter{w: w} } -func (p *testPrinter) Print(testName, out string) { - p.Fprint(os.Stdout, testName, out) +// Updatef prints a message about the status of the named test to w. +// +// The formatted message must include the test name itself. +func (p *chattyPrinter) Updatef(testName, format string, args ...interface{}) { + p.lastNameMu.Lock() + defer p.lastNameMu.Unlock() + + // Since the message already implies an association with a specific new test, + // we don't need to check what the old test name was or log an extra CONT line + // for it. (We're updating it anyway, and the current message already includes + // the test name.) + p.lastName = testName + fmt.Fprintf(p.w, format, args...) } -func (p *testPrinter) Fprint(w io.Writer, testName, out string) { +// Printf prints a message, generated by the named test, that does not +// necessarily mention that tests's name itself. +func (p *chattyPrinter) Printf(testName, format string, args ...interface{}) { p.lastNameMu.Lock() defer p.lastNameMu.Unlock() - if !p.chatty || - strings.HasPrefix(out, "--- PASS: ") || - strings.HasPrefix(out, "--- FAIL: ") || - strings.HasPrefix(out, "--- SKIP: ") || - strings.HasPrefix(out, "=== RUN ") || - strings.HasPrefix(out, "=== CONT ") || - strings.HasPrefix(out, "=== PAUSE ") { - // If we're buffering test output (!p.chatty), we don't really care which - // test is emitting which line so long as they are serialized. - // - // If the message already implies an association with a specific new test, - // we don't need to check what the old test name was or log an extra CONT - // line for it. (We're updating it anyway, and the current message already - // includes the test name.) - p.lastName = testName - fmt.Fprint(w, out) - return - } - if p.lastName == "" { p.lastName = testName } else if p.lastName != testName { - // Always printed as-is, with 0 decoration or indentation. So, we skip - // printing to w. - fmt.Printf("=== CONT %s\n", testName) + fmt.Fprintf(p.w, "=== CONT %s\n", testName) p.lastName = testName } - fmt.Fprint(w, out) + + fmt.Fprintf(p.w, format, args...) } // The maximum number of stack frames to go through when skipping helper functions for @@ -405,12 +394,12 @@ type common struct { cleanupName string // Name of the cleanup function. cleanupPc []uintptr // The stack trace at the point where Cleanup was called. - chatty bool // A copy of the chatty flag. - bench bool // Whether the current test is a benchmark. - finished bool // Test function has completed. - hasSub int32 // Written atomically. - raceErrors int // Number of races detected during test. - runner string // Function name of tRunner running the test. + chatty *chattyPrinter // A copy of chattyPrinter, if the chatty flag is set. + bench bool // Whether the current test is a benchmark. + finished bool // Test function has completed. + hasSub int32 // Written atomically. + raceErrors int // Number of races detected during test. + runner string // Function name of tRunner running the test. parent *common level int // Nesting depth of test or benchmark. @@ -572,12 +561,31 @@ func (c *common) flushToParent(testName, format string, args ...interface{}) { p.mu.Lock() defer p.mu.Unlock() - printer.Fprint(p.w, testName, fmt.Sprintf(format, args...)) - c.mu.Lock() defer c.mu.Unlock() - io.Copy(p.w, bytes.NewReader(c.output)) - c.output = c.output[:0] + + if len(c.output) > 0 { + format += "%s" + args = append(args[:len(args):len(args)], c.output) + c.output = c.output[:0] // but why? + } + + if c.chatty != nil && p.w == c.chatty.w { + // We're flushing to the actual output, so track that this output is + // associated with a specific test (and, specifically, that the next output + // is *not* associated with that test). + // + // Moreover, if c.output is non-empty it is important that this write be + // atomic with respect to the output of other tests, so that we don't end up + // with confusing '=== CONT' lines in the middle of our '--- PASS' block. + // Neither humans nor cmd/test2json can parse those easily. + // (See https://golang.org/issue/40771.) + c.chatty.Updatef(testName, format, args...) + } else { + // We're flushing to the output buffer of the parent test, which will + // itself follow a test-name header when it is finally flushed to stdout. + fmt.Fprintf(p.w, format, args...) + } } type indenter struct { @@ -746,13 +754,13 @@ func (c *common) logDepth(s string, depth int) { } panic("Log in goroutine after " + c.name + " has completed") } else { - if c.chatty { + if c.chatty != nil { if c.bench { // Benchmarks don't print === CONT, so we should skip the test // printer and just print straight to stdout. fmt.Print(c.decorate(s, depth+1)) } else { - printer.Print(c.name, c.decorate(s, depth+1)) + c.chatty.Printf(c.name, "%s", c.decorate(s, depth+1)) } return @@ -1019,34 +1027,22 @@ func (t *T) Parallel() { t.parent.sub = append(t.parent.sub, t) t.raceErrors += race.Errors() - if t.chatty { - // Print directly to root's io.Writer so there is no delay. - root := t.parent - for ; root.parent != nil; root = root.parent { - } - root.mu.Lock() + if t.chatty != nil { // Unfortunately, even though PAUSE indicates that the named test is *no // longer* running, cmd/test2json interprets it as changing the active test // for the purpose of log parsing. We could fix cmd/test2json, but that // won't fix existing deployments of third-party tools that already shell // out to older builds of cmd/test2json — so merely fixing cmd/test2json // isn't enough for now. - printer.Fprint(root.w, t.name, fmt.Sprintf("=== PAUSE %s\n", t.name)) - root.mu.Unlock() + t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name) } t.signal <- true // Release calling test. <-t.parent.barrier // Wait for the parent test to complete. t.context.waitParallel() - if t.chatty { - // Print directly to root's io.Writer so there is no delay. - root := t.parent - for ; root.parent != nil; root = root.parent { - } - root.mu.Lock() - printer.Fprint(root.w, t.name, fmt.Sprintf("=== CONT %s\n", t.name)) - root.mu.Unlock() + if t.chatty != nil { + t.chatty.Updatef(t.name, "=== CONT %s\n", t.name) } t.start = time.Now() @@ -1197,14 +1193,8 @@ func (t *T) Run(name string, f func(t *T)) bool { } t.w = indenter{&t.common} - if t.chatty { - // Print directly to root's io.Writer so there is no delay. - root := t.parent - for ; root.parent != nil; root = root.parent { - } - root.mu.Lock() - printer.Fprint(root.w, t.name, fmt.Sprintf("=== RUN %s\n", t.name)) - root.mu.Unlock() + if t.chatty != nil { + t.chatty.Updatef(t.name, "=== RUN %s\n", t.name) } // Instead of reducing the running count of this test before calling the // tRunner and increasing it afterwards, we rely on tRunner keeping the @@ -1369,8 +1359,6 @@ func (m *M) Run() (code int) { flag.Parse() } - printer = newTestPrinter(Verbose()) - if *parallel < 1 { fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer") flag.Usage() @@ -1415,7 +1403,7 @@ func (t *T) report() { format := "--- %s: %s (%s)\n" if t.Failed() { t.flushToParent(t.name, format, "FAIL", t.name, dstr) - } else if t.chatty { + } else if t.chatty != nil { if t.Skipped() { t.flushToParent(t.name, format, "SKIP", t.name, dstr) } else { @@ -1476,10 +1464,12 @@ func runTests(matchString func(pat, str string) (bool, error), tests []InternalT signal: make(chan bool), barrier: make(chan bool), w: os.Stdout, - chatty: *chatty, }, context: ctx, } + if Verbose() { + t.chatty = newChattyPrinter(t.w) + } tRunner(t, func(t *T) { for _, test := range tests { t.Run(test.Name, test.F) -- cgit v1.1 From dfbadb8ce9f4a7278121ab92bf77bde0c1d3b641 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 28 Oct 2020 11:48:19 -0700 Subject: syscall: don't build libcall_bsd.go on solaris This new file was based on master sources that are built for *BSD but not Solaris Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/266017 --- libgo/go/syscall/libcall_bsd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libgo/go') diff --git a/libgo/go/syscall/libcall_bsd.go b/libgo/go/syscall/libcall_bsd.go index f13d3bc..1dd957c 100644 --- a/libgo/go/syscall/libcall_bsd.go +++ b/libgo/go/syscall/libcall_bsd.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 solaris +// +build darwin dragonfly freebsd netbsd openbsd // BSD library calls. -- cgit v1.1 From 0cdde1e7ae197366e17e5ef50bf68d4d5760df01 Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Mon, 26 Oct 2020 18:42:08 +0000 Subject: libgo: handle linking to NetBSD's versioned symbols On NetBSD, for backwards compatibility, various libc symbols are renamed to a symbol with a version suffix. For example, this is the (abbreviated) definition of sigaction: int sigaction(...) __asm__ ("__sigaction14") This poses a challenge for libgo, which attempts to link sigaction by way of an "//extern" comment: //extern sigaction func sigaction(...) This results in a reference to the deprecated compatibility symbol "sigaction", rather than the desired "__sigaction14" symbol. This patch introduces a new "//extern-sysinfo" comment to handle this situation. The new mklinknames.awk script scans a package for these comments and outputs a "//go:linkname" directive that links the wrapper to the correct versioned symbol, as determined by parsing the __asm__ annotation on the function's declaration in gen-sysinfo.go. For now, only the following packages are scanned by mklinknames.awk: os os/user runtime syscall gotools/: * Makefile.am (check-runtime): Add runtime_linknames.go to --extrafiles. * Makefile.in: Regenerate. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/265125 --- libgo/go/os/dir_regfile.go | 2 +- libgo/go/os/user/decls_unix.go | 10 +++++----- libgo/go/runtime/netpoll_kqueue.go | 4 ++-- libgo/go/runtime/os_gccgo.go | 4 ++-- libgo/go/runtime/os_netbsd.go | 8 ++++---- libgo/go/runtime/signal_gccgo.go | 22 +++++++++++----------- libgo/go/runtime/stubs2.go | 2 +- libgo/go/syscall/mksyscall.awk | 4 ++-- 8 files changed, 28 insertions(+), 28 deletions(-) (limited to 'libgo/go') diff --git a/libgo/go/os/dir_regfile.go b/libgo/go/os/dir_regfile.go index 1f18bab..b2e6623 100644 --- a/libgo/go/os/dir_regfile.go +++ b/libgo/go/os/dir_regfile.go @@ -15,5 +15,5 @@ package os import "syscall" -//extern readdir_r +//extern-sysinfo readdir_r func libc_readdir_r(*syscall.DIR, *syscall.Dirent, **syscall.Dirent) syscall.Errno diff --git a/libgo/go/os/user/decls_unix.go b/libgo/go/os/user/decls_unix.go index 276468c..6ffaced 100644 --- a/libgo/go/os/user/decls_unix.go +++ b/libgo/go/os/user/decls_unix.go @@ -11,17 +11,17 @@ import "syscall" // Declarations for the libc functions on most Unix systems. -//extern getpwnam_r +//extern-sysinfo getpwnam_r func libc_getpwnam_r(name *byte, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int -//extern getpwuid_r +//extern-sysinfo getpwuid_r func libc_getpwuid_r(uid syscall.Uid_t, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int -//extern getgrnam_r +//extern-sysinfo getgrnam_r func libc_getgrnam_r(name *byte, grp *syscall.Group, buf *byte, buflen syscall.Size_t, result **syscall.Group) int -//extern getgrgid_r +//extern-sysinfo getgrgid_r func libc_getgrgid_r(gid syscall.Gid_t, grp *syscall.Group, buf *byte, buflen syscall.Size_t, result **syscall.Group) int -//extern getgrouplist +//extern-sysinfo getgrouplist func libc_getgrouplist(user *byte, group syscall.Gid_t, groups *syscall.Gid_t, ngroups *int32) int diff --git a/libgo/go/runtime/netpoll_kqueue.go b/libgo/go/runtime/netpoll_kqueue.go index c41a7d0..1724f37 100644 --- a/libgo/go/runtime/netpoll_kqueue.go +++ b/libgo/go/runtime/netpoll_kqueue.go @@ -13,11 +13,11 @@ import ( "unsafe" ) -//extern kqueue +//extern-sysinfo kqueue func kqueue() int32 //go:noescape -//extern kevent +//extern-sysinfo kevent func kevent(kq int32, ch *keventt, nch uintptr, ev *keventt, nev uintptr, ts *timespec) int32 var ( diff --git a/libgo/go/runtime/os_gccgo.go b/libgo/go/runtime/os_gccgo.go index a8859c0..79331c5 100644 --- a/libgo/go/runtime/os_gccgo.go +++ b/libgo/go/runtime/os_gccgo.go @@ -52,7 +52,7 @@ func getRandomData(r []byte) { } //go:noescape -//extern pipe +//extern-sysinfo pipe func libcPipe(*[2]int32) int32 func pipe() (r, w int32, e int32) { @@ -65,7 +65,7 @@ func pipe() (r, w int32, e int32) { } //go:noescape -//extern pipe2 +//extern-sysinfo pipe2 func libcPipe2(*[2]int32, int32) int32 func pipe2(flags int32) (r, w int32, e int32) { diff --git a/libgo/go/runtime/os_netbsd.go b/libgo/go/runtime/os_netbsd.go index 9ebb652..00c3285 100644 --- a/libgo/go/runtime/os_netbsd.go +++ b/libgo/go/runtime/os_netbsd.go @@ -18,19 +18,19 @@ func getProcID() uint64 { return uint64(lwp_self()) } -//extern _lwp_self +//extern-sysinfo _lwp_self func lwp_self() int32 //go:noescape -//extern _lwp_park +//extern-sysinfo _lwp_park func lwp_park(ts int32, rel int32, abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32 //go:noescape -//extern _lwp_unpark +//extern-sysinfo _lwp_unpark func lwp_unpark(lwp int32, hint unsafe.Pointer) int32 //go:noescape -//extern sysctl +//extern-sysinfo sysctl func sysctl(*uint32, uint32, *byte, *uintptr, *byte, uintptr) int32 func getncpu() int32 { diff --git a/libgo/go/runtime/signal_gccgo.go b/libgo/go/runtime/signal_gccgo.go index c555712..2eece68 100644 --- a/libgo/go/runtime/signal_gccgo.go +++ b/libgo/go/runtime/signal_gccgo.go @@ -14,44 +14,44 @@ import ( // these are written in OS-specific files and in assembler. //go:noescape -//extern sigaction +//extern-sysinfo sigaction func sigaction(signum uint32, act *_sigaction, oact *_sigaction) int32 //go:noescape -//extern sigprocmask +//extern-sysinfo sigprocmask func sigprocmask(how int32, set *sigset, oldset *sigset) int32 //go:noescape -//extern sigfillset +//extern-sysinfo sigfillset func sigfillset(set *sigset) int32 //go:noescape -//extern sigemptyset +//extern-sysinfo sigemptyset func sigemptyset(set *sigset) int32 //go:noescape -//extern sigaddset +//extern-sysinfo sigaddset func c_sigaddset(set *sigset, signum uint32) int32 //go:noescape -//extern sigdelset +//extern-sysinfo sigdelset func c_sigdelset(set *sigset, signum uint32) int32 //go:noescape -//extern sigaltstack +//extern-sysinfo sigaltstack func sigaltstack(ss *_stack_t, oss *_stack_t) int32 -//extern raise +//extern-sysinfo raise func raise(sig uint32) int32 -//extern getpid +//extern-sysinfo getpid func getpid() _pid_t -//extern kill +//extern-sysinfo kill func kill(pid _pid_t, sig uint32) int32 //go:noescape -//extern setitimer +//extern-sysinfo setitimer func setitimer(which int32, new *_itimerval, old *_itimerval) int32 type sigctxt struct { diff --git a/libgo/go/runtime/stubs2.go b/libgo/go/runtime/stubs2.go index 454afee..0aaed29 100644 --- a/libgo/go/runtime/stubs2.go +++ b/libgo/go/runtime/stubs2.go @@ -17,7 +17,7 @@ func read(fd int32, p unsafe.Pointer, n int32) int32 func closefd(fd int32) int32 -//extern exit +//extern-sysinfo exit func exit(code int32) func usleep(usec uint32) diff --git a/libgo/go/syscall/mksyscall.awk b/libgo/go/syscall/mksyscall.awk index 50802d9..5f46727 100644 --- a/libgo/go/syscall/mksyscall.awk +++ b/libgo/go/syscall/mksyscall.awk @@ -28,7 +28,7 @@ # type, without a name. BEGIN { - print "// This file was automatically generated by mksyscall.awk" + print "// Code generated by mksyscall.awk. DO NOT EDIT." print "" print "package syscall" print "" @@ -99,7 +99,7 @@ BEGIN { if (!(cfnname in cfns)) { cfns[cfnname] = 1 printf("//go:noescape\n") - printf("//extern %s\n", cfnname) + printf("//extern-sysinfo %s\n", cfnname) printf("func c_%s(%s) %s\n", cfnname, cfnparams, cfnresult) } printf("func %s(%s) %s%s%s%s{\n", -- cgit v1.1 From cf392dbdf17e38026f8e3c0e9af7f5b87f63be56 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 7 Nov 2020 07:25:23 -0800 Subject: libgo: update to Go 1.15.4 release Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/268177 --- libgo/go/cmd/go/internal/modfetch/coderepo_test.go | 5 -- libgo/go/compress/flate/deflate_test.go | 57 ++++++++++++++++++++++ libgo/go/compress/flate/deflatefast.go | 11 +++-- libgo/go/net/http/h2_bundle.go | 11 +++++ libgo/go/net/http/request.go | 2 +- libgo/go/net/http/request_test.go | 21 ++++++++ libgo/go/reflect/deepequal.go | 12 ++++- libgo/go/reflect/value.go | 12 ++++- libgo/go/runtime/netpoll.go | 48 ++++++++++++------ libgo/go/runtime/proc.go | 21 ++++++++ libgo/go/runtime/signal_unix.go | 7 +++ libgo/go/syscall/exec_unix_test.go | 45 +++++++++++++++++ libgo/go/time/zoneinfo_read.go | 19 +++++++- libgo/go/time/zoneinfo_test.go | 19 ++++++++ 14 files changed, 264 insertions(+), 26 deletions(-) (limited to 'libgo/go') diff --git a/libgo/go/cmd/go/internal/modfetch/coderepo_test.go b/libgo/go/cmd/go/internal/modfetch/coderepo_test.go index f69c193b..9a0cd7d 100644 --- a/libgo/go/cmd/go/internal/modfetch/coderepo_test.go +++ b/libgo/go/cmd/go/internal/modfetch/coderepo_test.go @@ -657,11 +657,6 @@ var codeRepoVersionsTests = []struct { }, { vcs: "git", - path: "gopkg.in/russross/blackfriday.v2", - versions: []string{"v2.0.0", "v2.0.1"}, - }, - { - vcs: "git", path: "gopkg.in/natefinch/lumberjack.v2", versions: []string{"v2.0.0"}, }, diff --git a/libgo/go/compress/flate/deflate_test.go b/libgo/go/compress/flate/deflate_test.go index 3362d25..8a22b8e 100644 --- a/libgo/go/compress/flate/deflate_test.go +++ b/libgo/go/compress/flate/deflate_test.go @@ -11,6 +11,7 @@ import ( "internal/testenv" "io" "io/ioutil" + "math/rand" "reflect" "runtime/debug" "sync" @@ -896,6 +897,62 @@ func TestBestSpeedMaxMatchOffset(t *testing.T) { } } +func TestBestSpeedShiftOffsets(t *testing.T) { + // Test if shiftoffsets properly preserves matches and resets out-of-range matches + // seen in https://github.com/golang/go/issues/4142 + enc := newDeflateFast() + + // testData may not generate internal matches. + testData := make([]byte, 32) + rng := rand.New(rand.NewSource(0)) + for i := range testData { + testData[i] = byte(rng.Uint32()) + } + + // Encode the testdata with clean state. + // Second part should pick up matches from the first block. + wantFirstTokens := len(enc.encode(nil, testData)) + wantSecondTokens := len(enc.encode(nil, testData)) + + if wantFirstTokens <= wantSecondTokens { + t.Fatalf("test needs matches between inputs to be generated") + } + // Forward the current indicator to before wraparound. + enc.cur = bufferReset - int32(len(testData)) + + // Part 1 before wrap, should match clean state. + got := len(enc.encode(nil, testData)) + if wantFirstTokens != got { + t.Errorf("got %d, want %d tokens", got, wantFirstTokens) + } + + // Verify we are about to wrap. + if enc.cur != bufferReset { + t.Errorf("got %d, want e.cur to be at bufferReset (%d)", enc.cur, bufferReset) + } + + // Part 2 should match clean state as well even if wrapped. + got = len(enc.encode(nil, testData)) + if wantSecondTokens != got { + t.Errorf("got %d, want %d token", got, wantSecondTokens) + } + + // Verify that we wrapped. + if enc.cur >= bufferReset { + t.Errorf("want e.cur to be < bufferReset (%d), got %d", bufferReset, enc.cur) + } + + // Forward the current buffer, leaving the matches at the bottom. + enc.cur = bufferReset + enc.shiftOffsets() + + // Ensure that no matches were picked up. + got = len(enc.encode(nil, testData)) + if wantFirstTokens != got { + t.Errorf("got %d, want %d tokens", got, wantFirstTokens) + } +} + func TestMaxStackSize(t *testing.T) { // This test must not run in parallel with other tests as debug.SetMaxStack // affects all goroutines. diff --git a/libgo/go/compress/flate/deflatefast.go b/libgo/go/compress/flate/deflatefast.go index 24f8be9..6aa439f 100644 --- a/libgo/go/compress/flate/deflatefast.go +++ b/libgo/go/compress/flate/deflatefast.go @@ -270,6 +270,7 @@ func (e *deflateFast) matchLen(s, t int32, src []byte) int32 { func (e *deflateFast) reset() { e.prev = e.prev[:0] // Bump the offset, so all matches will fail distance check. + // Nothing should be >= e.cur in the table. e.cur += maxMatchOffset // Protect against e.cur wraparound. @@ -288,17 +289,21 @@ func (e *deflateFast) shiftOffsets() { for i := range e.table[:] { e.table[i] = tableEntry{} } - e.cur = maxMatchOffset + e.cur = maxMatchOffset + 1 return } // Shift down everything in the table that isn't already too far away. for i := range e.table[:] { - v := e.table[i].offset - e.cur + maxMatchOffset + v := e.table[i].offset - e.cur + maxMatchOffset + 1 if v < 0 { + // We want to reset e.cur to maxMatchOffset + 1, so we need to shift + // all table entries down by (e.cur - (maxMatchOffset + 1)). + // Because we ignore matches > maxMatchOffset, we can cap + // any negative offsets at 0. v = 0 } e.table[i].offset = v } - e.cur = maxMatchOffset + e.cur = maxMatchOffset + 1 } diff --git a/libgo/go/net/http/h2_bundle.go b/libgo/go/net/http/h2_bundle.go index 779da4f..71592e9 100644 --- a/libgo/go/net/http/h2_bundle.go +++ b/libgo/go/net/http/h2_bundle.go @@ -5265,6 +5265,7 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error { if len(data) > 0 { wrote, err := st.body.Write(data) if err != nil { + sc.sendWindowUpdate(nil, int(f.Length)-wrote) return http2streamError(id, http2ErrCodeStreamClosed) } if wrote != len(data) { @@ -7167,6 +7168,7 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client cc.inflow.add(http2transportDefaultConnFlow + http2initialWindowSize) cc.bw.Flush() if cc.werr != nil { + cc.Close() return nil, cc.werr } @@ -7532,6 +7534,15 @@ func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterRe bodyWriter := cc.t.getBodyWriterState(cs, body) cs.on100 = bodyWriter.on100 + defer func() { + cc.wmu.Lock() + werr := cc.werr + cc.wmu.Unlock() + if werr != nil { + cc.Close() + } + }() + cc.wmu.Lock() endStream := !hasBody && !hasTrailers werr := cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs) diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go index fe6b6098..54ec1c5 100644 --- a/libgo/go/net/http/request.go +++ b/libgo/go/net/http/request.go @@ -382,7 +382,7 @@ func (r *Request) Clone(ctx context.Context) *Request { if s := r.TransferEncoding; s != nil { s2 := make([]string, len(s)) copy(s2, s) - r2.TransferEncoding = s + r2.TransferEncoding = s2 } r2.Form = cloneURLValues(r.Form) r2.PostForm = cloneURLValues(r.PostForm) diff --git a/libgo/go/net/http/request_test.go b/libgo/go/net/http/request_test.go index 42c16d0..461d66e 100644 --- a/libgo/go/net/http/request_test.go +++ b/libgo/go/net/http/request_test.go @@ -828,6 +828,27 @@ func TestWithContextDeepCopiesURL(t *testing.T) { } } +// Ensure that Request.Clone creates a deep copy of TransferEncoding. +// See issue 41907. +func TestRequestCloneTransferEncoding(t *testing.T) { + body := strings.NewReader("body") + req, _ := NewRequest("POST", "https://example.org/", body) + req.TransferEncoding = []string{ + "encoding1", + } + + clonedReq := req.Clone(context.Background()) + // modify original after deep copy + req.TransferEncoding[0] = "encoding2" + + if req.TransferEncoding[0] != "encoding2" { + t.Error("expected req.TransferEncoding to be changed") + } + if clonedReq.TransferEncoding[0] != "encoding1" { + t.Error("expected clonedReq.TransferEncoding to be unchanged") + } +} + func TestNoPanicOnRoundTripWithBasicAuth_h1(t *testing.T) { testNoPanicWithBasicAuth(t, h1Mode) } diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go index 8a2bf8b..b99c345 100644 --- a/libgo/go/reflect/deepequal.go +++ b/libgo/go/reflect/deepequal.go @@ -37,7 +37,17 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool { // and it's safe and valid to get Value's internal pointer. hard := func(v1, v2 Value) bool { switch v1.Kind() { - case Map, Slice, Ptr, Interface: + case Ptr: + if v1.typ.ptrdata == 0 { + // go:notinheap pointers can't be cyclic. + // At least, all of our current uses of go:notinheap have + // that property. The runtime ones aren't cyclic (and we don't use + // DeepEqual on them anyway), and the cgo-generated ones are + // all empty structs. + return false + } + fallthrough + case Map, Slice, Interface: // Nil pointers cannot be cyclic. Avoid putting them in the visited map. return !v1.IsNil() && !v2.IsNil() } diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 64f7432..1394dd3 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -91,6 +91,7 @@ func (f flag) ro() flag { // pointer returns the underlying pointer represented by v. // v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer +// if v.Kind() == Ptr, the base type must not be go:notinheap. func (v Value) pointer() unsafe.Pointer { if v.typ.size != ptrSize || !v.typ.pointers() { panic("can't call pointer on a non-pointer Value") @@ -1263,7 +1264,16 @@ func (v Value) Pointer() uintptr { // TODO: deprecate k := v.kind() switch k { - case Chan, Map, Ptr, UnsafePointer: + case Ptr: + if v.typ.ptrdata == 0 { + // Handle pointers to go:notinheap types directly, + // so we never materialize such pointers as an + // unsafe.Pointer. (Such pointers are always indirect.) + // See issue 42076. + return *(*uintptr)(v.ptr) + } + fallthrough + case Chan, Map, UnsafePointer: return uintptr(v.pointer()) case Func: p := v.pointer() diff --git a/libgo/go/runtime/netpoll.go b/libgo/go/runtime/netpoll.go index 5157e4d..72a136d 100644 --- a/libgo/go/runtime/netpoll.go +++ b/libgo/go/runtime/netpoll.go @@ -82,16 +82,17 @@ type pollDesc struct { lock mutex // protects the following fields fd uintptr closing bool - everr bool // marks event scanning error happened - user uint32 // user settable cookie - rseq uintptr // protects from stale read timers - rg uintptr // pdReady, pdWait, G waiting for read or nil - rt timer // read deadline timer (set if rt.f != nil) - rd int64 // read deadline - wseq uintptr // protects from stale write timers - wg uintptr // pdReady, pdWait, G waiting for write or nil - wt timer // write deadline timer - wd int64 // write deadline + everr bool // marks event scanning error happened + user uint32 // user settable cookie + rseq uintptr // protects from stale read timers + rg uintptr // pdReady, pdWait, G waiting for read or nil + rt timer // read deadline timer (set if rt.f != nil) + rd int64 // read deadline + wseq uintptr // protects from stale write timers + wg uintptr // pdReady, pdWait, G waiting for write or nil + wt timer // write deadline timer + wd int64 // write deadline + self *pollDesc // storage for indirect interface. See (*pollDesc).makeArg. } type pollCache struct { @@ -160,6 +161,7 @@ func poll_runtime_pollOpen(fd uintptr) (uintptr, int) { pd.wseq++ pd.wg = 0 pd.wd = 0 + pd.self = pd unlock(&pd.lock) var errno int32 @@ -279,14 +281,14 @@ func poll_runtime_pollSetDeadline(ctx uintptr, d int64, mode int) { // Copy current seq into the timer arg. // Timer func will check the seq against current descriptor seq, // if they differ the descriptor was reused or timers were reset. - pd.rt.arg = pd + pd.rt.arg = pd.makeArg() pd.rt.seq = pd.rseq resettimer(&pd.rt, pd.rd) } } else if pd.rd != rd0 || combo != combo0 { pd.rseq++ // invalidate current timers if pd.rd > 0 { - modtimer(&pd.rt, pd.rd, 0, rtf, pd, pd.rseq) + modtimer(&pd.rt, pd.rd, 0, rtf, pd.makeArg(), pd.rseq) } else { deltimer(&pd.rt) pd.rt.f = nil @@ -295,14 +297,14 @@ func poll_runtime_pollSetDeadline(ctx uintptr, d int64, mode int) { if pd.wt.f == nil { if pd.wd > 0 && !combo { pd.wt.f = netpollWriteDeadline - pd.wt.arg = pd + pd.wt.arg = pd.makeArg() pd.wt.seq = pd.wseq resettimer(&pd.wt, pd.wd) } } else if pd.wd != wd0 || combo != combo0 { pd.wseq++ // invalidate current timers if pd.wd > 0 && !combo { - modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd, pd.wseq) + modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd.makeArg(), pd.wseq) } else { deltimer(&pd.wt) pd.wt.f = nil @@ -556,3 +558,21 @@ func (c *pollCache) alloc() *pollDesc { unlock(&c.lock) return pd } + +// makeArg converts pd to an interface{}. +// makeArg does not do any allocation. Normally, such +// a conversion requires an allocation because pointers to +// go:notinheap types (which pollDesc is) must be stored +// in interfaces indirectly. See issue 42076. +func (pd *pollDesc) makeArg() (i interface{}) { + x := (*eface)(unsafe.Pointer(&i)) + x._type = pdType + // For gccgo, we still use pd.self here, not &pd.self. + x.data = unsafe.Pointer(pd.self) + return +} + +var ( + pdEface interface{} = (*pollDesc)(nil) + pdType *_type = efaceOf(&pdEface)._type +) diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go index 84070e4..0ca6c02 100644 --- a/libgo/go/runtime/proc.go +++ b/libgo/go/runtime/proc.go @@ -1258,6 +1258,14 @@ found: checkdead() unlock(&sched.lock) + if GOOS == "darwin" { + // Make sure pendingPreemptSignals is correct when an M exits. + // For #41702. + if atomic.Load(&m.signalPending) != 0 { + atomic.Xadd(&pendingPreemptSignals, -1) + } + } + if osStack { // Return from mstart and let the system thread // library free the g0 stack and terminate the thread. @@ -3349,11 +3357,24 @@ func syscall_runtime_AfterForkInChild() { inForkedChild = false } +// pendingPreemptSignals is the number of preemption signals +// that have been sent but not received. This is only used on Darwin. +// For #41702. +var pendingPreemptSignals uint32 + // Called from syscall package before Exec. //go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec func syscall_runtime_BeforeExec() { // Prevent thread creation during exec. execLock.lock() + + // On Darwin, wait for all pending preemption signals to + // be received. See issue #41702. + if GOOS == "darwin" { + for int32(atomic.Load(&pendingPreemptSignals)) > 0 { + osyield() + } + } } // Called from syscall package after Exec. diff --git a/libgo/go/runtime/signal_unix.go b/libgo/go/runtime/signal_unix.go index 17c15c5..6b69dcf 100644 --- a/libgo/go/runtime/signal_unix.go +++ b/libgo/go/runtime/signal_unix.go @@ -347,6 +347,10 @@ func doSigPreempt(gp *g, ctxt *sigctxt, sigpc uintptr) { // Acknowledge the preemption. atomic.Xadd(&gp.m.preemptGen, 1) atomic.Store(&gp.m.signalPending, 0) + + if GOOS == "darwin" { + atomic.Xadd(&pendingPreemptSignals, -1) + } } // This is false for gccgo. @@ -404,6 +408,9 @@ func sigtrampgo(sig uint32, info *_siginfo_t, ctx unsafe.Pointer) { // no non-Go signal handler for sigPreempt. // The default behavior for sigPreempt is to ignore // the signal, so badsignal will be a no-op anyway. + if GOOS == "darwin" { + atomic.Xadd(&pendingPreemptSignals, -1) + } return } badsignal(uintptr(sig), &c) diff --git a/libgo/go/syscall/exec_unix_test.go b/libgo/go/syscall/exec_unix_test.go index fab80e7..1399149 100644 --- a/libgo/go/syscall/exec_unix_test.go +++ b/libgo/go/syscall/exec_unix_test.go @@ -9,12 +9,14 @@ package syscall_test import ( "internal/testenv" "io" + "math/rand" "os" "os/exec" "os/signal" "runtime" "syscall" "testing" + "time" "unsafe" ) @@ -245,3 +247,46 @@ func TestInvalidExec(t *testing.T) { } }) } + +// TestExec is for issue #41702. +func TestExec(t *testing.T) { + testenv.MustHaveExec(t) + cmd := exec.Command(os.Args[0], "-test.run=TestExecHelper") + cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=2") + o, err := cmd.CombinedOutput() + if err != nil { + t.Errorf("%s\n%v", o, err) + } +} + +// TestExecHelper is used by TestExec. It does nothing by itself. +// In testing on macOS 10.14, this used to fail with +// "signal: illegal instruction" more than half the time. +func TestExecHelper(t *testing.T) { + if os.Getenv("GO_WANT_HELPER_PROCESS") != "2" { + return + } + + // We don't have to worry about restoring these values. + // We are in a child process that only runs this test, + // and we are going to call syscall.Exec anyhow. + runtime.GOMAXPROCS(50) + os.Setenv("GO_WANT_HELPER_PROCESS", "3") + + stop := time.Now().Add(time.Second) + for i := 0; i < 100; i++ { + go func(i int) { + r := rand.New(rand.NewSource(int64(i))) + for time.Now().Before(stop) { + r.Uint64() + } + }(i) + } + + time.Sleep(10 * time.Millisecond) + + argv := []string{os.Args[0], "-test.run=TestExecHelper"} + syscall.Exec(os.Args[0], argv, os.Environ()) + + t.Error("syscall.Exec returned") +} diff --git a/libgo/go/time/zoneinfo_read.go b/libgo/go/time/zoneinfo_read.go index c242972..1e3586f 100644 --- a/libgo/go/time/zoneinfo_read.go +++ b/libgo/go/time/zoneinfo_read.go @@ -325,10 +325,27 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) { if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) { l.cacheStart = tx[i].when l.cacheEnd = omega + zoneIdx := tx[i].index if i+1 < len(tx) { l.cacheEnd = tx[i+1].when + } else if l.extend != "" { + // If we're at the end of the known zone transitions, + // try the extend string. + if name, _, estart, eend, ok := tzset(l.extend, l.cacheEnd, sec); ok { + l.cacheStart = estart + l.cacheEnd = eend + // Find the zone that is returned by tzset, + // the last transition is not always the correct zone. + for i, z := range l.zone { + if z.name == name { + zoneIdx = uint8(i) + break + } + } + } } - l.cacheZone = &l.zone[tx[i].index] + l.cacheZone = &l.zone[zoneIdx] + break } } diff --git a/libgo/go/time/zoneinfo_test.go b/libgo/go/time/zoneinfo_test.go index dac05e0..d543f93e 100644 --- a/libgo/go/time/zoneinfo_test.go +++ b/libgo/go/time/zoneinfo_test.go @@ -189,6 +189,25 @@ func TestMalformedTZData(t *testing.T) { } } +func TestLoadLocationFromTZDataSlim(t *testing.T) { + // A 2020b slim tzdata for Europe/Berlin + tzData := "TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\f\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9cٮ\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\tq\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xffͩ\x17\x90\xff\xff\xff\xff\u03a2C\x10\xff\xff\xff\xffϒ4\x10\xff\xff\xff\xffЂ%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xffѶ\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xffҡO\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xffըs\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\t\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13ܐ\x00\x00\x00\x00\x17\x03͐\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18㯐\x00\x00\x00\x00\x19Ӡ\x90\x00\x00\x00\x00\x1aÑ\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\\c\x10\x00\x00\x00\x00\"LT\x10\x00\x00\x00\x00#