[Pkg-golang-commits] [golang] 01/01: Imported Upstream version 1.7.3
Michael Hudson-Doyle
mwhudson-guest at moszumanska.debian.org
Wed Oct 19 20:35:03 UTC 2016
This is an automated email from the git hooks/post-receive script.
mwhudson-guest pushed a commit to branch upstream-1.7
in repository golang.
commit 21c6d5f94ba4886599d6fc8cb39c24788e0f3dc9
Author: Michael Hudson-Doyle <michael.hudson at canonical.com>
Date: Thu Oct 20 09:00:12 2016 +1300
Imported Upstream version 1.7.3
---
VERSION | 2 +-
doc/devel/release.html | 16 +++++++-
doc/install-source.html | 4 +-
src/cmd/compile/internal/gc/esc.go | 21 ++++++++++
src/crypto/aes/cbc_s390x.go | 4 +-
src/crypto/cipher/cipher_test.go | 54 ++++++++++++++++++++++++++
src/crypto/tls/conn.go | 68 +++++++++++++++++++++++++--------
src/crypto/tls/handshake_client_test.go | 54 ++++++++++++++++++++++++++
src/net/http/clientserver_test.go | 2 +-
src/net/http/h2_bundle.go | 39 +++++++------------
src/runtime/asm_s390x.s | 1 +
src/runtime/defs_freebsd.go | 5 +++
src/runtime/defs_freebsd_386.go | 8 ++++
src/runtime/defs_freebsd_amd64.go | 8 ++++
src/runtime/defs_freebsd_arm.go | 8 ++++
src/runtime/os_freebsd.go | 16 ++++----
src/runtime/sys_freebsd_amd64.s | 4 +-
src/runtime/sys_freebsd_arm.s | 2 +-
test/fixedbugs/issue17318.go | 47 +++++++++++++++++++++++
19 files changed, 305 insertions(+), 58 deletions(-)
diff --git a/VERSION b/VERSION
index d91e2e8..816aead 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-go1.7.1
\ No newline at end of file
+go1.7.3
\ No newline at end of file
diff --git a/doc/devel/release.html b/doc/devel/release.html
index 5d0a129..9a4daf1 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -42,13 +42,27 @@ Read the <a href="/doc/go1.7">Go 1.7 Release Notes</a> for more information.
<p>
go1.7.1 (released 2016/09/07) includes fixes to the compiler, runtime,
documentation, and the <code>compress/flate</code>, <code>hash/crc32</code>,
-<code>io</code> <code>net</code>, <code>net/http</code>,
+<code>io</code>, <code>net</code>, <code>net/http</code>,
<code>path/filepath</code>, <code>reflect</code>, and <code>syscall</code>
packages.
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.1">Go
1.7.1 milestone</a> on our issue tracker for details.
</p>
+<p>
+go1.7.2 should not be used. It was tagged but not fully released.
+The release was deferred due to a last minute bug report.
+Use go1.7.3 instead, and refer to the summary of changes below.
+</p>
+
+<p>
+go1.7.3 (released 2016/10/19) includes fixes to the compiler, runtime,
+and the <code>crypto/cipher</code>, <code>crypto/tls</code>,
+<code>net/http</code>, and <code>strings</code> packages.
+See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.3">Go
+1.7.3 milestone</a> on our issue tracker for details.
+</p>
+
<h2 id="go1.6">go1.6 (released 2016/02/17)</h2>
<p>
diff --git a/doc/install-source.html b/doc/install-source.html
index 1cc2230..d0a4ed2 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -203,7 +203,7 @@ To build without <code>cgo</code>, set the environment variable
Change to the directory that will be its parent
and make sure the <code>go</code> directory does not exist.
Then clone the repository and check out the latest release tag
-(<code class="versionTag">go1.7.1</code>, for example):</p>
+(<code class="versionTag">go1.7.2</code>, for example):</p>
<pre>
$ git clone https://go.googlesource.com/go
@@ -391,7 +391,7 @@ New releases are announced on the
<a href="//groups.google.com/group/golang-announce">golang-announce</a>
mailing list.
Each announcement mentions the latest release tag, for instance,
-<code class="versionTag">go1.7.1</code>.
+<code class="versionTag">go1.7.2</code>.
</p>
<p>
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index 90ad75c..69b5964 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -472,9 +472,29 @@ func escAnalyze(all []*Node, recursive bool) {
// visit the upstream of each dst, mark address nodes with
// addrescapes, mark parameters unsafe
+ escapes := make([]uint16, len(e.dsts))
+ for i, n := range e.dsts {
+ escapes[i] = n.Esc
+ }
for _, n := range e.dsts {
escflood(e, n)
}
+ for {
+ done := true
+ for i, n := range e.dsts {
+ if n.Esc != escapes[i] {
+ done = false
+ if Debug['m'] > 2 {
+ Warnl(n.Lineno, "Reflooding %v %S", e.curfnSym(n), n)
+ }
+ escapes[i] = n.Esc
+ escflood(e, n)
+ }
+ }
+ if done {
+ break
+ }
+ }
// for all top level functions, tag the typenodes corresponding to the param nodes
for _, n := range all {
@@ -1796,6 +1816,7 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
}
leaks = level.int() <= 0 && level.guaranteedDereference() <= 0 && dstE.Escloopdepth < modSrcLoopdepth
+ leaks = leaks || level.int() <= 0 && dst.Esc&EscMask == EscHeap
osrcesc = src.Esc
switch src.Op {
diff --git a/src/crypto/aes/cbc_s390x.go b/src/crypto/aes/cbc_s390x.go
index 427b30b..739e1fe 100644
--- a/src/crypto/aes/cbc_s390x.go
+++ b/src/crypto/aes/cbc_s390x.go
@@ -48,7 +48,9 @@ func (x *cbc) CryptBlocks(dst, src []byte) {
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
- cryptBlocksChain(x.c, &x.iv[0], &x.b.key[0], &dst[0], &src[0], len(src))
+ if len(src) > 0 {
+ cryptBlocksChain(x.c, &x.iv[0], &x.b.key[0], &dst[0], &src[0], len(src))
+ }
}
func (x *cbc) SetIV(iv []byte) {
diff --git a/src/crypto/cipher/cipher_test.go b/src/crypto/cipher/cipher_test.go
index 1faa7b8..4d7cd6b 100644
--- a/src/crypto/cipher/cipher_test.go
+++ b/src/crypto/cipher/cipher_test.go
@@ -5,8 +5,10 @@
package cipher_test
import (
+ "bytes"
"crypto/aes"
"crypto/cipher"
+ "crypto/des"
"testing"
)
@@ -34,3 +36,55 @@ func mustPanic(t *testing.T, msg string, f func()) {
}()
f()
}
+
+func TestEmptyPlaintext(t *testing.T) {
+ var key [16]byte
+ a, err := aes.NewCipher(key[:16])
+ if err != nil {
+ t.Fatal(err)
+ }
+ d, err := des.NewCipher(key[:8])
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ s := 16
+ pt := make([]byte, s)
+ ct := make([]byte, s)
+ for i := 0; i < 16; i++ {
+ pt[i], ct[i] = byte(i), byte(i)
+ }
+
+ assertEqual := func(name string, got, want []byte) {
+ if !bytes.Equal(got, want) {
+ t.Fatalf("%s: got %v, want %v", name, got, want)
+ }
+ }
+
+ for _, b := range []cipher.Block{a, d} {
+ iv := make([]byte, b.BlockSize())
+ cbce := cipher.NewCBCEncrypter(b, iv)
+ cbce.CryptBlocks(ct, pt[:0])
+ assertEqual("CBC encrypt", ct, pt)
+
+ cbcd := cipher.NewCBCDecrypter(b, iv)
+ cbcd.CryptBlocks(ct, pt[:0])
+ assertEqual("CBC decrypt", ct, pt)
+
+ cfbe := cipher.NewCFBEncrypter(b, iv)
+ cfbe.XORKeyStream(ct, pt[:0])
+ assertEqual("CFB encrypt", ct, pt)
+
+ cfbd := cipher.NewCFBDecrypter(b, iv)
+ cfbd.XORKeyStream(ct, pt[:0])
+ assertEqual("CFB decrypt", ct, pt)
+
+ ctr := cipher.NewCTR(b, iv)
+ ctr.XORKeyStream(ct, pt[:0])
+ assertEqual("CTR", ct, pt)
+
+ ofb := cipher.NewOFB(b, iv)
+ ofb.XORKeyStream(ct, pt[:0])
+ assertEqual("OFB", ct, pt)
+ }
+}
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index 87bef23..77fd6d3 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -29,10 +29,14 @@ type Conn struct {
// constant after handshake; protected by handshakeMutex
handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
- handshakeErr error // error resulting from handshake
- vers uint16 // TLS version
- haveVers bool // version has been negotiated
- config *Config // configuration passed to constructor
+ // handshakeCond, if not nil, indicates that a goroutine is committed
+ // to running the handshake for this Conn. Other goroutines that need
+ // to wait for the handshake can wait on this, under handshakeMutex.
+ handshakeCond *sync.Cond
+ handshakeErr error // error resulting from handshake
+ vers uint16 // TLS version
+ haveVers bool // version has been negotiated
+ config *Config // configuration passed to constructor
// handshakeComplete is true if the connection is currently transfering
// application data (i.e. is not currently processing a handshake).
handshakeComplete bool
@@ -1206,26 +1210,50 @@ func (c *Conn) Handshake() error {
// need to check whether a handshake is pending (such as Write) to
// block.
//
- // Thus we take c.handshakeMutex first and, if we find that a handshake
- // is needed, then we unlock, acquire c.in and c.handshakeMutex in the
- // correct order, and check again.
+ // Thus we first take c.handshakeMutex to check whether a handshake is
+ // needed.
+ //
+ // If so then, previously, this code would unlock handshakeMutex and
+ // then lock c.in and handshakeMutex in the correct order to run the
+ // handshake. The problem was that it was possible for a Read to
+ // complete the handshake once handshakeMutex was unlocked and then
+ // keep c.in while waiting for network data. Thus a concurrent
+ // operation could be blocked on c.in.
+ //
+ // Thus handshakeCond is used to signal that a goroutine is committed
+ // to running the handshake and other goroutines can wait on it if they
+ // need. handshakeCond is protected by handshakeMutex.
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
- for i := 0; i < 2; i++ {
- if i == 1 {
- c.handshakeMutex.Unlock()
- c.in.Lock()
- defer c.in.Unlock()
- c.handshakeMutex.Lock()
- }
-
+ for {
if err := c.handshakeErr; err != nil {
return err
}
if c.handshakeComplete {
return nil
}
+ if c.handshakeCond == nil {
+ break
+ }
+
+ c.handshakeCond.Wait()
+ }
+
+ // Set handshakeCond to indicate that this goroutine is committing to
+ // running the handshake.
+ c.handshakeCond = sync.NewCond(&c.handshakeMutex)
+ c.handshakeMutex.Unlock()
+
+ c.in.Lock()
+ defer c.in.Unlock()
+
+ c.handshakeMutex.Lock()
+
+ // The handshake cannot have completed when handshakeMutex was unlocked
+ // because this goroutine set handshakeCond.
+ if c.handshakeErr != nil || c.handshakeComplete {
+ panic("handshake should not have been able to complete after handshakeCond was set")
}
if c.isClient {
@@ -1236,6 +1264,16 @@ func (c *Conn) Handshake() error {
if c.handshakeErr == nil {
c.handshakes++
}
+
+ if c.handshakeErr == nil && !c.handshakeComplete {
+ panic("handshake should have had a result.")
+ }
+
+ // Wake any other goroutines that are waiting for this handshake to
+ // complete.
+ c.handshakeCond.Broadcast()
+ c.handshakeCond = nil
+
return c.handshakeErr
}
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
index ce987f1..07d31b6 100644
--- a/src/crypto/tls/handshake_client_test.go
+++ b/src/crypto/tls/handshake_client_test.go
@@ -1045,3 +1045,57 @@ func TestBuffering(t *testing.T) {
t.Errorf("expected server handshake to complete with only two writes, but saw %d", n)
}
}
+
+func TestHandshakeRace(t *testing.T) {
+ // This test races a Read and Write to try and complete a handshake in
+ // order to provide some evidence that there are no races or deadlocks
+ // in the handshake locking.
+ for i := 0; i < 32; i++ {
+ c, s := net.Pipe()
+
+ go func() {
+ server := Server(s, testConfig)
+ if err := server.Handshake(); err != nil {
+ panic(err)
+ }
+
+ var request [1]byte
+ if n, err := server.Read(request[:]); err != nil || n != 1 {
+ panic(err)
+ }
+
+ server.Write(request[:])
+ server.Close()
+ }()
+
+ startWrite := make(chan struct{})
+ startRead := make(chan struct{})
+ readDone := make(chan struct{})
+
+ client := Client(c, testConfig)
+ go func() {
+ <-startWrite
+ var request [1]byte
+ client.Write(request[:])
+ }()
+
+ go func() {
+ <-startRead
+ var reply [1]byte
+ if n, err := client.Read(reply[:]); err != nil || n != 1 {
+ panic(err)
+ }
+ c.Close()
+ readDone <- struct{}{}
+ }()
+
+ if i&1 == 1 {
+ startWrite <- struct{}{}
+ startRead <- struct{}{}
+ } else {
+ startRead <- struct{}{}
+ startWrite <- struct{}{}
+ }
+ <-readDone
+ }
+}
diff --git a/src/net/http/clientserver_test.go b/src/net/http/clientserver_test.go
index e12ea0c..8caba28 100644
--- a/src/net/http/clientserver_test.go
+++ b/src/net/http/clientserver_test.go
@@ -468,7 +468,7 @@ func TestH12_RequestContentLength_Known_NonZero(t *testing.T) {
}
func TestH12_RequestContentLength_Known_Zero(t *testing.T) {
- h12requestContentLength(t, func() io.Reader { return strings.NewReader("") }, 0)
+ h12requestContentLength(t, func() io.Reader { return nil }, 0)
}
func TestH12_RequestContentLength_Unknown(t *testing.T) {
diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
index a41e3ca..063043a 100644
--- a/src/net/http/h2_bundle.go
+++ b/src/net/http/h2_bundle.go
@@ -1,5 +1,5 @@
// Code generated by golang.org/x/tools/cmd/bundle.
-//go:generate bundle -o h2_bundle.go -prefix http2 golang.org/x/net/http2
+//go:generate bundle -o h2_bundle.go -prefix http2 -underscore golang.org/x/net/http2
// Package http2 implements the HTTP/2 protocol.
//
@@ -5448,31 +5448,17 @@ func http2checkConnHeaders(req *Request) error {
return nil
}
-func http2bodyAndLength(req *Request) (body io.Reader, contentLen int64) {
- body = req.Body
- if body == nil {
- return nil, 0
+// actualContentLength returns a sanitized version of
+// req.ContentLength, where 0 actually means zero (not unknown) and -1
+// means unknown.
+func http2actualContentLength(req *Request) int64 {
+ if req.Body == nil {
+ return 0
}
if req.ContentLength != 0 {
- return req.Body, req.ContentLength
- }
-
- // We have a body but a zero content length. Test to see if
- // it's actually zero or just unset.
- var buf [1]byte
- n, rerr := body.Read(buf[:])
- if rerr != nil && rerr != io.EOF {
- return http2errorReader{rerr}, -1
- }
- if n == 1 {
-
- if rerr == io.EOF {
- return bytes.NewReader(buf[:]), 1
- }
- return io.MultiReader(bytes.NewReader(buf[:]), body), -1
+ return req.ContentLength
}
-
- return nil, 0
+ return -1
}
func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
@@ -5486,9 +5472,6 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
}
hasTrailers := trailers != ""
- body, contentLen := http2bodyAndLength(req)
- hasBody := body != nil
-
cc.mu.Lock()
cc.lastActive = time.Now()
if cc.closed || !cc.canTakeNewRequestLocked() {
@@ -5496,6 +5479,10 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
return nil, http2errClientConnUnusable
}
+ body := req.Body
+ hasBody := body != nil
+ contentLen := http2actualContentLength(req)
+
// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
var requestedGzip bool
if !cc.t.disableCompression() &&
diff --git a/src/runtime/asm_s390x.s b/src/runtime/asm_s390x.s
index 896ccde..97f276c 100644
--- a/src/runtime/asm_s390x.s
+++ b/src/runtime/asm_s390x.s
@@ -20,6 +20,7 @@ TEXT runtime·checkvectorfacility(SB),NOSPLIT,$32-0
MOVD $2, R0
MOVD R1, tmp-32(SP)
MOVD $x-24(SP), R1
+ XC $24, 0(R1), 0(R1)
// STFLE 0(R1)
WORD $0xB2B01000
MOVBZ z-8(SP), R1
diff --git a/src/runtime/defs_freebsd.go b/src/runtime/defs_freebsd.go
index 0253685..3f2184d 100644
--- a/src/runtime/defs_freebsd.go
+++ b/src/runtime/defs_freebsd.go
@@ -23,6 +23,7 @@ package runtime
#include <sys/mman.h>
#include <sys/ucontext.h>
#include <sys/umtx.h>
+#include <sys/_umtx.h>
#include <sys/rtprio.h>
#include <sys/thr.h>
#include <sys/_sigset.h>
@@ -49,6 +50,8 @@ const (
SA_RESTART = C.SA_RESTART
SA_ONSTACK = C.SA_ONSTACK
+ CLOCK_MONOTONIC = C.CLOCK_MONOTONIC
+
UMTX_OP_WAIT_UINT = C.UMTX_OP_WAIT_UINT
UMTX_OP_WAIT_UINT_PRIVATE = C.UMTX_OP_WAIT_UINT_PRIVATE
UMTX_OP_WAKE = C.UMTX_OP_WAKE
@@ -130,4 +133,6 @@ type Timespec C.struct_timespec
type Timeval C.struct_timeval
type Itimerval C.struct_itimerval
+type Umtx_time C.struct__umtx_time
+
type Kevent C.struct_kevent
diff --git a/src/runtime/defs_freebsd_386.go b/src/runtime/defs_freebsd_386.go
index 6938c18..efcbeb7 100644
--- a/src/runtime/defs_freebsd_386.go
+++ b/src/runtime/defs_freebsd_386.go
@@ -24,6 +24,8 @@ const (
_SA_RESTART = 0x2
_SA_ONSTACK = 0x1
+ _CLOCK_MONOTONIC = 0x4
+
_UMTX_OP_WAIT_UINT = 0xb
_UMTX_OP_WAIT_UINT_PRIVATE = 0xf
_UMTX_OP_WAKE = 0x3
@@ -203,6 +205,12 @@ type itimerval struct {
it_value timeval
}
+type umtx_time struct {
+ _timeout timespec
+ _flags uint32
+ _clockid uint32
+}
+
type keventt struct {
ident uint32
filter int16
diff --git a/src/runtime/defs_freebsd_amd64.go b/src/runtime/defs_freebsd_amd64.go
index de98e7a..594f957 100644
--- a/src/runtime/defs_freebsd_amd64.go
+++ b/src/runtime/defs_freebsd_amd64.go
@@ -24,6 +24,8 @@ const (
_SA_RESTART = 0x2
_SA_ONSTACK = 0x1
+ _CLOCK_MONOTONIC = 0x4
+
_UMTX_OP_WAIT_UINT = 0xb
_UMTX_OP_WAIT_UINT_PRIVATE = 0xf
_UMTX_OP_WAKE = 0x3
@@ -214,6 +216,12 @@ type itimerval struct {
it_value timeval
}
+type umtx_time struct {
+ _timeout timespec
+ _flags uint32
+ _clockid uint32
+}
+
type keventt struct {
ident uint64
filter int16
diff --git a/src/runtime/defs_freebsd_arm.go b/src/runtime/defs_freebsd_arm.go
index 744330f..0e9a2e9 100644
--- a/src/runtime/defs_freebsd_arm.go
+++ b/src/runtime/defs_freebsd_arm.go
@@ -24,6 +24,8 @@ const (
_SA_RESTART = 0x2
_SA_ONSTACK = 0x1
+ _CLOCK_MONOTONIC = 0x4
+
_UMTX_OP_WAIT_UINT = 0xb
_UMTX_OP_WAIT_UINT_PRIVATE = 0xf
_UMTX_OP_WAKE = 0x3
@@ -176,6 +178,12 @@ type itimerval struct {
it_value timeval
}
+type umtx_time struct {
+ _timeout timespec
+ _flags uint32
+ _clockid uint32
+}
+
type keventt struct {
ident uint32
filter int16
diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go
index c187ee8..0e09c60 100644
--- a/src/runtime/os_freebsd.go
+++ b/src/runtime/os_freebsd.go
@@ -35,7 +35,7 @@ func raise(sig int32)
func raiseproc(sig int32)
//go:noescape
-func sys_umtx_op(addr *uint32, mode int32, val uint32, ptr2, ts *timespec) int32
+func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uintptr, ut *umtx_time) int32
func osyield()
@@ -70,14 +70,14 @@ func futexsleep(addr *uint32, val uint32, ns int64) {
}
func futexsleep1(addr *uint32, val uint32, ns int64) {
- var tsp *timespec
+ var utp *umtx_time
if ns >= 0 {
- var ts timespec
- ts.tv_nsec = 0
- ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
- tsp = &ts
+ var ut umtx_time
+ ut._clockid = _CLOCK_MONOTONIC
+ ut._timeout.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ut._timeout.tv_nsec)))))
+ utp = &ut
}
- ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp)
+ ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, unsafe.Sizeof(*utp), utp)
if ret >= 0 || ret == -_EINTR {
return
}
@@ -87,7 +87,7 @@ func futexsleep1(addr *uint32, val uint32, ns int64) {
//go:nosplit
func futexwakeup(addr *uint32, cnt uint32) {
- ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil)
+ ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, 0, nil)
if ret >= 0 {
return
}
diff --git a/src/runtime/sys_freebsd_amd64.s b/src/runtime/sys_freebsd_amd64.s
index 9700117..277e7f8 100644
--- a/src/runtime/sys_freebsd_amd64.s
+++ b/src/runtime/sys_freebsd_amd64.s
@@ -14,8 +14,8 @@ TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
MOVQ addr+0(FP), DI
MOVL mode+8(FP), SI
MOVL val+12(FP), DX
- MOVQ ptr2+16(FP), R10
- MOVQ ts+24(FP), R8
+ MOVQ uaddr1+16(FP), R10
+ MOVQ ut+24(FP), R8
MOVL $454, AX
SYSCALL
MOVL AX, ret+32(FP)
diff --git a/src/runtime/sys_freebsd_arm.s b/src/runtime/sys_freebsd_arm.s
index e7dfb28..3c5a5cb 100644
--- a/src/runtime/sys_freebsd_arm.s
+++ b/src/runtime/sys_freebsd_arm.s
@@ -45,7 +45,7 @@ TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
MOVW addr+0(FP), R0
MOVW mode+4(FP), R1
MOVW val+8(FP), R2
- MOVW ptr2+12(FP), R3
+ MOVW uaddr1+12(FP), R3
ADD $20, R13 // arg 5 is passed on stack
MOVW $SYS__umtx_op, R7
SWI $0
diff --git a/test/fixedbugs/issue17318.go b/test/fixedbugs/issue17318.go
new file mode 100644
index 0000000..fe00859
--- /dev/null
+++ b/test/fixedbugs/issue17318.go
@@ -0,0 +1,47 @@
+// errorcheck -0 -N -m -l
+
+// Copyright 2016 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.
+
+// The escape analyzer needs to run till its root set settles
+// (this is not that often, it turns out).
+// This test is likely to become stale because the leak depends
+// on a spurious-escape bug -- return an interface as a named
+// output parameter appears to cause the called closure to escape,
+// where returning it as a regular type does not.
+
+package main
+
+import (
+ "fmt"
+)
+
+type closure func(i, j int) ent
+
+type ent int
+
+func (e ent) String() string {
+ return fmt.Sprintf("%d", int(e)) // ERROR "ent.String ... argument does not escape$" "int\(e\) escapes to heap$"
+}
+
+//go:noinline
+func foo(ops closure, j int) (err fmt.Stringer) { // ERROR "leaking param: ops$" "leaking param: ops to result err level=0$"
+ enqueue := func(i int) fmt.Stringer { // ERROR "func literal escapes to heap$"
+ return ops(i, j) // ERROR "ops\(i, j\) escapes to heap$"
+ }
+ err = enqueue(4)
+ if err != nil {
+ return err
+ }
+ return // return result of enqueue, a fmt.Stringer
+}
+
+func main() {
+ // 3 identical functions, to get different escape behavior.
+ f := func(i, j int) ent { // ERROR "func literal escapes to heap$"
+ return ent(i + j)
+ }
+ i := foo(f, 3).(ent)
+ fmt.Printf("foo(f,3)=%d\n", int(i)) // ERROR "int\(i\) escapes to heap$" "main ... argument does not escape$"
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-golang/golang.git
More information about the pkg-golang-commits
mailing list