[Pkg-golang-commits] [golang] 01/07: Imported Upstream version 1.7.5

Michael Stapelberg michael at stapelberg.de
Tue Jul 25 06:28:25 UTC 2017


This is an automated email from the git hooks/post-receive script.

stapelberg pushed a commit to branch golang-1.7
in repository golang.

commit 0f411dc5b70302fe3b7c2fa6d2c4f69a4d61fee1
Author: Michael Hudson-Doyle <michael.hudson at canonical.com>
Date:   Fri Jan 27 14:10:54 2017 +1300

    Imported Upstream version 1.7.5
---
 VERSION                              |   2 +-
 doc/conduct.html                     |   1 -
 doc/devel/release.html               |   7 ++
 src/cmd/compile/internal/gc/sinit.go |   2 +
 src/crypto/x509/root_darwin.go       | 229 ++++++++++++++++++++++++++---------
 src/crypto/x509/root_darwin_test.go  |  11 +-
 src/reflect/makefunc.go              |   2 +
 src/runtime/mgc.go                   |  12 +-
 src/runtime/mgcmark.go               |  22 ++--
 src/runtime/select.go                |  69 ++++++++++-
 src/runtime/traceback.go             |  43 +++++--
 src/time/time_test.go                |   7 +-
 test/fixedbugs/issue16331.go         |  48 ++++++++
 test/fixedbugs/issue18410.go         |  40 ++++++
 14 files changed, 410 insertions(+), 85 deletions(-)

diff --git a/VERSION b/VERSION
index 83caa74..375bdbb 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-go1.7.4
\ No newline at end of file
+go1.7.5
\ No newline at end of file
diff --git a/doc/conduct.html b/doc/conduct.html
index ce824a1..d4d0800 100644
--- a/doc/conduct.html
+++ b/doc/conduct.html
@@ -67,7 +67,6 @@ official forums operated by the Go project (“Go spaces”):
     <li>The <a href="https://groups.google.com/group/golang-nuts">golang-nuts</a> and
         <a href="https://groups.google.com/group/golang-dev">golang-dev</a> mailing lists.
 <li>The #go-nuts IRC channel on Freenode.
-<li>The <a href="https://reddit.com/r/golang">/r/golang subreddit</a>.
 </ul>
 
 <p>
diff --git a/doc/devel/release.html b/doc/devel/release.html
index 51957df..be340a3 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -69,6 +69,13 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.4">Go
 1.7.4 milestone</a> on our issue tracker for details.
 </p>
 
+<p>
+go1.7.5 (released 2017/01/26) includes fixes to the compiler, runtime,
+and the <code>crypto/x509</code> and <code>time</code> packages.
+See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.5">Go
+1.7.5 milestone</a> on our issue tracker for details.
+</p>
+
 <h2 id="go1.6">go1.6 (released 2016/02/17)</h2>
 
 <p>
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index 4469d71..7d006ff 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -1042,6 +1042,8 @@ func anylit(ctxt int, n *Node, var_ *Node, init *Nodes) {
 
 		var r *Node
 		if n.Right != nil {
+			// n.Right is stack temporary used as backing store.
+			init.Append(Nod(OAS, n.Right, nil)) // zero backing store, just in case (#18410)
 			r = Nod(OADDR, n.Right, nil)
 			r = typecheck(r, Erv)
 		} else {
diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go
index 59b303d..acdf43c 100644
--- a/src/crypto/x509/root_darwin.go
+++ b/src/crypto/x509/root_darwin.go
@@ -7,17 +7,22 @@
 package x509
 
 import (
+	"bufio"
 	"bytes"
+	"crypto/sha1"
 	"encoding/pem"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"os"
 	"os/exec"
-	"strconv"
+	"path/filepath"
+	"strings"
 	"sync"
-	"syscall"
 )
 
+var debugExecDarwinRoots = strings.Contains(os.Getenv("GODEBUG"), "x509roots=1")
+
 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
 	return nil, nil
 }
@@ -27,7 +32,35 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
 // even if the tests are run with cgo enabled.
 // The linker will not include these unused functions in binaries built with cgo enabled.
 
+// execSecurityRoots finds the macOS list of trusted root certificates
+// using only command-line tools. This is our fallback path when cgo isn't available.
+//
+// The strategy is as follows:
+//
+// 1. Run "security trust-settings-export" and "security
+//    trust-settings-export -d" to discover the set of certs with some
+//    user-tweaked trust policy. We're too lazy to parse the XML (at
+//    least at this stage of Go 1.8) to understand what the trust
+//    policy actually is. We just learn that there is _some_ policy.
+//
+// 2. Run "security find-certificate" to dump the list of system root
+//    CAs in PEM format.
+//
+// 3. For each dumped cert, conditionally verify it with "security
+//    verify-cert" if that cert was in the set discovered in Step 1.
+//    Without the Step 1 optimization, running "security verify-cert"
+//    150-200 times takes 3.5 seconds. With the optimization, the
+//    whole process takes about 180 milliseconds with 1 untrusted root
+//    CA. (Compared to 110ms in the cgo path)
 func execSecurityRoots() (*CertPool, error) {
+	hasPolicy, err := getCertsWithTrustPolicy()
+	if err != nil {
+		return nil, err
+	}
+	if debugExecDarwinRoots {
+		println(fmt.Sprintf("crypto/x509: %d certs have a trust policy", len(hasPolicy)))
+	}
+
 	cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
 	data, err := cmd.Output()
 	if err != nil {
@@ -35,22 +68,49 @@ func execSecurityRoots() (*CertPool, error) {
 	}
 
 	var (
-		mu    sync.Mutex
-		roots = NewCertPool()
+		mu          sync.Mutex
+		roots       = NewCertPool()
+		numVerified int // number of execs of 'security verify-cert', for debug stats
 	)
-	add := func(cert *Certificate) {
-		mu.Lock()
-		defer mu.Unlock()
-		roots.AddCert(cert)
-	}
+
 	blockCh := make(chan *pem.Block)
 	var wg sync.WaitGroup
+
+	// Using 4 goroutines to pipe into verify-cert seems to be
+	// about the best we can do. The verify-cert binary seems to
+	// just RPC to another server with coarse locking anyway, so
+	// running 16 at a time for instance doesn't help at all. Due
+	// to the "if hasPolicy" check below, though, we will rarely
+	// (or never) call verify-cert on stock macOS systems, though.
+	// The hope is that we only call verify-cert when the user has
+	// tweaked their trust poliy. These 4 goroutines are only
+	// defensive in the pathological case of many trust edits.
 	for i := 0; i < 4; i++ {
 		wg.Add(1)
 		go func() {
 			defer wg.Done()
 			for block := range blockCh {
-				verifyCertWithSystem(block, add)
+				cert, err := ParseCertificate(block.Bytes)
+				if err != nil {
+					continue
+				}
+				sha1CapHex := fmt.Sprintf("%X", sha1.Sum(block.Bytes))
+
+				valid := true
+				verifyChecks := 0
+				if hasPolicy[sha1CapHex] {
+					verifyChecks++
+					if !verifyCertWithSystem(block, cert) {
+						valid = false
+					}
+				}
+
+				mu.Lock()
+				numVerified += verifyChecks
+				if valid {
+					roots.AddCert(cert)
+				}
+				mu.Unlock()
 			}
 		}()
 	}
@@ -67,67 +127,118 @@ func execSecurityRoots() (*CertPool, error) {
 	}
 	close(blockCh)
 	wg.Wait()
+
+	if debugExecDarwinRoots {
+		mu.Lock()
+		defer mu.Unlock()
+		println(fmt.Sprintf("crypto/x509: ran security verify-cert %d times", numVerified))
+	}
+
 	return roots, nil
 }
 
-func verifyCertWithSystem(block *pem.Block, add func(*Certificate)) {
+func verifyCertWithSystem(block *pem.Block, cert *Certificate) bool {
 	data := pem.EncodeToMemory(block)
-	var cmd *exec.Cmd
-	if needsTmpFiles() {
-		f, err := ioutil.TempFile("", "cert")
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "can't create temporary file for cert: %v", err)
-			return
-		}
-		defer os.Remove(f.Name())
-		if _, err := f.Write(data); err != nil {
-			fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
-			return
-		}
-		if err := f.Close(); err != nil {
-			fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
-			return
-		}
-		cmd = exec.Command("/usr/bin/security", "verify-cert", "-c", f.Name(), "-l")
-	} else {
-		cmd = exec.Command("/usr/bin/security", "verify-cert", "-c", "/dev/stdin", "-l")
-		cmd.Stdin = bytes.NewReader(data)
-	}
-	if cmd.Run() == nil {
-		// Non-zero exit means untrusted
-		cert, err := ParseCertificate(block.Bytes)
-		if err != nil {
-			return
-		}
 
-		add(cert)
+	f, err := ioutil.TempFile("", "cert")
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "can't create temporary file for cert: %v", err)
+		return false
+	}
+	defer os.Remove(f.Name())
+	if _, err := f.Write(data); err != nil {
+		fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
+		return false
+	}
+	if err := f.Close(); err != nil {
+		fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
+		return false
+	}
+	cmd := exec.Command("/usr/bin/security", "verify-cert", "-c", f.Name(), "-l", "-L")
+	var stderr bytes.Buffer
+	if debugExecDarwinRoots {
+		cmd.Stderr = &stderr
+	}
+	if err := cmd.Run(); err != nil {
+		if debugExecDarwinRoots {
+			println(fmt.Sprintf("crypto/x509: verify-cert rejected %s: %q", cert.Subject.CommonName, bytes.TrimSpace(stderr.Bytes())))
+		}
+		return false
+	}
+	if debugExecDarwinRoots {
+		println(fmt.Sprintf("crypto/x509: verify-cert approved %s", cert.Subject.CommonName))
 	}
+	return true
 }
 
-var versionCache struct {
-	sync.Once
-	major int
-}
+// getCertsWithTrustPolicy returns the set of certs that have a
+// possibly-altered trust policy. The keys of the map are capitalized
+// sha1 hex of the raw cert.
+// They are the certs that should be checked against `security
+// verify-cert` to see whether the user altered the default trust
+// settings. This code is only used for cgo-disabled builds.
+func getCertsWithTrustPolicy() (map[string]bool, error) {
+	set := map[string]bool{}
+	td, err := ioutil.TempDir("", "x509trustpolicy")
+	if err != nil {
+		return nil, err
+	}
+	defer os.RemoveAll(td)
+	run := func(file string, args ...string) error {
+		file = filepath.Join(td, file)
+		args = append(args, file)
+		cmd := exec.Command("/usr/bin/security", args...)
+		var stderr bytes.Buffer
+		cmd.Stderr = &stderr
+		if err := cmd.Run(); err != nil {
+			// If there are no trust settings, the
+			// `security trust-settings-export` command
+			// fails with:
+			//    exit status 1, SecTrustSettingsCreateExternalRepresentation: No Trust Settings were found.
+			// Rather than match on English substrings that are probably localized
+			// on macOS, just treat interpret any failure as meaning that there are
+			// no trust settings.
+			if debugExecDarwinRoots {
+				println(fmt.Sprintf("crypto/x509: exec %q: %v, %s", cmd.Args, err, stderr.Bytes()))
+			}
+			return nil
+		}
 
-// needsTmpFiles reports whether the OS is <= 10.11 (which requires real
-// files as arguments to the security command).
-func needsTmpFiles() bool {
-	versionCache.Do(func() {
-		release, err := syscall.Sysctl("kern.osrelease")
+		f, err := os.Open(file)
 		if err != nil {
-			return
+			return err
 		}
-		for i, c := range release {
-			if c == '.' {
-				release = release[:i]
+		defer f.Close()
+
+		// Gather all the runs of 40 capitalized hex characters.
+		br := bufio.NewReader(f)
+		var hexBuf bytes.Buffer
+		for {
+			b, err := br.ReadByte()
+			isHex := ('A' <= b && b <= 'F') || ('0' <= b && b <= '9')
+			if isHex {
+				hexBuf.WriteByte(b)
+			} else {
+				if hexBuf.Len() == 40 {
+					set[hexBuf.String()] = true
+				}
+				hexBuf.Reset()
+			}
+			if err == io.EOF {
 				break
 			}
+			if err != nil {
+				return err
+			}
 		}
-		major, err := strconv.Atoi(release)
-		if err != nil {
-			return
-		}
-		versionCache.major = major
-	})
-	return versionCache.major <= 15
+
+		return nil
+	}
+	if err := run("user", "trust-settings-export"); err != nil {
+		return nil, fmt.Errorf("dump-trust-settings (user): %v", err)
+	}
+	if err := run("admin", "trust-settings-export", "-d"); err != nil {
+		return nil, fmt.Errorf("dump-trust-settings (admin): %v", err)
+	}
+	return set, nil
 }
diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go
index c8ca3ea..ac97e4e 100644
--- a/src/crypto/x509/root_darwin_test.go
+++ b/src/crypto/x509/root_darwin_test.go
@@ -7,6 +7,7 @@ package x509
 import (
 	"runtime"
 	"testing"
+	"time"
 )
 
 func TestSystemRoots(t *testing.T) {
@@ -15,13 +16,21 @@ func TestSystemRoots(t *testing.T) {
 		t.Skipf("skipping on %s/%s, no system root", runtime.GOOS, runtime.GOARCH)
 	}
 
-	sysRoots := systemRootsPool()         // actual system roots
+	t0 := time.Now()
+	sysRoots := systemRootsPool() // actual system roots
+	sysRootsDuration := time.Since(t0)
+
+	t1 := time.Now()
 	execRoots, err := execSecurityRoots() // non-cgo roots
+	execSysRootsDuration := time.Since(t1)
 
 	if err != nil {
 		t.Fatalf("failed to read system roots: %v", err)
 	}
 
+	t.Logf("    cgo sys roots: %v", sysRootsDuration)
+	t.Logf("non-cgo sys roots: %v", execSysRootsDuration)
+
 	for _, tt := range []*CertPool{sysRoots, execRoots} {
 		if tt == nil {
 			t.Fatal("no system roots")
diff --git a/src/reflect/makefunc.go b/src/reflect/makefunc.go
index ad2ebd0..a7efeb8 100644
--- a/src/reflect/makefunc.go
+++ b/src/reflect/makefunc.go
@@ -70,6 +70,8 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
 // word in the passed-in argument frame.
 func makeFuncStub()
 
+// This type is partially duplicated as runtime.reflectMethodValue.
+// Any changes should be reflected in both.
 type methodValue struct {
 	fn     uintptr
 	stack  *bitVector // stack bitmap for args - offset known to runtime
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index 3b238cb..67b4a21 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -1076,8 +1076,6 @@ top:
 		// objects reachable from global roots since they don't have write
 		// barriers. Rescan some roots and flush work caches.
 
-		gcMarkRootCheck()
-
 		// Disallow caching workbufs and indicate that we're in mark 2.
 		gcBlackenPromptly = true
 
@@ -1101,6 +1099,16 @@ top:
 			})
 		})
 
+		// Check that roots are marked. We should be able to
+		// do this before the forEachP, but based on issue
+		// #16083 there may be a (harmless) race where we can
+		// enter mark 2 while some workers are still scanning
+		// stacks. The forEachP ensures these scans are done.
+		//
+		// TODO(austin): Figure out the race and fix this
+		// properly.
+		gcMarkRootCheck()
+
 		// Now we can start up mark 2 workers.
 		atomic.Xaddint64(&gcController.dedicatedMarkWorkersNeeded, 0xffffffff)
 		atomic.Xaddint64(&gcController.fractionalMarkWorkersNeeded, 0xffffffff)
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index aa7f7a7..e5000ed 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -106,26 +106,32 @@ func gcMarkRootCheck() {
 
 	lock(&allglock)
 	// Check that stacks have been scanned.
+	var gp *g
 	if gcphase == _GCmarktermination {
 		for i := 0; i < len(allgs); i++ {
-			gp := allgs[i]
+			gp = allgs[i]
 			if !(gp.gcscandone && gp.gcscanvalid) && readgstatus(gp) != _Gdead {
-				println("gp", gp, "goid", gp.goid,
-					"status", readgstatus(gp),
-					"gcscandone", gp.gcscandone,
-					"gcscanvalid", gp.gcscanvalid)
-				throw("scan missed a g")
+				goto fail
 			}
 		}
 	} else {
 		for i := 0; i < work.nStackRoots; i++ {
-			gp := allgs[i]
+			gp = allgs[i]
 			if !gp.gcscandone {
-				throw("scan missed a g")
+				goto fail
 			}
 		}
 	}
 	unlock(&allglock)
+	return
+
+fail:
+	println("gp", gp, "goid", gp.goid,
+		"status", readgstatus(gp),
+		"gcscandone", gp.gcscandone,
+		"gcscanvalid", gp.gcscanvalid)
+	unlock(&allglock) // Avoid self-deadlock with traceback.
+	throw("scan missed a g")
 }
 
 // ptrmask for an allocation containing a single pointer.
diff --git a/src/runtime/select.go b/src/runtime/select.go
index 433048f..23299e4 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -422,8 +422,62 @@ loop:
 	gp.param = nil
 	gopark(selparkcommit, nil, "select", traceEvGoBlockSelect, 2)
 
-	// someone woke us up
-	sellock(scases, lockorder)
+	// While we were asleep, some goroutine came along and completed
+	// one of the cases in the select and woke us up (called ready).
+	// As part of that process, the goroutine did a cas on done above
+	// (aka *sg.selectdone for all queued sg) to win the right to
+	// complete the select. Now done = 1.
+	//
+	// If we copy (grow) our own stack, we will update the
+	// selectdone pointers inside the gp.waiting sudog list to point
+	// at the new stack. Another goroutine attempting to
+	// complete one of our (still linked in) select cases might
+	// see the new selectdone pointer (pointing at the new stack)
+	// before the new stack has real data; if the new stack has done = 0
+	// (before the old values are copied over), the goroutine might
+	// do a cas via sg.selectdone and incorrectly believe that it has
+	// won the right to complete the select, executing a second
+	// communication and attempting to wake us (call ready) again.
+	//
+	// Then things break.
+	//
+	// The best break is that the goroutine doing ready sees the
+	// _Gcopystack status and throws, as in #17007.
+	// A worse break would be for us to continue on, start running real code,
+	// block in a semaphore acquisition (sema.go), and have the other
+	// goroutine wake us up without having really acquired the semaphore.
+	// That would result in the goroutine spuriously running and then
+	// queue up another spurious wakeup when the semaphore really is ready.
+	// In general the situation can cascade until something notices the
+	// problem and causes a crash.
+	//
+	// A stack shrink does not have this problem, because it locks
+	// all the channels that are involved first, blocking out the
+	// possibility of a cas on selectdone.
+	//
+	// A stack growth before gopark above does not have this
+	// problem, because we hold those channel locks (released by
+	// selparkcommit).
+	//
+	// A stack growth after sellock below does not have this
+	// problem, because again we hold those channel locks.
+	//
+	// The only problem is a stack growth during sellock.
+	// To keep that from happening, run sellock on the system stack.
+	//
+	// It might be that we could avoid this if copystack copied the
+	// stack before calling adjustsudogs. In that case,
+	// syncadjustsudogs would need to recopy the tiny part that
+	// it copies today, resulting in a little bit of extra copying.
+	//
+	// An even better fix, not for the week before a release candidate,
+	// would be to put space in every sudog and make selectdone
+	// point at (say) the space in the first sudog.
+
+	systemstack(func() {
+		sellock(scases, lockorder)
+	})
+
 	sg = (*sudog)(gp.param)
 	gp.param = nil
 
@@ -464,8 +518,15 @@ loop:
 	}
 
 	if cas == nil {
-		// This can happen if we were woken up by a close().
-		// TODO: figure that out explicitly so we don't need this loop.
+		// We can wake up with gp.param == nil (so cas == nil)
+		// when a channel involved in the select has been closed.
+		// It is easiest to loop and re-run the operation;
+		// we'll see that it's now closed.
+		// Maybe some day we can signal the close explicitly,
+		// but we'd have to distinguish close-on-reader from close-on-writer.
+		// It's easiest not to duplicate the code and just recheck above.
+		// We know that something closed, and things never un-close,
+		// so we won't block again.
 		goto loop
 	}
 
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 80a5440..36abe1f 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -107,7 +107,7 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
 			}
 			frame.fn = f
 			frame.argp = uintptr(deferArgs(d))
-			frame.arglen, frame.argmap = getArgInfo(&frame, f, true)
+			frame.arglen, frame.argmap = getArgInfo(&frame, f, true, fn)
 		}
 		frame.continpc = frame.pc
 		if !callback((*stkframe)(noescape(unsafe.Pointer(&frame))), v) {
@@ -339,7 +339,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 		// metadata recorded by f's caller.
 		if callback != nil || printing {
 			frame.argp = frame.fp + sys.MinFrameSize
-			frame.arglen, frame.argmap = getArgInfo(&frame, f, callback != nil)
+			frame.arglen, frame.argmap = getArgInfo(&frame, f, callback != nil, nil)
 		}
 
 		// Determine frame's 'continuation PC', where it can continue.
@@ -546,19 +546,48 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 	return n
 }
 
-func getArgInfo(frame *stkframe, f *_func, needArgMap bool) (arglen uintptr, argmap *bitvector) {
+// reflectMethodValue is a partial duplicate of reflect.methodValue.
+type reflectMethodValue struct {
+	fn    uintptr
+	stack *bitvector // args bitmap
+}
+
+// getArgInfo returns the argument frame information for a call to f
+// with call frame frame.
+//
+// This is used for both actual calls with active stack frames and for
+// deferred calls that are not yet executing. If this is an actual
+// call, ctxt must be nil (getArgInfo will retrieve what it needs from
+// the active stack frame). If this is a deferred call, ctxt must be
+// the function object that was deferred.
+func getArgInfo(frame *stkframe, f *_func, needArgMap bool, ctxt *funcval) (arglen uintptr, argmap *bitvector) {
 	arglen = uintptr(f.args)
 	if needArgMap && f.args == _ArgsSizeUnknown {
 		// Extract argument bitmaps for reflect stubs from the calls they made to reflect.
 		switch funcname(f) {
 		case "reflect.makeFuncStub", "reflect.methodValueCall":
-			arg0 := frame.sp + sys.MinFrameSize
-			fn := *(**[2]uintptr)(unsafe.Pointer(arg0))
-			if fn[0] != f.entry {
+			// These take a *reflect.methodValue as their
+			// context register.
+			var mv *reflectMethodValue
+			if ctxt != nil {
+				// This is not an actual call, but a
+				// deferred call. The function value
+				// is itself the *reflect.methodValue.
+				mv = (*reflectMethodValue)(unsafe.Pointer(ctxt))
+			} else {
+				// This is a real call that took the
+				// *reflect.methodValue as its context
+				// register and immediately saved it
+				// to 0(SP). Get the methodValue from
+				// 0(SP).
+				arg0 := frame.sp + sys.MinFrameSize
+				mv = *(**reflectMethodValue)(unsafe.Pointer(arg0))
+			}
+			if mv.fn != f.entry {
 				print("runtime: confused by ", funcname(f), "\n")
 				throw("reflect mismatch")
 			}
-			bv := (*bitvector)(unsafe.Pointer(fn[1]))
+			bv := mv.stack
 			arglen = uintptr(bv.n * sys.PtrSize)
 			argmap = bv
 		}
diff --git a/src/time/time_test.go b/src/time/time_test.go
index b7ebb37..c9665ea 100644
--- a/src/time/time_test.go
+++ b/src/time/time_test.go
@@ -939,8 +939,11 @@ func TestLoadFixed(t *testing.T) {
 	// but Go and most other systems use "east is positive".
 	// So GMT+1 corresponds to -3600 in the Go zone, not +3600.
 	name, offset := Now().In(loc).Zone()
-	if name != "GMT+1" || offset != -1*60*60 {
-		t.Errorf("Now().In(loc).Zone() = %q, %d, want %q, %d", name, offset, "GMT+1", -1*60*60)
+	// The zone abbreviation is "-01" since tzdata-2016g, and "GMT+1"
+	// on earlier versions; we accept both. (Issue #17276).
+	if !(name == "GMT+1" || name == "-01") || offset != -1*60*60 {
+		t.Errorf("Now().In(loc).Zone() = %q, %d, want %q or %q, %d",
+			name, offset, "GMT+1", "-01", -1*60*60)
 	}
 }
 
diff --git a/test/fixedbugs/issue16331.go b/test/fixedbugs/issue16331.go
new file mode 100644
index 0000000..665e7fc
--- /dev/null
+++ b/test/fixedbugs/issue16331.go
@@ -0,0 +1,48 @@
+// run
+
+// 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.
+
+// Perform tracebackdefers with a deferred reflection method.
+
+package main
+
+import "reflect"
+
+type T struct{}
+
+func (T) M() {
+}
+
+func F(args []reflect.Value) (results []reflect.Value) {
+	return nil
+}
+
+func main() {
+	done := make(chan bool)
+	go func() {
+		// Test reflect.makeFuncStub.
+		t := reflect.TypeOf((func())(nil))
+		f := reflect.MakeFunc(t, F).Interface().(func())
+		defer f()
+		growstack(10000)
+		done <- true
+	}()
+	<-done
+	go func() {
+		// Test reflect.methodValueCall.
+		f := reflect.ValueOf(T{}).Method(0).Interface().(func())
+		defer f()
+		growstack(10000)
+		done <- true
+	}()
+	<-done
+}
+
+func growstack(x int) {
+	if x == 0 {
+		return
+	}
+	growstack(x - 1)
+}
diff --git a/test/fixedbugs/issue18410.go b/test/fixedbugs/issue18410.go
new file mode 100644
index 0000000..e9c6f86
--- /dev/null
+++ b/test/fixedbugs/issue18410.go
@@ -0,0 +1,40 @@
+// run
+
+// 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.
+
+// This checks partially initialized structure literals
+// used to create value.method functions have their
+// non-initialized fields properly zeroed/nil'd
+
+package main
+
+type X struct {
+	A, B, C *int
+}
+
+//go:noinline
+func (t X) Print() {
+	if t.B != nil {
+		panic("t.B must be nil")
+	}
+}
+
+//go:noinline
+func caller(f func()) {
+	f()
+}
+
+//go:noinline
+func test() {
+	var i, j int
+	x := X{A: &i, C: &j}
+	caller(func() { X{A: &i, C: &j}.Print() })
+	caller(X{A: &i, C: &j}.Print)
+	caller(x.Print)
+}
+
+func main() {
+	test()
+}

-- 
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