]> Cypherpunks.ru repositories - gostls13.git/commitdiff
all: merge dev.typealias into master
authorRuss Cox <rsc@golang.org>
Tue, 31 Jan 2017 17:57:12 +0000 (12:57 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 31 Jan 2017 18:01:31 +0000 (13:01 -0500)
For #18130.

f8b4123613 [dev.typealias] spec: use term 'embedded field' rather than 'anonymous field'
9ecc3ee252 [dev.typealias] cmd/compile: avoid false positive cycles from type aliases
49b7af8a30 [dev.typealias] reflect: add test for type aliases
9bbb07ddec [dev.typealias] cmd/compile, reflect: fix struct field names for embedded byte, rune
43c7094386 [dev.typealias] reflect: fix StructOf use of StructField to match StructField docs
9657e0b077 [dev.typealias] cmd/doc: update for type alias
de2e5459ae [dev.typealias] cmd/compile: declare methods after resolving receiver type
9259f3073a [dev.typealias] test: match gccgo error messages on alias2.go
5d92916770 [dev.typealias] cmd/compile: change Func.Shortname to *Sym
a7c884efc1 [dev.typealias] go/internal/gccgoimporter: support for type aliases
5802cfd900 [dev.typealias] cmd/compile: export/import test cases for type aliases
d7cabd40dd [dev.typealias] go/types: clarified doc string
cc2dcce3d7 [dev.typealias] cmd/compile: a few better comments related to alias types
5c160b28ba [dev.typealias] cmd/compile: improved error message for cyles involving type aliases
b2386dffa1 [dev.typealias] cmd/compile: type-check type alias declarations
ac8421f9a5 [dev.typealias] cmd/compile: various minor cleanups
f011e0c6c3 [dev.typealias] cmd/compile, go/types, go/importer: various alias related fixes
49de5f0351 [dev.typealias] cmd/compile, go/importer: define export format and implement importing of type aliases
5ceec42dc0 [dev.typealias] go/types: export TypeName.IsAlias so clients can use it
aa1f0681bc [dev.typealias] go/types: improved Object printing
c80748e389 [dev.typealias] go/types: remove some more vestiges of prior alias implementation
80d8b69e95 [dev.typealias] go/types: implement type aliases
a917097b5e [dev.typealias] go/build: add go1.9 build tag
3e11940437 [dev.typealias] cmd/compile: recognize type aliases but complain for now (not yet supported)
e0a05c274a [dev.typealias] cmd/gofmt: added test cases for alias type declarations
2e5116bd99 [dev.typealias] go/ast, go/parser, go/printer, go/types: initial type alias support

Change-Id: Ia65f2e011fd7195f18e1dce67d4d49b80a261203

115 files changed:
README.md
doc/contribute.html
doc/debugging_with_gdb.html
doc/devel/release.html
doc/gccgo_install.html
doc/go1.8.html
doc/install-source.html
doc/install.html
misc/cgo/test/issue18146.go
misc/cgo/test/sigaltstack.go
misc/cgo/testplugin/src/iface/main.go [new file with mode: 0644]
misc/cgo/testplugin/src/iface_a/a.go [new file with mode: 0644]
misc/cgo/testplugin/src/iface_b/b.go [new file with mode: 0644]
misc/cgo/testplugin/src/iface_i/i.go [new file with mode: 0644]
misc/cgo/testplugin/src/issue18676/dynamodbstreamsevt/definition.go [new file with mode: 0644]
misc/cgo/testplugin/src/issue18676/main.go [new file with mode: 0644]
misc/cgo/testplugin/src/issue18676/plugin.go [new file with mode: 0644]
misc/cgo/testplugin/test.bash
misc/cgo/testsanitizers/msan_shared.go [new file with mode: 0644]
misc/cgo/testsanitizers/test.bash
misc/cgo/testshared/shared_test.go
misc/cgo/testshared/src/depBase/dep.go
misc/cgo/testshared/src/exe/exe.go
misc/cgo/testshared/src/iface/main.go [new file with mode: 0644]
misc/cgo/testshared/src/iface_a/a.go [new file with mode: 0644]
misc/cgo/testshared/src/iface_b/b.go [new file with mode: 0644]
misc/cgo/testshared/src/iface_i/i.go [new file with mode: 0644]
misc/ios/go_darwin_arm_exec.go
src/cmd/compile/internal/gc/alg.go
src/cmd/compile/internal/gc/bimport.go
src/cmd/compile/internal/gc/builtin.go
src/cmd/compile/internal/gc/builtin/runtime.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/noder.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/subr.go
src/cmd/compile/internal/gc/util.go
src/cmd/compile/internal/gc/walk.go
src/cmd/compile/internal/ssa/compile.go
src/cmd/compile/internal/ssa/func.go
src/cmd/compile/internal/ssa/gen/PPC64.rules
src/cmd/compile/internal/ssa/gen/S390X.rules
src/cmd/compile/internal/ssa/loopreschedchecks.go [new file with mode: 0644]
src/cmd/compile/internal/ssa/nilcheck.go
src/cmd/compile/internal/ssa/rewritePPC64.go
src/cmd/compile/internal/ssa/rewriteS390X.go
src/cmd/compile/internal/ssa/sparsetree.go
src/cmd/compile/internal/ssa/writebarrier.go
src/cmd/dist/test.go
src/cmd/go/alldocs.go
src/cmd/go/bug.go
src/cmd/go/go_test.go
src/cmd/go/pkg.go
src/cmd/go/test.go
src/cmd/go/testdata/timeoutbench_test.go [new file with mode: 0644]
src/cmd/internal/obj/go.go
src/cmd/link/internal/ld/dwarf.go
src/cmd/link/internal/ld/pcln.go
src/compress/bzip2/bzip2_test.go
src/compress/flate/deflate.go
src/compress/flate/deflate_test.go
src/compress/flate/deflatefast.go
src/compress/gzip/issue14937_test.go
src/crypto/dsa/dsa_test.go
src/crypto/tls/cipher_suites.go
src/crypto/tls/tls.go
src/crypto/x509/cert_pool.go
src/crypto/x509/root_windows.go
src/crypto/x509/x509_test.go
src/database/sql/sql.go
src/database/sql/sql_test.go
src/go/ast/scope.go
src/go/doc/doc_test.go
src/go/parser/performance_test.go
src/go/printer/nodes.go
src/go/printer/printer.go
src/go/printer/testdata/comments2.golden
src/go/printer/testdata/comments2.input
src/go/types/stdlib_test.go
src/net/http/client.go
src/net/http/client_test.go
src/net/http/serve_test.go
src/net/http/server.go
src/net/http/transport_test.go
src/os/os_test.go
src/reflect/all_test.go
src/reflect/value.go
src/runtime/memmove_amd64.s
src/runtime/memmove_test.go
src/runtime/mgc.go
src/runtime/mgcsweep.go
src/runtime/msan.go
src/runtime/plugin.go
src/runtime/proc.go
src/runtime/runtime-gdb_test.go
src/runtime/symtab.go
src/runtime/sys_linux_amd64.s
src/runtime/testdata/testprogcgo/threadpprof.go
src/runtime/testdata/testprogcgo/traceback.go
src/syscall/mkpost.go
src/syscall/ztypes_linux_s390x.go
src/testing/benchmark.go
src/testing/sub_test.go
src/testing/testing.go
src/vendor/golang_org/x/crypto/poly1305/sum_amd64.s
src/vendor/golang_org/x/crypto/poly1305/sum_arm.s
test/fixedbugs/issue10958.go [new file with mode: 0644]
test/fixedbugs/issue18459.go [new file with mode: 0644]
test/fixedbugs/issue18661.go [new file with mode: 0644]
test/fixedbugs/issue18725.go [new file with mode: 0644]
test/fixedbugs/issue18808.go [new file with mode: 0644]
test/live.go
test/nilptr3.go
test/opt_branchlikely.go
test/run.go

index 281deecdfbdf1ce4e02283a878de29becad2a5b5..672cdf55686a7754f78e383440a3d5915fae528e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -5,39 +5,37 @@ reliable, and efficient software.
 
 ![Gopher image](doc/gopher/fiveyears.jpg)
 
-For documentation about how to install and use Go,
-visit https://golang.org/ or load doc/install-source.html
-in your web browser.
-
 Our canonical Git repository is located at https://go.googlesource.com/go.
 There is a mirror of the repository at https://github.com/golang/go.
 
-Go is the work of hundreds of contributors. We appreciate your help!
+Unless otherwise noted, the Go source files are distributed under the
+BSD-style license found in the LICENSE file.
 
-To contribute, please read the contribution guidelines:
-       https://golang.org/doc/contribute.html
+### Download and Install
 
-##### Note that we do not accept pull requests and that we use the issue tracker for bug reports and proposals only. Please ask questions on https://forum.golangbridge.org or https://groups.google.com/forum/#!forum/golang-nuts.
+#### Binary Distributions
 
-Unless otherwise noted, the Go source files are distributed
-under the BSD-style license found in the LICENSE file.
+Official binary distributions are available at https://golang.org/dl/.
 
---
+After downloading a binary release, visit https://golang.org/doc/install
+or load doc/install.html in your web browser for installation
+instructions.
 
-## Binary Distribution Notes
+#### Install From Source
 
-If you have just untarred a binary Go distribution, you need to set
-the environment variable $GOROOT to the full path of the go
-directory (the one containing this file).  You can omit the
-variable if you unpack it into /usr/local/go, or if you rebuild
-from sources by running all.bash (see doc/install-source.html).
-You should also add the Go binary directory $GOROOT/bin
-to your shell's path.
+If a binary distribution is not available for your combination of
+operating system and architecture, visit
+https://golang.org/doc/install/source or load doc/install-source.html
+in your web browser for source installation instructions.
 
-For example, if you extracted the tar file into $HOME/go, you might
-put the following in your .profile:
+### Contributing
 
-       export GOROOT=$HOME/go
-       export PATH=$PATH:$GOROOT/bin
+Go is the work of hundreds of contributors. We appreciate your help!
+
+To contribute, please read the contribution guidelines:
+       https://golang.org/doc/contribute.html
 
-See https://golang.org/doc/install or doc/install.html for more details.
+Note that the Go project does not use GitHub pull requests, and that
+we use the issue tracker for bug reports and proposals only. See
+https://golang.org/wiki/Questions for a list of places to ask
+questions about the Go language.
index bcf7b25c51158057b0c868050327cbf3ac8a30b0..f1a5b2799858966c51a19111e11369d5a34584db 100644 (file)
@@ -698,7 +698,7 @@ These files will be periodically updated based on the commit logs.
 <p>Code that you contribute should use the standard copyright header:</p>
 
 <pre>
-// Copyright 2016 The Go Authors. All rights reserved.
+// 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.
 </pre>
index 52a6e76723e94b7b4743268db132dc213c91ec84..f0e65ea29126c0904086d338a7424b68b64b0897 100644 (file)
@@ -4,7 +4,8 @@
 }-->
 
 <p><i>
-This applies to the <code>gc</code> toolchain. Gccgo has native gdb support.
+This applies to the standard toolchain (the <code>gc</code> Go
+compiler and tools). Gccgo has native gdb support.
 Besides this overview you might want to consult the
 <a href="http://sourceware.org/gdb/current/onlinedocs/gdb/">GDB manual</a>.
 </i></p>
@@ -49,6 +50,14 @@ when debugging, pass the flags <code>-gcflags "-N -l"</code> to the
 debugged.
 </p>
 
+<p>
+If you want to use gdb to inspect a core dump, you can trigger a dump
+on a program crash, on systems that permit it, by setting
+<code>GOTRACEBACK=crash</code> in the environment (see the
+<a href="/pkg/runtime/#hdr-Environment_Variables"> runtime package
+documentation</a> for more info).
+</p>
+
 <h3 id="Common_Operations">Common Operations</h3>
 
 <ul>
@@ -130,7 +139,7 @@ the DWARF code.
 
 <p>
 If you're interested in what the debugging information looks like, run
-'<code>objdump -W 6.out</code>' and browse through the <code>.debug_*</code>
+'<code>objdump -W a.out</code>' and browse through the <code>.debug_*</code>
 sections.
 </p>
 
@@ -377,7 +386,9 @@ $3 = struct hchan&lt;*testing.T&gt;
 </pre>
 
 <p>
-That <code>struct hchan&lt;*testing.T&gt;</code> is the runtime-internal representation of a channel.  It is currently empty, or gdb would have pretty-printed it's contents.
+That <code>struct hchan&lt;*testing.T&gt;</code> is the
+runtime-internal representation of a channel. It is currently empty,
+or gdb would have pretty-printed its contents.
 </p>
 
 <p>
index 51957dff281788b9f6bb83793e53d69f2b6e9ff9..be340a35fdac58d2bed49a4c29ad7aec7aefc326 100644 (file)
@@ -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>
index ef27fd1818265128e808900067fe71b47072dea1..4f6a911541f0430dc5c4b91c60b1937971112ed1 100644 (file)
@@ -52,6 +52,19 @@ user libraries.  The Go 1.4 runtime is not fully merged, but that
 should not be visible to Go programs.
 </p>
 
+<p>
+The GCC 6 releases include a complete implementation of the Go 1.6.1
+user libraries.  The Go 1.6 runtime is not fully merged, but that
+should not be visible to Go programs.
+</p>
+
+<p>
+The GCC 7 releases are expected to include a complete implementation
+of the Go 1.8 user libraries.  As with earlier releases, the Go 1.8
+runtime is not fully merged, but that should not be visible to Go
+programs.
+</p>
+
 <h2 id="Source_code">Source code</h2>
 
 <p>
@@ -160,23 +173,6 @@ make
 make install
 </pre>
 
-<h3 id="Ubuntu">A note on Ubuntu</h3>
-
-<p>
-Current versions of Ubuntu and versions of GCC before 4.8 disagree on
-where system libraries and header files are found.  This is not a
-gccgo issue.  When building older versions of GCC, setting these
-environment variables while configuring and building gccgo may fix the
-problem.
-</p>
-
-<pre>
-LIBRARY_PATH=/usr/lib/x86_64-linux-gnu
-C_INCLUDE_PATH=/usr/include/x86_64-linux-gnu
-CPLUS_INCLUDE_PATH=/usr/include/x86_64-linux-gnu
-export LIBRARY_PATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH
-</pre>
-
 <h2 id="Using_gccgo">Using gccgo</h2>
 
 <p>
@@ -364,12 +360,15 @@ or with C++ code compiled using <code>extern "C"</code>.
 <h3 id="Types">Types</h3>
 
 <p>
-Basic types map directly: an <code>int</code> in Go is an <code>int</code>
-in C, an <code>int32</code> is an <code>int32_t</code>,
-etc.  Go <code>byte</code> is equivalent to C <code>unsigned
-char</code>.
-Pointers in Go are pointers in C. A Go <code>struct</code> is the same as C
-<code>struct</code> with the same fields and types.
+Basic types map directly: an <code>int32</code> in Go is
+an <code>int32_t</code> in C, an <code>int64</code> is
+an <code>int64_t</code>, etc.
+The Go type <code>int</code> is an integer that is the same size as a
+pointer, and as such corresponds to the C type <code>intptr_t</code>.
+Go <code>byte</code> is equivalent to C <code>unsigned char</code>.
+Pointers in Go are pointers in C.
+A Go <code>struct</code> is the same as C <code>struct</code> with the
+same fields and types.
 </p>
 
 <p>
@@ -380,7 +379,7 @@ structure (this is <b style="color: red;">subject to change</b>):
 <pre>
 struct __go_string {
   const unsigned char *__data;
-  int __length;
+  intptr_t __length;
 };
 </pre>
 
@@ -400,8 +399,8 @@ A slice in Go is a structure.  The current definition is
 <pre>
 struct __go_slice {
   void *__values;
-  int __count;
-  int __capacity;
+  intptr_t __count;
+  intptr_t __capacity;
 };
 </pre>
 
@@ -526,15 +525,3 @@ This procedure is full of unstated caveats and restrictions and we make no
 guarantee that it will not change in the future. It is more useful as a
 starting point for real Go code than as a regular procedure.
 </p>
-
-<h2 id="RTEMS_Port">RTEMS Port</h2>
-<p>
-The gccgo compiler has been ported to <a href="http://www.rtems.com/">
-<code>RTEMS</code></a>. <code>RTEMS</code> is a real-time executive
-that provides a high performance environment for embedded applications
-on a range of processors and embedded hardware. The current gccgo
-port is for x86. The goal is to extend the port to most of the
-<a href="http://www.rtems.org/wiki/index.php/SupportedCPUs">
-architectures supported by <code>RTEMS</code></a>. For more information on the port,
-as well as instructions on how to install it, please see this
-<a href="http://www.rtems.org/wiki/index.php/GCCGoRTEMS"><code>RTEMS</code> Wiki page</a>.
index 2ac478632e5dec5e7f6a48c0747e34b49f32c67d..af56ae6b3af1782581b2cbda7a910e9a5151b3f4 100644 (file)
@@ -93,7 +93,8 @@ On OpenBSD, Go now requires OpenBSD 5.9 or later. <!-- CL 34093 -->
 <p>
 The Plan 9 port's networking support is now much more complete
 and matches the behavior of Unix and Windows with respect to deadlines
-and cancelation.
+and cancelation. For Plan 9 kernel requirements, see the
+<a href="https://golang.org/wiki/Plan9">Plan 9 wiki page</a>.
 </p>
 
 <p>
@@ -434,11 +435,11 @@ version of gccgo.
 <h3 id="plugin">Plugins</h3>
 
 <p>
-  Go now supports a “<code>plugin</code>” build mode for generating
-  plugins written in Go, and a
+  Go now provides early support for plugins with a “<code>plugin</code>”
+  build mode for generating plugins written in Go, and a
   new <a href="/pkg/plugin/"><code>plugin</code></a> package for
-  loading such plugins at run time. Plugin support is only currently
-  available on Linux.
+  loading such plugins at run time. Plugin support is currently only
+  available on Linux. Please report any issues.
 </p>
 
 <h2 id="runtime">Runtime</h2>
@@ -808,11 +809,6 @@ Optimizations and minor bug fixes are not listed.
 
 <dl id="crypto_x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
   <dd>
-    <p> <!-- CL 30578 -->
-      <a href="/pkg/crypto/x509/#SystemCertPool"><code>SystemCertPool</code></a>
-      is now implemented on Windows.
-    </p>
-
     <p> <!-- CL 24743 -->
       PSS signatures are now supported.
     </p>
@@ -863,11 +859,12 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
     <p>
       The <a href="/pkg/database/sql#IsolationLevel"><code>IsolationLevel</code></a>
       can now be set when starting a transaction by setting the isolation level
-      on the <code>Context</code> then passing that <code>Context</code> to
-      <a href="/pkg/database/sql#DB.BeginContext"><code>DB.BeginContext</code></a>.
+      on <a href="/pkg/database/sql#TxOptions.Isolation"><code>TxOptions.Isolation</code></a> and passing
+      it to <a href="/pkg/database/sql#DB.BeginTx"><code>DB.BeginTx</code></a>.
       An error will be returned if an isolation level is selected that the driver
       does not support. A read-only attribute may also be set on the transaction
-      with <a href="/pkg/database/sql/#ReadOnlyContext"><code>ReadOnlyContext</code></a>.
+      by setting <a href="/pkg/database/sql/#TxOptions.ReadOnly"><code>TxOptions.ReadOnly</code></a>
+      to true.
     </p>
     <p>
       Queries now expose the SQL column type information for drivers that support it.
@@ -1617,9 +1614,9 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
       June 31 and July 32.
     </p>
 
-    <p> <!-- CL 33029 -->
+    <p> <!-- CL 33029 --> <!-- CL 34816 -->
       The <code>tzdata</code> 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.
     </p>
 
@@ -1649,6 +1646,17 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
       and only the overall execution of the test binary would fail.
     </p>
 
+    <p><!-- CL 32455 -->
+      The signature of the
+      <a href="/pkg/testing/#MainStart"><code>MainStart</code></a>
+      function has changed, as allowed by the documentation. It is an
+      internal detail and not part of the Go 1 compatibility promise.
+      If you're not calling <code>MainStart</code> directly but see
+      errors, that likely means you set the
+      normally-empty <code>GOROOT</code> environment variable and it
+      doesn't match the version of your <code>go</code> command's binary.
+    </p>
+
   </dd>
 </dl>
 
index 4bf0ba35fb8e852c7cb071d15853666143898b83..efe864cb1a3188fddf924667dbcea04a4c2818ce 100644 (file)
@@ -147,6 +147,9 @@ either the git branch <code>release-branch.go1.4</code> or
 which contains the Go 1.4 source code plus accumulated fixes
 to keep the tools running on newer operating systems.
 (Go 1.4 was the last distribution in which the tool chain was written in C.)
+After unpacking the Go 1.4 source, <code>cd</code> to
+the <code>src</code> subdirectory and run <code>make.bash</code> (or,
+on Windows, <code>make.bat</code>).
 </p>
 
 <p>
index 2143d591cb25462cadfa43d9434c363f45d74ad2..6bff75c5a06ac60649f29be63de7fdca852562bb 100644 (file)
@@ -250,7 +250,7 @@ $ <b>cd $HOME/go/src/hello</b>
 $ <b>go build</b>
 </pre>
 
-<pre class="testWindows" style="display: none">
+<pre class="testWindows">
 C:\&gt; <b>cd %USERPROFILE%\go\src\hello</b>
 C:\Users\Gopher\go\src\hello&gt; <b>go build</b>
 </pre>
@@ -267,7 +267,7 @@ $ <b>./hello</b>
 hello, world
 </pre>
 
-<pre class="testWindows" style="display: none">
+<pre class="testWindows">
 C:\Users\Gopher\go\src\hello&gt; <b>hello</b>
 hello, world
 </pre>
index ffb04e9037ba4e1db7e35fabda86ef9011e2587a..3c600463f0335447f8a36c44fb20f607519f2b64 100644 (file)
@@ -73,7 +73,7 @@ func test18146(t *testing.T) {
                }
                runtime.GOMAXPROCS(threads)
                argv := append(os.Args, "-test.run=NoSuchTestExists")
-               if err := syscall.Exec(os.Args[0], argv, nil); err != nil {
+               if err := syscall.Exec(os.Args[0], argv, os.Environ()); err != nil {
                        t.Fatal(err)
                }
        }
index b16adc7d88f9822081c4ee969085e916c85fd47e..2b7a1ec9ad0a01e0dcb34f37ca756afbc94011c3 100644 (file)
@@ -17,7 +17,7 @@ package cgotest
 static stack_t oss;
 static char signalStack[SIGSTKSZ];
 
-static void changeSignalStack() {
+static void changeSignalStack(void) {
        stack_t ss;
        memset(&ss, 0, sizeof ss);
        ss.ss_sp = signalStack;
@@ -29,7 +29,7 @@ static void changeSignalStack() {
        }
 }
 
-static void restoreSignalStack() {
+static void restoreSignalStack(void) {
 #if (defined(__x86_64__) || defined(__i386__)) && defined(__APPLE__)
        // The Darwin C library enforces a minimum that the kernel does not.
        // This is OK since we allocated this much space in mpreinit,
@@ -42,7 +42,7 @@ static void restoreSignalStack() {
        }
 }
 
-static int zero() {
+static int zero(void) {
        return 0;
 }
 */
diff --git a/misc/cgo/testplugin/src/iface/main.go b/misc/cgo/testplugin/src/iface/main.go
new file mode 100644 (file)
index 0000000..5e7e4d8
--- /dev/null
@@ -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 (file)
index 0000000..29d2e27
--- /dev/null
@@ -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 (file)
index 0000000..29d2e27
--- /dev/null
@@ -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 (file)
index 0000000..31c8038
--- /dev/null
@@ -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 (file)
index 0000000..70fd054
--- /dev/null
@@ -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 (file)
index 0000000..c75409d
--- /dev/null
@@ -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 (file)
index 0000000..8a3b85a
--- /dev/null
@@ -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) {}
index fee99a758c0c0aea6cd81efe760b9349631e993b..ab7430acc37f95e580492a1aa341c51e5eaa41e6 100755 (executable)
@@ -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/testsanitizers/msan_shared.go b/misc/cgo/testsanitizers/msan_shared.go
new file mode 100644 (file)
index 0000000..966947c
--- /dev/null
@@ -0,0 +1,12 @@
+// 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.
+
+// This program segfaulted during libpreinit when built with -msan:
+// http://golang.org/issue/18707
+
+package main
+
+import "C"
+
+func main() {}
index dfc6d3819a284413c64cb517f9fa2dc998897df8..4da85020d89800a3db00594b1b7937b04b6646c3 100755 (executable)
@@ -68,6 +68,25 @@ fi
 
 status=0
 
+testmsanshared() {
+  goos=$(go env GOOS)
+  suffix="-installsuffix testsanitizers"
+  libext="so"
+  if [ "$goos" == "darwin" ]; then
+         libext="dylib"
+  fi
+  go build -msan -buildmode=c-shared $suffix -o ${TMPDIR}/libmsanshared.$libext msan_shared.go
+
+       echo 'int main() { return 0; }' > ${TMPDIR}/testmsanshared.c
+  $CC $(go env GOGCCFLAGS) -fsanitize=memory -o ${TMPDIR}/testmsanshared ${TMPDIR}/testmsanshared.c ${TMPDIR}/libmsanshared.$libext
+
+  if ! LD_LIBRARY_PATH=. ${TMPDIR}/testmsanshared; then
+    echo "FAIL: msan_shared"
+    status=1
+  fi
+  rm -f ${TMPDIR}/{testmsanshared,testmsanshared.c,libmsanshared.$libext}
+}
+
 if test "$msan" = "yes"; then
     if ! go build -msan std; then
        echo "FAIL: build -msan std"
@@ -108,6 +127,8 @@ if test "$msan" = "yes"; then
        echo "FAIL: msan_fail"
        status=1
     fi
+
+    testmsanshared
 fi
 
 if test "$tsan" = "yes"; then
index af4f91550f2094beb4152d5fb59b7d7252585054..f0766e511ec5b3e60f9365afa5d2154793d8349c 100644 (file)
@@ -815,3 +815,14 @@ func TestImplicitInclusion(t *testing.T) {
        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")
+}
index a518b4efe2955e785b7c46fddf9513bf89902624..9f86710db01a4438fe4ab7fb7e8f3b13829592f5 100644 (file)
@@ -5,6 +5,8 @@ import (
        "reflect"
 )
 
+var SlicePtr interface{} = &[]int{}
+
 var V int = 1
 
 var HasMask []string = []string{"hi"}
index 433727112b13166d1bdc71a5c82e73e32b7b422b..84302a811f0919b9035b8da22814581af1d122a0 100644 (file)
@@ -19,6 +19,8 @@ func F() *C {
        return nil
 }
 
+var slicePtr interface{} = &[]int{}
+
 func main() {
        defer depBase.ImplementedInAsm()
        // This code below causes various go.itab.* symbols to be generated in
@@ -32,4 +34,11 @@ func main() {
        if reflect.TypeOf(F).Out(0) != reflect.TypeOf(c) {
                panic("bad reflection results, see golang.org/issue/18252")
        }
+
+       sp := reflect.New(reflect.TypeOf(slicePtr).Elem())
+       s := sp.Interface()
+
+       if reflect.TypeOf(s) != reflect.TypeOf(slicePtr) {
+               panic("bad reflection results, see golang.org/issue/18729")
+       }
 }
diff --git a/misc/cgo/testshared/src/iface/main.go b/misc/cgo/testshared/src/iface/main.go
new file mode 100644 (file)
index 0000000..3d5b54e
--- /dev/null
@@ -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 (file)
index 0000000..e11047c
--- /dev/null
@@ -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 (file)
index 0000000..47aee2e
--- /dev/null
@@ -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 (file)
index 0000000..31c8038
--- /dev/null
@@ -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
index 1eeb289c7d249ce60f96425489a879267a5040ff..3de341b9c59170805f0fefc7387a0921f9a8e1a7 100644 (file)
@@ -99,7 +99,7 @@ func main() {
        // 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 @@ func run(bin string, args []string) (err error) {
        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 @@ func run(bin string, args []string) (err error) {
        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 @@ func run(bin string, args []string) (err error) {
                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 @@ func copyLocalData(dstbase string) (pkgpath string, err error) {
 
        // 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 {
index 8113710e3983742d588f3da4ba2dbd52d5ba01ae..d4f3d9884ed989222d4ff92f4569ee5a3fac0c9c 100644 (file)
@@ -303,7 +303,9 @@ func genhash(sym *Sym, t *Type) {
        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 @@ func geneq(sym *Sym, t *Type) {
        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.
index 1ee9e76737e51644514526fadfa7a35be38bc0a1..752f65be425ec55bea71d7513538f7e1e640a348 100644 (file)
@@ -217,7 +217,9 @@ func Import(in *bufio.Reader) {
        typecheckok = tcok
        resumecheckwidth()
 
-       testdclstack() // debugging only
+       if debug_dclstack != 0 {
+               testdclstack()
+       }
 }
 
 func formatErrorf(format string, args ...interface{}) {
index e02e2feb016b6498866aeda2462dbae383dddd27..71b323f8a1d1b2796b079578e3b05346d1a6e6dc 100644 (file)
@@ -15,6 +15,7 @@ var runtimeDecls = [...]struct {
        {"panicwrap", funcTag, 7},
        {"gopanic", funcTag, 9},
        {"gorecover", funcTag, 12},
+       {"goschedguarded", funcTag, 5},
        {"printbool", funcTag, 14},
        {"printfloat", funcTag, 16},
        {"printint", funcTag, 18},
index 98e25fefb899c710c28b14f36748be88f5aa9cf5..69511155f4728b431531d51f14139861e9f84b13 100644 (file)
@@ -21,6 +21,7 @@ func panicwrap(string, string, string)
 
 func gopanic(interface{})
 func gorecover(*int32) interface{}
+func goschedguarded()
 
 func printbool(bool)
 func printfloat(float64)
index 11f0547d5e8082bfa0d0e189d1aad945f6fbf39e..f5fb72bca539c3fa2a12ca017a07a6408aa7550e 100644 (file)
@@ -30,11 +30,12 @@ var (
 )
 
 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 @@ var debugtab = []struct {
        {"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 @@ func Main() {
        timings.Stop()
        timings.AddEvent(int64(lexlineno-lexlineno0), "lines")
 
-       testdclstack()
        mkpackage(localpkg.Name) // final import not used checks
        finishUniverse()
 
index 1d69151cc41dd2be51a70c01b9cf37820353774f..9dbe769fa7c8e370982501c0be6fd10778c1a840 100644 (file)
@@ -34,6 +34,7 @@ func parseFile(filename string) {
        }
 
        if nsyntaxerrors == 0 {
+               // Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
                testdclstack()
        }
 }
@@ -1051,6 +1052,7 @@ func (p *noder) pragma(pos, line int, text string) syntax.Pragma {
                lookup(f[1]).Linkname = f[2]
 
        case strings.HasPrefix(text, "go:cgo_"):
+               lineno = p.baseline + int32(line) - 1 // pragcgo may call yyerror
                pragcgobuf += pragcgo(text)
                fallthrough // because of //go:cgo_unsafe_args
        default:
@@ -1058,6 +1060,7 @@ func (p *noder) pragma(pos, line int, text string) syntax.Pragma {
                if i := strings.Index(text, " "); i >= 0 {
                        verb = verb[:i]
                }
+               lineno = p.baseline + int32(line) - 1 // pragmaValue may call yyerror
                return syntax.Pragma(pragmaValue(verb))
        }
 
index 55ee3c01dcc50e99dd1b53f84a2387f8c2fc056b..bf483f8416c118860faab62de85a22f8457499e6 100644 (file)
@@ -64,6 +64,9 @@ func buildssa(fn *Node) *ssa.Func {
        s.config = initssa()
        s.f = s.config.NewFunc()
        s.f.Name = name
+       if fn.Func.Pragma&Nosplit != 0 {
+               s.f.NoSplit = true
+       }
        s.exitCode = fn.Func.Exit
        s.panics = map[funcLine]*ssa.Block{}
        s.config.DebugTest = s.config.DebugHashMatch("GOSSAHASH", name)
index 9b9a3f121015d86fa746647b255ed19ab632e13d..7d008dfa65527f9d020995bfa67cd84ac7d76ec7 100644 (file)
@@ -1833,7 +1833,9 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
        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() {
index bb5cede5a60da75f700594c4aede4dacfa39ae01..c62bd00808f21c625343a495cebc31aab4747b30 100644 (file)
@@ -57,8 +57,13 @@ func startProfile() {
                        Fatalf("%v", err)
                }
                atExit(func() {
-                       runtime.GC() // profile all outstanding allocations
-                       if err := pprof.WriteHeapProfile(f); err != nil {
+                       // Profile all outstanding allocations.
+                       runtime.GC()
+                       // compilebench parses the memory profile to extract memstats,
+                       // which are only written in the legacy pprof format.
+                       // See golang.org/issue/18641 and runtime/pprof/pprof.go:writeHeap.
+                       const writeLegacyFormat = 1
+                       if err := pprof.Lookup("heap").WriteTo(f, writeLegacyFormat); err != nil {
                                Fatalf("%v", err)
                        }
                })
index efe2016e46ca2c8be566259520d458881d03fb70..7c2e2ab442886c4f511300a77075ad968ec16fec 100644 (file)
@@ -3117,12 +3117,12 @@ func walkcompare(n *Node, init *Nodes) *Node {
                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))
index b9ec7eb6b7bddf22b1d712f5812e24f9e12b2367..5b461bac4874476b4cfc8811e17c36d23bac9cff 100644 (file)
@@ -5,6 +5,7 @@
 package ssa
 
 import (
+       "cmd/internal/obj"
        "fmt"
        "log"
        "os"
@@ -349,6 +350,8 @@ var passes = [...]pass{
        {name: "writebarrier", fn: writebarrier, required: true}, // expand write barrier ops
        {name: "fuse", fn: fuse},
        {name: "dse", fn: dse},
+       {name: "insert resched checks", fn: insertLoopReschedChecks,
+               disabled: obj.Preemptibleloops_enabled == 0}, // insert resched checks in loops.
        {name: "tighten", fn: tighten}, // move values closer to their uses
        {name: "lower", fn: lower, required: true},
        {name: "lowered cse", fn: cse},
@@ -378,7 +381,13 @@ type constraint struct {
 }
 
 var passOrder = [...]constraint{
-       // prove reliese on common-subexpression elimination for maximum benefits.
+       // "insert resched checks" uses mem, better to clean out stores first.
+       {"dse", "insert resched checks"},
+       // insert resched checks adds new blocks containing generic instructions
+       {"insert resched checks", "lower"},
+       {"insert resched checks", "tighten"},
+
+       // prove relies on common-subexpression elimination for maximum benefits.
        {"generic cse", "prove"},
        // deadcode after prove to eliminate all new dead blocks.
        {"prove", "generic deadcode"},
index 7b2097bcae71aedda8fbbfcc690aa8316dc3038f..df29aa36064f19edd61d93d41858b910923bdced 100644 (file)
@@ -24,6 +24,7 @@ type Func struct {
        vid        idAlloc     // value ID allocator
 
        scheduled bool // Values in Blocks are in final order
+       NoSplit   bool // true if function is marked as nosplit.  Used by schedule check pass.
 
        // when register allocation is done, maps value ids to locations
        RegAlloc []Location
index 0e0f1f9c1e79c9bc19b1b3d4640760f8cc471914..cad753e591d8c995feece7eedea7a471a890940d 100644 (file)
 (Geq32F x y) -> (FGreaterEqual (FCMPU x y))
 (Geq64F x y) -> (FGreaterEqual (FCMPU x y))
 
-(Geq8U x y)  -> (GreaterEqual (CMPU (ZeroExt8to32 x) (ZeroExt8to32 y)))
-(Geq16U x y) -> (GreaterEqual (CMPU (ZeroExt16to32 x) (ZeroExt16to32 y)))
-(Geq32U x y) -> (GreaterEqual (CMPU x y))
+(Geq8U x y)  -> (GreaterEqual (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Geq16U x y) -> (GreaterEqual (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Geq32U x y) -> (GreaterEqual (CMPWU x y))
 (Geq64U x y) -> (GreaterEqual (CMPU x y))
 
 // Absorb pseudo-ops into blocks.
index 3e0533a95142d3bb8f883a8b609339086bca9ce7..be0d581fe099289c09ee805370af5588848cdee7 100644 (file)
 (MOVDEQ y _ (FlagLT)) -> y
 (MOVDEQ y _ (FlagGT)) -> y
 
-(MOVDNE _ y (FlagEQ)) -> y
-(MOVDNE x _ (FlagLT)) -> x
-(MOVDNE x _ (FlagGT)) -> x
+(MOVDNE y _ (FlagEQ)) -> y
+(MOVDNE _ x (FlagLT)) -> x
+(MOVDNE _ x (FlagGT)) -> x
 
 (MOVDLT y _ (FlagEQ)) -> y
 (MOVDLT _ x (FlagLT)) -> x
diff --git a/src/cmd/compile/internal/ssa/loopreschedchecks.go b/src/cmd/compile/internal/ssa/loopreschedchecks.go
new file mode 100644 (file)
index 0000000..8f8055e
--- /dev/null
@@ -0,0 +1,517 @@
+// 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.
+
+package ssa
+
+import "fmt"
+
+// an edgeMemCtr records a backedge, together with the memory and
+// counter phi functions at the target of the backedge that must
+// be updated when a rescheduling check replaces the backedge.
+type edgeMemCtr struct {
+       e Edge
+       m *Value // phi for memory at dest of e
+       c *Value // phi for counter at dest of e
+}
+
+// a rewriteTarget is a a value-argindex pair indicating
+// where a rewrite is applied.  Note that this is for values,
+// not for block controls, because block controls are not targets
+// for the rewrites performed in inserting rescheduling checks.
+type rewriteTarget struct {
+       v *Value
+       i int
+}
+
+type rewrite struct {
+       before, after *Value          // before is the expected value before rewrite, after is the new value installed.
+       rewrites      []rewriteTarget // all the targets for this rewrite.
+}
+
+func (r *rewrite) String() string {
+       s := "\n\tbefore=" + r.before.String() + ", after=" + r.after.String()
+       for _, rw := range r.rewrites {
+               s += ", (i=" + fmt.Sprint(rw.i) + ", v=" + rw.v.LongString() + ")"
+       }
+       s += "\n"
+       return s
+}
+
+const initialRescheduleCounterValue = 1021 // Largest 10-bit prime. 97 nSec loop bodies will check every 100 uSec.
+
+// insertLoopReschedChecks inserts rescheduling checks on loop backedges.
+func insertLoopReschedChecks(f *Func) {
+       // TODO: when split information is recorded in export data, insert checks only on backedges that can be reached on a split-call-free path.
+
+       // Loop reschedule checks decrement a per-function counter
+       // shared by all loops, and when the counter becomes non-positive
+       // a call is made to a rescheduling check in the runtime.
+       //
+       // Steps:
+       // 1. locate backedges.
+       // 2. Record memory definitions at block end so that
+       //    the SSA graph for mem can be prperly modified.
+       // 3. Define a counter and record its future uses (at backedges)
+       //    (Same process as 2, applied to a single definition of the counter.
+       //     difference for mem is that there are zero-to-many existing mem
+       //     definitions, versus exactly one for the new counter.)
+       // 4. Ensure that phi functions that will-be-needed for mem and counter
+       //    are present in the graph, initially with trivial inputs.
+       // 5. Record all to-be-modified uses of mem and counter;
+       //    apply modifications (split into two steps to simplify and
+       //    avoided nagging order-dependences).
+       // 6. Rewrite backedges to include counter check, reschedule check,
+       //    and modify destination phi function appropriately with new
+       //    definitions for mem and counter.
+
+       if f.NoSplit { // nosplit functions don't reschedule.
+               return
+       }
+
+       backedges := backedges(f)
+       if len(backedges) == 0 { // no backedges means no rescheduling checks.
+               return
+       }
+
+       lastMems := findLastMems(f)
+
+       idom := f.Idom()
+       sdom := f.sdom()
+
+       if f.pass.debug > 2 {
+               fmt.Printf("before %s = %s\n", f.Name, sdom.treestructure(f.Entry))
+       }
+
+       tofixBackedges := []edgeMemCtr{}
+
+       for _, e := range backedges { // TODO: could filter here by calls in loops, if declared and inferred nosplit are recorded in export data.
+               tofixBackedges = append(tofixBackedges, edgeMemCtr{e, nil, nil})
+       }
+
+       // It's possible that there is no memory state (no global/pointer loads/stores or calls)
+       if lastMems[f.Entry.ID] == nil {
+               lastMems[f.Entry.ID] = f.Entry.NewValue0(f.Entry.Line, OpInitMem, TypeMem)
+       }
+
+       memDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, the mem def seen at its bottom. Could be from earlier block.
+
+       // Propagate last mem definitions forward through successor blocks.
+       po := f.postorder()
+       for i := len(po) - 1; i >= 0; i-- {
+               b := po[i]
+               mem := lastMems[b.ID]
+               for j := 0; mem == nil; j++ { // if there's no def, then there's no phi, so the visible mem is identical in all predecessors.
+                       // loop because there might be backedges that haven't been visited yet.
+                       mem = memDefsAtBlockEnds[b.Preds[j].b.ID]
+               }
+               memDefsAtBlockEnds[b.ID] = mem
+       }
+
+       // Set up counter.  There are no phis etc pre-existing for it.
+       counter0 := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), initialRescheduleCounterValue)
+       ctrDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, def visible at its end, if that def will be used.
+
+       // There's a minor difference between memDefsAtBlockEnds and ctrDefsAtBlockEnds;
+       // because the counter only matter for loops and code that reaches them, it is nil for blocks where the ctr is no
+       // longer live.  This will avoid creation of dead phi functions.  This optimization is ignored for the mem variable
+       // because it is harder and also less likely to be helpful, though dead code elimination ought to clean this out anyhow.
+
+       for _, emc := range tofixBackedges {
+               e := emc.e
+               // set initial uses of counter zero (note available-at-bottom and use are the same thing initially.)
+               // each back-edge will be rewritten to include a reschedule check, and that will use the counter.
+               src := e.b.Preds[e.i].b
+               ctrDefsAtBlockEnds[src.ID] = counter0
+       }
+
+       // Push uses towards root
+       for _, b := range f.postorder() {
+               bd := ctrDefsAtBlockEnds[b.ID]
+               if bd == nil {
+                       continue
+               }
+               for _, e := range b.Preds {
+                       p := e.b
+                       if ctrDefsAtBlockEnds[p.ID] == nil {
+                               ctrDefsAtBlockEnds[p.ID] = bd
+                       }
+               }
+       }
+
+       // Maps from block to newly-inserted phi function in block.
+       newmemphis := make(map[*Block]rewrite)
+       newctrphis := make(map[*Block]rewrite)
+
+       // Insert phi functions as necessary for future changes to flow graph.
+       for i, emc := range tofixBackedges {
+               e := emc.e
+               h := e.b
+
+               // find the phi function for the memory input at "h", if there is one.
+               var headerMemPhi *Value // look for header mem phi
+
+               for _, v := range h.Values {
+                       if v.Op == OpPhi && v.Type.IsMemory() {
+                               headerMemPhi = v
+                       }
+               }
+
+               if headerMemPhi == nil {
+                       // if the header is nil, make a trivial phi from the dominator
+                       mem0 := memDefsAtBlockEnds[idom[h.ID].ID]
+                       headerMemPhi = newPhiFor(h, mem0)
+                       newmemphis[h] = rewrite{before: mem0, after: headerMemPhi}
+                       addDFphis(mem0, h, h, f, memDefsAtBlockEnds, newmemphis)
+
+               }
+               tofixBackedges[i].m = headerMemPhi
+
+               var headerCtrPhi *Value
+               rw, ok := newctrphis[h]
+               if !ok {
+                       headerCtrPhi = newPhiFor(h, counter0)
+                       newctrphis[h] = rewrite{before: counter0, after: headerCtrPhi}
+                       addDFphis(counter0, h, h, f, ctrDefsAtBlockEnds, newctrphis)
+               } else {
+                       headerCtrPhi = rw.after
+               }
+               tofixBackedges[i].c = headerCtrPhi
+       }
+
+       rewriteNewPhis(f.Entry, f.Entry, f, memDefsAtBlockEnds, newmemphis)
+       rewriteNewPhis(f.Entry, f.Entry, f, ctrDefsAtBlockEnds, newctrphis)
+
+       if f.pass.debug > 0 {
+               for b, r := range newmemphis {
+                       fmt.Printf("b=%s, rewrite=%s\n", b, r.String())
+               }
+
+               for b, r := range newctrphis {
+                       fmt.Printf("b=%s, rewrite=%s\n", b, r.String())
+               }
+       }
+
+       // Apply collected rewrites.
+       for _, r := range newmemphis {
+               for _, rw := range r.rewrites {
+                       rw.v.SetArg(rw.i, r.after)
+               }
+       }
+
+       for _, r := range newctrphis {
+               for _, rw := range r.rewrites {
+                       rw.v.SetArg(rw.i, r.after)
+               }
+       }
+
+       zero := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), 0)
+       one := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), 1)
+
+       // Rewrite backedges to include reschedule checks.
+       for _, emc := range tofixBackedges {
+               e := emc.e
+               headerMemPhi := emc.m
+               headerCtrPhi := emc.c
+               h := e.b
+               i := e.i
+               p := h.Preds[i]
+               bb := p.b
+               mem0 := headerMemPhi.Args[i]
+               ctr0 := headerCtrPhi.Args[i]
+               // bb e->p h,
+               // Because we're going to insert a rare-call, make sure the
+               // looping edge still looks likely.
+               likely := BranchLikely
+               if p.i != 0 {
+                       likely = BranchUnlikely
+               }
+               bb.Likely = likely
+
+               // rewrite edge to include reschedule check
+               // existing edges:
+               //
+               // bb.Succs[p.i] == Edge{h, i}
+               // h.Preds[i] == p == Edge{bb,p.i}
+               //
+               // new block(s):
+               // test:
+               //    ctr1 := ctr0 - 1
+               //    if ctr1 <= 0 { goto sched }
+               //    goto join
+               // sched:
+               //    mem1 := call resched (mem0)
+               //    goto join
+               // join:
+               //    ctr2 := phi(ctr1, counter0) // counter0 is the constant
+               //    mem2 := phi(mem0, mem1)
+               //    goto h
+               //
+               // and correct arg i of headerMemPhi and headerCtrPhi
+               //
+               // EXCEPT: block containing only phi functions is bad
+               // for the register allocator.  Therefore, there is no
+               // join, and instead branches targeting join instead target
+               // the header, and the other phi functions within header are
+               // adjusted for the additional input.
+
+               test := f.NewBlock(BlockIf)
+               sched := f.NewBlock(BlockPlain)
+
+               test.Line = bb.Line
+               sched.Line = bb.Line
+
+               //    ctr1 := ctr0 - 1
+               //    if ctr1 <= 0 { goto sched }
+               //    goto header
+               ctr1 := test.NewValue2(bb.Line, OpSub32, f.Config.fe.TypeInt32(), ctr0, one)
+               cmp := test.NewValue2(bb.Line, OpLeq32, f.Config.fe.TypeBool(), ctr1, zero)
+               test.SetControl(cmp)
+               test.AddEdgeTo(sched) // if true
+               // if false -- rewrite edge to header.
+               // do NOT remove+add, because that will perturb all the other phi functions
+               // as well as messing up other edges to the header.
+               test.Succs = append(test.Succs, Edge{h, i})
+               h.Preds[i] = Edge{test, 1}
+               headerMemPhi.SetArg(i, mem0)
+               headerCtrPhi.SetArg(i, ctr1)
+
+               test.Likely = BranchUnlikely
+
+               // sched:
+               //    mem1 := call resched (mem0)
+               //    goto header
+               resched := f.Config.fe.Syslook("goschedguarded")
+               mem1 := sched.NewValue1A(bb.Line, OpStaticCall, TypeMem, resched, mem0)
+               sched.AddEdgeTo(h)
+               headerMemPhi.AddArg(mem1)
+               headerCtrPhi.AddArg(counter0)
+
+               bb.Succs[p.i] = Edge{test, 0}
+               test.Preds = append(test.Preds, Edge{bb, p.i})
+
+               // Must correct all the other phi functions in the header for new incoming edge.
+               // Except for mem and counter phis, it will be the same value seen on the original
+               // backedge at index i.
+               for _, v := range h.Values {
+                       if v.Op == OpPhi && v != headerMemPhi && v != headerCtrPhi {
+                               v.AddArg(v.Args[i])
+                       }
+               }
+       }
+
+       f.invalidateCFG()
+
+       if f.pass.debug > 2 {
+               sdom = newSparseTree(f, f.Idom())
+               fmt.Printf("after %s = %s\n", f.Name, sdom.treestructure(f.Entry))
+       }
+
+       return
+}
+
+// newPhiFor inserts a new Phi function into b,
+// with all inputs set to v.
+func newPhiFor(b *Block, v *Value) *Value {
+       phiV := b.NewValue0(b.Line, OpPhi, v.Type)
+
+       for range b.Preds {
+               phiV.AddArg(v)
+       }
+       return phiV
+}
+
+// rewriteNewPhis updates newphis[h] to record all places where the new phi function inserted
+// in block h will replace a previous definition.  Block b is the block currently being processed;
+// if b has its own phi definition then it takes the place of h.
+// defsForUses provides information about other definitions of the variable that are present
+// (and if nil, indicates that the variable is no longer live)
+func rewriteNewPhis(h, b *Block, f *Func, defsForUses []*Value, newphis map[*Block]rewrite) {
+       // If b is a block with a new phi, then a new rewrite applies below it in the dominator tree.
+       if _, ok := newphis[b]; ok {
+               h = b
+       }
+       change := newphis[h]
+       x := change.before
+       y := change.after
+
+       // Apply rewrites to this block
+       if x != nil { // don't waste time on the common case of no definition.
+               p := &change.rewrites
+               for _, v := range b.Values {
+                       if v == y { // don't rewrite self -- phi inputs are handled below.
+                               continue
+                       }
+                       for i, w := range v.Args {
+                               if w != x {
+                                       continue
+                               }
+                               *p = append(*p, rewriteTarget{v, i})
+                       }
+               }
+
+               // Rewrite appropriate inputs of phis reached in successors
+               // in dominance frontier, self, and dominated.
+               // If the variable def reaching uses in b is itself defined in b, then the new phi function
+               // does not reach the successors of b.  (This assumes a bit about the structure of the
+               // phi use-def graph, but it's true for memory and the inserted counter.)
+               if dfu := defsForUses[b.ID]; dfu != nil && dfu.Block != b {
+                       for _, e := range b.Succs {
+                               s := e.b
+                               if sphi, ok := newphis[s]; ok { // saves time to find the phi this way.
+                                       *p = append(*p, rewriteTarget{sphi.after, e.i})
+                                       continue
+                               }
+                               for _, v := range s.Values {
+                                       if v.Op == OpPhi && v.Args[e.i] == x {
+                                               *p = append(*p, rewriteTarget{v, e.i})
+                                               break
+                                       }
+                               }
+                       }
+               }
+               newphis[h] = change
+       }
+
+       sdom := f.sdom()
+
+       for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
+               rewriteNewPhis(h, c, f, defsForUses, newphis) // TODO: convert to explicit stack from recursion.
+       }
+}
+
+// addDFphis creates new trivial phis that are necessary to correctly reflect (within SSA)
+// a new definition for variable "x" inserted at h (usually but not necessarily a phi).
+// These new phis can only occur at the dominance frontier of h; block s is in the dominance
+// frontier of h if h does not strictly dominate s and if s is a successor of a block b where
+// either b = h or h strictly dominates b.
+// These newly created phis are themselves new definitions that may require addition of their
+// own trivial phi functions in their own dominance frontier, and this is handled recursively.
+func addDFphis(x *Value, h, b *Block, f *Func, defForUses []*Value, newphis map[*Block]rewrite) {
+       oldv := defForUses[b.ID]
+       if oldv != x { // either a new definition replacing x, or nil if it is proven that there are no uses reachable from b
+               return
+       }
+       sdom := f.sdom()
+       idom := f.Idom()
+outer:
+       for _, e := range b.Succs {
+               s := e.b
+               // check phi functions in the dominance frontier
+               if sdom.isAncestor(h, s) {
+                       continue // h dominates s, successor of b, therefore s is not in the frontier.
+               }
+               if _, ok := newphis[s]; ok {
+                       continue // successor s of b already has a new phi function, so there is no need to add another.
+               }
+               if x != nil {
+                       for _, v := range s.Values {
+                               if v.Op == OpPhi && v.Args[e.i] == x {
+                                       continue outer // successor s of b has an old phi function, so there is no need to add another.
+                               }
+                       }
+               }
+
+               old := defForUses[idom[s.ID].ID] // new phi function is correct-but-redundant, combining value "old" on all inputs.
+               headerPhi := newPhiFor(s, old)
+               // the new phi will replace "old" in block s and all blocks dominated by s.
+               newphis[s] = rewrite{before: old, after: headerPhi} // record new phi, to have inputs labeled "old" rewritten to "headerPhi"
+               addDFphis(old, s, s, f, defForUses, newphis)        // the new definition may also create new phi functions.
+       }
+       for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
+               addDFphis(x, h, c, f, defForUses, newphis) // TODO: convert to explicit stack from recursion.
+       }
+}
+
+// findLastMems maps block ids to last memory-output op in a block, if any
+func findLastMems(f *Func) []*Value {
+
+       var stores []*Value
+       lastMems := make([]*Value, f.NumBlocks())
+       storeUse := f.newSparseSet(f.NumValues())
+       defer f.retSparseSet(storeUse)
+       for _, b := range f.Blocks {
+               // Find all the stores in this block. Categorize their uses:
+               //  storeUse contains stores which are used by a subsequent store.
+               storeUse.clear()
+               stores = stores[:0]
+               var memPhi *Value
+               for _, v := range b.Values {
+                       if v.Op == OpPhi {
+                               if v.Type.IsMemory() {
+                                       memPhi = v
+                               }
+                               continue
+                       }
+                       if v.Type.IsMemory() {
+                               stores = append(stores, v)
+                               if v.Op == OpSelect1 {
+                                       // Use the arg of the tuple-generating op.
+                                       v = v.Args[0]
+                               }
+                               for _, a := range v.Args {
+                                       if a.Block == b && a.Type.IsMemory() {
+                                               storeUse.add(a.ID)
+                                       }
+                               }
+                       }
+               }
+               if len(stores) == 0 {
+                       lastMems[b.ID] = memPhi
+                       continue
+               }
+
+               // find last store in the block
+               var last *Value
+               for _, v := range stores {
+                       if storeUse.contains(v.ID) {
+                               continue
+                       }
+                       if last != nil {
+                               b.Fatalf("two final stores - simultaneous live stores %s %s", last, v)
+                       }
+                       last = v
+               }
+               if last == nil {
+                       b.Fatalf("no last store found - cycle?")
+               }
+               lastMems[b.ID] = last
+       }
+       return lastMems
+}
+
+type backedgesState struct {
+       b *Block
+       i int
+}
+
+// backedges returns a slice of successor edges that are back
+// edges.  For reducible loops, edge.b is the header.
+func backedges(f *Func) []Edge {
+       edges := []Edge{}
+       mark := make([]markKind, f.NumBlocks())
+       stack := []backedgesState{}
+
+       mark[f.Entry.ID] = notExplored
+       stack = append(stack, backedgesState{f.Entry, 0})
+
+       for len(stack) > 0 {
+               l := len(stack)
+               x := stack[l-1]
+               if x.i < len(x.b.Succs) {
+                       e := x.b.Succs[x.i]
+                       stack[l-1].i++
+                       s := e.b
+                       if mark[s.ID] == notFound {
+                               mark[s.ID] = notExplored
+                               stack = append(stack, backedgesState{s, 0})
+                       } else if mark[s.ID] == notExplored {
+                               edges = append(edges, e)
+                       }
+               } else {
+                       mark[x.b.ID] = done
+                       stack = stack[0 : l-1]
+               }
+       }
+       return edges
+}
index 9f58db664b144499911a8924071b8b45b450e9b7..0a34cd1ae642305e44a516e646413e0cf74ba20e 100644 (file)
@@ -82,7 +82,7 @@ func nilcheckelim(f *Func) {
                                }
                        }
 
-                       // Next, process values in the block.
+                       // Next, eliminate any redundant nil checks in this block.
                        i := 0
                        for _, v := range b.Values {
                                b.Values[i] = v
@@ -105,13 +105,10 @@ func nilcheckelim(f *Func) {
                                                        f.Config.Warnl(v.Line, "removed nil check")
                                                }
                                                v.reset(OpUnknown)
+                                               // TODO: f.freeValue(v)
                                                i--
                                                continue
                                        }
-                                       // Record the fact that we know ptr is non nil, and remember to
-                                       // undo that information when this dominator subtree is done.
-                                       nonNilValues[ptr.ID] = true
-                                       work = append(work, bp{op: ClearPtr, ptr: ptr})
                                }
                        }
                        for j := i; j < len(b.Values); j++ {
@@ -119,6 +116,21 @@ func nilcheckelim(f *Func) {
                        }
                        b.Values = b.Values[:i]
 
+                       // Finally, find redundant nil checks for subsequent blocks.
+                       // Note that we can't add these until the loop above is done, as the
+                       // values in the block are not ordered in any way when this pass runs.
+                       // This was the cause of issue #18725.
+                       for _, v := range b.Values {
+                               if v.Op != OpNilCheck {
+                                       continue
+                               }
+                               ptr := v.Args[0]
+                               // Record the fact that we know ptr is non nil, and remember to
+                               // undo that information when this dominator subtree is done.
+                               nonNilValues[ptr.ID] = true
+                               work = append(work, bp{op: ClearPtr, ptr: ptr})
+                       }
+
                        // Add all dominated blocks to the work list.
                        for w := sdom[node.block.ID].child; w != nil; w = sdom[w.ID].sibling {
                                work = append(work, bp{op: Work, block: w})
index 8c8373b8aa019b24057184c631d733b70ce6168d..031459c1ffbedb0e42553e33b3fed1abd7e7ce23 100644 (file)
@@ -1543,12 +1543,12 @@ func rewriteValuePPC64_OpGeq16U(v *Value, config *Config) bool {
        _ = b
        // match: (Geq16U x y)
        // cond:
-       // result: (GreaterEqual (CMPU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+       // result: (GreaterEqual (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
        for {
                x := v.Args[0]
                y := v.Args[1]
                v.reset(OpPPC64GreaterEqual)
-               v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+               v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
                v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
                v1.AddArg(x)
                v0.AddArg(v1)
@@ -1598,12 +1598,12 @@ func rewriteValuePPC64_OpGeq32U(v *Value, config *Config) bool {
        _ = b
        // match: (Geq32U x y)
        // cond:
-       // result: (GreaterEqual (CMPU x y))
+       // result: (GreaterEqual (CMPWU x y))
        for {
                x := v.Args[0]
                y := v.Args[1]
                v.reset(OpPPC64GreaterEqual)
-               v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+               v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
                v0.AddArg(x)
                v0.AddArg(y)
                v.AddArg(v0)
@@ -1687,12 +1687,12 @@ func rewriteValuePPC64_OpGeq8U(v *Value, config *Config) bool {
        _ = b
        // match: (Geq8U x y)
        // cond:
-       // result: (GreaterEqual (CMPU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+       // result: (GreaterEqual (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
        for {
                x := v.Args[0]
                y := v.Args[1]
                v.reset(OpPPC64GreaterEqual)
-               v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+               v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
                v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
                v1.AddArg(x)
                v0.AddArg(v1)
index 7d023bcf8ba38f18b04fac62a4cd22694d622182..5acaf2dbdc4fcb1466c36afa07112dcbd8f4de07 100644 (file)
@@ -9847,11 +9847,11 @@ func rewriteValueS390X_OpS390XMOVDNE(v *Value, config *Config) bool {
                v.AddArg(cmp)
                return true
        }
-       // match: (MOVDNE _ y (FlagEQ))
+       // match: (MOVDNE y _ (FlagEQ))
        // cond:
        // result: y
        for {
-               y := v.Args[1]
+               y := v.Args[0]
                v_2 := v.Args[2]
                if v_2.Op != OpS390XFlagEQ {
                        break
@@ -9861,11 +9861,11 @@ func rewriteValueS390X_OpS390XMOVDNE(v *Value, config *Config) bool {
                v.AddArg(y)
                return true
        }
-       // match: (MOVDNE x _ (FlagLT))
+       // match: (MOVDNE _ x (FlagLT))
        // cond:
        // result: x
        for {
-               x := v.Args[0]
+               x := v.Args[1]
                v_2 := v.Args[2]
                if v_2.Op != OpS390XFlagLT {
                        break
@@ -9875,11 +9875,11 @@ func rewriteValueS390X_OpS390XMOVDNE(v *Value, config *Config) bool {
                v.AddArg(x)
                return true
        }
-       // match: (MOVDNE x _ (FlagGT))
+       // match: (MOVDNE _ x (FlagGT))
        // cond:
        // result: x
        for {
-               x := v.Args[0]
+               x := v.Args[1]
                v_2 := v.Args[2]
                if v_2.Op != OpS390XFlagGT {
                        break
index 7c82a60d0fa8fc1e26e4660e4370e4d4ca59645e..8e5b9f3e5bd68023bffdcd81beb0ab4b41fecbd1 100644 (file)
@@ -4,7 +4,10 @@
 
 package ssa
 
-import "fmt"
+import (
+       "fmt"
+       "strings"
+)
 
 type SparseTreeNode struct {
        child   *Block
@@ -67,6 +70,34 @@ func newSparseTree(f *Func, parentOf []*Block) SparseTree {
        return t
 }
 
+// treestructure provides a string description of the dominator
+// tree and flow structure of block b and all blocks that it
+// dominates.
+func (t SparseTree) treestructure(b *Block) string {
+       return t.treestructure1(b, 0)
+}
+func (t SparseTree) treestructure1(b *Block, i int) string {
+       s := "\n" + strings.Repeat("\t", i) + b.String() + "->["
+       for i, e := range b.Succs {
+               if i > 0 {
+                       s = s + ","
+               }
+               s = s + e.b.String()
+       }
+       s += "]"
+       if c0 := t[b.ID].child; c0 != nil {
+               s += "("
+               for c := c0; c != nil; c = t[c.ID].sibling {
+                       if c != c0 {
+                               s += " "
+                       }
+                       s += t.treestructure1(c, i+1)
+               }
+               s += ")"
+       }
+       return s
+}
+
 // numberBlock assigns entry and exit numbers for b and b's
 // children in an in-order walk from a gappy sequence, where n
 // is the first number not yet assigned or reserved. N should
index 1eb4d7bb1af5a929b411d756b08d7a7dd6a9a3a3..054ba1f85c6d155b3ecbbc79b64387678f038f63 100644 (file)
@@ -35,7 +35,7 @@ func writebarrier(f *Func) {
        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:
index 7d5f79f339219800a5c326565da198b336d51eb4..c51dcead2b3fd8d47d00a71490145cb61ba7026b 100644 (file)
@@ -15,7 +15,6 @@ import (
        "os/exec"
        "path/filepath"
        "regexp"
-       "runtime"
        "strconv"
        "strings"
        "sync"
@@ -354,7 +353,7 @@ func (t *tester) registerTests() {
 
        // This test needs its stdout/stderr to be terminals, so we don't run it from cmd/go's tests.
        // See issue 18153.
-       if runtime.GOOS == "linux" {
+       if t.goos == "linux" {
                t.tests = append(t.tests, distTest{
                        name:    "cmd_go_test_terminal",
                        heading: "cmd/go terminal test",
@@ -568,7 +567,7 @@ func (t *tester) registerTests() {
                if t.gohostos == "linux" && t.goarch == "amd64" {
                        t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go")
                }
-               if t.gohostos == "linux" && t.goarch == "amd64" {
+               if t.goos == "linux" && t.goarch == "amd64" {
                        t.registerTest("testsanitizers", "../misc/cgo/testsanitizers", "./test.bash")
                }
                if t.hasBash() && t.goos != "android" && !t.iOS() && t.gohostos != "windows" {
index e93fd6ebed7775157cdfd0c143d43cac6759fa2b..3d5dd2b39725883fd01bb5541d8604c268ddd4fc 100644 (file)
@@ -17,7 +17,7 @@
 //     clean       remove object files
 //     doc         show documentation for package or symbol
 //     env         print Go environment information
-//     bug         print information for bug reports
+//     bug         start a bug report
 //     fix         run go tool fix on packages
 //     fmt         run gofmt on package sources
 //     generate    generate Go files by processing source
 // each named variable on its own line.
 //
 //
-// Print information for bug reports
+// Start a bug report
 //
 // Usage:
 //
 //     go bug
 //
-// 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.
 //
 //
 // Run go tool fix on packages
index cbd258b80bde5f030f5f791ec831e368c89bed6a..658f6dabd90417b7c4efd8608948560f5f0365b2 100644 (file)
@@ -20,11 +20,10 @@ import (
 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.
        `,
 }
 
index 5727eb094e5473a1b5eadaed70a53e16aa9f0ef9..ef5348bba40ff8844911e57dce951ad904086cf9 100644 (file)
@@ -3744,6 +3744,13 @@ func TestMatchesOnlySubtestParallelIsOK(t *testing.T) {
        tg.grepBoth(okPattern, "go test did not say ok")
 }
 
+// Issue 18845
+func TestBenchTimeout(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.run("test", "-bench", ".", "-timeout", "750ms", "testdata/timeoutbench_test.go")
+}
+
 func TestLinkXImportPathEscape(t *testing.T) {
        // golang.org/issue/16710
        tg := testgo(t)
@@ -3787,3 +3794,26 @@ GLOBL ·constants<>(SB),8,$8
        tg.setenv("GOPATH", tg.path("go"))
        tg.run("build", "p")
 }
+
+// Issue 18778.
+func TestDotDotDotOutsideGOPATH(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+
+       tg.tempFile("pkgs/a.go", `package x`)
+       tg.tempFile("pkgs/a_test.go", `package x_test
+import "testing"
+func TestX(t *testing.T) {}`)
+
+       tg.tempFile("pkgs/a/a.go", `package a`)
+       tg.tempFile("pkgs/a/a_test.go", `package a_test
+import "testing"
+func TestA(t *testing.T) {}`)
+
+       tg.cd(tg.path("pkgs"))
+       tg.run("build", "./...")
+       tg.run("test", "./...")
+       tg.run("list", "./...")
+       tg.grepStdout("pkgs$", "expected package not listed")
+       tg.grepStdout("pkgs/a", "expected package not listed")
+}
index d69fa5118f520c374f305b02a8f422b7df861bc2..e40f9420c7e2217f9e126cf5f636c282c532d959 100644 (file)
@@ -429,7 +429,7 @@ func setErrorPos(p *Package, importPos []token.Position) *Package {
 func cleanImport(path string) string {
        orig := path
        path = pathpkg.Clean(path)
-       if strings.HasPrefix(orig, "./") && path != ".." && path != "." && !strings.HasPrefix(path, "../") {
+       if strings.HasPrefix(orig, "./") && path != ".." && !strings.HasPrefix(path, "../") {
                path = "./" + path
        }
        return path
index cdb167de75f86565b53b2ef29fce1339c4836822..6482f0fd32301a83a0bb9174170705b204587ef7 100644 (file)
@@ -894,9 +894,13 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 
        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 {
                if len(cp.coverVars) > 0 {
@@ -1343,7 +1347,8 @@ type testFuncs struct {
        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 @@ import (
        _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
 {{end}}
 
-{{if .NeedCgo}}
+{{if .IsIOS}}
+       "os/signal"
        _ "runtime/cgo"
+       "syscall"
 {{end}}
 )
 
@@ -1523,6 +1530,32 @@ func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts
 {{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/go/testdata/timeoutbench_test.go b/src/cmd/go/testdata/timeoutbench_test.go
new file mode 100644 (file)
index 0000000..57a8888
--- /dev/null
@@ -0,0 +1,10 @@
+package timeoutbench_test
+
+import (
+       "testing"
+       "time"
+)
+
+func BenchmarkSleep1s(b *testing.B) {
+       time.Sleep(1 * time.Second)
+}
index 1852dc74f63b7d4e0f014932d38c9d8f87316210..732ce1963477618250bf68b0cfbba9a1d40d95ee 100644 (file)
@@ -13,8 +13,9 @@ import (
 // go-specific code shared across loaders (5l, 6l, 8l).
 
 var (
-       framepointer_enabled int
-       Fieldtrack_enabled   int
+       framepointer_enabled     int
+       Fieldtrack_enabled       int
+       Preemptibleloops_enabled int
 )
 
 // Toolchain experiments.
@@ -27,6 +28,7 @@ var exper = []struct {
 }{
        {"fieldtrack", &Fieldtrack_enabled},
        {"framepointer", &framepointer_enabled},
+       {"preemptibleloops", &Preemptibleloops_enabled},
 }
 
 func addexp(s string) {
index 61d3e4fb720ecd1299540652816fcc2e11a90807..22d2c548c373e0c3b91f4805e8035fd3f64192cf 100644 (file)
@@ -1080,7 +1080,7 @@ func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
                epcs = s
 
                dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version))
-               dsym.Attr |= AttrHidden
+               dsym.Attr |= AttrHidden | AttrReachable
                dsym.Type = obj.SDWARFINFO
                for _, r := range dsym.R {
                        if r.Type == obj.R_DWARFREF && r.Sym.Size == 0 {
index 1ebd7de662ad4d1c2c7f5430bff15cf2fba44a9d..479425f2111ef6191778e136049b55921bc966e4 100644 (file)
@@ -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,
index a6c3080db3efe5f49467b28e703aed888e560b02..95fb18958561b311a6d545cdc4cb976f34ab6cf4 100644 (file)
@@ -204,12 +204,6 @@ func TestMTF(t *testing.T) {
        }
 }
 
-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 @@ func benchmarkDecode(b *testing.B, compressed []byte) {
        }
 }
 
-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)
+}
index 97265b3ca27ad091af42e7bf2ff120dd5e54f277..4d6a5357d881da4d90aba22d65728c60c075e287 100644 (file)
@@ -136,14 +136,17 @@ func (d *compressor) fillDeflate(b []byte) int {
                        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 {
index 521a2603658b9bba53c7138f2c950750a2eecba9..fbea761721a3e4115437c0bf244068daf86cfca7 100644 (file)
@@ -12,6 +12,7 @@ import (
        "io"
        "io/ioutil"
        "reflect"
+       "runtime/debug"
        "sync"
        "testing"
 )
@@ -864,3 +865,33 @@ func TestBestSpeedMaxMatchOffset(t *testing.T) {
                }
        }
 }
+
+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)
+       }
+}
index a1636a37d67cfa9826e78de10618c94faa12f5d6..08298b76bbb2da5a7882d439d61d8428b28f632a 100644 (file)
@@ -60,7 +60,7 @@ func newDeflateFast() *deflateFast {
 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 @@ func (e *deflateFast) reset() {
 
        // 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{}
        }
 }
index e76d47cc4ee5700d9faedfeb8b94a3c7370ac3ae..30c1390dfd7faf0ca4d2e1e37c8868db2f9e2089 100644 (file)
@@ -9,11 +9,17 @@ import (
        "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 {
index b89aeaebea6fcff67290fa2ae28b360931947d0f..8600059f0329fe26271a1d726e0923bcd9288ce5 100644 (file)
@@ -95,7 +95,7 @@ func TestSignAndVerify(t *testing.T) {
 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 @@ func TestSigningWithDegenerateKeys(t *testing.T) {
        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),
index 05146743acbba6010f3ac868bf2184303e11cf92..beb0f1926d89947d9603f0dbc2561ae08320d67f 100644 (file)
@@ -84,15 +84,15 @@ var cipherSuites = []*cipherSuite{
        {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},
index f2e5aea2bce5ed6d7305c2d8fdfd233b0d63c2fd..615d1e5576fdaab8c772eadae62a3d146757cc6d 100644 (file)
@@ -6,8 +6,8 @@
 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 (
index fea33df379aebdce57f78c6cc6a412e61acea99d..71ffbdf0e0460bd2df3d2a4e269f6056e3bd6b0d 100644 (file)
@@ -4,7 +4,11 @@
 
 package x509
 
-import "encoding/pem"
+import (
+       "encoding/pem"
+       "errors"
+       "runtime"
+)
 
 // CertPool is a set of certificates.
 type CertPool struct {
@@ -26,6 +30,11 @@ func NewCertPool() *CertPool {
 // 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()
 }
 
index ca2fba5cb421fe7b7925358fa50d15061da99cc5..a936fec7d8447dbc27669b4ff9aae4f2a32288e2 100644 (file)
@@ -226,6 +226,11 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
 }
 
 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"))
index aa30d85b7da06de25236732d0536b7c572831454..b085dad90f06a5f78a21e91d0f4ea5f2ef102522 100644 (file)
@@ -24,6 +24,7 @@ import (
        "net"
        "os/exec"
        "reflect"
+       "runtime"
        "strings"
        "testing"
        "time"
@@ -1477,6 +1478,9 @@ func TestMultipleRDN(t *testing.T) {
 }
 
 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)
index 0fa7c34a13e3bb7ee209b9b01a33befe2f414e80..feb91223a9e9b99f48fa65e041afd6f7d309e791 100644 (file)
@@ -1357,16 +1357,7 @@ func (db *DB) begin(ctx context.Context, opts *TxOptions, strategy connReuseStra
                cancel: cancel,
                ctx:    ctx,
        }
-       go func(tx *Tx) {
-               select {
-               case <-tx.ctx.Done():
-                       if !tx.isDone() {
-                               // Discard and close the connection used to ensure the transaction
-                               // is closed and the resources are released.
-                               tx.rollback(true)
-                       }
-               }
-       }(tx)
+       go tx.awaitDone()
        return tx, nil
 }
 
@@ -1388,6 +1379,11 @@ func (db *DB) Driver() driver.Driver {
 type Tx struct {
        db *DB
 
+       // closemu prevents the transaction from closing while there
+       // is an active query. It is held for read during queries
+       // and exclusively during close.
+       closemu sync.RWMutex
+
        // dc is owned exclusively until Commit or Rollback, at which point
        // it's returned with putConn.
        dc  *driverConn
@@ -1413,6 +1409,20 @@ type Tx struct {
        ctx context.Context
 }
 
+// awaitDone blocks until the context in Tx is canceled and rolls back
+// the transaction if it's not already done.
+func (tx *Tx) awaitDone() {
+       // Wait for either the transaction to be committed or rolled
+       // back, or for the associated context to be closed.
+       <-tx.ctx.Done()
+
+       // Discard and close the connection used to ensure the
+       // transaction is closed and the resources are released.  This
+       // rollback does nothing if the transaction has already been
+       // committed or rolled back.
+       tx.rollback(true)
+}
+
 func (tx *Tx) isDone() bool {
        return atomic.LoadInt32(&tx.done) != 0
 }
@@ -1424,16 +1434,31 @@ var ErrTxDone = errors.New("sql: Transaction has already been committed or rolle
 // close returns the connection to the pool and
 // must only be called by Tx.rollback or Tx.Commit.
 func (tx *Tx) close(err error) {
+       tx.closemu.Lock()
+       defer tx.closemu.Unlock()
+
        tx.db.putConn(tx.dc, err)
        tx.cancel()
        tx.dc = nil
        tx.txi = nil
 }
 
+// hookTxGrabConn specifies an optional hook to be called on
+// a successful call to (*Tx).grabConn. For tests.
+var hookTxGrabConn func()
+
 func (tx *Tx) grabConn(ctx context.Context) (*driverConn, error) {
+       select {
+       default:
+       case <-ctx.Done():
+               return nil, ctx.Err()
+       }
        if tx.isDone() {
                return nil, ErrTxDone
        }
+       if hookTxGrabConn != nil { // test hook
+               hookTxGrabConn()
+       }
        return tx.dc, nil
 }
 
@@ -1503,6 +1528,9 @@ func (tx *Tx) Rollback() error {
 // for the execution of the returned statement. The returned statement
 // will run in the transaction context.
 func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
+       tx.closemu.RLock()
+       defer tx.closemu.RUnlock()
+
        // TODO(bradfitz): We could be more efficient here and either
        // provide a method to take an existing Stmt (created on
        // perhaps a different Conn), and re-create it on this Conn if
@@ -1567,6 +1595,9 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
 // The returned statement operates within the transaction and will be closed
 // when the transaction has been committed or rolled back.
 func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt {
+       tx.closemu.RLock()
+       defer tx.closemu.RUnlock()
+
        // TODO(bradfitz): optimize this. Currently this re-prepares
        // each time. This is fine for now to illustrate the API but
        // we should really cache already-prepared statements
@@ -1618,6 +1649,9 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
 // ExecContext executes a query that doesn't return rows.
 // For example: an INSERT and UPDATE.
 func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
+       tx.closemu.RLock()
+       defer tx.closemu.RUnlock()
+
        dc, err := tx.grabConn(ctx)
        if err != nil {
                return nil, err
@@ -1661,6 +1695,9 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
 
 // QueryContext executes a query that returns rows, typically a SELECT.
 func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
+       tx.closemu.RLock()
+       defer tx.closemu.RUnlock()
+
        dc, err := tx.grabConn(ctx)
        if err != nil {
                return nil, err
@@ -2038,25 +2075,21 @@ type Rows struct {
        // closed value is 1 when the Rows is closed.
        // Use atomic operations on value when checking value.
        closed    int32
-       ctxClose  chan struct{} // closed when Rows is closed, may be null.
+       cancel    func() // called when Rows is closed, may be nil.
        lastcols  []driver.Value
        lasterr   error       // non-nil only if closed is true
        closeStmt *driverStmt // if non-nil, statement to Close on close
 }
 
 func (rs *Rows) initContextClose(ctx context.Context) {
-       if ctx.Done() == context.Background().Done() {
-               return
-       }
+       ctx, rs.cancel = context.WithCancel(ctx)
+       go rs.awaitDone(ctx)
+}
 
-       rs.ctxClose = make(chan struct{})
-       go func() {
-               select {
-               case <-ctx.Done():
-                       rs.Close()
-               case <-rs.ctxClose:
-               }
-       }()
+// awaitDone blocks until the rows are closed or the context canceled.
+func (rs *Rows) awaitDone(ctx context.Context) {
+       <-ctx.Done()
+       rs.Close()
 }
 
 // Next prepares the next result row for reading with the Scan method. It
@@ -2314,7 +2347,9 @@ func (rs *Rows) Scan(dest ...interface{}) error {
        return nil
 }
 
-var rowsCloseHook func(*Rows, *error)
+// rowsCloseHook returns a function so tests may install the
+// hook throug a test only mutex.
+var rowsCloseHook = func() func(*Rows, *error) { return nil }
 
 func (rs *Rows) isClosed() bool {
        return atomic.LoadInt32(&rs.closed) != 0
@@ -2328,13 +2363,15 @@ func (rs *Rows) Close() error {
        if !atomic.CompareAndSwapInt32(&rs.closed, 0, 1) {
                return nil
        }
-       if rs.ctxClose != nil {
-               close(rs.ctxClose)
-       }
+
        err := rs.rowsi.Close()
-       if fn := rowsCloseHook; fn != nil {
+       if fn := rowsCloseHook(); fn != nil {
                fn(rs, &err)
        }
+       if rs.cancel != nil {
+               rs.cancel()
+       }
+
        if rs.closeStmt != nil {
                rs.closeStmt.Close()
        }
index 63e1292cb1f2c50591f2e1f63f2606a879de5e95..898df3b455b22cac915bdb19510cc9ba22f83cbe 100644 (file)
@@ -14,6 +14,7 @@ import (
        "runtime"
        "strings"
        "sync"
+       "sync/atomic"
        "testing"
        "time"
 )
@@ -326,9 +327,7 @@ func TestQueryContext(t *testing.T) {
 
        // And verify that the final rows.Next() call, which hit EOF,
        // also closed the rows connection.
-       if n := db.numFreeConns(); n != 1 {
-               t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
-       }
+       waitForFree(t, db, 5*time.Second, 1)
        if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
                t.Errorf("executed %d Prepare statements; want 1", prepares)
        }
@@ -345,6 +344,18 @@ func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
        return false
 }
 
+// waitForFree checks db.numFreeConns until either it equals want or
+// the maxWait time elapses.
+func waitForFree(t *testing.T, db *DB, maxWait time.Duration, want int) {
+       var numFree int
+       if !waitCondition(maxWait, 5*time.Millisecond, func() bool {
+               numFree = db.numFreeConns()
+               return numFree == want
+       }) {
+               t.Fatalf("free conns after hitting EOF = %d; want %d", numFree, want)
+       }
+}
+
 func TestQueryContextWait(t *testing.T) {
        db := newTestDB(t, "people")
        defer closeDB(t, db)
@@ -361,9 +372,7 @@ func TestQueryContextWait(t *testing.T) {
        }
 
        // Verify closed rows connection after error condition.
-       if n := db.numFreeConns(); n != 1 {
-               t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
-       }
+       waitForFree(t, db, 5*time.Second, 1)
        if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
                t.Errorf("executed %d Prepare statements; want 1", prepares)
        }
@@ -388,13 +397,7 @@ func TestTxContextWait(t *testing.T) {
                t.Fatalf("expected QueryContext to error with context deadline exceeded but returned %v", err)
        }
 
-       var numFree int
-       if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
-               numFree = db.numFreeConns()
-               return numFree == 0
-       }) {
-               t.Fatalf("free conns after hitting EOF = %d; want 0", numFree)
-       }
+       waitForFree(t, db, 5*time.Second, 0)
 
        // Ensure the dropped connection allows more connections to be made.
        // Checked on DB Close.
@@ -471,9 +474,7 @@ func TestMultiResultSetQuery(t *testing.T) {
 
        // And verify that the final rows.Next() call, which hit EOF,
        // also closed the rows connection.
-       if n := db.numFreeConns(); n != 1 {
-               t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
-       }
+       waitForFree(t, db, 5*time.Second, 1)
        if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
                t.Errorf("executed %d Prepare statements; want 1", prepares)
        }
@@ -1135,6 +1136,24 @@ func TestQueryRowClosingStmt(t *testing.T) {
        }
 }
 
+var atomicRowsCloseHook atomic.Value // of func(*Rows, *error)
+
+func init() {
+       rowsCloseHook = func() func(*Rows, *error) {
+               fn, _ := atomicRowsCloseHook.Load().(func(*Rows, *error))
+               return fn
+       }
+}
+
+func setRowsCloseHook(fn func(*Rows, *error)) {
+       if fn == nil {
+               // Can't change an atomic.Value back to nil, so set it to this
+               // no-op func instead.
+               fn = func(*Rows, *error) {}
+       }
+       atomicRowsCloseHook.Store(fn)
+}
+
 // Test issue 6651
 func TestIssue6651(t *testing.T) {
        db := newTestDB(t, "people")
@@ -1147,6 +1166,7 @@ func TestIssue6651(t *testing.T) {
                return fmt.Errorf(want)
        }
        defer func() { rowsCursorNextHook = nil }()
+
        err := db.QueryRow("SELECT|people|name|").Scan(&v)
        if err == nil || err.Error() != want {
                t.Errorf("error = %q; want %q", err, want)
@@ -1154,10 +1174,10 @@ func TestIssue6651(t *testing.T) {
        rowsCursorNextHook = nil
 
        want = "error in rows.Close"
-       rowsCloseHook = func(rows *Rows, err *error) {
+       setRowsCloseHook(func(rows *Rows, err *error) {
                *err = fmt.Errorf(want)
-       }
-       defer func() { rowsCloseHook = nil }()
+       })
+       defer setRowsCloseHook(nil)
        err = db.QueryRow("SELECT|people|name|").Scan(&v)
        if err == nil || err.Error() != want {
                t.Errorf("error = %q; want %q", err, want)
@@ -1830,7 +1850,9 @@ func TestStmtCloseDeps(t *testing.T) {
                db.dumpDeps(t)
        }
 
-       if len(stmt.css) > nquery {
+       if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
+               return len(stmt.css) <= nquery
+       }) {
                t.Errorf("len(stmt.css) = %d; want <= %d", len(stmt.css), nquery)
        }
 
@@ -2576,10 +2598,10 @@ func TestIssue6081(t *testing.T) {
        if err != nil {
                t.Fatal(err)
        }
-       rowsCloseHook = func(rows *Rows, err *error) {
+       setRowsCloseHook(func(rows *Rows, err *error) {
                *err = driver.ErrBadConn
-       }
-       defer func() { rowsCloseHook = nil }()
+       })
+       defer setRowsCloseHook(nil)
        for i := 0; i < 10; i++ {
                rows, err := stmt.Query()
                if err != nil {
@@ -2642,7 +2664,10 @@ func TestIssue18429(t *testing.T) {
                        if err != nil {
                                return
                        }
-                       rows, err := tx.QueryContext(ctx, "WAIT|"+qwait+"|SELECT|people|name|")
+                       // This is expected to give a cancel error many, but not all the time.
+                       // Test failure will happen with a panic or other race condition being
+                       // reported.
+                       rows, _ := tx.QueryContext(ctx, "WAIT|"+qwait+"|SELECT|people|name|")
                        if rows != nil {
                                rows.Close()
                        }
@@ -2655,6 +2680,56 @@ func TestIssue18429(t *testing.T) {
        time.Sleep(milliWait * 3 * time.Millisecond)
 }
 
+// TestIssue18719 closes the context right before use. The sql.driverConn
+// will nil out the ci on close in a lock, but if another process uses it right after
+// it will panic with on the nil ref.
+//
+// See https://golang.org/cl/35550 .
+func TestIssue18719(t *testing.T) {
+       db := newTestDB(t, "people")
+       defer closeDB(t, db)
+
+       ctx, cancel := context.WithCancel(context.Background())
+       defer cancel()
+
+       tx, err := db.BeginTx(ctx, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       hookTxGrabConn = func() {
+               cancel()
+
+               // Wait for the context to cancel and tx to rollback.
+               for tx.isDone() == false {
+                       time.Sleep(time.Millisecond * 3)
+               }
+       }
+       defer func() { hookTxGrabConn = nil }()
+
+       // This call will grab the connection and cancel the context
+       // after it has done so. Code after must deal with the canceled state.
+       rows, err := tx.QueryContext(ctx, "SELECT|people|name|")
+       if err != nil {
+               rows.Close()
+               t.Fatalf("expected error %v but got %v", nil, err)
+       }
+
+       // Rows may be ignored because it will be closed when the context is canceled.
+
+       // Do not explicitly rollback. The rollback will happen from the
+       // canceled context.
+
+       // Wait for connections to return to pool.
+       var numOpen int
+       if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
+               numOpen = db.numOpenConns()
+               return numOpen == 0
+       }) {
+               t.Fatalf("open conns after hitting EOF = %d; want 0", numOpen)
+       }
+}
+
 func TestConcurrency(t *testing.T) {
        doConcurrentTest(t, new(concurrentDBQueryTest))
        doConcurrentTest(t, new(concurrentDBExecTest))
index 1ce5e2e84b5da1a7c4f9ee74666783c8a0add675..a400c7152a668a3e28e89ef9f18ff90d5357269a 100644 (file)
@@ -70,10 +70,8 @@ func (s *Scope) String() string {
 // 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
index ad8ba5378f3f13f7db193b5416bebb4439d0c18c..82e63100d4764d68516070e2e0e7fec2ac314011 100644 (file)
@@ -25,7 +25,7 @@ var files = flag.String("files", "", "consider only Go test files matching this
 
 const dataDir = "testdata"
 
-var templateTxt = readTemplate("template.txt")
+var templateTxt *template.Template
 
 func readTemplate(filename string) *template.Template {
        t := template.New(filename)
@@ -96,6 +96,9 @@ func test(t *testing.T, mode Mode) {
        if err != nil {
                t.Fatal(err)
        }
+       if templateTxt == nil {
+               templateTxt = readTemplate("template.txt")
+       }
 
        // test packages
        for _, pkg := range pkgs {
index f2732c0e2b18d142c121d98bf22de920f4b57eef..b2e1c11e9d538ed6c317e07740ce03c0d64f7866 100644 (file)
@@ -10,17 +10,12 @@ import (
        "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 {
index 5a408cd5710e580419569776f9043e9d0ea1bd93..08b8711c2d67c7cd8a599430ed58c49adf67fd97 100644 (file)
@@ -733,7 +733,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
 
        case *ast.FuncLit:
                p.expr(x.Type)
-               p.adjBlock(p.distanceFrom(x.Type.Pos()), blank, x.Body)
+               p.funcBody(p.distanceFrom(x.Type.Pos()), blank, x.Body)
 
        case *ast.ParenExpr:
                if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
@@ -825,6 +825,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
                if x.Type != nil {
                        p.expr1(x.Type, token.HighestPrec, depth)
                }
+               p.level++
                p.print(x.Lbrace, token.LBRACE)
                p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace)
                // do not insert extra line break following a /*-style comment
@@ -837,6 +838,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
                        mode |= noExtraBlank
                }
                p.print(mode, x.Rbrace, token.RBRACE, mode)
+               p.level--
 
        case *ast.Ellipsis:
                p.print(token.ELLIPSIS)
@@ -1560,18 +1562,23 @@ func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int {
        return bodySize
 }
 
-// adjBlock prints an "adjacent" block (e.g., a for-loop or function body) following
-// a header (e.g., a for-loop control clause or function signature) of given headerSize.
+// funcBody prints a function body following a function header of given headerSize.
 // If the header's and block's size are "small enough" and the block is "simple enough",
 // the block is printed on the current line, without line breaks, spaced from the header
 // by sep. Otherwise the block's opening "{" is printed on the current line, followed by
 // lines for the block's statements and its closing "}".
 //
-func (p *printer) adjBlock(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
+func (p *printer) funcBody(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
        if b == nil {
                return
        }
 
+       // save/restore composite literal nesting level
+       defer func(level int) {
+               p.level = level
+       }(p.level)
+       p.level = 0
+
        const maxSize = 100
        if headerSize+p.bodySize(b, maxSize) <= maxSize {
                p.print(sep, b.Lbrace, token.LBRACE)
@@ -1616,7 +1623,7 @@ func (p *printer) funcDecl(d *ast.FuncDecl) {
        }
        p.expr(d.Name)
        p.signature(d.Type.Params, d.Type.Results)
-       p.adjBlock(p.distanceFrom(d.Pos()), vtab, d.Body)
+       p.funcBody(p.distanceFrom(d.Pos()), vtab, d.Body)
 }
 
 func (p *printer) decl(decl ast.Decl) {
index eabf23e8b28691ec975c0fdcb5aee2584081f893..be61dad590eea02012364ae32c9c602d256f9c11 100644 (file)
@@ -58,6 +58,7 @@ type printer struct {
        // Current state
        output      []byte       // raw printer result
        indent      int          // current indentation
+       level       int          // level == 0: outside composite literal; level > 0: inside composite literal
        mode        pmode        // current printer mode
        impliedSemi bool         // if set, a linebreak implies a semicolon
        lastTok     token.Token  // last token printed (token.ILLEGAL if it's whitespace)
@@ -744,15 +745,19 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro
                // follows on the same line but is not a comma, and not a "closing"
                // token immediately following its corresponding "opening" token,
                // add an extra separator unless explicitly disabled. Use a blank
-               // as separator unless we have pending linebreaks and they are not
-               // disabled, in which case we want a linebreak (issue 15137).
+               // as separator unless we have pending linebreaks, they are not
+               // disabled, and we are outside a composite literal, in which case
+               // we want a linebreak (issue 15137).
+               // TODO(gri) This has become overly complicated. We should be able
+               // to track whether we're inside an expression or statement and
+               // use that information to decide more directly.
                needsLinebreak := false
                if p.mode&noExtraBlank == 0 &&
                        last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line &&
                        tok != token.COMMA &&
                        (tok != token.RPAREN || p.prevOpen == token.LPAREN) &&
                        (tok != token.RBRACK || p.prevOpen == token.LBRACK) {
-                       if p.containsLinebreak() && p.mode&noExtraLinebreak == 0 {
+                       if p.containsLinebreak() && p.mode&noExtraLinebreak == 0 && p.level == 0 {
                                needsLinebreak = true
                        } else {
                                p.writeByte(' ', 1)
index 7676a26c1259eec0a56ca1a3c2930bc593f86de6..8b3a94ddcd03a0ac75ab7e6c2bbfa5dbb88c2b95 100644 (file)
@@ -103,3 +103,62 @@ label:
        mask := uint64(1)<<c - 1                // Allocation mask
        used := atomic.LoadUint64(&h.used)      // Current allocations
 }
+
+// Test cases for issue 18782
+var _ = [][]int{
+       /*       a, b, c, d, e */
+       /* a */ {0, 0, 0, 0, 0},
+       /* b */ {0, 5, 4, 4, 4},
+       /* c */ {0, 4, 5, 4, 4},
+       /* d */ {0, 4, 4, 5, 4},
+       /* e */ {0, 4, 4, 4, 5},
+}
+
+var _ = T{ /* a */ 0}
+
+var _ = T{ /* a */ /* b */ 0}
+
+var _ = T{     /* a */ /* b */
+       /* c */ 0,
+}
+
+var _ = T{     /* a */ /* b */
+       /* c */
+       /* d */ 0,
+}
+
+var _ = T{
+       /* a */
+       /* b */ 0,
+}
+
+var _ = T{ /* a */ {}}
+
+var _ = T{ /* a */ /* b */ {}}
+
+var _ = T{     /* a */ /* b */
+       /* c */ {},
+}
+
+var _ = T{     /* a */ /* b */
+       /* c */
+       /* d */ {},
+}
+
+var _ = T{
+       /* a */
+       /* b */ {},
+}
+
+var _ = []T{
+       func() {
+               var _ = [][]int{
+                       /*       a, b, c, d, e */
+                       /* a */ {0, 0, 0, 0, 0},
+                       /* b */ {0, 5, 4, 4, 4},
+                       /* c */ {0, 4, 5, 4, 4},
+                       /* d */ {0, 4, 4, 5, 4},
+                       /* e */ {0, 4, 4, 4, 5},
+               }
+       },
+}
index 4a055c82772886a0b2ea165d7b2abc987e458235..8d38c4194bbcd73e3ba0f58d59775edfa09b6501 100644 (file)
@@ -103,3 +103,66 @@ label:
    mask := uint64(1)<<c - 1 // Allocation mask
    used := atomic.LoadUint64(&h.used) // Current allocations
 }
+
+// Test cases for issue 18782
+var _ = [][]int{
+   /*       a, b, c, d, e */
+   /* a */ {0, 0, 0, 0, 0},
+   /* b */ {0, 5, 4, 4, 4},
+   /* c */ {0, 4, 5, 4, 4},
+   /* d */ {0, 4, 4, 5, 4},
+   /* e */ {0, 4, 4, 4, 5},
+}
+
+var _ = T{ /* a */ 0,
+}
+
+var _ = T{ /* a */ /* b */ 0,
+}
+
+var _ = T{ /* a */ /* b */
+   /* c */ 0,
+}
+
+var _ = T{ /* a */ /* b */
+   /* c */
+   /* d */ 0,
+}
+
+var _ = T{
+   /* a */
+   /* b */ 0,
+}
+
+var _ = T{ /* a */ {},
+}
+
+var _ = T{ /* a */ /* b */ {},
+}
+
+var _ = T{ /* a */ /* b */
+   /* c */ {},
+}
+
+var _ = T{ /* a */ /* b */
+   /* c */
+   /* d */ {},
+}
+
+var _ = T{
+   /* a */
+   /* b */ {},
+}
+
+var _ = []T{
+   func() {
+      var _ = [][]int{
+         /*       a, b, c, d, e */
+         /* a */ {0, 0, 0, 0, 0},
+         /* b */ {0, 5, 4, 4, 4},
+         /* c */ {0, 4, 5, 4, 4},
+         /* d */ {0, 4, 4, 5, 4},
+         /* e */ {0, 4, 4, 4, 5},
+      }
+   },
+}
index 1c6d7b5299309738d7a9e523ca4278a08151006e..06d2c93dda3edff3945ddd25a2abb3ab06896eb8 100644 (file)
@@ -157,6 +157,7 @@ func TestStdFixed(t *testing.T) {
                "issue11362.go", // canonical import path check
                "issue15002.go", // uses Mmap; testTestDir should consult build tags
                "issue16369.go", // go/types handles this correctly - not an issue
+               "issue18459.go", // go/types doesn't check validity of //go:xxx directives
        )
 }
 
index 7eb87c6d10d8ccd69b70a1fe7710328128e9d187..0005538e70bd80ba432489360d1fea76dd62a4df 100644 (file)
@@ -413,19 +413,28 @@ func (c *Client) checkRedirect(req *Request, via []*Request) error {
 
 // redirectBehavior describes what should happen when the
 // client encounters a 3xx status code from the server
-func redirectBehavior(reqMethod string, resp *Response, via []*Request) (redirectMethod string, shouldRedirect bool) {
+func redirectBehavior(reqMethod string, resp *Response, ireq *Request) (redirectMethod string, shouldRedirect, includeBody bool) {
        switch resp.StatusCode {
        case 301, 302, 303:
-               redirectMethod = "GET"
+               redirectMethod = reqMethod
                shouldRedirect = true
+               includeBody = false
+
+               // RFC 2616 allowed automatic redirection only with GET and
+               // HEAD requests. RFC 7231 lifts this restriction, but we still
+               // restrict other methods to GET to maintain compatibility.
+               // See Issue 18570.
+               if reqMethod != "GET" && reqMethod != "HEAD" {
+                       redirectMethod = "GET"
+               }
        case 307, 308:
                redirectMethod = reqMethod
                shouldRedirect = true
+               includeBody = true
 
                // Treat 307 and 308 specially, since they're new in
                // Go 1.8, and they also require re-sending the request body.
-               loc := resp.Header.Get("Location")
-               if loc == "" {
+               if resp.Header.Get("Location") == "" {
                        // 308s have been observed in the wild being served
                        // without Location headers. Since Go 1.7 and earlier
                        // didn't follow these codes, just stop here instead
@@ -434,7 +443,6 @@ func redirectBehavior(reqMethod string, resp *Response, via []*Request) (redirec
                        shouldRedirect = false
                        break
                }
-               ireq := via[0]
                if ireq.GetBody == nil && ireq.outgoingLength() != 0 {
                        // We had a request body, and 307/308 require
                        // re-sending it, but GetBody is not defined. So just
@@ -443,8 +451,7 @@ func redirectBehavior(reqMethod string, resp *Response, via []*Request) (redirec
                        shouldRedirect = false
                }
        }
-
-       return redirectMethod, shouldRedirect
+       return redirectMethod, shouldRedirect, includeBody
 }
 
 // Do sends an HTTP request and returns an HTTP response, following
@@ -474,7 +481,8 @@ func redirectBehavior(reqMethod string, resp *Response, via []*Request) (redirec
 // If the server replies with a redirect, the Client first uses the
 // CheckRedirect function to determine whether the redirect should be
 // followed. If permitted, a 301, 302, or 303 redirect causes
-// subsequent requests to use HTTP method "GET", with no body.
+// subsequent requests to use HTTP method GET
+// (or HEAD if the original request was HEAD), with no body.
 // A 307 or 308 redirect preserves the original HTTP method and body,
 // provided that the Request.GetBody function is defined.
 // The NewRequest function automatically sets GetBody for common
@@ -486,11 +494,14 @@ func (c *Client) Do(req *Request) (*Response, error) {
        }
 
        var (
-               deadline       = c.deadline()
-               reqs           []*Request
-               resp           *Response
-               copyHeaders    = c.makeHeadersCopier(req)
+               deadline    = c.deadline()
+               reqs        []*Request
+               resp        *Response
+               copyHeaders = c.makeHeadersCopier(req)
+
+               // Redirect behavior:
                redirectMethod string
+               includeBody    bool
        )
        uerr := func(err error) error {
                req.closeBody()
@@ -528,7 +539,7 @@ func (c *Client) Do(req *Request) (*Response, error) {
                                Cancel:   ireq.Cancel,
                                ctx:      ireq.ctx,
                        }
-                       if ireq.GetBody != nil {
+                       if includeBody && ireq.GetBody != nil {
                                req.Body, err = ireq.GetBody()
                                if err != nil {
                                        return nil, uerr(err)
@@ -592,7 +603,7 @@ func (c *Client) Do(req *Request) (*Response, error) {
                }
 
                var shouldRedirect bool
-               redirectMethod, shouldRedirect = redirectBehavior(req.Method, resp, reqs)
+               redirectMethod, shouldRedirect, includeBody = redirectBehavior(req.Method, resp, reqs[0])
                if !shouldRedirect {
                        return resp, nil
                }
index ca6e9180f1c7d84ec8343d7bba571856a11f57f1..4f674dd8d6c785ca45b06781f2b2a247344db6ce 100644 (file)
@@ -360,25 +360,25 @@ func TestPostRedirects(t *testing.T) {
        wantSegments := []string{
                `POST / "first"`,
                `POST /?code=301&next=302 "c301"`,
-               `GET /?code=302 "c301"`,
-               `GET / "c301"`,
+               `GET /?code=302 ""`,
+               `GET / ""`,
                `POST /?code=302&next=302 "c302"`,
-               `GET /?code=302 "c302"`,
-               `GET / "c302"`,
+               `GET /?code=302 ""`,
+               `GET / ""`,
                `POST /?code=303&next=301 "c303wc301"`,
-               `GET /?code=301 "c303wc301"`,
-               `GET / "c303wc301"`,
+               `GET /?code=301 ""`,
+               `GET / ""`,
                `POST /?code=304 "c304"`,
                `POST /?code=305 "c305"`,
                `POST /?code=307&next=303,308,302 "c307"`,
                `POST /?code=303&next=308,302 "c307"`,
-               `GET /?code=308&next=302 "c307"`,
+               `GET /?code=308&next=302 ""`,
                `GET /?code=302 "c307"`,
-               `GET / "c307"`,
+               `GET / ""`,
                `POST /?code=308&next=302,301 "c308"`,
                `POST /?code=302&next=301 "c308"`,
-               `GET /?code=301 "c308"`,
-               `GET / "c308"`,
+               `GET /?code=301 ""`,
+               `GET / ""`,
                `POST /?code=404 "c404"`,
        }
        want := strings.Join(wantSegments, "\n")
@@ -399,20 +399,20 @@ func TestDeleteRedirects(t *testing.T) {
        wantSegments := []string{
                `DELETE / "first"`,
                `DELETE /?code=301&next=302,308 "c301"`,
-               `GET /?code=302&next=308 "c301"`,
-               `GET /?code=308 "c301"`,
+               `GET /?code=302&next=308 ""`,
+               `GET /?code=308 ""`,
                `GET / "c301"`,
                `DELETE /?code=302&next=302 "c302"`,
-               `GET /?code=302 "c302"`,
-               `GET / "c302"`,
+               `GET /?code=302 ""`,
+               `GET / ""`,
                `DELETE /?code=303 "c303"`,
-               `GET / "c303"`,
+               `GET / ""`,
                `DELETE /?code=307&next=301,308,303,302,304 "c307"`,
                `DELETE /?code=301&next=308,303,302,304 "c307"`,
-               `GET /?code=308&next=303,302,304 "c307"`,
+               `GET /?code=308&next=303,302,304 ""`,
                `GET /?code=303&next=302,304 "c307"`,
-               `GET /?code=302&next=304 "c307"`,
-               `GET /?code=304 "c307"`,
+               `GET /?code=302&next=304 ""`,
+               `GET /?code=304 ""`,
                `DELETE /?code=308&next=307 "c308"`,
                `DELETE /?code=307 "c308"`,
                `DELETE / "c308"`,
@@ -432,7 +432,11 @@ func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, wa
        ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
                log.Lock()
                slurp, _ := ioutil.ReadAll(r.Body)
-               fmt.Fprintf(&log.Buffer, "%s %s %q\n", r.Method, r.RequestURI, slurp)
+               fmt.Fprintf(&log.Buffer, "%s %s %q", r.Method, r.RequestURI, slurp)
+               if cl := r.Header.Get("Content-Length"); r.Method == "GET" && len(slurp) == 0 && (r.ContentLength != 0 || cl != "") {
+                       fmt.Fprintf(&log.Buffer, " (but with body=%T, content-length = %v, %q)", r.Body, r.ContentLength, cl)
+               }
+               log.WriteByte('\n')
                log.Unlock()
                urlQuery := r.URL.Query()
                if v := urlQuery.Get("code"); v != "" {
@@ -475,7 +479,24 @@ func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, wa
        want = strings.TrimSpace(want)
 
        if got != want {
-               t.Errorf("Log differs.\n Got:\n%s\nWant:\n%s\n", got, want)
+               got, want, lines := removeCommonLines(got, want)
+               t.Errorf("Log differs after %d common lines.\n\nGot:\n%s\n\nWant:\n%s\n", lines, got, want)
+       }
+}
+
+func removeCommonLines(a, b string) (asuffix, bsuffix string, commonLines int) {
+       for {
+               nl := strings.IndexByte(a, '\n')
+               if nl < 0 {
+                       return a, b, commonLines
+               }
+               line := a[:nl+1]
+               if !strings.HasPrefix(b, line) {
+                       return a, b, commonLines
+               }
+               commonLines++
+               a = a[len(line):]
+               b = b[len(line):]
        }
 }
 
@@ -1665,9 +1686,9 @@ func TestClientRedirectTypes(t *testing.T) {
                3: {method: "POST", serverStatus: 307, wantMethod: "POST"},
                4: {method: "POST", serverStatus: 308, wantMethod: "POST"},
 
-               5: {method: "HEAD", serverStatus: 301, wantMethod: "GET"},
-               6: {method: "HEAD", serverStatus: 302, wantMethod: "GET"},
-               7: {method: "HEAD", serverStatus: 303, wantMethod: "GET"},
+               5: {method: "HEAD", serverStatus: 301, wantMethod: "HEAD"},
+               6: {method: "HEAD", serverStatus: 302, wantMethod: "HEAD"},
+               7: {method: "HEAD", serverStatus: 303, wantMethod: "HEAD"},
                8: {method: "HEAD", serverStatus: 307, wantMethod: "HEAD"},
                9: {method: "HEAD", serverStatus: 308, wantMethod: "HEAD"},
 
index 072da2552bc5d06d8e109657d0ddfd9c19ad1fec..73dd56e8c426562c966aaf56954a06b4655e9517 100644 (file)
@@ -5173,3 +5173,142 @@ func TestServerDuplicateBackgroundRead(t *testing.T) {
        }
        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.Errorf("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")
+       }
+}
index 96236489bd9faf0e404a01aed92bafcab19ee33f..df70a15193bc6adb0127f250d4c2e3edb033e6e2 100644 (file)
@@ -164,7 +164,7 @@ type Flusher interface {
 // 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 @@ type Hijacker interface {
        // 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 @@ func (c *conn) hijackLocked() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
        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
 }
index d5ddf6a1232a019e97d1d48f9f423d58d8af7dc0..a58b1839cc6e09e30d5f1a975a6f8394008dae98 100644 (file)
@@ -36,6 +36,7 @@ import (
        "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 @@ func (f closerFunc) Close() error { return f() }
 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 < 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
-                       }()
+       for i := 0; i < 3; i++ {
+               res, err := c.Get("http://fake.golang/")
+               if err != nil {
+                       t.Fatalf("i=%d: Get = %v", i, 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
index b7300cd38c468243959ff271b65a8c9222c07d2d..7ad9aac70e25101ffca31b7a7ba4cad98cd166c8 100644 (file)
@@ -54,12 +54,15 @@ var sysdir = func() *sysDir {
        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",
index 1fed972eeafcd72c57a5544cfcedd72ab9bd5bff..0be306dc5418e52ff65c57d8fbf072a43210654d 100644 (file)
@@ -26,6 +26,8 @@ import (
        "unsafe"
 )
 
+var sink interface{}
+
 func TestBool(t *testing.T) {
        v := ValueOf(true)
        if v.Bool() != true {
@@ -5338,6 +5340,72 @@ func TestCallGC(t *testing.T) {
        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 {
        rcvr, t                  Type
        size, argsize, retOffset uintptr
index a1bfb6d489976c1505cc283e8012741576c5104b..1abfbe6f65029d2f83b2498579213a3b6b7d156c 100644 (file)
@@ -538,6 +538,11 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
                        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 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
        // 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.
index 464f5fdc1b48b549030f885cb203291c92b2890c..c2286d3edd241ca1801565745d9829110677c432 100644 (file)
@@ -146,10 +146,16 @@ move_1or2:
 move_0:
        RET
 move_3or4:
+       CMPQ    BX, $4
+       JB      move_3
+       MOVL    (SI), AX
+       MOVL    AX, (DI)
+       RET
+move_3:
        MOVW    (SI), AX
-       MOVW    -2(SI)(BX*1), CX
+       MOVB    2(SI), CX
        MOVW    AX, (DI)
-       MOVW    CX, -2(DI)(BX*1)
+       MOVB    CX, 2(DI)
        RET
 move_5through7:
        MOVL    (SI), AX
index dbfa284c28bc6020592b2d33afdc8207d7fef4a1..74b8753b5f78f4f22f53346c2ce0b3f9113f2980 100644 (file)
@@ -6,6 +6,7 @@ package runtime_test
 
 import (
        "crypto/rand"
+       "encoding/binary"
        "fmt"
        "internal/race"
        . "runtime"
@@ -447,3 +448,22 @@ func BenchmarkCopyFat1024(b *testing.B) {
                _ = y
        }
 }
+
+func BenchmarkIssue18740(b *testing.B) {
+       // This tests that memmove uses one 4-byte load/store to move 4 bytes.
+       // It used to do 2 2-byte load/stores, which leads to a pipeline stall
+       // when we try to read the result with one 4-byte load.
+       var buf [4]byte
+       for j := 0; j < b.N; j++ {
+               s := uint32(0)
+               for i := 0; i < 4096; i += 4 {
+                       copy(buf[:], g[i:])
+                       s += binary.LittleEndian.Uint32(buf[:])
+               }
+               sink = uint64(s)
+       }
+}
+
+// TODO: 2 byte and 8 byte benchmarks also.
+
+var g [4096]byte
index 64a2f3abef863d7f01b3184003ad1993db35146e..0b996d895080c9ba73bcab3666e5447ff96928a5 100644 (file)
@@ -1129,8 +1129,6 @@ top:
                // 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
 
@@ -1153,6 +1151,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)
index e74a451d0d44f7b8f69df6a58f61113a70f0f99a..fb5c488ffc37ed87e22ac91c569928842dd3940c 100644 (file)
@@ -405,7 +405,10 @@ func reimburseSweepCredit(unusableBytes uintptr) {
                // Nobody cares about the credit. Avoid the atomic.
                return
        }
-       if int64(atomic.Xadd64(&mheap_.spanBytesAlloc, -int64(unusableBytes))) < 0 {
+       nval := atomic.Xadd64(&mheap_.spanBytesAlloc, -int64(unusableBytes))
+       if int64(nval) < 0 {
+               // Debugging for #18043.
+               print("runtime: bad spanBytesAlloc=", nval, " (was ", nval+uint64(unusableBytes), ") unusableBytes=", unusableBytes, " sweepPagesPerByte=", mheap_.sweepPagesPerByte, "\n")
                throw("spanBytesAlloc underflow")
        }
 }
index 7177c8e611b5dfdeff286b892b7f8a85e192c1c5..c0f3957e2891e3dadb514ef5c673bd15f64ead8c 100644 (file)
@@ -28,9 +28,11 @@ const msanenabled = true
 // the runtime, but operations like a slice copy can call msanread
 // anyhow for values on the stack. Just ignore msanread when running
 // on the system stack. The other msan functions are fine.
+//
+//go:nosplit
 func msanread(addr unsafe.Pointer, sz uintptr) {
        g := getg()
-       if g == g.m.g0 || g == g.m.gsignal {
+       if g == nil || g.m == nil || g == g.m.g0 || g == g.m.gsignal {
                return
        }
        domsanread(addr, sz)
index 80869e1b1c1a5cb69502d26ee2b11ec323f7c9e7..8edb29c9fea5604febd823da1667b50f4531057b 100644 (file)
@@ -56,7 +56,9 @@ func plugin_lastmoduleinit() (path string, syms map[string]interface{}, mismatch
 
        lock(&ifaceLock)
        for _, i := range md.itablinks {
-               additab(i, true, false)
+               if i.inhash == 0 {
+                       additab(i, true, false)
+               }
        }
        unlock(&ifaceLock)
 
index 756ce63c2421f13fcf19e0b1e5fdf50400fb15d7..f41672de73a67876b036f6a89068152c8cdf0742 100644 (file)
@@ -240,6 +240,16 @@ func Gosched() {
        mcall(gosched_m)
 }
 
+var alwaysFalse bool
+
+// goschedguarded does nothing, but is written in a way that guarantees a preemption check in its prologue.
+// Calls to this function are inserted by the compiler in otherwise uninterruptible loops (see insertLoopReschedChecks).
+func goschedguarded() {
+       if alwaysFalse {
+               goschedguarded()
+       }
+}
+
 // Puts the current goroutine into a waiting state and calls unlockf.
 // If unlockf returns false, the goroutine is resumed.
 // unlockf must not access this G's stack, as it may be moved between
index c2844375f7ac98472e64a8c9f47ccdf85b6fb5a2..f886961d6ad3dad94e7f2ac1d613cd75c092a79f 100644 (file)
@@ -7,6 +7,7 @@ package runtime_test
 import (
        "bytes"
        "fmt"
+       "go/build"
        "internal/testenv"
        "io/ioutil"
        "os"
@@ -67,7 +68,6 @@ func checkGdbPython(t *testing.T) {
 }
 
 const helloSource = `
-package main
 import "fmt"
 var gslice []string
 func main() {
@@ -85,9 +85,20 @@ func main() {
 `
 
 func TestGdbPython(t *testing.T) {
+       testGdbPython(t, false)
+}
+
+func TestGdbPythonCgo(t *testing.T) {
+       testGdbPython(t, true)
+}
+
+func testGdbPython(t *testing.T, cgo bool) {
        if runtime.GOARCH == "mips64" {
                testenv.SkipFlaky(t, 18173)
        }
+       if cgo && !build.Default.CgoEnabled {
+               t.Skip("skipping because cgo is not enabled")
+       }
 
        t.Parallel()
        checkGdbEnvironment(t)
@@ -100,8 +111,15 @@ func TestGdbPython(t *testing.T) {
        }
        defer os.RemoveAll(dir)
 
+       var buf bytes.Buffer
+       buf.WriteString("package main\n")
+       if cgo {
+               buf.WriteString(`import "C"` + "\n")
+       }
+       buf.WriteString(helloSource)
+
        src := filepath.Join(dir, "main.go")
-       err = ioutil.WriteFile(src, []byte(helloSource), 0644)
+       err = ioutil.WriteFile(src, buf.Bytes(), 0644)
        if err != nil {
                t.Fatalf("failed to create file: %v", err)
        }
index f52190661cee83ee80e69eddb2fba1d775101a45..ed82783ca969f328c2ec11ad0e1ffd35710b2203 100644 (file)
@@ -285,6 +285,25 @@ func modulesinit() {
                        md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), md.ebss-md.bss)
                }
        }
+
+       // Modules appear in the moduledata linked list in the order they are
+       // loaded by the dynamic loader, with one exception: the
+       // firstmoduledata itself the module that contains the runtime. This
+       // is not always the first module (when using -buildmode=shared, it
+       // is typically libstd.so, the second module). The order matters for
+       // typelinksinit, so we swap the first module with whatever module
+       // contains the main function.
+       //
+       // See Issue #18729.
+       mainText := funcPC(main_main)
+       for i, md := range *modules {
+               if md.text <= mainText && mainText <= md.etext {
+                       (*modules)[0] = md
+                       (*modules)[i] = &firstmoduledata
+                       break
+               }
+       }
+
        atomicstorep(unsafe.Pointer(&modulesSlice), unsafe.Pointer(modules))
 }
 
index 839df164068f0c302cf4329ea956ce53c343893c..6ddcb30ae204ddfa5e2f639cf4968646c44c223a 100644 (file)
@@ -330,9 +330,9 @@ sigtrampnog:
        // 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.
index 44afb91d96f1a252f3f87f1771200697c008f110..3da82961b9b74a21d5fe6da480e55d38a91180bf 100644 (file)
@@ -61,7 +61,7 @@ static void* cpuHogDriver(void* arg __attribute__ ((unused))) {
        return 0;
 }
 
-void runCPUHogThread() {
+void runCPUHogThread(void) {
        pthread_t tid;
        pthread_create(&tid, 0, cpuHogDriver, 0);
 }
index e8b0a04556a0f135f22e8ac9597d2fb96930101f..2a023f66caeb74f49933e2f9111b20beac3faa69 100644 (file)
@@ -15,16 +15,16 @@ package main
 
 char *p;
 
-static int f3() {
+static int f3(void) {
        *p = 0;
        return 0;
 }
 
-static int f2() {
+static int f2(void) {
        return f3();
 }
 
-static int f1() {
+static int f1(void) {
        return f2();
 }
 
index 26aeec843f1599bf144259899b33d012561697e4..e75ba1502a94aadd8d461e9fe077efa3b56e500d 100644 (file)
@@ -18,6 +18,7 @@ import (
        "log"
        "os"
        "regexp"
+       "strings"
 )
 
 func main() {
@@ -38,10 +39,16 @@ func main() {
                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.
                re = regexp.MustCompile("(Data\\s+\\[14\\])uint8")
index cdde47863f7d584eebf9b84c321424908d3c5fa3..63c4a83b19cfe6efaf813818dc7da36a50701ad0 100644 (file)
@@ -140,7 +140,7 @@ type Dirent struct {
 }
 
 type Fsid struct {
-       _ [2]int32
+       X__val [2]int32
 }
 
 type Flock_t struct {
index c033ce5fecb1286965089adde2a4919ff2a4da84..bcebb418c42572e1c26aa3427926667c596adf5b 100644 (file)
@@ -219,7 +219,7 @@ func (b *B) run1() bool {
        }
        // 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 @@ func (ctx *benchContext) processBench(b *B) {
 //
 // 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()
 
index 8d5d9206f03563633e457afceb37b035d861f2cc..bb7b3e09255ea167de3001248b55c83e20b21109 100644 (file)
@@ -6,6 +6,7 @@ package testing
 
 import (
        "bytes"
+       "fmt"
        "regexp"
        "strings"
        "sync/atomic"
@@ -515,3 +516,19 @@ func TestBenchmarkOutput(t *T) {
        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
+       }
+}
index c972b2737f28d80692e2e8a18f27a7fc53350615..bd19a31c27c85ad61e3e378d00641ec615accf21 100644 (file)
@@ -216,6 +216,7 @@ import (
        "strconv"
        "strings"
        "sync"
+       "sync/atomic"
        "time"
 )
 
@@ -267,8 +268,8 @@ type common struct {
        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 @@ func tRunner(t *T, fn func(t *T)) {
                // 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 @@ func tRunner(t *T, fn func(t *T)) {
 
 // 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
@@ -817,6 +821,7 @@ func (m *M) Run() int {
        haveExamples = len(m.examples) > 0
        testRan, testOk := runTests(m.deps.MatchString, m.tests)
        exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
+       stopAlarm()
        if !testRan && !exampleRan && *matchBenchmarks == "" {
                fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
        }
index bc75c61afcf6a7dd43b529396c65f469676fcef7..2edae63828a5f0d3efa73585d3882a31c3f4343c 100644 (file)
@@ -54,9 +54,9 @@
        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 @@ TEXT ·poly1305(SB), $0-32
 
        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
index 93167b27129c103620ee72bd4be9adfb9209ce5a..f70b4ac484518ba4a6e16009a769b0472e902bc1 100644 (file)
@@ -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 @@ TEXT poly1305_init_ext_armv6<>(SB), NOSPLIT, $0
        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/issue10958.go b/test/fixedbugs/issue10958.go
new file mode 100644 (file)
index 0000000..86d2057
--- /dev/null
@@ -0,0 +1,95 @@
+// +build !nacl,disabled
+// buildrun -t 10  -gcflags=-d=ssa/insert_resched_checks/on,ssa/check/on
+
+// 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.
+
+// Test is disabled because it flakes when run in all.bash
+// on some platforms, but is useful standalone to verify
+// that rescheduling checks are working (and we may wish
+// to investigate the flake, since it suggests that the
+// loop rescheduling check may not work right on those
+// platforms).
+
+// This checks to see that call-free infinite loops do not
+// block garbage collection.  IF YOU RUN IT STANDALONE without
+// -gcflags=-d=ssa/insert_resched_checks/on in a not-experimental
+// build, it should hang.
+
+package main
+
+import (
+       "runtime"
+)
+
+var someglobal1 int
+var someglobal2 int
+var someglobal3 int
+
+//go:noinline
+func f() {}
+
+func standinacorner1() {
+       for someglobal1&1 == 0 {
+               someglobal1++
+               someglobal1++
+       }
+}
+
+func standinacorner2(i int) {
+       // contains an irreducible loop containing changes to memory
+       if i != 0 {
+               goto midloop
+       }
+
+loop:
+       if someglobal2&1 != 0 {
+               goto done
+       }
+       someglobal2++
+midloop:
+       someglobal2++
+       goto loop
+
+done:
+       return
+}
+
+func standinacorner3() {
+       for someglobal3&1 == 0 {
+               if someglobal3&2 != 0 {
+                       for someglobal3&3 == 2 {
+                               someglobal3++
+                               someglobal3++
+                               someglobal3++
+                               someglobal3++
+                       }
+               }
+               someglobal3++
+               someglobal3++
+               someglobal3++
+               someglobal3++
+       }
+}
+
+func main() {
+       go standinacorner1()
+       go standinacorner2(0)
+       go standinacorner3()
+       // println("About to stand in a corner1")
+       for someglobal1 == 0 {
+               runtime.Gosched()
+       }
+       // println("About to stand in a corner2")
+       for someglobal2 == 0 {
+               runtime.Gosched()
+       }
+       // println("About to stand in a corner3")
+       for someglobal3 == 0 {
+               runtime.Gosched()
+       }
+       // println("About to GC")
+       runtime.GC()
+       // println("Success")
+}
diff --git a/test/fixedbugs/issue18459.go b/test/fixedbugs/issue18459.go
new file mode 100644 (file)
index 0000000..ac07661
--- /dev/null
@@ -0,0 +1,13 @@
+// errorcheck
+
+// 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.
+
+// Verify that we have a line number for this error.
+
+package main
+
+//go:nowritebarrier // ERROR "go:nowritebarrier only allowed in runtime"
+func main() {
+}
diff --git a/test/fixedbugs/issue18661.go b/test/fixedbugs/issue18661.go
new file mode 100644 (file)
index 0000000..8c83775
--- /dev/null
@@ -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 }{} {
+       }
+}
diff --git a/test/fixedbugs/issue18725.go b/test/fixedbugs/issue18725.go
new file mode 100644 (file)
index 0000000..c632dba
--- /dev/null
@@ -0,0 +1,24 @@
+// run
+
+// 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 "os"
+
+func panicWhenNot(cond bool) {
+       if cond {
+               os.Exit(0)
+       } else {
+               panic("nilcheck elim failed")
+       }
+}
+
+func main() {
+       e := (*string)(nil)
+       panicWhenNot(e == e)
+       // Should never reach this line.
+       panicWhenNot(*e == *e)
+}
diff --git a/test/fixedbugs/issue18808.go b/test/fixedbugs/issue18808.go
new file mode 100644 (file)
index 0000000..c98386e
--- /dev/null
@@ -0,0 +1,63 @@
+// run
+
+// 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
+
+const lim = 0x80000000
+
+//go:noinline
+func eq(x uint32) {
+       if x == lim {
+               return
+       }
+       panic("x == lim returned false")
+}
+
+//go:noinline
+func neq(x uint32) {
+       if x != lim {
+               panic("x != lim returned true")
+       }
+}
+
+//go:noinline
+func gt(x uint32) {
+       if x > lim {
+               return
+       }
+       panic("x > lim returned false")
+}
+
+//go:noinline
+func gte(x uint32) {
+       if x >= lim {
+               return
+       }
+       panic("x >= lim returned false")
+}
+
+//go:noinline
+func lt(x uint32) {
+       if x < lim {
+               panic("x < lim returned true")
+       }
+}
+
+//go:noinline
+func lte(x uint32) {
+       if x <= lim {
+               panic("x <= lim returned true")
+       }
+}
+
+func main() {
+       eq(lim)
+       neq(lim)
+       gt(lim+1)
+       gte(lim+1)
+       lt(lim+1)
+       lte(lim+1)
+}
index 4fb231cfef9df5838471690da26a1f45ac489232..b23e1509e01da640e33a0023dd41817e02f2116d 100644 (file)
@@ -1,6 +1,7 @@
-// errorcheckwithauto -0 -l -live -wb=0
+// errorcheckwithauto -0 -l -live -wb=0 -d=ssa/insert_resched_checks/off
 // +build !ppc64,!ppc64le
 // ppc64 needs a better tighten pass to make f18 pass
+// rescheduling checks need to be turned off because there are some live variables across the inserted check call
 
 // Copyright 2014 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index 8fdae8c075f0651243b99f3b06f07a0847154425..c681cba50c4cf1ce93c0c1fa278cd8c4a933d316 100644 (file)
@@ -40,23 +40,23 @@ var (
 )
 
 func f1() {
-       _ = *intp // ERROR "generated nil check"
+       _ = *intp // ERROR "removed nil check"
 
        // This one should be removed but the block copy needs
        // to be turned into its own pseudo-op in order to see
        // the indirect.
-       _ = *arrayp // ERROR "generated nil check"
+       _ = *arrayp // ERROR "removed nil check"
 
        // 0-byte indirect doesn't suffice.
        // we don't registerize globals, so there are no removed.* nil checks.
-       _ = *array0p // ERROR "generated nil check"
        _ = *array0p // ERROR "removed nil check"
+       _ = *array0p // ERROR "generated nil check"
 
-       _ = *intp    // ERROR "removed nil check"
+       _ = *intp    // ERROR "generated nil check"
        _ = *arrayp  // ERROR "removed nil check"
        _ = *structp // ERROR "generated nil check"
        _ = *emptyp  // ERROR "generated nil check"
-       _ = *arrayp  // ERROR "removed nil check"
+       _ = *arrayp  // ERROR "generated nil check"
 }
 
 func f2() {
@@ -71,15 +71,15 @@ func f2() {
                empty1p    *Empty1
        )
 
-       _ = *intp       // ERROR "generated nil check"
-       _ = *arrayp     // ERROR "generated nil check"
-       _ = *array0p    // ERROR "generated nil check"
-       _ = *array0p    // ERROR "removed.* nil check"
        _ = *intp       // ERROR "removed.* nil check"
        _ = *arrayp     // ERROR "removed.* nil check"
+       _ = *array0p    // ERROR "removed.* nil check"
+       _ = *array0p    // ERROR "generated nil check"
+       _ = *intp       // ERROR "generated nil check"
+       _ = *arrayp     // ERROR "removed.* nil check"
        _ = *structp    // ERROR "generated nil check"
        _ = *emptyp     // ERROR "generated nil check"
-       _ = *arrayp     // ERROR "removed.* nil check"
+       _ = *arrayp     // ERROR "generated nil check"
        _ = *bigarrayp  // ERROR "generated nil check" ARM removed nil check before indirect!!
        _ = *bigstructp // ERROR "generated nil check"
        _ = *empty1p    // ERROR "generated nil check"
@@ -122,16 +122,16 @@ func f3(x *[10000]int) {
        // x wasn't going to change across the function call.
        // But it's a little complex to do and in practice doesn't
        // matter enough.
-       _ = x[9999] // ERROR "removed nil check"
+       _ = x[9999] // ERROR "generated nil check" // TODO: fix
 }
 
 func f3a() {
        x := fx10k()
        y := fx10k()
        z := fx10k()
-       _ = &x[9] // ERROR "generated nil check"
-       y = z
        _ = &x[9] // ERROR "removed.* nil check"
+       y = z
+       _ = &x[9] // ERROR "generated nil check"
        x = y
        _ = &x[9] // ERROR "generated nil check"
 }
@@ -139,11 +139,11 @@ func f3a() {
 func f3b() {
        x := fx10k()
        y := fx10k()
-       _ = &x[9] // ERROR "generated nil check"
+       _ = &x[9] // ERROR "removed.* nil check"
        y = x
        _ = &x[9] // ERROR "removed.* nil check"
        x = y
-       _ = &x[9] // ERROR "removed.* nil check"
+       _ = &x[9] // ERROR "generated nil check"
 }
 
 func fx10() *[10]int
@@ -179,15 +179,15 @@ func f4(x *[10]int) {
        _ = x[9] // ERROR "generated nil check"  // bug would like to remove before indirect
 
        fx10()
-       _ = x[9] // ERROR "removed nil check"
+       _ = x[9] // ERROR "generated nil check"  // TODO: fix
 
        x = fx10()
        y := fx10()
-       _ = &x[9] // ERROR "generated nil check"
+       _ = &x[9] // ERROR "removed[a-z ]* nil check"
        y = x
        _ = &x[9] // ERROR "removed[a-z ]* nil check"
        x = y
-       _ = &x[9] // ERROR "removed[a-z ]* nil check"
+       _ = &x[9] // ERROR "generated nil check"
 }
 
 func f5(p *float32, q *float64, r *float32, s *float64) float64 {
index 5781253e3edf589770b4973ca951f6d9b82ddad4..84de32179f38a0a4b8e99e729c48a1b1cf8acc44 100644 (file)
@@ -1,5 +1,6 @@
 // +build amd64
-// errorcheck -0 -d=ssa/likelyadjust/debug=1
+// errorcheck -0 -d=ssa/likelyadjust/debug=1,ssa/insert_resched_checks/off
+// rescheduling check insertion is turend off because the inserted conditional branches perturb the errorcheck
 
 // Copyright 2016 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index 0dee6b5caab41a96fde48b1a75ac4bef1f53ecbe..19ca3287651388d34ef71171930e708b6dd9a4af 100644 (file)
@@ -463,6 +463,7 @@ func (t *test) run() {
        }
 
        var args, flags []string
+       var tim int
        wantError := false
        wantAuto := false
        singlefilepkgs := false
@@ -478,7 +479,7 @@ func (t *test) run() {
                action = "rundir"
        case "cmpout":
                action = "run" // the run case already looks for <dir>/<test>.out files
-       case "compile", "compiledir", "build", "run", "runoutput", "rundir":
+       case "compile", "compiledir", "build", "run", "buildrun", "runoutput", "rundir":
                // nothing to do
        case "errorcheckandrundir":
                wantError = false // should be no error if also will run
@@ -505,6 +506,14 @@ func (t *test) run() {
                        wantError = false
                case "-s":
                        singlefilepkgs = true
+               case "-t": // timeout in seconds
+                       args = args[1:]
+                       var err error
+                       tim, err = strconv.Atoi(args[0])
+                       if err != nil {
+                               t.err = fmt.Errorf("need number of seconds for -t timeout, got %s instead", args[0])
+                       }
+
                default:
                        flags = append(flags, args[0])
                }
@@ -539,7 +548,31 @@ func (t *test) run() {
                } else {
                        cmd.Env = os.Environ()
                }
-               err := cmd.Run()
+
+               var err error
+
+               if tim != 0 {
+                       err = cmd.Start()
+                       // This command-timeout code adapted from cmd/go/test.go
+                       if err == nil {
+                               tick := time.NewTimer(time.Duration(tim) * time.Second)
+                               done := make(chan error)
+                               go func() {
+                                       done <- cmd.Wait()
+                               }()
+                               select {
+                               case err = <-done:
+                                       // ok
+                               case <-tick.C:
+                                       cmd.Process.Kill()
+                                       err = <-done
+                                       // err = errors.New("Test timeout")
+                               }
+                               tick.Stop()
+                       }
+               } else {
+                       err = cmd.Run()
+               }
                if err != nil {
                        err = fmt.Errorf("%s\n%s", err, buf.Bytes())
                }
@@ -671,6 +704,32 @@ func (t *test) run() {
                        t.err = err
                }
 
+       case "buildrun": // build binary, then run binary, instead of go run. Useful for timeout tests where failure mode is infinite loop.
+               // TODO: not supported on NaCl
+               useTmp = true
+               cmd := []string{"go", "build", "-o", "a.exe"}
+               if *linkshared {
+                       cmd = append(cmd, "-linkshared")
+               }
+               longdirgofile := filepath.Join(filepath.Join(cwd, t.dir), t.gofile)
+               cmd = append(cmd, flags...)
+               cmd = append(cmd, longdirgofile)
+               out, err := runcmd(cmd...)
+               if err != nil {
+                       t.err = err
+                       return
+               }
+               cmd = []string{"./a.exe"}
+               out, err = runcmd(append(cmd, args...)...)
+               if err != nil {
+                       t.err = err
+                       return
+               }
+
+               if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
+                       t.err = fmt.Errorf("incorrect output\n%s", out)
+               }
+
        case "run":
                useTmp = false
                cmd := []string{"go", "run"}