[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