-
- SystemCertPool
- is now implemented on Windows.
-
-
PSS signatures are now supported.
@@ -1617,9 +1613,9 @@ it already rejected dates beyond the end of the month, such as
June 31 and July 32.
-
+
The tzdata database has been updated to version
- 2016i for systems that don't already have a local time zone
+ 2016j for systems that don't already have a local time zone
database.
diff --git a/doc/install.html b/doc/install.html
index 2143d591cb25462cadfa43d9434c363f45d74ad2..6bff75c5a06ac60649f29be63de7fdca852562bb 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -250,7 +250,7 @@ $ cd $HOME/go/src/hello
$ go build
-
+
C:\> cd %USERPROFILE%\go\src\hello
C:\Users\Gopher\go\src\hello> go build
@@ -267,7 +267,7 @@ $ ./hello
hello, world
-
+
C:\Users\Gopher\go\src\hello> hello
hello, world
diff --git a/misc/cgo/testplugin/src/iface/main.go b/misc/cgo/testplugin/src/iface/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..5e7e4d8b4802141f2e81d2bbb7b9676e0af390e4
--- /dev/null
+++ b/misc/cgo/testplugin/src/iface/main.go
@@ -0,0 +1,46 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "iface_i"
+ "log"
+ "plugin"
+)
+
+func main() {
+ a, err := plugin.Open("iface_a.so")
+ if err != nil {
+ log.Fatalf(`plugin.Open("iface_a.so"): %v`, err)
+ }
+ b, err := plugin.Open("iface_b.so")
+ if err != nil {
+ log.Fatalf(`plugin.Open("iface_b.so"): %v`, err)
+ }
+
+ af, err := a.Lookup("F")
+ if err != nil {
+ log.Fatalf(`a.Lookup("F") failed: %v`, err)
+ }
+ bf, err := b.Lookup("F")
+ if err != nil {
+ log.Fatalf(`b.Lookup("F") failed: %v`, err)
+ }
+ if af.(func() interface{})() != bf.(func() interface{})() {
+ panic("empty interfaces not equal")
+ }
+
+ ag, err := a.Lookup("G")
+ if err != nil {
+ log.Fatalf(`a.Lookup("G") failed: %v`, err)
+ }
+ bg, err := b.Lookup("G")
+ if err != nil {
+ log.Fatalf(`b.Lookup("G") failed: %v`, err)
+ }
+ if ag.(func() iface_i.I)() != bg.(func() iface_i.I)() {
+ panic("nonempty interfaces not equal")
+ }
+}
diff --git a/misc/cgo/testplugin/src/iface_a/a.go b/misc/cgo/testplugin/src/iface_a/a.go
new file mode 100644
index 0000000000000000000000000000000000000000..29d2e2776406624d76965a420ce4e3fcc8b62d9c
--- /dev/null
+++ b/misc/cgo/testplugin/src/iface_a/a.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "iface_i"
+
+//go:noinline
+func F() interface{} {
+ return (*iface_i.T)(nil)
+}
+
+//go:noinline
+func G() iface_i.I {
+ return (*iface_i.T)(nil)
+}
diff --git a/misc/cgo/testplugin/src/iface_b/b.go b/misc/cgo/testplugin/src/iface_b/b.go
new file mode 100644
index 0000000000000000000000000000000000000000..29d2e2776406624d76965a420ce4e3fcc8b62d9c
--- /dev/null
+++ b/misc/cgo/testplugin/src/iface_b/b.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "iface_i"
+
+//go:noinline
+func F() interface{} {
+ return (*iface_i.T)(nil)
+}
+
+//go:noinline
+func G() iface_i.I {
+ return (*iface_i.T)(nil)
+}
diff --git a/misc/cgo/testplugin/src/iface_i/i.go b/misc/cgo/testplugin/src/iface_i/i.go
new file mode 100644
index 0000000000000000000000000000000000000000..31c80387c7e56c752e422fb73e81592d1a34c87b
--- /dev/null
+++ b/misc/cgo/testplugin/src/iface_i/i.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package iface_i
+
+type I interface {
+ M()
+}
+
+type T struct {
+}
+
+func (t *T) M() {
+}
+
+// *T implements I
diff --git a/misc/cgo/testplugin/src/issue18676/dynamodbstreamsevt/definition.go b/misc/cgo/testplugin/src/issue18676/dynamodbstreamsevt/definition.go
new file mode 100644
index 0000000000000000000000000000000000000000..70fd054d089ee2cde6447298741454f25c3a0b37
--- /dev/null
+++ b/misc/cgo/testplugin/src/issue18676/dynamodbstreamsevt/definition.go
@@ -0,0 +1,13 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dynamodbstreamsevt
+
+import "encoding/json"
+
+var foo json.RawMessage
+
+type Event struct{}
+
+func (e *Event) Dummy() {}
diff --git a/misc/cgo/testplugin/src/issue18676/main.go b/misc/cgo/testplugin/src/issue18676/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..c75409dafe7fd73e3a85401b158b5a1675d9d44a
--- /dev/null
+++ b/misc/cgo/testplugin/src/issue18676/main.go
@@ -0,0 +1,31 @@
+// Copyright 2017 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 bug happened like this:
+// 1) The main binary adds an itab for *json.UnsupportedValueError / error
+// (concrete type / interface type). This itab goes in hash bucket 0x111.
+// 2) The plugin adds that same itab again. That makes a cycle in the itab
+// chain rooted at hash bucket 0x111.
+// 3) The main binary then asks for the itab for *dynamodbstreamsevt.Event /
+// json.Unmarshaler. This itab happens to also live in bucket 0x111.
+// The lookup code goes into an infinite loop searching for this itab.
+// The code is carefully crafted so that the two itabs are both from the
+// same bucket, and so that the second itab doesn't exist in
+// the itab hashmap yet (so the entire linked list must be searched).
+package main
+
+import (
+ "encoding/json"
+ "issue18676/dynamodbstreamsevt"
+ "plugin"
+)
+
+func main() {
+ plugin.Open("plugin.so")
+
+ var x interface{} = (*dynamodbstreamsevt.Event)(nil)
+ if _, ok := x.(json.Unmarshaler); !ok {
+ println("something")
+ }
+}
diff --git a/misc/cgo/testplugin/src/issue18676/plugin.go b/misc/cgo/testplugin/src/issue18676/plugin.go
new file mode 100644
index 0000000000000000000000000000000000000000..8a3b85a75cd2a87ca8cb8b6fe623a37717da39a7
--- /dev/null
+++ b/misc/cgo/testplugin/src/issue18676/plugin.go
@@ -0,0 +1,11 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "C"
+
+import "issue18676/dynamodbstreamsevt"
+
+func F(evt *dynamodbstreamsevt.Event) {}
diff --git a/misc/cgo/testplugin/test.bash b/misc/cgo/testplugin/test.bash
index fee99a758c0c0aea6cd81efe760b9349631e993b..ab7430acc37f95e580492a1aa341c51e5eaa41e6 100755
--- a/misc/cgo/testplugin/test.bash
+++ b/misc/cgo/testplugin/test.bash
@@ -15,8 +15,8 @@ goos=$(go env GOOS)
goarch=$(go env GOARCH)
function cleanup() {
- rm -f plugin*.so unnamed*.so
- rm -rf host pkg sub
+ rm -f plugin*.so unnamed*.so iface*.so
+ rm -rf host pkg sub iface issue18676
}
trap cleanup EXIT
@@ -32,3 +32,15 @@ GOPATH=$(pwd) go build -buildmode=plugin unnamed2.go
GOPATH=$(pwd) go build host
LD_LIBRARY_PATH=$(pwd) ./host
+
+# Test that types and itabs get properly uniqified.
+GOPATH=$(pwd) go build -buildmode=plugin iface_a
+GOPATH=$(pwd) go build -buildmode=plugin iface_b
+GOPATH=$(pwd) go build iface
+LD_LIBRARY_PATH=$(pwd) ./iface
+
+# Test for issue 18676 - make sure we don't add the same itab twice.
+# The buggy code hangs forever, so use a timeout to check for that.
+GOPATH=$(pwd) go build -buildmode=plugin -o plugin.so src/issue18676/plugin.go
+GOPATH=$(pwd) go build -o issue18676 src/issue18676/main.go
+timeout 10s ./issue18676
diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go
index af4f91550f2094beb4152d5fb59b7d7252585054..f0766e511ec5b3e60f9365afa5d2154793d8349c 100644
--- a/misc/cgo/testshared/shared_test.go
+++ b/misc/cgo/testshared/shared_test.go
@@ -815,3 +815,14 @@ goCmd(t, "install", "-buildmode=shared", "-linkshared", "explicit")
goCmd(t, "install", "-linkshared", "implicitcmd")
run(t, "running executable linked against library that contains same package as it", "./bin/implicitcmd")
}
+
+// Tests to make sure that the type fields of empty interfaces and itab
+// fields of nonempty interfaces are unique even across modules,
+// so that interface equality works correctly.
+func TestInterface(t *testing.T) {
+ goCmd(t, "install", "-buildmode=shared", "-linkshared", "iface_a")
+ // Note: iface_i gets installed implicitly as a dependency of iface_a.
+ goCmd(t, "install", "-buildmode=shared", "-linkshared", "iface_b")
+ goCmd(t, "install", "-linkshared", "iface")
+ run(t, "running type/itab uniqueness tester", "./bin/iface")
+}
diff --git a/misc/cgo/testshared/src/iface/main.go b/misc/cgo/testshared/src/iface/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..3d5b54e73b9e8b0ad35a925ee845ee0e4698d808
--- /dev/null
+++ b/misc/cgo/testshared/src/iface/main.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "iface_a"
+import "iface_b"
+
+func main() {
+ if iface_a.F() != iface_b.F() {
+ panic("empty interfaces not equal")
+ }
+ if iface_a.G() != iface_b.G() {
+ panic("non-empty interfaces not equal")
+ }
+}
diff --git a/misc/cgo/testshared/src/iface_a/a.go b/misc/cgo/testshared/src/iface_a/a.go
new file mode 100644
index 0000000000000000000000000000000000000000..e11047c166c66523e5a7960d150465c18eb922ac
--- /dev/null
+++ b/misc/cgo/testshared/src/iface_a/a.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package iface_a
+
+import "iface_i"
+
+//go:noinline
+func F() interface{} {
+ return (*iface_i.T)(nil)
+}
+
+//go:noinline
+func G() iface_i.I {
+ return (*iface_i.T)(nil)
+}
diff --git a/misc/cgo/testshared/src/iface_b/b.go b/misc/cgo/testshared/src/iface_b/b.go
new file mode 100644
index 0000000000000000000000000000000000000000..47aee2e77ee9d71e00947099b040ac0de252f52b
--- /dev/null
+++ b/misc/cgo/testshared/src/iface_b/b.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package iface_b
+
+import "iface_i"
+
+//go:noinline
+func F() interface{} {
+ return (*iface_i.T)(nil)
+}
+
+//go:noinline
+func G() iface_i.I {
+ return (*iface_i.T)(nil)
+}
diff --git a/misc/cgo/testshared/src/iface_i/i.go b/misc/cgo/testshared/src/iface_i/i.go
new file mode 100644
index 0000000000000000000000000000000000000000..31c80387c7e56c752e422fb73e81592d1a34c87b
--- /dev/null
+++ b/misc/cgo/testshared/src/iface_i/i.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package iface_i
+
+type I interface {
+ M()
+}
+
+type T struct {
+}
+
+func (t *T) M() {
+}
+
+// *T implements I
diff --git a/misc/ios/go_darwin_arm_exec.go b/misc/ios/go_darwin_arm_exec.go
index 1eeb289c7d249ce60f96425489a879267a5040ff..3de341b9c59170805f0fefc7387a0921f9a8e1a7 100644
--- a/misc/ios/go_darwin_arm_exec.go
+++ b/misc/ios/go_darwin_arm_exec.go
@@ -99,7 +99,7 @@ }
// Approximately 1 in a 100 binaries fail to start. If it happens,
// try again. These failures happen for several reasons beyond
// our control, but all of them are safe to retry as they happen
- // before lldb encounters the initial getwd breakpoint. As we
+ // before lldb encounters the initial SIGUSR2 stop. As we
// know the tests haven't started, we are not hiding flaky tests
// with this retry.
for i := 0; i < 5; i++ {
@@ -204,6 +204,11 @@
var opts options
opts, args = parseArgs(args)
+ // Pass the suffix for the current working directory as the
+ // first argument to the test. For iOS, cmd/go generates
+ // special handling of this argument.
+ args = append([]string{"cwdSuffix=" + pkgpath}, args...)
+
// ios-deploy invokes lldb to give us a shell session with the app.
s, err := newSession(appdir, args, opts)
if err != nil {
@@ -224,6 +229,7 @@ // Script LLDB. Oh dear.
s.do(`process handle SIGHUP --stop false --pass true --notify false`)
s.do(`process handle SIGPIPE --stop false --pass true --notify false`)
s.do(`process handle SIGUSR1 --stop false --pass true --notify false`)
+ s.do(`process handle SIGUSR2 --stop true --pass false --notify true`) // sent by test harness
s.do(`process handle SIGCONT --stop false --pass true --notify false`)
s.do(`process handle SIGSEGV --stop false --pass true --notify false`) // does not work
s.do(`process handle SIGBUS --stop false --pass true --notify false`) // does not work
@@ -236,20 +242,9 @@ }
return nil
}
- s.do(`breakpoint set -n getwd`) // in runtime/cgo/gcc_darwin_arm.go
-
started = true
- s.doCmd("run", "stop reason = breakpoint", 20*time.Second)
-
- // Move the current working directory into the faux gopath.
- if pkgpath != "src" {
- s.do(`breakpoint delete 1`)
- s.do(`expr char* $mem = (char*)malloc(512)`)
- s.do(`expr $mem = (char*)getwd($mem, 512)`)
- s.do(`expr $mem = (char*)strcat($mem, "/` + pkgpath + `")`)
- s.do(`call (void)chdir($mem)`)
- }
+ s.doCmd("run", "stop reason = signal SIGUSR2", 20*time.Second)
startTestsLen := s.out.Len()
fmt.Fprintln(s.in, `process continue`)
@@ -520,13 +515,11 @@ }
// Copy timezone file.
//
- // Typical apps have the zoneinfo.zip in the root of their app bundle,
+ // Apps have the zoneinfo.zip in the root of their app bundle,
// read by the time package as the working directory at initialization.
- // As we move the working directory to the GOROOT pkg directory, we
- // install the zoneinfo.zip file in the pkgpath.
if underGoRoot {
err := cp(
- filepath.Join(dstbase, pkgpath),
+ dstbase,
filepath.Join(cwd, "lib", "time", "zoneinfo.zip"),
)
if err != nil {
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
index 8113710e3983742d588f3da4ba2dbd52d5ba01ae..d4f3d9884ed989222d4ff92f4569ee5a3fac0c9c 100644
--- a/src/cmd/compile/internal/gc/alg.go
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -303,7 +303,9 @@ fn = typecheck(fn, Etop)
typecheckslice(fn.Nbody.Slice(), Etop)
Curfn = nil
popdcl()
- testdclstack()
+ if debug_dclstack != 0 {
+ testdclstack()
+ }
// Disable safemode while compiling this code: the code we
// generate internally can refer to unsafe.Pointer.
@@ -493,7 +495,9 @@ fn = typecheck(fn, Etop)
typecheckslice(fn.Nbody.Slice(), Etop)
Curfn = nil
popdcl()
- testdclstack()
+ if debug_dclstack != 0 {
+ testdclstack()
+ }
// Disable safemode while compiling this code: the code we
// generate internally can refer to unsafe.Pointer.
diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go
index 1d668412a181d05b6bc330865fc3e24535b1884e..94c1184138fc311349f504450e6487f909e2380a 100644
--- a/src/cmd/compile/internal/gc/bimport.go
+++ b/src/cmd/compile/internal/gc/bimport.go
@@ -217,7 +217,9 @@
typecheckok = tcok
resumecheckwidth()
- testdclstack() // debugging only
+ if debug_dclstack != 0 {
+ testdclstack()
+ }
}
func formatErrorf(format string, args ...interface{}) {
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 75f58a731c079f1bae8f7c19bfc4dd5467caa653..1690944b3df430c6cdf4f2d0d844f67dfed5ed87 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -30,11 +30,12 @@ buildid string
)
var (
- Debug_append int
- Debug_closure int
- Debug_panic int
- Debug_slice int
- Debug_wb int
+ Debug_append int
+ Debug_closure int
+ debug_dclstack int
+ Debug_panic int
+ Debug_slice int
+ Debug_wb int
)
// Debug arguments.
@@ -48,6 +49,7 @@ }{
{"append", &Debug_append}, // print information about append compilation
{"closure", &Debug_closure}, // print information about closure compilation
{"disablenil", &disable_checknil}, // disable nil checks
+ {"dclstack", &debug_dclstack}, // run internal dclstack checks
{"gcprog", &Debug_gcprog}, // print dump of GC programs
{"nil", &Debug_checknil}, // print information about nil checks
{"panic", &Debug_panic}, // do not hide any compiler panic
@@ -325,7 +327,6 @@ }
timings.Stop()
timings.AddEvent(int64(lexlineno-lexlineno0), "lines")
- testdclstack()
mkpackage(localpkg.Name) // final import not used checks
finishUniverse()
diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go
index ca99adea27caa1959e558b01c9a01c917a330037..ce18297ac3d31006ca50a85589a8bb8064aec832 100644
--- a/src/cmd/compile/internal/gc/noder.go
+++ b/src/cmd/compile/internal/gc/noder.go
@@ -34,6 +34,7 @@ }
}
if nsyntaxerrors == 0 {
+ // Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
testdclstack()
}
}
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 9b9a3f121015d86fa746647b255ed19ab632e13d..7d008dfa65527f9d020995bfa67cd84ac7d76ec7 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -1833,7 +1833,9 @@
funcbody(fn)
Curfn = fn
popdcl()
- testdclstack()
+ if debug_dclstack != 0 {
+ testdclstack()
+ }
// wrappers where T is anonymous (struct or interface) can be duplicated.
if rcvr.IsStruct() || rcvr.IsInterface() || rcvr.IsPtr() && rcvr.Elem().IsStruct() {
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index efe2016e46ca2c8be566259520d458881d03fb70..7c2e2ab442886c4f511300a77075ad968ec16fec 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -3117,12 +3117,12 @@ for cmpr != nil && cmpr.Op == OCONVNOP {
cmpr = cmpr.Left
}
- if !islvalue(cmpl) || !islvalue(cmpr) {
- Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
- }
-
// Chose not to inline. Call equality function directly.
if !inline {
+ if !islvalue(cmpl) || !islvalue(cmpr) {
+ Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
+ }
+
// eq algs take pointers
pl := temp(ptrto(t))
al := nod(OAS, pl, nod(OADDR, cmpl, nil))
diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go
index 1eb4d7bb1af5a929b411d756b08d7a7dd6a9a3a3..054ba1f85c6d155b3ecbbc79b64387678f038f63 100644
--- a/src/cmd/compile/internal/ssa/writebarrier.go
+++ b/src/cmd/compile/internal/ssa/writebarrier.go
@@ -35,7 +35,7 @@ for _, b := range f.Blocks { // range loop is safe since the blocks we added contain no WB stores
valueLoop:
for i, v := range b.Values {
switch v.Op {
- case OpStoreWB, OpMoveWB, OpMoveWBVolatile:
+ case OpStoreWB, OpMoveWB, OpMoveWBVolatile, OpZeroWB:
if IsStackAddr(v.Args[0]) {
switch v.Op {
case OpStoreWB:
diff --git a/src/cmd/go/bug.go b/src/cmd/go/bug.go
index cbd258b80bde5f030f5f791ec831e368c89bed6a..658f6dabd90417b7c4efd8608948560f5f0365b2 100644
--- a/src/cmd/go/bug.go
+++ b/src/cmd/go/bug.go
@@ -20,11 +20,10 @@
var cmdBug = &Command{
Run: runBug,
UsageLine: "bug",
- Short: "print information for bug reports",
+ Short: "start a bug report",
Long: `
-Bug prints information that helps file effective bug reports.
-
-Bugs may be reported at https://golang.org/issue/new.
+Bug opens the default browser and starts a new bug report.
+The report includes useful system information.
`,
}
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index cdb167de75f86565b53b2ef29fce1339c4836822..6482f0fd32301a83a0bb9174170705b204587ef7 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -894,8 +894,12 @@ }
if buildContext.GOOS == "darwin" {
if buildContext.GOARCH == "arm" || buildContext.GOARCH == "arm64" {
- t.NeedCgo = true
+ t.IsIOS = true
+ t.NeedOS = true
}
+ }
+ if t.TestMain == nil {
+ t.NeedOS = true
}
for _, cp := range pmain.imports {
@@ -1343,7 +1347,8 @@ ImportTest bool
NeedTest bool
ImportXtest bool
NeedXtest bool
- NeedCgo bool
+ NeedOS bool
+ IsIOS bool
Cover []coverInfo
}
@@ -1444,7 +1449,7 @@ var testmainTmpl = template.Must(template.New("main").Parse(`
package main
import (
-{{if not .TestMain}}
+{{if .NeedOS}}
"os"
{{end}}
"testing"
@@ -1460,8 +1465,10 @@ {{range $i, $p := .Cover}}
_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
{{end}}
-{{if .NeedCgo}}
+{{if .IsIOS}}
+ "os/signal"
_ "runtime/cgo"
+ "syscall"
{{end}}
)
@@ -1523,6 +1530,32 @@ }
{{end}}
func main() {
+{{if .IsIOS}}
+ // Send a SIGUSR2, which will be intercepted by LLDB to
+ // tell the test harness that installation was successful.
+ // See misc/ios/go_darwin_arm_exec.go.
+ signal.Notify(make(chan os.Signal), syscall.SIGUSR2)
+ syscall.Kill(0, syscall.SIGUSR2)
+ signal.Reset(syscall.SIGUSR2)
+
+ // The first argument supplied to an iOS test is an offset
+ // suffix for the current working directory.
+ // Process it here, and remove it from os.Args.
+ const hdr = "cwdSuffix="
+ if len(os.Args) < 2 || len(os.Args[1]) <= len(hdr) || os.Args[1][:len(hdr)] != hdr {
+ panic("iOS test not passed a working directory suffix")
+ }
+ suffix := os.Args[1][len(hdr):]
+ dir, err := os.Getwd()
+ if err != nil {
+ panic(err)
+ }
+ if err := os.Chdir(dir + "/" + suffix); err != nil {
+ panic(err)
+ }
+ os.Args = append([]string{os.Args[0]}, os.Args[2:]...)
+{{end}}
+
{{if .CoverEnabled}}
testing.RegisterCover(testing.Cover{
Mode: {{printf "%q" .CoverMode}},
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index 1ebd7de662ad4d1c2c7f5430bff15cf2fba44a9d..479425f2111ef6191778e136049b55921bc966e4 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -168,7 +168,7 @@ func container(s *Symbol) int {
if s == nil {
return 0
}
- if Buildmode == BuildmodePlugin && onlycsymbol(s) {
+ if Buildmode == BuildmodePlugin && Headtype == obj.Hdarwin && onlycsymbol(s) {
return 1
}
// We want to generate func table entries only for the "lowest level" symbols,
diff --git a/src/compress/bzip2/bzip2_test.go b/src/compress/bzip2/bzip2_test.go
index a6c3080db3efe5f49467b28e703aed888e560b02..95fb18958561b311a6d545cdc4cb976f34ab6cf4 100644
--- a/src/compress/bzip2/bzip2_test.go
+++ b/src/compress/bzip2/bzip2_test.go
@@ -204,12 +204,6 @@ }
}
}
-var (
- digits = mustLoadFile("testdata/e.txt.bz2")
- twain = mustLoadFile("testdata/Mark.Twain-Tom.Sawyer.txt.bz2")
- random = mustLoadFile("testdata/random.data.bz2")
-)
-
func benchmarkDecode(b *testing.B, compressed []byte) {
// Determine the uncompressed size of testfile.
uncompressedSize, err := io.Copy(ioutil.Discard, NewReader(bytes.NewReader(compressed)))
@@ -227,6 +221,18 @@ io.Copy(ioutil.Discard, NewReader(r))
}
}
-func BenchmarkDecodeDigits(b *testing.B) { benchmarkDecode(b, digits) }
-func BenchmarkDecodeTwain(b *testing.B) { benchmarkDecode(b, twain) }
-func BenchmarkDecodeRand(b *testing.B) { benchmarkDecode(b, random) }
+func BenchmarkDecodeDigits(b *testing.B) {
+ digits := mustLoadFile("testdata/e.txt.bz2")
+ b.ResetTimer()
+ benchmarkDecode(b, digits)
+}
+func BenchmarkDecodeTwain(b *testing.B) {
+ twain := mustLoadFile("testdata/Mark.Twain-Tom.Sawyer.txt.bz2")
+ b.ResetTimer()
+ benchmarkDecode(b, twain)
+}
+func BenchmarkDecodeRand(b *testing.B) {
+ random := mustLoadFile("testdata/random.data.bz2")
+ b.ResetTimer()
+ benchmarkDecode(b, random)
+}
diff --git a/src/compress/flate/deflate.go b/src/compress/flate/deflate.go
index 97265b3ca27ad091af42e7bf2ff120dd5e54f277..4d6a5357d881da4d90aba22d65728c60c075e287 100644
--- a/src/compress/flate/deflate.go
+++ b/src/compress/flate/deflate.go
@@ -136,14 +136,17 @@ if d.hashOffset > maxHashOffset {
delta := d.hashOffset - 1
d.hashOffset -= delta
d.chainHead -= delta
- for i, v := range d.hashPrev {
+
+ // Iterate over slices instead of arrays to avoid copying
+ // the entire table onto the stack (Issue #18625).
+ for i, v := range d.hashPrev[:] {
if int(v) > delta {
d.hashPrev[i] = uint32(int(v) - delta)
} else {
d.hashPrev[i] = 0
}
}
- for i, v := range d.hashHead {
+ for i, v := range d.hashHead[:] {
if int(v) > delta {
d.hashHead[i] = uint32(int(v) - delta)
} else {
diff --git a/src/compress/flate/deflate_test.go b/src/compress/flate/deflate_test.go
index 521a2603658b9bba53c7138f2c950750a2eecba9..fbea761721a3e4115437c0bf244068daf86cfca7 100644
--- a/src/compress/flate/deflate_test.go
+++ b/src/compress/flate/deflate_test.go
@@ -12,6 +12,7 @@ "internal/testenv"
"io"
"io/ioutil"
"reflect"
+ "runtime/debug"
"sync"
"testing"
)
@@ -864,3 +865,33 @@ }
}
}
}
+
+func TestMaxStackSize(t *testing.T) {
+ // This test must not run in parallel with other tests as debug.SetMaxStack
+ // affects all goroutines.
+ n := debug.SetMaxStack(1 << 16)
+ defer debug.SetMaxStack(n)
+
+ var wg sync.WaitGroup
+ defer wg.Wait()
+
+ b := make([]byte, 1<<20)
+ for level := HuffmanOnly; level <= BestCompression; level++ {
+ // Run in separate goroutine to increase probability of stack regrowth.
+ wg.Add(1)
+ go func(level int) {
+ defer wg.Done()
+ zw, err := NewWriter(ioutil.Discard, level)
+ if err != nil {
+ t.Errorf("level %d, NewWriter() = %v, want nil", level, err)
+ }
+ if n, err := zw.Write(b); n != len(b) || err != nil {
+ t.Errorf("level %d, Write() = (%d, %v), want (%d, nil)", level, n, err, len(b))
+ }
+ if err := zw.Close(); err != nil {
+ t.Errorf("level %d, Close() = %v, want nil", level, err)
+ }
+ zw.Reset(ioutil.Discard)
+ }(level)
+ }
+}
diff --git a/src/compress/flate/deflatefast.go b/src/compress/flate/deflatefast.go
index a1636a37d67cfa9826e78de10618c94faa12f5d6..08298b76bbb2da5a7882d439d61d8428b28f632a 100644
--- a/src/compress/flate/deflatefast.go
+++ b/src/compress/flate/deflatefast.go
@@ -60,7 +60,7 @@ // to dst and returns the result.
func (e *deflateFast) encode(dst []token, src []byte) []token {
// Ensure that e.cur doesn't wrap.
if e.cur > 1<<30 {
- *e = deflateFast{cur: maxStoreBlockSize, prev: e.prev[:0]}
+ e.resetAll()
}
// This check isn't in the Snappy implementation, but there, the caller
@@ -265,6 +265,21 @@ e.cur += maxMatchOffset
// Protect against e.cur wraparound.
if e.cur > 1<<30 {
- *e = deflateFast{cur: maxStoreBlockSize, prev: e.prev[:0]}
+ e.resetAll()
+ }
+}
+
+// resetAll resets the deflateFast struct and is only called in rare
+// situations to prevent integer overflow. It manually resets each field
+// to avoid causing large stack growth.
+//
+// See https://golang.org/issue/18636.
+func (e *deflateFast) resetAll() {
+ // This is equivalent to:
+ // *e = deflateFast{cur: maxStoreBlockSize, prev: e.prev[:0]}
+ e.cur = maxStoreBlockSize
+ e.prev = e.prev[:0]
+ for i := range e.table {
+ e.table[i] = tableEntry{}
}
}
diff --git a/src/compress/gzip/issue14937_test.go b/src/compress/gzip/issue14937_test.go
index e76d47cc4ee5700d9faedfeb8b94a3c7370ac3ae..30c1390dfd7faf0ca4d2e1e37c8868db2f9e2089 100644
--- a/src/compress/gzip/issue14937_test.go
+++ b/src/compress/gzip/issue14937_test.go
@@ -9,11 +9,17 @@ "strings"
"testing"
)
-// Per golang.org/issue/14937, check that every .gz file
-// in the tree has a zero mtime.
+// TestGZIPFilesHaveZeroMTimes checks that every .gz file in the tree
+// has a zero MTIME. This is a requirement for the Debian maintainers
+// to be able to have deterministic packages.
+//
+// See https://golang.org/issue/14937.
func TestGZIPFilesHaveZeroMTimes(t *testing.T) {
- if testing.Short() && testenv.Builder() == "" {
- t.Skip("skipping in short mode")
+ // To avoid spurious false positives due to untracked GZIP files that
+ // may be in the user's GOROOT (Issue 18604), we only run this test on
+ // the builders, which should have a clean checkout of the tree.
+ if testenv.Builder() == "" {
+ t.Skip("skipping test on non-builder")
}
goroot, err := filepath.EvalSymlinks(runtime.GOROOT())
if err != nil {
diff --git a/src/crypto/dsa/dsa_test.go b/src/crypto/dsa/dsa_test.go
index b89aeaebea6fcff67290fa2ae28b360931947d0f..8600059f0329fe26271a1d726e0923bcd9288ce5 100644
--- a/src/crypto/dsa/dsa_test.go
+++ b/src/crypto/dsa/dsa_test.go
@@ -95,7 +95,7 @@
func TestSigningWithDegenerateKeys(t *testing.T) {
// Signing with degenerate private keys should not cause an infinite
// loop.
- badKeys := []struct{
+ badKeys := []struct {
p, q, g, y, x string
}{
{"00", "01", "00", "00", "00"},
@@ -105,7 +105,7 @@
for i, test := range badKeys {
priv := PrivateKey{
PublicKey: PublicKey{
- Parameters: Parameters {
+ Parameters: Parameters{
P: fromHex(test.p),
Q: fromHex(test.q),
G: fromHex(test.g),
diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go
index 05146743acbba6010f3ac868bf2184303e11cf92..beb0f1926d89947d9603f0dbc2561ae08320d67f 100644
--- a/src/crypto/tls/cipher_suites.go
+++ b/src/crypto/tls/cipher_suites.go
@@ -84,15 +84,15 @@ {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
- {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
- {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
{TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
- {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
diff --git a/src/crypto/tls/tls.go b/src/crypto/tls/tls.go
index f2e5aea2bce5ed6d7305c2d8fdfd233b0d63c2fd..615d1e5576fdaab8c772eadae62a3d146757cc6d 100644
--- a/src/crypto/tls/tls.go
+++ b/src/crypto/tls/tls.go
@@ -6,8 +6,8 @@ // Package tls partially implements TLS 1.2, as specified in RFC 5246.
package tls
// BUG(agl): The crypto/tls package only implements some countermeasures
-// against Lucky13 attacks on CBC-mode encryption. See
-// http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
+// against Lucky13 attacks on CBC-mode encryption, and only on SHA1
+// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
import (
diff --git a/src/crypto/x509/cert_pool.go b/src/crypto/x509/cert_pool.go
index fea33df379aebdce57f78c6cc6a412e61acea99d..71ffbdf0e0460bd2df3d2a4e269f6056e3bd6b0d 100644
--- a/src/crypto/x509/cert_pool.go
+++ b/src/crypto/x509/cert_pool.go
@@ -4,7 +4,11 @@ // license that can be found in the LICENSE file.
package x509
-import "encoding/pem"
+import (
+ "encoding/pem"
+ "errors"
+ "runtime"
+)
// CertPool is a set of certificates.
type CertPool struct {
@@ -26,6 +30,11 @@ //
// Any mutations to the returned pool are not written to disk and do
// not affect any other pool.
func SystemCertPool() (*CertPool, error) {
+ if runtime.GOOS == "windows" {
+ // Issue 16736, 18609:
+ return nil, errors.New("crypto/x509: system root pool is not available on Windows")
+ }
+
return loadSystemRoots()
}
diff --git a/src/crypto/x509/root_windows.go b/src/crypto/x509/root_windows.go
index ca2fba5cb421fe7b7925358fa50d15061da99cc5..a936fec7d8447dbc27669b4ff9aae4f2a32288e2 100644
--- a/src/crypto/x509/root_windows.go
+++ b/src/crypto/x509/root_windows.go
@@ -226,6 +226,11 @@ return chains, nil
}
func loadSystemRoots() (*CertPool, error) {
+ // TODO: restore this functionality on Windows. We tried to do
+ // it in Go 1.8 but had to revert it. See Issue 18609.
+ // Returning (nil, nil) was the old behavior, prior to CL 30578.
+ return nil, nil
+
const CRYPT_E_NOT_FOUND = 0x80092004
store, err := syscall.CertOpenSystemStore(0, syscall.StringToUTF16Ptr("ROOT"))
diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go
index aa30d85b7da06de25236732d0536b7c572831454..b085dad90f06a5f78a21e91d0f4ea5f2ef102522 100644
--- a/src/crypto/x509/x509_test.go
+++ b/src/crypto/x509/x509_test.go
@@ -24,6 +24,7 @@ "math/big"
"net"
"os/exec"
"reflect"
+ "runtime"
"strings"
"testing"
"time"
@@ -1477,6 +1478,9 @@ }
}
func TestSystemCertPool(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("not implemented on Windows; Issue 16736, 18609")
+ }
_, err := SystemCertPool()
if err != nil {
t.Fatal(err)
diff --git a/src/go/ast/scope.go b/src/go/ast/scope.go
index 1ce5e2e84b5da1a7c4f9ee74666783c8a0add675..a400c7152a668a3e28e89ef9f18ff90d5357269a 100644
--- a/src/go/ast/scope.go
+++ b/src/go/ast/scope.go
@@ -70,10 +70,8 @@ //
// The Data fields contains object-specific data:
//
// Kind Data type Data value
-// Pkg *types.Package package scope
+// Pkg *Scope package scope
// Con int iota for the respective declaration
-// Con != nil constant value
-// Typ *Scope (used as method scope during type checking - transient)
//
type Object struct {
Kind ObjKind
diff --git a/src/go/doc/doc_test.go b/src/go/doc/doc_test.go
index ad8ba5378f3f13f7db193b5416bebb4439d0c18c..82e63100d4764d68516070e2e0e7fec2ac314011 100644
--- a/src/go/doc/doc_test.go
+++ b/src/go/doc/doc_test.go
@@ -25,7 +25,7 @@ var files = flag.String("files", "", "consider only Go test files matching this regular expression")
const dataDir = "testdata"
-var templateTxt = readTemplate("template.txt")
+var templateTxt *template.Template
func readTemplate(filename string) *template.Template {
t := template.New(filename)
@@ -95,6 +95,9 @@ fset := token.NewFileSet()
pkgs, err := parser.ParseDir(fset, dataDir, filter, parser.ParseComments)
if err != nil {
t.Fatal(err)
+ }
+ if templateTxt == nil {
+ templateTxt = readTemplate("template.txt")
}
// test packages
diff --git a/src/go/parser/performance_test.go b/src/go/parser/performance_test.go
index f2732c0e2b18d142c121d98bf22de920f4b57eef..b2e1c11e9d538ed6c317e07740ce03c0d64f7866 100644
--- a/src/go/parser/performance_test.go
+++ b/src/go/parser/performance_test.go
@@ -10,17 +10,12 @@ "io/ioutil"
"testing"
)
-var src = readFile("parser.go")
-
-func readFile(filename string) []byte {
- data, err := ioutil.ReadFile(filename)
+func BenchmarkParse(b *testing.B) {
+ src, err := ioutil.ReadFile("parser.go")
if err != nil {
- panic(err)
+ b.Fatal(err)
}
- return data
-}
-
-func BenchmarkParse(b *testing.B) {
+ b.ResetTimer()
b.SetBytes(int64(len(src)))
for i := 0; i < b.N; i++ {
if _, err := ParseFile(token.NewFileSet(), "", src, ParseComments); err != nil {
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index 072da2552bc5d06d8e109657d0ddfd9c19ad1fec..681dff193aa1dd6ef5d0f31c88ed3c9d0ceb85c7 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -5173,3 +5173,142 @@ }()
}
wg.Wait()
}
+
+// Test that the bufio.Reader returned by Hijack includes any buffered
+// byte (from the Server's backgroundRead) in its buffer. We want the
+// Handler code to be able to tell that a byte is available via
+// bufio.Reader.Buffered(), without resorting to Reading it
+// (potentially blocking) to get at it.
+func TestServerHijackGetsBackgroundByte(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see https://golang.org/issue/18657")
+ }
+ setParallel(t)
+ defer afterTest(t)
+ done := make(chan struct{})
+ inHandler := make(chan bool, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ defer close(done)
+
+ // Tell the client to send more data after the GET request.
+ inHandler <- true
+
+ // Wait until the HTTP server sees the extra data
+ // after the GET request. The HTTP server fires the
+ // close notifier here, assuming it's a pipelined
+ // request, as documented.
+ select {
+ case <-w.(CloseNotifier).CloseNotify():
+ case <-time.After(5 * time.Second):
+ t.Error("timeout")
+ return
+ }
+
+ conn, buf, err := w.(Hijacker).Hijack()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer conn.Close()
+ n := buf.Reader.Buffered()
+ if n != 1 {
+ t.Errorf("buffered data = %d; want 1", n)
+ }
+ peek, err := buf.Reader.Peek(3)
+ if string(peek) != "foo" || err != nil {
+ t.Errorf("Peek = %q, %v; want foo, nil", peek, err)
+ }
+ }))
+ defer ts.Close()
+
+ cn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer cn.Close()
+ if _, err := cn.Write([]byte("GET / HTTP/1.1\r\nHost: e.com\r\n\r\n")); err != nil {
+ t.Fatal(err)
+ }
+ <-inHandler
+ if _, err := cn.Write([]byte("foo")); err != nil {
+ t.Fatal(err)
+ }
+
+ if err := cn.(*net.TCPConn).CloseWrite(); err != nil {
+ t.Fatal(err)
+ }
+ select {
+ case <-done:
+ case <-time.After(2 * time.Second):
+ t.Error("timeout")
+ }
+}
+
+// Like TestServerHijackGetsBackgroundByte above but sending a
+// immediate 1MB of data to the server to fill up the server's 4KB
+// buffer.
+func TestServerHijackGetsBackgroundByte_big(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see https://golang.org/issue/18657")
+ }
+ setParallel(t)
+ defer afterTest(t)
+ done := make(chan struct{})
+ const size = 8 << 10
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ defer close(done)
+
+ // Wait until the HTTP server sees the extra data
+ // after the GET request. The HTTP server fires the
+ // close notifier here, assuming it's a pipelined
+ // request, as documented.
+ select {
+ case <-w.(CloseNotifier).CloseNotify():
+ case <-time.After(5 * time.Second):
+ t.Error("timeout")
+ return
+ }
+
+ conn, buf, err := w.(Hijacker).Hijack()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer conn.Close()
+ slurp, err := ioutil.ReadAll(buf.Reader)
+ if err != nil {
+ t.Error("Copy: %v", err)
+ }
+ allX := true
+ for _, v := range slurp {
+ if v != 'x' {
+ allX = false
+ }
+ }
+ if len(slurp) != size {
+ t.Errorf("read %d; want %d", len(slurp), size)
+ } else if !allX {
+ t.Errorf("read %q; want %d 'x'", slurp, size)
+ }
+ }))
+ defer ts.Close()
+
+ cn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer cn.Close()
+ if _, err := fmt.Fprintf(cn, "GET / HTTP/1.1\r\nHost: e.com\r\n\r\n%s",
+ strings.Repeat("x", size)); err != nil {
+ t.Fatal(err)
+ }
+ if err := cn.(*net.TCPConn).CloseWrite(); err != nil {
+ t.Fatal(err)
+ }
+
+ select {
+ case <-done:
+ case <-time.After(2 * time.Second):
+ t.Error("timeout")
+ }
+}
diff --git a/src/net/http/server.go b/src/net/http/server.go
index 96236489bd9faf0e404a01aed92bafcab19ee33f..df70a15193bc6adb0127f250d4c2e3edb033e6e2 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -164,7 +164,7 @@ // ResponseWriter wrappers may also not support Hijacker. Handlers
// should always test for this ability at runtime.
type Hijacker interface {
// Hijack lets the caller take over the connection.
- // After a call to Hijack(), the HTTP server library
+ // After a call to Hijack the HTTP server library
// will not do anything else with the connection.
//
// It becomes the caller's responsibility to manage
@@ -174,6 +174,9 @@ // The returned net.Conn may have read or write deadlines
// already set, depending on the configuration of the
// Server. It is the caller's responsibility to set
// or clear those deadlines as needed.
+ //
+ // The returned bufio.Reader may contain unprocessed buffered
+ // data from the client.
Hijack() (net.Conn, *bufio.ReadWriter, error)
}
@@ -293,6 +296,11 @@ rwc = c.rwc
rwc.SetDeadline(time.Time{})
buf = bufio.NewReadWriter(c.bufr, bufio.NewWriter(rwc))
+ if c.r.hasByte {
+ if _, err := c.bufr.Peek(c.bufr.Buffered() + 1); err != nil {
+ return nil, nil, fmt.Errorf("unexpected Peek failure reading buffered byte: %v", err)
+ }
+ }
c.setState(rwc, StateHijacked)
return
}
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index d5ddf6a1232a019e97d1d48f9f423d58d8af7dc0..a58b1839cc6e09e30d5f1a975a6f8394008dae98 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -36,6 +36,7 @@ "runtime"
"strconv"
"strings"
"sync"
+ "sync/atomic"
"testing"
"time"
)
@@ -2545,6 +2546,13 @@ type closerFunc func() error
func (f closerFunc) Close() error { return f() }
+type writerFuncConn struct {
+ net.Conn
+ write func(p []byte) (n int, err error)
+}
+
+func (c writerFuncConn) Write(p []byte) (n int, err error) { return c.write(p) }
+
// Issue 4677. If we try to reuse a connection that the server is in the
// process of closing, we may end up successfully writing out our request (or a
// portion of our request) only to find a connection error when we try to read
@@ -2557,66 +2565,78 @@ // cached keep-alive connections eventually.
func TestRetryIdempotentRequestsOnError(t *testing.T) {
defer afterTest(t)
+ var (
+ mu sync.Mutex
+ logbuf bytes.Buffer
+ )
+ logf := func(format string, args ...interface{}) {
+ mu.Lock()
+ defer mu.Unlock()
+ fmt.Fprintf(&logbuf, format, args...)
+ logbuf.WriteByte('\n')
+ }
+
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ logf("Handler")
+ w.Header().Set("X-Status", "ok")
}))
defer ts.Close()
- tr := &Transport{}
+ var writeNumAtomic int32
+ tr := &Transport{
+ Dial: func(network, addr string) (net.Conn, error) {
+ logf("Dial")
+ c, err := net.Dial(network, ts.Listener.Addr().String())
+ if err != nil {
+ logf("Dial error: %v", err)
+ return nil, err
+ }
+ return &writerFuncConn{
+ Conn: c,
+ write: func(p []byte) (n int, err error) {
+ if atomic.AddInt32(&writeNumAtomic, 1) == 2 {
+ logf("intentional write failure")
+ return 0, errors.New("second write fails")
+ }
+ logf("Write(%q)", p)
+ return c.Write(p)
+ },
+ }, nil
+ },
+ }
+ defer tr.CloseIdleConnections()
c := &Client{Transport: tr}
- const N = 2
- retryc := make(chan struct{}, N)
SetRoundTripRetried(func() {
- retryc <- struct{}{}
+ logf("Retried.")
})
defer SetRoundTripRetried(nil)
- for n := 0; n < 100; n++ {
- // open 2 conns
- errc := make(chan error, N)
- for i := 0; i < N; i++ {
- // start goroutines, send on errc
- go func() {
- res, err := c.Get(ts.URL)
- if err == nil {
- res.Body.Close()
- }
- errc <- err
- }()
+ for i := 0; i < 3; i++ {
+ res, err := c.Get("http://fake.golang/")
+ if err != nil {
+ t.Fatalf("i=%d: Get = %v", i, err)
}
- for i := 0; i < N; i++ {
- if err := <-errc; err != nil {
- t.Fatal(err)
- }
- }
-
- ts.CloseClientConnections()
- for i := 0; i < N; i++ {
- go func() {
- res, err := c.Get(ts.URL)
- if err == nil {
- res.Body.Close()
- }
- errc <- err
- }()
- }
+ res.Body.Close()
+ }
- for i := 0; i < N; i++ {
- if err := <-errc; err != nil {
- t.Fatal(err)
- }
- }
- for i := 0; i < N; i++ {
- select {
- case <-retryc:
- // we triggered a retry, test was successful
- t.Logf("finished after %d runs\n", n)
- return
- default:
- }
- }
+ mu.Lock()
+ got := logbuf.String()
+ mu.Unlock()
+ const want = `Dial
+Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n")
+Handler
+intentional write failure
+Retried.
+Dial
+Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n")
+Handler
+Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n")
+Handler
+`
+ if got != want {
+ t.Errorf("Log of events differs. Got:\n%s\nWant:\n%s", got, want)
}
- t.Fatal("did not trigger any retries")
}
// Issue 6981
diff --git a/src/os/os_test.go b/src/os/os_test.go
index b7300cd38c468243959ff271b65a8c9222c07d2d..7ad9aac70e25101ffca31b7a7ba4cad98cd166c8 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -54,12 +54,15 @@ }
case "darwin":
switch runtime.GOARCH {
case "arm", "arm64":
+ /// At this point the test harness has not had a chance
+ // to move us into the ./src/os directory, so the
+ // current working directory is the root of the app.
wd, err := syscall.Getwd()
if err != nil {
wd = err.Error()
}
return &sysDir{
- filepath.Join(wd, "..", ".."),
+ wd,
[]string{
"ResourceRules.plist",
"Info.plist",
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 033a18171de96b966bc9f2233689dd5d49191d93..022350b322f9910f30514b5df973203c8ebaaf59 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -26,6 +26,8 @@ "unicode/utf8"
"unsafe"
)
+var sink interface{}
+
func TestBool(t *testing.T) {
v := ValueOf(true)
if v.Bool() != true {
@@ -5329,6 +5331,72 @@ }
typ := ValueOf(f).Type()
f2 := MakeFunc(typ, g).Interface().(func(string, string, string, string, string))
f2("four", "five5", "six666", "seven77", "eight888")
+}
+
+// Issue 18635 (function version).
+func TestKeepFuncLive(t *testing.T) {
+ // Test that we keep makeFuncImpl live as long as it is
+ // referenced on the stack.
+ typ := TypeOf(func(i int) {})
+ var f, g func(in []Value) []Value
+ f = func(in []Value) []Value {
+ clobber()
+ i := int(in[0].Int())
+ if i > 0 {
+ // We can't use Value.Call here because
+ // runtime.call* will keep the makeFuncImpl
+ // alive. However, by converting it to an
+ // interface value and calling that,
+ // reflect.callReflect is the only thing that
+ // can keep the makeFuncImpl live.
+ //
+ // Alternate between f and g so that if we do
+ // reuse the memory prematurely it's more
+ // likely to get obviously corrupted.
+ MakeFunc(typ, g).Interface().(func(i int))(i - 1)
+ }
+ return nil
+ }
+ g = func(in []Value) []Value {
+ clobber()
+ i := int(in[0].Int())
+ MakeFunc(typ, f).Interface().(func(i int))(i)
+ return nil
+ }
+ MakeFunc(typ, f).Call([]Value{ValueOf(10)})
+}
+
+// Issue 18635 (method version).
+type KeepMethodLive struct{}
+
+func (k KeepMethodLive) Method1(i int) {
+ clobber()
+ if i > 0 {
+ ValueOf(k).MethodByName("Method2").Interface().(func(i int))(i - 1)
+ }
+}
+
+func (k KeepMethodLive) Method2(i int) {
+ clobber()
+ ValueOf(k).MethodByName("Method1").Interface().(func(i int))(i)
+}
+
+func TestKeepMethodLive(t *testing.T) {
+ // Test that we keep methodValue live as long as it is
+ // referenced on the stack.
+ KeepMethodLive{}.Method1(10)
+}
+
+// clobber tries to clobber unreachable memory.
+func clobber() {
+ runtime.GC()
+ for i := 1; i < 32; i++ {
+ for j := 0; j < 10; j++ {
+ obj := make([]*byte, i)
+ sink = obj
+ }
+ }
+ runtime.GC()
}
type funcLayoutTest struct {
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 042414ffe78556ba56f3eb6853673f6c6edbc20e..699ba69408671db979b0037af4d7fc6629ac89ef 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -538,6 +538,11 @@ }
off += typ.size
}
}
+
+ // runtime.getArgInfo expects to be able to find ctxt on the
+ // stack when it finds our caller, makeFuncStub. Make sure it
+ // doesn't get garbage collected.
+ runtime.KeepAlive(ctxt)
}
// methodReceiver returns information about the receiver
@@ -650,6 +655,9 @@ // This is untyped because the frame is really a stack, even
// though it's a heap object.
memclrNoHeapPointers(args, frametype.size)
framePool.Put(args)
+
+ // See the comment in callReflect.
+ runtime.KeepAlive(ctxt)
}
// funcName returns the name of f, for use in error messages.
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index 64a2f3abef863d7f01b3184003ad1993db35146e..0b996d895080c9ba73bcab3666e5447ff96928a5 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -1129,8 +1129,6 @@ // The global work list is empty, but there can still be work
// sitting in the per-P work caches.
// Flush and disable work caches.
- gcMarkRootCheck()
-
// Disallow caching workbufs and indicate that we're in mark 2.
gcBlackenPromptly = true
@@ -1152,6 +1150,16 @@ forEachP(func(_p_ *p) {
_p_.gcw.dispose()
})
})
+
+ // 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)
diff --git a/src/runtime/plugin.go b/src/runtime/plugin.go
index 80869e1b1c1a5cb69502d26ee2b11ec323f7c9e7..8edb29c9fea5604febd823da1667b50f4531057b 100644
--- a/src/runtime/plugin.go
+++ b/src/runtime/plugin.go
@@ -56,7 +56,9 @@ moduledataverify1(md)
lock(&ifaceLock)
for _, i := range md.itablinks {
- additab(i, true, false)
+ if i.inhash == 0 {
+ additab(i, true, false)
+ }
}
unlock(&ifaceLock)
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index 839df164068f0c302cf4329ea956ce53c343893c..6ddcb30ae204ddfa5e2f639cf4968646c44c223a 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -330,9 +330,9 @@
// Lock sigprofCallersUse.
MOVL $0, AX
MOVL $1, CX
- MOVQ $runtime·sigprofCallersUse(SB), BX
+ MOVQ $runtime·sigprofCallersUse(SB), R11
LOCK
- CMPXCHGL CX, 0(BX)
+ CMPXCHGL CX, 0(R11)
JNZ sigtramp // Skip stack trace if already locked.
// Jump to the traceback function in runtime/cgo.
diff --git a/src/syscall/mkpost.go b/src/syscall/mkpost.go
index 26aeec843f1599bf144259899b33d012561697e4..e75ba1502a94aadd8d461e9fe077efa3b56e500d 100644
--- a/src/syscall/mkpost.go
+++ b/src/syscall/mkpost.go
@@ -18,6 +18,7 @@ "io/ioutil"
"log"
"os"
"regexp"
+ "strings"
)
func main() {
@@ -38,9 +39,15 @@ // Replace padding fields inserted by cgo with blank identifiers.
re = regexp.MustCompile("Pad_cgo[A-Za-z0-9_]*")
s = re.ReplaceAllString(s, "_")
+ // We want to keep X__val in Fsid. Hide it and restore it later.
+ s = strings.Replace(s, "X__val", "MKPOSTFSIDVAL", 1)
+
// Replace other unwanted fields with blank identifiers.
re = regexp.MustCompile("X_[A-Za-z0-9_]*")
s = re.ReplaceAllString(s, "_")
+
+ // Restore X__val in Fsid.
+ s = strings.Replace(s, "MKPOSTFSIDVAL", "X__val", 1)
// Force the type of RawSockaddr.Data to [14]int8 to match
// the existing gccgo API.
diff --git a/src/syscall/ztypes_linux_s390x.go b/src/syscall/ztypes_linux_s390x.go
index cdde47863f7d584eebf9b84c321424908d3c5fa3..63c4a83b19cfe6efaf813818dc7da36a50701ad0 100644
--- a/src/syscall/ztypes_linux_s390x.go
+++ b/src/syscall/ztypes_linux_s390x.go
@@ -140,7 +140,7 @@ _ [5]byte
}
type Fsid struct {
- _ [2]int32
+ X__val [2]int32
}
type Flock_t struct {
diff --git a/src/testing/benchmark.go b/src/testing/benchmark.go
index c033ce5fecb1286965089adde2a4919ff2a4da84..bcebb418c42572e1c26aa3427926667c596adf5b 100644
--- a/src/testing/benchmark.go
+++ b/src/testing/benchmark.go
@@ -219,7 +219,7 @@ return false
}
// Only print the output if we know we are not going to proceed.
// Otherwise it is printed in processBench.
- if b.hasSub || b.finished {
+ if atomic.LoadInt32(&b.hasSub) != 0 || b.finished {
tag := "BENCH"
if b.skipped {
tag = "SKIP"
@@ -460,10 +460,13 @@ // whether there were any failures.
//
// A subbenchmark is like any other benchmark. A benchmark that calls Run at
// least once will not be measured itself and will be called once with N=1.
+//
+// Run may be called simultaneously from multiple goroutines, but all such
+// calls must happen before the outer benchmark function for b returns.
func (b *B) Run(name string, f func(b *B)) bool {
// Since b has subbenchmarks, we will no longer run it as a benchmark itself.
// Release the lock and acquire it on exit to ensure locks stay paired.
- b.hasSub = true
+ atomic.StoreInt32(&b.hasSub, 1)
benchmarkLock.Unlock()
defer benchmarkLock.Lock()
diff --git a/src/testing/sub_test.go b/src/testing/sub_test.go
index 8d5d9206f03563633e457afceb37b035d861f2cc..bb7b3e09255ea167de3001248b55c83e20b21109 100644
--- a/src/testing/sub_test.go
+++ b/src/testing/sub_test.go
@@ -6,6 +6,7 @@ package testing
import (
"bytes"
+ "fmt"
"regexp"
"strings"
"sync/atomic"
@@ -515,3 +516,19 @@ // normal case.
Benchmark(func(b *B) { b.Error("do not print this output") })
Benchmark(func(b *B) {})
}
+
+func TestParallelSub(t *T) {
+ c := make(chan int)
+ block := make(chan int)
+ for i := 0; i < 10; i++ {
+ go func(i int) {
+ <-block
+ t.Run(fmt.Sprint(i), func(t *T) {})
+ c <- 1
+ }(i)
+ }
+ close(block)
+ for i := 0; i < 10; i++ {
+ <-c
+ }
+}
diff --git a/src/testing/testing.go b/src/testing/testing.go
index c972b2737f28d80692e2e8a18f27a7fc53350615..ddbdc25bf11d5d7d69d5443ec68b74cad413d12d 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -216,6 +216,7 @@ "runtime/trace"
"strconv"
"strings"
"sync"
+ "sync/atomic"
"time"
)
@@ -267,8 +268,8 @@ failed bool // Test or benchmark has failed.
skipped bool // Test of benchmark has been skipped.
finished bool // Test function has completed.
done bool // Test is finished and all subtests have completed.
- hasSub bool
- raceErrors int // number of races detected during test
+ hasSub int32 // written atomically
+ raceErrors int // number of races detected during test
parent *common
level int // Nesting depth of test or benchmark.
@@ -645,7 +646,7 @@
// Do not lock t.done to allow race detector to detect race in case
// the user does not appropriately synchronizes a goroutine.
t.done = true
- if t.parent != nil && !t.hasSub {
+ if t.parent != nil && atomic.LoadInt32(&t.hasSub) == 0 {
t.setRan()
}
t.signal <- true
@@ -659,8 +660,11 @@ }
// Run runs f as a subtest of t called name. It reports whether f succeeded.
// Run will block until all its parallel subtests have completed.
+//
+// Run may be called simultaneously from multiple goroutines, but all such
+// calls must happen before the outer test function for t returns.
func (t *T) Run(name string, f func(t *T)) bool {
- t.hasSub = true
+ atomic.StoreInt32(&t.hasSub, 1)
testName, ok := t.context.match.fullName(&t.common, name)
if !ok {
return true
diff --git a/src/vendor/golang_org/x/crypto/poly1305/sum_amd64.s b/src/vendor/golang_org/x/crypto/poly1305/sum_amd64.s
index bc75c61afcf6a7dd43b529396c65f469676fcef7..2edae63828a5f0d3efa73585d3882a31c3f4343c 100644
--- a/src/vendor/golang_org/x/crypto/poly1305/sum_amd64.s
+++ b/src/vendor/golang_org/x/crypto/poly1305/sum_amd64.s
@@ -54,9 +54,9 @@ ADDQ t2, h0; \
ADCQ t3, h1; \
ADCQ $0, h2
-DATA poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
-DATA poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
-GLOBL poly1305Mask<>(SB), RODATA, $16
+DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
+DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
+GLOBL ·poly1305Mask<>(SB), RODATA, $16
// func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]key)
TEXT ·poly1305(SB), $0-32
@@ -67,8 +67,8 @@ MOVQ key+24(FP), AX
MOVQ 0(AX), R11
MOVQ 8(AX), R12
- ANDQ poly1305Mask<>(SB), R11 // r0
- ANDQ poly1305Mask<>+8(SB), R12 // r1
+ ANDQ ·poly1305Mask<>(SB), R11 // r0
+ ANDQ ·poly1305Mask<>+8(SB), R12 // r1
XORQ R8, R8 // h0
XORQ R9, R9 // h1
XORQ R10, R10 // h2
diff --git a/src/vendor/golang_org/x/crypto/poly1305/sum_arm.s b/src/vendor/golang_org/x/crypto/poly1305/sum_arm.s
index 93167b27129c103620ee72bd4be9adfb9209ce5a..f70b4ac484518ba4a6e16009a769b0472e902bc1 100644
--- a/src/vendor/golang_org/x/crypto/poly1305/sum_arm.s
+++ b/src/vendor/golang_org/x/crypto/poly1305/sum_arm.s
@@ -9,12 +9,12 @@
// This code was translated into a form compatible with 5a from the public
// domain source by Andrew Moon: github.com/floodyberry/poly1305-opt/blob/master/app/extensions/poly1305.
-DATA poly1305_init_constants_armv6<>+0x00(SB)/4, $0x3ffffff
-DATA poly1305_init_constants_armv6<>+0x04(SB)/4, $0x3ffff03
-DATA poly1305_init_constants_armv6<>+0x08(SB)/4, $0x3ffc0ff
-DATA poly1305_init_constants_armv6<>+0x0c(SB)/4, $0x3f03fff
-DATA poly1305_init_constants_armv6<>+0x10(SB)/4, $0x00fffff
-GLOBL poly1305_init_constants_armv6<>(SB), 8, $20
+DATA ·poly1305_init_constants_armv6<>+0x00(SB)/4, $0x3ffffff
+DATA ·poly1305_init_constants_armv6<>+0x04(SB)/4, $0x3ffff03
+DATA ·poly1305_init_constants_armv6<>+0x08(SB)/4, $0x3ffc0ff
+DATA ·poly1305_init_constants_armv6<>+0x0c(SB)/4, $0x3f03fff
+DATA ·poly1305_init_constants_armv6<>+0x10(SB)/4, $0x00fffff
+GLOBL ·poly1305_init_constants_armv6<>(SB), 8, $20
// Warning: the linker may use R11 to synthesize certain instructions. Please
// take care and verify that no synthetic instructions use it.
@@ -27,7 +27,7 @@ // bytes of stack because that's saving the value of 'g'.
ADD $4, R13, R8
MOVM.IB [R4-R7], (R8)
MOVM.IA.W (R1), [R2-R5]
- MOVW $poly1305_init_constants_armv6<>(SB), R7
+ MOVW $·poly1305_init_constants_armv6<>(SB), R7
MOVW R2, R8
MOVW R2>>26, R9
MOVW R3>>20, g
diff --git a/test/fixedbugs/issue18661.go b/test/fixedbugs/issue18661.go
new file mode 100644
index 0000000000000000000000000000000000000000..8c83775200902e953b82b794880cbd8224651749
--- /dev/null
+++ b/test/fixedbugs/issue18661.go
@@ -0,0 +1,18 @@
+// compile
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+var (
+ e interface{}
+ s = struct{ a *int }{}
+ b = e == s
+)
+
+func test(obj interface{}) {
+ if obj != struct{ a *string }{} {
+ }
+}