mirror of
https://github.com/golang/go.git
synced 2026-01-29 15:12:08 +03:00
Compare commits
63 Commits
dev.inline
...
go1.12.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac02fdec7c | ||
|
|
4fc9d3bc58 | ||
|
|
92e78f7e8d | ||
|
|
c4e9966a32 | ||
|
|
5ca2cf89e7 | ||
|
|
fcc527344f | ||
|
|
731ebf4d87 | ||
|
|
8b086a2b7f | ||
|
|
499088f6dd | ||
|
|
991583017c | ||
|
|
578e281583 | ||
|
|
8acc2ea68b | ||
|
|
ec06e9ba45 | ||
|
|
aeb9d03e4a | ||
|
|
827c5d5355 | ||
|
|
e552f772f7 | ||
|
|
fc6457d1d2 | ||
|
|
ff048033e4 | ||
|
|
c1d8d9d8be | ||
|
|
0380c9ad38 | ||
|
|
100b6739fc | ||
|
|
82d12bdcf7 | ||
|
|
32355f5c31 | ||
|
|
35ddc140c4 | ||
|
|
746edd459d | ||
|
|
ad8ebb9e85 | ||
|
|
6fc1242ea8 | ||
|
|
f9d0594a47 | ||
|
|
7294ede961 | ||
|
|
f062f48c1f | ||
|
|
a40b76a40c | ||
|
|
7e880151b1 | ||
|
|
4dd46a678f | ||
|
|
0ea746023f | ||
|
|
6ff06c19fd | ||
|
|
71b8a3bc87 | ||
|
|
91fd14b824 | ||
|
|
162b3610e6 | ||
|
|
a2884af3b6 | ||
|
|
c55fb33612 | ||
|
|
4754cba67f | ||
|
|
491b7bcff5 | ||
|
|
05e77d4191 | ||
|
|
297d394cab | ||
|
|
6e501da62e | ||
|
|
6ae7c0bc6d | ||
|
|
efc6d86965 | ||
|
|
a718f939d2 | ||
|
|
da1f5d376a | ||
|
|
35e6a10c90 | ||
|
|
320da8d149 | ||
|
|
b840ae1e16 | ||
|
|
fc60d9dd6e | ||
|
|
96d39207d1 | ||
|
|
a4aee30cb4 | ||
|
|
e3a53db2b8 | ||
|
|
52d020260d | ||
|
|
9527a465f3 | ||
|
|
fa5e4baf87 | ||
|
|
0cfe46ce74 | ||
|
|
74f0f6939c | ||
|
|
7ab5e0c5e2 | ||
|
|
1af509d46e |
@@ -18,10 +18,8 @@ underlying binary with arguments appropriate to package-level processing.
|
||||
|
||||
<p>
|
||||
The programs can also be run as stand-alone binaries, with unmodified arguments,
|
||||
using the go <code>tool</code> subcommand, such as <code>go tool vet</code>.
|
||||
This style of invocation allows, for instance, checking a single source file
|
||||
rather than an entire package: <code>go tool vet myprogram.go</code> as
|
||||
compared to <code>go vet mypackage</code>.
|
||||
using the go <code>tool</code> subcommand, such as <code>go tool cgo</code>.
|
||||
For most commands this is mainly useful for debugging.
|
||||
Some of the commands, such as <code>pprof</code>, are accessible only through
|
||||
the go <code>tool</code> subcommand.
|
||||
</p>
|
||||
@@ -76,7 +74,7 @@ and rewrites them to use newer ones.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="/cmd/go/">fmt</a></td>
|
||||
<td><a href="/cmd/gofmt/">fmt</a></td>
|
||||
<td> </td>
|
||||
<td>Fmt formats Go packages, it is also available as an independent <a href="/cmd/gofmt/">
|
||||
gofmt</a> command with more general options.</td>
|
||||
|
||||
@@ -34,6 +34,7 @@ We encourage all Go users to subscribe to
|
||||
<p>A <a href="/doc/devel/release.html">summary</a> of the changes between Go releases. Notes for the major releases:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="/doc/go1.12">Go 1.12</a> <small>(February 2019)</small></li>
|
||||
<li><a href="/doc/go1.11">Go 1.11</a> <small>(August 2018)</small></li>
|
||||
<li><a href="/doc/go1.10">Go 1.10</a> <small>(February 2018)</small></li>
|
||||
<li><a href="/doc/go1.9">Go 1.9</a> <small>(August 2017)</small></li>
|
||||
|
||||
@@ -23,6 +23,31 @@ in supported releases as needed by issuing minor revisions
|
||||
(for example, Go 1.6.1, Go 1.6.2, and so on).
|
||||
</p>
|
||||
|
||||
<h2 id="go1.12">go1.12 (released 2019/02/25)</h2>
|
||||
|
||||
<p>
|
||||
Go 1.12 is a major release of Go.
|
||||
Read the <a href="/doc/go1.12">Go 1.12 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="go1.12.minor">Minor revisions</h3>
|
||||
|
||||
<p>
|
||||
go1.12.1 (released 2019/03/14) includes fixes to cgo, the compiler, the go
|
||||
command, and the <code>fmt</code>, <code>net/smtp</code>, <code>os</code>,
|
||||
<code>path/filepath</code>, <code>sync</code>, and <code>text/template</code>
|
||||
packages. See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.12.1">Go
|
||||
1.12.1 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.12.2 (released 2019/04/05) includes fixes to the compiler, the go
|
||||
command, the runtime, and the <code>doc</code>, <code>net</code>,
|
||||
<code>net/http/httputil</code>, and <code>os</code> packages. See the
|
||||
<a href="https://github.com/golang/go/issues?q=milestone%3AGo1.12.2">Go
|
||||
1.12.2 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.11">go1.11 (released 2018/08/24)</h2>
|
||||
|
||||
<p>
|
||||
@@ -66,6 +91,28 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.4+labe
|
||||
1.11.4 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.11.5 (released 2019/01/23) includes a security fix to the
|
||||
<code>crypto/elliptic</code> package. See
|
||||
the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.5">Go
|
||||
1.11.5 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.11.6 (released 2019/03/14) includes fixes to cgo, the compiler, linker,
|
||||
runtime, go command, and the <code>crypto/x509</code>, <code>encoding/json</code>,
|
||||
<code>net</code>, and <code>net/url</code> packages. See the
|
||||
<a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.6">Go
|
||||
1.11.6 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.11.7 (released 2019/04/05) includes fixes to the runtime and the
|
||||
<code>net</code> packages. See the
|
||||
<a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.7">Go
|
||||
1.11.7 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.10">go1.10 (released 2018/02/16)</h2>
|
||||
|
||||
<p>
|
||||
@@ -131,6 +178,13 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.7+labe
|
||||
Go 1.10.7 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.10.8 (released 2019/01/23) includes a security fix to the
|
||||
<code>crypto/elliptic</code> package. See
|
||||
the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.8">Go
|
||||
1.10.8 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.9">go1.9 (released 2017/08/24)</h2>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -15,14 +15,7 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
ul li { margin: 0.5em 0; }
|
||||
</style>
|
||||
|
||||
<h2 id="introduction">DRAFT RELEASE NOTES - Introduction to Go 1.12</h2>
|
||||
|
||||
<p>
|
||||
<strong>
|
||||
Go 1.12 is not yet released. These are work-in-progress
|
||||
release notes. Go 1.12 is expected to be released in February 2019.
|
||||
</strong>
|
||||
</p>
|
||||
<h2 id="introduction">Introduction to Go 1.12</h2>
|
||||
|
||||
<p>
|
||||
The latest Go release, version 1.12, arrives six months after <a href="go1.11">Go 1.11</a>.
|
||||
@@ -109,7 +102,7 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
is no longer available with <code>go vet</code>. Checking for
|
||||
variable shadowing may now be done using
|
||||
<pre>
|
||||
go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
|
||||
go get -u golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
|
||||
go vet -vettool=$(which shadow)
|
||||
</pre>
|
||||
</p>
|
||||
@@ -121,7 +114,7 @@ The Go tour is no longer included in the main binary distribution. To
|
||||
run the tour locally, instead of running <code>go</code> <code>tool</code> <code>tour</code>,
|
||||
manually install it:
|
||||
<pre>
|
||||
go install golang.org/x/tour
|
||||
go get -u golang.org/x/tour
|
||||
tour
|
||||
</pre>
|
||||
</p>
|
||||
@@ -192,6 +185,17 @@ tour
|
||||
that build fails.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 147282, 147281 -->
|
||||
This changed use of the <code>go</code> directive means that if you
|
||||
use Go 1.12 to build a module, thus recording <code>go 1.12</code>
|
||||
in the <code>go.mod</code> file, you will get an error when
|
||||
attempting to build the same module with Go 1.11 through Go 1.11.3.
|
||||
Go 1.11.4 or later will work fine, as will releases older than Go 1.11.
|
||||
If you must use Go 1.11 through 1.11.3, you can avoid the problem by
|
||||
setting the language version to 1.11, using the Go 1.12 go tool,
|
||||
via <code>go mod edit -go=1.11</code>.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 152739 -->
|
||||
When an import cannot be resolved using the active modules,
|
||||
the <code>go</code> command will now try to use the modules mentioned in the
|
||||
@@ -303,7 +307,9 @@ for {
|
||||
<p>
|
||||
In Go 1.12, <code>godoc</code> no longer has a command-line interface and
|
||||
is only a web server. Users should use <code>go</code> <code>doc</code>
|
||||
for command-line help output instead.
|
||||
for command-line help output instead. Go 1.12 is the last release that will
|
||||
include the <code>godoc</code> webserver; in Go 1.13 it will be available
|
||||
via <code>go</code> <code>get</code>.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 141977 -->
|
||||
@@ -493,8 +499,11 @@ for {
|
||||
<dl id="crypto/rc4"><dt><a href="/pkg/crypto/rc4/">crypto/rc4</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 130397 -->
|
||||
This release removes the optimized assembly implementations. RC4 is insecure
|
||||
and should only be used for compatibility with legacy systems.
|
||||
This release removes the assembly implementations, leaving only
|
||||
the pure Go version. The Go compiler generates code that is
|
||||
either slightly better or slightly worse, depending on the exact
|
||||
CPU. RC4 is insecure and should only be used for compatibility
|
||||
with legacy systems.
|
||||
</p>
|
||||
|
||||
</dl><!-- crypto/rc4 -->
|
||||
@@ -602,17 +611,6 @@ for {
|
||||
|
||||
</dl><!-- io -->
|
||||
|
||||
<dl id="lib/time"><dt><a href="/pkg/lib/time/">lib/time</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 151299 -->
|
||||
The time zone database in <code>$GOROOT/lib/time/zoneinfo.zip</code>
|
||||
has been updated to version 2018i. Note that this ZIP file is
|
||||
only used if a time zone database is not provided by the operating
|
||||
system.
|
||||
</p>
|
||||
|
||||
</dl><!-- lib/time -->
|
||||
|
||||
<dl id="math"><dt><a href="/pkg/math/">math</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 153059 -->
|
||||
@@ -689,6 +687,20 @@ for {
|
||||
|
||||
</dl><!-- net/http -->
|
||||
|
||||
<dl id="net/url"><dt><a href="/pkg/net/url/">net/url</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 159157, CL 160178 -->
|
||||
<a href="/pkg/net/url/#Parse"><code>Parse</code></a>,
|
||||
<a href="/pkg/net/url/#ParseRequestURI"><code>ParseRequestURI</code></a>,
|
||||
and
|
||||
<a href="/pkg/net/url/#URL.Parse"><code>URL.Parse</code></a>
|
||||
now return an
|
||||
error for URLs containing ASCII control characters, which includes NULL,
|
||||
tab, and newlines.
|
||||
</p>
|
||||
|
||||
</dl><!-- net/url -->
|
||||
|
||||
<dl id="net/http/httputil"><dt><a href="/pkg/net/http/httputil/">net/http/httputil</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 146437 -->
|
||||
@@ -912,6 +924,17 @@ for {
|
||||
</p>
|
||||
</dl><!-- text/template -->
|
||||
|
||||
<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 151299 -->
|
||||
The time zone database in <code>$GOROOT/lib/time/zoneinfo.zip</code>
|
||||
has been updated to version 2018i. Note that this ZIP file is
|
||||
only used if a time zone database is not provided by the operating
|
||||
system.
|
||||
</p>
|
||||
|
||||
</dl><!-- time -->
|
||||
|
||||
<dl id="unsafe"><dt><a href="/pkg/unsafe/">unsafe</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 146058 -->
|
||||
|
||||
@@ -349,15 +349,7 @@ provides <b>essential setup instructions</b> for using the Go tools.
|
||||
<p>
|
||||
The source code for several Go tools (including <a href="/cmd/godoc/">godoc</a>)
|
||||
is kept in <a href="https://golang.org/x/tools">the go.tools repository</a>.
|
||||
To install all of them, run the <code>go</code> <code>get</code> command:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ go get golang.org/x/tools/cmd/...
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Or if you just want to install a specific command (<code>godoc</code> in this case):
|
||||
To install one of the tools (<code>godoc</code> in this case):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -374,16 +366,6 @@ You must also have a workspace (<code>GOPATH</code>) set up;
|
||||
see <a href="/doc/code.html">How to Write Go Code</a> for the details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Note</b>: The <code>go</code> command will install the <code>godoc</code>
|
||||
binary to <code>$GOROOT/bin</code> (or <code>$GOBIN</code>) and the
|
||||
<code>cover</code> and <code>vet</code> binaries to
|
||||
<code>$GOROOT/pkg/tool/$GOOS_$GOARCH</code>.
|
||||
You can access the latter commands with
|
||||
"<code>go</code> <code>tool</code> <code>cover</code>" and
|
||||
"<code>go</code> <code>tool</code> <code>vet</code>".
|
||||
</p>
|
||||
|
||||
<h2 id="community">Community resources</h2>
|
||||
|
||||
<p>
|
||||
|
||||
14
misc/cgo/test/testdata/issue30527.go
vendored
Normal file
14
misc/cgo/test/testdata/issue30527.go
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2019 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 30527: function call rewriting casts untyped
|
||||
// constants to int because of ":=" usage.
|
||||
|
||||
package cgotest
|
||||
|
||||
import "cgotest/issue30527"
|
||||
|
||||
func issue30527G() {
|
||||
issue30527.G(nil)
|
||||
}
|
||||
19
misc/cgo/test/testdata/issue30527/a.go
vendored
Normal file
19
misc/cgo/test/testdata/issue30527/a.go
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package issue30527
|
||||
|
||||
import "math"
|
||||
|
||||
/*
|
||||
#include <inttypes.h>
|
||||
|
||||
static void issue30527F(char **p, uint64_t mod, uint32_t unused) {}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func G(p **C.char) {
|
||||
C.issue30527F(p, math.MaxUint64, 1)
|
||||
C.issue30527F(p, 1<<64-1, Z)
|
||||
}
|
||||
11
misc/cgo/test/testdata/issue30527/b.go
vendored
Normal file
11
misc/cgo/test/testdata/issue30527/b.go
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package issue30527
|
||||
|
||||
const (
|
||||
X = 1 << iota
|
||||
Y
|
||||
Z
|
||||
)
|
||||
12
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
12
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
@@ -261,6 +261,18 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
ORRW $0x1b000, R2, R3 // ORRW $110592, R2, R3 // 1b0096523b00a07243001b2a
|
||||
TSTW $0x500000, R1 // TSTW $5242880, R1 // 1b0aa0523f001b6a
|
||||
TSTW $0xff00ff, R1 // TSTW $16711935, R1 // 3f9c0072
|
||||
TSTW $0x60060, R5 // TSTW $393312, R5 // 1b0c8052db00a072bf001b6a
|
||||
TSTW $0x6006000060060, R5 // TSTW $1689262177517664, R5 // 1b0c8052db00a072bf001b6a
|
||||
ANDW $0x6006000060060, R5 // ANDW $1689262177517664, R5 // 1b0c8052db00a072a5001b0a
|
||||
ANDSW $0x6006000060060, R5 // ANDSW $1689262177517664, R5 // 1b0c8052db00a072a5001b6a
|
||||
EORW $0x6006000060060, R5 // EORW $1689262177517664, R5 // 1b0c8052db00a072a5001b4a
|
||||
ORRW $0x6006000060060, R5 // ORRW $1689262177517664, R5 // 1b0c8052db00a072a5001b2a
|
||||
BICW $0x6006000060060, R5 // BICW $1689262177517664, R5 // 1b0c8052db00a072a5003b0a
|
||||
EONW $0x6006000060060, R5 // EONW $1689262177517664, R5 // 1b0c8052db00a072a5003b4a
|
||||
ORNW $0x6006000060060, R5 // ORNW $1689262177517664, R5 // 1b0c8052db00a072a5003b2a
|
||||
BICSW $0x6006000060060, R5 // BICSW $1689262177517664, R5 // 1b0c8052db00a072a5003b6a
|
||||
ADDW $0x60060, R2 // ADDW $393312, R2 // 4280011142804111
|
||||
CMPW $0x60060, R2 // CMPW $393312, R2 // 1b0c8052db00a0725f001b6b
|
||||
|
||||
AND $8, R0, RSP // 1f007d92
|
||||
ORR $8, R0, RSP // 1f007db2
|
||||
|
||||
@@ -200,18 +200,6 @@ func (f *File) saveExprs(x interface{}, context astContext) {
|
||||
}
|
||||
case *ast.CallExpr:
|
||||
f.saveCall(x, context)
|
||||
case *ast.GenDecl:
|
||||
if x.Tok == token.CONST {
|
||||
for _, spec := range x.Specs {
|
||||
vs := spec.(*ast.ValueSpec)
|
||||
if vs.Type == nil {
|
||||
for _, name := range spec.(*ast.ValueSpec).Names {
|
||||
consts[name.Name] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -897,21 +897,16 @@ func (p *Package) rewriteCall(f *File, call *Call) (string, bool) {
|
||||
needsUnsafe = true
|
||||
}
|
||||
|
||||
// Explicitly convert untyped constants to the
|
||||
// parameter type, to avoid a type mismatch.
|
||||
if p.isConst(f, arg) {
|
||||
ptype := p.rewriteUnsafe(param.Go)
|
||||
// Use "var x T = ..." syntax to explicitly convert untyped
|
||||
// constants to the parameter type, to avoid a type mismatch.
|
||||
ptype := p.rewriteUnsafe(param.Go)
|
||||
|
||||
if !p.needsPointerCheck(f, param.Go, args[i]) || param.BadPointer {
|
||||
if ptype != param.Go {
|
||||
needsUnsafe = true
|
||||
}
|
||||
arg = &ast.CallExpr{
|
||||
Fun: ptype,
|
||||
Args: []ast.Expr{arg},
|
||||
}
|
||||
}
|
||||
|
||||
if !p.needsPointerCheck(f, param.Go, args[i]) {
|
||||
fmt.Fprintf(&sb, "_cgo%d := %s; ", i, gofmtPos(arg, origArg.Pos()))
|
||||
fmt.Fprintf(&sb, "var _cgo%d %s = %s; ", i,
|
||||
gofmtLine(ptype), gofmtPos(arg, origArg.Pos()))
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1254,47 +1249,6 @@ func (p *Package) isType(t ast.Expr) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// isConst reports whether x is an untyped constant expression.
|
||||
func (p *Package) isConst(f *File, x ast.Expr) bool {
|
||||
switch x := x.(type) {
|
||||
case *ast.BasicLit:
|
||||
return true
|
||||
case *ast.SelectorExpr:
|
||||
id, ok := x.X.(*ast.Ident)
|
||||
if !ok || id.Name != "C" {
|
||||
return false
|
||||
}
|
||||
name := f.Name[x.Sel.Name]
|
||||
if name != nil {
|
||||
return name.IsConst()
|
||||
}
|
||||
case *ast.Ident:
|
||||
return x.Name == "nil" ||
|
||||
strings.HasPrefix(x.Name, "_Ciconst_") ||
|
||||
strings.HasPrefix(x.Name, "_Cfconst_") ||
|
||||
strings.HasPrefix(x.Name, "_Csconst_") ||
|
||||
consts[x.Name]
|
||||
case *ast.UnaryExpr:
|
||||
return p.isConst(f, x.X)
|
||||
case *ast.BinaryExpr:
|
||||
return p.isConst(f, x.X) && p.isConst(f, x.Y)
|
||||
case *ast.ParenExpr:
|
||||
return p.isConst(f, x.X)
|
||||
case *ast.CallExpr:
|
||||
// Calling the builtin function complex on two untyped
|
||||
// constants returns an untyped constant.
|
||||
// TODO: It's possible to construct a case that will
|
||||
// erroneously succeed if there is a local function
|
||||
// named "complex", shadowing the builtin, that returns
|
||||
// a numeric type. I can't think of any cases that will
|
||||
// erroneously fail.
|
||||
if id, ok := x.Fun.(*ast.Ident); ok && id.Name == "complex" && len(x.Args) == 2 {
|
||||
return p.isConst(f, x.Args[0]) && p.isConst(f, x.Args[1])
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isVariable reports whether x is a variable, possibly with field references.
|
||||
func (p *Package) isVariable(x ast.Expr) bool {
|
||||
switch x := x.(type) {
|
||||
@@ -2511,13 +2465,16 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||
// Treat this typedef as a uintptr.
|
||||
s := *sub
|
||||
s.Go = c.uintptr
|
||||
s.BadPointer = true
|
||||
sub = &s
|
||||
// Make sure we update any previously computed type.
|
||||
if oldType := typedef[name.Name]; oldType != nil {
|
||||
oldType.Go = sub.Go
|
||||
oldType.BadPointer = true
|
||||
}
|
||||
}
|
||||
t.Go = name
|
||||
t.BadPointer = sub.BadPointer
|
||||
if unionWithPointer[sub.Go] {
|
||||
unionWithPointer[t.Go] = true
|
||||
}
|
||||
@@ -2527,6 +2484,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||
if oldType == nil {
|
||||
tt := *t
|
||||
tt.Go = sub.Go
|
||||
tt.BadPointer = sub.BadPointer
|
||||
typedef[name.Name] = &tt
|
||||
}
|
||||
|
||||
|
||||
@@ -71,9 +71,6 @@ type File struct {
|
||||
Edit *edit.Buffer
|
||||
}
|
||||
|
||||
// Untyped constants in the current package.
|
||||
var consts = make(map[string]bool)
|
||||
|
||||
func (f *File) offset(p token.Pos) int {
|
||||
return fset.Position(p).Offset
|
||||
}
|
||||
@@ -154,6 +151,7 @@ type Type struct {
|
||||
Go ast.Expr
|
||||
EnumValues map[string]int64
|
||||
Typedef string
|
||||
BadPointer bool
|
||||
}
|
||||
|
||||
// A FuncType collects information about a function type in both the C and Go worlds.
|
||||
|
||||
@@ -24,6 +24,7 @@ func Init(arch *gc.Arch) {
|
||||
arch.ZeroRange = zerorange
|
||||
arch.ZeroAuto = zeroAuto
|
||||
arch.Ginsnop = ginsnop
|
||||
arch.Ginsnopdefer = ginsnop
|
||||
|
||||
arch.SSAMarkMoves = ssaMarkMoves
|
||||
arch.SSAGenValue = ssaGenValue
|
||||
|
||||
@@ -19,6 +19,7 @@ func Init(arch *gc.Arch) {
|
||||
arch.ZeroRange = zerorange
|
||||
arch.ZeroAuto = zeroAuto
|
||||
arch.Ginsnop = ginsnop
|
||||
arch.Ginsnopdefer = ginsnop
|
||||
|
||||
arch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
|
||||
arch.SSAGenValue = ssaGenValue
|
||||
|
||||
@@ -19,6 +19,7 @@ func Init(arch *gc.Arch) {
|
||||
arch.ZeroRange = zerorange
|
||||
arch.ZeroAuto = zeroAuto
|
||||
arch.Ginsnop = ginsnop
|
||||
arch.Ginsnopdefer = ginsnop
|
||||
|
||||
arch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
|
||||
arch.SSAGenValue = ssaGenValue
|
||||
|
||||
@@ -127,7 +127,7 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
|
||||
DeclLine: v.DeclLine,
|
||||
DeclCol: v.DeclCol,
|
||||
}
|
||||
synthesized := strings.HasPrefix(v.Name, "~r") || canonName == "_"
|
||||
synthesized := strings.HasPrefix(v.Name, "~r") || canonName == "_" || strings.HasPrefix(v.Name, "~b")
|
||||
if idx, found := m[vp]; found {
|
||||
v.ChildIndex = int32(idx)
|
||||
v.IsInAbstract = !synthesized
|
||||
|
||||
@@ -2105,6 +2105,16 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
|
||||
step.describe(src)
|
||||
}
|
||||
extraloopdepth = modSrcLoopdepth
|
||||
if src.Op == OCONVIFACE {
|
||||
lt := src.Left.Type
|
||||
if !lt.IsInterface() && !isdirectiface(lt) && types.Haspointers(lt) {
|
||||
// We're converting from a non-direct interface type.
|
||||
// The interface will hold a heap copy of the data
|
||||
// (by calling convT2I or friend). Flow the data to heap.
|
||||
// See issue 29353.
|
||||
e.escwalk(level, &e.theSink, src.Left, e.stepWalk(dst, src.Left, "interface-converted", step))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case ODOT,
|
||||
|
||||
@@ -255,9 +255,10 @@ type Arch struct {
|
||||
Use387 bool // should 386 backend use 387 FP instructions instead of sse2.
|
||||
SoftFloat bool
|
||||
|
||||
PadFrame func(int64) int64
|
||||
ZeroRange func(*Progs, *obj.Prog, int64, int64, *uint32) *obj.Prog
|
||||
Ginsnop func(*Progs) *obj.Prog
|
||||
PadFrame func(int64) int64
|
||||
ZeroRange func(*Progs, *obj.Prog, int64, int64, *uint32) *obj.Prog
|
||||
Ginsnop func(*Progs) *obj.Prog
|
||||
Ginsnopdefer func(*Progs) *obj.Prog // special ginsnop for deferreturn
|
||||
|
||||
// SSAMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
|
||||
SSAMarkMoves func(*SSAGenState, *ssa.Block)
|
||||
|
||||
@@ -1108,10 +1108,10 @@ func (o *Order) expr(n, lhs *Node) *Node {
|
||||
if n.Left.Type.IsInterface() {
|
||||
break
|
||||
}
|
||||
if _, needsaddr := convFuncName(n.Left.Type, n.Type); needsaddr || consttype(n.Left) > 0 {
|
||||
if _, needsaddr := convFuncName(n.Left.Type, n.Type); needsaddr || isStaticCompositeLiteral(n.Left) {
|
||||
// Need a temp if we need to pass the address to the conversion function.
|
||||
// We also process constants here, making a named static global whose
|
||||
// address we can put directly in an interface (see OCONVIFACE case in walk).
|
||||
// We also process static composite literal node here, making a named static global
|
||||
// whose address we can put directly in an interface (see OCONVIFACE case in walk).
|
||||
n.Left = o.addrTemp(n.Left)
|
||||
}
|
||||
|
||||
@@ -1130,14 +1130,40 @@ func (o *Order) expr(n, lhs *Node) *Node {
|
||||
}
|
||||
|
||||
case OANDAND, OOROR:
|
||||
mark := o.markTemp()
|
||||
n.Left = o.expr(n.Left, nil)
|
||||
// ... = LHS && RHS
|
||||
//
|
||||
// var r bool
|
||||
// r = LHS
|
||||
// if r { // or !r, for OROR
|
||||
// r = RHS
|
||||
// }
|
||||
// ... = r
|
||||
|
||||
// Clean temporaries from first branch at beginning of second.
|
||||
// Leave them on the stack so that they can be killed in the outer
|
||||
// context in case the short circuit is taken.
|
||||
n.Right = addinit(n.Right, o.cleanTempNoPop(mark))
|
||||
n.Right = o.exprInPlace(n.Right)
|
||||
r := o.newTemp(n.Type, false)
|
||||
|
||||
// Evaluate left-hand side.
|
||||
lhs := o.expr(n.Left, nil)
|
||||
o.out = append(o.out, typecheck(nod(OAS, r, lhs), ctxStmt))
|
||||
|
||||
// Evaluate right-hand side, save generated code.
|
||||
saveout := o.out
|
||||
o.out = nil
|
||||
t := o.markTemp()
|
||||
rhs := o.expr(n.Right, nil)
|
||||
o.out = append(o.out, typecheck(nod(OAS, r, rhs), ctxStmt))
|
||||
o.cleanTemp(t)
|
||||
gen := o.out
|
||||
o.out = saveout
|
||||
|
||||
// If left-hand side doesn't cause a short-circuit, issue right-hand side.
|
||||
nif := nod(OIF, r, nil)
|
||||
if n.Op == OANDAND {
|
||||
nif.Nbody.Set(gen)
|
||||
} else {
|
||||
nif.Rlist.Set(gen)
|
||||
}
|
||||
o.out = append(o.out, nif)
|
||||
n = r
|
||||
|
||||
case OCALLFUNC,
|
||||
OCALLINTER,
|
||||
|
||||
@@ -597,8 +597,22 @@ func createDwarfVars(fnsym *obj.LSym, fn *Func, automDecls []*Node) ([]*Node, []
|
||||
typename := dwarf.InfoPrefix + typesymname(n.Type)
|
||||
decls = append(decls, n)
|
||||
abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
|
||||
isReturnValue := (n.Class() == PPARAMOUT)
|
||||
if n.Class() == PPARAM || n.Class() == PPARAMOUT {
|
||||
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
|
||||
} else if n.Class() == PAUTOHEAP {
|
||||
// If dcl in question has been promoted to heap, do a bit
|
||||
// of extra work to recover original class (auto or param);
|
||||
// see issue 30908. This insures that we get the proper
|
||||
// signature in the abstract function DIE, but leaves a
|
||||
// misleading location for the param (we want pointer-to-heap
|
||||
// and not stack).
|
||||
// TODO(thanm): generate a better location expression
|
||||
stackcopy := n.Name.Param.Stackcopy
|
||||
if stackcopy != nil && (stackcopy.Class() == PPARAM || stackcopy.Class() == PPARAMOUT) {
|
||||
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
|
||||
isReturnValue = (stackcopy.Class() == PPARAMOUT)
|
||||
}
|
||||
}
|
||||
inlIndex := 0
|
||||
if genDwarfInline > 1 {
|
||||
@@ -612,7 +626,7 @@ func createDwarfVars(fnsym *obj.LSym, fn *Func, automDecls []*Node) ([]*Node, []
|
||||
declpos := Ctxt.InnermostPos(n.Pos)
|
||||
vars = append(vars, &dwarf.Var{
|
||||
Name: n.Sym.Name,
|
||||
IsReturnValue: n.Class() == PPARAMOUT,
|
||||
IsReturnValue: isReturnValue,
|
||||
Abbrev: abbrev,
|
||||
StackOffset: int32(n.Xoffset),
|
||||
Type: Ctxt.Lookup(typename),
|
||||
|
||||
@@ -993,26 +993,32 @@ func (s *state) stmt(n *Node) {
|
||||
s.assign(n.Left, r, deref, skip)
|
||||
|
||||
case OIF:
|
||||
bThen := s.f.NewBlock(ssa.BlockPlain)
|
||||
bEnd := s.f.NewBlock(ssa.BlockPlain)
|
||||
var bElse *ssa.Block
|
||||
var likely int8
|
||||
if n.Likely() {
|
||||
likely = 1
|
||||
}
|
||||
var bThen *ssa.Block
|
||||
if n.Nbody.Len() != 0 {
|
||||
bThen = s.f.NewBlock(ssa.BlockPlain)
|
||||
} else {
|
||||
bThen = bEnd
|
||||
}
|
||||
var bElse *ssa.Block
|
||||
if n.Rlist.Len() != 0 {
|
||||
bElse = s.f.NewBlock(ssa.BlockPlain)
|
||||
s.condBranch(n.Left, bThen, bElse, likely)
|
||||
} else {
|
||||
s.condBranch(n.Left, bThen, bEnd, likely)
|
||||
bElse = bEnd
|
||||
}
|
||||
s.condBranch(n.Left, bThen, bElse, likely)
|
||||
|
||||
s.startBlock(bThen)
|
||||
s.stmtList(n.Nbody)
|
||||
if b := s.endBlock(); b != nil {
|
||||
b.AddEdgeTo(bEnd)
|
||||
if n.Nbody.Len() != 0 {
|
||||
s.startBlock(bThen)
|
||||
s.stmtList(n.Nbody)
|
||||
if b := s.endBlock(); b != nil {
|
||||
b.AddEdgeTo(bEnd)
|
||||
}
|
||||
}
|
||||
|
||||
if n.Rlist.Len() != 0 {
|
||||
s.startBlock(bElse)
|
||||
s.stmtList(n.Rlist)
|
||||
@@ -5597,7 +5603,7 @@ func (s *SSAGenState) PrepareCall(v *ssa.Value) {
|
||||
// insert an actual hardware NOP that will have the right line number.
|
||||
// This is different from obj.ANOP, which is a virtual no-op
|
||||
// that doesn't make it into the instruction stream.
|
||||
thearch.Ginsnop(s.pp)
|
||||
thearch.Ginsnopdefer(s.pp)
|
||||
}
|
||||
|
||||
if sym, ok := v.Aux.(*obj.LSym); ok {
|
||||
|
||||
@@ -22,6 +22,7 @@ func Init(arch *gc.Arch) {
|
||||
arch.ZeroRange = zerorange
|
||||
arch.ZeroAuto = zeroAuto
|
||||
arch.Ginsnop = ginsnop
|
||||
arch.Ginsnopdefer = ginsnop
|
||||
arch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
|
||||
arch.SSAGenValue = ssaGenValue
|
||||
arch.SSAGenBlock = ssaGenBlock
|
||||
|
||||
@@ -22,6 +22,7 @@ func Init(arch *gc.Arch) {
|
||||
arch.ZeroRange = zerorange
|
||||
arch.ZeroAuto = zeroAuto
|
||||
arch.Ginsnop = ginsnop
|
||||
arch.Ginsnopdefer = ginsnop
|
||||
|
||||
arch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
|
||||
arch.SSAGenValue = ssaGenValue
|
||||
|
||||
@@ -20,7 +20,8 @@ func Init(arch *gc.Arch) {
|
||||
|
||||
arch.ZeroRange = zerorange
|
||||
arch.ZeroAuto = zeroAuto
|
||||
arch.Ginsnop = ginsnop2
|
||||
arch.Ginsnop = ginsnop
|
||||
arch.Ginsnopdefer = ginsnop2
|
||||
|
||||
arch.SSAMarkMoves = ssaMarkMoves
|
||||
arch.SSAGenValue = ssaGenValue
|
||||
|
||||
@@ -17,6 +17,7 @@ func Init(arch *gc.Arch) {
|
||||
arch.ZeroRange = zerorange
|
||||
arch.ZeroAuto = zeroAuto
|
||||
arch.Ginsnop = ginsnop
|
||||
arch.Ginsnopdefer = ginsnop
|
||||
|
||||
arch.SSAMarkMoves = ssaMarkMoves
|
||||
arch.SSAGenValue = ssaGenValue
|
||||
|
||||
@@ -1220,6 +1220,13 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
// This forces later liveness analysis to make the
|
||||
// value live at this point.
|
||||
v.SetArg(0, s.makeSpill(a, b))
|
||||
} else if _, ok := a.Aux.(GCNode); ok && vi.rematerializeable {
|
||||
// Rematerializeable value with a gc.Node. This is the address of
|
||||
// a stack object (e.g. an LEAQ). Keep the object live.
|
||||
// Change it to VarLive, which is what plive expects for locals.
|
||||
v.Op = OpVarLive
|
||||
v.SetArgs1(v.Args[1])
|
||||
v.Aux = a.Aux
|
||||
} else {
|
||||
// In-register and rematerializeable values are already live.
|
||||
// These are typically rematerializeable constants like nil,
|
||||
|
||||
@@ -1141,7 +1141,7 @@ func symIsRO(sym interface{}) bool {
|
||||
// read8 reads one byte from the read-only global sym at offset off.
|
||||
func read8(sym interface{}, off int64) uint8 {
|
||||
lsym := sym.(*obj.LSym)
|
||||
if off >= int64(len(lsym.P)) {
|
||||
if off >= int64(len(lsym.P)) || off < 0 {
|
||||
// Invalid index into the global sym.
|
||||
// This can happen in dead code, so we don't want to panic.
|
||||
// Just return any value, it will eventually get ignored.
|
||||
@@ -1154,7 +1154,7 @@ func read8(sym interface{}, off int64) uint8 {
|
||||
// read16 reads two bytes from the read-only global sym at offset off.
|
||||
func read16(sym interface{}, off int64, bigEndian bool) uint16 {
|
||||
lsym := sym.(*obj.LSym)
|
||||
if off >= int64(len(lsym.P))-1 {
|
||||
if off >= int64(len(lsym.P))-1 || off < 0 {
|
||||
return 0
|
||||
}
|
||||
if bigEndian {
|
||||
@@ -1167,7 +1167,7 @@ func read16(sym interface{}, off int64, bigEndian bool) uint16 {
|
||||
// read32 reads four bytes from the read-only global sym at offset off.
|
||||
func read32(sym interface{}, off int64, bigEndian bool) uint32 {
|
||||
lsym := sym.(*obj.LSym)
|
||||
if off >= int64(len(lsym.P))-3 {
|
||||
if off >= int64(len(lsym.P))-3 || off < 0 {
|
||||
return 0
|
||||
}
|
||||
if bigEndian {
|
||||
@@ -1180,7 +1180,7 @@ func read32(sym interface{}, off int64, bigEndian bool) uint32 {
|
||||
// read64 reads eight bytes from the read-only global sym at offset off.
|
||||
func read64(sym interface{}, off int64, bigEndian bool) uint64 {
|
||||
lsym := sym.(*obj.LSym)
|
||||
if off >= int64(len(lsym.P))-7 {
|
||||
if off >= int64(len(lsym.P))-7 || off < 0 {
|
||||
return 0
|
||||
}
|
||||
if bigEndian {
|
||||
|
||||
@@ -196,6 +196,43 @@ func writebarrier(f *Func) {
|
||||
// and simple store version to bElse
|
||||
memThen := mem
|
||||
memElse := mem
|
||||
|
||||
// If the source of a MoveWB is volatile (will be clobbered by a
|
||||
// function call), we need to copy it to a temporary location, as
|
||||
// marshaling the args of typedmemmove might clobber the value we're
|
||||
// trying to move.
|
||||
// Look for volatile source, copy it to temporary before we emit any
|
||||
// call.
|
||||
// It is unlikely to have more than one of them. Just do a linear
|
||||
// search instead of using a map.
|
||||
type volatileCopy struct {
|
||||
src *Value // address of original volatile value
|
||||
tmp *Value // address of temporary we've copied the volatile value into
|
||||
}
|
||||
var volatiles []volatileCopy
|
||||
copyLoop:
|
||||
for _, w := range stores {
|
||||
if w.Op == OpMoveWB {
|
||||
val := w.Args[1]
|
||||
if isVolatile(val) {
|
||||
for _, c := range volatiles {
|
||||
if val == c.src {
|
||||
continue copyLoop // already copied
|
||||
}
|
||||
}
|
||||
|
||||
t := val.Type.Elem()
|
||||
tmp := f.fe.Auto(w.Pos, t)
|
||||
memThen = bThen.NewValue1A(w.Pos, OpVarDef, types.TypeMem, tmp, memThen)
|
||||
tmpaddr := bThen.NewValue2A(w.Pos, OpLocalAddr, t.PtrTo(), tmp, sp, memThen)
|
||||
siz := t.Size()
|
||||
memThen = bThen.NewValue3I(w.Pos, OpMove, types.TypeMem, siz, tmpaddr, val, memThen)
|
||||
memThen.Aux = t
|
||||
volatiles = append(volatiles, volatileCopy{val, tmpaddr})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, w := range stores {
|
||||
ptr := w.Args[0]
|
||||
pos := w.Pos
|
||||
@@ -222,11 +259,19 @@ func writebarrier(f *Func) {
|
||||
// then block: emit write barrier call
|
||||
switch w.Op {
|
||||
case OpStoreWB, OpMoveWB, OpZeroWB:
|
||||
volatile := w.Op == OpMoveWB && isVolatile(val)
|
||||
if w.Op == OpStoreWB {
|
||||
memThen = bThen.NewValue3A(pos, OpWB, types.TypeMem, gcWriteBarrier, ptr, val, memThen)
|
||||
} else {
|
||||
memThen = wbcall(pos, bThen, fn, typ, ptr, val, memThen, sp, sb, volatile)
|
||||
srcval := val
|
||||
if w.Op == OpMoveWB && isVolatile(srcval) {
|
||||
for _, c := range volatiles {
|
||||
if srcval == c.src {
|
||||
srcval = c.tmp
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
memThen = wbcall(pos, bThen, fn, typ, ptr, srcval, memThen, sp, sb)
|
||||
}
|
||||
// Note that we set up a writebarrier function call.
|
||||
f.fe.SetWBPos(pos)
|
||||
@@ -249,6 +294,12 @@ func writebarrier(f *Func) {
|
||||
}
|
||||
}
|
||||
|
||||
// mark volatile temps dead
|
||||
for _, c := range volatiles {
|
||||
tmpNode := c.tmp.Aux
|
||||
memThen = bThen.NewValue1A(memThen.Pos, OpVarKill, types.TypeMem, tmpNode, memThen)
|
||||
}
|
||||
|
||||
// merge memory
|
||||
// Splice memory Phi into the last memory of the original sequence,
|
||||
// which may be used in subsequent blocks. Other memories in the
|
||||
@@ -302,25 +353,9 @@ func writebarrier(f *Func) {
|
||||
}
|
||||
|
||||
// wbcall emits write barrier runtime call in b, returns memory.
|
||||
// if valIsVolatile, it moves val into temp space before making the call.
|
||||
func wbcall(pos src.XPos, b *Block, fn, typ *obj.LSym, ptr, val, mem, sp, sb *Value, valIsVolatile bool) *Value {
|
||||
func wbcall(pos src.XPos, b *Block, fn, typ *obj.LSym, ptr, val, mem, sp, sb *Value) *Value {
|
||||
config := b.Func.Config
|
||||
|
||||
var tmp GCNode
|
||||
if valIsVolatile {
|
||||
// Copy to temp location if the source is volatile (will be clobbered by
|
||||
// a function call). Marshaling the args to typedmemmove might clobber the
|
||||
// value we're trying to move.
|
||||
t := val.Type.Elem()
|
||||
tmp = b.Func.fe.Auto(val.Pos, t)
|
||||
mem = b.NewValue1A(pos, OpVarDef, types.TypeMem, tmp, mem)
|
||||
tmpaddr := b.NewValue2A(pos, OpLocalAddr, t.PtrTo(), tmp, sp, mem)
|
||||
siz := t.Size()
|
||||
mem = b.NewValue3I(pos, OpMove, types.TypeMem, siz, tmpaddr, val, mem)
|
||||
mem.Aux = t
|
||||
val = tmpaddr
|
||||
}
|
||||
|
||||
// put arguments on stack
|
||||
off := config.ctxt.FixedFrameSize()
|
||||
|
||||
@@ -348,11 +383,6 @@ func wbcall(pos src.XPos, b *Block, fn, typ *obj.LSym, ptr, val, mem, sp, sb *Va
|
||||
// issue call
|
||||
mem = b.NewValue1A(pos, OpStaticCall, types.TypeMem, fn, mem)
|
||||
mem.AuxInt = off - config.ctxt.FixedFrameSize()
|
||||
|
||||
if valIsVolatile {
|
||||
mem = b.NewValue1A(pos, OpVarKill, types.TypeMem, tmp, mem) // mark temp dead
|
||||
}
|
||||
|
||||
return mem
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ func Init(arch *gc.Arch) {
|
||||
arch.ZeroRange = zeroRange
|
||||
arch.ZeroAuto = zeroAuto
|
||||
arch.Ginsnop = ginsnop
|
||||
arch.Ginsnopdefer = ginsnop
|
||||
|
||||
arch.SSAMarkMoves = ssaMarkMoves
|
||||
arch.SSAGenValue = ssaGenValue
|
||||
|
||||
@@ -32,6 +32,7 @@ func Init(arch *gc.Arch) {
|
||||
arch.ZeroRange = zerorange
|
||||
arch.ZeroAuto = zeroAuto
|
||||
arch.Ginsnop = ginsnop
|
||||
arch.Ginsnopdefer = ginsnop
|
||||
|
||||
arch.SSAMarkMoves = ssaMarkMoves
|
||||
}
|
||||
|
||||
7
src/cmd/go/internal/cache/default.go
vendored
7
src/cmd/go/internal/cache/default.go
vendored
@@ -37,7 +37,7 @@ See golang.org to learn more about Go.
|
||||
// the first time Default is called.
|
||||
func initDefaultCache() {
|
||||
dir := DefaultDir()
|
||||
if dir == "off" || dir == "" {
|
||||
if dir == "off" {
|
||||
if defaultDirErr != nil {
|
||||
base.Fatalf("build cache is required, but could not be located: %v", defaultDirErr)
|
||||
}
|
||||
@@ -74,7 +74,12 @@ func DefaultDir() string {
|
||||
|
||||
defaultDirOnce.Do(func() {
|
||||
defaultDir = os.Getenv("GOCACHE")
|
||||
if filepath.IsAbs(defaultDir) || defaultDir == "off" {
|
||||
return
|
||||
}
|
||||
if defaultDir != "" {
|
||||
defaultDir = "off"
|
||||
defaultDirErr = fmt.Errorf("GOCACHE is not an absolute path")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1178,6 +1178,36 @@ var cgoSyscallExclude = map[string]bool{
|
||||
|
||||
var foldPath = make(map[string]string)
|
||||
|
||||
// DefaultExecName returns the default executable name
|
||||
// for a package with the import path importPath.
|
||||
//
|
||||
// The default executable name is the last element of the import path.
|
||||
// In module-aware mode, an additional rule is used. If the last element
|
||||
// is a vN path element specifying the major version, then the second last
|
||||
// element of the import path is used instead.
|
||||
func DefaultExecName(importPath string) string {
|
||||
_, elem := pathpkg.Split(importPath)
|
||||
if cfg.ModulesEnabled {
|
||||
// If this is example.com/mycmd/v2, it's more useful to install it as mycmd than as v2.
|
||||
// See golang.org/issue/24667.
|
||||
isVersion := func(v string) bool {
|
||||
if len(v) < 2 || v[0] != 'v' || v[1] < '1' || '9' < v[1] {
|
||||
return false
|
||||
}
|
||||
for i := 2; i < len(v); i++ {
|
||||
if c := v[i]; c < '0' || '9' < c {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
if isVersion(elem) {
|
||||
_, elem = pathpkg.Split(pathpkg.Dir(importPath))
|
||||
}
|
||||
}
|
||||
return elem
|
||||
}
|
||||
|
||||
// load populates p using information from bp, err, which should
|
||||
// be the result of calling build.Context.Import.
|
||||
func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
|
||||
@@ -1220,7 +1250,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
|
||||
}
|
||||
_, elem := filepath.Split(p.Dir)
|
||||
if cfg.ModulesEnabled {
|
||||
// NOTE(rsc): Using p.ImportPath instead of p.Dir
|
||||
// NOTE(rsc,dmitshur): Using p.ImportPath instead of p.Dir
|
||||
// makes sure we install a package in the root of a
|
||||
// cached module directory as that package name
|
||||
// not name@v1.2.3.
|
||||
@@ -1229,26 +1259,9 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
|
||||
// even for non-module-enabled code,
|
||||
// but I'm not brave enough to change the
|
||||
// non-module behavior this late in the
|
||||
// release cycle. Maybe for Go 1.12.
|
||||
// release cycle. Can be done for Go 1.13.
|
||||
// See golang.org/issue/26869.
|
||||
_, elem = pathpkg.Split(p.ImportPath)
|
||||
|
||||
// If this is example.com/mycmd/v2, it's more useful to install it as mycmd than as v2.
|
||||
// See golang.org/issue/24667.
|
||||
isVersion := func(v string) bool {
|
||||
if len(v) < 2 || v[0] != 'v' || v[1] < '1' || '9' < v[1] {
|
||||
return false
|
||||
}
|
||||
for i := 2; i < len(v); i++ {
|
||||
if c := v[i]; c < '0' || '9' < c {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
if isVersion(elem) {
|
||||
_, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath))
|
||||
}
|
||||
elem = DefaultExecName(p.ImportPath)
|
||||
}
|
||||
full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem
|
||||
if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH {
|
||||
|
||||
@@ -129,6 +129,7 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag
|
||||
ptest.Internal.Imports = append(imports, p.Internal.Imports...)
|
||||
ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports)
|
||||
ptest.Internal.ForceLibrary = true
|
||||
ptest.Internal.BuildInfo = ""
|
||||
ptest.Internal.Build = new(build.Package)
|
||||
*ptest.Internal.Build = *p.Internal.Build
|
||||
m := map[string][]token.Position{}
|
||||
@@ -186,6 +187,7 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag
|
||||
},
|
||||
Internal: PackageInternal{
|
||||
Build: &build.Package{Name: "main"},
|
||||
BuildInfo: p.Internal.BuildInfo,
|
||||
Asmflags: p.Internal.Asmflags,
|
||||
Gcflags: p.Internal.Gcflags,
|
||||
Ldflags: p.Internal.Ldflags,
|
||||
@@ -266,17 +268,8 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag
|
||||
pmain.Imports = pmain.Imports[:w]
|
||||
pmain.Internal.RawImports = str.StringList(pmain.Imports)
|
||||
|
||||
if ptest != p {
|
||||
// We have made modifications to the package p being tested
|
||||
// and are rebuilding p (as ptest).
|
||||
// Arrange to rebuild all packages q such that
|
||||
// the test depends on q and q depends on p.
|
||||
// This makes sure that q sees the modifications to p.
|
||||
// Strictly speaking, the rebuild is only necessary if the
|
||||
// modifications to p change its export metadata, but
|
||||
// determining that is a bit tricky, so we rebuild always.
|
||||
recompileForTest(pmain, p, ptest, pxtest)
|
||||
}
|
||||
// Replace pmain's transitive dependencies with test copies, as necessary.
|
||||
recompileForTest(pmain, p, ptest, pxtest)
|
||||
|
||||
// Should we apply coverage analysis locally,
|
||||
// only for this package and only for this test?
|
||||
@@ -323,6 +316,14 @@ Search:
|
||||
return stk
|
||||
}
|
||||
|
||||
// recompileForTest copies and replaces certain packages in pmain's dependency
|
||||
// graph. This is necessary for two reasons. First, if ptest is different than
|
||||
// preal, packages that import the package under test should get ptest instead
|
||||
// of preal. This is particularly important if pxtest depends on functionality
|
||||
// exposed in test sources in ptest. Second, if there is a main package
|
||||
// (other than pmain) anywhere, we need to clear p.Internal.BuildInfo in
|
||||
// the test copy to prevent link conflicts. This may happen if both -coverpkg
|
||||
// and the command line patterns include multiple main packages.
|
||||
func recompileForTest(pmain, preal, ptest, pxtest *Package) {
|
||||
// The "test copy" of preal is ptest.
|
||||
// For each package that depends on preal, make a "test copy"
|
||||
@@ -352,6 +353,7 @@ func recompileForTest(pmain, preal, ptest, pxtest *Package) {
|
||||
copy(p1.Imports, p.Imports)
|
||||
p = p1
|
||||
p.Target = ""
|
||||
p.Internal.BuildInfo = ""
|
||||
}
|
||||
|
||||
// Update p.Internal.Imports to use test copies.
|
||||
@@ -361,6 +363,13 @@ func recompileForTest(pmain, preal, ptest, pxtest *Package) {
|
||||
p.Internal.Imports[i] = p1
|
||||
}
|
||||
}
|
||||
|
||||
// Don't compile build info from a main package. This can happen
|
||||
// if -coverpkg patterns include main packages, since those packages
|
||||
// are imported by pmain. See golang.org/issue/30907.
|
||||
if p.Internal.BuildInfo != "" && p != pmain {
|
||||
split()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,55 +23,99 @@ import (
|
||||
type codeRepo struct {
|
||||
modPath string
|
||||
|
||||
code codehost.Repo
|
||||
// code is the repository containing this module.
|
||||
code codehost.Repo
|
||||
// codeRoot is the import path at the root of code.
|
||||
codeRoot string
|
||||
codeDir string
|
||||
// codeDir is the directory (relative to root) at which we expect to find the module.
|
||||
// If pathMajor is non-empty and codeRoot is not the full modPath,
|
||||
// then we look in both codeDir and codeDir+modPath
|
||||
codeDir string
|
||||
|
||||
path string
|
||||
pathPrefix string
|
||||
pathMajor string
|
||||
// pathMajor is the suffix of modPath that indicates its major version,
|
||||
// or the empty string if modPath is at major version 0 or 1.
|
||||
//
|
||||
// pathMajor is typically of the form "/vN", but possibly ".vN", or
|
||||
// ".vN-unstable" for modules resolved using gopkg.in.
|
||||
pathMajor string
|
||||
// pathPrefix is the prefix of modPath that excludes pathMajor.
|
||||
// It is used only for logging.
|
||||
pathPrefix string
|
||||
|
||||
// pseudoMajor is the major version prefix to use when generating
|
||||
// pseudo-versions for this module, derived from the module path.
|
||||
//
|
||||
// TODO(golang.org/issue/29262): We can't distinguish v0 from v1 using the
|
||||
// path alone: we have to compute it by examining the tags at a particular
|
||||
// revision.
|
||||
pseudoMajor string
|
||||
}
|
||||
|
||||
func newCodeRepo(code codehost.Repo, root, path string) (Repo, error) {
|
||||
if !hasPathPrefix(path, root) {
|
||||
return nil, fmt.Errorf("mismatched repo: found %s for %s", root, path)
|
||||
// newCodeRepo returns a Repo that reads the source code for the module with the
|
||||
// given path, from the repo stored in code, with the root of the repo
|
||||
// containing the path given by codeRoot.
|
||||
func newCodeRepo(code codehost.Repo, codeRoot, path string) (Repo, error) {
|
||||
if !hasPathPrefix(path, codeRoot) {
|
||||
return nil, fmt.Errorf("mismatched repo: found %s for %s", codeRoot, path)
|
||||
}
|
||||
pathPrefix, pathMajor, ok := module.SplitPathVersion(path)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid module path %q", path)
|
||||
}
|
||||
if codeRoot == path {
|
||||
pathPrefix = path
|
||||
}
|
||||
pseudoMajor := "v0"
|
||||
if pathMajor != "" {
|
||||
pseudoMajor = pathMajor[1:]
|
||||
}
|
||||
|
||||
// Compute codeDir = bar, the subdirectory within the repo
|
||||
// corresponding to the module root.
|
||||
//
|
||||
// At this point we might have:
|
||||
// codeRoot = github.com/rsc/foo
|
||||
// path = github.com/rsc/foo/bar/v2
|
||||
// codeRoot = github.com/rsc/foo
|
||||
// pathPrefix = github.com/rsc/foo/bar
|
||||
// pathMajor = /v2
|
||||
// pseudoMajor = v2
|
||||
//
|
||||
// Compute codeDir = bar, the subdirectory within the repo
|
||||
// corresponding to the module root.
|
||||
codeDir := strings.Trim(strings.TrimPrefix(pathPrefix, root), "/")
|
||||
if strings.HasPrefix(path, "gopkg.in/") {
|
||||
// But gopkg.in is a special legacy case, in which pathPrefix does not start with codeRoot.
|
||||
// For example we might have:
|
||||
// codeRoot = gopkg.in/yaml.v2
|
||||
// pathPrefix = gopkg.in/yaml
|
||||
// pathMajor = .v2
|
||||
// pseudoMajor = v2
|
||||
// codeDir = pathPrefix (because codeRoot is not a prefix of pathPrefix)
|
||||
// Clear codeDir - the module root is the repo root for gopkg.in repos.
|
||||
codeDir = ""
|
||||
// which gives
|
||||
// codeDir = bar
|
||||
//
|
||||
// We know that pathPrefix is a prefix of path, and codeRoot is a prefix of
|
||||
// path, but codeRoot may or may not be a prefix of pathPrefix, because
|
||||
// codeRoot may be the entire path (in which case codeDir should be empty).
|
||||
// That occurs in two situations.
|
||||
//
|
||||
// One is when a go-import meta tag resolves the complete module path,
|
||||
// including the pathMajor suffix:
|
||||
// path = nanomsg.org/go/mangos/v2
|
||||
// codeRoot = nanomsg.org/go/mangos/v2
|
||||
// pathPrefix = nanomsg.org/go/mangos
|
||||
// pathMajor = /v2
|
||||
// pseudoMajor = v2
|
||||
//
|
||||
// The other is similar: for gopkg.in only, the major version is encoded
|
||||
// with a dot rather than a slash, and thus can't be in a subdirectory.
|
||||
// path = gopkg.in/yaml.v2
|
||||
// codeRoot = gopkg.in/yaml.v2
|
||||
// pathPrefix = gopkg.in/yaml
|
||||
// pathMajor = .v2
|
||||
// pseudoMajor = v2
|
||||
//
|
||||
codeDir := ""
|
||||
if codeRoot != path {
|
||||
if !hasPathPrefix(pathPrefix, codeRoot) {
|
||||
return nil, fmt.Errorf("repository rooted at %s cannot contain module %s", codeRoot, path)
|
||||
}
|
||||
codeDir = strings.Trim(pathPrefix[len(codeRoot):], "/")
|
||||
}
|
||||
|
||||
r := &codeRepo{
|
||||
modPath: path,
|
||||
code: code,
|
||||
codeRoot: root,
|
||||
codeRoot: codeRoot,
|
||||
codeDir: codeDir,
|
||||
pathPrefix: pathPrefix,
|
||||
pathMajor: pathMajor,
|
||||
@@ -149,9 +193,6 @@ func (r *codeRepo) Stat(rev string) (*RevInfo, error) {
|
||||
return r.Latest()
|
||||
}
|
||||
codeRev := r.revToRev(rev)
|
||||
if semver.IsValid(codeRev) && r.codeDir != "" {
|
||||
codeRev = r.codeDir + "/" + codeRev
|
||||
}
|
||||
info, err := r.code.Stat(codeRev)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -290,7 +331,7 @@ func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err e
|
||||
found1 := err1 == nil && isMajor(mpath1, r.pathMajor)
|
||||
|
||||
var file2 string
|
||||
if r.pathMajor != "" && !strings.HasPrefix(r.pathMajor, ".") {
|
||||
if r.pathMajor != "" && r.codeRoot != r.modPath && !strings.HasPrefix(r.pathMajor, ".") {
|
||||
// Suppose pathMajor is "/v2".
|
||||
// Either go.mod should claim v2 and v2/go.mod should not exist,
|
||||
// or v2/go.mod should exist and claim v2. Not both.
|
||||
@@ -298,6 +339,9 @@ func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err e
|
||||
// because of replacement modules. This might be a fork of
|
||||
// the real module, found at a different path, usable only in
|
||||
// a replace directive.
|
||||
//
|
||||
// TODO(bcmills): This doesn't seem right. Investigate futher.
|
||||
// (Notably: why can't we replace foo/v2 with fork-of-foo/v3?)
|
||||
dir2 := path.Join(r.codeDir, r.pathMajor[1:])
|
||||
file2 = path.Join(dir2, "go.mod")
|
||||
gomod2, err2 := r.code.ReadFile(rev, file2, codehost.MaxGoMod)
|
||||
@@ -418,7 +462,7 @@ func (r *codeRepo) Zip(dst io.Writer, version string) error {
|
||||
}
|
||||
defer dl.Close()
|
||||
if actualDir != "" && !hasPathPrefix(dir, actualDir) {
|
||||
return fmt.Errorf("internal error: downloading %v %v: dir=%q but actualDir=%q", r.path, rev, dir, actualDir)
|
||||
return fmt.Errorf("internal error: downloading %v %v: dir=%q but actualDir=%q", r.modPath, rev, dir, actualDir)
|
||||
}
|
||||
subdir := strings.Trim(strings.TrimPrefix(dir, actualDir), "/")
|
||||
|
||||
|
||||
@@ -323,6 +323,15 @@ var codeRepoTests = []struct {
|
||||
time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC),
|
||||
gomod: "module gopkg.in/natefinch/lumberjack.v2\n",
|
||||
},
|
||||
{
|
||||
path: "nanomsg.org/go/mangos/v2",
|
||||
rev: "v2.0.2",
|
||||
version: "v2.0.2",
|
||||
name: "63f66a65137b9a648ac9f7bf0160b4a4d17d7999",
|
||||
short: "63f66a65137b",
|
||||
time: time.Date(2018, 12, 1, 15, 7, 40, 0, time.UTC),
|
||||
gomod: "module nanomsg.org/go/mangos/v2\n\nrequire (\n\tgithub.com/Microsoft/go-winio v0.4.11\n\tgithub.com/droundy/goopt v0.0.0-20170604162106-0b8effe182da\n\tgithub.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect\n\tgithub.com/gorilla/websocket v1.4.0\n\tgithub.com/jtolds/gls v4.2.1+incompatible // indirect\n\tgithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect\n\tgithub.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c\n\tgolang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 // indirect\n)\n",
|
||||
},
|
||||
}
|
||||
|
||||
func TestCodeRepo(t *testing.T) {
|
||||
|
||||
@@ -805,7 +805,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
|
||||
if p.ImportPath == "command-line-arguments" {
|
||||
elem = p.Name
|
||||
} else {
|
||||
_, elem = path.Split(p.ImportPath)
|
||||
elem = load.DefaultExecName(p.ImportPath)
|
||||
}
|
||||
testBinary := elem + ".test"
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"go/build"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
@@ -285,7 +284,7 @@ func runBuild(cmd *base.Command, args []string) {
|
||||
pkgs := load.PackagesForBuild(args)
|
||||
|
||||
if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" {
|
||||
_, cfg.BuildO = path.Split(pkgs[0].ImportPath)
|
||||
cfg.BuildO = load.DefaultExecName(pkgs[0].ImportPath)
|
||||
cfg.BuildO += cfg.ExeSuffix
|
||||
}
|
||||
|
||||
@@ -518,7 +517,7 @@ func InstallPackages(patterns []string, pkgs []*load.Package) {
|
||||
if len(patterns) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" {
|
||||
// Compute file 'go build' would have created.
|
||||
// If it exists and is an executable file, remove it.
|
||||
_, targ := filepath.Split(pkgs[0].ImportPath)
|
||||
targ := load.DefaultExecName(pkgs[0].ImportPath)
|
||||
targ += cfg.ExeSuffix
|
||||
if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory
|
||||
fi, err := os.Stat(targ)
|
||||
|
||||
@@ -214,6 +214,7 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
|
||||
if p.Internal.CoverMode != "" {
|
||||
fmt.Fprintf(h, "cover %q %q\n", p.Internal.CoverMode, b.toolID("cover"))
|
||||
}
|
||||
fmt.Fprintf(h, "modinfo %q\n", p.Internal.BuildInfo)
|
||||
|
||||
// Configuration specific to compiler toolchain.
|
||||
switch cfg.BuildToolchainName {
|
||||
@@ -655,7 +656,7 @@ func (b *Builder) build(a *Action) (err error) {
|
||||
if len(out) > 0 {
|
||||
output := b.processOutput(out)
|
||||
if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
|
||||
output += "note: module requires Go " + p.Module.GoVersion
|
||||
output += "note: module requires Go " + p.Module.GoVersion + "\n"
|
||||
}
|
||||
b.showOutput(a, a.Package.Dir, a.Package.Desc(), output)
|
||||
if err != nil {
|
||||
|
||||
@@ -13,3 +13,9 @@ import "rsc.io/quote"
|
||||
func main() {
|
||||
println(quote.Hello())
|
||||
}
|
||||
-- fortune_test.go --
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFortuneV2(t *testing.T) {}
|
||||
|
||||
5
src/cmd/go/testdata/script/build_nocache.txt
vendored
5
src/cmd/go/testdata/script/build_nocache.txt
vendored
@@ -10,6 +10,11 @@ env HOME=
|
||||
! go build -o triv triv.go
|
||||
stderr 'build cache is required, but could not be located: GOCACHE is not defined and .*'
|
||||
|
||||
# If GOCACHE is set but is not an absolute path, and we cannot build.
|
||||
env GOCACHE=test
|
||||
! go build -o triv triv.go
|
||||
stderr 'build cache is required, but could not be located: GOCACHE is not an absolute path'
|
||||
|
||||
# An explicit GOCACHE=off also disables builds.
|
||||
env GOCACHE=off
|
||||
! go build -o triv triv.go
|
||||
|
||||
43
src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt
vendored
Normal file
43
src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# This test checks that multiple main packages can be tested
|
||||
# with -coverpkg=all without duplicate symbol errors.
|
||||
# Verifies golang.org/issue/30374.
|
||||
|
||||
env GO111MODULE=on
|
||||
|
||||
[short] skip
|
||||
|
||||
go test -coverpkg=all ./...
|
||||
|
||||
-- go.mod --
|
||||
module example.com/cov
|
||||
|
||||
-- mainonly/mainonly.go --
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
|
||||
-- mainwithtest/mainwithtest.go --
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
|
||||
func Foo() {}
|
||||
|
||||
-- mainwithtest/mainwithtest_test.go --
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFoo(t *testing.T) {
|
||||
Foo()
|
||||
}
|
||||
|
||||
-- xtest/x.go --
|
||||
package x
|
||||
|
||||
-- xtest/x_test.go --
|
||||
package x_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestX(t *testing.T) {}
|
||||
16
src/cmd/go/testdata/script/mod_build_versioned.txt
vendored
Normal file
16
src/cmd/go/testdata/script/mod_build_versioned.txt
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
env GO111MODULE=on
|
||||
|
||||
go get -m rsc.io/fortune/v2
|
||||
|
||||
# The default executable name shouldn't be v2$exe
|
||||
go build rsc.io/fortune/v2
|
||||
! exists v2$exe
|
||||
exists fortune$exe
|
||||
|
||||
# The default test binary name shouldn't be v2.test$exe
|
||||
go test -c rsc.io/fortune/v2
|
||||
! exists v2.test$exe
|
||||
exists fortune.test$exe
|
||||
|
||||
-- go.mod --
|
||||
module scratch
|
||||
@@ -2986,7 +2986,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
||||
num := uint8(0)
|
||||
cls := oclass(&p.From)
|
||||
if isADDWop(p.As) {
|
||||
if (cls != C_LCON) && (cls != C_ADDCON2) {
|
||||
if !cmp(C_LCON, cls) {
|
||||
c.ctxt.Diag("illegal combination: %v", p)
|
||||
}
|
||||
num = c.omovlconst(AMOVW, p, &p.From, REGTMP, os[:])
|
||||
@@ -3271,7 +3271,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
||||
num := uint8(0)
|
||||
cls := oclass(&p.From)
|
||||
if isANDWop(p.As) {
|
||||
if (cls != C_LCON) && (cls != C_ADDCON) {
|
||||
if !cmp(C_LCON, cls) {
|
||||
c.ctxt.Diag("illegal combination: %v", p)
|
||||
}
|
||||
num = c.omovlconst(AMOVW, p, &p.From, REGTMP, os[:])
|
||||
|
||||
@@ -45,8 +45,10 @@ func NewCipher(key []byte) (*Cipher, error) {
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// Reset zeros the key data so that it will no longer appear in the
|
||||
// process's memory.
|
||||
// Reset zeros the key data and makes the Cipher unusable.
|
||||
//
|
||||
// Deprecated: Reset can't guarantee that the key will be entirely removed from
|
||||
// the process's memory.
|
||||
func (c *Cipher) Reset() {
|
||||
for i := range c.s {
|
||||
c.s[i] = 0
|
||||
|
||||
@@ -573,7 +573,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
|
||||
}
|
||||
|
||||
signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(key.Public(), certReq.supportedSignatureAlgorithms, hs.hello.supportedSignatureAlgorithms, c.vers)
|
||||
signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(key.Public(), certReq.supportedSignatureAlgorithms, supportedSignatureAlgorithmsTLS12, c.vers)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
|
||||
@@ -873,10 +873,41 @@ func TestHandshakeClientCertPSSDisabled(t *testing.T) {
|
||||
supportedSignatureAlgorithmsTLS12 = savedSupportedSignatureAlgorithmsTLS12
|
||||
|
||||
// Use t.Run to ensure the defer runs after all parallel tests end.
|
||||
t.Run("", func(t *testing.T) {
|
||||
t.Run("1024", func(t *testing.T) {
|
||||
runClientTestTLS12(t, test)
|
||||
runClientTestTLS13(t, test)
|
||||
})
|
||||
|
||||
// Use a 512-bit key to check that the TLS 1.2 handshake is actually using
|
||||
// PKCS#1 v1.5. PSS would be failing here.
|
||||
cert, err := X509KeyPair([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIBcTCCARugAwIBAgIQGjQnkCFlUqaFlt6ixyz/tDANBgkqhkiG9w0BAQsFADAS
|
||||
MRAwDgYDVQQKEwdBY21lIENvMB4XDTE5MDExODIzMjMyOFoXDTIwMDExODIzMjMy
|
||||
OFowEjEQMA4GA1UEChMHQWNtZSBDbzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDd
|
||||
ez1rFUDwax2HTxbcnFUP9AhcgEGMHVV2nn4VVEWFJB6I8C/Nkx0XyyQlrmFYBzEQ
|
||||
nIPhKls4T0hFoLvjJnXpAgMBAAGjTTBLMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUE
|
||||
DDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBYGA1UdEQQPMA2CC2V4YW1wbGUu
|
||||
Y29tMA0GCSqGSIb3DQEBCwUAA0EAxDuUS+BrrS3c+h+k+fQPOmOScy6yTX9mHw0Q
|
||||
KbucGamXYEy0URIwOdO0tQ3LHPc1YGvYSPwkDjkjqECs2Vm/AA==
|
||||
-----END CERTIFICATE-----`), []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBOgIBAAJBAN17PWsVQPBrHYdPFtycVQ/0CFyAQYwdVXaefhVURYUkHojwL82T
|
||||
HRfLJCWuYVgHMRCcg+EqWzhPSEWgu+MmdekCAwEAAQJBALjQYNTdXF4CFBbXwUz/
|
||||
yt9QFDYT9B5WT/12jeGAe653gtYS6OOi/+eAkGmzg1GlRnw6fOfn+HYNFDORST7z
|
||||
4j0CIQDn2xz9hVWQEu9ee3vecNT3f60huDGTNoRhtqgweQGX0wIhAPSLj1VcRZEz
|
||||
nKpbtU22+PbIMSJ+e80fmY9LIPx5N4HTAiAthGSimMR9bloz0EY3GyuUEyqoDgMd
|
||||
hXxjuno2WesoJQIgemilbcALXpxsLmZLgcQ2KSmaVr7jb5ECx9R+hYKTw1sCIG4s
|
||||
T+E0J8wlH24pgwQHzy7Ko2qLwn1b5PW8ecrlvP1g
|
||||
-----END RSA PRIVATE KEY-----`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
test.name = "ClientCert-RSA-PSS-Disabled-512"
|
||||
config.Certificates = []Certificate{cert}
|
||||
|
||||
t.Run("512", func(t *testing.T) {
|
||||
runClientTestTLS12(t, test)
|
||||
})
|
||||
}
|
||||
|
||||
func TestClientKeyUpdate(t *testing.T) {
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
000000e0 a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 |.G.bC.(.._.).0..|
|
||||
000000f0 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |........_X.;t|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 16 03 03 00 59 02 00 00 55 03 03 33 ad 8d f8 90 |....Y...U..3....|
|
||||
00000010 d1 72 5d ef e8 94 0f d7 58 15 59 9f 0b f9 ec 73 |.r].....X.Y....s|
|
||||
00000020 99 53 f7 03 81 53 1a aa 05 f0 17 20 55 a1 9e 4e |.S...S..... U..N|
|
||||
00000030 98 26 6b b8 d5 bc 2c 3e ca f6 a0 d9 bb f2 3b dd |.&k...,>......;.|
|
||||
00000040 be 99 f1 35 de 1c f6 51 5b 19 4f 55 c0 2f 00 00 |...5...Q[.OU./..|
|
||||
00000000 16 03 03 00 59 02 00 00 55 03 03 05 c1 62 2b 2f |....Y...U....b+/|
|
||||
00000010 12 46 4d c5 47 61 bd 43 6d bb 3a 60 42 c1 cf da |.FM.Ga.Cm.:`B...|
|
||||
00000020 47 96 0a 11 35 f0 71 d8 f6 39 69 20 0f 9c c1 3f |G...5.q..9i ...?|
|
||||
00000030 9c 68 e7 86 13 7c 1f 83 6b 56 39 ee 0d c0 82 0b |.h...|..kV9.....|
|
||||
00000040 24 1b 8a 39 a6 dc bf 57 79 27 02 e4 c0 2f 00 00 |$..9...Wy'.../..|
|
||||
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
|
||||
00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
|
||||
00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
|
||||
@@ -60,17 +60,17 @@
|
||||
00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
|
||||
000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
|
||||
000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
|
||||
000002c0 ac 0c 00 00 a8 03 00 1d 20 2d c8 0c d2 27 fc f9 |........ -...'..|
|
||||
000002d0 79 71 c4 17 ea 45 ec 0b dd 66 ce af ec 49 96 7d |yq...E...f...I.}|
|
||||
000002e0 43 ff 88 68 b1 a8 bb e1 38 08 04 00 80 5a ab 5b |C..h....8....Z.[|
|
||||
000002f0 e6 b3 32 e2 98 ae c3 ed 7c f9 90 c4 a4 ea dd 70 |..2.....|......p|
|
||||
00000300 fc a4 f8 ef d1 15 0d b7 ad b8 e3 1f 3e c0 e4 40 |............>..@|
|
||||
00000310 0d 7b 50 36 8f 88 cb 88 59 7c 20 63 d1 7f 36 9e |.{P6....Y| c..6.|
|
||||
00000320 de a7 cb 6a 49 fd 65 32 36 0b 10 6a df 58 ef fd |...jI.e26..j.X..|
|
||||
00000330 f6 fc e6 65 e7 81 0e 73 25 87 c7 89 dc ec ae 7c |...e...s%......||
|
||||
00000340 e4 81 79 79 a2 b9 12 28 ab 3b d0 2e 5e 81 47 2a |..yy...(.;..^.G*|
|
||||
00000350 79 1e 16 21 fa 64 78 24 33 24 f7 ac f1 11 a7 15 |y..!.dx$3$......|
|
||||
00000360 98 f6 24 52 14 7c 1f 28 0c 24 b1 a9 8a 16 03 03 |..$R.|.(.$......|
|
||||
000002c0 ac 0c 00 00 a8 03 00 1d 20 94 54 54 4c 52 a7 a5 |........ .TTLR..|
|
||||
000002d0 c0 01 ed 59 bf 46 03 59 25 3b 57 f8 24 99 1b dc |...Y.F.Y%;W.$...|
|
||||
000002e0 f6 f4 1d 42 0e 2e c3 7c 02 08 04 00 80 5a 42 35 |...B...|.....ZB5|
|
||||
000002f0 78 c8 a9 37 6f 61 a4 ef 3a a3 12 03 f7 ee 44 be |x..7oa..:.....D.|
|
||||
00000300 8b c9 52 4f de db f5 1e 9c c8 33 32 3c 0a 9e d6 |..RO......32<...|
|
||||
00000310 32 bf 2e 12 f7 b0 9b 15 dc eb 24 6e d6 f2 ad 5d |2.........$n...]|
|
||||
00000320 9e 77 c4 a7 7a a1 a0 13 0b 90 b4 aa 3e 51 a1 3d |.w..z.......>Q.=|
|
||||
00000330 71 09 15 84 1c c5 98 bb 12 db 11 e2 4c 2c d1 a9 |q...........L,..|
|
||||
00000340 5a ed 8e fb c6 ae ec d5 6d ec d8 d8 2a a7 23 ae |Z.......m...*.#.|
|
||||
00000350 d7 d2 03 d0 23 8a 21 ac 7e 56 b4 23 7f c6 2a 72 |....#.!.~V.#..*r|
|
||||
00000360 85 0b 6d 6c 9d 6f ad ee 15 20 d9 2b b9 16 03 03 |..ml.o... .+....|
|
||||
00000370 00 3a 0d 00 00 36 03 01 02 40 00 2e 04 03 05 03 |.:...6...@......|
|
||||
00000380 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
|
||||
00000390 08 06 04 01 05 01 06 01 03 03 02 03 03 01 02 01 |................|
|
||||
@@ -112,26 +112,26 @@
|
||||
00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
|
||||
00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
|
||||
00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....|
|
||||
00000230 88 0f 00 00 84 08 04 00 80 8b ad 4b 9a 7a 53 b8 |...........K.zS.|
|
||||
00000240 6a 0a e7 71 6a 9b 8b 89 7d 3a 49 c9 af ce 3f e2 |j..qj...}:I...?.|
|
||||
00000250 3e cc 0b da 57 9b 8c 2f 58 0f a9 05 4d e9 de 83 |>...W../X...M...|
|
||||
00000260 60 e8 1c 77 ef 23 e4 aa 6b c3 15 64 98 f8 b1 72 |`..w.#..k..d...r|
|
||||
00000270 b2 8a 9e a3 19 3d 73 84 05 53 59 e1 bb e1 db 51 |.....=s..SY....Q|
|
||||
00000280 49 38 cf 8b ee 3c b6 05 0d ba 62 02 b3 36 dc c1 |I8...<....b..6..|
|
||||
00000290 e1 52 4d bd 6a c1 3e 55 ff 82 5f e3 7c 84 1c 65 |.RM.j.>U.._.|..e|
|
||||
000002a0 45 53 b9 c0 56 99 ac 56 d7 4a fa 72 3e 63 36 06 |ES..V..V.J.r>c6.|
|
||||
000002b0 d3 60 ef 34 05 3f 57 20 79 14 03 03 00 01 01 16 |.`.4.?W y.......|
|
||||
000002c0 03 03 00 28 00 00 00 00 00 00 00 00 00 26 b7 73 |...(.........&.s|
|
||||
000002d0 b5 e9 b3 8a 63 00 9b 36 a0 cf 2a 60 0f 8a 59 75 |....c..6..*`..Yu|
|
||||
000002e0 08 71 97 dc 66 73 15 04 08 b4 d3 91 |.q..fs......|
|
||||
00000230 88 0f 00 00 84 04 01 00 80 61 11 ba 1a fe 08 7c |.........a.....||
|
||||
00000240 40 68 88 01 a4 3a 46 bf f6 e9 bb b6 08 92 20 f0 |@h...:F....... .|
|
||||
00000250 13 90 c2 4b 53 83 a1 12 c2 d5 8d e6 67 82 df 80 |...KS.......g...|
|
||||
00000260 85 a5 b4 e0 cf 1b d6 3a 46 1e 62 e5 7f 21 bc 91 |.......:F.b..!..|
|
||||
00000270 4a 8c c0 79 16 64 5f 7e 40 c5 fb 7a 52 5b bf db |J..y.d_~@..zR[..|
|
||||
00000280 cc 31 f8 b8 37 ef df dc 5f 96 30 ad dd 0b 8a 87 |.1..7..._.0.....|
|
||||
00000290 af 4d c6 5c a5 5e d7 2e fa c7 72 68 85 71 c3 0e |.M.\.^....rh.q..|
|
||||
000002a0 1b 26 87 ff 46 47 4a 1b ce b7 a5 aa 13 d2 5a e3 |.&..FGJ.......Z.|
|
||||
000002b0 36 02 35 df 68 d9 bf 3f 24 14 03 03 00 01 01 16 |6.5.h..?$.......|
|
||||
000002c0 03 03 00 28 00 00 00 00 00 00 00 00 e3 8e cc e5 |...(............|
|
||||
000002d0 2e ab 40 fa 3d 47 c1 4f 3f de 97 a9 3d 96 73 ba |..@.=G.O?...=.s.|
|
||||
000002e0 eb a0 ce 67 f6 d1 14 b8 7e cd 1f 85 |...g....~...|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 14 03 03 00 01 01 16 03 03 00 28 d2 b2 3f a8 43 |..........(..?.C|
|
||||
00000010 41 1a 85 20 9f ee 21 6a c5 96 cf 7c 01 8e f6 3a |A.. ..!j...|...:|
|
||||
00000020 e3 29 14 68 ea 74 a3 ef 85 04 78 33 db c7 d4 c9 |.).h.t....x3....|
|
||||
00000030 a2 fd 6a |..j|
|
||||
00000000 14 03 03 00 01 01 16 03 03 00 28 6a 0a 74 70 75 |..........(j.tpu|
|
||||
00000010 0b 39 33 a5 15 0d 7c 7f f8 13 de 0e 0a 8f 13 3b |.93...|........;|
|
||||
00000020 62 4f 8a 0b bd 0a aa 9b 5a 52 d5 e6 9f e5 b9 3f |bO......ZR.....?|
|
||||
00000030 bd d8 3b |..;|
|
||||
>>> Flow 5 (client to server)
|
||||
00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 c3 3b 68 |..............;h|
|
||||
00000010 b5 e9 4d 75 22 92 fb 19 85 88 38 97 12 3f ce ca |..Mu".....8..?..|
|
||||
00000020 36 c0 d6 15 03 03 00 1a 00 00 00 00 00 00 00 02 |6...............|
|
||||
00000030 c1 a9 03 81 61 04 7c 86 24 e9 90 22 59 6f c7 bc |....a.|.$.."Yo..|
|
||||
00000040 c2 a1 |..|
|
||||
00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 0e 4d 62 |..............Mb|
|
||||
00000010 d3 ac cd 11 15 6d 24 c7 00 fa f9 d2 91 ba eb 06 |.....m$.........|
|
||||
00000020 f2 44 f1 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.D..............|
|
||||
00000030 d1 5a 58 ba ae 65 15 67 79 1f 52 f1 1a da 50 99 |.ZX..e.gy.R...P.|
|
||||
00000040 e8 50 |.P|
|
||||
|
||||
125
src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-PSS-Disabled-512
vendored
Normal file
125
src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-PSS-Disabled-512
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
>>> Flow 1 (client to server)
|
||||
00000000 16 03 01 00 f8 01 00 00 f4 03 03 00 00 00 00 00 |................|
|
||||
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
|
||||
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a8 |.............2..|
|
||||
00000050 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
|
||||
00000060 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
|
||||
00000070 c0 12 00 0a 00 05 c0 11 c0 07 13 01 13 03 13 02 |................|
|
||||
00000080 01 00 00 79 00 05 00 05 01 00 00 00 00 00 0a 00 |...y............|
|
||||
00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
|
||||
000000a0 00 00 0d 00 18 00 16 08 04 08 05 08 06 04 01 04 |................|
|
||||
000000b0 03 05 01 05 03 06 01 06 03 02 01 02 03 ff 01 00 |................|
|
||||
000000c0 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 03 03 |.......+........|
|
||||
000000d0 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f e5 7d |....3.&.$... /.}|
|
||||
000000e0 a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 |.G.bC.(.._.).0..|
|
||||
000000f0 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |........_X.;t|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 16 03 03 00 59 02 00 00 55 03 03 68 11 23 f1 8d |....Y...U..h.#..|
|
||||
00000010 2b a0 71 8f 6e ad 9f ae 43 58 c2 93 2e f5 01 3d |+.q.n...CX.....=|
|
||||
00000020 15 b6 d6 0d f5 42 25 ca b7 b4 96 20 00 c7 86 06 |.....B%.... ....|
|
||||
00000030 ed d1 23 99 dd e3 c4 f5 f9 31 42 51 a3 51 5a 40 |..#......1BQ.QZ@|
|
||||
00000040 11 f6 07 90 51 04 f8 a2 f6 66 c1 f7 c0 2f 00 00 |....Q....f.../..|
|
||||
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
|
||||
00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
|
||||
00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
|
||||
00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
|
||||
00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
|
||||
000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
|
||||
000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
|
||||
000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
|
||||
000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
|
||||
000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
|
||||
000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
|
||||
00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
|
||||
00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
|
||||
00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
|
||||
00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
|
||||
00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
|
||||
00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
|
||||
00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
|
||||
00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
|
||||
00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
|
||||
00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
|
||||
000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
|
||||
000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
|
||||
000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
|
||||
000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
|
||||
000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
|
||||
000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
|
||||
00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
|
||||
00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
|
||||
00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
|
||||
00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
|
||||
00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
|
||||
00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
|
||||
00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
|
||||
00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
|
||||
00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
|
||||
00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
|
||||
000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
|
||||
000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
|
||||
000002c0 ac 0c 00 00 a8 03 00 1d 20 fe 68 1c bf 2b d7 75 |........ .h..+.u|
|
||||
000002d0 c2 dd 96 03 5d 77 61 c1 7d dd 6f bc ea 3c aa 27 |....]wa.}.o..<.'|
|
||||
000002e0 ba cf 93 e2 8b d8 66 a1 1c 08 04 00 80 5e 16 b9 |......f......^..|
|
||||
000002f0 53 17 7d 8d bb 46 4b 1f 37 be cd fe e1 45 c3 10 |S.}..FK.7....E..|
|
||||
00000300 68 54 e4 61 20 a5 a5 98 4b df a7 5d 41 4a aa f8 |hT.a ...K..]AJ..|
|
||||
00000310 0e 36 c2 02 a6 56 a9 f1 aa 76 86 fd a7 86 fb 06 |.6...V...v......|
|
||||
00000320 94 55 56 bd eb 57 10 9a d5 ba 70 59 46 75 e3 b3 |.UV..W....pYFu..|
|
||||
00000330 29 14 c2 65 0e 5c a1 47 e6 bf 12 9d 31 8f 65 4d |)..e.\.G....1.eM|
|
||||
00000340 af dc 1b 6e d2 de d7 fb 85 e7 5a 42 4f de bf d8 |...n......ZBO...|
|
||||
00000350 d5 d8 5c 95 71 27 e7 04 af 58 0a d8 77 fb 3d 22 |..\.q'...X..w.="|
|
||||
00000360 84 f6 f6 53 c0 79 7a 72 01 6e 5c e1 a8 16 03 03 |...S.yzr.n\.....|
|
||||
00000370 00 3a 0d 00 00 36 03 01 02 40 00 2e 04 03 05 03 |.:...6...@......|
|
||||
00000380 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
|
||||
00000390 08 06 04 01 05 01 06 01 03 03 02 03 03 01 02 01 |................|
|
||||
000003a0 03 02 02 02 04 02 05 02 06 02 00 00 16 03 03 00 |................|
|
||||
000003b0 04 0e 00 00 00 |.....|
|
||||
>>> Flow 3 (client to server)
|
||||
00000000 16 03 03 01 7f 0b 00 01 7b 00 01 78 00 01 75 30 |........{..x..u0|
|
||||
00000010 82 01 71 30 82 01 1b a0 03 02 01 02 02 10 1a 34 |..q0...........4|
|
||||
00000020 27 90 21 65 52 a6 85 96 de a2 c7 2c ff b4 30 0d |'.!eR......,..0.|
|
||||
00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
|
||||
00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
|
||||
00000050 6f 30 1e 17 0d 31 39 30 31 31 38 32 33 32 33 32 |o0...19011823232|
|
||||
00000060 38 5a 17 0d 32 30 30 31 31 38 32 33 32 33 32 38 |8Z..200118232328|
|
||||
00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
|
||||
00000080 6d 65 20 43 6f 30 5c 30 0d 06 09 2a 86 48 86 f7 |me Co0\0...*.H..|
|
||||
00000090 0d 01 01 01 05 00 03 4b 00 30 48 02 41 00 dd 7b |.......K.0H.A..{|
|
||||
000000a0 3d 6b 15 40 f0 6b 1d 87 4f 16 dc 9c 55 0f f4 08 |=k.@.k..O...U...|
|
||||
000000b0 5c 80 41 8c 1d 55 76 9e 7e 15 54 45 85 24 1e 88 |\.A..Uv.~.TE.$..|
|
||||
000000c0 f0 2f cd 93 1d 17 cb 24 25 ae 61 58 07 31 10 9c |./.....$%.aX.1..|
|
||||
000000d0 83 e1 2a 5b 38 4f 48 45 a0 bb e3 26 75 e9 02 03 |..*[8OHE...&u...|
|
||||
000000e0 01 00 01 a3 4d 30 4b 30 0e 06 03 55 1d 0f 01 01 |....M0K0...U....|
|
||||
000000f0 ff 04 04 03 02 05 a0 30 13 06 03 55 1d 25 04 0c |.......0...U.%..|
|
||||
00000100 30 0a 06 08 2b 06 01 05 05 07 03 01 30 0c 06 03 |0...+.......0...|
|
||||
00000110 55 1d 13 01 01 ff 04 02 30 00 30 16 06 03 55 1d |U.......0.0...U.|
|
||||
00000120 11 04 0f 30 0d 82 0b 65 78 61 6d 70 6c 65 2e 63 |...0...example.c|
|
||||
00000130 6f 6d 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |om0...*.H.......|
|
||||
00000140 00 03 41 00 c4 3b 94 4b e0 6b ad 2d dc fa 1f a4 |..A..;.K.k.-....|
|
||||
00000150 f9 f4 0f 3a 63 92 73 2e b2 4d 7f 66 1f 0d 10 29 |...:c.s..M.f...)|
|
||||
00000160 bb 9c 19 a9 97 60 4c b4 51 12 30 39 d3 b4 b5 0d |.....`L.Q.09....|
|
||||
00000170 cb 1c f7 35 60 6b d8 48 fc 24 0e 39 23 a8 40 ac |...5`k.H.$.9#.@.|
|
||||
00000180 d9 59 bf 00 16 03 03 00 25 10 00 00 21 20 2f e5 |.Y......%...! /.|
|
||||
00000190 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff |}.G.bC.(.._.).0.|
|
||||
000001a0 f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 |........._X.;t..|
|
||||
000001b0 03 00 48 0f 00 00 44 04 01 00 40 15 33 b2 27 d6 |..H...D...@.3.'.|
|
||||
000001c0 ad 7f 45 86 df a0 83 5e 7c fb a7 0e 04 8e 3c a1 |..E....^|.....<.|
|
||||
000001d0 5b 9a 8f 98 04 cf 66 bb cf 6a d4 63 d7 ff b2 a4 |[.....f..j.c....|
|
||||
000001e0 f1 08 27 f7 53 1c ec 76 35 b1 09 93 91 db 63 e3 |..'.S..v5.....c.|
|
||||
000001f0 a6 2b e5 55 da 06 5b 2f c7 8d c3 14 03 03 00 01 |.+.U..[/........|
|
||||
00000200 01 16 03 03 00 28 00 00 00 00 00 00 00 00 98 d8 |.....(..........|
|
||||
00000210 99 fa 5a fb 79 57 1f 02 4e 07 51 d6 c6 32 9c e8 |..Z.yW..N.Q..2..|
|
||||
00000220 54 50 6c f9 63 fb 38 e2 ef 88 4b 7e 8d 7a |TPl.c.8...K~.z|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 14 03 03 00 01 01 16 03 03 00 28 4c 6b f0 26 84 |..........(Lk.&.|
|
||||
00000010 97 e6 54 cf 1f 25 1c 91 5d 10 63 22 66 73 d2 ce |..T..%..].c"fs..|
|
||||
00000020 0d 7c 0b 3d 7d 31 3c 0b 6c be 30 72 9e 04 c0 fb |.|.=}1<.l.0r....|
|
||||
00000030 73 88 75 |s.u|
|
||||
>>> Flow 5 (client to server)
|
||||
00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 2a b2 2d |.............*.-|
|
||||
00000010 7f 6e 12 2d d7 63 05 e8 c4 fd 81 de b6 65 2f 2b |.n.-.c.......e/+|
|
||||
00000020 00 0e 13 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
|
||||
00000030 9c c0 ae 5a b4 5f b5 4f cd 3f 27 78 f9 b3 b5 b5 |...Z._.O.?'x....|
|
||||
00000040 57 f2 |W.|
|
||||
@@ -4,6 +4,15 @@
|
||||
|
||||
// Package tls partially implements TLS 1.2, as specified in RFC 5246,
|
||||
// and TLS 1.3, as specified in RFC 8446.
|
||||
//
|
||||
// TLS 1.3 is available only on an opt-in basis in Go 1.12. To enable
|
||||
// it, set the GODEBUG environment variable (comma-separated key=value
|
||||
// options) such that it includes "tls13=1". To enable it from within
|
||||
// the process, set the environment variable before any use of TLS:
|
||||
//
|
||||
// func init() {
|
||||
// os.Setenv("GODEBUG", os.Getenv("GODEBUG")+",tls13=1")
|
||||
// }
|
||||
package tls
|
||||
|
||||
// BUG(agl): The crypto/tls package only implements some countermeasures
|
||||
|
||||
@@ -137,7 +137,7 @@ type Pinger interface {
|
||||
|
||||
// Execer is an optional interface that may be implemented by a Conn.
|
||||
//
|
||||
// If a Conn implements neither ExecerContext nor Execer Execer,
|
||||
// If a Conn implements neither ExecerContext nor Execer,
|
||||
// the sql package's DB.Exec will first prepare a query, execute the statement,
|
||||
// and then close the statement.
|
||||
//
|
||||
|
||||
@@ -167,7 +167,7 @@ func compare(aVal, bVal reflect.Value) int {
|
||||
if c, ok := nilCompare(aVal, bVal); ok {
|
||||
return c
|
||||
}
|
||||
c := compare(reflect.ValueOf(aType), reflect.ValueOf(bType))
|
||||
c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type()))
|
||||
if c != 0 {
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -126,10 +126,6 @@ var sortTests = []sortTest{
|
||||
map[[2]int]string{{7, 2}: "72", {7, 1}: "71", {3, 4}: "34"},
|
||||
"[3 4]:34 [7 1]:71 [7 2]:72",
|
||||
},
|
||||
{
|
||||
map[interface{}]string{7: "7", 4: "4", 3: "3", nil: "nil"},
|
||||
"<nil>:nil 3:3 4:4 7:7",
|
||||
},
|
||||
}
|
||||
|
||||
func sprint(data interface{}) string {
|
||||
@@ -210,3 +206,41 @@ func TestOrder(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterface(t *testing.T) {
|
||||
// A map containing multiple concrete types should be sorted by type,
|
||||
// then value. However, the relative ordering of types is unspecified,
|
||||
// so test this by checking the presence of sorted subgroups.
|
||||
m := map[interface{}]string{
|
||||
[2]int{1, 0}: "",
|
||||
[2]int{0, 1}: "",
|
||||
true: "",
|
||||
false: "",
|
||||
3.1: "",
|
||||
2.1: "",
|
||||
1.1: "",
|
||||
math.NaN(): "",
|
||||
3: "",
|
||||
2: "",
|
||||
1: "",
|
||||
"c": "",
|
||||
"b": "",
|
||||
"a": "",
|
||||
struct{ x, y int }{1, 0}: "",
|
||||
struct{ x, y int }{0, 1}: "",
|
||||
}
|
||||
got := sprint(m)
|
||||
typeGroups := []string{
|
||||
"NaN: 1.1: 2.1: 3.1:", // float64
|
||||
"false: true:", // bool
|
||||
"1: 2: 3:", // int
|
||||
"a: b: c:", // string
|
||||
"[0 1]: [1 0]:", // [2]int
|
||||
"{0 1}: {1 0}:", // struct{ x int; y int }
|
||||
}
|
||||
for _, g := range typeGroups {
|
||||
if !strings.Contains(got, g) {
|
||||
t.Errorf("sorted map should contain %q", g)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,6 +660,10 @@ func (fd *FD) Write(buf []byte) (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
defer fd.writeUnlock()
|
||||
if fd.isFile || fd.isDir || fd.isConsole {
|
||||
fd.l.Lock()
|
||||
defer fd.l.Unlock()
|
||||
}
|
||||
|
||||
ntotal := 0
|
||||
for len(buf) > 0 {
|
||||
@@ -670,8 +674,6 @@ func (fd *FD) Write(buf []byte) (int, error) {
|
||||
var n int
|
||||
var err error
|
||||
if fd.isFile || fd.isDir || fd.isConsole {
|
||||
fd.l.Lock()
|
||||
defer fd.l.Unlock()
|
||||
if fd.isConsole {
|
||||
n, err = fd.writeConsole(b)
|
||||
} else {
|
||||
|
||||
@@ -152,7 +152,7 @@ type ClientTrace struct {
|
||||
WroteHeaders func()
|
||||
|
||||
// Wait100Continue is called if the Request specified
|
||||
// "Expected: 100-continue" and the Transport has written the
|
||||
// "Expect: 100-continue" and the Transport has written the
|
||||
// request headers but is waiting for "100 Continue" from the
|
||||
// server before writing the request body.
|
||||
Wait100Continue func()
|
||||
|
||||
@@ -389,6 +389,11 @@ func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader, flushInterval
|
||||
latency: flushInterval,
|
||||
}
|
||||
defer mlw.stop()
|
||||
|
||||
// set up initial timer so headers get flushed even if body writes are delayed
|
||||
mlw.flushPending = true
|
||||
mlw.t = time.AfterFunc(flushInterval, mlw.delayedFlush)
|
||||
|
||||
dst = mlw
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ package httputil
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -317,6 +318,47 @@ func TestReverseProxyFlushInterval(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReverseProxyFlushIntervalHeaders(t *testing.T) {
|
||||
const expected = "hi"
|
||||
stopCh := make(chan struct{})
|
||||
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("MyHeader", expected)
|
||||
w.WriteHeader(200)
|
||||
w.(http.Flusher).Flush()
|
||||
<-stopCh
|
||||
}))
|
||||
defer backend.Close()
|
||||
defer close(stopCh)
|
||||
|
||||
backendURL, err := url.Parse(backend.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
proxyHandler := NewSingleHostReverseProxy(backendURL)
|
||||
proxyHandler.FlushInterval = time.Microsecond
|
||||
|
||||
frontend := httptest.NewServer(proxyHandler)
|
||||
defer frontend.Close()
|
||||
|
||||
req, _ := http.NewRequest("GET", frontend.URL, nil)
|
||||
req.Close = true
|
||||
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
res, err := frontend.Client().Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("Get: %v", err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.Header.Get("MyHeader") != expected {
|
||||
t.Errorf("got header %q; expected %q", res.Header.Get("MyHeader"), expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReverseProxyCancelation(t *testing.T) {
|
||||
const backendResponse = "I am the backend"
|
||||
|
||||
|
||||
@@ -262,8 +262,9 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IP
|
||||
// only the values in context. See Issue 28600.
|
||||
lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
|
||||
|
||||
lookupKey := network + "\000" + host
|
||||
dnsWaitGroup.Add(1)
|
||||
ch, called := r.getLookupGroup().DoChan(host, func() (interface{}, error) {
|
||||
ch, called := r.getLookupGroup().DoChan(lookupKey, func() (interface{}, error) {
|
||||
defer dnsWaitGroup.Done()
|
||||
return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
|
||||
})
|
||||
@@ -280,7 +281,7 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IP
|
||||
// let the lookup continue uncanceled, and let later
|
||||
// lookups with the same key share the result.
|
||||
// See issues 8602, 20703, 22724.
|
||||
if r.getLookupGroup().ForgetUnshared(host) {
|
||||
if r.getLookupGroup().ForgetUnshared(lookupKey) {
|
||||
lookupGroupCancel()
|
||||
} else {
|
||||
go func() {
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -253,14 +254,11 @@ func TestLookupGmailTXT(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
var lookupGooglePublicDNSAddrTests = []struct {
|
||||
addr, name string
|
||||
}{
|
||||
{"8.8.8.8", ".google.com."},
|
||||
{"8.8.4.4", ".google.com."},
|
||||
|
||||
{"2001:4860:4860::8888", ".google.com."},
|
||||
{"2001:4860:4860::8844", ".google.com."},
|
||||
var lookupGooglePublicDNSAddrTests = []string{
|
||||
"8.8.8.8",
|
||||
"8.8.4.4",
|
||||
"2001:4860:4860::8888",
|
||||
"2001:4860:4860::8844",
|
||||
}
|
||||
|
||||
func TestLookupGooglePublicDNSAddr(t *testing.T) {
|
||||
@@ -272,8 +270,8 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
|
||||
|
||||
defer dnsWaitGroup.Wait()
|
||||
|
||||
for _, tt := range lookupGooglePublicDNSAddrTests {
|
||||
names, err := LookupAddr(tt.addr)
|
||||
for _, ip := range lookupGooglePublicDNSAddrTests {
|
||||
names, err := LookupAddr(ip)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -281,8 +279,8 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
|
||||
t.Error("got no record")
|
||||
}
|
||||
for _, name := range names {
|
||||
if !strings.HasSuffix(name, tt.name) {
|
||||
t.Errorf("got %s; want a record containing %s", name, tt.name)
|
||||
if !strings.HasSuffix(name, ".google.com.") && !strings.HasSuffix(name, ".google.") {
|
||||
t.Errorf("got %q; want a record ending in .google.com. or .google.", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -658,8 +656,8 @@ func testDots(t *testing.T, mode string) {
|
||||
t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode)
|
||||
} else {
|
||||
for _, name := range names {
|
||||
if !strings.HasSuffix(name, ".google.com.") {
|
||||
t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names, mode)
|
||||
if !strings.HasSuffix(name, ".google.com.") && !strings.HasSuffix(name, ".google.") {
|
||||
t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com or .google with trailing dot (mode=%v)", names, mode)
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -1096,6 +1094,69 @@ func TestLookupIPAddrPreservesContextValues(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 30521: The lookup group should call the resolver for each network.
|
||||
func TestLookupIPAddrConcurrentCallsForNetworks(t *testing.T) {
|
||||
origTestHookLookupIP := testHookLookupIP
|
||||
defer func() { testHookLookupIP = origTestHookLookupIP }()
|
||||
|
||||
queries := [][]string{
|
||||
{"udp", "golang.org"},
|
||||
{"udp4", "golang.org"},
|
||||
{"udp6", "golang.org"},
|
||||
{"udp", "golang.org"},
|
||||
{"udp", "golang.org"},
|
||||
}
|
||||
results := map[[2]string][]IPAddr{
|
||||
{"udp", "golang.org"}: {
|
||||
{IP: IPv4(127, 0, 0, 1)},
|
||||
{IP: IPv6loopback},
|
||||
},
|
||||
{"udp4", "golang.org"}: {
|
||||
{IP: IPv4(127, 0, 0, 1)},
|
||||
},
|
||||
{"udp6", "golang.org"}: {
|
||||
{IP: IPv6loopback},
|
||||
},
|
||||
}
|
||||
calls := int32(0)
|
||||
waitCh := make(chan struct{})
|
||||
testHookLookupIP = func(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
|
||||
// We'll block until this is called one time for each different
|
||||
// expected result. This will ensure that the lookup group would wait
|
||||
// for the existing call if it was to be reused.
|
||||
if atomic.AddInt32(&calls, 1) == int32(len(results)) {
|
||||
close(waitCh)
|
||||
}
|
||||
select {
|
||||
case <-waitCh:
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
return results[[2]string{network, host}], nil
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
wg := sync.WaitGroup{}
|
||||
for _, q := range queries {
|
||||
network := q[0]
|
||||
host := q[1]
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
gotIPs, err := DefaultResolver.lookupIPAddr(ctx, network, host)
|
||||
if err != nil {
|
||||
t.Errorf("lookupIPAddr(%v, %v): unexpected error: %v", network, host, err)
|
||||
}
|
||||
wantIPs := results[[2]string{network, host}]
|
||||
if !reflect.DeepEqual(gotIPs, wantIPs) {
|
||||
t.Errorf("lookupIPAddr(%v, %v): mismatched IPAddr results\n\tGot: %v\n\tWant: %v", network, host, gotIPs, wantIPs)
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestWithUnexpiredValuesPreserved(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ func MkdirAll(path string, perm FileMode) error {
|
||||
// It removes everything it can but returns the first error
|
||||
// it encounters. If the path does not exist, RemoveAll
|
||||
// returns nil (no error).
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func RemoveAll(path string) error {
|
||||
return removeAll(path)
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func splitPath(path string) (string, string) {
|
||||
// Remove leading directory path
|
||||
for i--; i >= 0; i-- {
|
||||
if path[i] == '/' {
|
||||
dirname = path[:i+1]
|
||||
dirname = path[:i]
|
||||
basename = path[i+1:]
|
||||
break
|
||||
}
|
||||
|
||||
@@ -46,13 +46,20 @@ func removeAll(path string) error {
|
||||
}
|
||||
defer parent.Close()
|
||||
|
||||
return removeAllFrom(parent, base)
|
||||
if err := removeAllFrom(parent, base); err != nil {
|
||||
if pathErr, ok := err.(*PathError); ok {
|
||||
pathErr.Path = parentDir + string(PathSeparator) + pathErr.Path
|
||||
err = pathErr
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeAllFrom(parent *File, path string) error {
|
||||
func removeAllFrom(parent *File, base string) error {
|
||||
parentFd := int(parent.Fd())
|
||||
// Simple case: if Unlink (aka remove) works, we're done.
|
||||
err := unix.Unlinkat(parentFd, path, 0)
|
||||
err := unix.Unlinkat(parentFd, base, 0)
|
||||
if err == nil || IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
@@ -64,18 +71,21 @@ func removeAllFrom(parent *File, path string) error {
|
||||
// whose contents need to be removed.
|
||||
// Otherwise just return the error.
|
||||
if err != syscall.EISDIR && err != syscall.EPERM && err != syscall.EACCES {
|
||||
return err
|
||||
return &PathError{"unlinkat", base, err}
|
||||
}
|
||||
|
||||
// Is this a directory we need to recurse into?
|
||||
var statInfo syscall.Stat_t
|
||||
statErr := unix.Fstatat(parentFd, path, &statInfo, unix.AT_SYMLINK_NOFOLLOW)
|
||||
statErr := unix.Fstatat(parentFd, base, &statInfo, unix.AT_SYMLINK_NOFOLLOW)
|
||||
if statErr != nil {
|
||||
return statErr
|
||||
if IsNotExist(statErr) {
|
||||
return nil
|
||||
}
|
||||
return &PathError{"fstatat", base, statErr}
|
||||
}
|
||||
if statInfo.Mode&syscall.S_IFMT != syscall.S_IFDIR {
|
||||
// Not a directory; return the error from the Remove.
|
||||
return err
|
||||
// Not a directory; return the error from the unix.Unlinkat.
|
||||
return &PathError{"unlinkat", base, err}
|
||||
}
|
||||
|
||||
// Remove the directory's entries.
|
||||
@@ -84,12 +94,13 @@ func removeAllFrom(parent *File, path string) error {
|
||||
const request = 1024
|
||||
|
||||
// Open the directory to recurse into
|
||||
file, err := openFdAt(parentFd, path)
|
||||
file, err := openFdAt(parentFd, base)
|
||||
if err != nil {
|
||||
if IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
recurseErr = &PathError{"openfdat", base, err}
|
||||
break
|
||||
}
|
||||
|
||||
names, readErr := file.Readdirnames(request)
|
||||
@@ -99,12 +110,15 @@ func removeAllFrom(parent *File, path string) error {
|
||||
if IsNotExist(readErr) {
|
||||
return nil
|
||||
}
|
||||
return readErr
|
||||
return &PathError{"readdirnames", base, readErr}
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
err := removeAllFrom(file, name)
|
||||
if err != nil {
|
||||
if pathErr, ok := err.(*PathError); ok {
|
||||
pathErr.Path = base + string(PathSeparator) + pathErr.Path
|
||||
}
|
||||
recurseErr = err
|
||||
}
|
||||
}
|
||||
@@ -123,7 +137,7 @@ func removeAllFrom(parent *File, path string) error {
|
||||
}
|
||||
|
||||
// Remove the directory itself.
|
||||
unlinkError := unix.Unlinkat(parentFd, path, unix.AT_REMOVEDIR)
|
||||
unlinkError := unix.Unlinkat(parentFd, base, unix.AT_REMOVEDIR)
|
||||
if unlinkError == nil || IsNotExist(unlinkError) {
|
||||
return nil
|
||||
}
|
||||
@@ -131,7 +145,7 @@ func removeAllFrom(parent *File, path string) error {
|
||||
if recurseErr != nil {
|
||||
return recurseErr
|
||||
}
|
||||
return unlinkError
|
||||
return &PathError{"unlinkat", base, unlinkError}
|
||||
}
|
||||
|
||||
// openFdAt opens path relative to the directory in fd.
|
||||
@@ -153,7 +167,7 @@ func openFdAt(dirfd int, name string) (*File, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
return nil, &PathError{"openat", name, e}
|
||||
return nil, e
|
||||
}
|
||||
|
||||
if !supportsCloseOnExec {
|
||||
|
||||
@@ -294,7 +294,7 @@ func TestRemoveReadOnlyDir(t *testing.T) {
|
||||
}
|
||||
|
||||
// Issue #29983.
|
||||
func TestRemoveAllButReadOnly(t *testing.T) {
|
||||
func TestRemoveAllButReadOnlyAndPathError(t *testing.T) {
|
||||
switch runtime.GOOS {
|
||||
case "nacl", "js", "windows":
|
||||
t.Skipf("skipping test on %s", runtime.GOOS)
|
||||
@@ -355,10 +355,21 @@ func TestRemoveAllButReadOnly(t *testing.T) {
|
||||
defer Chmod(d, 0777)
|
||||
}
|
||||
|
||||
if err := RemoveAll(tempDir); err == nil {
|
||||
err = RemoveAll(tempDir)
|
||||
if err == nil {
|
||||
t.Fatal("RemoveAll succeeded unexpectedly")
|
||||
}
|
||||
|
||||
// The error should be of type *PathError.
|
||||
// see issue 30491 for details.
|
||||
if pathErr, ok := err.(*PathError); ok {
|
||||
if g, w := pathErr.Path, filepath.Join(tempDir, "b", "y"); g != w {
|
||||
t.Errorf("got %q, expected pathErr.path %q", g, w)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("got %T, expected *os.PathError", err)
|
||||
}
|
||||
|
||||
for _, dir := range dirs {
|
||||
_, err := Stat(filepath.Join(tempDir, dir))
|
||||
if inReadonly(dir) {
|
||||
@@ -372,3 +383,33 @@ func TestRemoveAllButReadOnly(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveUnreadableDir(t *testing.T) {
|
||||
switch runtime.GOOS {
|
||||
case "nacl", "js", "windows":
|
||||
t.Skipf("skipping test on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
if Getuid() == 0 {
|
||||
t.Skip("skipping test when running as root")
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
|
||||
tempDir, err := ioutil.TempDir("", "TestRemoveAllButReadOnly-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer RemoveAll(tempDir)
|
||||
|
||||
target := filepath.Join(tempDir, "d0", "d1", "d2")
|
||||
if err := MkdirAll(target, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := Chmod(target, 0300); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := RemoveAll(filepath.Join(tempDir, "d0")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,19 +96,14 @@ func Clean(path string) string {
|
||||
}
|
||||
return originalPath + "."
|
||||
}
|
||||
|
||||
n := len(path)
|
||||
if volLen > 2 && n == 1 && os.IsPathSeparator(path[0]) {
|
||||
// UNC volume name with trailing slash.
|
||||
return FromSlash(originalPath[:volLen])
|
||||
}
|
||||
rooted := os.IsPathSeparator(path[0])
|
||||
|
||||
// Invariants:
|
||||
// reading from path; r is index of next byte to process.
|
||||
// writing to out; w is index of next byte to write.
|
||||
// dotdot is index in out where .. must stop, either because
|
||||
// writing to buf; w is index of next byte to write.
|
||||
// dotdot is index in buf where .. must stop, either because
|
||||
// it is the leading slash or it is a leading ../../.. prefix.
|
||||
n := len(path)
|
||||
out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen}
|
||||
r, dotdot := 0, 0
|
||||
if rooted {
|
||||
|
||||
@@ -93,9 +93,6 @@ var wincleantests = []PathTest{
|
||||
{`//host/share/foo/../baz`, `\\host\share\baz`},
|
||||
{`\\a\b\..\c`, `\\a\b\c`},
|
||||
{`\\a\b`, `\\a\b`},
|
||||
{`\\a\b\`, `\\a\b`},
|
||||
{`\\folder\share\foo`, `\\folder\share\foo`},
|
||||
{`\\folder\share\foo\`, `\\folder\share\foo`},
|
||||
}
|
||||
|
||||
func TestClean(t *testing.T) {
|
||||
@@ -1413,3 +1410,103 @@ func TestIssue29372(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 30520 part 1.
|
||||
func TestEvalSymlinksAboveRoot(t *testing.T) {
|
||||
testenv.MustHaveSymlink(t)
|
||||
|
||||
t.Parallel()
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "TestEvalSymlinksAboveRoot")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
evalTmpDir, err := filepath.EvalSymlinks(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := os.Mkdir(filepath.Join(evalTmpDir, "a"), 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Symlink(filepath.Join(evalTmpDir, "a"), filepath.Join(evalTmpDir, "b")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(evalTmpDir, "a", "file"), nil, 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Count the number of ".." elements to get to the root directory.
|
||||
vol := filepath.VolumeName(evalTmpDir)
|
||||
c := strings.Count(evalTmpDir[len(vol):], string(os.PathSeparator))
|
||||
var dd []string
|
||||
for i := 0; i < c+2; i++ {
|
||||
dd = append(dd, "..")
|
||||
}
|
||||
|
||||
wantSuffix := strings.Join([]string{"a", "file"}, string(os.PathSeparator))
|
||||
|
||||
// Try different numbers of "..".
|
||||
for _, i := range []int{c, c + 1, c + 2} {
|
||||
check := strings.Join([]string{evalTmpDir, strings.Join(dd[:i], string(os.PathSeparator)), evalTmpDir[len(vol)+1:], "b", "file"}, string(os.PathSeparator))
|
||||
if resolved, err := filepath.EvalSymlinks(check); err != nil {
|
||||
t.Errorf("EvalSymlinks(%q) failed: %v", check, err)
|
||||
} else if !strings.HasSuffix(resolved, wantSuffix) {
|
||||
t.Errorf("EvalSymlinks(%q) = %q does not end with %q", check, resolved, wantSuffix)
|
||||
} else {
|
||||
t.Logf("EvalSymlinks(%q) = %q", check, resolved)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 30520 part 2.
|
||||
func TestEvalSymlinksAboveRootChdir(t *testing.T) {
|
||||
testenv.MustHaveSymlink(t)
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "TestEvalSymlinksAboveRootChdir")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Chdir(wd)
|
||||
|
||||
if err := os.Chdir(tmpDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
subdir := filepath.Join("a", "b")
|
||||
if err := os.MkdirAll(subdir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Symlink(subdir, "c"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(subdir, "file"), nil, 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
subdir = filepath.Join("d", "e", "f")
|
||||
if err := os.MkdirAll(subdir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Chdir(subdir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
check := filepath.Join("..", "..", "..", "c", "file")
|
||||
wantSuffix := filepath.Join("a", "b", "file")
|
||||
if resolved, err := filepath.EvalSymlinks(check); err != nil {
|
||||
t.Errorf("EvalSymlinks(%q) failed: %v", check, err)
|
||||
} else if !strings.HasSuffix(resolved, wantSuffix) {
|
||||
t.Errorf("EvalSymlinks(%q) = %q does not end with %q", check, resolved, wantSuffix)
|
||||
} else {
|
||||
t.Logf("EvalSymlinks(%q) = %q", check, resolved)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,18 +44,26 @@ func walkSymlinks(path string) (string, error) {
|
||||
} else if path[start:end] == ".." {
|
||||
// Back up to previous component if possible.
|
||||
// Note that volLen includes any leading slash.
|
||||
|
||||
// Set r to the index of the last slash in dest,
|
||||
// after the volume.
|
||||
var r int
|
||||
for r = len(dest) - 1; r >= volLen; r-- {
|
||||
if os.IsPathSeparator(dest[r]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if r < volLen {
|
||||
if r < volLen || dest[r+1:] == ".." {
|
||||
// Either path has no slashes
|
||||
// (it's empty or just "C:")
|
||||
// or it ends in a ".." we had to keep.
|
||||
// Either way, keep this "..".
|
||||
if len(dest) > volLen {
|
||||
dest += pathSeparator
|
||||
}
|
||||
dest += ".."
|
||||
} else {
|
||||
// Discard everything since the last slash.
|
||||
dest = dest[:r]
|
||||
}
|
||||
continue
|
||||
|
||||
@@ -443,7 +443,7 @@ TEXT runtime·gcWriteBarrier(SB), NOSPLIT, $16
|
||||
// Record value
|
||||
MOVD R1, 0(R5)
|
||||
// Record *slot
|
||||
MOVD R0, 8(R5)
|
||||
MOVD (R0), 8(R5)
|
||||
|
||||
// Increment wbBuf.next
|
||||
Get R5
|
||||
|
||||
@@ -728,3 +728,15 @@ func TestG0StackOverflow(t *testing.T) {
|
||||
|
||||
runtime.G0StackOverflow()
|
||||
}
|
||||
|
||||
// Test that panic message is not clobbered.
|
||||
// See issue 30150.
|
||||
func TestDoublePanic(t *testing.T) {
|
||||
output := runTestProg(t, "testprog", "DoublePanic", "GODEBUG=clobberfree=1")
|
||||
wants := []string{"panic: XXX", "panic: YYY"}
|
||||
for _, want := range wants {
|
||||
if !strings.Contains(output, want) {
|
||||
t.Errorf("output:\n%s\n\nwant output containing: %s", output, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@ It is a comma-separated list of name=val pairs setting these named variables:
|
||||
allocfreetrace: setting allocfreetrace=1 causes every allocation to be
|
||||
profiled and a stack trace printed on each object's allocation and free.
|
||||
|
||||
clobberfree: setting clobberfree=1 causes the garbage collector to
|
||||
clobber the memory content of an object with bad content when it frees
|
||||
the object.
|
||||
|
||||
cgocheck: setting cgocheck=0 disables all checks for packages
|
||||
using cgo to incorrectly pass Go pointers to non-Go code.
|
||||
Setting cgocheck=1 (the default) enables relatively cheap
|
||||
@@ -123,7 +127,7 @@ It is a comma-separated list of name=val pairs setting these named variables:
|
||||
IDs will refer to the ID of the goroutine at the time of creation; it's possible for this
|
||||
ID to be reused for another goroutine. Setting N to 0 will report no ancestry information.
|
||||
|
||||
The net and net/http packages also refer to debugging variables in GODEBUG.
|
||||
The net, net/http, and crypto/tls packages also refer to debugging variables in GODEBUG.
|
||||
See the documentation for those packages for details.
|
||||
|
||||
The GOMAXPROCS variable limits the number of operating system threads that
|
||||
|
||||
@@ -709,7 +709,20 @@ func scanstack(gp *g, gcw *gcWork) {
|
||||
return true
|
||||
}
|
||||
gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0)
|
||||
|
||||
// Find additional pointers that point into the stack from the heap.
|
||||
// Currently this includes defers and panics. See also function copystack.
|
||||
tracebackdefers(gp, scanframe, nil)
|
||||
for d := gp._defer; d != nil; d = d.link {
|
||||
// tracebackdefers above does not scan the func value, which could
|
||||
// be a stack allocated closure. See issue 30453.
|
||||
if d.fn != nil {
|
||||
scanblock(uintptr(unsafe.Pointer(&d.fn)), sys.PtrSize, &oneptrmask[0], gcw, &state)
|
||||
}
|
||||
}
|
||||
if gp._panic != nil {
|
||||
state.putPtr(uintptr(unsafe.Pointer(gp._panic)))
|
||||
}
|
||||
|
||||
// Find and scan all reachable stack objects.
|
||||
state.buildIndex()
|
||||
|
||||
@@ -291,7 +291,7 @@ func (s *mspan) sweep(preserve bool) bool {
|
||||
}
|
||||
}
|
||||
|
||||
if debug.allocfreetrace != 0 || raceenabled || msanenabled {
|
||||
if debug.allocfreetrace != 0 || debug.clobberfree != 0 || raceenabled || msanenabled {
|
||||
// Find all newly freed objects. This doesn't have to
|
||||
// efficient; allocfreetrace has massive overhead.
|
||||
mbits := s.markBitsForBase()
|
||||
@@ -302,6 +302,9 @@ func (s *mspan) sweep(preserve bool) bool {
|
||||
if debug.allocfreetrace != 0 {
|
||||
tracefree(unsafe.Pointer(x), size)
|
||||
}
|
||||
if debug.clobberfree != 0 {
|
||||
clobberfree(unsafe.Pointer(x), size)
|
||||
}
|
||||
if raceenabled {
|
||||
racefree(unsafe.Pointer(x), size)
|
||||
}
|
||||
@@ -446,3 +449,12 @@ retry:
|
||||
traceGCSweepDone()
|
||||
}
|
||||
}
|
||||
|
||||
// clobberfree sets the memory content at x to bad content, for debugging
|
||||
// purposes.
|
||||
func clobberfree(x unsafe.Pointer, size uintptr) {
|
||||
// size (span.elemsize) is always a multiple of 4.
|
||||
for i := uintptr(0); i < size; i += 4 {
|
||||
*(*uint32)(add(x, i)) = 0xdeadbeef
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ const (
|
||||
//go:cgo_import_dynamic runtime._GetProcessAffinityMask GetProcessAffinityMask%3 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus%5 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle%1 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._GetSystemDirectoryA GetSystemDirectoryA%2 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll"
|
||||
@@ -47,12 +48,9 @@ const (
|
||||
//go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc%4 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._VirtualQuery VirtualQuery%3 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult%5 "ws2_32.dll"
|
||||
//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod%1 "winmm.dll"
|
||||
//go:cgo_import_dynamic runtime._timeEndPeriod timeEndPeriod%1 "winmm.dll"
|
||||
|
||||
type stdFunction unsafe.Pointer
|
||||
|
||||
@@ -75,6 +73,7 @@ var (
|
||||
_GetProcessAffinityMask,
|
||||
_GetQueuedCompletionStatus,
|
||||
_GetStdHandle,
|
||||
_GetSystemDirectoryA,
|
||||
_GetSystemInfo,
|
||||
_GetSystemTimeAsFileTime,
|
||||
_GetThreadContext,
|
||||
@@ -96,12 +95,9 @@ var (
|
||||
_VirtualAlloc,
|
||||
_VirtualFree,
|
||||
_VirtualQuery,
|
||||
_WSAGetOverlappedResult,
|
||||
_WaitForSingleObject,
|
||||
_WriteConsoleW,
|
||||
_WriteFile,
|
||||
_timeBeginPeriod,
|
||||
_timeEndPeriod,
|
||||
_ stdFunction
|
||||
|
||||
// Following syscalls are only available on some Windows PCs.
|
||||
@@ -109,6 +105,7 @@ var (
|
||||
_AddDllDirectory,
|
||||
_AddVectoredContinueHandler,
|
||||
_GetQueuedCompletionStatusEx,
|
||||
_LoadLibraryExA,
|
||||
_LoadLibraryExW,
|
||||
_ stdFunction
|
||||
|
||||
@@ -126,6 +123,12 @@ var (
|
||||
// links wrong printf function to cgo executable (see issue
|
||||
// 12030 for details).
|
||||
_NtWaitForSingleObject stdFunction
|
||||
|
||||
// These are from non-kernel32.dll, so we prefer to LoadLibraryEx them.
|
||||
_timeBeginPeriod,
|
||||
_timeEndPeriod,
|
||||
_WSAGetOverlappedResult,
|
||||
_ stdFunction
|
||||
)
|
||||
|
||||
// Function to be called by windows CreateThread
|
||||
@@ -173,6 +176,26 @@ func windowsFindfunc(lib uintptr, name []byte) stdFunction {
|
||||
return stdFunction(unsafe.Pointer(f))
|
||||
}
|
||||
|
||||
var sysDirectory [521]byte
|
||||
var sysDirectoryLen uintptr
|
||||
|
||||
func windowsLoadSystemLib(name []byte) uintptr {
|
||||
if useLoadLibraryEx {
|
||||
return stdcall3(_LoadLibraryExA, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
|
||||
} else {
|
||||
if sysDirectoryLen == 0 {
|
||||
l := stdcall2(_GetSystemDirectoryA, uintptr(unsafe.Pointer(&sysDirectory[0])), uintptr(len(sysDirectory)-1))
|
||||
if l == 0 || l > uintptr(len(sysDirectory)-1) {
|
||||
throw("Unable to determine system directory")
|
||||
}
|
||||
sysDirectory[l] = '\\'
|
||||
sysDirectoryLen = l + 1
|
||||
}
|
||||
absName := append(sysDirectory[:sysDirectoryLen], name...)
|
||||
return stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&absName[0])))
|
||||
}
|
||||
}
|
||||
|
||||
func loadOptionalSyscalls() {
|
||||
var kernel32dll = []byte("kernel32.dll\000")
|
||||
k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0])))
|
||||
@@ -182,17 +205,19 @@ func loadOptionalSyscalls() {
|
||||
_AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000"))
|
||||
_AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000"))
|
||||
_GetQueuedCompletionStatusEx = windowsFindfunc(k32, []byte("GetQueuedCompletionStatusEx\000"))
|
||||
_LoadLibraryExA = windowsFindfunc(k32, []byte("LoadLibraryExA\000"))
|
||||
_LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
|
||||
useLoadLibraryEx = (_LoadLibraryExW != nil && _LoadLibraryExA != nil && _AddDllDirectory != nil)
|
||||
|
||||
var advapi32dll = []byte("advapi32.dll\000")
|
||||
a32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&advapi32dll[0])))
|
||||
a32 := windowsLoadSystemLib(advapi32dll)
|
||||
if a32 == 0 {
|
||||
throw("advapi32.dll not found")
|
||||
}
|
||||
_RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000"))
|
||||
|
||||
var ntdll = []byte("ntdll.dll\000")
|
||||
n32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&ntdll[0])))
|
||||
n32 := windowsLoadSystemLib(ntdll)
|
||||
if n32 == 0 {
|
||||
throw("ntdll.dll not found")
|
||||
}
|
||||
@@ -205,6 +230,27 @@ func loadOptionalSyscalls() {
|
||||
}
|
||||
}
|
||||
|
||||
var winmmdll = []byte("winmm.dll\000")
|
||||
m32 := windowsLoadSystemLib(winmmdll)
|
||||
if m32 == 0 {
|
||||
throw("winmm.dll not found")
|
||||
}
|
||||
_timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000"))
|
||||
_timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000"))
|
||||
if _timeBeginPeriod == nil || _timeEndPeriod == nil {
|
||||
throw("timeBegin/EndPeriod not found")
|
||||
}
|
||||
|
||||
var ws232dll = []byte("ws2_32.dll\000")
|
||||
ws232 := windowsLoadSystemLib(ws232dll)
|
||||
if ws232 == 0 {
|
||||
throw("ws2_32.dll not found")
|
||||
}
|
||||
_WSAGetOverlappedResult = windowsFindfunc(ws232, []byte("WSAGetOverlappedResult\000"))
|
||||
if _WSAGetOverlappedResult == nil {
|
||||
throw("WSAGetOverlappedResult not found")
|
||||
}
|
||||
|
||||
if windowsFindfunc(n32, []byte("wine_get_version\000")) != nil {
|
||||
// running on Wine
|
||||
initWine(k32)
|
||||
@@ -311,8 +357,6 @@ func osinit() {
|
||||
|
||||
loadOptionalSyscalls()
|
||||
|
||||
useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil)
|
||||
|
||||
disableWER()
|
||||
|
||||
initExceptionHandler()
|
||||
|
||||
@@ -139,6 +139,7 @@ func TestLldbPython(t *testing.T) {
|
||||
if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final {
|
||||
t.Skip("gdb test can fail with GOROOT_FINAL pending")
|
||||
}
|
||||
testenv.SkipFlaky(t, 31188)
|
||||
|
||||
checkLldbPython(t)
|
||||
|
||||
|
||||
@@ -301,6 +301,7 @@ type dbgVar struct {
|
||||
var debug struct {
|
||||
allocfreetrace int32
|
||||
cgocheck int32
|
||||
clobberfree int32
|
||||
efence int32
|
||||
gccheckmark int32
|
||||
gcpacertrace int32
|
||||
@@ -318,6 +319,7 @@ var debug struct {
|
||||
|
||||
var dbgvars = []dbgVar{
|
||||
{"allocfreetrace", &debug.allocfreetrace},
|
||||
{"clobberfree", &debug.clobberfree},
|
||||
{"cgocheck", &debug.cgocheck},
|
||||
{"efence", &debug.efence},
|
||||
{"gccheckmark", &debug.gccheckmark},
|
||||
|
||||
@@ -787,3 +787,11 @@ func TestTracebackAncestors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that defer closure is correctly scanned when the stack is scanned.
|
||||
func TestDeferLiveness(t *testing.T) {
|
||||
output := runTestProg(t, "testprog", "DeferLiveness", "GODEBUG=clobberfree=1")
|
||||
if output != "" {
|
||||
t.Errorf("output:\n%s\n\nwant no output", output)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,13 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
|
||||
|
||||
const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
|
||||
|
||||
// When available, this function will use LoadLibraryEx with the filename
|
||||
// parameter and the important SEARCH_SYSTEM32 argument. But on systems that
|
||||
// do not have that option, absoluteFilepath should contain a fallback
|
||||
// to the full path inside of system32 for use with vanilla LoadLibrary.
|
||||
//go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary
|
||||
//go:nosplit
|
||||
func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
|
||||
func syscall_loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle, err uintptr) {
|
||||
lockOSThread()
|
||||
defer unlockOSThread()
|
||||
c := &getg().m.syscall
|
||||
@@ -121,15 +125,9 @@ func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
|
||||
}{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32}
|
||||
c.args = uintptr(noescape(unsafe.Pointer(&args)))
|
||||
} else {
|
||||
// User doesn't have KB2533623 installed. The caller
|
||||
// wanted to only load the filename DLL from the
|
||||
// System32 directory but that facility doesn't exist,
|
||||
// so just load it the normal way. This is a potential
|
||||
// security risk, but so is not installing security
|
||||
// updates.
|
||||
c.fn = getLoadLibrary()
|
||||
c.n = 1
|
||||
c.args = uintptr(noescape(unsafe.Pointer(&filename)))
|
||||
c.args = uintptr(noescape(unsafe.Pointer(&absoluteFilepath)))
|
||||
}
|
||||
|
||||
cgocall(asmstdcallAddr, unsafe.Pointer(c))
|
||||
|
||||
21
src/runtime/testdata/testprog/crash.go
vendored
21
src/runtime/testdata/testprog/crash.go
vendored
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
func init() {
|
||||
register("Crash", Crash)
|
||||
register("DoublePanic", DoublePanic)
|
||||
}
|
||||
|
||||
func test(name string) {
|
||||
@@ -43,3 +44,23 @@ func Crash() {
|
||||
testInNewThread("second-new-thread")
|
||||
test("main-again")
|
||||
}
|
||||
|
||||
type P string
|
||||
|
||||
func (p P) String() string {
|
||||
// Try to free the "YYY" string header when the "XXX"
|
||||
// panic is stringified.
|
||||
runtime.GC()
|
||||
runtime.GC()
|
||||
runtime.GC()
|
||||
return string(p)
|
||||
}
|
||||
|
||||
// Test that panic message is not clobbered.
|
||||
// See issue 30150.
|
||||
func DoublePanic() {
|
||||
defer func() {
|
||||
panic(P("YYY"))
|
||||
}()
|
||||
panic(P("XXX"))
|
||||
}
|
||||
|
||||
23
src/runtime/testdata/testprog/gc.go
vendored
23
src/runtime/testdata/testprog/gc.go
vendored
@@ -18,6 +18,7 @@ func init() {
|
||||
register("GCFairness2", GCFairness2)
|
||||
register("GCSys", GCSys)
|
||||
register("GCPhys", GCPhys)
|
||||
register("DeferLiveness", DeferLiveness)
|
||||
}
|
||||
|
||||
func GCSys() {
|
||||
@@ -207,3 +208,25 @@ func GCPhys() {
|
||||
fmt.Println("OK")
|
||||
runtime.KeepAlive(saved)
|
||||
}
|
||||
|
||||
// Test that defer closure is correctly scanned when the stack is scanned.
|
||||
func DeferLiveness() {
|
||||
var x [10]int
|
||||
escape(&x)
|
||||
fn := func() {
|
||||
if x[0] != 42 {
|
||||
panic("FAIL")
|
||||
}
|
||||
}
|
||||
defer fn()
|
||||
|
||||
x[0] = 42
|
||||
runtime.GC()
|
||||
runtime.GC()
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func escape(x interface{}) { sink2 = x; sink2 = nil }
|
||||
|
||||
var sink2 interface{}
|
||||
|
||||
@@ -28,7 +28,7 @@ func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 ui
|
||||
func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)
|
||||
func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2 uintptr, err Errno)
|
||||
func loadlibrary(filename *uint16) (handle uintptr, err Errno)
|
||||
func loadsystemlibrary(filename *uint16) (handle uintptr, err Errno)
|
||||
func loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle uintptr, err Errno)
|
||||
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
|
||||
|
||||
// A DLL implements access to a single DLL.
|
||||
@@ -37,6 +37,26 @@ type DLL struct {
|
||||
Handle Handle
|
||||
}
|
||||
|
||||
// We use this for computing the absolute path for system DLLs on systems
|
||||
// where SEARCH_SYSTEM32 is not available.
|
||||
var systemDirectoryPrefix string
|
||||
|
||||
func init() {
|
||||
n := uint32(MAX_PATH)
|
||||
for {
|
||||
b := make([]uint16, n)
|
||||
l, e := getSystemDirectory(&b[0], n)
|
||||
if e != nil {
|
||||
panic("Unable to determine system directory: " + e.Error())
|
||||
}
|
||||
if l <= n {
|
||||
systemDirectoryPrefix = UTF16ToString(b[:l]) + "\\"
|
||||
break
|
||||
}
|
||||
n = l
|
||||
}
|
||||
}
|
||||
|
||||
// LoadDLL loads the named DLL file into memory.
|
||||
//
|
||||
// If name is not an absolute path and is not a known system DLL used by
|
||||
@@ -53,7 +73,11 @@ func LoadDLL(name string) (*DLL, error) {
|
||||
var h uintptr
|
||||
var e Errno
|
||||
if sysdll.IsSystemDLL[name] {
|
||||
h, e = loadsystemlibrary(namep)
|
||||
absoluteFilepathp, err := UTF16PtrFromString(systemDirectoryPrefix + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h, e = loadsystemlibrary(namep, absoluteFilepathp)
|
||||
} else {
|
||||
h, e = loadlibrary(namep)
|
||||
}
|
||||
|
||||
@@ -290,6 +290,7 @@ type Tokenprimarygroup struct {
|
||||
//sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
|
||||
//sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation
|
||||
//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
|
||||
//sys getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemDirectoryW
|
||||
|
||||
// An access token contains the security information for a logon session.
|
||||
// The system creates an access token when a user logs on, and every
|
||||
|
||||
@@ -360,10 +360,23 @@ func TestSyscallNoError(t *testing.T) {
|
||||
strconv.FormatUint(uint64(-uid), 10) + " / " +
|
||||
strconv.FormatUint(uint64(uid), 10)
|
||||
if got != want {
|
||||
if filesystemIsNoSUID(tmpBinary) {
|
||||
t.Skip("skipping test when temp dir is mounted nosuid")
|
||||
}
|
||||
t.Errorf("expected %s, got %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
// filesystemIsNoSUID reports whether the filesystem for the given
|
||||
// path is mounted nosuid.
|
||||
func filesystemIsNoSUID(path string) bool {
|
||||
var st syscall.Statfs_t
|
||||
if syscall.Statfs(path, &st) != nil {
|
||||
return false
|
||||
}
|
||||
return st.Flags&syscall.MS_NOSUID != 0
|
||||
}
|
||||
|
||||
func syscallNoError() {
|
||||
// Test that the return value from SYS_GETEUID32 (which cannot fail)
|
||||
// doesn't get treated as an error (see https://golang.org/issue/22924)
|
||||
|
||||
@@ -190,6 +190,7 @@ var (
|
||||
procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken")
|
||||
procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation")
|
||||
procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW")
|
||||
procGetSystemDirectoryW = modkernel32.NewProc("GetSystemDirectoryW")
|
||||
)
|
||||
|
||||
func GetLastError() (lasterr error) {
|
||||
@@ -1916,3 +1917,16 @@ func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) {
|
||||
r0, _, e1 := Syscall(procGetSystemDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(dirLen), 0)
|
||||
len = uint32(r0)
|
||||
if len == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -576,6 +576,13 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
|
||||
}
|
||||
typ := receiver.Type()
|
||||
receiver, isNil := indirect(receiver)
|
||||
if receiver.Kind() == reflect.Interface && isNil {
|
||||
// Calling a method on a nil interface can't work. The
|
||||
// MethodByName method call below would panic.
|
||||
s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
|
||||
return zero
|
||||
}
|
||||
|
||||
// Unless it's an interface, need to get to a value of type *T to guarantee
|
||||
// we see all methods of T and *T.
|
||||
ptr := receiver
|
||||
|
||||
@@ -58,8 +58,10 @@ type T struct {
|
||||
Empty3 interface{}
|
||||
Empty4 interface{}
|
||||
// Non-empty interfaces.
|
||||
NonEmptyInterface I
|
||||
NonEmptyInterfacePtS *I
|
||||
NonEmptyInterface I
|
||||
NonEmptyInterfacePtS *I
|
||||
NonEmptyInterfaceNil I
|
||||
NonEmptyInterfaceTypedNil I
|
||||
// Stringer.
|
||||
Str fmt.Stringer
|
||||
Err error
|
||||
@@ -141,24 +143,25 @@ var tVal = &T{
|
||||
{"one": 1, "two": 2},
|
||||
{"eleven": 11, "twelve": 12},
|
||||
},
|
||||
Empty1: 3,
|
||||
Empty2: "empty2",
|
||||
Empty3: []int{7, 8},
|
||||
Empty4: &U{"UinEmpty"},
|
||||
NonEmptyInterface: &T{X: "x"},
|
||||
NonEmptyInterfacePtS: &siVal,
|
||||
Str: bytes.NewBuffer([]byte("foozle")),
|
||||
Err: errors.New("erroozle"),
|
||||
PI: newInt(23),
|
||||
PS: newString("a string"),
|
||||
PSI: newIntSlice(21, 22, 23),
|
||||
BinaryFunc: func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) },
|
||||
VariadicFunc: func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
|
||||
VariadicFuncInt: func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
|
||||
NilOKFunc: func(s *int) bool { return s == nil },
|
||||
ErrFunc: func() (string, error) { return "bla", nil },
|
||||
PanicFunc: func() string { panic("test panic") },
|
||||
Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X
|
||||
Empty1: 3,
|
||||
Empty2: "empty2",
|
||||
Empty3: []int{7, 8},
|
||||
Empty4: &U{"UinEmpty"},
|
||||
NonEmptyInterface: &T{X: "x"},
|
||||
NonEmptyInterfacePtS: &siVal,
|
||||
NonEmptyInterfaceTypedNil: (*T)(nil),
|
||||
Str: bytes.NewBuffer([]byte("foozle")),
|
||||
Err: errors.New("erroozle"),
|
||||
PI: newInt(23),
|
||||
PS: newString("a string"),
|
||||
PSI: newIntSlice(21, 22, 23),
|
||||
BinaryFunc: func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) },
|
||||
VariadicFunc: func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
|
||||
VariadicFuncInt: func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
|
||||
NilOKFunc: func(s *int) bool { return s == nil },
|
||||
ErrFunc: func() (string, error) { return "bla", nil },
|
||||
PanicFunc: func() string { panic("test panic") },
|
||||
Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X
|
||||
}
|
||||
|
||||
var tSliceOfNil = []*T{nil}
|
||||
@@ -365,6 +368,7 @@ var execTests = []execTest{
|
||||
{".NilOKFunc not nil", "{{call .NilOKFunc .PI}}", "false", tVal, true},
|
||||
{".NilOKFunc nil", "{{call .NilOKFunc nil}}", "true", tVal, true},
|
||||
{"method on nil value from slice", "-{{range .}}{{.Method1 1234}}{{end}}-", "-1234-", tSliceOfNil, true},
|
||||
{"method on typed nil interface value", "{{.NonEmptyInterfaceTypedNil.Method0}}", "M0", tVal, true},
|
||||
|
||||
// Function call builtin.
|
||||
{".BinaryFunc", "{{call .BinaryFunc `1` `2`}}", "[1=2]", tVal, true},
|
||||
@@ -1492,6 +1496,11 @@ func TestExecutePanicDuringCall(t *testing.T) {
|
||||
"{{call .PanicFunc}}", tVal,
|
||||
`template: t:1:2: executing "t" at <call .PanicFunc>: error calling call: test panic`,
|
||||
},
|
||||
{
|
||||
"method call on nil interface",
|
||||
"{{.NonEmptyInterfaceNil.Method0}}", tVal,
|
||||
`template: t:1:23: executing "t" at <.NonEmptyInterfaceNil.Method0>: nil pointer evaluating template.I.Method0`,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
b := new(bytes.Buffer)
|
||||
|
||||
@@ -33,9 +33,7 @@ func f1(a [256]int, i int) {
|
||||
|
||||
if 4 <= i && i < len(a) {
|
||||
useInt(a[i])
|
||||
useInt(a[i-1]) // ERROR "Found IsInBounds$"
|
||||
// TODO: 'if 4 <= i && i < len(a)' gets rewritten to 'if uint(i - 4) < 256 - 4',
|
||||
// which the bounds checker cannot yet use to infer that the next line doesn't need a bounds check.
|
||||
useInt(a[i-1])
|
||||
useInt(a[i-4])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func f2(q *int) { // ERROR "from &u \(address-of\) at escape_because.go:43$" "fr
|
||||
sink = &u // ERROR "&u escapes to heap$" "from &u \(interface-converted\) at escape_because.go:43$" "from sink \(assigned to top level variable\) at escape_because.go:43$"
|
||||
}
|
||||
|
||||
func f3(r *int) interface{} { // ERROR "from \[\]\*int literal \(slice-literal-element\) at escape_because.go:47$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:48$" "leaking param: r to result ~r1 level=-1$"
|
||||
func f3(r *int) interface{} { // ERROR "from \[\]\*int literal \(slice-literal-element\) at escape_because.go:47$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:48$" "leaking param: r"
|
||||
c := []*int{r} // ERROR "\[\]\*int literal escapes to heap$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:48$"
|
||||
return c // "return" // ERROR "c escapes to heap$" "from ~r1 \(return\) at escape_because.go:48$"
|
||||
}
|
||||
|
||||
@@ -424,3 +424,18 @@ func h(x *Node) { // ERROR "leaking param: x"
|
||||
Sink = g(y)
|
||||
f(y)
|
||||
}
|
||||
|
||||
// interface(in) -> out
|
||||
// See also issue 29353.
|
||||
|
||||
// Convert to a non-direct interface, require an allocation and
|
||||
// copy x to heap (not to result).
|
||||
func param14a(x [4]*int) interface{} { // ERROR "leaking param: x$"
|
||||
return x // ERROR "x escapes to heap"
|
||||
}
|
||||
|
||||
// Convert to a direct interface, does not need an allocation.
|
||||
// So x only leaks to result.
|
||||
func param14b(x *int) interface{} { // ERROR "leaking param: x to result ~r1 level=0"
|
||||
return x // ERROR "x escapes to heap"
|
||||
}
|
||||
|
||||
@@ -16,3 +16,20 @@ func f() {
|
||||
}
|
||||
_ = s == "bbb"
|
||||
}
|
||||
|
||||
// Another case: load from negative offset of a symbol
|
||||
// in dead code (issue 30257).
|
||||
func g() {
|
||||
var i int
|
||||
var s string
|
||||
|
||||
if true {
|
||||
s = "a"
|
||||
}
|
||||
|
||||
if f := 0.0; -f < 0 {
|
||||
i = len(s[:4])
|
||||
}
|
||||
|
||||
_ = s[i-1:0] != "bb" && true
|
||||
}
|
||||
|
||||
30
test/fixedbugs/issue30476.go
Normal file
30
test/fixedbugs/issue30476.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// run
|
||||
|
||||
// Copyright 2019 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 30476: KeepAlive didn't keep stack object alive.
|
||||
|
||||
package main
|
||||
|
||||
import "runtime"
|
||||
|
||||
func main() {
|
||||
x := new([10]int)
|
||||
runtime.SetFinalizer(x, func(*[10]int) { panic("FAIL: finalizer runs") })
|
||||
p := &T{x, 0}
|
||||
use(p)
|
||||
runtime.GC()
|
||||
runtime.GC()
|
||||
runtime.GC()
|
||||
runtime.KeepAlive(p)
|
||||
}
|
||||
|
||||
type T struct {
|
||||
x *[10]int
|
||||
y int
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func use(*T) {}
|
||||
23
test/fixedbugs/issue30566a.go
Normal file
23
test/fixedbugs/issue30566a.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// run
|
||||
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
//go:noinline
|
||||
func ident(s string) string { return s }
|
||||
|
||||
func returnSecond(x bool, s string) string { return s }
|
||||
|
||||
func identWrapper(s string) string { return ident(s) }
|
||||
|
||||
func main() {
|
||||
got := returnSecond((false || identWrapper("bad") != ""), ident("good"))
|
||||
if got != "good" {
|
||||
panic(fmt.Sprintf("wanted \"good\", got \"%s\"", got))
|
||||
}
|
||||
}
|
||||
27
test/fixedbugs/issue30566b.go
Normal file
27
test/fixedbugs/issue30566b.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// run
|
||||
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
_, _ = false || g(1), g(2)
|
||||
if !bytes.Equal(x, []byte{1, 2}) {
|
||||
panic(fmt.Sprintf("wanted [1,2], got %v", x))
|
||||
}
|
||||
}
|
||||
|
||||
var x []byte
|
||||
|
||||
//go:noinline
|
||||
func g(b byte) bool {
|
||||
x = append(x, b)
|
||||
return false
|
||||
}
|
||||
32
test/fixedbugs/issue30956.go
Normal file
32
test/fixedbugs/issue30956.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// run
|
||||
|
||||
// Copyright 2019 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.
|
||||
|
||||
// Check for compile generated static data for literal
|
||||
// composite struct
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type X struct {
|
||||
V interface{}
|
||||
|
||||
a int
|
||||
b int
|
||||
c int
|
||||
}
|
||||
|
||||
func pr(x X) {
|
||||
fmt.Println(x.V)
|
||||
}
|
||||
|
||||
func main() {
|
||||
pr(X{
|
||||
V: struct {
|
||||
A int
|
||||
}{42},
|
||||
})
|
||||
}
|
||||
1
test/fixedbugs/issue30956.out
Normal file
1
test/fixedbugs/issue30956.out
Normal file
@@ -0,0 +1 @@
|
||||
{42}
|
||||
52
test/fixedbugs/issue30977.go
Normal file
52
test/fixedbugs/issue30977.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// run
|
||||
|
||||
// Copyright 2019 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 30977: write barrier call clobbers volatile
|
||||
// value when there are multiple uses of the value.
|
||||
|
||||
package main
|
||||
|
||||
import "runtime"
|
||||
|
||||
type T struct {
|
||||
a, b, c, d, e string
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func g() T {
|
||||
return T{"a", "b", "c", "d", "e"}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func f() {
|
||||
// The compiler optimizes this to direct copying
|
||||
// the call result to both globals, with write
|
||||
// barriers. The first write barrier call clobbers
|
||||
// the result of g on stack.
|
||||
X = g()
|
||||
Y = X
|
||||
}
|
||||
|
||||
var X, Y T
|
||||
|
||||
const N = 1000
|
||||
|
||||
func main() {
|
||||
// Keep GC running so the write barrier is on.
|
||||
go func() {
|
||||
for {
|
||||
runtime.GC()
|
||||
}
|
||||
}()
|
||||
|
||||
for i := 0; i < N; i++ {
|
||||
runtime.Gosched()
|
||||
f()
|
||||
if X != Y {
|
||||
panic("FAIL")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -572,7 +572,7 @@ func f36() {
|
||||
func f37() {
|
||||
if (m33[byteptr()] == 0 || // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
|
||||
m33[byteptr()] == 0) && // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
|
||||
m33[byteptr()] == 0 { // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
|
||||
m33[byteptr()] == 0 {
|
||||
printnl()
|
||||
return
|
||||
}
|
||||
@@ -697,9 +697,10 @@ func f41(p, q *int) (r *int) { // ERROR "live at entry to f41: p q$"
|
||||
|
||||
func f42() {
|
||||
var p, q, r int
|
||||
f43([]*int{&p,&q,&r}) // ERROR "stack object .autotmp_[0-9]+ \[3\]\*int$"
|
||||
f43([]*int{&p,&r,&q})
|
||||
f43([]*int{&q,&p,&r})
|
||||
f43([]*int{&p, &q, &r}) // ERROR "stack object .autotmp_[0-9]+ \[3\]\*int$"
|
||||
f43([]*int{&p, &r, &q})
|
||||
f43([]*int{&q, &p, &r})
|
||||
}
|
||||
|
||||
//go:noescape
|
||||
func f43(a []*int)
|
||||
|
||||
Reference in New Issue
Block a user