aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2016-08-04 10:08:20 -0700
committerKeith Randall <khr@golang.org>2016-08-04 10:08:20 -0700
commitd2286ea2843569c7d277587f3d3ef06ae4092b78 (patch)
tree0e2c7fa3abda784d6aa797bc8cbfbadbdcb0d693
parent6a1153acb4aff2d481be1611862be0f9f5203e62 (diff)
parent50edddb7383a0e4aef990a085777f958c5d8a2b8 (diff)
downloadgo-d2286ea2843569c7d277587f3d3ef06ae4092b78.tar.gz
go-d2286ea2843569c7d277587f3d3ef06ae4092b78.zip
[dev.ssa] Merge remote-tracking branch 'origin/master' into mergebranch
Semi-regular merge from tip into dev.ssa. Change-Id: Iadb60e594ef65a99c0e1404b14205fa67c32a9e9
-rw-r--r--doc/asm.html58
-rw-r--r--doc/devel/release.html8
-rw-r--r--doc/go1.7.html41
-rw-r--r--misc/trace/trace_viewer_lean.html2
-rw-r--r--src/cmd/api/goapi.go2
-rw-r--r--src/cmd/compile/internal/amd64/ssa.go44
-rw-r--r--src/cmd/compile/internal/gc/sparselocatephifunctions.go5
-rw-r--r--src/cmd/compile/internal/ssa/compile.go1
-rw-r--r--src/cmd/compile/internal/ssa/gen/AMD64.rules4
-rw-r--r--src/cmd/compile/internal/ssa/gen/AMD64Ops.go4
-rw-r--r--src/cmd/compile/internal/ssa/rewrite.go45
-rw-r--r--src/cmd/compile/internal/ssa/rewriteAMD64.go13
-rw-r--r--src/cmd/compile/internal/ssa/sparsetreemap.go104
-rw-r--r--src/cmd/compile/internal/ssa/tighten.go23
-rw-r--r--src/cmd/doc/doc_test.go16
-rw-r--r--src/cmd/doc/pkg.go28
-rw-r--r--src/cmd/doc/testdata/pkg.go7
-rw-r--r--src/compress/flate/deflate.go13
-rw-r--r--src/context/context_test.go6
-rw-r--r--src/crypto/x509/root_cgo_darwin.go60
-rw-r--r--src/fmt/scan.go6
-rw-r--r--src/fmt/scan_test.go101
-rw-r--r--src/go/build/build_test.go8
-rw-r--r--src/go/build/deps_test.go8
-rw-r--r--src/net/dial_test.go5
-rw-r--r--src/net/dial_unix_test.go108
-rw-r--r--src/net/fd_unix.go55
-rw-r--r--src/net/hook_unix.go3
-rw-r--r--src/net/http/cgi/host.go4
-rw-r--r--src/net/http/cgi/host_test.go37
-rw-r--r--src/net/http/h2_bundle.go343
-rw-r--r--src/net/http/http.go2
-rw-r--r--src/net/http/serve_test.go11
-rw-r--r--src/net/http/server.go40
-rw-r--r--src/net/http/transfer.go2
-rw-r--r--src/net/http/transport.go57
-rw-r--r--src/net/http/transport_internal_test.go9
-rw-r--r--src/net/http/transport_test.go53
-rw-r--r--src/net/interface_bsd.go2
-rw-r--r--src/net/interface_bsdvar.go2
-rw-r--r--src/net/interface_darwin.go2
-rw-r--r--src/net/interface_freebsd.go2
-rw-r--r--src/net/smtp/smtp.go5
-rw-r--r--src/runtime/cgocall.go3
-rw-r--r--src/runtime/internal/atomic/asm_386.s6
-rw-r--r--src/runtime/internal/atomic/asm_amd64.s2
-rw-r--r--src/runtime/internal/atomic/asm_amd64p32.s4
-rw-r--r--src/runtime/internal/atomic/asm_arm.s6
-rw-r--r--src/runtime/internal/atomic/asm_arm64.s4
-rw-r--r--src/runtime/internal/atomic/asm_ppc64x.s2
-rw-r--r--src/runtime/mbarrier.go4
-rw-r--r--src/runtime/mem_linux.go22
-rw-r--r--src/runtime/mgc.go9
-rw-r--r--src/runtime/mgcmark.go11
-rw-r--r--src/runtime/mheap.go5
-rw-r--r--src/runtime/pprof/pprof.go68
-rw-r--r--src/runtime/pprof/pprof_test.go4
-rw-r--r--src/runtime/proc.go28
-rw-r--r--src/runtime/race/README2
-rw-r--r--src/runtime/race/race_darwin_amd64.sysobin341304 -> 326172 bytes
-rw-r--r--src/runtime/race/race_freebsd_amd64.sysobin399904 -> 404216 bytes
-rw-r--r--src/runtime/race/race_linux_amd64.sysobin371032 -> 376048 bytes
-rw-r--r--src/runtime/race/race_test.go18
-rw-r--r--src/runtime/race/race_windows_amd64.sysobin363595 -> 367717 bytes
-rw-r--r--src/runtime/sys_darwin_386.s7
-rw-r--r--src/runtime/sys_darwin_amd64.s2
-rw-r--r--src/vendor/golang_org/x/net/http2/hpack/encode.go (renamed from src/vendor/golang.org/x/net/http2/hpack/encode.go)0
-rw-r--r--src/vendor/golang_org/x/net/http2/hpack/encode_test.go (renamed from src/vendor/golang.org/x/net/http2/hpack/encode_test.go)0
-rw-r--r--src/vendor/golang_org/x/net/http2/hpack/hpack.go (renamed from src/vendor/golang.org/x/net/http2/hpack/hpack.go)0
-rw-r--r--src/vendor/golang_org/x/net/http2/hpack/hpack_test.go (renamed from src/vendor/golang.org/x/net/http2/hpack/hpack_test.go)0
-rw-r--r--src/vendor/golang_org/x/net/http2/hpack/huffman.go (renamed from src/vendor/golang.org/x/net/http2/hpack/huffman.go)0
-rw-r--r--src/vendor/golang_org/x/net/http2/hpack/tables.go (renamed from src/vendor/golang.org/x/net/http2/hpack/tables.go)0
-rw-r--r--src/vendor/golang_org/x/net/lex/httplex/httplex.go (renamed from src/vendor/golang.org/x/net/lex/httplex/httplex.go)0
-rw-r--r--src/vendor/golang_org/x/net/lex/httplex/httplex_test.go (renamed from src/vendor/golang.org/x/net/lex/httplex/httplex_test.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/address.go (renamed from src/vendor/golang.org/x/net/route/address.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/address_darwin_test.go (renamed from src/vendor/golang.org/x/net/route/address_darwin_test.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/address_test.go (renamed from src/vendor/golang.org/x/net/route/address_test.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/binary.go (renamed from src/vendor/golang.org/x/net/route/binary.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/defs_darwin.go (renamed from src/vendor/golang.org/x/net/route/defs_darwin.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/defs_dragonfly.go (renamed from src/vendor/golang.org/x/net/route/defs_dragonfly.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/defs_freebsd.go (renamed from src/vendor/golang.org/x/net/route/defs_freebsd.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/defs_netbsd.go (renamed from src/vendor/golang.org/x/net/route/defs_netbsd.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/defs_openbsd.go (renamed from src/vendor/golang.org/x/net/route/defs_openbsd.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/interface.go (renamed from src/vendor/golang.org/x/net/route/interface.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/interface_announce.go (renamed from src/vendor/golang.org/x/net/route/interface_announce.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/interface_classic.go (renamed from src/vendor/golang.org/x/net/route/interface_classic.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/interface_freebsd.go (renamed from src/vendor/golang.org/x/net/route/interface_freebsd.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/interface_multicast.go (renamed from src/vendor/golang.org/x/net/route/interface_multicast.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/interface_openbsd.go (renamed from src/vendor/golang.org/x/net/route/interface_openbsd.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/message.go (renamed from src/vendor/golang.org/x/net/route/message.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/message_darwin_test.go (renamed from src/vendor/golang.org/x/net/route/message_darwin_test.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/message_freebsd_test.go (renamed from src/vendor/golang.org/x/net/route/message_freebsd_test.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/message_test.go (renamed from src/vendor/golang.org/x/net/route/message_test.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/route.go (renamed from src/vendor/golang.org/x/net/route/route.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/route_classic.go (renamed from src/vendor/golang.org/x/net/route/route_classic.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/route_openbsd.go (renamed from src/vendor/golang.org/x/net/route/route_openbsd.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/route_test.go (renamed from src/vendor/golang.org/x/net/route/route_test.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/sys.go (renamed from src/vendor/golang.org/x/net/route/sys.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/sys_darwin.go (renamed from src/vendor/golang.org/x/net/route/sys_darwin.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/sys_dragonfly.go (renamed from src/vendor/golang.org/x/net/route/sys_dragonfly.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/sys_freebsd.go (renamed from src/vendor/golang.org/x/net/route/sys_freebsd.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/sys_netbsd.go (renamed from src/vendor/golang.org/x/net/route/sys_netbsd.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/sys_openbsd.go (renamed from src/vendor/golang.org/x/net/route/sys_openbsd.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/syscall.go (renamed from src/vendor/golang.org/x/net/route/syscall.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/syscall.s (renamed from src/vendor/golang.org/x/net/route/syscall.s)0
-rw-r--r--src/vendor/golang_org/x/net/route/zsys_darwin.go (renamed from src/vendor/golang.org/x/net/route/zsys_darwin.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/zsys_dragonfly.go (renamed from src/vendor/golang.org/x/net/route/zsys_dragonfly.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/zsys_freebsd_386.go (renamed from src/vendor/golang.org/x/net/route/zsys_freebsd_386.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/zsys_freebsd_amd64.go (renamed from src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/zsys_freebsd_arm.go (renamed from src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/zsys_netbsd.go (renamed from src/vendor/golang.org/x/net/route/zsys_netbsd.go)0
-rw-r--r--src/vendor/golang_org/x/net/route/zsys_openbsd.go (renamed from src/vendor/golang.org/x/net/route/zsys_openbsd.go)0
-rw-r--r--test/fixedbugs/issue16515.go53
113 files changed, 1225 insertions, 384 deletions
diff --git a/doc/asm.html b/doc/asm.html
index 392af174c2..3e03c548fd 100644
--- a/doc/asm.html
+++ b/doc/asm.html
@@ -780,6 +780,64 @@ mode as on the x86, but the only scale allowed is <code>1</code>.
</ul>
+<h3 id="s390x">IBM z/Architecture, a.k.a. s390x</h3>
+
+<p>
+The registers <code>R10</code> and <code>R11</code> are reserved.
+The assembler uses them to hold temporary values when assembling some instructions.
+</p>
+
+<p>
+<code>R13</code> points to the <code>g</code> (goroutine) structure.
+This register must be referred to as <code>g</code>; the name <code>R13</code> is not recognized.
+</p>
+
+<p>
+<code>R15</code> points to the stack frame and should typically only be accessed using the
+virtual registers <code>SP</code> and <code>FP</code>.
+</p>
+
+<p>
+Load- and store-multiple instructions operate on a range of registers.
+The range of registers is specified by a start register and an end register.
+For example, <code>LMG</code> <code>(R9),</code> <code>R5,</code> <code>R7</code> would load
+<code>R5</code>, <code>R6</code> and <code>R7</code> with the 64-bit values at
+<code>0(R9)</code>, <code>8(R9)</code> and <code>16(R9)</code> respectively.
+</p>
+
+<p>
+Storage-and-storage instructions such as <code>MVC</code> and <code>XC</code> are written
+with the length as the first argument.
+For example, <code>XC</code> <code>$8,</code> <code>(R9),</code> <code>(R9)</code> would clear
+eight bytes at the address specified in <code>R9</code>.
+</p>
+
+<p>
+If a vector instruction takes a length or an index as an argument then it will be the
+first argument.
+For example, <code>VLEIF</code> <code>$1,</code> <code>$16,</code> <code>V2</code> will load
+the value sixteen into index one of <code>V2</code>.
+Care should be taken when using vector instructions to ensure that they are available at
+runtime.
+To use vector instructions a machine must have both the vector facility (bit 129 in the
+facility list) and kernel support.
+Without kernel support a vector instruction will have no effect (it will be equivalent
+to a <code>NOP</code> instruction).
+</p>
+
+<p>
+Addressing modes:
+</p>
+
+<ul>
+
+<li>
+<code>(R5)(R6*1)</code>: The location at <code>R5</code> plus <code>R6</code>.
+It is a scaled mode as on the x86, but the only scale allowed is <code>1</code>.
+</li>
+
+</ul>
+
<h3 id="unsupported_opcodes">Unsupported opcodes</h3>
<p>
diff --git a/doc/devel/release.html b/doc/devel/release.html
index 97c4133f1d..fcb8c19003 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -53,6 +53,14 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.6.2">Go
1.6.2 milestone</a> on our issue tracker for details.
</p>
+<p>
+go1.6.3 (released 2016/07/17) includes security fixes to the
+<code>net/http/cgi</code> package and <code>net/http</code> package when used in
+a CGI environment. This release also adds support for macOS Sierra.
+See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.6.3">Go
+1.6.3 milestone</a> on our issue tracker for details.
+</p>
+
<h2 id="go1.5">go1.5 (released 2015/08/19)</h2>
<p>
diff --git a/doc/go1.7.html b/doc/go1.7.html
index d209a5ab0e..7e17ff2424 100644
--- a/doc/go1.7.html
+++ b/doc/go1.7.html
@@ -75,6 +75,13 @@ This change has no effect on the correctness of existing programs.
<h2 id="ports">Ports</h2>
<p>
+Go 1.7 adds support for macOS 10.12 Sierra.
+This support was backported to Go 1.6.3.
+Binaries built with versions of Go before 1.6.3 will not work
+correctly on Sierra.
+</p>
+
+<p>
Go 1.7 adds an experimental port to <a href="https://en.wikipedia.org/wiki/Linux_on_z_Systems">Linux on z Systems</a> (<code>linux/s390x</code>)
and the beginning of a port to Plan 9 on ARM (<code>plan9/arm</code>).
</p>
@@ -85,14 +92,27 @@ added in Go 1.6 now have full support for cgo and external linking.
</p>
<p>
-The experimental port to Linux on big-endian 64-bit PowerPC (<code>linux/ppc64</code>)
+The experimental port to Linux on little-endian 64-bit PowerPC (<code>linux/ppc64le</code>)
now requires the POWER8 architecture or later.
+Big-endian 64-bit PowerPC (<code>linux/ppc64</code>) only requires the
+POWER5 architecture.
</p>
<p>
The OpenBSD port now requires OpenBSD 5.6 or later, for access to the <a href="http://man.openbsd.org/getentropy.2"><i>getentropy</i>(2)</a> system call.
</p>
+<h3 id="known_issues">Known Issues</h3>
+
+<p>
+There are some instabilities on FreeBSD that are known but not understood.
+These can lead to program crashes in rare cases.
+See <a href="https://golang.org/issue/16136">issue 16136</a>,
+<a href="https://golang.org/issue/15658">issue 15658</a>,
+and <a href="https://golang.org/issue/16396">issue 16396</a>.
+Any help in solving these FreeBSD-specific issues would be appreciated.
+</p>
+
<h2 id="tools">Tools</h2>
<h3 id="cmd_asm">Assembler</h3>
@@ -367,6 +387,12 @@ and
packages.
</p>
+<p>
+Garbage collection pauses should be significantly shorter than they
+were in Go 1.6 for programs with large numbers of idle goroutines,
+substantial stack size fluctuation, or large package-level variables.
+</p>
+
<h2 id="library">Core library</h2>
<h3 id="context">Context</h3>
@@ -463,6 +489,13 @@ common in some environments.
</p>
<p>
+The runtime can now return unused memory to the operating system on
+all architectures.
+In Go 1.6 and earlier, the runtime could not
+release memory on ARM64, 64-bit PowerPC, or MIPS.
+</p>
+
+<p>
On Windows, Go programs in Go 1.5 and earlier forced
the global Windows timer resolution to 1ms at startup
by calling <code>timeBeginPeriod(1)</code>.
@@ -884,6 +917,12 @@ For example, the address on which a request received is
</p>
<p>
+The server's <a href="/pkg/net/http/#Server.Serve"><code>Serve</code></a> method
+now only enables HTTP/2 support if the <code>Server.TLSConfig</code> field is <code>nil</code>
+or includes <code>"h2"</code> in its <code>TLSConfig.NextProto</code>.
+</p>
+
+<p>
The server implementation now
pads response codes less than 100 to three digits
as required by the protocol,
diff --git a/misc/trace/trace_viewer_lean.html b/misc/trace/trace_viewer_lean.html
index 7939aae8a6..076cb4359a 100644
--- a/misc/trace/trace_viewer_lean.html
+++ b/misc/trace/trace_viewer_lean.html
@@ -5281,7 +5281,7 @@ if(traces.length&&!this.hasEventDataDecoder_(importers)){throw new Error('Could
importers.sort(function(x,y){return x.importPriority-y.importPriority;});},this);lastTask=lastTask.timedAfter('TraceImport',function importClockSyncMarkers(task){importers.forEach(function(importer,index){task.subTask(Timing.wrapNamedFunction('TraceImport',importer.importerName,function runImportClockSyncMarkersOnOneImporter(){progressMeter.update('Importing clock sync markers '+(index+1)+' of '+
importers.length);importer.importClockSyncMarkers();}),this);},this);},this);lastTask=lastTask.timedAfter('TraceImport',function runImport(task){importers.forEach(function(importer,index){task.subTask(Timing.wrapNamedFunction('TraceImport',importer.importerName,function runImportEventsOnOneImporter(){progressMeter.update('Importing '+(index+1)+' of '+importers.length);importer.importEvents();}),this);},this);},this);if(this.importOptions_.customizeModelCallback){lastTask=lastTask.timedAfter('TraceImport',function runCustomizeCallbacks(task){this.importOptions_.customizeModelCallback(this.model_);},this);}
lastTask=lastTask.timedAfter('TraceImport',function importSampleData(task){importers.forEach(function(importer,index){progressMeter.update('Importing sample data '+(index+1)+'/'+importers.length);importer.importSampleData();},this);},this);lastTask=lastTask.timedAfter('TraceImport',function runAutoclosers(){progressMeter.update('Autoclosing open slices...');this.model_.autoCloseOpenSlices();this.model_.createSubSlices();},this);lastTask=lastTask.timedAfter('TraceImport',function finalizeImport(task){importers.forEach(function(importer,index){progressMeter.update('Finalizing import '+(index+1)+'/'+importers.length);importer.finalizeImport();},this);},this);lastTask=lastTask.timedAfter('TraceImport',function runPreinits(){progressMeter.update('Initializing objects (step 1/2)...');this.model_.preInitializeObjects();},this);if(this.importOptions_.pruneEmptyContainers){lastTask=lastTask.timedAfter('TraceImport',function runPruneEmptyContainers(){progressMeter.update('Pruning empty containers...');this.model_.pruneEmptyContainers();},this);}
-lastTask=lastTask.timedAfter('TraceImport',function runMergeKernelWithuserland(){progressMeter.update('Merging kernel with userland...');this.model_.mergeKernelWithUserland();},this);var auditors=[];lastTask=lastTask.timedAfter('TraceImport',function createAuditorsAndRunAnnotate(){progressMeter.update('Adding arbitrary data to model...');auditors=this.importOptions_.auditorConstructors.map(function(auditorConstructor){return new auditorConstructor(this.model_);},this);auditors.forEach(function(auditor){auditor.runAnnotate();auditor.installUserFriendlyCategoryDriverIfNeeded();});},this);lastTask=lastTask.timedAfter('TraceImport',function computeWorldBounds(){progressMeter.update('Computing final world bounds...');this.model_.computeWorldBounds(this.importOptions_.shiftWorldToZero);},this);lastTask=lastTask.timedAfter('TraceImport',function buildFlowEventIntervalTree(){progressMeter.update('Building flow event map...');this.model_.buildFlowEventIntervalTree();},this);lastTask=lastTask.timedAfter('TraceImport',function joinRefs(){progressMeter.update('Joining object refs...');this.model_.joinRefs();},this);lastTask=lastTask.timedAfter('TraceImport',function cleanupUndeletedObjects(){progressMeter.update('Cleaning up undeleted objects...');this.model_.cleanupUndeletedObjects();},this);lastTask=lastTask.timedAfter('TraceImport',function sortMemoryDumps(){progressMeter.update('Sorting memory dumps...');this.model_.sortMemoryDumps();},this);lastTask=lastTask.timedAfter('TraceImport',function finalizeMemoryGraphs(){progressMeter.update('Finalizing memory dump graphs...');this.model_.finalizeMemoryGraphs();},this);lastTask=lastTask.timedAfter('TraceImport',function initializeObjects(){progressMeter.update('Initializing objects (step 2/2)...');this.model_.initializeObjects();},this);lastTask=lastTask.timedAfter('TraceImport',function buildEventIndices(){progressMeter.update('Building event indices...');this.model_.buildEventIndices();},this);lastTask=lastTask.timedAfter('TraceImport',function buildUserModel(){progressMeter.update('Building UserModel...');var userModelBuilder=new tr.importer.UserModelBuilder(this.model_);userModelBuilder.buildUserModel();},this);lastTask=lastTask.timedAfter('TraceImport',function sortExpectations(){progressMeter.update('Sorting user expectations...');this.model_.userModel.sortExpectations();},this);lastTask=lastTask.timedAfter('TraceImport',function runAudits(){progressMeter.update('Running auditors...');auditors.forEach(function(auditor){auditor.runAudit();});},this);lastTask=lastTask.timedAfter('TraceImport',function sortAlerts(){progressMeter.update('Updating alerts...');this.model_.sortAlerts();},this);lastTask=lastTask.timedAfter('TraceImport',function lastUpdateBounds(){progressMeter.update('Update bounds...');this.model_.updateBounds();},this);lastTask=lastTask.timedAfter('TraceImport',function addModelWarnings(){progressMeter.update('Looking for warnings...');if(!this.model_.isTimeHighResolution){this.model_.importWarning({type:'low_resolution_timer',message:'Trace time is low resolution, trace may be unusable.',showToUser:true});}},this);lastTask.after(function(){this.importing_=false;},this);return importTask;},createImporter_:function(eventData){var importerConstructor=tr.importer.Importer.findImporterFor(eventData);if(!importerConstructor){throw new Error('Couldn\'t create an importer for the provided '+'eventData.');}
+lastTask=lastTask.timedAfter('TraceImport',function runMergeKernelWithuserland(){progressMeter.update('Merging kernel with userland...');this.model_.mergeKernelWithUserland();},this);var auditors=[];lastTask=lastTask.timedAfter('TraceImport',function createAuditorsAndRunAnnotate(){progressMeter.update('Adding arbitrary data to model...');auditors=this.importOptions_.auditorConstructors.map(function(auditorConstructor){return new auditorConstructor(this.model_);},this);auditors.forEach(function(auditor){auditor.runAnnotate();auditor.installUserFriendlyCategoryDriverIfNeeded();});},this);lastTask=lastTask.timedAfter('TraceImport',function computeWorldBounds(){progressMeter.update('Computing final world bounds...');this.model_.computeWorldBounds(this.importOptions_.shiftWorldToZero);},this);lastTask=lastTask.timedAfter('TraceImport',function buildFlowEventIntervalTree(){progressMeter.update('Building flow event map...');this.model_.buildFlowEventIntervalTree();},this);lastTask=lastTask.timedAfter('TraceImport',function joinRefs(){progressMeter.update('Joining object refs...');this.model_.joinRefs();},this);lastTask=lastTask.timedAfter('TraceImport',function cleanupUndeletedObjects(){progressMeter.update('Cleaning up undeleted objects...');this.model_.cleanupUndeletedObjects();},this);lastTask=lastTask.timedAfter('TraceImport',function sortMemoryDumps(){progressMeter.update('Sorting memory dumps...');this.model_.sortMemoryDumps();},this);lastTask=lastTask.timedAfter('TraceImport',function finalizeMemoryGraphs(){progressMeter.update('Finalizing memory dump graphs...');this.model_.finalizeMemoryGraphs();},this);lastTask=lastTask.timedAfter('TraceImport',function initializeObjects(){progressMeter.update('Initializing objects (step 2/2)...');this.model_.initializeObjects();},this);lastTask=lastTask.timedAfter('TraceImport',function buildEventIndices(){progressMeter.update('Building event indices...');this.model_.buildEventIndices();},this);lastTask=lastTask.timedAfter('TraceImport',function buildUserModel(){progressMeter.update('Building UserModel...');var userModelBuilder=new tr.importer.UserModelBuilder(this.model_);userModelBuilder.buildUserModel();},this);lastTask=lastTask.timedAfter('TraceImport',function sortExpectations(){progressMeter.update('Sorting user expectations...');this.model_.userModel.sortExpectations();},this);lastTask=lastTask.timedAfter('TraceImport',function runAudits(){progressMeter.update('Running auditors...');auditors.forEach(function(auditor){auditor.runAudit();});},this);lastTask=lastTask.timedAfter('TraceImport',function sortAlerts(){progressMeter.update('Updating alerts...');this.model_.sortAlerts();},this);lastTask=lastTask.timedAfter('TraceImport',function lastUpdateBounds(){progressMeter.update('Update bounds...');this.model_.updateBounds();},this);lastTask=lastTask.timedAfter('TraceImport',function addModelWarnings(){progressMeter.update('Looking for warnings...');if(!this.model_.isTimeHighResolution){this.model_.importWarning({type:'low_resolution_timer',message:'Trace time is low resolution, trace may be unusable.',showToUser:false});}},this);lastTask.after(function(){this.importing_=false;},this);return importTask;},createImporter_:function(eventData){var importerConstructor=tr.importer.Importer.findImporterFor(eventData);if(!importerConstructor){throw new Error('Couldn\'t create an importer for the provided '+'eventData.');}
return new importerConstructor(this.model_,eventData);},hasEventDataDecoder_:function(importers){for(var i=0;i<importers.length;++i){if(!importers[i].isTraceDataContainer())
return true;}
return false;}};return{ImportOptions:ImportOptions,Import:Import};});'use strict';tr.exportTo('tr.e.cc',function(){function PictureAsImageData(picture,errorOrImageData){this.picture_=picture;if(errorOrImageData instanceof ImageData){this.error_=undefined;this.imageData_=errorOrImageData;}else{this.error_=errorOrImageData;this.imageData_=undefined;}};PictureAsImageData.Pending=function(picture){return new PictureAsImageData(picture,undefined);};PictureAsImageData.prototype={get picture(){return this.picture_;},get error(){return this.error_;},get imageData(){return this.imageData_;},isPending:function(){return this.error_===undefined&&this.imageData_===undefined;},asCanvas:function(){if(!this.imageData_)
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index e9c91477c6..936f9e5511 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -425,7 +425,7 @@ func (w *Walker) Import(name string) (*types.Package, error) {
w.imported[name] = &importing
root := w.root
- if strings.HasPrefix(name, "golang.org/x/") {
+ if strings.HasPrefix(name, "golang_org/x/") {
root = filepath.Join(root, "vendor")
}
diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go
index a714e06c15..a95fa245d2 100644
--- a/src/cmd/compile/internal/amd64/ssa.go
+++ b/src/cmd/compile/internal/amd64/ssa.go
@@ -156,6 +156,36 @@ func opregreg(op obj.As, dest, src int16) *obj.Prog {
return p
}
+// DUFFZERO consists of repeated blocks of 4 MOVUPSs + ADD,
+// See runtime/mkduff.go.
+func duffStart(size int64) int64 {
+ x, _ := duff(size)
+ return x
+}
+func duffAdj(size int64) int64 {
+ _, x := duff(size)
+ return x
+}
+
+// duff returns the offset (from duffzero, in bytes) and pointer adjust (in bytes)
+// required to use the duffzero mechanism for a block of the given size.
+func duff(size int64) (int64, int64) {
+ if size < 32 || size > 1024 || size%dzClearStep != 0 {
+ panic("bad duffzero size")
+ }
+ steps := size / dzClearStep
+ blocks := steps / dzBlockLen
+ steps %= dzBlockLen
+ off := dzBlockSize * (dzBlocks - blocks)
+ var adj int64
+ if steps != 0 {
+ off -= dzAddSize
+ off -= dzMovSize * steps
+ adj -= dzClearStep * (dzBlockLen - steps)
+ }
+ return off, adj
+}
+
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line)
switch v.Op {
@@ -647,10 +677,20 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
ssa.OpAMD64CVTSS2SD, ssa.OpAMD64CVTSD2SS:
opregreg(v.Op.Asm(), gc.SSARegNum(v), gc.SSARegNum(v.Args[0]))
case ssa.OpAMD64DUFFZERO:
- p := gc.Prog(obj.ADUFFZERO)
+ off := duffStart(v.AuxInt)
+ adj := duffAdj(v.AuxInt)
+ var p *obj.Prog
+ if adj != 0 {
+ p = gc.Prog(x86.AADDQ)
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = adj
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = x86.REG_DI
+ }
+ p = gc.Prog(obj.ADUFFZERO)
p.To.Type = obj.TYPE_ADDR
p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
- p.To.Offset = v.AuxInt
+ p.To.Offset = off
case ssa.OpAMD64MOVOconst:
if v.AuxInt != 0 {
v.Unimplementedf("MOVOconst can only do constant=0")
diff --git a/src/cmd/compile/internal/gc/sparselocatephifunctions.go b/src/cmd/compile/internal/gc/sparselocatephifunctions.go
index e15f22123f..43cc50bd92 100644
--- a/src/cmd/compile/internal/gc/sparselocatephifunctions.go
+++ b/src/cmd/compile/internal/gc/sparselocatephifunctions.go
@@ -153,10 +153,13 @@ func (s *state) locatePotentialPhiFunctions(fn *Node) *sparseDefState {
p := e.Block()
dm.Use(t, p) // always count phi pred as "use"; no-op except for loop edges, which matter.
x := t.stm.Find(p, ssa.AdjustAfter, helper) // Look for defs reaching or within predecessors.
+ if x == nil { // nil def from a predecessor means a backedge that will be visited soon.
+ continue
+ }
if defseen == nil {
defseen = x
}
- if defseen != x || x == nil { // TODO: too conservative at loops, does better if x == nil -> continue
+ if defseen != x {
// Need to insert a phi function here because predecessors's definitions differ.
change = true
// Phi insertion is at AdjustBefore, visible with find in same block at AdjustWithin or AdjustAfter.
diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go
index b3c7544ad1..d8b0b0a5c1 100644
--- a/src/cmd/compile/internal/ssa/compile.go
+++ b/src/cmd/compile/internal/ssa/compile.go
@@ -270,6 +270,7 @@ var passes = [...]pass{
{name: "checkLower", fn: checkLower, required: true},
{name: "late phielim", fn: phielim},
{name: "late copyelim", fn: copyelim},
+ {name: "phi tighten", fn: phiTighten},
{name: "late deadcode", fn: deadcode},
{name: "critical", fn: critical, required: true}, // remove critical edges
{name: "likelyadjust", fn: likelyadjust},
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
index 811e810f15..9b418661f0 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -400,9 +400,7 @@
(Zero [SizeAndAlign(s).Size()-8] (ADDQconst [8] destptr) (MOVQstore destptr (MOVQconst [0]) mem))
(Zero [s] destptr mem)
&& SizeAndAlign(s).Size() <= 1024 && SizeAndAlign(s).Size()%16 == 0 && !config.noDuffDevice ->
- (DUFFZERO [duffStartAMD64(SizeAndAlign(s).Size())]
- (ADDQconst [duffAdjAMD64(SizeAndAlign(s).Size())] destptr) (MOVOconst [0])
- mem)
+ (DUFFZERO [SizeAndAlign(s).Size()] destptr (MOVOconst [0]) mem)
// Large zeroing uses REP STOSQ.
(Zero [s] destptr mem)
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
index 3b1edf2956..5772cada9c 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
@@ -416,10 +416,10 @@ func init() {
{name: "MOVQstoreconstidx1", argLength: 3, reg: gpstoreconstidx, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem"}, // store 8 bytes of ... arg1 ...
{name: "MOVQstoreconstidx8", argLength: 3, reg: gpstoreconstidx, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem"}, // store 8 bytes of ... 8*arg1 ...
- // arg0 = (duff-adjusted) pointer to start of memory to zero
+ // arg0 = pointer to start of memory to zero
// arg1 = value to store (will always be zero)
// arg2 = mem
- // auxint = offset into duffzero code to start executing
+ // auxint = # of bytes to zero
// returns mem
{
name: "DUFFZERO",
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
index 082aacd9c9..1c4815dc81 100644
--- a/src/cmd/compile/internal/ssa/rewrite.go
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -259,51 +259,6 @@ func isSamePtr(p1, p2 *Value) bool {
return false
}
-func duffStartAMD64(size int64) int64 {
- x, _ := duffAMD64(size)
- return x
-}
-func duffAdjAMD64(size int64) int64 {
- _, x := duffAMD64(size)
- return x
-}
-
-// duff returns the offset (from duffzero, in bytes) and pointer adjust (in bytes)
-// required to use the duffzero mechanism for a block of the given size.
-func duffAMD64(size int64) (int64, int64) {
- // DUFFZERO consists of repeated blocks of 4 MOVUPSs + ADD,
- // See runtime/mkduff.go.
- const (
- dzBlocks = 16 // number of MOV/ADD blocks
- dzBlockLen = 4 // number of clears per block
- dzBlockSize = 19 // size of instructions in a single block
- dzMovSize = 4 // size of single MOV instruction w/ offset
- dzAddSize = 4 // size of single ADD instruction
- dzClearStep = 16 // number of bytes cleared by each MOV instruction
-
- dzTailLen = 4 // number of final STOSQ instructions
- dzTailSize = 2 // size of single STOSQ instruction
-
- dzClearLen = dzClearStep * dzBlockLen // bytes cleared by one block
- dzSize = dzBlocks * dzBlockSize
- )
-
- if size < 32 || size > 1024 || size%dzClearStep != 0 {
- panic("bad duffzero size")
- }
- steps := size / dzClearStep
- blocks := steps / dzBlockLen
- steps %= dzBlockLen
- off := dzBlockSize * (dzBlocks - blocks)
- var adj int64
- if steps != 0 {
- off -= dzAddSize
- off -= dzMovSize * steps
- adj -= dzClearStep * (dzBlockLen - steps)
- }
- return off, adj
-}
-
// moveSize returns the number of bytes an aligned MOV instruction moves
func moveSize(align int64, c *Config) int64 {
switch {
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
index 19f01a0148..3aa38f31ad 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -17415,7 +17415,7 @@ func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
}
// match: (Zero [s] destptr mem)
// cond: SizeAndAlign(s).Size() <= 1024 && SizeAndAlign(s).Size()%16 == 0 && !config.noDuffDevice
- // result: (DUFFZERO [duffStartAMD64(SizeAndAlign(s).Size())] (ADDQconst [duffAdjAMD64(SizeAndAlign(s).Size())] destptr) (MOVOconst [0]) mem)
+ // result: (DUFFZERO [SizeAndAlign(s).Size()] destptr (MOVOconst [0]) mem)
for {
s := v.AuxInt
destptr := v.Args[0]
@@ -17424,14 +17424,11 @@ func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
break
}
v.reset(OpAMD64DUFFZERO)
- v.AuxInt = duffStartAMD64(SizeAndAlign(s).Size())
- v0 := b.NewValue0(v.Line, OpAMD64ADDQconst, config.fe.TypeUInt64())
- v0.AuxInt = duffAdjAMD64(SizeAndAlign(s).Size())
- v0.AddArg(destptr)
+ v.AuxInt = SizeAndAlign(s).Size()
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVOconst, TypeInt128)
+ v0.AuxInt = 0
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64MOVOconst, TypeInt128)
- v1.AuxInt = 0
- v.AddArg(v1)
v.AddArg(mem)
return true
}
diff --git a/src/cmd/compile/internal/ssa/sparsetreemap.go b/src/cmd/compile/internal/ssa/sparsetreemap.go
index 61276985b1..3e6f296796 100644
--- a/src/cmd/compile/internal/ssa/sparsetreemap.go
+++ b/src/cmd/compile/internal/ssa/sparsetreemap.go
@@ -14,8 +14,8 @@ import "fmt"
// the nearest tree ancestor of a given node such that the
// ancestor is also in the set.
//
-// Given a set of blocks {B1, B2, B3} within the dominator tree, established by
-// stm.Insert()ing B1, B2, B3, etc, a query at block B
+// Given a set of blocks {B1, B2, B3} within the dominator tree, established
+// by stm.Insert()ing B1, B2, B3, etc, a query at block B
// (performed with stm.Find(stm, B, adjust, helper))
// will return the member of the set that is the nearest strict
// ancestor of B within the dominator tree, or nil if none exists.
@@ -49,9 +49,9 @@ type SparseTreeMap RBTint32
// packages, such as gc.
type SparseTreeHelper struct {
Sdom []SparseTreeNode // indexed by block.ID
- Po []*Block // exported data
- Dom []*Block // exported data
- Ponums []int32 // exported data
+ Po []*Block // exported data; the blocks, in a post-order
+ Dom []*Block // exported data; the dominator of this block.
+ Ponums []int32 // exported data; Po[Ponums[b.ID]] == b; the index of b in Po
}
// NewSparseTreeHelper returns a SparseTreeHelper for use
@@ -79,11 +79,19 @@ func makeSparseTreeHelper(sdom SparseTree, dom, po []*Block, ponums []int32) *Sp
// A sparseTreeMapEntry contains the data stored in a binary search
// data structure indexed by (dominator tree walk) entry and exit numbers.
// Each entry is added twice, once keyed by entry-1/entry/entry+1 and
-// once keyed by exit+1/exit/exit-1. (there are three choices of paired indices, not 9, and they properly nest)
+// once keyed by exit+1/exit/exit-1.
+//
+// Within a sparse tree, the two entries added bracket all their descendant
+// entries within the tree; the first insertion is keyed by entry number,
+// which comes before all the entry and exit numbers of descendants, and
+// the second insertion is keyed by exit number, which comes after all the
+// entry and exit numbers of the descendants.
type sparseTreeMapEntry struct {
- index *SparseTreeNode
- block *Block // TODO: store this in a separate index.
- data interface{}
+ index *SparseTreeNode // references the entry and exit numbers for a block in the sparse tree
+ block *Block // TODO: store this in a separate index.
+ data interface{}
+ sparseParent *sparseTreeMapEntry // references the nearest ancestor of this block in the sparse tree.
+ adjust int32 // at what adjustment was this node entered into the sparse tree? The same block may be entered more than once, but at different adjustments.
}
// Insert creates a definition within b with data x.
@@ -98,12 +106,25 @@ func (m *SparseTreeMap) Insert(b *Block, adjust int32, x interface{}, helper *Sp
// assert unreachable
return
}
- entry := &sparseTreeMapEntry{index: blockIndex, data: x}
+ // sp will be the sparse parent in this sparse tree (nearest ancestor in the larger tree that is also in this sparse tree)
+ sp := m.findEntry(b, adjust, helper)
+ entry := &sparseTreeMapEntry{index: blockIndex, block: b, data: x, sparseParent: sp, adjust: adjust}
+
right := blockIndex.exit - adjust
_ = rbtree.Insert(right, entry)
left := blockIndex.entry + adjust
_ = rbtree.Insert(left, entry)
+
+ // This newly inserted block may now be the sparse parent of some existing nodes (the new sparse children of this block)
+ // Iterate over nodes bracketed by this new node to correct their parent, but not over the proper sparse descendants of those nodes.
+ _, d := rbtree.Lub(left) // Lub (not EQ) of left is either right or a sparse child
+ for tme := d.(*sparseTreeMapEntry); tme != entry; tme = d.(*sparseTreeMapEntry) {
+ tme.sparseParent = entry
+ // all descendants of tme are unchanged;
+ // next sparse sibling (or right-bracketing sparse parent == entry) is first node after tme.index.exit - tme.adjust
+ _, d = rbtree.Lub(tme.index.exit - tme.adjust)
+ }
}
// Find returns the definition visible from block b, or nil if none can be found.
@@ -118,45 +139,41 @@ func (m *SparseTreeMap) Insert(b *Block, adjust int32, x interface{}, helper *Sp
//
// Another way to think of this is that Find searches for inputs, Insert defines outputs.
func (m *SparseTreeMap) Find(b *Block, adjust int32, helper *SparseTreeHelper) interface{} {
+ v := m.findEntry(b, adjust, helper)
+ if v == nil {
+ return nil
+ }
+ return v.data
+}
+
+func (m *SparseTreeMap) findEntry(b *Block, adjust int32, helper *SparseTreeHelper) *sparseTreeMapEntry {
rbtree := (*RBTint32)(m)
if rbtree == nil {
return nil
}
blockIndex := &helper.Sdom[b.ID]
+
+ // The Glb (not EQ) of this probe is either the entry-indexed end of a sparse parent
+ // or the exit-indexed end of a sparse sibling
_, v := rbtree.Glb(blockIndex.entry + adjust)
- for v != nil {
- otherEntry := v.(*sparseTreeMapEntry)
- otherIndex := otherEntry.index
- // Two cases -- either otherIndex brackets blockIndex,
- // or it doesn't.
- //
- // Note that if otherIndex and blockIndex are
- // the same block, then the glb test only passed
- // because the definition is "before",
- // i.e., k == blockIndex.entry-1
- // allowing equality is okay on the blocks check.
- if otherIndex.exit >= blockIndex.exit {
- // bracketed.
- return otherEntry.data
+
+ if v == nil {
+ return nil
+ }
+
+ otherEntry := v.(*sparseTreeMapEntry)
+ if otherEntry.index.exit >= blockIndex.exit { // otherEntry exit after blockIndex exit; therefore, brackets
+ return otherEntry
+ }
+ // otherEntry is a sparse Sibling, and shares the same sparse parent (nearest ancestor within larger tree)
+ sp := otherEntry.sparseParent
+ if sp != nil {
+ if sp.index.exit < blockIndex.exit { // no ancestor found
+ return nil
}
- // In the not-bracketed case, we could memoize the results of
- // walking up the tree, but for now we won't.
- // Memoize plan is to take the gap (inclusive)
- // from otherIndex.exit+1 to blockIndex.entry-1
- // and insert it into this or a second tree.
- // Said tree would then need adjusting whenever
- // an insertion occurred.
-
- // Expectation is that per-variable tree is sparse,
- // therefore probe siblings instead of climbing up.
- // Note that each sibling encountered in this walk
- // to find a defining ancestor shares that ancestor
- // because the walk skips over the interior -- each
- // Glb will be an exit, and the iteration is to the
- // Glb of the entry.
- _, v = rbtree.Glb(otherIndex.entry - 1)
+ return sp
}
- return nil // nothing found
+ return nil
}
func (m *SparseTreeMap) String() string {
@@ -165,5 +182,8 @@ func (m *SparseTreeMap) String() string {
}
func (e *sparseTreeMapEntry) String() string {
- return fmt.Sprintf("index=%v, data=%v", e.index, e.data)
+ if e == nil {
+ return "nil"
+ }
+ return fmt.Sprintf("(index=%v, block=%v, data=%v)->%v", e.index, e.block, e.data, e.sparseParent)
}
diff --git a/src/cmd/compile/internal/ssa/tighten.go b/src/cmd/compile/internal/ssa/tighten.go
index b722f108e5..5be55ac858 100644
--- a/src/cmd/compile/internal/ssa/tighten.go
+++ b/src/cmd/compile/internal/ssa/tighten.go
@@ -92,3 +92,26 @@ func tighten(f *Func) {
}
}
}
+
+// phiTighten moves constants closer to phi users.
+// This pass avoids having lots of constants live for lots of the program.
+// See issue 16407.
+func phiTighten(f *Func) {
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ if v.Op != OpPhi {
+ continue
+ }
+ for i, a := range v.Args {
+ if !a.rematerializeable() {
+ continue // not a constant we can move around
+ }
+ if a.Block == b.Preds[i].b {
+ continue // already in the right place
+ }
+ // Make a copy of a, put in predecessor block.
+ v.SetArg(i, a.copyInto(b.Preds[i].b))
+ }
+ }
+ }
+}
diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go
index 5cb1ec990e..453a3d53aa 100644
--- a/src/cmd/doc/doc_test.go
+++ b/src/cmd/doc/doc_test.go
@@ -61,6 +61,7 @@ var tests = []test{
`var ExportedVariable = 1`, // Simple variable.
`var VarOne = 1`, // First entry in variable block.
`func ExportedFunc\(a int\) bool`, // Function.
+ `func ReturnUnexported\(\) unexportedType`, // Function with unexported return type.
`type ExportedType struct { ... }`, // Exported type.
`const ExportedTypedConstant ExportedType = iota`, // Typed constant.
`const ExportedTypedConstant_unexported unexportedType`, // Typed constant, exported for unexported type.
@@ -89,9 +90,10 @@ var tests = []test{
"full package with u",
[]string{`-u`, p},
[]string{
- `const ExportedConstant = 1`, // Simple constant.
- `const internalConstant = 2`, // Internal constants.
- `func internalFunc\(a int\) bool`, // Internal functions.
+ `const ExportedConstant = 1`, // Simple constant.
+ `const internalConstant = 2`, // Internal constants.
+ `func internalFunc\(a int\) bool`, // Internal functions.
+ `func ReturnUnexported\(\) unexportedType`, // Function with unexported return type.
},
[]string{
`Comment about exported constant`, // No comment for simple constant.
@@ -221,6 +223,7 @@ var tests = []test{
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
`const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
`func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor.
+ `io.Reader.*Comment on line with embedded Reader.`,
},
[]string{
`unexportedField`, // No unexported field.
@@ -228,6 +231,7 @@ var tests = []test{
`Comment about exported method.`, // No comment about exported method.
`unexportedMethod`, // No unexported method.
`unexportedTypedConstant`, // No unexported constant.
+ `error`, // No embedded error.
},
},
// Type -u with unexported fields.
@@ -243,6 +247,8 @@ var tests = []test{
`\*ExportedEmbeddedType.*Comment on line with exported embedded \*field.`,
`unexportedType.*Comment on line with unexported embedded field.`,
`\*unexportedType.*Comment on line with unexported embedded \*field.`,
+ `io.Reader.*Comment on line with embedded Reader.`,
+ `error.*Comment on line with embedded error.`,
`func \(ExportedType\) unexportedMethod\(a int\) bool`,
`unexportedTypedConstant`,
},
@@ -274,6 +280,8 @@ var tests = []test{
`type ExportedInterface interface`, // Interface definition.
`Comment before exported method.*\n.*ExportedMethod\(\)` +
`.*Comment on line with exported method`,
+ `io.Reader.*Comment on line with embedded Reader.`,
+ `error.*Comment on line with embedded error.`,
`Has unexported methods`,
},
[]string{
@@ -293,6 +301,8 @@ var tests = []test{
`Comment before exported method.*\n.*ExportedMethod\(\)` +
`.*Comment on line with exported method`,
`unexportedMethod\(\).*Comment on line with unexported method.`,
+ `io.Reader.*Comment on line with embedded Reader.`,
+ `error.*Comment on line with embedded error.`,
},
[]string{
`Has unexported methods`,
diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go
index efd681d514..defddfd74a 100644
--- a/src/cmd/doc/pkg.go
+++ b/src/cmd/doc/pkg.go
@@ -317,7 +317,9 @@ func (pkg *Package) funcSummary(funcs []*doc.Func, showConstructors bool) {
isConstructor = make(map[*doc.Func]bool)
for _, typ := range pkg.doc.Types {
for _, constructor := range typ.Funcs {
- isConstructor[constructor] = true
+ if isExported(typ.Name) {
+ isConstructor[constructor] = true
+ }
}
}
}
@@ -494,14 +496,19 @@ func trimUnexportedElems(spec *ast.TypeSpec) {
}
switch typ := spec.Type.(type) {
case *ast.StructType:
- typ.Fields = trimUnexportedFields(typ.Fields, "fields")
+ typ.Fields = trimUnexportedFields(typ.Fields, false)
case *ast.InterfaceType:
- typ.Methods = trimUnexportedFields(typ.Methods, "methods")
+ typ.Methods = trimUnexportedFields(typ.Methods, true)
}
}
// trimUnexportedFields returns the field list trimmed of unexported fields.
-func trimUnexportedFields(fields *ast.FieldList, what string) *ast.FieldList {
+func trimUnexportedFields(fields *ast.FieldList, isInterface bool) *ast.FieldList {
+ what := "methods"
+ if !isInterface {
+ what = "fields"
+ }
+
trimmed := false
list := make([]*ast.Field, 0, len(fields.List))
for _, field := range fields.List {
@@ -511,12 +518,23 @@ func trimUnexportedFields(fields *ast.FieldList, what string) *ast.FieldList {
// Nothing else is allowed.
switch ident := field.Type.(type) {
case *ast.Ident:
+ if isInterface && ident.Name == "error" && ident.Obj == nil {
+ // For documentation purposes, we consider the builtin error
+ // type special when embedded in an interface, such that it
+ // always gets shown publicly.
+ list = append(list, field)
+ continue
+ }
names = []*ast.Ident{ident}
case *ast.StarExpr:
// Must have the form *identifier.
- if ident, ok := ident.X.(*ast.Ident); ok {
+ // This is only valid on embedded types in structs.
+ if ident, ok := ident.X.(*ast.Ident); ok && !isInterface {
names = []*ast.Ident{ident}
}
+ case *ast.SelectorExpr:
+ // An embedded type may refer to a type in another package.
+ names = []*ast.Ident{ident.Sel}
}
if names == nil {
// Can only happen if AST is incorrect. Safe to continue with a nil list.
diff --git a/src/cmd/doc/testdata/pkg.go b/src/cmd/doc/testdata/pkg.go
index 5f79414b33..6a52ac2f65 100644
--- a/src/cmd/doc/testdata/pkg.go
+++ b/src/cmd/doc/testdata/pkg.go
@@ -66,6 +66,8 @@ type ExportedType struct {
*ExportedEmbeddedType // Comment on line with exported embedded *field.
unexportedType // Comment on line with unexported embedded field.
*unexportedType // Comment on line with unexported embedded *field.
+ io.Reader // Comment on line with embedded Reader.
+ error // Comment on line with embedded error.
}
// Comment about exported method.
@@ -96,6 +98,8 @@ type ExportedInterface interface {
// Comment before exported method.
ExportedMethod() // Comment on line with exported method.
unexportedMethod() // Comment on line with unexported method.
+ io.Reader // Comment on line with embedded Reader.
+ error // Comment on line with embedded error.
}
// Comment about unexported type.
@@ -119,3 +123,6 @@ const unexportedTypedConstant unexportedType = 1 // In a separate section to tes
// For case matching.
const CaseMatch = 1
const Casematch = 2
+
+func ReturnUnexported() unexportedType { return 0 }
+func ReturnExported() ExportedType { return ExportedType{} }
diff --git a/src/compress/flate/deflate.go b/src/compress/flate/deflate.go
index 8a085ba347..3e4dc7b57e 100644
--- a/src/compress/flate/deflate.go
+++ b/src/compress/flate/deflate.go
@@ -15,7 +15,17 @@ const (
BestSpeed = 1
BestCompression = 9
DefaultCompression = -1
- HuffmanOnly = -2 // Disables match search and only does Huffman entropy reduction.
+
+ // HuffmanOnly disables Lempel-Ziv match searching and only performs Huffman
+ // entropy encoding. This mode is useful in compressing data that has
+ // already been compressed with an LZ style algorithm (e.g. Snappy or LZ4)
+ // that lacks an entropy encoder. Compression gains are achieved when
+ // certain bytes in the input stream occur more frequently than others.
+ //
+ // Note that HuffmanOnly produces a compressed output that is
+ // RFC 1951 compliant. That is, any valid DEFLATE decompressor will
+ // continue to be able to decompress this output.
+ HuffmanOnly = -2
)
const (
@@ -644,7 +654,6 @@ func (d *compressor) close() error {
// a very fast compression for all types of input, but sacrificing considerable
// compression efficiency.
//
-//
// If level is in the range [-2, 9] then the error returned will be nil.
// Otherwise the error returned will be non-nil.
func NewWriter(w io.Writer, level int) (*Writer, error) {
diff --git a/src/context/context_test.go b/src/context/context_test.go
index 90e78e57ec..cf182110fb 100644
--- a/src/context/context_test.go
+++ b/src/context/context_test.go
@@ -255,6 +255,12 @@ func TestDeadline(t *testing.T) {
o = otherContext{c}
c, _ = WithDeadline(o, time.Now().Add(4*time.Second))
testDeadline(c, "WithDeadline+otherContext+WithDeadline", 2*time.Second, t)
+
+ c, _ = WithDeadline(Background(), time.Now().Add(-time.Millisecond))
+ testDeadline(c, "WithDeadline+inthepast", time.Second, t)
+
+ c, _ = WithDeadline(Background(), time.Now())
+ testDeadline(c, "WithDeadline+now", time.Second, t)
}
func TestTimeout(t *testing.T) {
diff --git a/src/crypto/x509/root_cgo_darwin.go b/src/crypto/x509/root_cgo_darwin.go
index 0e2fb357ee..a4b33c7660 100644
--- a/src/crypto/x509/root_cgo_darwin.go
+++ b/src/crypto/x509/root_cgo_darwin.go
@@ -10,9 +10,65 @@ package x509
#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
#cgo LDFLAGS: -framework CoreFoundation -framework Security
+#include <errno.h>
+#include <sys/sysctl.h>
+
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
+// FetchPEMRoots_MountainLion is the version of FetchPEMRoots from Go 1.6
+// which still works on OS X 10.8 (Mountain Lion).
+// It lacks support for admin & user cert domains.
+// See golang.org/issue/16473
+int FetchPEMRoots_MountainLion(CFDataRef *pemRoots) {
+ if (pemRoots == NULL) {
+ return -1;
+ }
+ CFArrayRef certs = NULL;
+ OSStatus err = SecTrustCopyAnchorCertificates(&certs);
+ if (err != noErr) {
+ return -1;
+ }
+ CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ int i, ncerts = CFArrayGetCount(certs);
+ for (i = 0; i < ncerts; i++) {
+ CFDataRef data = NULL;
+ SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
+ if (cert == NULL) {
+ continue;
+ }
+ // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
+ // Once we support weak imports via cgo we should prefer that, and fall back to this
+ // for older systems.
+ err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+ if (err != noErr) {
+ continue;
+ }
+ if (data != NULL) {
+ CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
+ CFRelease(data);
+ }
+ }
+ CFRelease(certs);
+ *pemRoots = combinedData;
+ return 0;
+}
+
+// useOldCode reports whether the running machine is OS X 10.8 Mountain Lion
+// or older. We only support Mountain Lion and higher, but we'll at least try our
+// best on older machines and continue to use the old code path.
+//
+// See golang.org/issue/16473
+int useOldCode() {
+ char str[256];
+ size_t size = sizeof(str);
+ memset(str, 0, size);
+ sysctlbyname("kern.osrelease", str, &size, NULL, 0);
+ // OS X 10.8 is osrelease "12.*", 10.7 is 11.*, 10.6 is 10.*.
+ // We never supported things before that.
+ return memcmp(str, "12.", 3) == 0 || memcmp(str, "11.", 3) == 0 || memcmp(str, "10.", 3) == 0;
+}
+
// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
//
// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
@@ -21,6 +77,10 @@ package x509
// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
// we've consumed its content.
int FetchPEMRoots(CFDataRef *pemRoots) {
+ if (useOldCode()) {
+ return FetchPEMRoots_MountainLion(pemRoots);
+ }
+
// Get certificates from all domains, not just System, this lets
// the user add CAs to their "login" keychain, and Admins to add
// to the "System" keychain
diff --git a/src/fmt/scan.go b/src/fmt/scan.go
index 08b0bf96a6..fdf419795d 100644
--- a/src/fmt/scan.go
+++ b/src/fmt/scan.go
@@ -325,9 +325,9 @@ func (r *readRune) readByte() (b byte, err error) {
r.pending--
return
}
- _, err = r.reader.Read(r.pendBuf[:1])
- if err != nil {
- return
+ n, err := io.ReadFull(r.reader, r.pendBuf[:1])
+ if n != 1 {
+ return 0, err
}
return r.pendBuf[0], err
}
diff --git a/src/fmt/scan_test.go b/src/fmt/scan_test.go
index 364d4fb42a..e36b62e78a 100644
--- a/src/fmt/scan_test.go
+++ b/src/fmt/scan_test.go
@@ -15,6 +15,7 @@ import (
"regexp"
"strings"
"testing"
+ "testing/iotest"
"unicode/utf8"
)
@@ -118,20 +119,6 @@ func (s *IntString) Scan(state ScanState, verb rune) error {
var intStringVal IntString
-// myStringReader implements Read but not ReadRune, allowing us to test our readRune wrapper
-// type that creates something that can read runes given only Read().
-type myStringReader struct {
- r *strings.Reader
-}
-
-func (s *myStringReader) Read(p []byte) (n int, err error) {
- return s.r.Read(p)
-}
-
-func newReader(s string) *myStringReader {
- return &myStringReader{strings.NewReader(s)}
-}
-
var scanTests = []ScanTest{
// Basic types
{"T\n", &boolVal, true}, // boolean test vals toggle to be sure they are written
@@ -363,25 +350,38 @@ var multiTests = []ScanfMultiTest{
{"%v%v", "FALSE23", args(&truth, &i), args(false, 23), ""},
}
-func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, error)) {
+var readers = []struct {
+ name string
+ f func(string) io.Reader
+}{
+ {"StringReader", func(s string) io.Reader {
+ return strings.NewReader(s)
+ }},
+ {"ReaderOnly", func(s string) io.Reader {
+ return struct{ io.Reader }{strings.NewReader(s)}
+ }},
+ {"OneByteReader", func(s string) io.Reader {
+ return iotest.OneByteReader(strings.NewReader(s))
+ }},
+ {"DataErrReader", func(s string) io.Reader {
+ return iotest.DataErrReader(strings.NewReader(s))
+ }},
+}
+
+func testScan(t *testing.T, f func(string) io.Reader, scan func(r io.Reader, a ...interface{}) (int, error)) {
for _, test := range scanTests {
- var r io.Reader
- if name == "StringReader" {
- r = strings.NewReader(test.text)
- } else {
- r = newReader(test.text)
- }
+ r := f(test.text)
n, err := scan(r, test.in)
if err != nil {
m := ""
if n > 0 {
m = Sprintf(" (%d fields ok)", n)
}
- t.Errorf("%s got error scanning %q: %s%s", name, test.text, err, m)
+ t.Errorf("got error scanning %q: %s%s", test.text, err, m)
continue
}
if n != 1 {
- t.Errorf("%s count error on entry %q: got %d", name, test.text, n)
+ t.Errorf("count error on entry %q: got %d", test.text, n)
continue
}
// The incoming value may be a pointer
@@ -391,25 +391,25 @@ func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}
}
val := v.Interface()
if !reflect.DeepEqual(val, test.out) {
- t.Errorf("%s scanning %q: expected %#v got %#v, type %T", name, test.text, test.out, val, val)
+ t.Errorf("scanning %q: expected %#v got %#v, type %T", test.text, test.out, val, val)
}
}
}
func TestScan(t *testing.T) {
- testScan("StringReader", t, Fscan)
-}
-
-func TestMyReaderScan(t *testing.T) {
- testScan("myStringReader", t, Fscan)
+ for _, r := range readers {
+ t.Run(r.name, func(t *testing.T) {
+ testScan(t, r.f, Fscan)
+ })
+ }
}
func TestScanln(t *testing.T) {
- testScan("StringReader", t, Fscanln)
-}
-
-func TestMyReaderScanln(t *testing.T) {
- testScan("myStringReader", t, Fscanln)
+ for _, r := range readers {
+ t.Run(r.name, func(t *testing.T) {
+ testScan(t, r.f, Fscanln)
+ })
+ }
}
func TestScanf(t *testing.T) {
@@ -500,15 +500,10 @@ func TestInf(t *testing.T) {
}
}
-func testScanfMulti(name string, t *testing.T) {
+func testScanfMulti(t *testing.T, f func(string) io.Reader) {
sliceType := reflect.TypeOf(make([]interface{}, 1))
for _, test := range multiTests {
- var r io.Reader
- if name == "StringReader" {
- r = strings.NewReader(test.text)
- } else {
- r = newReader(test.text)
- }
+ r := f(test.text)
n, err := Fscanf(r, test.format, test.in...)
if err != nil {
if test.err == "" {
@@ -539,11 +534,11 @@ func testScanfMulti(name string, t *testing.T) {
}
func TestScanfMulti(t *testing.T) {
- testScanfMulti("StringReader", t)
-}
-
-func TestMyReaderScanfMulti(t *testing.T) {
- testScanfMulti("myStringReader", t)
+ for _, r := range readers {
+ t.Run(r.name, func(t *testing.T) {
+ testScanfMulti(t, r.f)
+ })
+ }
}
func TestScanMultiple(t *testing.T) {
@@ -818,20 +813,10 @@ func TestMultiLine(t *testing.T) {
}
}
-// simpleReader is a strings.Reader that implements only Read, not ReadRune.
-// Good for testing readahead.
-type simpleReader struct {
- sr *strings.Reader
-}
-
-func (s *simpleReader) Read(b []byte) (n int, err error) {
- return s.sr.Read(b)
-}
-
// TestLineByLineFscanf tests that Fscanf does not read past newline. Issue
// 3481.
func TestLineByLineFscanf(t *testing.T) {
- r := &simpleReader{strings.NewReader("1\n2\n")}
+ r := struct{ io.Reader }{strings.NewReader("1\n2\n")}
var i, j int
n, err := Fscanf(r, "%v\n", &i)
if n != 1 || err != nil {
@@ -1000,7 +985,7 @@ func BenchmarkScanRecursiveIntReaderWrapper(b *testing.B) {
ints := makeInts(intCount)
var r RecursiveInt
for i := b.N - 1; i >= 0; i-- {
- buf := newReader(string(ints))
+ buf := struct{ io.Reader }{strings.NewReader(string(ints))}
b.StartTimer()
Fscan(buf, &r)
b.StopTimer()
diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go
index c9f906a7da..198a649b15 100644
--- a/src/go/build/build_test.go
+++ b/src/go/build/build_test.go
@@ -303,11 +303,11 @@ func TestImportVendor(t *testing.T) {
testenv.MustHaveGoBuild(t) // really must just have source
ctxt := Default
ctxt.GOPATH = ""
- p, err := ctxt.Import("golang.org/x/net/http2/hpack", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
+ p, err := ctxt.Import("golang_org/x/net/http2/hpack", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
if err != nil {
- t.Fatalf("cannot find vendored golang.org/x/net/http2/hpack from net/http directory: %v", err)
+ t.Fatalf("cannot find vendored golang_org/x/net/http2/hpack from net/http directory: %v", err)
}
- want := "vendor/golang.org/x/net/http2/hpack"
+ want := "vendor/golang_org/x/net/http2/hpack"
if p.ImportPath != want {
t.Fatalf("Import succeeded but found %q, want %q", p.ImportPath, want)
}
@@ -333,7 +333,7 @@ func TestImportVendorParentFailure(t *testing.T) {
ctxt := Default
ctxt.GOPATH = ""
// This import should fail because the vendor/golang.org/x/net/http2 directory has no source code.
- p, err := ctxt.Import("golang.org/x/net/http2", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
+ p, err := ctxt.Import("golang_org/x/net/http2", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
if err == nil {
t.Fatalf("found empty parent in %s", p.Dir)
}
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 335e774a7c..5b2529129c 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -297,7 +297,7 @@ var pkgDeps = map[string][]string{
"context", "math/rand", "os", "sort", "syscall", "time",
"internal/nettrace",
"internal/syscall/windows", "internal/singleflight", "internal/race",
- "golang.org/x/net/route",
+ "golang_org/x/net/route",
},
// NET enables use of basic network-related packages.
@@ -378,8 +378,8 @@ var pkgDeps = map[string][]string{
"context", "compress/gzip", "container/list", "crypto/tls",
"mime/multipart", "runtime/debug",
"net/http/internal",
- "golang.org/x/net/http2/hpack",
- "golang.org/x/net/lex/httplex",
+ "golang_org/x/net/http2/hpack",
+ "golang_org/x/net/lex/httplex",
"internal/nettrace",
"net/http/httptrace",
},
@@ -443,7 +443,7 @@ func listStdPkgs(goroot string) ([]string, error) {
}
name := filepath.ToSlash(path[len(src):])
- if name == "builtin" || name == "cmd" || strings.Contains(name, ".") {
+ if name == "builtin" || name == "cmd" || strings.Contains(name, "golang_org") {
return filepath.SkipDir
}
diff --git a/src/net/dial_test.go b/src/net/dial_test.go
index 9fe507e901..8b21e6b088 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -695,6 +695,11 @@ func TestDialerLocalAddr(t *testing.T) {
}
func TestDialerDualStack(t *testing.T) {
+ // This test is known to be flaky. Don't frighten regular
+ // users about it; only fail on the build dashboard.
+ if testenv.Builder() == "" {
+ testenv.SkipFlaky(t, 13324)
+ }
if !supportsIPv4 || !supportsIPv6 {
t.Skip("both IPv4 and IPv6 are required")
}
diff --git a/src/net/dial_unix_test.go b/src/net/dial_unix_test.go
new file mode 100644
index 0000000000..4705254728
--- /dev/null
+++ b/src/net/dial_unix_test.go
@@ -0,0 +1,108 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package net
+
+import (
+ "context"
+ "syscall"
+ "testing"
+ "time"
+)
+
+// Issue 16523
+func TestDialContextCancelRace(t *testing.T) {
+ oldConnectFunc := connectFunc
+ oldGetsockoptIntFunc := getsockoptIntFunc
+ oldTestHookCanceledDial := testHookCanceledDial
+ defer func() {
+ connectFunc = oldConnectFunc
+ getsockoptIntFunc = oldGetsockoptIntFunc
+ testHookCanceledDial = oldTestHookCanceledDial
+ }()
+
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ listenerDone := make(chan struct{})
+ go func() {
+ defer close(listenerDone)
+ c, err := ln.Accept()
+ if err == nil {
+ c.Close()
+ }
+ }()
+ defer func() { <-listenerDone }()
+ defer ln.Close()
+
+ sawCancel := make(chan bool, 1)
+ testHookCanceledDial = func() {
+ sawCancel <- true
+ }
+
+ ctx, cancelCtx := context.WithCancel(context.Background())
+
+ connectFunc = func(fd int, addr syscall.Sockaddr) error {
+ err := oldConnectFunc(fd, addr)
+ t.Logf("connect(%d, addr) = %v", fd, err)
+ if err == nil {
+ // On some operating systems, localhost
+ // connects _sometimes_ succeed immediately.
+ // Prevent that, so we exercise the code path
+ // we're interested in testing. This seems
+ // harmless. It makes FreeBSD 10.10 work when
+ // run with many iterations. It failed about
+ // half the time previously.
+ return syscall.EINPROGRESS
+ }
+ return err
+ }
+
+ getsockoptIntFunc = func(fd, level, opt int) (val int, err error) {
+ val, err = oldGetsockoptIntFunc(fd, level, opt)
+ t.Logf("getsockoptIntFunc(%d, %d, %d) = (%v, %v)", fd, level, opt, val, err)
+ if level == syscall.SOL_SOCKET && opt == syscall.SO_ERROR && err == nil && val == 0 {
+ t.Logf("canceling context")
+
+ // Cancel the context at just the moment which
+ // caused the race in issue 16523.
+ cancelCtx()
+
+ // And wait for the "interrupter" goroutine to
+ // cancel the dial by messing with its write
+ // timeout before returning.
+ select {
+ case <-sawCancel:
+ t.Logf("saw cancel")
+ case <-time.After(5 * time.Second):
+ t.Errorf("didn't see cancel after 5 seconds")
+ }
+ }
+ return
+ }
+
+ var d Dialer
+ c, err := d.DialContext(ctx, "tcp", ln.Addr().String())
+ if err == nil {
+ c.Close()
+ t.Fatal("unexpected successful dial; want context canceled error")
+ }
+
+ select {
+ case <-ctx.Done():
+ case <-time.After(5 * time.Second):
+ t.Fatal("expected context to be canceled")
+ }
+
+ oe, ok := err.(*OpError)
+ if !ok || oe.Op != "dial" {
+ t.Fatalf("Dial error = %#v; want dial *OpError", err)
+ }
+ if oe.Err != ctx.Err() {
+ t.Errorf("DialContext = (%v, %v); want OpError with error %v", c, err, ctx.Err())
+ }
+}
diff --git a/src/net/fd_unix.go b/src/net/fd_unix.go
index 0f80bc79ac..11dde76977 100644
--- a/src/net/fd_unix.go
+++ b/src/net/fd_unix.go
@@ -64,7 +64,7 @@ func (fd *netFD) name() string {
return fd.net + ":" + ls + "->" + rs
}
-func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
+func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret error) {
// Do not need to call fd.writeLock here,
// because fd is not yet accessible to user,
// so no concurrent operations are possible.
@@ -101,21 +101,44 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
defer fd.setWriteDeadline(noDeadline)
}
- // Wait for the goroutine converting context.Done into a write timeout
- // to exist, otherwise our caller might cancel the context and
- // cause fd.setWriteDeadline(aLongTimeAgo) to cancel a successful dial.
- done := make(chan bool) // must be unbuffered
- defer func() { done <- true }()
- go func() {
- select {
- case <-ctx.Done():
- // Force the runtime's poller to immediately give
- // up waiting for writability.
- fd.setWriteDeadline(aLongTimeAgo)
- <-done
- case <-done:
- }
- }()
+ // Start the "interrupter" goroutine, if this context might be canceled.
+ // (The background context cannot)
+ //
+ // The interrupter goroutine waits for the context to be done and
+ // interrupts the dial (by altering the fd's write deadline, which
+ // wakes up waitWrite).
+ if ctx != context.Background() {
+ // Wait for the interrupter goroutine to exit before returning
+ // from connect.
+ done := make(chan struct{})
+ interruptRes := make(chan error)
+ defer func() {
+ close(done)
+ if ctxErr := <-interruptRes; ctxErr != nil && ret == nil {
+ // The interrupter goroutine called setWriteDeadline,
+ // but the connect code below had returned from
+ // waitWrite already and did a successful connect (ret
+ // == nil). Because we've now poisoned the connection
+ // by making it unwritable, don't return a successful
+ // dial. This was issue 16523.
+ ret = ctxErr
+ fd.Close() // prevent a leak
+ }
+ }()
+ go func() {
+ select {
+ case <-ctx.Done():
+ // Force the runtime's poller to immediately give up
+ // waiting for writability, unblocking waitWrite
+ // below.
+ fd.setWriteDeadline(aLongTimeAgo)
+ testHookCanceledDial()
+ interruptRes <- ctx.Err()
+ case <-done:
+ interruptRes <- nil
+ }
+ }()
+ }
for {
// Performing multiple connect system calls on a
diff --git a/src/net/hook_unix.go b/src/net/hook_unix.go
index 361ca5980c..cf52567fcf 100644
--- a/src/net/hook_unix.go
+++ b/src/net/hook_unix.go
@@ -9,7 +9,8 @@ package net
import "syscall"
var (
- testHookDialChannel = func() {} // see golang.org/issue/5349
+ testHookDialChannel = func() {} // for golang.org/issue/5349
+ testHookCanceledDial = func() {} // for golang.org/issue/16523
// Placeholders for socket system calls.
socketFunc func(int, int, int) (int, error) = syscall.Socket
diff --git a/src/net/http/cgi/host.go b/src/net/http/cgi/host.go
index 2eea64334b..58e9f7132a 100644
--- a/src/net/http/cgi/host.go
+++ b/src/net/http/cgi/host.go
@@ -153,6 +153,10 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
for k, v := range req.Header {
k = strings.Map(upperCaseAndUnderscore, k)
+ if k == "PROXY" {
+ // See Issue 16405
+ continue
+ }
joinStr := ", "
if k == "COOKIE" {
joinStr = "; "
diff --git a/src/net/http/cgi/host_test.go b/src/net/http/cgi/host_test.go
index 70c5aff5e2..11213349a7 100644
--- a/src/net/http/cgi/host_test.go
+++ b/src/net/http/cgi/host_test.go
@@ -35,15 +35,18 @@ func newRequest(httpreq string) *http.Request {
return req
}
-func runCgiTest(t *testing.T, h *Handler, httpreq string, expectedMap map[string]string) *httptest.ResponseRecorder {
+func runCgiTest(t *testing.T, h *Handler,
+ httpreq string,
+ expectedMap map[string]string, checks ...func(reqInfo map[string]string)) *httptest.ResponseRecorder {
rw := httptest.NewRecorder()
req := newRequest(httpreq)
h.ServeHTTP(rw, req)
- runResponseChecks(t, rw, expectedMap)
+ runResponseChecks(t, rw, expectedMap, checks...)
return rw
}
-func runResponseChecks(t *testing.T, rw *httptest.ResponseRecorder, expectedMap map[string]string) {
+func runResponseChecks(t *testing.T, rw *httptest.ResponseRecorder,
+ expectedMap map[string]string, checks ...func(reqInfo map[string]string)) {
// Make a map to hold the test map that the CGI returns.
m := make(map[string]string)
m["_body"] = rw.Body.String()
@@ -81,6 +84,9 @@ readlines:
t.Errorf("for key %q got %q; expected %q", key, got, expected)
}
}
+ for _, check := range checks {
+ check(m)
+ }
}
var cgiTested, cgiWorks bool
@@ -236,6 +242,31 @@ func TestDupHeaders(t *testing.T) {
expectedMap)
}
+// Issue 16405: CGI+http.Transport differing uses of HTTP_PROXY.
+// Verify we don't set the HTTP_PROXY environment variable.
+// Hope nobody was depending on it. It's not a known header, though.
+func TestDropProxyHeader(t *testing.T) {
+ check(t)
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ }
+ expectedMap := map[string]string{
+ "env-REQUEST_URI": "/myscript/bar?a=b",
+ "env-SCRIPT_FILENAME": "testdata/test.cgi",
+ "env-HTTP_X_FOO": "a",
+ }
+ runCgiTest(t, h, "GET /myscript/bar?a=b HTTP/1.0\n"+
+ "X-Foo: a\n"+
+ "Proxy: should_be_stripped\n"+
+ "Host: example.com\n\n",
+ expectedMap,
+ func(reqInfo map[string]string) {
+ if v, ok := reqInfo["env-HTTP_PROXY"]; ok {
+ t.Errorf("HTTP_PROXY = %q; should be absent", v)
+ }
+ })
+}
+
func TestPathInfoNoRoot(t *testing.T) {
check(t)
h := &Handler{
diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
index 352a41d414..cd66c0960e 100644
--- a/src/net/http/h2_bundle.go
+++ b/src/net/http/h2_bundle.go
@@ -41,8 +41,8 @@ import (
"sync"
"time"
- "golang.org/x/net/http2/hpack"
- "golang.org/x/net/lex/httplex"
+ "golang_org/x/net/http2/hpack"
+ "golang_org/x/net/lex/httplex"
)
// ClientConnPool manages a pool of HTTP/2 client connections.
@@ -85,7 +85,16 @@ const (
http2noDialOnMiss = false
)
-func (p *http2clientConnPool) getClientConn(_ *Request, addr string, dialOnMiss bool) (*http2ClientConn, error) {
+func (p *http2clientConnPool) getClientConn(req *Request, addr string, dialOnMiss bool) (*http2ClientConn, error) {
+ if http2isConnectionCloseRequest(req) && dialOnMiss {
+ // It gets its own connection.
+ const singleUse = true
+ cc, err := p.t.dialClientConn(addr, singleUse)
+ if err != nil {
+ return nil, err
+ }
+ return cc, nil
+ }
p.mu.Lock()
for _, cc := range p.conns[addr] {
if cc.CanTakeNewRequest() {
@@ -128,7 +137,8 @@ func (p *http2clientConnPool) getStartDialLocked(addr string) *http2dialCall {
// run in its own goroutine.
func (c *http2dialCall) dial(addr string) {
- c.res, c.err = c.p.t.dialClientConn(addr)
+ const singleUse = false // shared conn
+ c.res, c.err = c.p.t.dialClientConn(addr, singleUse)
close(c.done)
c.p.mu.Lock()
@@ -1105,6 +1115,7 @@ func http2parseDataFrame(fh http2FrameHeader, payload []byte) (http2Frame, error
var (
http2errStreamID = errors.New("invalid stream ID")
http2errDepStreamID = errors.New("invalid dependent stream ID")
+ http2errPadLength = errors.New("pad length too large")
)
func http2validStreamIDOrZero(streamID uint32) bool {
@@ -1118,18 +1129,40 @@ func http2validStreamID(streamID uint32) bool {
// WriteData writes a DATA frame.
//
// It will perform exactly one Write to the underlying Writer.
-// It is the caller's responsibility to not call other Write methods concurrently.
+// It is the caller's responsibility not to violate the maximum frame size
+// and to not call other Write methods concurrently.
func (f *http2Framer) WriteData(streamID uint32, endStream bool, data []byte) error {
+ return f.WriteDataPadded(streamID, endStream, data, nil)
+}
+// WriteData writes a DATA frame with optional padding.
+//
+// If pad is nil, the padding bit is not sent.
+// The length of pad must not exceed 255 bytes.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility not to violate the maximum frame size
+// and to not call other Write methods concurrently.
+func (f *http2Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad []byte) error {
if !http2validStreamID(streamID) && !f.AllowIllegalWrites {
return http2errStreamID
}
+ if len(pad) > 255 {
+ return http2errPadLength
+ }
var flags http2Flags
if endStream {
flags |= http2FlagDataEndStream
}
+ if pad != nil {
+ flags |= http2FlagDataPadded
+ }
f.startWrite(http2FrameData, flags, streamID)
+ if pad != nil {
+ f.wbuf = append(f.wbuf, byte(len(pad)))
+ }
f.wbuf = append(f.wbuf, data...)
+ f.wbuf = append(f.wbuf, pad...)
return f.endWrite()
}
@@ -3803,6 +3836,9 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) {
}
delete(sc.streams, st.id)
if p := st.body; p != nil {
+
+ sc.sendWindowUpdate(nil, p.Len())
+
p.CloseWithError(err)
}
st.cw.Close()
@@ -3879,36 +3915,51 @@ func (sc *http2serverConn) processSettingInitialWindowSize(val uint32) error {
func (sc *http2serverConn) processData(f *http2DataFrame) error {
sc.serveG.check()
+ data := f.Data()
id := f.Header().StreamID
st, ok := sc.streams[id]
if !ok || st.state != http2stateOpen || st.gotTrailerHeader {
+ if sc.inflow.available() < int32(f.Length) {
+ return http2StreamError{id, http2ErrCodeFlowControl}
+ }
+
+ sc.inflow.take(int32(f.Length))
+ sc.sendWindowUpdate(nil, int(f.Length))
+
return http2StreamError{id, http2ErrCodeStreamClosed}
}
if st.body == nil {
panic("internal error: should have a body in this state")
}
- data := f.Data()
if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
return http2StreamError{id, http2ErrCodeStreamClosed}
}
- if len(data) > 0 {
+ if f.Length > 0 {
- if int(st.inflow.available()) < len(data) {
+ if st.inflow.available() < int32(f.Length) {
return http2StreamError{id, http2ErrCodeFlowControl}
}
- st.inflow.take(int32(len(data)))
- wrote, err := st.body.Write(data)
- if err != nil {
- return http2StreamError{id, http2ErrCodeStreamClosed}
+ st.inflow.take(int32(f.Length))
+
+ if len(data) > 0 {
+ wrote, err := st.body.Write(data)
+ if err != nil {
+ return http2StreamError{id, http2ErrCodeStreamClosed}
+ }
+ if wrote != len(data) {
+ panic("internal error: bad Writer")
+ }
+ st.bodyBytes += int64(len(data))
}
- if wrote != len(data) {
- panic("internal error: bad Writer")
+
+ if pad := int32(f.Length) - int32(len(data)); pad > 0 {
+ sc.sendWindowUpdate32(nil, pad)
+ sc.sendWindowUpdate32(st, pad)
}
- st.bodyBytes += int64(len(data))
}
if f.StreamEnded() {
st.endStream()
@@ -4919,27 +4970,29 @@ func (t *http2Transport) initConnPool() {
// ClientConn is the state of a single HTTP/2 client connection to an
// HTTP/2 server.
type http2ClientConn struct {
- t *http2Transport
- tconn net.Conn // usually *tls.Conn, except specialized impls
- tlsState *tls.ConnectionState // nil only for specialized impls
+ t *http2Transport
+ tconn net.Conn // usually *tls.Conn, except specialized impls
+ tlsState *tls.ConnectionState // nil only for specialized impls
+ singleUse bool // whether being used for a single http.Request
// readLoop goroutine fields:
readerDone chan struct{} // closed on error
readerErr error // set before readerDone is closed
- mu sync.Mutex // guards following
- cond *sync.Cond // hold mu; broadcast on flow/closed changes
- flow http2flow // our conn-level flow control quota (cs.flow is per stream)
- inflow http2flow // peer's conn-level flow control
- closed bool
- goAway *http2GoAwayFrame // if non-nil, the GoAwayFrame we received
- goAwayDebug string // goAway frame's debug data, retained as a string
- streams map[uint32]*http2clientStream // client-initiated
- nextStreamID uint32
- bw *bufio.Writer
- br *bufio.Reader
- fr *http2Framer
- lastActive time.Time
+ mu sync.Mutex // guards following
+ cond *sync.Cond // hold mu; broadcast on flow/closed changes
+ flow http2flow // our conn-level flow control quota (cs.flow is per stream)
+ inflow http2flow // peer's conn-level flow control
+ closed bool
+ wantSettingsAck bool // we sent a SETTINGS frame and haven't heard back
+ goAway *http2GoAwayFrame // if non-nil, the GoAwayFrame we received
+ goAwayDebug string // goAway frame's debug data, retained as a string
+ streams map[uint32]*http2clientStream // client-initiated
+ nextStreamID uint32
+ bw *bufio.Writer
+ br *bufio.Reader
+ fr *http2Framer
+ lastActive time.Time
// Settings from peer:
maxFrameSize uint32
@@ -5117,7 +5170,7 @@ func http2shouldRetryRequest(req *Request, err error) bool {
return err == http2errClientConnUnusable
}
-func (t *http2Transport) dialClientConn(addr string) (*http2ClientConn, error) {
+func (t *http2Transport) dialClientConn(addr string, singleUse bool) (*http2ClientConn, error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
@@ -5126,7 +5179,7 @@ func (t *http2Transport) dialClientConn(addr string) (*http2ClientConn, error) {
if err != nil {
return nil, err
}
- return t.NewClientConn(tconn)
+ return t.newClientConn(tconn, singleUse)
}
func (t *http2Transport) newTLSConfig(host string) *tls.Config {
@@ -5187,13 +5240,13 @@ func (t *http2Transport) expectContinueTimeout() time.Duration {
}
func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
+ return t.newClientConn(c, false)
+}
+
+func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2ClientConn, error) {
if http2VerboseLogs {
t.vlogf("http2: Transport creating client conn to %v", c.RemoteAddr())
}
- if _, err := c.Write(http2clientPreface); err != nil {
- t.vlogf("client preface write error: %v", err)
- return nil, err
- }
cc := &http2ClientConn{
t: t,
@@ -5204,6 +5257,8 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
initialWindowSize: 65535,
maxConcurrentStreams: 1000,
streams: make(map[uint32]*http2clientStream),
+ singleUse: singleUse,
+ wantSettingsAck: true,
}
cc.cond = sync.NewCond(&cc.mu)
cc.flow.add(int32(http2initialWindowSize))
@@ -5228,6 +5283,8 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
if max := t.maxHeaderListSize(); max != 0 {
initialSettings = append(initialSettings, http2Setting{ID: http2SettingMaxHeaderListSize, Val: max})
}
+
+ cc.bw.Write(http2clientPreface)
cc.fr.WriteSettings(initialSettings...)
cc.fr.WriteWindowUpdate(0, http2transportDefaultConnFlow)
cc.inflow.add(http2transportDefaultConnFlow + http2initialWindowSize)
@@ -5236,32 +5293,6 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
return nil, cc.werr
}
- f, err := cc.fr.ReadFrame()
- if err != nil {
- return nil, err
- }
- sf, ok := f.(*http2SettingsFrame)
- if !ok {
- return nil, fmt.Errorf("expected settings frame, got: %T", f)
- }
- cc.fr.WriteSettingsAck()
- cc.bw.Flush()
-
- sf.ForeachSetting(func(s http2Setting) error {
- switch s.ID {
- case http2SettingMaxFrameSize:
- cc.maxFrameSize = s.Val
- case http2SettingMaxConcurrentStreams:
- cc.maxConcurrentStreams = s.Val
- case http2SettingInitialWindowSize:
- cc.initialWindowSize = s.Val
- default:
-
- t.vlogf("Unhandled Setting: %v", s)
- }
- return nil
- })
-
go cc.readLoop()
return cc, nil
}
@@ -5288,6 +5319,9 @@ func (cc *http2ClientConn) CanTakeNewRequest() bool {
}
func (cc *http2ClientConn) canTakeNewRequestLocked() bool {
+ if cc.singleUse && cc.nextStreamID > 1 {
+ return false
+ }
return cc.goAway == nil && !cc.closed &&
int64(len(cc.streams)+1) < int64(cc.maxConcurrentStreams) &&
cc.nextStreamID < 2147483647
@@ -5494,22 +5528,26 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
bodyWritten := false
ctx := http2reqContext(req)
+ handleReadLoopResponse := func(re http2resAndError) (*Response, error) {
+ res := re.res
+ if re.err != nil || res.StatusCode > 299 {
+
+ bodyWriter.cancel()
+ cs.abortRequestBodyWrite(http2errStopReqBodyWrite)
+ }
+ if re.err != nil {
+ cc.forgetStreamID(cs.ID)
+ return nil, re.err
+ }
+ res.Request = req
+ res.TLS = cc.tlsState
+ return res, nil
+ }
+
for {
select {
case re := <-readLoopResCh:
- res := re.res
- if re.err != nil || res.StatusCode > 299 {
-
- bodyWriter.cancel()
- cs.abortRequestBodyWrite(http2errStopReqBodyWrite)
- }
- if re.err != nil {
- cc.forgetStreamID(cs.ID)
- return nil, re.err
- }
- res.Request = req
- res.TLS = cc.tlsState
- return res, nil
+ return handleReadLoopResponse(re)
case <-respHeaderTimer:
cc.forgetStreamID(cs.ID)
if !hasBody || bodyWritten {
@@ -5541,6 +5579,12 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
return nil, cs.resetErr
case err := <-bodyWriter.resc:
+
+ select {
+ case re := <-readLoopResCh:
+ return handleReadLoopResponse(re)
+ default:
+ }
if err != nil {
return nil, err
}
@@ -5648,26 +5692,24 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos
}
}
+ var trls []byte
+ if !sentEnd && hasTrailers {
+ cc.mu.Lock()
+ defer cc.mu.Unlock()
+ trls = cc.encodeTrailers(req)
+ }
+
cc.wmu.Lock()
- if !sentEnd {
- var trls []byte
- if hasTrailers {
- cc.mu.Lock()
- trls = cc.encodeTrailers(req)
- cc.mu.Unlock()
- }
+ defer cc.wmu.Unlock()
- if len(trls) > 0 {
- err = cc.writeHeaders(cs.ID, true, trls)
- } else {
- err = cc.fr.WriteData(cs.ID, true, nil)
- }
+ if len(trls) > 0 {
+ err = cc.writeHeaders(cs.ID, true, trls)
+ } else {
+ err = cc.fr.WriteData(cs.ID, true, nil)
}
if ferr := cc.bw.Flush(); ferr != nil && err == nil {
err = ferr
}
- cc.wmu.Unlock()
-
return err
}
@@ -5896,6 +5938,14 @@ func (e http2GoAwayError) Error() string {
e.LastStreamID, e.ErrCode, e.DebugData)
}
+func http2isEOFOrNetReadError(err error) bool {
+ if err == io.EOF {
+ return true
+ }
+ ne, ok := err.(*net.OpError)
+ return ok && ne.Op == "read"
+}
+
func (rl *http2clientConnReadLoop) cleanup() {
cc := rl.cc
defer cc.tconn.Close()
@@ -5904,16 +5954,14 @@ func (rl *http2clientConnReadLoop) cleanup() {
err := cc.readerErr
cc.mu.Lock()
- if err == io.EOF {
- if cc.goAway != nil {
- err = http2GoAwayError{
- LastStreamID: cc.goAway.LastStreamID,
- ErrCode: cc.goAway.ErrCode,
- DebugData: cc.goAwayDebug,
- }
- } else {
- err = io.ErrUnexpectedEOF
+ if cc.goAway != nil && http2isEOFOrNetReadError(err) {
+ err = http2GoAwayError{
+ LastStreamID: cc.goAway.LastStreamID,
+ ErrCode: cc.goAway.ErrCode,
+ DebugData: cc.goAwayDebug,
}
+ } else if err == io.EOF {
+ err = io.ErrUnexpectedEOF
}
for _, cs := range rl.activeRes {
cs.bufPipe.CloseWithError(err)
@@ -5932,8 +5980,9 @@ func (rl *http2clientConnReadLoop) cleanup() {
func (rl *http2clientConnReadLoop) run() error {
cc := rl.cc
- rl.closeWhenIdle = cc.t.disableKeepAlives()
+ rl.closeWhenIdle = cc.t.disableKeepAlives() || cc.singleUse
gotReply := false
+ gotSettings := false
for {
f, err := cc.fr.ReadFrame()
if err != nil {
@@ -5950,6 +5999,13 @@ func (rl *http2clientConnReadLoop) run() error {
if http2VerboseLogs {
cc.vlogf("http2: Transport received %s", http2summarizeFrame(f))
}
+ if !gotSettings {
+ if _, ok := f.(*http2SettingsFrame); !ok {
+ cc.logf("protocol error: received %T before a SETTINGS frame", f)
+ return http2ConnectionError(http2ErrCodeProtocol)
+ }
+ gotSettings = true
+ }
maybeIdle := false
switch f := f.(type) {
@@ -6216,10 +6272,27 @@ var http2errClosedResponseBody = errors.New("http2: response body closed")
func (b http2transportResponseBody) Close() error {
cs := b.cs
- if cs.bufPipe.Err() != io.EOF {
+ cc := cs.cc
- cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+ serverSentStreamEnd := cs.bufPipe.Err() == io.EOF
+ unread := cs.bufPipe.Len()
+
+ if unread > 0 || !serverSentStreamEnd {
+ cc.mu.Lock()
+ cc.wmu.Lock()
+ if !serverSentStreamEnd {
+ cc.fr.WriteRSTStream(cs.ID, http2ErrCodeCancel)
+ }
+
+ if unread > 0 {
+ cc.inflow.add(int32(unread))
+ cc.fr.WriteWindowUpdate(0, uint32(unread))
+ }
+ cc.bw.Flush()
+ cc.wmu.Unlock()
+ cc.mu.Unlock()
}
+
cs.bufPipe.BreakWithError(http2errClosedResponseBody)
return nil
}
@@ -6227,6 +6300,7 @@ func (b http2transportResponseBody) Close() error {
func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
cc := rl.cc
cs := cc.streamByID(f.StreamID, f.StreamEnded())
+ data := f.Data()
if cs == nil {
cc.mu.Lock()
neverSent := cc.nextStreamID
@@ -6237,27 +6311,49 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
return http2ConnectionError(http2ErrCodeProtocol)
}
+ if f.Length > 0 {
+ cc.mu.Lock()
+ cc.inflow.add(int32(f.Length))
+ cc.mu.Unlock()
+
+ cc.wmu.Lock()
+ cc.fr.WriteWindowUpdate(0, uint32(f.Length))
+ cc.bw.Flush()
+ cc.wmu.Unlock()
+ }
return nil
}
- if data := f.Data(); len(data) > 0 {
- if cs.bufPipe.b == nil {
+ if f.Length > 0 {
+ if len(data) > 0 && cs.bufPipe.b == nil {
cc.logf("http2: Transport received DATA frame for closed stream; closing connection")
return http2ConnectionError(http2ErrCodeProtocol)
}
cc.mu.Lock()
- if cs.inflow.available() >= int32(len(data)) {
- cs.inflow.take(int32(len(data)))
+ if cs.inflow.available() >= int32(f.Length) {
+ cs.inflow.take(int32(f.Length))
} else {
cc.mu.Unlock()
return http2ConnectionError(http2ErrCodeFlowControl)
}
+
+ if pad := int32(f.Length) - int32(len(data)); pad > 0 {
+ cs.inflow.add(pad)
+ cc.inflow.add(pad)
+ cc.wmu.Lock()
+ cc.fr.WriteWindowUpdate(0, uint32(pad))
+ cc.fr.WriteWindowUpdate(cs.ID, uint32(pad))
+ cc.bw.Flush()
+ cc.wmu.Unlock()
+ }
cc.mu.Unlock()
- if _, err := cs.bufPipe.Write(data); err != nil {
- rl.endStreamError(cs, err)
- return err
+ if len(data) > 0 {
+ if _, err := cs.bufPipe.Write(data); err != nil {
+ rl.endStreamError(cs, err)
+ return err
+ }
}
}
@@ -6282,7 +6378,7 @@ func (rl *http2clientConnReadLoop) endStreamError(cs *http2clientStream, err err
}
cs.bufPipe.closeWithErrorAndCode(err, code)
delete(rl.activeRes, cs.ID)
- if cs.req.Close || cs.req.Header.Get("Connection") == "close" {
+ if http2isConnectionCloseRequest(cs.req) {
rl.closeWhenIdle = true
}
}
@@ -6312,7 +6408,16 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error
cc := rl.cc
cc.mu.Lock()
defer cc.mu.Unlock()
- return f.ForeachSetting(func(s http2Setting) error {
+
+ if f.IsAck() {
+ if cc.wantSettingsAck {
+ cc.wantSettingsAck = false
+ return nil
+ }
+ return http2ConnectionError(http2ErrCodeProtocol)
+ }
+
+ err := f.ForeachSetting(func(s http2Setting) error {
switch s.ID {
case http2SettingMaxFrameSize:
cc.maxFrameSize = s.Val
@@ -6327,6 +6432,16 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error
}
return nil
})
+ if err != nil {
+ return err
+ }
+
+ cc.wmu.Lock()
+ defer cc.wmu.Unlock()
+
+ cc.fr.WriteSettingsAck()
+ cc.bw.Flush()
+ return cc.werr
}
func (rl *http2clientConnReadLoop) processWindowUpdate(f *http2WindowUpdateFrame) error {
@@ -6538,6 +6653,12 @@ func (s http2bodyWriterState) scheduleBodyWrite() {
}
}
+// isConnectionCloseRequest reports whether req should use its own
+// connection for a single request and then close the connection.
+func http2isConnectionCloseRequest(req *Request) bool {
+ return req.Close || httplex.HeaderValuesContainsToken(req.Header["Connection"], "close")
+}
+
// writeFramer is implemented by any type that is used to write frames.
type http2writeFramer interface {
writeFrame(http2writeContext) error
diff --git a/src/net/http/http.go b/src/net/http/http.go
index 4d088a5bb1..b34ae41ec5 100644
--- a/src/net/http/http.go
+++ b/src/net/http/http.go
@@ -7,7 +7,7 @@ package http
import (
"strings"
- "golang.org/x/net/lex/httplex"
+ "golang_org/x/net/lex/httplex"
)
// maxInt64 is the effective "infinite" value for the Server and
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index 139ce3eafc..13e5f283e4 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -4716,3 +4716,14 @@ func BenchmarkCloseNotifier(b *testing.B) {
}
b.StopTimer()
}
+
+// Verify this doesn't race (Issue 16505)
+func TestConcurrentServerServe(t *testing.T) {
+ for i := 0; i < 100; i++ {
+ ln1 := &oneConnListener{conn: nil}
+ ln2 := &oneConnListener{conn: nil}
+ srv := Server{}
+ go func() { srv.Serve(ln1) }()
+ go func() { srv.Serve(ln2) }()
+ }
+}
diff --git a/src/net/http/server.go b/src/net/http/server.go
index 9bf4d667e2..89574a8b36 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -28,7 +28,7 @@ import (
"sync/atomic"
"time"
- "golang.org/x/net/lex/httplex"
+ "golang_org/x/net/lex/httplex"
)
// Errors used by the HTTP server.
@@ -2129,8 +2129,8 @@ type Server struct {
ErrorLog *log.Logger
disableKeepAlives int32 // accessed atomically.
- nextProtoOnce sync.Once // guards initialization of TLSNextProto in Serve
- nextProtoErr error
+ nextProtoOnce sync.Once // guards setupHTTP2_* init
+ nextProtoErr error // result of http2.ConfigureServer if used
}
// A ConnState represents the state of a client connection to a server.
@@ -2260,10 +2260,8 @@ func (srv *Server) Serve(l net.Listener) error {
}
var tempDelay time.Duration // how long to sleep on accept failure
- if srv.shouldConfigureHTTP2ForServe() {
- if err := srv.setupHTTP2(); err != nil {
- return err
- }
+ if err := srv.setupHTTP2_Serve(); err != nil {
+ return err
}
// TODO: allow changing base context? can't imagine concrete
@@ -2408,7 +2406,7 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
// Setup HTTP/2 before srv.Serve, to initialize srv.TLSConfig
// before we clone it and create the TLS Listener.
- if err := srv.setupHTTP2(); err != nil {
+ if err := srv.setupHTTP2_ListenAndServeTLS(); err != nil {
return err
}
@@ -2436,14 +2434,36 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
return srv.Serve(tlsListener)
}
-func (srv *Server) setupHTTP2() error {
+// setupHTTP2_ListenAndServeTLS conditionally configures HTTP/2 on
+// srv and returns whether there was an error setting it up. If it is
+// not configured for policy reasons, nil is returned.
+func (srv *Server) setupHTTP2_ListenAndServeTLS() error {
srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults)
return srv.nextProtoErr
}
+// setupHTTP2_Serve is called from (*Server).Serve and conditionally
+// configures HTTP/2 on srv using a more conservative policy than
+// setupHTTP2_ListenAndServeTLS because Serve may be called
+// concurrently.
+//
+// The tests named TestTransportAutomaticHTTP2* and
+// TestConcurrentServerServe in server_test.go demonstrate some
+// of the supported use cases and motivations.
+func (srv *Server) setupHTTP2_Serve() error {
+ srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults_Serve)
+ return srv.nextProtoErr
+}
+
+func (srv *Server) onceSetNextProtoDefaults_Serve() {
+ if srv.shouldConfigureHTTP2ForServe() {
+ srv.onceSetNextProtoDefaults()
+ }
+}
+
// onceSetNextProtoDefaults configures HTTP/2, if the user hasn't
// configured otherwise. (by setting srv.TLSNextProto non-nil)
-// It must only be called via srv.nextProtoOnce (use srv.setupHTTP2).
+// It must only be called via srv.nextProtoOnce (use srv.setupHTTP2_*).
func (srv *Server) onceSetNextProtoDefaults() {
if strings.Contains(os.Getenv("GODEBUG"), "http2server=0") {
return
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
index b27ace638a..c653467098 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -18,7 +18,7 @@ import (
"strings"
"sync"
- "golang.org/x/net/lex/httplex"
+ "golang_org/x/net/lex/httplex"
)
// ErrLineTooLong is returned when reading request or response bodies
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index f7904b4a89..009f3c5b6a 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -27,7 +27,7 @@ import (
"sync"
"time"
- "golang.org/x/net/lex/httplex"
+ "golang_org/x/net/lex/httplex"
)
// DefaultTransport is the default implementation of Transport and is
@@ -251,6 +251,9 @@ func ProxyFromEnvironment(req *Request) (*url.URL, error) {
}
if proxy == "" {
proxy = httpProxyEnv.Get()
+ if proxy != "" && os.Getenv("REQUEST_METHOD") != "" {
+ return nil, errors.New("net/http: refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy")
+ }
}
if proxy == "" {
return nil, nil
@@ -380,6 +383,11 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
return resp, nil
}
if !pconn.shouldRetryRequest(req, err) {
+ // Issue 16465: return underlying net.Conn.Read error from peek,
+ // as we've historically done.
+ if e, ok := err.(transportReadFromServerError); ok {
+ err = e.err
+ }
return nil, err
}
testHookRoundTripRetried()
@@ -412,11 +420,19 @@ func (pc *persistConn) shouldRetryRequest(req *Request, err error) bool {
// first, per golang.org/issue/15723
return false
}
- if _, ok := err.(nothingWrittenError); ok {
+ switch err.(type) {
+ case nothingWrittenError:
// We never wrote anything, so it's safe to retry.
return true
+ case transportReadFromServerError:
+ // We got some non-EOF net.Conn.Read failure reading
+ // the 1st response byte from the server.
+ return true
}
- if err == errServerClosedIdle || err == errServerClosedConn {
+ if err == errServerClosedIdle {
+ // The server replied with io.EOF while we were trying to
+ // read the response. Probably an unfortunately keep-alive
+ // timeout, just as the client was writing a request.
return true
}
return false // conservatively
@@ -563,10 +579,25 @@ var (
errCloseIdleConns = errors.New("http: CloseIdleConnections called")
errReadLoopExiting = errors.New("http: persistConn.readLoop exiting")
errServerClosedIdle = errors.New("http: server closed idle connection")
- errServerClosedConn = errors.New("http: server closed connection")
errIdleConnTimeout = errors.New("http: idle connection timeout")
)
+// transportReadFromServerError is used by Transport.readLoop when the
+// 1 byte peek read fails and we're actually anticipating a response.
+// Usually this is just due to the inherent keep-alive shut down race,
+// where the server closed the connection at the same time the client
+// wrote. The underlying err field is usually io.EOF or some
+// ECONNRESET sort of thing which varies by platform. But it might be
+// the user's custom net.Conn.Read error too, so we carry it along for
+// them to return from Transport.RoundTrip.
+type transportReadFromServerError struct {
+ err error
+}
+
+func (e transportReadFromServerError) Error() string {
+ return fmt.Sprintf("net/http: Transport failed to read from server: %v", e.err)
+}
+
func (t *Transport) putOrCloseIdleConn(pconn *persistConn) {
if err := t.tryPutIdleConn(pconn); err != nil {
pconn.close(err)
@@ -1290,7 +1321,10 @@ func (pc *persistConn) mapRoundTripErrorFromReadLoop(startBytesWritten int64, er
if pc.isCanceled() {
return errRequestCanceled
}
- if err == errServerClosedIdle || err == errServerClosedConn {
+ if err == errServerClosedIdle {
+ return err
+ }
+ if _, ok := err.(transportReadFromServerError); ok {
return err
}
if pc.isBroken() {
@@ -1311,7 +1345,11 @@ func (pc *persistConn) mapRoundTripErrorAfterClosed(startBytesWritten int64) err
return errRequestCanceled
}
err := pc.closed
- if err == errServerClosedIdle || err == errServerClosedConn {
+ if err == errServerClosedIdle {
+ // Don't decorate
+ return err
+ }
+ if _, ok := err.(transportReadFromServerError); ok {
// Don't decorate
return err
}
@@ -1380,7 +1418,7 @@ func (pc *persistConn) readLoop() {
if err == nil {
resp, err = pc.readResponse(rc, trace)
} else {
- err = errServerClosedConn
+ err = transportReadFromServerError{err}
closeErr = err
}
@@ -1781,6 +1819,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
var re responseAndError
var respHeaderTimer <-chan time.Time
cancelChan := req.Request.Cancel
+ ctxDoneChan := req.Context().Done()
WaitResponse:
for {
testHookWaitResLoop()
@@ -1812,9 +1851,11 @@ WaitResponse:
case <-cancelChan:
pc.t.CancelRequest(req.Request)
cancelChan = nil
- case <-req.Context().Done():
+ ctxDoneChan = nil
+ case <-ctxDoneChan:
pc.t.CancelRequest(req.Request)
cancelChan = nil
+ ctxDoneChan = nil
}
}
diff --git a/src/net/http/transport_internal_test.go b/src/net/http/transport_internal_test.go
index a157d90630..a05ca6ed0d 100644
--- a/src/net/http/transport_internal_test.go
+++ b/src/net/http/transport_internal_test.go
@@ -46,17 +46,22 @@ func TestTransportPersistConnReadLoopEOF(t *testing.T) {
conn.Close() // simulate the server hanging up on the client
_, err = pc.roundTrip(treq)
- if err != errServerClosedConn && err != errServerClosedIdle {
+ if !isTransportReadFromServerError(err) && err != errServerClosedIdle {
t.Fatalf("roundTrip = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err)
}
<-pc.closech
err = pc.closed
- if err != errServerClosedConn && err != errServerClosedIdle {
+ if !isTransportReadFromServerError(err) && err != errServerClosedIdle {
t.Fatalf("pc.closed = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err)
}
}
+func isTransportReadFromServerError(err error) bool {
+ _, ok := err.(transportReadFromServerError)
+ return ok
+}
+
func newLocalListener(t *testing.T) net.Listener {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index d653a5a7fc..749d4530b8 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -2060,7 +2060,8 @@ type proxyFromEnvTest struct {
env string // HTTP_PROXY
httpsenv string // HTTPS_PROXY
- noenv string // NO_RPXY
+ noenv string // NO_PROXY
+ reqmeth string // REQUEST_METHOD
want string
wanterr error
@@ -2084,6 +2085,10 @@ func (t proxyFromEnvTest) String() string {
space()
fmt.Fprintf(&buf, "no_proxy=%q", t.noenv)
}
+ if t.reqmeth != "" {
+ space()
+ fmt.Fprintf(&buf, "request_method=%q", t.reqmeth)
+ }
req := "http://example.com"
if t.req != "" {
req = t.req
@@ -2107,6 +2112,12 @@ var proxyFromEnvTests = []proxyFromEnvTest{
{req: "https://secure.tld/", env: "http.proxy.tld", httpsenv: "secure.proxy.tld", want: "http://secure.proxy.tld"},
{req: "https://secure.tld/", env: "http.proxy.tld", httpsenv: "https://secure.proxy.tld", want: "https://secure.proxy.tld"},
+ // Issue 16405: don't use HTTP_PROXY in a CGI environment,
+ // where HTTP_PROXY can be attacker-controlled.
+ {env: "http://10.1.2.3:8080", reqmeth: "POST",
+ want: "<nil>",
+ wanterr: errors.New("net/http: refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy")},
+
{want: "<nil>"},
{noenv: "example.com", req: "http://example.com/", env: "proxy", want: "<nil>"},
@@ -2122,6 +2133,7 @@ func TestProxyFromEnvironment(t *testing.T) {
os.Setenv("HTTP_PROXY", tt.env)
os.Setenv("HTTPS_PROXY", tt.httpsenv)
os.Setenv("NO_PROXY", tt.noenv)
+ os.Setenv("REQUEST_METHOD", tt.reqmeth)
ResetCachedEnvironment()
reqURL := tt.req
if reqURL == "" {
@@ -3499,6 +3511,45 @@ func TestTransportIdleConnTimeout(t *testing.T) {
}
}
+type funcConn struct {
+ net.Conn
+ read func([]byte) (int, error)
+ write func([]byte) (int, error)
+}
+
+func (c funcConn) Read(p []byte) (int, error) { return c.read(p) }
+func (c funcConn) Write(p []byte) (int, error) { return c.write(p) }
+func (c funcConn) Close() error { return nil }
+
+// Issue 16465: Transport.RoundTrip should return the raw net.Conn.Read error from Peek
+// back to the caller.
+func TestTransportReturnsPeekError(t *testing.T) {
+ errValue := errors.New("specific error value")
+
+ wrote := make(chan struct{})
+ var wroteOnce sync.Once
+
+ tr := &Transport{
+ Dial: func(network, addr string) (net.Conn, error) {
+ c := funcConn{
+ read: func([]byte) (int, error) {
+ <-wrote
+ return 0, errValue
+ },
+ write: func(p []byte) (int, error) {
+ wroteOnce.Do(func() { close(wrote) })
+ return len(p), nil
+ },
+ }
+ return c, nil
+ },
+ }
+ _, err := tr.RoundTrip(httptest.NewRequest("GET", "http://fake.tld/", nil))
+ if err != errValue {
+ t.Errorf("error = %#v; want %v", err, errValue)
+ }
+}
+
var errFakeRoundTrip = errors.New("fake roundtrip")
type funcRoundTripper func()
diff --git a/src/net/interface_bsd.go b/src/net/interface_bsd.go
index d791cb3016..35b1c26815 100644
--- a/src/net/interface_bsd.go
+++ b/src/net/interface_bsd.go
@@ -9,7 +9,7 @@ package net
import (
"syscall"
- "golang.org/x/net/route"
+ "golang_org/x/net/route"
)
// If the ifindex is zero, interfaceTable returns mappings of all
diff --git a/src/net/interface_bsdvar.go b/src/net/interface_bsdvar.go
index a809b5f5ce..0b84ca37d4 100644
--- a/src/net/interface_bsdvar.go
+++ b/src/net/interface_bsdvar.go
@@ -9,7 +9,7 @@ package net
import (
"syscall"
- "golang.org/x/net/route"
+ "golang_org/x/net/route"
)
func interfaceMessages(ifindex int) ([]route.Message, error) {
diff --git a/src/net/interface_darwin.go b/src/net/interface_darwin.go
index bb4fd73a98..2ec8e1cc6e 100644
--- a/src/net/interface_darwin.go
+++ b/src/net/interface_darwin.go
@@ -7,7 +7,7 @@ package net
import (
"syscall"
- "golang.org/x/net/route"
+ "golang_org/x/net/route"
)
func interfaceMessages(ifindex int) ([]route.Message, error) {
diff --git a/src/net/interface_freebsd.go b/src/net/interface_freebsd.go
index 45badd6495..8a7d6f67c0 100644
--- a/src/net/interface_freebsd.go
+++ b/src/net/interface_freebsd.go
@@ -7,7 +7,7 @@ package net
import (
"syscall"
- "golang.org/x/net/route"
+ "golang_org/x/net/route"
)
func interfaceMessages(ifindex int) ([]route.Message, error) {
diff --git a/src/net/smtp/smtp.go b/src/net/smtp/smtp.go
index b4e4867a9e..9e04dd7c82 100644
--- a/src/net/smtp/smtp.go
+++ b/src/net/smtp/smtp.go
@@ -8,6 +8,11 @@
// AUTH RFC 2554
// STARTTLS RFC 3207
// Additional extensions may be handled by clients.
+//
+// The smtp package is frozen and not accepting new features.
+// Some external packages provide more functionality. See:
+//
+// https://godoc.org/?q=smtp
package smtp
import (
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index d7e20ebc1d..f8d693060d 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -80,6 +80,7 @@
package runtime
import (
+ "runtime/internal/atomic"
"runtime/internal/sys"
"unsafe"
)
@@ -176,7 +177,7 @@ func cgocallbackg(ctxt uintptr) {
func cgocallbackg1(ctxt uintptr) {
gp := getg()
- if gp.m.needextram {
+ if gp.m.needextram || atomic.Load(&extraMWaiters) > 0 {
gp.m.needextram = false
systemstack(newextram)
}
diff --git a/src/runtime/internal/atomic/asm_386.s b/src/runtime/internal/atomic/asm_386.s
index ebecd0b4cb..357d830289 100644
--- a/src/runtime/internal/atomic/asm_386.s
+++ b/src/runtime/internal/atomic/asm_386.s
@@ -32,13 +32,13 @@ TEXT runtime∕internal∕atomic·Loaduint(SB), NOSPLIT, $0-8
TEXT runtime∕internal∕atomic·Storeuintptr(SB), NOSPLIT, $0-8
JMP runtime∕internal∕atomic·Store(SB)
-TEXT runtime∕internal∕atomic·Xadduintptr(SB), NOSPLIT, $0-8
+TEXT runtime∕internal∕atomic·Xadduintptr(SB), NOSPLIT, $0-12
JMP runtime∕internal∕atomic·Xadd(SB)
-TEXT runtime∕internal∕atomic·Loadint64(SB), NOSPLIT, $0-16
+TEXT runtime∕internal∕atomic·Loadint64(SB), NOSPLIT, $0-12
JMP runtime∕internal∕atomic·Load64(SB)
-TEXT runtime∕internal∕atomic·Xaddint64(SB), NOSPLIT, $0-16
+TEXT runtime∕internal∕atomic·Xaddint64(SB), NOSPLIT, $0-20
JMP runtime∕internal∕atomic·Xadd64(SB)
diff --git a/src/runtime/internal/atomic/asm_amd64.s b/src/runtime/internal/atomic/asm_amd64.s
index 94d4ac2698..0001d2301c 100644
--- a/src/runtime/internal/atomic/asm_amd64.s
+++ b/src/runtime/internal/atomic/asm_amd64.s
@@ -52,7 +52,7 @@ TEXT runtime∕internal∕atomic·Storeuintptr(SB), NOSPLIT, $0-16
TEXT runtime∕internal∕atomic·Loadint64(SB), NOSPLIT, $0-16
JMP runtime∕internal∕atomic·Load64(SB)
-TEXT runtime∕internal∕atomic·Xaddint64(SB), NOSPLIT, $0-16
+TEXT runtime∕internal∕atomic·Xaddint64(SB), NOSPLIT, $0-24
JMP runtime∕internal∕atomic·Xadd64(SB)
// bool Casp(void **val, void *old, void *new)
diff --git a/src/runtime/internal/atomic/asm_amd64p32.s b/src/runtime/internal/atomic/asm_amd64p32.s
index 74c79d08fd..22c707c325 100644
--- a/src/runtime/internal/atomic/asm_amd64p32.s
+++ b/src/runtime/internal/atomic/asm_amd64p32.s
@@ -29,10 +29,10 @@ TEXT runtime∕internal∕atomic·Loaduintptr(SB), NOSPLIT, $0-12
TEXT runtime∕internal∕atomic·Loaduint(SB), NOSPLIT, $0-12
JMP runtime∕internal∕atomic·Load(SB)
-TEXT runtime∕internal∕atomic·Storeuintptr(SB), NOSPLIT, $0-12
+TEXT runtime∕internal∕atomic·Storeuintptr(SB), NOSPLIT, $0-8
JMP runtime∕internal∕atomic·Store(SB)
-TEXT runtime∕internal∕atomic·Loadint64(SB), NOSPLIT, $0-24
+TEXT runtime∕internal∕atomic·Loadint64(SB), NOSPLIT, $0-16
JMP runtime∕internal∕atomic·Load64(SB)
TEXT runtime∕internal∕atomic·Xaddint64(SB), NOSPLIT, $0-24
diff --git a/src/runtime/internal/atomic/asm_arm.s b/src/runtime/internal/atomic/asm_arm.s
index 235e8bfd20..12da22390d 100644
--- a/src/runtime/internal/atomic/asm_arm.s
+++ b/src/runtime/internal/atomic/asm_arm.s
@@ -61,11 +61,11 @@ TEXT runtime∕internal∕atomic·Loaduint(SB),NOSPLIT,$0-8
TEXT runtime∕internal∕atomic·Storeuintptr(SB),NOSPLIT,$0-8
B runtime∕internal∕atomic·Store(SB)
-TEXT runtime∕internal∕atomic·Xadduintptr(SB),NOSPLIT,$0-8
+TEXT runtime∕internal∕atomic·Xadduintptr(SB),NOSPLIT,$0-12
B runtime∕internal∕atomic·Xadd(SB)
-TEXT runtime∕internal∕atomic·Loadint64(SB),NOSPLIT,$0-16
+TEXT runtime∕internal∕atomic·Loadint64(SB),NOSPLIT,$0-12
B runtime∕internal∕atomic·Load64(SB)
-TEXT runtime∕internal∕atomic·Xaddint64(SB),NOSPLIT,$0-16
+TEXT runtime∕internal∕atomic·Xaddint64(SB),NOSPLIT,$0-20
B runtime∕internal∕atomic·Xadd64(SB)
diff --git a/src/runtime/internal/atomic/asm_arm64.s b/src/runtime/internal/atomic/asm_arm64.s
index c255677f78..929bf7189c 100644
--- a/src/runtime/internal/atomic/asm_arm64.s
+++ b/src/runtime/internal/atomic/asm_arm64.s
@@ -38,13 +38,13 @@ TEXT runtime∕internal∕atomic·Loaduint(SB), NOSPLIT, $-8-16
TEXT runtime∕internal∕atomic·Storeuintptr(SB), NOSPLIT, $0-16
B runtime∕internal∕atomic·Store64(SB)
-TEXT runtime∕internal∕atomic·Xadduintptr(SB), NOSPLIT, $0-16
+TEXT runtime∕internal∕atomic·Xadduintptr(SB), NOSPLIT, $0-24
B runtime∕internal∕atomic·Xadd64(SB)
TEXT runtime∕internal∕atomic·Loadint64(SB), NOSPLIT, $0-16
B runtime∕internal∕atomic·Load64(SB)
-TEXT runtime∕internal∕atomic·Xaddint64(SB), NOSPLIT, $0-16
+TEXT runtime∕internal∕atomic·Xaddint64(SB), NOSPLIT, $0-24
B runtime∕internal∕atomic·Xadd64(SB)
// bool Casp(void **val, void *old, void *new)
diff --git a/src/runtime/internal/atomic/asm_ppc64x.s b/src/runtime/internal/atomic/asm_ppc64x.s
index de4f895efd..aa6067e15b 100644
--- a/src/runtime/internal/atomic/asm_ppc64x.s
+++ b/src/runtime/internal/atomic/asm_ppc64x.s
@@ -77,7 +77,7 @@ TEXT runtime∕internal∕atomic·Xadduintptr(SB), NOSPLIT, $0-24
TEXT runtime∕internal∕atomic·Loadint64(SB), NOSPLIT, $0-16
BR runtime∕internal∕atomic·Load64(SB)
-TEXT runtime∕internal∕atomic·Xaddint64(SB), NOSPLIT, $0-16
+TEXT runtime∕internal∕atomic·Xaddint64(SB), NOSPLIT, $0-24
BR runtime∕internal∕atomic·Xadd64(SB)
// bool casp(void **val, void *old, void *new)
diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go
index bf75934ed6..4a8f501dfe 100644
--- a/src/runtime/mbarrier.go
+++ b/src/runtime/mbarrier.go
@@ -145,7 +145,7 @@ func writebarrierptr(dst *uintptr, src uintptr) {
if !writeBarrier.needed {
return
}
- if src != 0 && src < sys.PhysPageSize {
+ if src != 0 && src < minPhysPageSize {
systemstack(func() {
print("runtime: writebarrierptr *", dst, " = ", hex(src), "\n")
throw("bad pointer in write barrier")
@@ -164,7 +164,7 @@ func writebarrierptr_nostore(dst *uintptr, src uintptr) {
if !writeBarrier.needed {
return
}
- if src != 0 && src < sys.PhysPageSize {
+ if src != 0 && src < minPhysPageSize {
systemstack(func() { throw("bad pointer in write barrier") })
}
writebarrierptr_nostore1(dst, src)
diff --git a/src/runtime/mem_linux.go b/src/runtime/mem_linux.go
index 61fdcee543..cd0bf26328 100644
--- a/src/runtime/mem_linux.go
+++ b/src/runtime/mem_linux.go
@@ -10,8 +10,8 @@ import (
)
const (
- _PAGE_SIZE = sys.PhysPageSize
- _EACCES = 13
+ _EACCES = 13
+ _EINVAL = 22
)
// NOTE: vec must be just 1 byte long here.
@@ -22,13 +22,19 @@ const (
var addrspace_vec [1]byte
func addrspace_free(v unsafe.Pointer, n uintptr) bool {
- var chunk uintptr
- for off := uintptr(0); off < n; off += chunk {
- chunk = _PAGE_SIZE * uintptr(len(addrspace_vec))
- if chunk > (n - off) {
- chunk = n - off
+ // Step by the minimum possible physical page size. This is
+ // safe even if we have the wrong physical page size; mincore
+ // will just return EINVAL for unaligned addresses.
+ for off := uintptr(0); off < n; off += minPhysPageSize {
+ // Use a length of 1 byte, which the kernel will round
+ // up to one physical page regardless of the true
+ // physical page size.
+ errval := mincore(unsafe.Pointer(uintptr(v)+off), 1, &addrspace_vec[0])
+ if errval == -_EINVAL {
+ // Address is not a multiple of the physical
+ // page size. That's fine.
+ continue
}
- errval := mincore(unsafe.Pointer(uintptr(v)+off), chunk, &addrspace_vec[0])
// ENOMEM means unmapped, which is what we want.
// Anything else we assume means the pages are mapped.
if errval != -_ENOMEM {
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index c50bd02881..1efbace63c 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -742,11 +742,10 @@ const gcCreditSlack = 2000
// can accumulate on a P before updating gcController.assistTime.
const gcAssistTimeSlack = 5000
-// gcOverAssistBytes determines how many extra allocation bytes of
-// assist credit a GC assist builds up when an assist happens. This
-// amortizes the cost of an assist by pre-paying for this many bytes
-// of future allocations.
-const gcOverAssistBytes = 1 << 20
+// gcOverAssistWork determines how many extra units of scan work a GC
+// assist does when an assist happens. This amortizes the cost of an
+// assist by pre-paying for this many bytes of future allocations.
+const gcOverAssistWork = 64 << 10
var work struct {
full uint64 // lock-free list of full blocks workbuf
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index 00b96fd00b..aa7f7a7769 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -393,10 +393,15 @@ func gcAssistAlloc(gp *g) {
}
// Compute the amount of scan work we need to do to make the
- // balance positive. We over-assist to build up credit for
- // future allocations and amortize the cost of assisting.
- debtBytes := -gp.gcAssistBytes + gcOverAssistBytes
+ // balance positive. When the required amount of work is low,
+ // we over-assist to build up credit for future allocations
+ // and amortize the cost of assisting.
+ debtBytes := -gp.gcAssistBytes
scanWork := int64(gcController.assistWorkPerByte * float64(debtBytes))
+ if scanWork < gcOverAssistWork {
+ scanWork = gcOverAssistWork
+ debtBytes = int64(gcController.assistBytesPerWork * float64(scanWork))
+ }
retry:
// Steal as much credit as we can from the background GC's
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index 4093288a7c..db60f7a872 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -14,6 +14,11 @@ import (
"unsafe"
)
+// minPhysPageSize is a lower-bound on the physical page size. The
+// true physical page size may be larger than this. In contrast,
+// sys.PhysPageSize is an upper-bound on the physical page size.
+const minPhysPageSize = 4096
+
// Main malloc heap.
// The heap itself is the "free[]" and "large" arrays,
// but all the other global data is here too.
diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go
index f2cd81adb1..25f7ed6eb1 100644
--- a/src/runtime/pprof/pprof.go
+++ b/src/runtime/pprof/pprof.go
@@ -4,8 +4,69 @@
// Package pprof writes runtime profiling data in the format expected
// by the pprof visualization tool.
+//
+// Profiling a Go program
+//
+// The first step to profiling a Go program is to enable profiling.
+// Support for profiling benchmarks built with the standard testing
+// package is built into go test. For example, the following command
+// runs benchmarks in the current directory and writes the CPU and
+// memory profiles to cpu.prof and mem.prof:
+//
+// go test -cpuprofile cpu.prof -memprofile mem.prof -bench .
+//
+// To add equivalent profiling support to a standalone program, add
+// code like the following to your main function:
+//
+// var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
+// var memprofile = flag.String("memprofile", "", "write memory profile to `file`")
+//
+// func main() {
+// flag.Parse()
+// if *cpuprofile != "" {
+// f, err := os.Create(*cpuprofile)
+// if err != nil {
+// log.Fatal("could not create CPU profile: ", err)
+// }
+// if err := pprof.StartCPUProfile(f); err != nil {
+// log.Fatal("could not start CPU profile: ", err)
+// }
+// defer pprof.StopCPUProfile()
+// }
+// ...
+// if *memprofile != "" {
+// f, err := os.Create(*memprofile)
+// if err != nil {
+// log.Fatal("could not create memory profile: ", err)
+// }
+// runtime.GC() // get up-to-date statistics
+// if err := pprof.WriteHeapProfile(f); err != nil {
+// log.Fatal("could not write memory profile: ", err)
+// }
+// f.Close()
+// }
+// }
+//
+// There is also a standard HTTP interface to profiling data. Adding
+// the following line will install handlers under the /debug/pprof/
+// URL to download live profiles:
+//
+// import _ "net/http/pprof"
+//
+// See the net/http/pprof package for more details.
+//
+// Profiles can then be visualized with the pprof tool:
+//
+// go tool pprof cpu.prof
+//
+// There are many commands available from the pprof command line.
+// Commonly used commands include "top", which prints a summary of the
+// top program hot-spots, and "web", which opens an interactive graph
+// of hot-spots and their call graphs. Use "help" for information on
+// all pprof commands.
+//
// For more information about pprof, see
-// http://github.com/google/pprof/.
+// https://github.com/google/pprof/blob/master/doc/pprof.md.
package pprof
import (
@@ -353,12 +414,9 @@ func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
if name == "" {
show = true
fmt.Fprintf(w, "#\t%#x\n", frame.PC)
- } else {
+ } else if name != "runtime.goexit" && (show || !strings.HasPrefix(name, "runtime.")) {
// Hide runtime.goexit and any runtime functions at the beginning.
// This is useful mainly for allocation traces.
- if name == "runtime.goexit" || !show && strings.HasPrefix(name, "runtime.") {
- continue
- }
show = true
fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", frame.PC, name, frame.PC-frame.Entry, frame.File, frame.Line)
}
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index a6f5eda458..a0930155a5 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -497,6 +497,10 @@ func TestBlockProfile(t *testing.T) {
t.Fatalf("Bad profile header:\n%v", prof)
}
+ if strings.HasSuffix(prof, "#\t0x0\n\n") {
+ t.Errorf("Useless 0 suffix:\n%v", prof)
+ }
+
for _, test := range tests {
if !regexp.MustCompile(strings.Replace(test.re, "\t", "\t+", -1)).MatchString(prof) {
t.Fatalf("Bad %v entry, expect:\n%v\ngot:\n%v", test.name, test.re, prof)
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 2c0b3df167..1d00930ac5 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -1389,10 +1389,27 @@ func needm(x byte) {
var earlycgocallback = []byte("fatal error: cgo callback before cgo call\n")
-// newextram allocates an m and puts it on the extra list.
+// newextram allocates m's and puts them on the extra list.
// It is called with a working local m, so that it can do things
// like call schedlock and allocate.
func newextram() {
+ c := atomic.Xchg(&extraMWaiters, 0)
+ if c > 0 {
+ for i := uint32(0); i < c; i++ {
+ oneNewExtraM()
+ }
+ } else {
+ // Make sure there is at least one extra M.
+ mp := lockextra(true)
+ unlockextra(mp)
+ if mp == nil {
+ oneNewExtraM()
+ }
+ }
+}
+
+// oneNewExtraM allocates an m and puts it on the extra list.
+func oneNewExtraM() {
// Create extra goroutine locked to extra m.
// The goroutine is the context in which the cgo callback will run.
// The sched.pc will never be returned to, but setting it to
@@ -1485,6 +1502,7 @@ func getm() uintptr {
}
var extram uintptr
+var extraMWaiters uint32
// lockextra locks the extra list and returns the list head.
// The caller must unlock the list by storing a new list head
@@ -1495,6 +1513,7 @@ var extram uintptr
func lockextra(nilokay bool) *m {
const locked = 1
+ incr := false
for {
old := atomic.Loaduintptr(&extram)
if old == locked {
@@ -1503,6 +1522,13 @@ func lockextra(nilokay bool) *m {
continue
}
if old == 0 && !nilokay {
+ if !incr {
+ // Add 1 to the number of threads
+ // waiting for an M.
+ // This is cleared by newextram.
+ atomic.Xadd(&extraMWaiters, 1)
+ incr = true
+ }
usleep(1)
continue
}
diff --git a/src/runtime/race/README b/src/runtime/race/README
index 3a506b0c08..95e241c072 100644
--- a/src/runtime/race/README
+++ b/src/runtime/race/README
@@ -4,4 +4,4 @@ the LLVM project (http://llvm.org/git/compiler-rt.git).
To update the .syso files use golang.org/x/build/cmd/racebuild.
-Current runtime is built on rev 9d79ea3416bfbe3acac50e47802ee9621bf53254.
+Current runtime is built on rev e35e7c00b5c7e7ee5e24d537b80cb0d34cebb038.
diff --git a/src/runtime/race/race_darwin_amd64.syso b/src/runtime/race/race_darwin_amd64.syso
index 1822486e08..c19740fb8f 100644
--- a/src/runtime/race/race_darwin_amd64.syso
+++ b/src/runtime/race/race_darwin_amd64.syso
Binary files differ
diff --git a/src/runtime/race/race_freebsd_amd64.syso b/src/runtime/race/race_freebsd_amd64.syso
index 75d94952c3..df1bc26861 100644
--- a/src/runtime/race/race_freebsd_amd64.syso
+++ b/src/runtime/race/race_freebsd_amd64.syso
Binary files differ
diff --git a/src/runtime/race/race_linux_amd64.syso b/src/runtime/race/race_linux_amd64.syso
index 8f571afa9a..174033041e 100644
--- a/src/runtime/race/race_linux_amd64.syso
+++ b/src/runtime/race/race_linux_amd64.syso
Binary files differ
diff --git a/src/runtime/race/race_test.go b/src/runtime/race/race_test.go
index 81e51cc5b2..53ec74c085 100644
--- a/src/runtime/race/race_test.go
+++ b/src/runtime/race/race_test.go
@@ -221,3 +221,21 @@ func BenchmarkSyncLeak(b *testing.B) {
}
wg.Wait()
}
+
+func BenchmarkStackLeak(b *testing.B) {
+ done := make(chan bool, 1)
+ for i := 0; i < b.N; i++ {
+ go func() {
+ growStack(rand.Intn(100))
+ done <- true
+ }()
+ <-done
+ }
+}
+
+func growStack(i int) {
+ if i == 0 {
+ return
+ }
+ growStack(i - 1)
+}
diff --git a/src/runtime/race/race_windows_amd64.syso b/src/runtime/race/race_windows_amd64.syso
index 64c54b6e2f..fd93959af5 100644
--- a/src/runtime/race/race_windows_amd64.syso
+++ b/src/runtime/race/race_windows_amd64.syso
Binary files differ
diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s
index 83f4709f38..b5e65e6869 100644
--- a/src/runtime/sys_darwin_386.s
+++ b/src/runtime/sys_darwin_386.s
@@ -196,15 +196,16 @@ timeloop:
systime:
// Fall back to system call (usually first call in this thread)
- LEAL 12(SP), AX // must be non-nil, unused
+ LEAL 16(SP), AX // must be non-nil, unused
MOVL AX, 4(SP)
MOVL $0, 8(SP) // time zone pointer
+ MOVL $0, 12(SP) // required as of Sierra; Issue 16570
MOVL $116, AX
INT $0x80
CMPL AX, $0
JNE inreg
- MOVL 12(SP), AX
- MOVL 16(SP), DX
+ MOVL 16(SP), AX
+ MOVL 20(SP), DX
inreg:
// sec is in AX, usec in DX
// convert to DX:AX nsec
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index e09b906ba5..ea2cc068f6 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -157,6 +157,7 @@ systime:
// Fall back to system call (usually first call in this thread).
MOVQ SP, DI
MOVQ $0, SI
+ MOVQ $0, DX // required as of Sierra; Issue 16570
MOVL $(0x2000000+116), AX
SYSCALL
CMPQ AX, $0
@@ -244,6 +245,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$32
MOVQ R8, 24(SP) // ctx
MOVQ $runtime·sigtrampgo(SB), AX
CALL AX
+ INT $3 // not reached (see issue 16453)
TEXT runtime·mmap(SB),NOSPLIT,$0
MOVQ addr+0(FP), DI // arg 1 addr
diff --git a/src/vendor/golang.org/x/net/http2/hpack/encode.go b/src/vendor/golang_org/x/net/http2/hpack/encode.go
index f9bb033984..f9bb033984 100644
--- a/src/vendor/golang.org/x/net/http2/hpack/encode.go
+++ b/src/vendor/golang_org/x/net/http2/hpack/encode.go
diff --git a/src/vendor/golang.org/x/net/http2/hpack/encode_test.go b/src/vendor/golang_org/x/net/http2/hpack/encode_test.go
index 92286f3bad..92286f3bad 100644
--- a/src/vendor/golang.org/x/net/http2/hpack/encode_test.go
+++ b/src/vendor/golang_org/x/net/http2/hpack/encode_test.go
diff --git a/src/vendor/golang.org/x/net/http2/hpack/hpack.go b/src/vendor/golang_org/x/net/http2/hpack/hpack.go
index 8aa197ad67..8aa197ad67 100644
--- a/src/vendor/golang.org/x/net/http2/hpack/hpack.go
+++ b/src/vendor/golang_org/x/net/http2/hpack/hpack.go
diff --git a/src/vendor/golang.org/x/net/http2/hpack/hpack_test.go b/src/vendor/golang_org/x/net/http2/hpack/hpack_test.go
index 4c7b17bfb1..4c7b17bfb1 100644
--- a/src/vendor/golang.org/x/net/http2/hpack/hpack_test.go
+++ b/src/vendor/golang_org/x/net/http2/hpack/hpack_test.go
diff --git a/src/vendor/golang.org/x/net/http2/hpack/huffman.go b/src/vendor/golang_org/x/net/http2/hpack/huffman.go
index 8850e39467..8850e39467 100644
--- a/src/vendor/golang.org/x/net/http2/hpack/huffman.go
+++ b/src/vendor/golang_org/x/net/http2/hpack/huffman.go
diff --git a/src/vendor/golang.org/x/net/http2/hpack/tables.go b/src/vendor/golang_org/x/net/http2/hpack/tables.go
index b9283a0233..b9283a0233 100644
--- a/src/vendor/golang.org/x/net/http2/hpack/tables.go
+++ b/src/vendor/golang_org/x/net/http2/hpack/tables.go
diff --git a/src/vendor/golang.org/x/net/lex/httplex/httplex.go b/src/vendor/golang_org/x/net/lex/httplex/httplex.go
index bd0ec24f44..bd0ec24f44 100644
--- a/src/vendor/golang.org/x/net/lex/httplex/httplex.go
+++ b/src/vendor/golang_org/x/net/lex/httplex/httplex.go
diff --git a/src/vendor/golang.org/x/net/lex/httplex/httplex_test.go b/src/vendor/golang_org/x/net/lex/httplex/httplex_test.go
index c4ace1991b..c4ace1991b 100644
--- a/src/vendor/golang.org/x/net/lex/httplex/httplex_test.go
+++ b/src/vendor/golang_org/x/net/lex/httplex/httplex_test.go
diff --git a/src/vendor/golang.org/x/net/route/address.go b/src/vendor/golang_org/x/net/route/address.go
index 206a8371d4..206a8371d4 100644
--- a/src/vendor/golang.org/x/net/route/address.go
+++ b/src/vendor/golang_org/x/net/route/address.go
diff --git a/src/vendor/golang.org/x/net/route/address_darwin_test.go b/src/vendor/golang_org/x/net/route/address_darwin_test.go
index b86bd3df1f..b86bd3df1f 100644
--- a/src/vendor/golang.org/x/net/route/address_darwin_test.go
+++ b/src/vendor/golang_org/x/net/route/address_darwin_test.go
diff --git a/src/vendor/golang.org/x/net/route/address_test.go b/src/vendor/golang_org/x/net/route/address_test.go
index 2005ef7c20..2005ef7c20 100644
--- a/src/vendor/golang.org/x/net/route/address_test.go
+++ b/src/vendor/golang_org/x/net/route/address_test.go
diff --git a/src/vendor/golang.org/x/net/route/binary.go b/src/vendor/golang_org/x/net/route/binary.go
index 4c561631b9..4c561631b9 100644
--- a/src/vendor/golang.org/x/net/route/binary.go
+++ b/src/vendor/golang_org/x/net/route/binary.go
diff --git a/src/vendor/golang.org/x/net/route/defs_darwin.go b/src/vendor/golang_org/x/net/route/defs_darwin.go
index f452ad14ce..f452ad14ce 100644
--- a/src/vendor/golang.org/x/net/route/defs_darwin.go
+++ b/src/vendor/golang_org/x/net/route/defs_darwin.go
diff --git a/src/vendor/golang.org/x/net/route/defs_dragonfly.go b/src/vendor/golang_org/x/net/route/defs_dragonfly.go
index c737751d76..c737751d76 100644
--- a/src/vendor/golang.org/x/net/route/defs_dragonfly.go
+++ b/src/vendor/golang_org/x/net/route/defs_dragonfly.go
diff --git a/src/vendor/golang.org/x/net/route/defs_freebsd.go b/src/vendor/golang_org/x/net/route/defs_freebsd.go
index 8f834e81db..8f834e81db 100644
--- a/src/vendor/golang.org/x/net/route/defs_freebsd.go
+++ b/src/vendor/golang_org/x/net/route/defs_freebsd.go
diff --git a/src/vendor/golang.org/x/net/route/defs_netbsd.go b/src/vendor/golang_org/x/net/route/defs_netbsd.go
index b18d85e016..b18d85e016 100644
--- a/src/vendor/golang.org/x/net/route/defs_netbsd.go
+++ b/src/vendor/golang_org/x/net/route/defs_netbsd.go
diff --git a/src/vendor/golang.org/x/net/route/defs_openbsd.go b/src/vendor/golang_org/x/net/route/defs_openbsd.go
index 5df7a43bc3..5df7a43bc3 100644
--- a/src/vendor/golang.org/x/net/route/defs_openbsd.go
+++ b/src/vendor/golang_org/x/net/route/defs_openbsd.go
diff --git a/src/vendor/golang.org/x/net/route/interface.go b/src/vendor/golang_org/x/net/route/interface.go
index 854906d9c4..854906d9c4 100644
--- a/src/vendor/golang.org/x/net/route/interface.go
+++ b/src/vendor/golang_org/x/net/route/interface.go
diff --git a/src/vendor/golang.org/x/net/route/interface_announce.go b/src/vendor/golang_org/x/net/route/interface_announce.go
index 520d657b57..520d657b57 100644
--- a/src/vendor/golang.org/x/net/route/interface_announce.go
+++ b/src/vendor/golang_org/x/net/route/interface_announce.go
diff --git a/src/vendor/golang.org/x/net/route/interface_classic.go b/src/vendor/golang_org/x/net/route/interface_classic.go
index ac4e7a6805..ac4e7a6805 100644
--- a/src/vendor/golang.org/x/net/route/interface_classic.go
+++ b/src/vendor/golang_org/x/net/route/interface_classic.go
diff --git a/src/vendor/golang.org/x/net/route/interface_freebsd.go b/src/vendor/golang_org/x/net/route/interface_freebsd.go
index c83053915d..c83053915d 100644
--- a/src/vendor/golang.org/x/net/route/interface_freebsd.go
+++ b/src/vendor/golang_org/x/net/route/interface_freebsd.go
diff --git a/src/vendor/golang.org/x/net/route/interface_multicast.go b/src/vendor/golang_org/x/net/route/interface_multicast.go
index 1e99a9cc64..1e99a9cc64 100644
--- a/src/vendor/golang.org/x/net/route/interface_multicast.go
+++ b/src/vendor/golang_org/x/net/route/interface_multicast.go
diff --git a/src/vendor/golang.org/x/net/route/interface_openbsd.go b/src/vendor/golang_org/x/net/route/interface_openbsd.go
index 24451d8ca1..24451d8ca1 100644
--- a/src/vendor/golang.org/x/net/route/interface_openbsd.go
+++ b/src/vendor/golang_org/x/net/route/interface_openbsd.go
diff --git a/src/vendor/golang.org/x/net/route/message.go b/src/vendor/golang_org/x/net/route/message.go
index 27cbf6b77a..27cbf6b77a 100644
--- a/src/vendor/golang.org/x/net/route/message.go
+++ b/src/vendor/golang_org/x/net/route/message.go
diff --git a/src/vendor/golang.org/x/net/route/message_darwin_test.go b/src/vendor/golang_org/x/net/route/message_darwin_test.go
index 3fdd12df55..3fdd12df55 100644
--- a/src/vendor/golang.org/x/net/route/message_darwin_test.go
+++ b/src/vendor/golang_org/x/net/route/message_darwin_test.go
diff --git a/src/vendor/golang.org/x/net/route/message_freebsd_test.go b/src/vendor/golang_org/x/net/route/message_freebsd_test.go
index 785c273f65..785c273f65 100644
--- a/src/vendor/golang.org/x/net/route/message_freebsd_test.go
+++ b/src/vendor/golang_org/x/net/route/message_freebsd_test.go
diff --git a/src/vendor/golang.org/x/net/route/message_test.go b/src/vendor/golang_org/x/net/route/message_test.go
index a1263d8f25..a1263d8f25 100644
--- a/src/vendor/golang.org/x/net/route/message_test.go
+++ b/src/vendor/golang_org/x/net/route/message_test.go
diff --git a/src/vendor/golang.org/x/net/route/route.go b/src/vendor/golang_org/x/net/route/route.go
index c986e29ebc..c986e29ebc 100644
--- a/src/vendor/golang.org/x/net/route/route.go
+++ b/src/vendor/golang_org/x/net/route/route.go
diff --git a/src/vendor/golang.org/x/net/route/route_classic.go b/src/vendor/golang_org/x/net/route/route_classic.go
index d333c6aa52..d333c6aa52 100644
--- a/src/vendor/golang.org/x/net/route/route_classic.go
+++ b/src/vendor/golang_org/x/net/route/route_classic.go
diff --git a/src/vendor/golang.org/x/net/route/route_openbsd.go b/src/vendor/golang_org/x/net/route/route_openbsd.go
index b07862f04d..b07862f04d 100644
--- a/src/vendor/golang.org/x/net/route/route_openbsd.go
+++ b/src/vendor/golang_org/x/net/route/route_openbsd.go
diff --git a/src/vendor/golang.org/x/net/route/route_test.go b/src/vendor/golang_org/x/net/route/route_test.go
index 99f57b712d..99f57b712d 100644
--- a/src/vendor/golang.org/x/net/route/route_test.go
+++ b/src/vendor/golang_org/x/net/route/route_test.go
diff --git a/src/vendor/golang.org/x/net/route/sys.go b/src/vendor/golang_org/x/net/route/sys.go
index 80ca83ae13..80ca83ae13 100644
--- a/src/vendor/golang.org/x/net/route/sys.go
+++ b/src/vendor/golang_org/x/net/route/sys.go
diff --git a/src/vendor/golang.org/x/net/route/sys_darwin.go b/src/vendor/golang_org/x/net/route/sys_darwin.go
index fff3a0fd1d..fff3a0fd1d 100644
--- a/src/vendor/golang.org/x/net/route/sys_darwin.go
+++ b/src/vendor/golang_org/x/net/route/sys_darwin.go
diff --git a/src/vendor/golang.org/x/net/route/sys_dragonfly.go b/src/vendor/golang_org/x/net/route/sys_dragonfly.go
index da848b3d07..da848b3d07 100644
--- a/src/vendor/golang.org/x/net/route/sys_dragonfly.go
+++ b/src/vendor/golang_org/x/net/route/sys_dragonfly.go
diff --git a/src/vendor/golang.org/x/net/route/sys_freebsd.go b/src/vendor/golang_org/x/net/route/sys_freebsd.go
index 7b05c1a5a0..7b05c1a5a0 100644
--- a/src/vendor/golang.org/x/net/route/sys_freebsd.go
+++ b/src/vendor/golang_org/x/net/route/sys_freebsd.go
diff --git a/src/vendor/golang.org/x/net/route/sys_netbsd.go b/src/vendor/golang_org/x/net/route/sys_netbsd.go
index 4d8076b518..4d8076b518 100644
--- a/src/vendor/golang.org/x/net/route/sys_netbsd.go
+++ b/src/vendor/golang_org/x/net/route/sys_netbsd.go
diff --git a/src/vendor/golang.org/x/net/route/sys_openbsd.go b/src/vendor/golang_org/x/net/route/sys_openbsd.go
index 26d0438696..26d0438696 100644
--- a/src/vendor/golang.org/x/net/route/sys_openbsd.go
+++ b/src/vendor/golang_org/x/net/route/sys_openbsd.go
diff --git a/src/vendor/golang.org/x/net/route/syscall.go b/src/vendor/golang_org/x/net/route/syscall.go
index d136325a30..d136325a30 100644
--- a/src/vendor/golang.org/x/net/route/syscall.go
+++ b/src/vendor/golang_org/x/net/route/syscall.go
diff --git a/src/vendor/golang.org/x/net/route/syscall.s b/src/vendor/golang_org/x/net/route/syscall.s
index fa6297f0aa..fa6297f0aa 100644
--- a/src/vendor/golang.org/x/net/route/syscall.s
+++ b/src/vendor/golang_org/x/net/route/syscall.s
diff --git a/src/vendor/golang.org/x/net/route/zsys_darwin.go b/src/vendor/golang_org/x/net/route/zsys_darwin.go
index 265b81cd50..265b81cd50 100644
--- a/src/vendor/golang.org/x/net/route/zsys_darwin.go
+++ b/src/vendor/golang_org/x/net/route/zsys_darwin.go
diff --git a/src/vendor/golang.org/x/net/route/zsys_dragonfly.go b/src/vendor/golang_org/x/net/route/zsys_dragonfly.go
index dd36dece0f..dd36dece0f 100644
--- a/src/vendor/golang.org/x/net/route/zsys_dragonfly.go
+++ b/src/vendor/golang_org/x/net/route/zsys_dragonfly.go
diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go b/src/vendor/golang_org/x/net/route/zsys_freebsd_386.go
index 9bac2e3900..9bac2e3900 100644
--- a/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go
+++ b/src/vendor/golang_org/x/net/route/zsys_freebsd_386.go
diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go b/src/vendor/golang_org/x/net/route/zsys_freebsd_amd64.go
index b1920d7ac1..b1920d7ac1 100644
--- a/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go
+++ b/src/vendor/golang_org/x/net/route/zsys_freebsd_amd64.go
diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go b/src/vendor/golang_org/x/net/route/zsys_freebsd_arm.go
index a034d6fcbf..a034d6fcbf 100644
--- a/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go
+++ b/src/vendor/golang_org/x/net/route/zsys_freebsd_arm.go
diff --git a/src/vendor/golang.org/x/net/route/zsys_netbsd.go b/src/vendor/golang_org/x/net/route/zsys_netbsd.go
index aa4aad1613..aa4aad1613 100644
--- a/src/vendor/golang.org/x/net/route/zsys_netbsd.go
+++ b/src/vendor/golang_org/x/net/route/zsys_netbsd.go
diff --git a/src/vendor/golang.org/x/net/route/zsys_openbsd.go b/src/vendor/golang_org/x/net/route/zsys_openbsd.go
index 4fadc4e8fa..4fadc4e8fa 100644
--- a/src/vendor/golang.org/x/net/route/zsys_openbsd.go
+++ b/src/vendor/golang_org/x/net/route/zsys_openbsd.go
diff --git a/test/fixedbugs/issue16515.go b/test/fixedbugs/issue16515.go
new file mode 100644
index 0000000000..6b67436383
--- /dev/null
+++ b/test/fixedbugs/issue16515.go
@@ -0,0 +1,53 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 16515: spilled Duff-adjusted address may be invalid
+
+package main
+
+import "runtime"
+
+type T [62]int // DUFFZERO with non-zero adjustment on AMD64
+
+var sink interface{}
+
+//go:noinline
+func zero(x *T) {
+ // Two DUFFZEROs on the same address with a function call in between.
+ // Duff-adjusted address will be spilled and loaded
+
+ *x = T{} // DUFFZERO
+ runtime.GC()
+ (*x)[0] = 1
+ g() // call a function with large frame, trigger a stack move
+ *x = T{} // DUFFZERO again
+}
+
+//go:noinline
+// a function with large frame
+func g() {
+ var x [1000]int
+ _ = x
+}
+
+func main() {
+ var s struct { a T; b [8192-62]int } // allocate 64K, hopefully it's in a new span and a few bytes before it is garbage
+ sink = &s // force heap allocation
+ s.a[0] = 2
+ zero(&s.a)
+ if s.a[0] != 0 {
+ println("s.a[0] =", s.a[0])
+ panic("zeroing failed")
+ }
+
+ var a T // on stack
+ a[0] = 2
+ zero(&a)
+ if a[0] != 0 {
+ println("a[0] =", a[0])
+ panic("zeroing failed")
+ }
+}