mirror of
https://github.com/golang/go.git
synced 2026-01-29 23:22:06 +03:00
Compare commits
129 Commits
dev.corety
...
go1.11.11
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
541c49144d | ||
|
|
f68c8ad666 | ||
|
|
d497d80d23 | ||
|
|
efa061d9f5 | ||
|
|
f0ae474222 | ||
|
|
1bebc53bc3 | ||
|
|
5ee175e682 | ||
|
|
01c8062308 | ||
|
|
428e5f29a9 | ||
|
|
fbac0fe947 | ||
|
|
f8a63418e9 | ||
|
|
9f131004d9 | ||
|
|
462e7deede | ||
|
|
2c5363d9c1 | ||
|
|
ffe346022e | ||
|
|
5ed6ac1fc1 | ||
|
|
987e905bb8 | ||
|
|
e18f2ca380 | ||
|
|
6e6462315b | ||
|
|
6a7a8ba07f | ||
|
|
8390781ca3 | ||
|
|
aa95a1eb5a | ||
|
|
c8c897a670 | ||
|
|
3705d34af1 | ||
|
|
688dc859ea | ||
|
|
4ae9e7f166 | ||
|
|
e104ebfeab | ||
|
|
eb0f2b3d27 | ||
|
|
ddfb74ed26 | ||
|
|
f8e8303f56 | ||
|
|
35bb62e60a | ||
|
|
daef79d405 | ||
|
|
983d8092ef | ||
|
|
42b42f71cf | ||
|
|
cbf9140f89 | ||
|
|
e39e43d734 | ||
|
|
8455a848e7 | ||
|
|
84f1e92144 | ||
|
|
c36b5322a7 | ||
|
|
b2c472f91e | ||
|
|
61b8817b8e | ||
|
|
f500f13d72 | ||
|
|
a171e15500 | ||
|
|
4601a4c1b1 | ||
|
|
37b7c99ffd | ||
|
|
55cfdd7f45 | ||
|
|
66f09979de | ||
|
|
17bf5e9031 | ||
|
|
5128a419b3 | ||
|
|
928a4b6919 | ||
|
|
a1d388ebf2 | ||
|
|
bdc7d5677e | ||
|
|
b86522faa5 | ||
|
|
ef209c9eb1 | ||
|
|
26b98e1be0 | ||
|
|
90c8964486 | ||
|
|
897b44e439 | ||
|
|
914efab0eb | ||
|
|
d39cd4d6d7 | ||
|
|
d01ccd8ee8 | ||
|
|
5aedc8af94 | ||
|
|
8954addb32 | ||
|
|
df52396943 | ||
|
|
71b7b4fad3 | ||
|
|
9cc0209ef1 | ||
|
|
6fa0ace128 | ||
|
|
6971090515 | ||
|
|
ba4638df61 | ||
|
|
62b47c284c | ||
|
|
3e6c171e47 | ||
|
|
c92a20818b | ||
|
|
e602388f98 | ||
|
|
f3b9f362c9 | ||
|
|
402eb45b21 | ||
|
|
e8a95aeb75 | ||
|
|
bbce36c1d8 | ||
|
|
6fb1030157 | ||
|
|
68ad1d60a2 | ||
|
|
369c188667 | ||
|
|
eb46d15471 | ||
|
|
ce6c8a5101 | ||
|
|
97781d2ed1 | ||
|
|
edb6c16b9b | ||
|
|
05b2b9b4d5 | ||
|
|
844bb04531 | ||
|
|
c33153f7b4 | ||
|
|
aa0966105e | ||
|
|
19fe28a3dc | ||
|
|
e9c178da3b | ||
|
|
26957168c4 | ||
|
|
52c4bdb65d | ||
|
|
92ae524bc5 | ||
|
|
307f8b5a6d | ||
|
|
58c9bd9bfb | ||
|
|
3afa9dfa9b | ||
|
|
a2f1c8e2ad | ||
|
|
34e5a852e0 | ||
|
|
7544ac632f | ||
|
|
05a0c7b4c6 | ||
|
|
e535c71009 | ||
|
|
b5ed6ec140 | ||
|
|
f2113d94c1 | ||
|
|
c9ca36fb70 | ||
|
|
0541668416 | ||
|
|
5a25f45bce | ||
|
|
eeaf877114 | ||
|
|
71fce844b5 | ||
|
|
cd9f60131b | ||
|
|
57534891d4 | ||
|
|
ebf5d985d1 | ||
|
|
ad116f72b9 | ||
|
|
359a02b0fc | ||
|
|
6d601b8a95 | ||
|
|
523dc5a412 | ||
|
|
41e62b8c49 | ||
|
|
89eb905c6d | ||
|
|
f5c8875aef | ||
|
|
c7415c1bd4 | ||
|
|
08c66d75ec | ||
|
|
02c0c32960 | ||
|
|
ca25572abb | ||
|
|
2eb8116f9e | ||
|
|
4124fe1c2c | ||
|
|
4383edf1c6 | ||
|
|
e1ad7cdf4f | ||
|
|
811b0c1bf5 | ||
|
|
ece4cdb9cb | ||
|
|
673a05e4df | ||
|
|
807e7f2420 |
@@ -1,7 +1,7 @@
|
||||
pkg crypto/cipher, func NewGCMWithTagSize(Block, int) (AEAD, error)
|
||||
pkg crypto/rsa, method (*PrivateKey) Size() int
|
||||
pkg crypto/rsa, method (*PublicKey) Size() int
|
||||
pkg crypto/tls, type ConnectionState struct, ExportKeyingMaterial func(string, []uint8, int) ([]uint8, bool)
|
||||
pkg crypto/tls, method (*ConnectionState) ExportKeyingMaterial(string, []uint8, int) ([]uint8, error)
|
||||
pkg database/sql, method (IsolationLevel) String() string
|
||||
pkg database/sql, type DBStats struct, Idle int
|
||||
pkg database/sql, type DBStats struct, InUse int
|
||||
|
||||
@@ -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.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>
|
||||
<li><a href="/doc/go1.8">Go 1.8</a> <small>(February 2017)</small></li>
|
||||
|
||||
@@ -23,6 +23,97 @@ 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.11">go1.11 (released 2018/08/24)</h2>
|
||||
|
||||
<p>
|
||||
Go 1.11 is a major release of Go.
|
||||
Read the <a href="/doc/go1.11">Go 1.11 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="go1.11.minor">Minor revisions</h3>
|
||||
|
||||
<p>
|
||||
go1.11.1 (released 2018/10/01) includes fixes to the compiler, documentation, go
|
||||
command, runtime, and the <code>crypto/x509</code>, <code>encoding/json</code>,
|
||||
<code>go/types</code>, <code>net</code>, <code>net/http</code>, and
|
||||
<code>reflect</code> packages.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.1">Go
|
||||
1.11.1 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.11.2 (released 2018/11/02) includes fixes to the compiler, linker,
|
||||
documentation, go command, and the <code>database/sql</code> and
|
||||
<code>go/types</code> packages.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.2">Go
|
||||
1.11.2 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.11.3 (released 2018/12/12) includes three security fixes to "go get" and
|
||||
the <code>crypto/x509</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.3">Go
|
||||
1.11.3 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.11.4 (released 2018/12/14) includes fixes to cgo, the compiler, linker,
|
||||
runtime, documentation, go command, and the <code>net/http</code> and
|
||||
<code>go/types</code> packages.
|
||||
It includes a fix to a bug introduced in Go 1.11.3 that broke <code>go</code>
|
||||
<code>get</code> for import path patterns containing "<code>...</code>".
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.4+label%3ACherryPickApproved">Go
|
||||
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+label%3ACherryPickApproved">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>
|
||||
|
||||
<p>
|
||||
go1.11.8 (released 2019/04/08) was accidentally released without its
|
||||
intended fix. It is identical to go1.11.7, except for its version
|
||||
number. The intended fix is in go1.11.9.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.11.9 (released 2019/04/11) fixes an issue where using the prebuilt binary
|
||||
releases on older versions of GNU/Linux
|
||||
<a href="https://golang.org/issues/31293">led to failures</a>
|
||||
when linking programs that used cgo.
|
||||
Only Linux users who hit this issue need to update.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.11.10 (released 2019/05/06) includes fixes to the runtime and the linker.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.10">Go
|
||||
1.11.10 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.11.11 (released 2019/06/11) includes a fix to the <code>crypto/x509</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.11">Go
|
||||
1.11.11 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.10">go1.10 (released 2018/02/16)</h2>
|
||||
|
||||
<p>
|
||||
@@ -57,6 +148,44 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.3">Go
|
||||
1.10.3 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.10.4 (released 2018/08/24) includes fixes to the go command, linker, and the
|
||||
<code>net/http</code>, <code>mime/multipart</code>, <code>ld/macho</code>,
|
||||
<code>bytes</code>, and <code>strings</code> packages.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.4">Go
|
||||
1.10.4 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.10.5 (released 2018/11/02) includes fixes to the go command, linker, runtime
|
||||
and the <code>database/sql</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.5">Go
|
||||
1.10.5 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.10.6 (released 2018/12/12) includes three security fixes to "go get" and
|
||||
the <code>crypto/x509</code> package.
|
||||
It contains the same fixes as Go 1.11.3 and was released at the same time.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.6">Go
|
||||
1.10.6 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.10.7 (released 2018/12/14) includes a fix to a bug introduced in Go 1.10.6
|
||||
that broke <code>go</code> <code>get</code> for import path patterns containing
|
||||
"<code>...</code>".
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.7+label%3ACherryPickApproved">
|
||||
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+label%3ACherryPickApproved">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>
|
||||
|
||||
@@ -50,10 +50,10 @@ learned. You can {{if not $.GoogleCN}}<a href="//tour.golang.org/">take the tour
|
||||
online</a> or{{end}} install it locally with:
|
||||
</p>
|
||||
<pre>
|
||||
$ go get golang.org/x/tour/gotour
|
||||
$ go get golang.org/x/tour
|
||||
</pre>
|
||||
<p>
|
||||
This will place the <code>gotour</code> binary in your workspace's <code>bin</code> directory.
|
||||
This will place the <code>tour</code> binary in your workspace's <code>bin</code> directory.
|
||||
</p>
|
||||
|
||||
<h3 id="code"><a href="code.html">How to write Go code</a></h3>
|
||||
|
||||
@@ -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.11</h2>
|
||||
|
||||
<p>
|
||||
<strong>
|
||||
Go 1.11 is not yet released. These are work-in-progress
|
||||
release notes. Go 1.11 is expected to be released in August 2018.
|
||||
</strong>
|
||||
</p>
|
||||
<h2 id="introduction">Introduction to Go 1.11</h2>
|
||||
|
||||
<p>
|
||||
The latest Go release, version 1.11, arrives six months after <a href="go1.10">Go 1.10</a>.
|
||||
@@ -95,7 +88,8 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
|
||||
<h3 id="wasm">WebAssembly</h3>
|
||||
<p>
|
||||
Go 1.11 adds an experimental port to WebAssembly (<code>js/wasm</code>).
|
||||
Go 1.11 adds an experimental port to <a href="https://webassembly.org">WebAssembly</a>
|
||||
(<code>js/wasm</code>).
|
||||
</p>
|
||||
<p>
|
||||
Go programs currently compile to one WebAssembly module that
|
||||
@@ -116,6 +110,10 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
tools</a> except when those GOOS/GOARCH values are being used.
|
||||
If you have existing filenames matching those patterns, you will need to rename them.
|
||||
</p>
|
||||
<p>
|
||||
More information can be found on the
|
||||
<a href="https://golang.org/wiki/WebAssembly">WebAssembly wiki page</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="riscv">RISC-V GOARCH values reserved</h3>
|
||||
<p><!-- CL 106256 -->
|
||||
@@ -350,6 +348,20 @@ updating. See the <a href="go1.10.html#cgo">Go 1.10 release notes</a> for
|
||||
details. <!-- CL 126275, CL 127156, CL 122217, CL 122575, CL 123177 -->
|
||||
</p>
|
||||
|
||||
<h3 id="go_command">Go command</h3>
|
||||
|
||||
<p><!-- CL 126656 -->
|
||||
The environment variable <code>GOFLAGS</code> may now be used
|
||||
to set default flags for the <code>go</code> command.
|
||||
This is useful in certain situations.
|
||||
Linking can be noticeably slower on underpowered systems due to DWARF,
|
||||
and users may want to set <code>-ldflags=-w</code> by default.
|
||||
For modules, some users and CI systems will want vendoring always,
|
||||
so they should set <code>-mod=vendor</code> by default.
|
||||
For more information, see the <a href="/cmd/go/#hdr-Environment_variables"><code>go</code>
|
||||
command documentation</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="godoc">Godoc</h3>
|
||||
|
||||
<p>
|
||||
@@ -384,10 +396,20 @@ details. <!-- CL 126275, CL 127156, CL 122217, CL 122575, CL 123177 -->
|
||||
time.
|
||||
In general, systems that need consistent formatting of Go source code should
|
||||
use a specific version of the <code>gofmt</code> binary.
|
||||
See the <a href="/pkg/go/format/">go/format</a> package godoc for more
|
||||
See the <a href="/pkg/go/format/">go/format</a> package documentation for more
|
||||
information.
|
||||
</p>
|
||||
|
||||
<h3 id="run">Run</h3>
|
||||
|
||||
<p>
|
||||
<!-- CL 109341 -->
|
||||
The <a href="/cmd/go/"><code>go</code> <code>run</code></a>
|
||||
command now allows a single import path, a directory name or a
|
||||
pattern matching a single package.
|
||||
This allows <code>go</code> <code>run</code> <code>pkg</code> or <code>go</code> <code>run</code> <code>dir</code>, most importantly <code>go</code> <code>run</code> <code>.</code>
|
||||
</p>
|
||||
|
||||
<h2 id="runtime">Runtime</h2>
|
||||
|
||||
<p><!-- CL 85887 -->
|
||||
@@ -398,7 +420,7 @@ details. <!-- CL 126275, CL 127156, CL 122217, CL 122575, CL 123177 -->
|
||||
</p>
|
||||
|
||||
<p><!-- CL 108679, CL 106156 -->
|
||||
On macOS and iOS, the runtime now uses <code>libSystem.so</code> instead of
|
||||
On macOS and iOS, the runtime now uses <code>libSystem.dylib</code> instead of
|
||||
calling the kernel directly. This should make Go binaries more
|
||||
compatible with future versions of macOS and iOS.
|
||||
The <a href="/pkg/syscall">syscall</a> package still makes direct
|
||||
@@ -500,7 +522,8 @@ for k := range m {
|
||||
<dd>
|
||||
<p><!-- CL 85115 -->
|
||||
<a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>'s new
|
||||
<code>ExportKeyingMaterial</code> field allows exporting keying material bound to the
|
||||
<a href="/pkg/crypto/tls/#ConnectionState.ExportKeyingMaterial"><code>ExportKeyingMaterial</code></a>
|
||||
method allows exporting keying material bound to the
|
||||
connection according to RFC 5705.
|
||||
</p>
|
||||
|
||||
|
||||
@@ -92,6 +92,8 @@ func Test25143(t *testing.T) { test25143(t) }
|
||||
func Test23356(t *testing.T) { test23356(t) }
|
||||
func Test26066(t *testing.T) { test26066(t) }
|
||||
func Test26213(t *testing.T) { test26213(t) }
|
||||
func Test27660(t *testing.T) { test27660(t) }
|
||||
func Test28896(t *testing.T) { test28896(t) }
|
||||
|
||||
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
|
||||
func BenchmarkGoString(b *testing.B) { benchGoString(b) }
|
||||
|
||||
12
misc/cgo/test/issue27340.go
Normal file
12
misc/cgo/test/issue27340.go
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Failed to resolve typedefs consistently.
|
||||
// No runtime test; just make sure it compiles.
|
||||
|
||||
package cgotest
|
||||
|
||||
import "./issue27340"
|
||||
|
||||
var issue27340Var = issue27340.Issue27340GoFunc
|
||||
42
misc/cgo/test/issue27340/a.go
Normal file
42
misc/cgo/test/issue27340/a.go
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Failed to resolve typedefs consistently.
|
||||
// No runtime test; just make sure it compiles.
|
||||
// In separate directory to isolate #pragma GCC diagnostic.
|
||||
|
||||
package issue27340
|
||||
|
||||
// We use the #pragma to avoid a compiler warning about incompatible
|
||||
// pointer types, because we generate code passing a struct ptr rather
|
||||
// than using the typedef. This warning is expected and does not break
|
||||
// a normal build.
|
||||
// We can only disable -Wincompatible-pointer-types starting with GCC 5.
|
||||
|
||||
// #if __GNU_MAJOR__ >= 5
|
||||
//
|
||||
// #pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
|
||||
//
|
||||
// typedef struct {
|
||||
// int a;
|
||||
// } issue27340Struct, *issue27340Ptr;
|
||||
//
|
||||
// static void issue27340CFunc(issue27340Ptr p) {}
|
||||
//
|
||||
// #else /* _GNU_MAJOR_ < 5 */
|
||||
//
|
||||
// typedef struct {
|
||||
// int a;
|
||||
// } issue27340Struct;
|
||||
//
|
||||
// static issue27340Struct* issue27340Ptr(issue27340Struct* p) { return p; }
|
||||
//
|
||||
// static void issue27340CFunc(issue27340Struct *p) {}
|
||||
// #endif /* _GNU_MAJOR_ < 5 */
|
||||
import "C"
|
||||
|
||||
func Issue27340GoFunc() {
|
||||
var s C.issue27340Struct
|
||||
C.issue27340CFunc(C.issue27340Ptr(&s))
|
||||
}
|
||||
83
misc/cgo/test/issue28896.go
Normal file
83
misc/cgo/test/issue28896.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// cgo was incorrectly adding padding after a packed struct.
|
||||
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
void *f1;
|
||||
uint32_t f2;
|
||||
} __attribute__((__packed__)) innerPacked;
|
||||
|
||||
typedef struct {
|
||||
innerPacked g1;
|
||||
uint64_t g2;
|
||||
} outerPacked;
|
||||
|
||||
typedef struct {
|
||||
void *f1;
|
||||
uint32_t f2;
|
||||
} innerUnpacked;
|
||||
|
||||
typedef struct {
|
||||
innerUnpacked g1;
|
||||
uint64_t g2;
|
||||
} outerUnpacked;
|
||||
|
||||
size_t offset(int x) {
|
||||
switch (x) {
|
||||
case 0:
|
||||
return offsetof(innerPacked, f2);
|
||||
case 1:
|
||||
return offsetof(outerPacked, g2);
|
||||
case 2:
|
||||
return offsetof(innerUnpacked, f2);
|
||||
case 3:
|
||||
return offsetof(outerUnpacked, g2);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func offset(i int) uintptr {
|
||||
var pi C.innerPacked
|
||||
var po C.outerPacked
|
||||
var ui C.innerUnpacked
|
||||
var uo C.outerUnpacked
|
||||
switch i {
|
||||
case 0:
|
||||
return unsafe.Offsetof(pi.f2)
|
||||
case 1:
|
||||
return unsafe.Offsetof(po.g2)
|
||||
case 2:
|
||||
return unsafe.Offsetof(ui.f2)
|
||||
case 3:
|
||||
return unsafe.Offsetof(uo.g2)
|
||||
default:
|
||||
panic("can't happen")
|
||||
}
|
||||
}
|
||||
|
||||
func test28896(t *testing.T) {
|
||||
for i := 0; i < 4; i++ {
|
||||
c := uintptr(C.offset(C.int(i)))
|
||||
g := offset(i)
|
||||
if c != g {
|
||||
t.Errorf("%d: C: %d != Go %d", i, c, g)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ func Test(t *testing.T) {
|
||||
// Brittle: the assertion may fail spuriously when the algorithm
|
||||
// changes, but should remain stable otherwise.
|
||||
got := fmt.Sprintf("%T %T", in, opts)
|
||||
want := "issue9026._Ctype_struct___0 *issue9026._Ctype_struct___1"
|
||||
want := "issue9026._Ctype_struct___0 *issue9026._Ctype_struct___0"
|
||||
if got != want {
|
||||
t.Errorf("Non-deterministic type names: got %s, want %s", got, want)
|
||||
}
|
||||
|
||||
54
misc/cgo/test/test27660.go
Normal file
54
misc/cgo/test/test27660.go
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Stress the interaction between the race detector and cgo in an
|
||||
// attempt to reproduce the memory corruption described in #27660.
|
||||
// The bug was very timing sensitive; at the time of writing this
|
||||
// test would only trigger the bug about once out of every five runs.
|
||||
|
||||
package cgotest
|
||||
|
||||
// #include <unistd.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func test27660(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
ints := make([]int, 100)
|
||||
locks := make([]sync.Mutex, 100)
|
||||
// Slowly create threads so that ThreadSanitizer is forced to
|
||||
// frequently resize its SyncClocks.
|
||||
for i := 0; i < 100; i++ {
|
||||
go func() {
|
||||
for ctx.Err() == nil {
|
||||
// Sleep in C for long enough that it is likely that the runtime
|
||||
// will retake this goroutine's currently wired P.
|
||||
C.usleep(1000 /* 1ms */)
|
||||
runtime.Gosched() // avoid starvation (see #28701)
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
// Trigger lots of synchronization and memory reads/writes to
|
||||
// increase the likelihood that the race described in #27660
|
||||
// results in corruption of ThreadSanitizer's internal state
|
||||
// and thus an assertion failure or segfault.
|
||||
for ctx.Err() == nil {
|
||||
j := rand.Intn(100)
|
||||
locks[j].Lock()
|
||||
ints[j]++
|
||||
locks[j].Unlock()
|
||||
}
|
||||
}()
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,11 @@ license that can be found in the LICENSE file.
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!--
|
||||
Add the following polyfill for Microsoft Edge 17/18 support:
|
||||
<script src="https://cdn.jsdelivr.net/npm/text-encoding@0.7.0/lib/encoding.min.js"></script>
|
||||
(see https://caniuse.com/#feat=textencoder)
|
||||
-->
|
||||
<script src="wasm_exec.js"></script>
|
||||
<script>
|
||||
if (!WebAssembly.instantiateStreaming) { // polyfill
|
||||
|
||||
@@ -163,6 +163,10 @@ func (p *Package) Translate(f *File) {
|
||||
// Convert C.ulong to C.unsigned long, etc.
|
||||
cref.Name.C = cname(cref.Name.Go)
|
||||
}
|
||||
|
||||
var conv typeConv
|
||||
conv.Init(p.PtrSize, p.IntSize)
|
||||
|
||||
p.loadDefines(f)
|
||||
p.typedefs = map[string]bool{}
|
||||
p.typedefList = nil
|
||||
@@ -178,7 +182,7 @@ func (p *Package) Translate(f *File) {
|
||||
}
|
||||
needType := p.guessKinds(f)
|
||||
if len(needType) > 0 {
|
||||
p.loadDWARF(f, needType)
|
||||
p.loadDWARF(f, &conv, needType)
|
||||
}
|
||||
|
||||
// In godefs mode we're OK with the typedefs, which
|
||||
@@ -472,7 +476,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||
// loadDWARF parses the DWARF debug information generated
|
||||
// by gcc to learn the details of the constants, variables, and types
|
||||
// being referred to as C.xxx.
|
||||
func (p *Package) loadDWARF(f *File, names []*Name) {
|
||||
func (p *Package) loadDWARF(f *File, conv *typeConv, names []*Name) {
|
||||
// Extract the types from the DWARF section of an object
|
||||
// from a well-formed C program. Gcc only generates DWARF info
|
||||
// for symbols in the object file, so it is not enough to print the
|
||||
@@ -579,8 +583,6 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
||||
}
|
||||
|
||||
// Record types and typedef information.
|
||||
var conv typeConv
|
||||
conv.Init(p.PtrSize, p.IntSize)
|
||||
for i, n := range names {
|
||||
if strings.HasSuffix(n.Go, "GetTypeID") && types[i].String() == "func() CFTypeID" {
|
||||
conv.getTypeIDs[n.Go[:len(n.Go)-9]] = true
|
||||
@@ -1734,10 +1736,10 @@ func runGcc(stdin []byte, args []string) (string, string) {
|
||||
// with equivalent memory layout.
|
||||
type typeConv struct {
|
||||
// Cache of already-translated or in-progress types.
|
||||
m map[dwarf.Type]*Type
|
||||
m map[string]*Type
|
||||
|
||||
// Map from types to incomplete pointers to those types.
|
||||
ptrs map[dwarf.Type][]*Type
|
||||
ptrs map[string][]*Type
|
||||
// Keys of ptrs in insertion order (deterministic worklist)
|
||||
// ptrKeys contains exactly the keys in ptrs.
|
||||
ptrKeys []dwarf.Type
|
||||
@@ -1772,8 +1774,8 @@ var unionWithPointer = make(map[ast.Expr]bool)
|
||||
func (c *typeConv) Init(ptrSize, intSize int64) {
|
||||
c.ptrSize = ptrSize
|
||||
c.intSize = intSize
|
||||
c.m = make(map[dwarf.Type]*Type)
|
||||
c.ptrs = make(map[dwarf.Type][]*Type)
|
||||
c.m = make(map[string]*Type)
|
||||
c.ptrs = make(map[string][]*Type)
|
||||
c.getTypeIDs = make(map[string]bool)
|
||||
c.bool = c.Ident("bool")
|
||||
c.byte = c.Ident("byte")
|
||||
@@ -1881,11 +1883,12 @@ func (c *typeConv) FinishType(pos token.Pos) {
|
||||
// Keep looping until they're all done.
|
||||
for len(c.ptrKeys) > 0 {
|
||||
dtype := c.ptrKeys[0]
|
||||
dtypeKey := dtype.String()
|
||||
c.ptrKeys = c.ptrKeys[1:]
|
||||
ptrs := c.ptrs[dtype]
|
||||
delete(c.ptrs, dtype)
|
||||
ptrs := c.ptrs[dtypeKey]
|
||||
delete(c.ptrs, dtypeKey)
|
||||
|
||||
// Note Type might invalidate c.ptrs[dtype].
|
||||
// Note Type might invalidate c.ptrs[dtypeKey].
|
||||
t := c.Type(dtype, pos)
|
||||
for _, ptr := range ptrs {
|
||||
ptr.Go.(*ast.StarExpr).X = t.Go
|
||||
@@ -1897,18 +1900,29 @@ func (c *typeConv) FinishType(pos token.Pos) {
|
||||
// Type returns a *Type with the same memory layout as
|
||||
// dtype when used as the type of a variable or a struct field.
|
||||
func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||
if t, ok := c.m[dtype]; ok {
|
||||
if t.Go == nil {
|
||||
fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
|
||||
// Always recompute bad pointer typedefs, as the set of such
|
||||
// typedefs changes as we see more types.
|
||||
checkCache := true
|
||||
if dtt, ok := dtype.(*dwarf.TypedefType); ok && c.badPointerTypedef(dtt) {
|
||||
checkCache = false
|
||||
}
|
||||
|
||||
key := dtype.String()
|
||||
|
||||
if checkCache {
|
||||
if t, ok := c.m[key]; ok {
|
||||
if t.Go == nil {
|
||||
fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
|
||||
}
|
||||
return t
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
t := new(Type)
|
||||
t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
|
||||
t.Align = -1
|
||||
t.C = &TypeRepr{Repr: dtype.Common().Name}
|
||||
c.m[dtype] = t
|
||||
c.m[key] = t
|
||||
|
||||
switch dt := dtype.(type) {
|
||||
default:
|
||||
@@ -2071,10 +2085,11 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||
// Placeholder initialization; completed in FinishType.
|
||||
t.Go = &ast.StarExpr{}
|
||||
t.C.Set("<incomplete>*")
|
||||
if _, ok := c.ptrs[dt.Type]; !ok {
|
||||
key := dt.Type.String()
|
||||
if _, ok := c.ptrs[key]; !ok {
|
||||
c.ptrKeys = append(c.ptrKeys, dt.Type)
|
||||
}
|
||||
c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
|
||||
c.ptrs[key] = append(c.ptrs[key], t)
|
||||
|
||||
case *dwarf.QualType:
|
||||
t1 := c.Type(dt.Type, pos)
|
||||
@@ -2462,11 +2477,6 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
|
||||
|
||||
anon := 0
|
||||
for _, f := range dt.Field {
|
||||
if f.ByteOffset > off {
|
||||
fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
|
||||
off = f.ByteOffset
|
||||
}
|
||||
|
||||
name := f.Name
|
||||
ft := f.Type
|
||||
|
||||
@@ -2515,6 +2525,19 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
|
||||
// structs are in system headers that cannot be corrected.
|
||||
continue
|
||||
}
|
||||
|
||||
// Round off up to talign, assumed to be a power of 2.
|
||||
off = (off + talign - 1) &^ (talign - 1)
|
||||
|
||||
if f.ByteOffset > off {
|
||||
fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
|
||||
off = f.ByteOffset
|
||||
}
|
||||
if f.ByteOffset < off {
|
||||
// Drop a packed field that we can't represent.
|
||||
continue
|
||||
}
|
||||
|
||||
n := len(fld)
|
||||
fld = fld[0 : n+1]
|
||||
if name == "" {
|
||||
|
||||
@@ -740,6 +740,12 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
fmt.Fprintf(fgcc, "#include <stdlib.h>\n")
|
||||
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n")
|
||||
|
||||
// We use packed structs, but they are always aligned.
|
||||
// The pragmas and address-of-packed-member are not recognized as warning groups in clang 3.4.1, so ignore unknown pragmas first.
|
||||
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wunknown-pragmas\"\n")
|
||||
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wpragmas\"\n")
|
||||
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Waddress-of-packed-member\"\n")
|
||||
|
||||
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int, __SIZE_TYPE__), void *, int, __SIZE_TYPE__);\n")
|
||||
fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done();\n")
|
||||
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
|
||||
@@ -1340,6 +1346,13 @@ __cgo_size_assert(double, 8)
|
||||
|
||||
extern char* _cgo_topofstack(void);
|
||||
|
||||
/* We use packed structs, but they are always aligned. */
|
||||
/* The pragmas and address-of-packed-member are not recognized as warning groups in clang 3.4.1, so ignore unknown pragmas first. */
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma GCC diagnostic ignored "-Wpragmas"
|
||||
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
`
|
||||
|
||||
@@ -121,6 +121,17 @@ func (n *Node) Int64() int64 {
|
||||
return n.Val().U.(*Mpint).Int64()
|
||||
}
|
||||
|
||||
// CanInt64 reports whether it is safe to call Int64() on n.
|
||||
func (n *Node) CanInt64() bool {
|
||||
if !Isconst(n, CTINT) {
|
||||
return false
|
||||
}
|
||||
|
||||
// if the value inside n cannot be represented as an int64, the
|
||||
// return value of Int64 is undefined
|
||||
return n.Val().U.(*Mpint).CmpInt64(n.Int64()) == 0
|
||||
}
|
||||
|
||||
// Bool returns n as a bool.
|
||||
// n must be a boolean constant.
|
||||
func (n *Node) Bool() bool {
|
||||
|
||||
@@ -481,13 +481,17 @@ func Main(archInit func(*Arch)) {
|
||||
// Phase 1: const, type, and names and types of funcs.
|
||||
// This will gather all the information about types
|
||||
// and methods but doesn't depend on any of it.
|
||||
//
|
||||
// We also defer type alias declarations until phase 2
|
||||
// to avoid cycles like #18640.
|
||||
// TODO(gri) Remove this again once we have a fix for #25838.
|
||||
defercheckwidth()
|
||||
|
||||
// Don't use range--typecheck can add closures to xtop.
|
||||
timings.Start("fe", "typecheck", "top1")
|
||||
for i := 0; i < len(xtop); i++ {
|
||||
n := xtop[i]
|
||||
if op := n.Op; op != ODCL && op != OAS && op != OAS2 {
|
||||
if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
|
||||
xtop[i] = typecheck(n, Etop)
|
||||
}
|
||||
}
|
||||
@@ -499,7 +503,7 @@ func Main(archInit func(*Arch)) {
|
||||
timings.Start("fe", "typecheck", "top2")
|
||||
for i := 0; i < len(xtop); i++ {
|
||||
n := xtop[i]
|
||||
if op := n.Op; op == ODCL || op == OAS || op == OAS2 {
|
||||
if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
|
||||
xtop[i] = typecheck(n, Etop)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3863,6 +3863,18 @@ func (s *state) boundsCheck(idx, len *ssa.Value) {
|
||||
s.check(cmp, panicindex)
|
||||
}
|
||||
|
||||
func couldBeNegative(v *ssa.Value) bool {
|
||||
switch v.Op {
|
||||
case ssa.OpSliceLen, ssa.OpSliceCap, ssa.OpStringLen:
|
||||
return false
|
||||
case ssa.OpConst64:
|
||||
return v.AuxInt < 0
|
||||
case ssa.OpConst32:
|
||||
return int32(v.AuxInt) < 0
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
|
||||
// Starts a new block on return.
|
||||
// idx and len are already converted to full int width.
|
||||
@@ -3870,6 +3882,15 @@ func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
|
||||
if Debug['B'] != 0 {
|
||||
return
|
||||
}
|
||||
if couldBeNegative(len) {
|
||||
// OpIsSliceInBounds requires second arg not negative; if it's not obviously true, must check.
|
||||
cmpop := ssa.OpGeq64
|
||||
if len.Type.Size() == 4 {
|
||||
cmpop = ssa.OpGeq32
|
||||
}
|
||||
cmp := s.newValue2(cmpop, types.Types[TBOOL], len, s.zeroVal(len.Type))
|
||||
s.check(cmp, panicslice)
|
||||
}
|
||||
|
||||
// bounds check
|
||||
cmp := s.newValue2(ssa.OpIsSliceInBounds, types.Types[TBOOL], idx, len)
|
||||
|
||||
@@ -1116,7 +1116,7 @@ func calcHasCall(n *Node) bool {
|
||||
|
||||
// When using soft-float, these ops might be rewritten to function calls
|
||||
// so we ensure they are evaluated first.
|
||||
case OADD, OSUB, OMINUS:
|
||||
case OADD, OSUB, OMINUS, OMUL:
|
||||
if thearch.SoftFloat && (isFloat[n.Type.Etype] || isComplex[n.Type.Etype]) {
|
||||
return true
|
||||
}
|
||||
@@ -1627,8 +1627,9 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
|
||||
return
|
||||
}
|
||||
|
||||
// Only generate I.M wrappers for I in I's own package.
|
||||
if rcvr.IsInterface() && rcvr.Sym != nil && rcvr.Sym.Pkg != localpkg {
|
||||
// Only generate I.M wrappers for I in I's own package
|
||||
// but keep doing it for error.Error (was issue #29304).
|
||||
if rcvr.IsInterface() && rcvr.Sym != nil && rcvr.Sym.Pkg != localpkg && rcvr != types.Errortype {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -202,8 +202,16 @@ func typecheck(n *Node, top int) *Node {
|
||||
// since it would expand indefinitely when aliases
|
||||
// are substituted.
|
||||
cycle := cycleFor(n)
|
||||
for _, n := range cycle {
|
||||
if n.Name != nil && !n.Name.Param.Alias {
|
||||
for _, n1 := range cycle {
|
||||
if n1.Name != nil && !n1.Name.Param.Alias {
|
||||
// Cycle is ok. But if n is an alias type and doesn't
|
||||
// have a type yet, we have a recursive type declaration
|
||||
// with aliases that we can't handle properly yet.
|
||||
// Report an error rather than crashing later.
|
||||
if n.Name != nil && n.Name.Param.Alias && n.Type == nil {
|
||||
lineno = n.Pos
|
||||
Fatalf("cannot handle alias type declaration (issue #25838): %v", n)
|
||||
}
|
||||
lineno = lno
|
||||
return n
|
||||
}
|
||||
@@ -1263,7 +1271,7 @@ func typecheck1(n *Node, top int) *Node {
|
||||
n.Op = OCALLFUNC
|
||||
if t.Etype != TFUNC {
|
||||
name := l.String()
|
||||
if isBuiltinFuncName(name) {
|
||||
if isBuiltinFuncName(name) && l.Name.Defn != nil {
|
||||
// be more specific when the function
|
||||
// name matches a predeclared function
|
||||
yyerror("cannot call non-function %s (type %v), declared at %s",
|
||||
@@ -3987,6 +3995,12 @@ func deadcode(fn *Node) {
|
||||
}
|
||||
|
||||
func deadcodeslice(nn Nodes) {
|
||||
var lastLabel = -1
|
||||
for i, n := range nn.Slice() {
|
||||
if n != nil && n.Op == OLABEL {
|
||||
lastLabel = i
|
||||
}
|
||||
}
|
||||
for i, n := range nn.Slice() {
|
||||
// Cut is set to true when all nodes after i'th position
|
||||
// should be removed.
|
||||
@@ -4009,10 +4023,14 @@ func deadcodeslice(nn Nodes) {
|
||||
// If "then" or "else" branch ends with panic or return statement,
|
||||
// it is safe to remove all statements after this node.
|
||||
// isterminating is not used to avoid goto-related complications.
|
||||
// We must be careful not to deadcode-remove labels, as they
|
||||
// might be the target of a goto. See issue 28616.
|
||||
if body := body.Slice(); len(body) != 0 {
|
||||
switch body[(len(body) - 1)].Op {
|
||||
case ORETURN, ORETJMP, OPANIC:
|
||||
cut = true
|
||||
if i > lastLabel {
|
||||
cut = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3701,6 +3701,12 @@ func walkinrange(n *Node, init *Nodes) *Node {
|
||||
return n
|
||||
}
|
||||
|
||||
// Ensure that Int64() does not overflow on a and c (it'll happen
|
||||
// for any const above 2**63; see issue #27143).
|
||||
if !a.CanInt64() || !c.CanInt64() {
|
||||
return n
|
||||
}
|
||||
|
||||
if opl == OLT {
|
||||
// We have a < b && ...
|
||||
// We need a ≤ b && ... to safely use unsigned comparison tricks.
|
||||
|
||||
@@ -197,7 +197,8 @@ func elimDeadAutosGeneric(f *Func) {
|
||||
panic("unhandled op with sym effect")
|
||||
}
|
||||
|
||||
if v.Uses == 0 || len(args) == 0 {
|
||||
if v.Uses == 0 && v.Op != OpNilCheck || len(args) == 0 {
|
||||
// Nil check has no use, but we need to keep it.
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -670,8 +670,8 @@
|
||||
(SGTUconst [c] (MOVHUreg _)) && 0xffff < uint32(c) -> (MOVWconst [1])
|
||||
(SGTconst [c] (ANDconst [m] _)) && 0 <= int32(m) && int32(m) < int32(c) -> (MOVWconst [1])
|
||||
(SGTUconst [c] (ANDconst [m] _)) && uint32(m) < uint32(c) -> (MOVWconst [1])
|
||||
(SGTconst [c] (SRLconst _ [d])) && 0 <= int32(c) && uint32(d) <= 31 && 1<<(32-uint32(d)) <= int32(c) -> (MOVWconst [1])
|
||||
(SGTUconst [c] (SRLconst _ [d])) && uint32(d) <= 31 && 1<<(32-uint32(d)) <= uint32(c) -> (MOVWconst [1])
|
||||
(SGTconst [c] (SRLconst _ [d])) && 0 <= int32(c) && uint32(d) <= 31 && 0xffffffff>>uint32(d) < uint32(c) -> (MOVWconst [1])
|
||||
(SGTUconst [c] (SRLconst _ [d])) && uint32(d) <= 31 && 0xffffffff>>uint32(d) < uint32(c) -> (MOVWconst [1])
|
||||
|
||||
// absorb constants into branches
|
||||
(EQ (MOVWconst [0]) yes no) -> (First nil yes no)
|
||||
|
||||
@@ -667,8 +667,8 @@
|
||||
(SGTconst [c] (MOVWUreg _)) && c < 0 -> (MOVVconst [0])
|
||||
(SGTconst [c] (ANDconst [m] _)) && 0 <= m && m < c -> (MOVVconst [1])
|
||||
(SGTUconst [c] (ANDconst [m] _)) && uint64(m) < uint64(c) -> (MOVVconst [1])
|
||||
(SGTconst [c] (SRLVconst _ [d])) && 0 <= c && 0 < d && d <= 63 && 1<<uint64(64-d) <= c -> (MOVVconst [1])
|
||||
(SGTUconst [c] (SRLVconst _ [d])) && 0 < d && d <= 63 && 1<<uint64(64-d) <= uint64(c) -> (MOVVconst [1])
|
||||
(SGTconst [c] (SRLVconst _ [d])) && 0 <= c && 0 < d && d <= 63 && 0xffffffffffffffff>>uint64(d) < uint64(c) -> (MOVVconst [1])
|
||||
(SGTUconst [c] (SRLVconst _ [d])) && 0 < d && d <= 63 && 0xffffffffffffffff>>uint64(d) < uint64(c) -> (MOVVconst [1])
|
||||
|
||||
// absorb constants into branches
|
||||
(EQ (MOVVconst [0]) yes no) -> (First nil yes no)
|
||||
|
||||
@@ -1539,8 +1539,8 @@
|
||||
// Don't Move from memory if the values are likely to already be
|
||||
// in registers.
|
||||
(Move {t1} [n] dst p1
|
||||
mem:(Store {t2} op2:(OffPtr [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr [0] p3) d2 _)))
|
||||
mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr <tt3> [0] p3) d2 _)))
|
||||
&& isSamePtr(p1, p2) && isSamePtr(p2, p3)
|
||||
&& alignof(t2) <= alignof(t1)
|
||||
&& alignof(t3) <= alignof(t1)
|
||||
@@ -1548,12 +1548,12 @@
|
||||
&& registerizable(b, t3)
|
||||
&& o2 == sizeof(t3)
|
||||
&& n == sizeof(t2) + sizeof(t3)
|
||||
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <t3.(*types.Type)> [0] dst) d2 mem))
|
||||
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <tt3> [0] dst) d2 mem))
|
||||
(Move {t1} [n] dst p1
|
||||
mem:(Store {t2} op2:(OffPtr [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr [0] p4) d3 _))))
|
||||
mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr <tt3> [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr <tt4> [0] p4) d3 _))))
|
||||
&& isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4)
|
||||
&& alignof(t2) <= alignof(t1)
|
||||
&& alignof(t3) <= alignof(t1)
|
||||
@@ -1564,14 +1564,14 @@
|
||||
&& o3 == sizeof(t4)
|
||||
&& o2-o3 == sizeof(t3)
|
||||
&& n == sizeof(t2) + sizeof(t3) + sizeof(t4)
|
||||
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <t4.(*types.Type)> [0] dst) d3 mem)))
|
||||
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <tt3> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <tt4> [0] dst) d3 mem)))
|
||||
(Move {t1} [n] dst p1
|
||||
mem:(Store {t2} op2:(OffPtr [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr [o4] p4) d3
|
||||
(Store {t5} op5:(OffPtr [0] p5) d4 _)))))
|
||||
mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr <tt3> [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr <tt4> [o4] p4) d3
|
||||
(Store {t5} op5:(OffPtr <tt5> [0] p5) d4 _)))))
|
||||
&& isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && isSamePtr(p4, p5)
|
||||
&& alignof(t2) <= alignof(t1)
|
||||
&& alignof(t3) <= alignof(t1)
|
||||
@@ -1585,16 +1585,16 @@
|
||||
&& o3-o4 == sizeof(t4)
|
||||
&& o2-o3 == sizeof(t3)
|
||||
&& n == sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5)
|
||||
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <t4.(*types.Type)> [o4] dst) d3
|
||||
(Store {t5} (OffPtr <t5.(*types.Type)> [0] dst) d4 mem))))
|
||||
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <tt3> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <tt4> [o4] dst) d3
|
||||
(Store {t5} (OffPtr <tt5> [0] dst) d4 mem))))
|
||||
|
||||
// Same thing but with VarDef in the middle.
|
||||
(Move {t1} [n] dst p1
|
||||
mem:(VarDef
|
||||
(Store {t2} op2:(OffPtr [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr [0] p3) d2 _))))
|
||||
(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr <tt3> [0] p3) d2 _))))
|
||||
&& isSamePtr(p1, p2) && isSamePtr(p2, p3)
|
||||
&& alignof(t2) <= alignof(t1)
|
||||
&& alignof(t3) <= alignof(t1)
|
||||
@@ -1602,13 +1602,13 @@
|
||||
&& registerizable(b, t3)
|
||||
&& o2 == sizeof(t3)
|
||||
&& n == sizeof(t2) + sizeof(t3)
|
||||
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <t3.(*types.Type)> [0] dst) d2 mem))
|
||||
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <tt3> [0] dst) d2 mem))
|
||||
(Move {t1} [n] dst p1
|
||||
mem:(VarDef
|
||||
(Store {t2} op2:(OffPtr [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr [0] p4) d3 _)))))
|
||||
(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr <tt3> [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr <tt4> [0] p4) d3 _)))))
|
||||
&& isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4)
|
||||
&& alignof(t2) <= alignof(t1)
|
||||
&& alignof(t3) <= alignof(t1)
|
||||
@@ -1619,15 +1619,15 @@
|
||||
&& o3 == sizeof(t4)
|
||||
&& o2-o3 == sizeof(t3)
|
||||
&& n == sizeof(t2) + sizeof(t3) + sizeof(t4)
|
||||
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <t4.(*types.Type)> [0] dst) d3 mem)))
|
||||
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <tt3> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <tt4> [0] dst) d3 mem)))
|
||||
(Move {t1} [n] dst p1
|
||||
mem:(VarDef
|
||||
(Store {t2} op2:(OffPtr [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr [o4] p4) d3
|
||||
(Store {t5} op5:(OffPtr [0] p5) d4 _))))))
|
||||
(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr <tt3> [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr <tt4> [o4] p4) d3
|
||||
(Store {t5} op5:(OffPtr <tt5> [0] p5) d4 _))))))
|
||||
&& isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && isSamePtr(p4, p5)
|
||||
&& alignof(t2) <= alignof(t1)
|
||||
&& alignof(t3) <= alignof(t1)
|
||||
@@ -1641,10 +1641,10 @@
|
||||
&& o3-o4 == sizeof(t4)
|
||||
&& o2-o3 == sizeof(t3)
|
||||
&& n == sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5)
|
||||
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <t4.(*types.Type)> [o4] dst) d3
|
||||
(Store {t5} (OffPtr <t5.(*types.Type)> [0] dst) d4 mem))))
|
||||
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <tt3> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <tt4> [o4] dst) d3
|
||||
(Store {t5} (OffPtr <tt5> [0] dst) d4 mem))))
|
||||
|
||||
// Prefer to Zero and Store than to Move.
|
||||
(Move {t1} [n] dst p1
|
||||
|
||||
@@ -197,6 +197,9 @@ func newFactsTable(f *Func) *factsTable {
|
||||
// update updates the set of relations between v and w in domain d
|
||||
// restricting it to r.
|
||||
func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
|
||||
if parent.Func.pass.debug > 2 {
|
||||
parent.Func.Warnl(parent.Pos, "parent=%s, update %s %s %s", parent, v, w, r)
|
||||
}
|
||||
// No need to do anything else if we already found unsat.
|
||||
if ft.unsat {
|
||||
return
|
||||
@@ -234,6 +237,9 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
|
||||
panic("unknown relation")
|
||||
}
|
||||
if !ok {
|
||||
if parent.Func.pass.debug > 2 {
|
||||
parent.Func.Warnl(parent.Pos, "unsat %s %s %s", v, w, r)
|
||||
}
|
||||
ft.unsat = true
|
||||
return
|
||||
}
|
||||
@@ -260,6 +266,9 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
|
||||
ft.facts[p] = oldR & r
|
||||
// If this relation is not satisfiable, mark it and exit right away
|
||||
if oldR&r == 0 {
|
||||
if parent.Func.pass.debug > 2 {
|
||||
parent.Func.Warnl(parent.Pos, "unsat %s %s %s", v, w, r)
|
||||
}
|
||||
ft.unsat = true
|
||||
return
|
||||
}
|
||||
@@ -361,7 +370,7 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
|
||||
lim = old.intersect(lim)
|
||||
ft.limits[v.ID] = lim
|
||||
if v.Block.Func.pass.debug > 2 {
|
||||
v.Block.Func.Warnl(parent.Pos, "parent=%s, new limits %s %s %s", parent, v, w, lim.String())
|
||||
v.Block.Func.Warnl(parent.Pos, "parent=%s, new limits %s %s %s %s", parent, v, w, r, lim.String())
|
||||
}
|
||||
if lim.min > lim.max || lim.umin > lim.umax {
|
||||
ft.unsat = true
|
||||
@@ -425,13 +434,13 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
|
||||
//
|
||||
// Useful for i > 0; s[i-1].
|
||||
lim, ok := ft.limits[x.ID]
|
||||
if ok && lim.min > opMin[v.Op] {
|
||||
if ok && ((d == signed && lim.min > opMin[v.Op]) || (d == unsigned && lim.umin > 0)) {
|
||||
ft.update(parent, x, w, d, gt)
|
||||
}
|
||||
} else if x, delta := isConstDelta(w); x != nil && delta == 1 {
|
||||
// v >= x+1 && x < max ⇒ v > x
|
||||
lim, ok := ft.limits[x.ID]
|
||||
if ok && lim.max < opMax[w.Op] {
|
||||
if ok && ((d == signed && lim.max < opMax[w.Op]) || (d == unsigned && lim.umax < opUMax[w.Op])) {
|
||||
ft.update(parent, v, x, d, gt)
|
||||
}
|
||||
}
|
||||
@@ -442,7 +451,7 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
|
||||
if r == gt || r == gt|eq {
|
||||
if x, delta := isConstDelta(v); x != nil && d == signed {
|
||||
if parent.Func.pass.debug > 1 {
|
||||
parent.Func.Warnl(parent.Pos, "x+d >= w; x:%v %v delta:%v w:%v d:%v", x, parent.String(), delta, w.AuxInt, d)
|
||||
parent.Func.Warnl(parent.Pos, "x+d %s w; x:%v %v delta:%v w:%v d:%v", r, x, parent.String(), delta, w.AuxInt, d)
|
||||
}
|
||||
if !w.isGenericIntConst() {
|
||||
// If we know that x+delta > w but w is not constant, we can derive:
|
||||
@@ -503,8 +512,10 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
|
||||
// the other must be true
|
||||
if l, has := ft.limits[x.ID]; has {
|
||||
if l.max <= min {
|
||||
// x>min is impossible, so it must be x<=max
|
||||
ft.update(parent, vmax, x, d, r|eq)
|
||||
if r&eq == 0 || l.max < min {
|
||||
// x>min (x>=min) is impossible, so it must be x<=max
|
||||
ft.update(parent, vmax, x, d, r|eq)
|
||||
}
|
||||
} else if l.min > max {
|
||||
// x<=max is impossible, so it must be x>min
|
||||
ft.update(parent, x, vmin, d, r)
|
||||
@@ -527,6 +538,11 @@ var opMax = map[Op]int64{
|
||||
OpAdd32: math.MaxInt32, OpSub32: math.MaxInt32,
|
||||
}
|
||||
|
||||
var opUMax = map[Op]uint64{
|
||||
OpAdd64: math.MaxUint64, OpSub64: math.MaxUint64,
|
||||
OpAdd32: math.MaxUint32, OpSub32: math.MaxUint32,
|
||||
}
|
||||
|
||||
// isNonNegative reports whether v is known to be non-negative.
|
||||
func (ft *factsTable) isNonNegative(v *Value) bool {
|
||||
if isNonNegative(v) {
|
||||
|
||||
@@ -5623,7 +5623,7 @@ func rewriteValueMIPS_OpMIPSSGTUconst_0(v *Value) bool {
|
||||
return true
|
||||
}
|
||||
// match: (SGTUconst [c] (SRLconst _ [d]))
|
||||
// cond: uint32(d) <= 31 && 1<<(32-uint32(d)) <= uint32(c)
|
||||
// cond: uint32(d) <= 31 && 0xffffffff>>uint32(d) < uint32(c)
|
||||
// result: (MOVWconst [1])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
@@ -5632,7 +5632,7 @@ func rewriteValueMIPS_OpMIPSSGTUconst_0(v *Value) bool {
|
||||
break
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
if !(uint32(d) <= 31 && 1<<(32-uint32(d)) <= uint32(c)) {
|
||||
if !(uint32(d) <= 31 && 0xffffffff>>uint32(d) < uint32(c)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpMIPSMOVWconst)
|
||||
@@ -5860,7 +5860,7 @@ func rewriteValueMIPS_OpMIPSSGTconst_10(v *Value) bool {
|
||||
return true
|
||||
}
|
||||
// match: (SGTconst [c] (SRLconst _ [d]))
|
||||
// cond: 0 <= int32(c) && uint32(d) <= 31 && 1<<(32-uint32(d)) <= int32(c)
|
||||
// cond: 0 <= int32(c) && uint32(d) <= 31 && 0xffffffff>>uint32(d) < uint32(c)
|
||||
// result: (MOVWconst [1])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
@@ -5869,7 +5869,7 @@ func rewriteValueMIPS_OpMIPSSGTconst_10(v *Value) bool {
|
||||
break
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
if !(0 <= int32(c) && uint32(d) <= 31 && 1<<(32-uint32(d)) <= int32(c)) {
|
||||
if !(0 <= int32(c) && uint32(d) <= 31 && 0xffffffff>>uint32(d) < uint32(c)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpMIPSMOVWconst)
|
||||
|
||||
@@ -6003,7 +6003,7 @@ func rewriteValueMIPS64_OpMIPS64SGTUconst_0(v *Value) bool {
|
||||
return true
|
||||
}
|
||||
// match: (SGTUconst [c] (SRLVconst _ [d]))
|
||||
// cond: 0 < d && d <= 63 && 1<<uint64(64-d) <= uint64(c)
|
||||
// cond: 0 < d && d <= 63 && 0xffffffffffffffff>>uint64(d) < uint64(c)
|
||||
// result: (MOVVconst [1])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
@@ -6012,7 +6012,7 @@ func rewriteValueMIPS64_OpMIPS64SGTUconst_0(v *Value) bool {
|
||||
break
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
if !(0 < d && d <= 63 && 1<<uint64(64-d) <= uint64(c)) {
|
||||
if !(0 < d && d <= 63 && 0xffffffffffffffff>>uint64(d) < uint64(c)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpMIPS64MOVVconst)
|
||||
@@ -6221,7 +6221,7 @@ func rewriteValueMIPS64_OpMIPS64SGTconst_10(v *Value) bool {
|
||||
return true
|
||||
}
|
||||
// match: (SGTconst [c] (SRLVconst _ [d]))
|
||||
// cond: 0 <= c && 0 < d && d <= 63 && 1<<uint64(64-d) <= c
|
||||
// cond: 0 <= c && 0 < d && d <= 63 && 0xffffffffffffffff>>uint64(d) < uint64(c)
|
||||
// result: (MOVVconst [1])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
@@ -6230,7 +6230,7 @@ func rewriteValueMIPS64_OpMIPS64SGTconst_10(v *Value) bool {
|
||||
break
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
if !(0 <= c && 0 < d && d <= 63 && 1<<uint64(64-d) <= c) {
|
||||
if !(0 <= c && 0 < d && d <= 63 && 0xffffffffffffffff>>uint64(d) < uint64(c)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpMIPS64MOVVconst)
|
||||
|
||||
@@ -16223,9 +16223,9 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [0] p3) d2 _)))
|
||||
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [0] p3) d2 _)))
|
||||
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && o2 == sizeof(t3) && n == sizeof(t2) + sizeof(t3)
|
||||
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [0] dst) d2 mem))
|
||||
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [0] dst) d2 mem))
|
||||
for {
|
||||
n := v.AuxInt
|
||||
t1 := v.Aux
|
||||
@@ -16242,6 +16242,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
if op2.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt2 := op2.Type
|
||||
o2 := op2.AuxInt
|
||||
p2 := op2.Args[0]
|
||||
d1 := mem.Args[1]
|
||||
@@ -16255,6 +16256,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
if op3.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt3 := op3.Type
|
||||
if op3.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
@@ -16265,14 +16267,14 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
}
|
||||
v.reset(OpStore)
|
||||
v.Aux = t2
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
|
||||
v0.AuxInt = o2
|
||||
v0.AddArg(dst)
|
||||
v.AddArg(v0)
|
||||
v.AddArg(d1)
|
||||
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v1.Aux = t3
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
|
||||
v2.AuxInt = 0
|
||||
v2.AddArg(dst)
|
||||
v1.AddArg(v2)
|
||||
@@ -16281,9 +16283,9 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
v.AddArg(v1)
|
||||
return true
|
||||
}
|
||||
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [o3] p3) d2 (Store {t4} op4:(OffPtr [0] p4) d3 _))))
|
||||
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [o3] p3) d2 (Store {t4} op4:(OffPtr <tt4> [0] p4) d3 _))))
|
||||
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && alignof(t4) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && registerizable(b, t4) && o3 == sizeof(t4) && o2-o3 == sizeof(t3) && n == sizeof(t2) + sizeof(t3) + sizeof(t4)
|
||||
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2 (Store {t4} (OffPtr <t4.(*types.Type)> [0] dst) d3 mem)))
|
||||
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [0] dst) d3 mem)))
|
||||
for {
|
||||
n := v.AuxInt
|
||||
t1 := v.Aux
|
||||
@@ -16300,6 +16302,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
if op2.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt2 := op2.Type
|
||||
o2 := op2.AuxInt
|
||||
p2 := op2.Args[0]
|
||||
d1 := mem.Args[1]
|
||||
@@ -16313,6 +16316,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
if op3.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt3 := op3.Type
|
||||
o3 := op3.AuxInt
|
||||
p3 := op3.Args[0]
|
||||
d2 := mem_2.Args[1]
|
||||
@@ -16326,6 +16330,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
if op4.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt4 := op4.Type
|
||||
if op4.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
@@ -16336,21 +16341,21 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
}
|
||||
v.reset(OpStore)
|
||||
v.Aux = t2
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
|
||||
v0.AuxInt = o2
|
||||
v0.AddArg(dst)
|
||||
v.AddArg(v0)
|
||||
v.AddArg(d1)
|
||||
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v1.Aux = t3
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
|
||||
v2.AuxInt = o3
|
||||
v2.AddArg(dst)
|
||||
v1.AddArg(v2)
|
||||
v1.AddArg(d2)
|
||||
v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v3.Aux = t4
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, t4.(*types.Type))
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, tt4)
|
||||
v4.AuxInt = 0
|
||||
v4.AddArg(dst)
|
||||
v3.AddArg(v4)
|
||||
@@ -16360,9 +16365,9 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
v.AddArg(v1)
|
||||
return true
|
||||
}
|
||||
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [o3] p3) d2 (Store {t4} op4:(OffPtr [o4] p4) d3 (Store {t5} op5:(OffPtr [0] p5) d4 _)))))
|
||||
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [o3] p3) d2 (Store {t4} op4:(OffPtr <tt4> [o4] p4) d3 (Store {t5} op5:(OffPtr <tt5> [0] p5) d4 _)))))
|
||||
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && isSamePtr(p4, p5) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && alignof(t4) <= alignof(t1) && alignof(t5) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && registerizable(b, t4) && registerizable(b, t5) && o4 == sizeof(t5) && o3-o4 == sizeof(t4) && o2-o3 == sizeof(t3) && n == sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5)
|
||||
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2 (Store {t4} (OffPtr <t4.(*types.Type)> [o4] dst) d3 (Store {t5} (OffPtr <t5.(*types.Type)> [0] dst) d4 mem))))
|
||||
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [o4] dst) d3 (Store {t5} (OffPtr <tt5> [0] dst) d4 mem))))
|
||||
for {
|
||||
n := v.AuxInt
|
||||
t1 := v.Aux
|
||||
@@ -16379,6 +16384,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
if op2.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt2 := op2.Type
|
||||
o2 := op2.AuxInt
|
||||
p2 := op2.Args[0]
|
||||
d1 := mem.Args[1]
|
||||
@@ -16392,6 +16398,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
if op3.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt3 := op3.Type
|
||||
o3 := op3.AuxInt
|
||||
p3 := op3.Args[0]
|
||||
d2 := mem_2.Args[1]
|
||||
@@ -16405,6 +16412,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
if op4.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt4 := op4.Type
|
||||
o4 := op4.AuxInt
|
||||
p4 := op4.Args[0]
|
||||
d3 := mem_2_2.Args[1]
|
||||
@@ -16418,6 +16426,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
if op5.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt5 := op5.Type
|
||||
if op5.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
@@ -16428,28 +16437,28 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
}
|
||||
v.reset(OpStore)
|
||||
v.Aux = t2
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
|
||||
v0.AuxInt = o2
|
||||
v0.AddArg(dst)
|
||||
v.AddArg(v0)
|
||||
v.AddArg(d1)
|
||||
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v1.Aux = t3
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
|
||||
v2.AuxInt = o3
|
||||
v2.AddArg(dst)
|
||||
v1.AddArg(v2)
|
||||
v1.AddArg(d2)
|
||||
v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v3.Aux = t4
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, t4.(*types.Type))
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, tt4)
|
||||
v4.AuxInt = o4
|
||||
v4.AddArg(dst)
|
||||
v3.AddArg(v4)
|
||||
v3.AddArg(d3)
|
||||
v5 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v5.Aux = t5
|
||||
v6 := b.NewValue0(v.Pos, OpOffPtr, t5.(*types.Type))
|
||||
v6 := b.NewValue0(v.Pos, OpOffPtr, tt5)
|
||||
v6.AuxInt = 0
|
||||
v6.AddArg(dst)
|
||||
v5.AddArg(v6)
|
||||
@@ -16465,9 +16474,9 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
||||
func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [0] p3) d2 _))))
|
||||
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [0] p3) d2 _))))
|
||||
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && o2 == sizeof(t3) && n == sizeof(t2) + sizeof(t3)
|
||||
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [0] dst) d2 mem))
|
||||
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [0] dst) d2 mem))
|
||||
for {
|
||||
n := v.AuxInt
|
||||
t1 := v.Aux
|
||||
@@ -16488,6 +16497,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
if op2.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt2 := op2.Type
|
||||
o2 := op2.AuxInt
|
||||
p2 := op2.Args[0]
|
||||
d1 := mem_0.Args[1]
|
||||
@@ -16501,6 +16511,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
if op3.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt3 := op3.Type
|
||||
if op3.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
@@ -16511,14 +16522,14 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
}
|
||||
v.reset(OpStore)
|
||||
v.Aux = t2
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
|
||||
v0.AuxInt = o2
|
||||
v0.AddArg(dst)
|
||||
v.AddArg(v0)
|
||||
v.AddArg(d1)
|
||||
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v1.Aux = t3
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
|
||||
v2.AuxInt = 0
|
||||
v2.AddArg(dst)
|
||||
v1.AddArg(v2)
|
||||
@@ -16527,9 +16538,9 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
v.AddArg(v1)
|
||||
return true
|
||||
}
|
||||
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [o3] p3) d2 (Store {t4} op4:(OffPtr [0] p4) d3 _)))))
|
||||
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [o3] p3) d2 (Store {t4} op4:(OffPtr <tt4> [0] p4) d3 _)))))
|
||||
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && alignof(t4) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && registerizable(b, t4) && o3 == sizeof(t4) && o2-o3 == sizeof(t3) && n == sizeof(t2) + sizeof(t3) + sizeof(t4)
|
||||
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2 (Store {t4} (OffPtr <t4.(*types.Type)> [0] dst) d3 mem)))
|
||||
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [0] dst) d3 mem)))
|
||||
for {
|
||||
n := v.AuxInt
|
||||
t1 := v.Aux
|
||||
@@ -16550,6 +16561,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
if op2.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt2 := op2.Type
|
||||
o2 := op2.AuxInt
|
||||
p2 := op2.Args[0]
|
||||
d1 := mem_0.Args[1]
|
||||
@@ -16563,6 +16575,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
if op3.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt3 := op3.Type
|
||||
o3 := op3.AuxInt
|
||||
p3 := op3.Args[0]
|
||||
d2 := mem_0_2.Args[1]
|
||||
@@ -16576,6 +16589,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
if op4.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt4 := op4.Type
|
||||
if op4.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
@@ -16586,21 +16600,21 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
}
|
||||
v.reset(OpStore)
|
||||
v.Aux = t2
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
|
||||
v0.AuxInt = o2
|
||||
v0.AddArg(dst)
|
||||
v.AddArg(v0)
|
||||
v.AddArg(d1)
|
||||
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v1.Aux = t3
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
|
||||
v2.AuxInt = o3
|
||||
v2.AddArg(dst)
|
||||
v1.AddArg(v2)
|
||||
v1.AddArg(d2)
|
||||
v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v3.Aux = t4
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, t4.(*types.Type))
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, tt4)
|
||||
v4.AuxInt = 0
|
||||
v4.AddArg(dst)
|
||||
v3.AddArg(v4)
|
||||
@@ -16610,9 +16624,9 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
v.AddArg(v1)
|
||||
return true
|
||||
}
|
||||
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [o3] p3) d2 (Store {t4} op4:(OffPtr [o4] p4) d3 (Store {t5} op5:(OffPtr [0] p5) d4 _))))))
|
||||
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [o3] p3) d2 (Store {t4} op4:(OffPtr <tt4> [o4] p4) d3 (Store {t5} op5:(OffPtr <tt5> [0] p5) d4 _))))))
|
||||
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && isSamePtr(p4, p5) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && alignof(t4) <= alignof(t1) && alignof(t5) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && registerizable(b, t4) && registerizable(b, t5) && o4 == sizeof(t5) && o3-o4 == sizeof(t4) && o2-o3 == sizeof(t3) && n == sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5)
|
||||
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2 (Store {t4} (OffPtr <t4.(*types.Type)> [o4] dst) d3 (Store {t5} (OffPtr <t5.(*types.Type)> [0] dst) d4 mem))))
|
||||
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [o4] dst) d3 (Store {t5} (OffPtr <tt5> [0] dst) d4 mem))))
|
||||
for {
|
||||
n := v.AuxInt
|
||||
t1 := v.Aux
|
||||
@@ -16633,6 +16647,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
if op2.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt2 := op2.Type
|
||||
o2 := op2.AuxInt
|
||||
p2 := op2.Args[0]
|
||||
d1 := mem_0.Args[1]
|
||||
@@ -16646,6 +16661,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
if op3.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt3 := op3.Type
|
||||
o3 := op3.AuxInt
|
||||
p3 := op3.Args[0]
|
||||
d2 := mem_0_2.Args[1]
|
||||
@@ -16659,6 +16675,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
if op4.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt4 := op4.Type
|
||||
o4 := op4.AuxInt
|
||||
p4 := op4.Args[0]
|
||||
d3 := mem_0_2_2.Args[1]
|
||||
@@ -16672,6 +16689,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
if op5.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt5 := op5.Type
|
||||
if op5.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
@@ -16682,28 +16700,28 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
}
|
||||
v.reset(OpStore)
|
||||
v.Aux = t2
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
|
||||
v0.AuxInt = o2
|
||||
v0.AddArg(dst)
|
||||
v.AddArg(v0)
|
||||
v.AddArg(d1)
|
||||
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v1.Aux = t3
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
|
||||
v2.AuxInt = o3
|
||||
v2.AddArg(dst)
|
||||
v1.AddArg(v2)
|
||||
v1.AddArg(d2)
|
||||
v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v3.Aux = t4
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, t4.(*types.Type))
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, tt4)
|
||||
v4.AuxInt = o4
|
||||
v4.AddArg(dst)
|
||||
v3.AddArg(v4)
|
||||
v3.AddArg(d3)
|
||||
v5 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v5.Aux = t5
|
||||
v6 := b.NewValue0(v.Pos, OpOffPtr, t5.(*types.Type))
|
||||
v6 := b.NewValue0(v.Pos, OpOffPtr, tt5)
|
||||
v6.AuxInt = 0
|
||||
v6.AddArg(dst)
|
||||
v5.AddArg(v6)
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
|
||||
package ssa
|
||||
|
||||
import "math"
|
||||
import (
|
||||
"cmd/compile/internal/types"
|
||||
"math"
|
||||
)
|
||||
|
||||
func softfloat(f *Func) {
|
||||
if !f.Config.SoftFloat {
|
||||
@@ -53,6 +56,15 @@ func softfloat(f *Func) {
|
||||
v.Type = f.Config.Types.UInt64
|
||||
}
|
||||
newInt64 = newInt64 || v.Type.Size() == 8
|
||||
} else if (v.Op == OpStore || v.Op == OpZero || v.Op == OpMove) && v.Aux.(*types.Type).IsFloat() {
|
||||
switch size := v.Aux.(*types.Type).Size(); size {
|
||||
case 4:
|
||||
v.Aux = f.Config.Types.UInt32
|
||||
case 8:
|
||||
v.Aux = f.Config.Types.UInt64
|
||||
default:
|
||||
v.Fatalf("bad float type with size %d", size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -817,7 +817,7 @@ func (t *Type) ChanArgs() *Type {
|
||||
return t.Extra.(ChanArgs).T
|
||||
}
|
||||
|
||||
// FuncArgs returns the channel type for TFUNCARGS type t.
|
||||
// FuncArgs returns the func type for TFUNCARGS type t.
|
||||
func (t *Type) FuncArgs() *Type {
|
||||
t.wantEtype(TFUNCARGS)
|
||||
return t.Extra.(FuncArgs).T
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
// link against shared libraries previously created with
|
||||
// -buildmode=shared.
|
||||
// -mod mode
|
||||
// module download mode to use: readonly, release, or vendor.
|
||||
// module download mode to use: readonly or vendor.
|
||||
// See 'go help modules' for more.
|
||||
// -pkgdir dir
|
||||
// install and load all packages from dir instead of the usual locations.
|
||||
@@ -889,7 +889,7 @@
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// go mod download [-dir] [-json] [modules]
|
||||
// go mod download [-json] [modules]
|
||||
//
|
||||
// Download downloads the named modules, which can be module patterns selecting
|
||||
// dependencies of the main module or module queries of the form path@version.
|
||||
@@ -905,13 +905,15 @@
|
||||
// corresponding to this Go struct:
|
||||
//
|
||||
// type Module struct {
|
||||
// Path string // module path
|
||||
// Version string // module version
|
||||
// Error string // error loading module
|
||||
// Info string // absolute path to cached .info file
|
||||
// GoMod string // absolute path to cached .mod file
|
||||
// Zip string // absolute path to cached .zip file
|
||||
// Dir string // absolute path to cached source root directory
|
||||
// Path string // module path
|
||||
// Version string // module version
|
||||
// Error string // error loading module
|
||||
// Info string // absolute path to cached .info file
|
||||
// GoMod string // absolute path to cached .mod file
|
||||
// Zip string // absolute path to cached .zip file
|
||||
// Dir string // absolute path to cached source root directory
|
||||
// Sum string // checksum for path, version (as in go.sum)
|
||||
// GoModSum string // checksum for go.mod (as in go.sum)
|
||||
// }
|
||||
//
|
||||
// See 'go help modules' for more about module queries.
|
||||
@@ -1447,6 +1449,12 @@
|
||||
// The directory where the go command will write
|
||||
// temporary source files, packages, and binaries.
|
||||
//
|
||||
// Each entry in the GOFLAGS list must be a standalone flag.
|
||||
// Because the entries are space-separated, flag values must
|
||||
// not contain spaces. In some cases, you can provide multiple flag
|
||||
// values instead: for example, to set '-ldflags=-s -w'
|
||||
// you can use 'GOFLAGS=-ldflags=-s -ldflags=-w'.
|
||||
//
|
||||
// Environment variables for use with cgo:
|
||||
//
|
||||
// CC
|
||||
@@ -1614,7 +1622,19 @@
|
||||
//
|
||||
// The go command automatically updates go.mod each time it uses the
|
||||
// module graph, to make sure go.mod always accurately reflects reality
|
||||
// and is properly formatted.
|
||||
// and is properly formatted. For example, consider this go.mod file:
|
||||
//
|
||||
// module M
|
||||
//
|
||||
// require (
|
||||
// A v1
|
||||
// B v1.0.0
|
||||
// C v1.0.0
|
||||
// D v1.2.3
|
||||
// E dev
|
||||
// )
|
||||
//
|
||||
// exclude D v1.2.3
|
||||
//
|
||||
// The update rewrites non-canonical version identifiers to semver form,
|
||||
// so A's v1 becomes v1.0.0 and E's dev becomes the pseudo-version for the
|
||||
|
||||
@@ -232,7 +232,7 @@ var downloadCache = map[string]bool{}
|
||||
var downloadRootCache = map[string]bool{}
|
||||
|
||||
// download runs the download half of the get command
|
||||
// for the package named by the argument.
|
||||
// for the package or pattern named by the argument.
|
||||
func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
|
||||
if mode&load.ResolveImport != 0 {
|
||||
// Caller is responsible for expanding vendor paths.
|
||||
@@ -402,6 +402,23 @@ func downloadPackage(p *load.Package) error {
|
||||
security = web.Insecure
|
||||
}
|
||||
|
||||
// p can be either a real package, or a pseudo-package whose “import path” is
|
||||
// actually a wildcard pattern.
|
||||
// Trim the path at the element containing the first wildcard,
|
||||
// and hope that it applies to the wildcarded parts too.
|
||||
// This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
|
||||
importPrefix := p.ImportPath
|
||||
if i := strings.Index(importPrefix, "..."); i >= 0 {
|
||||
slash := strings.LastIndexByte(importPrefix[:i], '/')
|
||||
if slash < 0 {
|
||||
return fmt.Errorf("cannot expand ... in %q", p.ImportPath)
|
||||
}
|
||||
importPrefix = importPrefix[:slash]
|
||||
}
|
||||
if err := CheckImportPath(importPrefix); err != nil {
|
||||
return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err)
|
||||
}
|
||||
|
||||
if p.Internal.Build.SrcRoot != "" {
|
||||
// Directory exists. Look for checkout along path to src.
|
||||
vcs, rootPath, err = vcsFromDir(p.Dir, p.Internal.Build.SrcRoot)
|
||||
@@ -421,7 +438,7 @@ func downloadPackage(p *load.Package) error {
|
||||
}
|
||||
repo = remote
|
||||
if !*getF && err == nil {
|
||||
if rr, err := RepoRootForImportPath(p.ImportPath, IgnoreMod, security); err == nil {
|
||||
if rr, err := RepoRootForImportPath(importPrefix, IgnoreMod, security); err == nil {
|
||||
repo := rr.Repo
|
||||
if rr.vcs.resolveRepo != nil {
|
||||
resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
|
||||
@@ -438,7 +455,7 @@ func downloadPackage(p *load.Package) error {
|
||||
} else {
|
||||
// Analyze the import path to determine the version control system,
|
||||
// repository, and the import path for the root of the repository.
|
||||
rr, err := RepoRootForImportPath(p.ImportPath, IgnoreMod, security)
|
||||
rr, err := RepoRootForImportPath(importPrefix, IgnoreMod, security)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
192
src/cmd/go/internal/get/path.go
Normal file
192
src/cmd/go/internal/get/path.go
Normal file
@@ -0,0 +1,192 @@
|
||||
// Copyright 2018 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 get
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// The following functions are copied verbatim from cmd/go/internal/module/module.go,
|
||||
// with a change to additionally reject Windows short-names,
|
||||
// and one to accept arbitrary letters (golang.org/issue/29101).
|
||||
//
|
||||
// TODO(bcmills): After the call site for this function is backported,
|
||||
// consolidate this back down to a single copy.
|
||||
//
|
||||
// NOTE: DO NOT MERGE THESE UNTIL WE DECIDE ABOUT ARBITRARY LETTERS IN MODULE MODE.
|
||||
|
||||
// CheckImportPath checks that an import path is valid.
|
||||
func CheckImportPath(path string) error {
|
||||
if err := checkPath(path, false); err != nil {
|
||||
return fmt.Errorf("malformed import path %q: %v", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkPath checks that a general path is valid.
|
||||
// It returns an error describing why but not mentioning path.
|
||||
// Because these checks apply to both module paths and import paths,
|
||||
// the caller is expected to add the "malformed ___ path %q: " prefix.
|
||||
// fileName indicates whether the final element of the path is a file name
|
||||
// (as opposed to a directory name).
|
||||
func checkPath(path string, fileName bool) error {
|
||||
if !utf8.ValidString(path) {
|
||||
return fmt.Errorf("invalid UTF-8")
|
||||
}
|
||||
if path == "" {
|
||||
return fmt.Errorf("empty string")
|
||||
}
|
||||
if strings.Contains(path, "..") {
|
||||
return fmt.Errorf("double dot")
|
||||
}
|
||||
if strings.Contains(path, "//") {
|
||||
return fmt.Errorf("double slash")
|
||||
}
|
||||
if path[len(path)-1] == '/' {
|
||||
return fmt.Errorf("trailing slash")
|
||||
}
|
||||
elemStart := 0
|
||||
for i, r := range path {
|
||||
if r == '/' {
|
||||
if err := checkElem(path[elemStart:i], fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
elemStart = i + 1
|
||||
}
|
||||
}
|
||||
if err := checkElem(path[elemStart:], fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkElem checks whether an individual path element is valid.
|
||||
// fileName indicates whether the element is a file name (not a directory name).
|
||||
func checkElem(elem string, fileName bool) error {
|
||||
if elem == "" {
|
||||
return fmt.Errorf("empty path element")
|
||||
}
|
||||
if strings.Count(elem, ".") == len(elem) {
|
||||
return fmt.Errorf("invalid path element %q", elem)
|
||||
}
|
||||
if elem[0] == '.' && !fileName {
|
||||
return fmt.Errorf("leading dot in path element")
|
||||
}
|
||||
if elem[len(elem)-1] == '.' {
|
||||
return fmt.Errorf("trailing dot in path element")
|
||||
}
|
||||
|
||||
charOK := pathOK
|
||||
if fileName {
|
||||
charOK = fileNameOK
|
||||
}
|
||||
for _, r := range elem {
|
||||
if !charOK(r) {
|
||||
return fmt.Errorf("invalid char %q", r)
|
||||
}
|
||||
}
|
||||
|
||||
// Windows disallows a bunch of path elements, sadly.
|
||||
// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
|
||||
short := elem
|
||||
if i := strings.Index(short, "."); i >= 0 {
|
||||
short = short[:i]
|
||||
}
|
||||
for _, bad := range badWindowsNames {
|
||||
if strings.EqualFold(bad, short) {
|
||||
return fmt.Errorf("disallowed path element %q", elem)
|
||||
}
|
||||
}
|
||||
|
||||
// Reject path components that look like Windows short-names.
|
||||
// Those usually end in a tilde followed by one or more ASCII digits.
|
||||
if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 {
|
||||
suffix := short[tilde+1:]
|
||||
suffixIsDigits := true
|
||||
for _, r := range suffix {
|
||||
if r < '0' || r > '9' {
|
||||
suffixIsDigits = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if suffixIsDigits {
|
||||
return fmt.Errorf("trailing tilde and digits in path element")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// pathOK reports whether r can appear in an import path element.
|
||||
//
|
||||
// NOTE: This function DIVERGES from module mode pathOK by accepting Unicode letters.
|
||||
func pathOK(r rune) bool {
|
||||
if r < utf8.RuneSelf {
|
||||
return r == '+' || r == '-' || r == '.' || r == '_' || r == '~' ||
|
||||
'0' <= r && r <= '9' ||
|
||||
'A' <= r && r <= 'Z' ||
|
||||
'a' <= r && r <= 'z'
|
||||
}
|
||||
return unicode.IsLetter(r)
|
||||
}
|
||||
|
||||
// fileNameOK reports whether r can appear in a file name.
|
||||
// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters.
|
||||
// If we expand the set of allowed characters here, we have to
|
||||
// work harder at detecting potential case-folding and normalization collisions.
|
||||
// See note about "safe encoding" below.
|
||||
func fileNameOK(r rune) bool {
|
||||
if r < utf8.RuneSelf {
|
||||
// Entire set of ASCII punctuation, from which we remove characters:
|
||||
// ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
|
||||
// We disallow some shell special characters: " ' * < > ? ` |
|
||||
// (Note that some of those are disallowed by the Windows file system as well.)
|
||||
// We also disallow path separators / : and \ (fileNameOK is only called on path element characters).
|
||||
// We allow spaces (U+0020) in file names.
|
||||
const allowed = "!#$%&()+,-.=@[]^_{}~ "
|
||||
if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' {
|
||||
return true
|
||||
}
|
||||
for i := 0; i < len(allowed); i++ {
|
||||
if rune(allowed[i]) == r {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
// It may be OK to add more ASCII punctuation here, but only carefully.
|
||||
// For example Windows disallows < > \, and macOS disallows :, so we must not allow those.
|
||||
return unicode.IsLetter(r)
|
||||
}
|
||||
|
||||
// badWindowsNames are the reserved file path elements on Windows.
|
||||
// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
|
||||
var badWindowsNames = []string{
|
||||
"CON",
|
||||
"PRN",
|
||||
"AUX",
|
||||
"NUL",
|
||||
"COM1",
|
||||
"COM2",
|
||||
"COM3",
|
||||
"COM4",
|
||||
"COM5",
|
||||
"COM6",
|
||||
"COM7",
|
||||
"COM8",
|
||||
"COM9",
|
||||
"LPT1",
|
||||
"LPT2",
|
||||
"LPT3",
|
||||
"LPT4",
|
||||
"LPT5",
|
||||
"LPT6",
|
||||
"LPT7",
|
||||
"LPT8",
|
||||
"LPT9",
|
||||
}
|
||||
@@ -647,14 +647,7 @@ const (
|
||||
func RepoRootForImportPath(importPath string, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) {
|
||||
rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths)
|
||||
if err == errUnknownSite {
|
||||
// If there are wildcards, look up the thing before the wildcard,
|
||||
// hoping it applies to the wildcarded parts too.
|
||||
// This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
|
||||
lookup := strings.TrimSuffix(importPath, "/...")
|
||||
if i := strings.Index(lookup, "/.../"); i >= 0 {
|
||||
lookup = lookup[:i]
|
||||
}
|
||||
rr, err = repoRootForImportDynamic(lookup, mod, security)
|
||||
rr, err = repoRootForImportDynamic(importPath, mod, security)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unrecognized import path %q (%v)", importPath, err)
|
||||
}
|
||||
@@ -667,6 +660,7 @@ func RepoRootForImportPath(importPath string, mod ModuleMode, security web.Secur
|
||||
}
|
||||
}
|
||||
|
||||
// Should have been taken care of above, but make sure.
|
||||
if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.Root, "...") {
|
||||
// Do not allow wildcards in the repo root.
|
||||
rr = nil
|
||||
@@ -966,10 +960,14 @@ func matchGoImport(imports []metaImport, importPath string) (metaImport, error)
|
||||
|
||||
// expand rewrites s to replace {k} with match[k] for each key k in match.
|
||||
func expand(match map[string]string, s string) string {
|
||||
// We want to replace each match exactly once, and the result of expansion
|
||||
// must not depend on the iteration order through the map.
|
||||
// A strings.Replacer has exactly the properties we're looking for.
|
||||
oldNew := make([]string, 0, 2*len(match))
|
||||
for k, v := range match {
|
||||
s = strings.Replace(s, "{"+k+"}", v, -1)
|
||||
oldNew = append(oldNew, "{"+k+"}", v)
|
||||
}
|
||||
return s
|
||||
return strings.NewReplacer(oldNew...).Replace(s)
|
||||
}
|
||||
|
||||
// vcsPaths defines the meaning of import paths referring to
|
||||
|
||||
@@ -507,6 +507,12 @@ General-purpose environment variables:
|
||||
The directory where the go command will write
|
||||
temporary source files, packages, and binaries.
|
||||
|
||||
Each entry in the GOFLAGS list must be a standalone flag.
|
||||
Because the entries are space-separated, flag values must
|
||||
not contain spaces. In some cases, you can provide multiple flag
|
||||
values instead: for example, to set '-ldflags=-s -w'
|
||||
you can use 'GOFLAGS=-ldflags=-s -ldflags=-w'.
|
||||
|
||||
Environment variables for use with cgo:
|
||||
|
||||
CC
|
||||
|
||||
@@ -510,7 +510,9 @@ func runList(cmd *base.Command, args []string) {
|
||||
a := &work.Action{}
|
||||
// TODO: Use pkgsFilter?
|
||||
for _, p := range pkgs {
|
||||
a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
|
||||
if len(p.GoFiles)+len(p.CgoFiles) > 0 {
|
||||
a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
|
||||
}
|
||||
}
|
||||
b.Do(a)
|
||||
}
|
||||
|
||||
@@ -227,6 +227,12 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag
|
||||
}
|
||||
}
|
||||
|
||||
allTestImports := make([]*Package, 0, len(pmain.Internal.Imports)+len(imports)+len(ximports))
|
||||
allTestImports = append(allTestImports, pmain.Internal.Imports...)
|
||||
allTestImports = append(allTestImports, imports...)
|
||||
allTestImports = append(allTestImports, ximports...)
|
||||
setToolFlags(allTestImports...)
|
||||
|
||||
// Do initial scan for metadata needed for writing _testmain.go
|
||||
// Use that metadata to update the list of imports for package main.
|
||||
// The list of imports is used by recompileForTest and by the loop
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
var cmdDownload = &base.Command{
|
||||
UsageLine: "go mod download [-dir] [-json] [modules]",
|
||||
UsageLine: "go mod download [-json] [modules]",
|
||||
Short: "download modules to local cache",
|
||||
Long: `
|
||||
Download downloads the named modules, which can be module patterns selecting
|
||||
@@ -32,13 +32,15 @@ to standard output, describing each downloaded module (or failure),
|
||||
corresponding to this Go struct:
|
||||
|
||||
type Module struct {
|
||||
Path string // module path
|
||||
Version string // module version
|
||||
Error string // error loading module
|
||||
Info string // absolute path to cached .info file
|
||||
GoMod string // absolute path to cached .mod file
|
||||
Zip string // absolute path to cached .zip file
|
||||
Dir string // absolute path to cached source root directory
|
||||
Path string // module path
|
||||
Version string // module version
|
||||
Error string // error loading module
|
||||
Info string // absolute path to cached .info file
|
||||
GoMod string // absolute path to cached .mod file
|
||||
Zip string // absolute path to cached .zip file
|
||||
Dir string // absolute path to cached source root directory
|
||||
Sum string // checksum for path, version (as in go.sum)
|
||||
GoModSum string // checksum for go.mod (as in go.sum)
|
||||
}
|
||||
|
||||
See 'go help modules' for more about module queries.
|
||||
@@ -52,13 +54,15 @@ func init() {
|
||||
}
|
||||
|
||||
type moduleJSON struct {
|
||||
Path string `json:",omitempty"`
|
||||
Version string `json:",omitempty"`
|
||||
Error string `json:",omitempty"`
|
||||
Info string `json:",omitempty"`
|
||||
GoMod string `json:",omitempty"`
|
||||
Zip string `json:",omitempty"`
|
||||
Dir string `json:",omitempty"`
|
||||
Path string `json:",omitempty"`
|
||||
Version string `json:",omitempty"`
|
||||
Error string `json:",omitempty"`
|
||||
Info string `json:",omitempty"`
|
||||
GoMod string `json:",omitempty"`
|
||||
Zip string `json:",omitempty"`
|
||||
Dir string `json:",omitempty"`
|
||||
Sum string `json:",omitempty"`
|
||||
GoModSum string `json:",omitempty"`
|
||||
}
|
||||
|
||||
func runDownload(cmd *base.Command, args []string) {
|
||||
@@ -98,12 +102,18 @@ func runDownload(cmd *base.Command, args []string) {
|
||||
m.Error = err.Error()
|
||||
return
|
||||
}
|
||||
m.GoModSum, err = modfetch.GoModSum(m.Path, m.Version)
|
||||
if err != nil {
|
||||
m.Error = err.Error()
|
||||
return
|
||||
}
|
||||
mod := module.Version{Path: m.Path, Version: m.Version}
|
||||
m.Zip, err = modfetch.DownloadZip(mod)
|
||||
if err != nil {
|
||||
m.Error = err.Error()
|
||||
return
|
||||
}
|
||||
m.Sum = modfetch.Sum(mod)
|
||||
m.Dir, err = modfetch.Download(mod)
|
||||
if err != nil {
|
||||
m.Error = err.Error()
|
||||
|
||||
@@ -290,6 +290,23 @@ func GoModFile(path, version string) (string, error) {
|
||||
return file, nil
|
||||
}
|
||||
|
||||
// GoModSum returns the go.sum entry for the module version's go.mod file.
|
||||
// (That is, it returns the entry listed in go.sum as "path version/go.mod".)
|
||||
func GoModSum(path, version string) (string, error) {
|
||||
if !semver.IsValid(version) {
|
||||
return "", fmt.Errorf("invalid version %q", version)
|
||||
}
|
||||
data, err := GoMod(path, version)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sum, err := goModSum(data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return sum, nil
|
||||
}
|
||||
|
||||
var errNotCached = fmt.Errorf("not in cache")
|
||||
|
||||
// readDiskStat reads a cached stat result from disk,
|
||||
|
||||
@@ -694,6 +694,10 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if err := ensureGitAttributes(r.dir); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// Incredibly, git produces different archives depending on whether
|
||||
// it is running on a Windows system or not, in an attempt to normalize
|
||||
// text file line endings. Setting -c core.autocrlf=input means only
|
||||
@@ -709,3 +713,43 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
|
||||
|
||||
return ioutil.NopCloser(bytes.NewReader(archive)), "", nil
|
||||
}
|
||||
|
||||
// ensureGitAttributes makes sure export-subst and export-ignore features are
|
||||
// disabled for this repo. This is intended to be run prior to running git
|
||||
// archive so that zip files are generated that produce consistent ziphashes
|
||||
// for a given revision, independent of variables such as git version and the
|
||||
// size of the repo.
|
||||
//
|
||||
// See: https://github.com/golang/go/issues/27153
|
||||
func ensureGitAttributes(repoDir string) (err error) {
|
||||
const attr = "\n* -export-subst -export-ignore\n"
|
||||
|
||||
d := repoDir + "/info"
|
||||
p := d + "/attributes"
|
||||
|
||||
if err := os.MkdirAll(d, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(p, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
closeErr := f.Close()
|
||||
if closeErr != nil {
|
||||
err = closeErr
|
||||
}
|
||||
}()
|
||||
|
||||
b, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.HasSuffix(b, []byte(attr)) {
|
||||
_, err := f.WriteString(attr)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -498,6 +498,11 @@ func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error
|
||||
}
|
||||
}
|
||||
for _, zf := range zr.File {
|
||||
if !zf.FileInfo().Mode().IsRegular() {
|
||||
// Skip symlinks (golang.org/issue/27093).
|
||||
continue
|
||||
}
|
||||
|
||||
if topPrefix == "" {
|
||||
i := strings.Index(zf.Name, "/")
|
||||
if i < 0 {
|
||||
|
||||
@@ -253,12 +253,17 @@ func checkSum(mod module.Version) {
|
||||
checkOneSum(mod, h)
|
||||
}
|
||||
|
||||
// goModSum returns the checksum for the go.mod contents.
|
||||
func goModSum(data []byte) (string, error) {
|
||||
return dirhash.Hash1([]string{"go.mod"}, func(string) (io.ReadCloser, error) {
|
||||
return ioutil.NopCloser(bytes.NewReader(data)), nil
|
||||
})
|
||||
}
|
||||
|
||||
// checkGoMod checks the given module's go.mod checksum;
|
||||
// data is the go.mod content.
|
||||
func checkGoMod(path, version string, data []byte) {
|
||||
h, err := dirhash.Hash1([]string{"go.mod"}, func(string) (io.ReadCloser, error) {
|
||||
return ioutil.NopCloser(bytes.NewReader(data)), nil
|
||||
})
|
||||
h, err := goModSum(data)
|
||||
if err != nil {
|
||||
base.Fatalf("go: verifying %s %s go.mod: %v", path, version, err)
|
||||
}
|
||||
|
||||
@@ -25,15 +25,21 @@ var (
|
||||
)
|
||||
|
||||
func isStandardImportPath(path string) bool {
|
||||
return findStandardImportPath(path) != ""
|
||||
}
|
||||
|
||||
func findStandardImportPath(path string) string {
|
||||
if search.IsStandardImportPath(path) {
|
||||
if _, err := os.Stat(filepath.Join(cfg.GOROOT, "src", path)); err == nil {
|
||||
return true
|
||||
dir := filepath.Join(cfg.GOROOT, "src", path)
|
||||
if _, err := os.Stat(dir); err == nil {
|
||||
return dir
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(cfg.GOROOT, "src/vendor", path)); err == nil {
|
||||
return true
|
||||
dir = filepath.Join(cfg.GOROOT, "src/vendor", path)
|
||||
if _, err := os.Stat(dir); err == nil {
|
||||
return dir
|
||||
}
|
||||
}
|
||||
return false
|
||||
return ""
|
||||
}
|
||||
|
||||
func PackageModuleInfo(pkgpath string) *modinfo.ModulePublic {
|
||||
|
||||
@@ -420,7 +420,19 @@ See 'go help mod edit'.
|
||||
|
||||
The go command automatically updates go.mod each time it uses the
|
||||
module graph, to make sure go.mod always accurately reflects reality
|
||||
and is properly formatted.
|
||||
and is properly formatted. For example, consider this go.mod file:
|
||||
|
||||
module M
|
||||
|
||||
require (
|
||||
A v1
|
||||
B v1.0.0
|
||||
C v1.0.0
|
||||
D v1.2.3
|
||||
E dev
|
||||
)
|
||||
|
||||
exclude D v1.2.3
|
||||
|
||||
The update rewrites non-canonical version identifiers to semver form,
|
||||
so A's v1 becomes v1.0.0 and E's dev becomes the pseudo-version for the
|
||||
|
||||
@@ -181,7 +181,7 @@ func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFile
|
||||
// So we only check local module trees
|
||||
// (the main module, and any directory trees pointed at by replace directives).
|
||||
if isLocal {
|
||||
for d := dir; d != mdir && len(d) > len(mdir); d = filepath.Dir(d) {
|
||||
for d := dir; d != mdir && len(d) > len(mdir); {
|
||||
haveGoMod := haveGoModCache.Do(d, func() interface{} {
|
||||
_, err := os.Stat(filepath.Join(d, "go.mod"))
|
||||
return err == nil
|
||||
@@ -190,6 +190,13 @@ func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFile
|
||||
if haveGoMod {
|
||||
return "", false
|
||||
}
|
||||
parent := filepath.Dir(d)
|
||||
if parent == d {
|
||||
// Break the loop, as otherwise we'd loop
|
||||
// forever if d=="." and mdir=="".
|
||||
break
|
||||
}
|
||||
d = parent
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ var importTests = []struct {
|
||||
},
|
||||
{
|
||||
path: "golang.org/x/net",
|
||||
err: "missing module for import: golang.org/x/net@.* provides golang.org/x/net",
|
||||
err: "cannot find module providing package golang.org/x/net",
|
||||
},
|
||||
{
|
||||
path: "golang.org/x/text",
|
||||
|
||||
@@ -399,11 +399,17 @@ func ModuleUsedDirectly(path string) bool {
|
||||
func Lookup(path string) (dir, realPath string, err error) {
|
||||
pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
|
||||
if !ok {
|
||||
if isStandardImportPath(path) {
|
||||
dir := filepath.Join(cfg.GOROOT, "src", path)
|
||||
if _, err := os.Stat(dir); err == nil {
|
||||
return dir, path, nil
|
||||
}
|
||||
// The loader should have found all the relevant paths.
|
||||
// There are a few exceptions, though:
|
||||
// - during go list without -test, the p.Resolve calls to process p.TestImports and p.XTestImports
|
||||
// end up here to canonicalize the import paths.
|
||||
// - during any load, non-loaded packages like "unsafe" end up here.
|
||||
// - during any load, build-injected dependencies like "runtime/cgo" end up here.
|
||||
// - because we ignore appengine/* in the module loader,
|
||||
// the dependencies of any actual appengine/* library end up here.
|
||||
dir := findStandardImportPath(path)
|
||||
if dir != "" {
|
||||
return dir, path, nil
|
||||
}
|
||||
return "", "", errMissing
|
||||
}
|
||||
|
||||
@@ -78,6 +78,9 @@ func runRun(cmd *base.Command, args []string) {
|
||||
p = load.GoFilesPackage(files)
|
||||
} else if len(args) > 0 && !strings.HasPrefix(args[0], "-") {
|
||||
pkgs := load.PackagesAndErrors(args[:1])
|
||||
if len(pkgs) == 0 {
|
||||
base.Fatalf("go run: no packages loaded from %s", args[0])
|
||||
}
|
||||
if len(pkgs) > 1 {
|
||||
var names []string
|
||||
for _, p := range pkgs {
|
||||
|
||||
@@ -99,7 +99,7 @@ and test commands:
|
||||
link against shared libraries previously created with
|
||||
-buildmode=shared.
|
||||
-mod mode
|
||||
module download mode to use: readonly, release, or vendor.
|
||||
module download mode to use: readonly or vendor.
|
||||
See 'go help modules' for more.
|
||||
-pkgdir dir
|
||||
install and load all packages from dir instead of the usual locations.
|
||||
|
||||
@@ -224,7 +224,9 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
|
||||
if len(p.SFiles) > 0 {
|
||||
fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags)
|
||||
}
|
||||
fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(cfg.BuildContext.GOARCH))) // GO386, GOARM, etc
|
||||
// GO386, GOARM, GOMIPS, etc.
|
||||
baseArch := strings.TrimSuffix(cfg.BuildContext.GOARCH, "le")
|
||||
fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(baseArch)))
|
||||
|
||||
// TODO(rsc): Convince compiler team not to add more magic environment variables,
|
||||
// or perhaps restrict the environment variables passed to subprocesses.
|
||||
@@ -432,10 +434,6 @@ func (b *Builder) build(a *Action) (err error) {
|
||||
return fmt.Errorf("missing or invalid binary-only package; expected file %q", a.Package.Target)
|
||||
}
|
||||
|
||||
if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
|
||||
return fmt.Errorf("module requires Go %s", p.Module.GoVersion)
|
||||
}
|
||||
|
||||
if err := b.Mkdir(a.Objdir); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -636,12 +634,19 @@ func (b *Builder) build(a *Action) (err error) {
|
||||
objpkg := objdir + "_pkg_.a"
|
||||
ofile, out, err := BuildToolchain.gc(b, a, objpkg, icfg.Bytes(), len(sfiles) > 0, gofiles)
|
||||
if len(out) > 0 {
|
||||
b.showOutput(a, a.Package.Dir, a.Package.Desc(), b.processOutput(out))
|
||||
output := b.processOutput(out)
|
||||
if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
|
||||
output += "note: module requires Go " + p.Module.GoVersion
|
||||
}
|
||||
b.showOutput(a, a.Package.Dir, a.Package.Desc(), output)
|
||||
if err != nil {
|
||||
return errPrintedOutput
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
|
||||
b.showOutput(a, a.Package.Dir, a.Package.Desc(), "note: module requires Go "+p.Module.GoVersion)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if ofile != objpkg {
|
||||
@@ -2075,14 +2080,37 @@ func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []s
|
||||
}
|
||||
|
||||
// gccld runs the gcc linker to create an executable from a set of object files.
|
||||
func (b *Builder) gccld(p *load.Package, objdir, out string, flags []string, objs []string) error {
|
||||
func (b *Builder) gccld(p *load.Package, objdir, outfile string, flags []string, objs []string) error {
|
||||
var cmd []string
|
||||
if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
|
||||
cmd = b.GxxCmd(p.Dir, objdir)
|
||||
} else {
|
||||
cmd = b.GccCmd(p.Dir, objdir)
|
||||
}
|
||||
return b.run(nil, p.Dir, p.ImportPath, b.cCompilerEnv(), cmd, "-o", out, objs, flags)
|
||||
|
||||
cmdargs := []interface{}{cmd, "-o", outfile, objs, flags}
|
||||
dir := p.Dir
|
||||
out, err := b.runOut(dir, b.cCompilerEnv(), cmdargs...)
|
||||
if len(out) > 0 {
|
||||
// Filter out useless linker warnings caused by bugs outside Go.
|
||||
// See also cmd/link/internal/ld's hostlink method.
|
||||
var save [][]byte
|
||||
for _, line := range bytes.SplitAfter(out, []byte("\n")) {
|
||||
// golang.org/issue/26073 - Apple Xcode bug
|
||||
if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
|
||||
continue
|
||||
}
|
||||
save = append(save, line)
|
||||
}
|
||||
out = bytes.Join(save, nil)
|
||||
if len(out) > 0 {
|
||||
b.showOutput(nil, dir, p.ImportPath, b.processOutput(out))
|
||||
if err != nil {
|
||||
err = errPrintedOutput
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Grab these before main helpfully overwrites them.
|
||||
|
||||
@@ -170,6 +170,7 @@ var validLinkerFlags = []*regexp.Regexp{
|
||||
re(`-Wl,-e[=,][a-zA-Z0-9]*`),
|
||||
re(`-Wl,--enable-new-dtags`),
|
||||
re(`-Wl,--end-group`),
|
||||
re(`-Wl,--(no-)?export-dynamic`),
|
||||
re(`-Wl,-framework,[^,@\-][^,]+`),
|
||||
re(`-Wl,-headerpad_max_install_names`),
|
||||
re(`-Wl,--no-undefined`),
|
||||
|
||||
@@ -629,6 +629,9 @@ func scriptMatch(ts *testScript, neg bool, args []string, text, name string) {
|
||||
text = string(data)
|
||||
}
|
||||
|
||||
// Matching against workdir would be misleading.
|
||||
text = strings.Replace(text, ts.workdir, "$WORK", -1)
|
||||
|
||||
if neg {
|
||||
if re.MatchString(text) {
|
||||
if isGrep {
|
||||
|
||||
37
src/cmd/go/testdata/script/build_cache_gomips.txt
vendored
Normal file
37
src/cmd/go/testdata/script/build_cache_gomips.txt
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# Set up fresh GOCACHE.
|
||||
env GOCACHE=$WORK/gocache
|
||||
mkdir $GOCACHE
|
||||
|
||||
# Building for mipsle without setting GOMIPS will use floating point registers.
|
||||
env GOARCH=mipsle
|
||||
env GOOS=linux
|
||||
go build -gcflags=-S f.go
|
||||
stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+
|
||||
|
||||
# Clean cache
|
||||
go clean -cache
|
||||
|
||||
# Building with GOMIPS=softfloat will not use floating point registers
|
||||
env GOMIPS=softfloat
|
||||
go build -gcflags=-S f.go
|
||||
! stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+
|
||||
|
||||
# Clean cache
|
||||
go clean -cache
|
||||
|
||||
# Build without setting GOMIPS
|
||||
env GOMIPS=
|
||||
go build -gcflags=-S f.go
|
||||
stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+
|
||||
|
||||
# Building with GOMIPS should still not use floating point registers.
|
||||
env GOMIPS=softfloat
|
||||
go build -gcflags=-S f.go
|
||||
! stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+
|
||||
|
||||
-- f.go --
|
||||
package f
|
||||
|
||||
func F(x float64) float64 {
|
||||
return x + x
|
||||
}
|
||||
28
src/cmd/go/testdata/script/gcflags_patterns.txt
vendored
28
src/cmd/go/testdata/script/gcflags_patterns.txt
vendored
@@ -2,24 +2,28 @@
|
||||
|
||||
# -gcflags=-e applies to named packages, not dependencies
|
||||
go build -n -v -gcflags=-e z1 z2
|
||||
stderr 'compile.* -e .*-p z1'
|
||||
stderr 'compile.* -e .*-p z2'
|
||||
stderr 'compile.* -e.* -p z1'
|
||||
stderr 'compile.* -e.* -p z2'
|
||||
stderr 'compile.* -p y'
|
||||
! stderr 'compile.* -e .*-p [^z]'
|
||||
! stderr 'compile.* -e.* -p [^z]'
|
||||
|
||||
# -gcflags can specify package=flags, and can be repeated; last match wins
|
||||
go build -n -v -gcflags=-e -gcflags=z1=-N z1 z2
|
||||
stderr 'compile.* -N .*-p z1'
|
||||
! stderr 'compile.* -e .*-p z1'
|
||||
! stderr 'compile.* -N .*-p z2'
|
||||
stderr 'compile.* -e .*-p z2'
|
||||
stderr 'compile.* -N.* -p z1'
|
||||
! stderr 'compile.* -e.* -p z1'
|
||||
! stderr 'compile.* -N.* -p z2'
|
||||
stderr 'compile.* -e.* -p z2'
|
||||
stderr 'compile.* -p y'
|
||||
! stderr 'compile.* -e .*-p [^z]'
|
||||
! stderr 'compile.* -N .*-p [^z]'
|
||||
! stderr 'compile.* -e.* -p [^z]'
|
||||
! stderr 'compile.* -N.* -p [^z]'
|
||||
|
||||
# -gcflags can have arbitrary spaces around the flags
|
||||
go build -n -v -gcflags=' z1 = -e ' z1
|
||||
stderr 'compile.* -e .*-p z1'
|
||||
stderr 'compile.* -e.* -p z1'
|
||||
|
||||
# -gcflags='all=-e' should apply to all packages, even with go test
|
||||
go test -c -n -gcflags='all=-e' z1
|
||||
stderr 'compile.* -e.* -p z3 '
|
||||
|
||||
# -ldflags for implicit test package applies to test binary
|
||||
go test -c -n -gcflags=-N -ldflags=-X=x.y=z z1
|
||||
@@ -58,11 +62,15 @@ import _ "z2"
|
||||
-- z1/z_test.go --
|
||||
package z1_test
|
||||
import "testing"
|
||||
import _ "z3"
|
||||
func Test(t *testing.T) {}
|
||||
|
||||
-- z2/z.go --
|
||||
package z2
|
||||
|
||||
-- z3/z.go --
|
||||
package z3
|
||||
|
||||
-- y/y.go --
|
||||
package y
|
||||
|
||||
|
||||
49
src/cmd/go/testdata/script/get_brace.txt
vendored
Normal file
49
src/cmd/go/testdata/script/get_brace.txt
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
[!exec:git] skip
|
||||
|
||||
# Set up some empty repositories.
|
||||
cd $WORK/_origin/foo
|
||||
exec git init
|
||||
exec git config user.name 'Nameless Gopher'
|
||||
exec git config user.email 'nobody@golang.org'
|
||||
exec git commit --allow-empty -m 'create master branch'
|
||||
|
||||
cd $WORK
|
||||
cd '_origin/{confusing}'
|
||||
exec git init
|
||||
exec git config user.name 'Nameless Gopher'
|
||||
exec git config user.email 'nobody@golang.org'
|
||||
exec git commit --allow-empty -m 'create master branch'
|
||||
|
||||
# Clone the empty repositories into GOPATH.
|
||||
# This tells the Go command where to find them: it takes the place of a user's meta-tag redirector.
|
||||
mkdir $GOPATH/src/example.com
|
||||
cd $GOPATH/src/example.com
|
||||
exec git clone $WORK/_origin/foo
|
||||
exec git clone $WORK/_origin/{confusing}
|
||||
|
||||
# Commit contents to the repositories.
|
||||
cd $WORK/_origin/foo
|
||||
exec git add main.go
|
||||
exec git commit -m 'add main'
|
||||
|
||||
cd $WORK
|
||||
cd '_origin/{confusing}'
|
||||
exec git add confusing.go
|
||||
exec git commit -m 'just try to delete this!'
|
||||
|
||||
# 'go get' should refuse to download or update the confusingly-named repo.
|
||||
cd $GOPATH/src/example.com/foo
|
||||
! go get -u 'example.com/{confusing}'
|
||||
stderr 'invalid char'
|
||||
! go get -u example.com/foo
|
||||
stderr 'invalid import path'
|
||||
! exists example.com/{confusing}
|
||||
|
||||
-- $WORK/_origin/foo/main.go --
|
||||
package main
|
||||
import _ "example.com/{confusing}"
|
||||
|
||||
func main() {}
|
||||
|
||||
-- $WORK/_origin/{confusing}/confusing.go --
|
||||
package confusing
|
||||
61
src/cmd/go/testdata/script/get_dotfiles.txt
vendored
Normal file
61
src/cmd/go/testdata/script/get_dotfiles.txt
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
[!exec:git] skip
|
||||
|
||||
# Set up a benign repository and a repository with a dotfile name.
|
||||
cd $WORK/_origin/foo
|
||||
exec git init
|
||||
exec git config user.name 'Nameless Gopher'
|
||||
exec git config user.email 'nobody@golang.org'
|
||||
exec git commit --allow-empty -m 'create master branch'
|
||||
|
||||
cd $WORK/_origin/.hidden
|
||||
exec git init
|
||||
exec git config user.name 'Nameless Gopher'
|
||||
exec git config user.email 'nobody@golang.org'
|
||||
exec git commit --allow-empty -m 'create master branch'
|
||||
|
||||
# Clone the empty repositories into GOPATH.
|
||||
# This tells the Go command where to find them: it takes the place of a user's meta-tag redirector.
|
||||
mkdir $GOPATH/src/example.com
|
||||
cd $GOPATH/src/example.com
|
||||
exec git clone $WORK/_origin/foo
|
||||
exec git clone $WORK/_origin/.hidden
|
||||
|
||||
# Add a benign commit.
|
||||
cd $WORK/_origin/foo
|
||||
cp _ok/main.go main.go
|
||||
exec git add main.go
|
||||
exec git commit -m 'add ok'
|
||||
|
||||
# 'go get' should install the benign commit.
|
||||
cd $GOPATH
|
||||
go get -u example.com/foo
|
||||
|
||||
# Now sneak in an import of a dotfile path.
|
||||
cd $WORK/_origin/.hidden
|
||||
exec git add hidden.go
|
||||
exec git commit -m 'nothing to see here, move along'
|
||||
|
||||
cd $WORK/_origin/foo
|
||||
cp _sneaky/main.go main.go
|
||||
exec git add main.go
|
||||
exec git commit -m 'fix typo (heh heh heh)'
|
||||
|
||||
# 'go get -u' should refuse to download or update the dotfile-named repo.
|
||||
cd $GOPATH/src/example.com/foo
|
||||
! go get -u example.com/foo
|
||||
stderr 'leading dot'
|
||||
! exists example.com/.hidden/hidden.go
|
||||
|
||||
-- $WORK/_origin/foo/_ok/main.go --
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
|
||||
-- $WORK/_origin/foo/_sneaky/main.go --
|
||||
package main
|
||||
import _ "example.com/.hidden"
|
||||
|
||||
func main() {}
|
||||
|
||||
-- $WORK/_origin/.hidden/hidden.go --
|
||||
package hidden
|
||||
21
src/cmd/go/testdata/script/get_tilde.txt
vendored
Normal file
21
src/cmd/go/testdata/script/get_tilde.txt
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Paths containing windows short names should be rejected before attempting to fetch.
|
||||
! go get example.com/longna~1.dir/thing
|
||||
stderr 'trailing tilde and digits'
|
||||
! go get example.com/longna~1/thing
|
||||
stderr 'trailing tilde and digits'
|
||||
! go get example.com/~9999999/thing
|
||||
stderr 'trailing tilde and digits'
|
||||
|
||||
# A path containing an element that is just a tilde, or a tilde followed by non-digits,
|
||||
# should attempt to resolve.
|
||||
! go get example.com/~glenda/notfound
|
||||
! stderr 'trailing tilde and digits'
|
||||
stderr 'unrecognized import path'
|
||||
|
||||
! go get example.com/~glenda2/notfound
|
||||
! stderr 'trailing tilde and digits'
|
||||
stderr 'unrecognized import path'
|
||||
|
||||
! go get example.com/~/notfound
|
||||
! stderr 'trailing tilde and digits'
|
||||
stderr 'unrecognized import path'
|
||||
37
src/cmd/go/testdata/script/get_unicode.txt
vendored
Normal file
37
src/cmd/go/testdata/script/get_unicode.txt
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
[!exec:git] skip
|
||||
|
||||
# Construct a repository that imports a non-ASCII path.
|
||||
cd $WORK/_origin/example.com/unicode
|
||||
exec git init
|
||||
exec git config user.name 'Nameless Gopher'
|
||||
exec git config user.email 'nobody@golang.org'
|
||||
exec git add unicode.go
|
||||
exec git commit -m 'add unicode.go'
|
||||
|
||||
# Clone the repo into GOPATH so that 'go get -u' can find it.
|
||||
mkdir $GOPATH/src/example.com/unicode
|
||||
cd $GOPATH/src/example.com/unicode
|
||||
exec git clone $WORK/_origin/example.com/unicode .
|
||||
|
||||
# Construct the imported repository.
|
||||
cd $WORK/_origin/example.com/испытание
|
||||
exec git init
|
||||
exec git config user.name 'Nameless Gopher'
|
||||
exec git config user.email 'nobody@golang.org'
|
||||
exec git add испытание.go
|
||||
exec git commit -m 'add испытание.go'
|
||||
|
||||
# Clone that repo into GOPATH too.
|
||||
mkdir $GOPATH/src/example.com/испытание
|
||||
cd $GOPATH/src/example.com/испытание
|
||||
exec git clone $WORK/_origin/example.com/испытание .
|
||||
|
||||
# Upgrading the importer should pull from the non-ASCII repo.
|
||||
cd $GOPATH
|
||||
go get -u example.com/unicode
|
||||
|
||||
-- $WORK/_origin/example.com/unicode/unicode.go --
|
||||
package unicode
|
||||
import _ "example.com/испытание"
|
||||
-- $WORK/_origin/example.com/испытание/испытание.go --
|
||||
package испытание
|
||||
2
src/cmd/go/testdata/script/mod_download.txt
vendored
2
src/cmd/go/testdata/script/mod_download.txt
vendored
@@ -15,6 +15,8 @@ stdout '^\t"Version": "v1.5.0"'
|
||||
stdout '^\t"Info": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.0.info"'
|
||||
stdout '^\t"GoMod": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.0.mod"'
|
||||
stdout '^\t"Zip": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.0.zip"'
|
||||
stdout '^\t"Sum": "h1:6fJa6E\+wGadANKkUMlZ0DhXFpoKlslOQDCo259XtdIE="' # hash of testdata/mod version, not real version!
|
||||
stdout '^\t"GoModSum": "h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe\+TKr0="'
|
||||
! stdout '"Error"'
|
||||
|
||||
# download queries above should not have added to go.mod.
|
||||
|
||||
21
src/cmd/go/testdata/script/mod_git_export_subst.txt
vendored
Normal file
21
src/cmd/go/testdata/script/mod_git_export_subst.txt
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
env GO111MODULE=on
|
||||
env GOPROXY=
|
||||
|
||||
# Testing that git export-subst is disabled
|
||||
[!net] skip
|
||||
[!exec:git] skip
|
||||
go build
|
||||
|
||||
-- x.go --
|
||||
package x
|
||||
|
||||
import _ "github.com/jasonkeene/export-subst"
|
||||
|
||||
-- go.mod --
|
||||
module x
|
||||
|
||||
require github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626
|
||||
|
||||
-- go.sum --
|
||||
github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626 h1:AUkXi/xFnm7lH2pgtvVkGb7buRn1ywFHw+xDpZ29Rz0=
|
||||
github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626/go.mod h1:DwJXqVtrgrQkv3Giuf2Jh4YyubVe7y41S1eOIaysTJw=
|
||||
16
src/cmd/go/testdata/script/mod_go_version.txt
vendored
16
src/cmd/go/testdata/script/mod_go_version.txt
vendored
@@ -3,9 +3,10 @@
|
||||
env GO111MODULE=on
|
||||
|
||||
go list
|
||||
! go build
|
||||
stderr 'module requires Go 1.999'
|
||||
go build
|
||||
go build sub.1
|
||||
go build subver.1
|
||||
! stderr 'module requires'
|
||||
! go build badsub.1
|
||||
stderr 'module requires Go 1.11111'
|
||||
|
||||
@@ -19,11 +20,13 @@ module m
|
||||
go 1.999
|
||||
require (
|
||||
sub.1 v1.0.0
|
||||
subver.1 v1.0.0
|
||||
badsub.1 v1.0.0
|
||||
versioned.1 v1.0.0
|
||||
)
|
||||
replace (
|
||||
sub.1 => ./sub
|
||||
subver.1 => ./subver
|
||||
badsub.1 => ./badsub
|
||||
versioned.1 v1.0.0 => ./versioned1
|
||||
versioned.1 v1.1.0 => ./versioned2
|
||||
@@ -39,12 +42,20 @@ go 1.11
|
||||
-- sub/x.go --
|
||||
package x
|
||||
|
||||
-- subver/go.mod --
|
||||
module m
|
||||
go 1.11111
|
||||
|
||||
-- subver/x.go --
|
||||
package x
|
||||
|
||||
-- badsub/go.mod --
|
||||
module m
|
||||
go 1.11111
|
||||
|
||||
-- badsub/x.go --
|
||||
package x
|
||||
invalid syntax
|
||||
|
||||
-- versioned1/go.mod --
|
||||
module versioned
|
||||
@@ -59,3 +70,4 @@ go 1.99999
|
||||
|
||||
-- versioned2/x.go --
|
||||
package x
|
||||
invalid syntax
|
||||
|
||||
16
src/cmd/go/testdata/script/mod_list_test.txt
vendored
Normal file
16
src/cmd/go/testdata/script/mod_list_test.txt
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
env GO111MODULE=on
|
||||
|
||||
# go list -compiled -test must handle test-only packages
|
||||
# golang.org/issue/27097.
|
||||
go list -compiled -test
|
||||
stdout '^m$'
|
||||
stdout '^m\.test$'
|
||||
stdout '^m \[m\.test\]$'
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
||||
-- x_test.go --
|
||||
package x
|
||||
import "testing"
|
||||
func Test(t *testing.T) {}
|
||||
19
src/cmd/go/testdata/script/mod_std_vendor.txt
vendored
Normal file
19
src/cmd/go/testdata/script/mod_std_vendor.txt
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
env GO111MODULE=on
|
||||
|
||||
go list -f '{{.TestImports}}'
|
||||
stdout net/http # from .TestImports
|
||||
|
||||
go list -test -f '{{.Deps}}'
|
||||
stdout golang_org/x/crypto # dep of .TestImports
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
||||
-- x.go --
|
||||
package x
|
||||
|
||||
-- x_test.go --
|
||||
package x
|
||||
import "testing"
|
||||
import _ "net/http"
|
||||
func Test(t *testing.T) {}
|
||||
5
src/cmd/go/testdata/script/run_wildcard.txt
vendored
Normal file
5
src/cmd/go/testdata/script/run_wildcard.txt
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Fix for https://github.com/golang/go/issues/28696:
|
||||
# go run x/... should not panic when directory x doesn't exist.
|
||||
|
||||
! go run nonexistent/...
|
||||
stderr '^go run: no packages loaded from nonexistent/...$'
|
||||
113
src/cmd/link/elf_test.go
Normal file
113
src/cmd/link/elf_test.go
Normal file
@@ -0,0 +1,113 @@
|
||||
// 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.
|
||||
|
||||
// +build dragonfly freebsd linux netbsd openbsd
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var asmSource = `
|
||||
.section .text1,"ax"
|
||||
s1:
|
||||
.byte 0
|
||||
.section .text2,"ax"
|
||||
s2:
|
||||
.byte 0
|
||||
`
|
||||
|
||||
var goSource = `
|
||||
package main
|
||||
func main() {}
|
||||
`
|
||||
|
||||
// The linker used to crash if an ELF input file had multiple text sections
|
||||
// with the same name.
|
||||
func TestSectionsWithSameName(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
testenv.MustHaveCGO(t)
|
||||
t.Parallel()
|
||||
|
||||
objcopy, err := exec.LookPath("objcopy")
|
||||
if err != nil {
|
||||
t.Skipf("can't find objcopy: %v", err)
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir("", "go-link-TestSectionsWithSameName")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
gopath := filepath.Join(dir, "GOPATH")
|
||||
env := append(os.Environ(), "GOPATH="+gopath)
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(dir, "go.mod"), []byte("module elf_test\n"), 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
asmFile := filepath.Join(dir, "x.s")
|
||||
if err := ioutil.WriteFile(asmFile, []byte(asmSource), 0444); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
goTool := testenv.GoToolPath(t)
|
||||
cmd := exec.Command(goTool, "env", "CC")
|
||||
cmd.Env = env
|
||||
ccb, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cc := strings.TrimSpace(string(ccb))
|
||||
|
||||
cmd = exec.Command(goTool, "env", "GOGCCFLAGS")
|
||||
cmd.Env = env
|
||||
cflagsb, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cflags := strings.Fields(string(cflagsb))
|
||||
|
||||
asmObj := filepath.Join(dir, "x.o")
|
||||
t.Logf("%s %v -c -o %s %s", cc, cflags, asmObj, asmFile)
|
||||
if out, err := exec.Command(cc, append(cflags, "-c", "-o", asmObj, asmFile)...).CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
asm2Obj := filepath.Join(dir, "x2.syso")
|
||||
t.Logf("%s --rename-section .text2=.text1 %s %s", objcopy, asmObj, asm2Obj)
|
||||
if out, err := exec.Command(objcopy, "--rename-section", ".text2=.text1", asmObj, asm2Obj).CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, s := range []string{asmFile, asmObj} {
|
||||
if err := os.Remove(s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
goFile := filepath.Join(dir, "main.go")
|
||||
if err := ioutil.WriteFile(goFile, []byte(goSource), 0444); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cmd = exec.Command(goTool, "build")
|
||||
cmd.Dir = dir
|
||||
cmd.Env = env
|
||||
t.Logf("%s build", goTool)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -982,6 +982,7 @@ func hostobjCopy() (paths []string) {
|
||||
if err != nil {
|
||||
Exitf("cannot reopen %s: %v", h.pn, err)
|
||||
}
|
||||
defer f.Close()
|
||||
if _, err := f.Seek(h.off, 0); err != nil {
|
||||
Exitf("cannot seek %s: %v", h.pn, err)
|
||||
}
|
||||
@@ -1323,9 +1324,24 @@ func (ctxt *Link) hostlink() {
|
||||
ctxt.Logf("\n")
|
||||
}
|
||||
|
||||
if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
|
||||
out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput()
|
||||
if err != nil {
|
||||
Exitf("running %s failed: %v\n%s", argv[0], err, out)
|
||||
} else if len(out) > 0 {
|
||||
}
|
||||
|
||||
// Filter out useless linker warnings caused by bugs outside Go.
|
||||
// See also cmd/go/internal/work/exec.go's gccld method.
|
||||
var save [][]byte
|
||||
for _, line := range bytes.SplitAfter(out, []byte("\n")) {
|
||||
// golang.org/issue/26073 - Apple Xcode bug
|
||||
if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
|
||||
continue
|
||||
}
|
||||
save = append(save, line)
|
||||
}
|
||||
out = bytes.Join(save, nil)
|
||||
|
||||
if len(out) > 0 {
|
||||
// always print external output even if the command is successful, so that we don't
|
||||
// swallow linker warnings (see https://golang.org/issue/17935).
|
||||
ctxt.Logf("%s", out)
|
||||
|
||||
@@ -678,6 +678,8 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
|
||||
// as well use one large chunk.
|
||||
|
||||
// create symbols for elfmapped sections
|
||||
sectsymNames := make(map[string]bool)
|
||||
counter := 0
|
||||
for i := 0; uint(i) < elfobj.nsect; i++ {
|
||||
sect = &elfobj.sect[i]
|
||||
if sect.type_ == SHT_ARM_ATTRIBUTES && sect.name == ".ARM.attributes" {
|
||||
@@ -709,6 +711,12 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("%s(%s)", pkg, sect.name)
|
||||
for sectsymNames[name] {
|
||||
counter++
|
||||
name = fmt.Sprintf("%s(%s%d)", pkg, sect.name, counter)
|
||||
}
|
||||
sectsymNames[name] = true
|
||||
|
||||
s := syms.Lookup(name, localSymVersion)
|
||||
|
||||
switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
|
||||
|
||||
@@ -685,13 +685,14 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
|
||||
}
|
||||
ctx.emitSlice(&fakeMarkStart, text)
|
||||
case trace.EvGCSweepStart:
|
||||
slice := ctx.emitSlice(ev, "SWEEP")
|
||||
slice := ctx.makeSlice(ev, "SWEEP")
|
||||
if done := ev.Link; done != nil && done.Args[0] != 0 {
|
||||
slice.Arg = struct {
|
||||
Swept uint64 `json:"Swept bytes"`
|
||||
Reclaimed uint64 `json:"Reclaimed bytes"`
|
||||
}{done.Args[0], done.Args[1]}
|
||||
}
|
||||
ctx.emit(slice)
|
||||
case trace.EvGoStart, trace.EvGoStartLabel:
|
||||
info := getGInfo(ev.G)
|
||||
if ev.Type == trace.EvGoStartLabel {
|
||||
@@ -846,7 +847,11 @@ func (ctx *traceContext) proc(ev *trace.Event) uint64 {
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx *traceContext) emitSlice(ev *trace.Event, name string) *ViewerEvent {
|
||||
func (ctx *traceContext) emitSlice(ev *trace.Event, name string) {
|
||||
ctx.emit(ctx.makeSlice(ev, name))
|
||||
}
|
||||
|
||||
func (ctx *traceContext) makeSlice(ev *trace.Event, name string) *ViewerEvent {
|
||||
// If ViewerEvent.Dur is not a positive value,
|
||||
// trace viewer handles it as a non-terminating time interval.
|
||||
// Avoid it by setting the field with a small value.
|
||||
@@ -885,7 +890,6 @@ func (ctx *traceContext) emitSlice(ev *trace.Event, name string) *ViewerEvent {
|
||||
sl.Cname = colorLightGrey
|
||||
}
|
||||
}
|
||||
ctx.emit(sl)
|
||||
return sl
|
||||
}
|
||||
|
||||
|
||||
@@ -210,8 +210,9 @@ func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int,
|
||||
|
||||
x3 := new(big.Int).Mul(alpha, alpha)
|
||||
beta8 := new(big.Int).Lsh(beta, 3)
|
||||
beta8.Mod(beta8, curve.P)
|
||||
x3.Sub(x3, beta8)
|
||||
for x3.Sign() == -1 {
|
||||
if x3.Sign() == -1 {
|
||||
x3.Add(x3, curve.P)
|
||||
}
|
||||
x3.Mod(x3, curve.P)
|
||||
|
||||
@@ -164,11 +164,8 @@ type ConnectionState struct {
|
||||
SignedCertificateTimestamps [][]byte // SCTs from the server, if any
|
||||
OCSPResponse []byte // stapled OCSP response from server, if any
|
||||
|
||||
// ExportKeyMaterial returns length bytes of exported key material as
|
||||
// defined in https://tools.ietf.org/html/rfc5705. If context is nil, it is
|
||||
// not used as part of the seed. If Config.Renegotiation was set to allow
|
||||
// renegotiation, this function will always return nil, false.
|
||||
ExportKeyingMaterial func(label string, context []byte, length int) ([]byte, bool)
|
||||
// ekm is a closure exposed via ExportKeyingMaterial.
|
||||
ekm func(label string, context []byte, length int) ([]byte, error)
|
||||
|
||||
// TLSUnique contains the "tls-unique" channel binding value (see RFC
|
||||
// 5929, section 3). For resumed sessions this value will be nil
|
||||
@@ -179,6 +176,14 @@ type ConnectionState struct {
|
||||
TLSUnique []byte
|
||||
}
|
||||
|
||||
// ExportKeyingMaterial returns length bytes of exported key material in a new
|
||||
// slice as defined in https://tools.ietf.org/html/rfc5705. If context is nil,
|
||||
// it is not used as part of the seed. If the connection was set to allow
|
||||
// renegotiation via Config.Renegotiation, this function will return an error.
|
||||
func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
|
||||
return cs.ekm(label, context, length)
|
||||
}
|
||||
|
||||
// ClientAuthType declares the policy the server will follow for
|
||||
// TLS Client Authentication.
|
||||
type ClientAuthType int
|
||||
|
||||
@@ -56,7 +56,7 @@ type Conn struct {
|
||||
// renegotiation is not supported in that case.)
|
||||
secureRenegotiation bool
|
||||
// ekm is a closure for exporting keying material.
|
||||
ekm func(label string, context []byte, length int) ([]byte, bool)
|
||||
ekm func(label string, context []byte, length int) ([]byte, error)
|
||||
|
||||
// clientFinishedIsFirst is true if the client sent the first Finished
|
||||
// message during the most recent handshake. This is recorded because
|
||||
@@ -1315,9 +1315,9 @@ func (c *Conn) ConnectionState() ConnectionState {
|
||||
}
|
||||
}
|
||||
if c.config.Renegotiation != RenegotiateNever {
|
||||
state.ExportKeyingMaterial = noExportedKeyingMaterial
|
||||
state.ekm = noExportedKeyingMaterial
|
||||
} else {
|
||||
state.ExportKeyingMaterial = c.ekm
|
||||
state.ekm = c.ekm
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -979,6 +979,24 @@ func TestRenegotiateTwiceRejected(t *testing.T) {
|
||||
runClientTestTLS12(t, test)
|
||||
}
|
||||
|
||||
func TestHandshakeClientExportKeyingMaterial(t *testing.T) {
|
||||
test := &clientTest{
|
||||
name: "ExportKeyingMaterial",
|
||||
command: []string{"openssl", "s_server"},
|
||||
config: testConfig.Clone(),
|
||||
validate: func(state ConnectionState) error {
|
||||
if km, err := state.ExportKeyingMaterial("test", nil, 42); err != nil {
|
||||
return fmt.Errorf("ExportKeyingMaterial failed: %v", err)
|
||||
} else if len(km) != 42 {
|
||||
return fmt.Errorf("Got %d bytes from ExportKeyingMaterial, wanted %d", len(km), 42)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
runClientTestTLS10(t, test)
|
||||
runClientTestTLS12(t, test)
|
||||
}
|
||||
|
||||
var hostnameInSNITests = []struct {
|
||||
in, out string
|
||||
}{
|
||||
|
||||
@@ -998,6 +998,24 @@ func TestFallbackSCSV(t *testing.T) {
|
||||
runServerTestTLS11(t, test)
|
||||
}
|
||||
|
||||
func TestHandshakeServerExportKeyingMaterial(t *testing.T) {
|
||||
test := &serverTest{
|
||||
name: "ExportKeyingMaterial",
|
||||
command: []string{"openssl", "s_client"},
|
||||
config: testConfig.Clone(),
|
||||
validate: func(state ConnectionState) error {
|
||||
if km, err := state.ExportKeyingMaterial("test", nil, 42); err != nil {
|
||||
return fmt.Errorf("ExportKeyingMaterial failed: %v", err)
|
||||
} else if len(km) != 42 {
|
||||
return fmt.Errorf("Got %d bytes from ExportKeyingMaterial, wanted %d", len(km), 42)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
runServerTestTLS10(t, test)
|
||||
runServerTestTLS12(t, test)
|
||||
}
|
||||
|
||||
func benchmarkHandshakeServer(b *testing.B, cipherSuite uint16, curve CurveID, cert []byte, key crypto.PrivateKey) {
|
||||
config := testConfig.Clone()
|
||||
config.CipherSuites = []uint16{cipherSuite}
|
||||
|
||||
@@ -347,20 +347,20 @@ func (h *finishedHash) discardHandshakeBuffer() {
|
||||
}
|
||||
|
||||
// noExportedKeyingMaterial is used as a value of
|
||||
// ConnectionState.ExportKeyingMaterial when renegotation is enabled and thus
|
||||
// ConnectionState.ekm when renegotation is enabled and thus
|
||||
// we wish to fail all key-material export requests.
|
||||
func noExportedKeyingMaterial(label string, context []byte, length int) ([]byte, bool) {
|
||||
return nil, false
|
||||
func noExportedKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
|
||||
return nil, errors.New("crypto/tls: ExportKeyingMaterial is unavailable when renegotiation is enabled")
|
||||
}
|
||||
|
||||
// ekmFromMasterSecret generates exported keying material as defined in
|
||||
// https://tools.ietf.org/html/rfc5705.
|
||||
func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte) func(string, []byte, int) ([]byte, bool) {
|
||||
return func(label string, context []byte, length int) ([]byte, bool) {
|
||||
func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte) func(string, []byte, int) ([]byte, error) {
|
||||
return func(label string, context []byte, length int) ([]byte, error) {
|
||||
switch label {
|
||||
case "client finished", "server finished", "master secret", "key expansion":
|
||||
// These values are reserved and may not be used.
|
||||
return nil, false
|
||||
return nil, fmt.Errorf("crypto/tls: reserved ExportKeyingMaterial label: %s", label)
|
||||
}
|
||||
|
||||
seedLen := len(serverRandom) + len(clientRandom)
|
||||
@@ -374,7 +374,7 @@ func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clien
|
||||
|
||||
if context != nil {
|
||||
if len(context) >= 1<<16 {
|
||||
return nil, false
|
||||
return nil, fmt.Errorf("crypto/tls: ExportKeyingMaterial context too long")
|
||||
}
|
||||
seed = append(seed, byte(len(context)>>8), byte(len(context)))
|
||||
seed = append(seed, context...)
|
||||
@@ -382,6 +382,6 @@ func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clien
|
||||
|
||||
keyMaterial := make([]byte, length)
|
||||
prfForVersion(version, suite)(keyMaterial, masterSecret, []byte(label), seed)
|
||||
return keyMaterial, true
|
||||
return keyMaterial, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,14 +70,14 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
|
||||
}
|
||||
|
||||
ekm := ekmFromMasterSecret(test.version, test.suite, masterSecret, clientRandom, serverRandom)
|
||||
contextKeyingMaterial, ok := ekm("label", []byte("context"), 32)
|
||||
if !ok {
|
||||
t.Fatalf("ekmFromMasterSecret failed")
|
||||
contextKeyingMaterial, err := ekm("label", []byte("context"), 32)
|
||||
if err != nil {
|
||||
t.Fatalf("ekmFromMasterSecret failed: %v", err)
|
||||
}
|
||||
|
||||
noContextKeyingMaterial, ok := ekm("label", nil, 32)
|
||||
if !ok {
|
||||
t.Fatalf("ekmFromMasterSecret failed")
|
||||
noContextKeyingMaterial, err := ekm("label", nil, 32)
|
||||
if err != nil {
|
||||
t.Fatalf("ekmFromMasterSecret failed: %v", err)
|
||||
}
|
||||
|
||||
if hex.EncodeToString(contextKeyingMaterial) != test.contextKeyingMaterial ||
|
||||
|
||||
89
src/crypto/tls/testdata/Client-TLSv10-ExportKeyingMaterial
vendored
Normal file
89
src/crypto/tls/testdata/Client-TLSv10-ExportKeyingMaterial
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
>>> Flow 1 (client to server)
|
||||
00000000 16 03 01 00 95 01 00 00 91 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 00 00 2c cc a8 |.............,..|
|
||||
00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
|
||||
00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
|
||||
00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..|
|
||||
00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
|
||||
00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................|
|
||||
00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................|
|
||||
00000090 03 ff 01 00 01 00 00 12 00 00 |..........|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 16 03 01 00 59 02 00 00 55 03 01 67 4f 02 da 87 |....Y...U..gO...|
|
||||
00000010 52 30 9a f0 3b e0 63 42 bf 6c 18 58 00 06 70 cf |R0..;.cB.l.X..p.|
|
||||
00000020 2a 27 5a 00 a7 57 49 fe 03 dd 3b 20 7c 2c 74 00 |*'Z..WI...; |,t.|
|
||||
00000030 6e b2 35 ca 1b b5 8c 46 f7 78 ab 11 92 43 8c f6 |n.5....F.x...C..|
|
||||
00000040 97 d3 b8 07 4c 9c 95 2b 08 fe e8 82 c0 13 00 00 |....L..+........|
|
||||
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
|
||||
00000060 01 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 01 00 |.=.`.\!.;.......|
|
||||
000002c0 aa 0c 00 00 a6 03 00 1d 20 a0 0e 1d 92 2d b0 a5 |........ ....-..|
|
||||
000002d0 f0 ab d5 79 a0 bb 12 ff 23 46 bc 27 0d 73 ff 3e |...y....#F.'.s.>|
|
||||
000002e0 ad 06 d6 57 6b c2 11 76 2d 00 80 77 bf cd 2b cb |...Wk..v-..w..+.|
|
||||
000002f0 66 c2 fa 30 ed b1 e7 44 79 1b 28 e6 89 62 17 07 |f..0...Dy.(..b..|
|
||||
00000300 82 c1 5f dc b2 20 4e 42 ed 54 d6 28 3a 2a e3 a3 |.._.. NB.T.(:*..|
|
||||
00000310 79 06 e3 08 3c c1 3e b9 c6 41 71 2f d0 29 82 36 |y...<.>..Aq/.).6|
|
||||
00000320 ef 8d 67 c8 77 d0 32 d3 33 5f 77 92 dd 98 bb 03 |..g.w.2.3_w.....|
|
||||
00000330 cc 0b a6 75 8f 4a 1d f5 6e 1b 06 5b 4a 8b 16 a4 |...u.J..n..[J...|
|
||||
00000340 c1 ce 11 9d 70 bc 62 7f 58 a5 86 76 91 3d 3a 04 |....p.b.X..v.=:.|
|
||||
00000350 93 92 89 42 9b a7 7d 9d 75 25 6d 98 f3 e6 68 7e |...B..}.u%m...h~|
|
||||
00000360 a8 c6 b1 db a7 95 63 39 94 5a 05 16 03 01 00 04 |......c9.Z......|
|
||||
00000370 0e 00 00 00 |....|
|
||||
>>> Flow 3 (client to server)
|
||||
00000000 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
|
||||
00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
|
||||
00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 01 00 01 01 |....._X.;t......|
|
||||
00000030 16 03 01 00 30 73 ad 46 66 66 e8 bd 44 e4 bf 71 |....0s.Fff..D..q|
|
||||
00000040 a2 d4 87 e2 4b a3 4a b2 a0 ca ed ac 61 8c 1e 7f |....K.J.....a...|
|
||||
00000050 68 bf 6f 98 b1 fb 10 1a 5a e6 36 61 91 ac c4 55 |h.o.....Z.6a...U|
|
||||
00000060 a3 4d 69 66 6e |.Mifn|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 14 03 01 00 01 01 16 03 01 00 30 57 aa 5c d5 dc |..........0W.\..|
|
||||
00000010 83 4b 23 80 34 4e 36 e8 d6 f3 40 7e ae 12 44 a6 |.K#.4N6...@~..D.|
|
||||
00000020 c7 48 99 99 0a 85 3c 59 75 32 4e 88 3c 98 a0 23 |.H....<Yu2N.<..#|
|
||||
00000030 78 c8 a7 2b 43 25 6a ad d1 78 54 |x..+C%j..xT|
|
||||
>>> Flow 5 (client to server)
|
||||
00000000 17 03 01 00 20 e4 9c f4 fa 6b e8 85 87 6f 20 45 |.... ....k...o E|
|
||||
00000010 71 d3 e2 9e e3 14 2a 7c 64 e8 11 53 fd 93 c1 4a |q.....*|d..S...J|
|
||||
00000020 1b 94 f8 48 78 17 03 01 00 20 b9 41 32 1d e8 70 |...Hx.... .A2..p|
|
||||
00000030 87 5f 2c c6 67 d1 77 3c 30 83 0c 66 35 eb 1d da |._,.g.w<0..f5...|
|
||||
00000040 6e dd 30 ff 82 05 5f f1 cd e7 15 03 01 00 20 6c |n.0..._....... l|
|
||||
00000050 47 82 5e 90 5b 84 15 78 05 bd 48 63 d5 46 2f 7e |G.^.[..x..Hc.F/~|
|
||||
00000060 83 49 ce 3c 0f 04 92 52 5b e7 d5 cf 2c bf 65 |.I.<...R[...,.e|
|
||||
84
src/crypto/tls/testdata/Client-TLSv12-ExportKeyingMaterial
vendored
Normal file
84
src/crypto/tls/testdata/Client-TLSv12-ExportKeyingMaterial
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
>>> Flow 1 (client to server)
|
||||
00000000 16 03 01 00 95 01 00 00 91 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 00 00 2c cc a8 |.............,..|
|
||||
00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
|
||||
00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
|
||||
00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..|
|
||||
00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
|
||||
00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................|
|
||||
00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................|
|
||||
00000090 03 ff 01 00 01 00 00 12 00 00 |..........|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 16 03 03 00 59 02 00 00 55 03 03 fc 37 e8 a4 e3 |....Y...U...7...|
|
||||
00000010 5d da a5 95 0b fb e0 c3 d9 78 8b 91 bd 5c 1c b1 |]........x...\..|
|
||||
00000020 c6 8d 69 62 f9 c6 0f 12 da 46 ba 20 34 a3 22 f2 |..ib.....F. 4.".|
|
||||
00000030 a9 f7 da 3a c4 5f 6f f7 4b be df 03 e5 b6 d0 ff |...:._o.K.......|
|
||||
00000040 ca 54 68 59 57 53 63 a5 2f 91 1d 1e cc a8 00 00 |.ThYWSc./.......|
|
||||
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 cc e9 71 f5 36 52 5a |........ ..q.6RZ|
|
||||
000002d0 d8 19 ce e4 0d 41 8d a6 9b f3 19 56 8d 81 fe 84 |.....A.....V....|
|
||||
000002e0 71 2f d7 fb e7 86 23 4c 04 04 01 00 80 90 da 29 |q/....#L.......)|
|
||||
000002f0 79 18 70 e8 81 66 83 70 97 f1 d1 5f dc 1d a2 0a |y.p..f.p..._....|
|
||||
00000300 94 d8 e8 b8 32 4f 03 34 0b af e8 2d 94 b2 eb 30 |....2O.4...-...0|
|
||||
00000310 57 b5 a5 92 9e 9a df a6 bc 3e 25 0e 18 cb ea 84 |W........>%.....|
|
||||
00000320 34 89 08 8a d4 be 16 a3 5d 3a 7d 32 10 9b 41 1c |4.......]:}2..A.|
|
||||
00000330 2a 1e 05 68 5f fa d9 56 30 b6 44 08 b0 a5 25 5a |*..h_..V0.D...%Z|
|
||||
00000340 c3 60 c0 9a 98 fd 48 5f a4 18 d0 15 0f fb b3 ea |.`....H_........|
|
||||
00000350 b9 c4 e3 c6 0c 27 51 64 01 de 65 78 c7 a0 57 df |.....'Qd..ex..W.|
|
||||
00000360 9b de 2f 74 bc 72 e5 e0 57 7c 59 e6 ae 16 03 03 |../t.r..W|Y.....|
|
||||
00000370 00 04 0e 00 00 00 |......|
|
||||
>>> Flow 3 (client to server)
|
||||
00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
|
||||
00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
|
||||
00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
|
||||
00000030 16 03 03 00 20 92 0a 4e aa 2d b3 9b c8 b9 80 28 |.... ..N.-.....(|
|
||||
00000040 f3 22 e2 57 15 ff a1 9a 33 9b e8 4c 5c dc f4 29 |.".W....3..L\..)|
|
||||
00000050 7d 25 d7 df bc |}%...|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 14 03 03 00 01 01 16 03 03 00 20 91 85 06 0e 00 |.......... .....|
|
||||
00000010 ad 96 2e 1c a5 4d f7 63 f9 84 1c 6e da 54 0b e0 |.....M.c...n.T..|
|
||||
00000020 44 37 6a 90 4c fd f5 e8 45 1d ce |D7j.L...E..|
|
||||
>>> Flow 5 (client to server)
|
||||
00000000 17 03 03 00 16 4c e8 8a e0 a6 95 f3 df 37 8a 2d |.....L.......7.-|
|
||||
00000010 4f 11 ce a6 53 16 2c b0 bb c5 7f 15 03 03 00 12 |O...S.,.........|
|
||||
00000020 4e 91 d8 67 c5 16 d2 4e cc b8 0a 00 76 91 68 7a |N..g...N....v.hz|
|
||||
00000030 85 2e |..|
|
||||
92
src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial
vendored
Normal file
92
src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
>>> Flow 1 (client to server)
|
||||
00000000 16 03 01 00 61 01 00 00 5d 03 01 f4 ec 99 73 ec |....a...].....s.|
|
||||
00000010 36 30 c7 0b 26 33 a2 c4 26 8e 9f 04 f7 5b e7 4f |60..&3..&....[.O|
|
||||
00000020 86 85 14 bf f7 49 96 a4 ae c9 1d 00 00 12 c0 0a |.....I..........|
|
||||
00000030 c0 14 00 39 c0 09 c0 13 00 33 00 35 00 2f 00 ff |...9.....3.5./..|
|
||||
00000040 01 00 00 22 00 0b 00 04 03 00 01 02 00 0a 00 0a |..."............|
|
||||
00000050 00 08 00 1d 00 17 00 19 00 18 00 23 00 00 00 16 |...........#....|
|
||||
00000060 00 00 00 17 00 00 |......|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 16 03 01 00 35 02 00 00 31 03 01 00 00 00 00 00 |....5...1.......|
|
||||
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 00 c0 14 00 00 |................|
|
||||
00000030 09 00 23 00 00 ff 01 00 01 00 16 03 01 02 59 0b |..#...........Y.|
|
||||
00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..|
|
||||
00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.|
|
||||
00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
|
||||
00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1|
|
||||
00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
|
||||
00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000|
|
||||
000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
|
||||
000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go|
|
||||
000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..|
|
||||
000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........|
|
||||
000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...|
|
||||
000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R|
|
||||
00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....|
|
||||
00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y.@.Om..+.....g.|
|
||||
00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..|
|
||||
00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.|
|
||||
00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.|
|
||||
00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C|
|
||||
00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......|
|
||||
00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......|
|
||||
00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.|
|
||||
00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...|
|
||||
000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......|
|
||||
000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........|
|
||||
000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..|
|
||||
000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~|
|
||||
000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.|
|
||||
000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g|
|
||||
00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....|
|
||||
00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0.@+[P.|
|
||||
00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.|
|
||||
00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....|
|
||||
00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ |
|
||||
00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\|
|
||||
00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...|
|
||||
00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |....@.a.Lr+...F.|
|
||||
00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`|
|
||||
00000290 84 5c 21 d3 3b e9 fa e7 16 03 01 00 aa 0c 00 00 |.\!.;...........|
|
||||
000002a0 a6 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 da |.... /.}.G.bC.(.|
|
||||
000002b0 ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 |._.).0..........|
|
||||
000002c0 5f 58 cb 3b 74 00 80 8e fe 28 f2 06 d8 b9 d6 74 |_X.;t....(.....t|
|
||||
000002d0 72 34 dc fa 00 38 56 1a fc a1 68 e8 ca 8f 7a 61 |r4...8V...h...za|
|
||||
000002e0 92 e2 2a 63 ce 4d 96 c6 bb 84 82 41 2d 97 35 13 |..*c.M.....A-.5.|
|
||||
000002f0 e1 ff 4c ec f2 e6 62 16 15 35 da 8a 57 55 cb 28 |..L...b..5..WU.(|
|
||||
00000300 26 35 e6 86 00 b0 92 44 b7 40 7b 6a c4 b0 b8 10 |&5.....D.@{j....|
|
||||
00000310 b7 16 97 a7 26 eb 1e 0b 99 b3 22 4a 6b 7f 0b 69 |....&....."Jk..i|
|
||||
00000320 0d 21 1e 33 6d fd 78 b5 62 68 53 db 62 69 ba b4 |.!.3m.x.bhS.bi..|
|
||||
00000330 bc 74 b3 d4 ce a2 41 d7 ba 62 aa cc b2 39 65 86 |.t....A..b...9e.|
|
||||
00000340 5f 00 68 e2 16 a5 13 16 03 01 00 04 0e 00 00 00 |_.h.............|
|
||||
>>> Flow 3 (client to server)
|
||||
00000000 16 03 01 00 25 10 00 00 21 20 81 08 e4 37 1d 03 |....%...! ...7..|
|
||||
00000010 87 5a 00 68 ae 49 76 08 4a e2 20 82 0b e5 7c 3e |.Z.h.Iv.J. ...|>|
|
||||
00000020 90 49 9b c3 b9 c7 c9 3c 29 24 14 03 01 00 01 01 |.I.....<)$......|
|
||||
00000030 16 03 01 00 30 33 07 d5 08 ca ae f9 70 50 93 0a |....03......pP..|
|
||||
00000040 55 2e e0 df 1d 88 ae 1e 06 17 47 64 a3 52 36 37 |U.........Gd.R67|
|
||||
00000050 d5 ca f1 b1 d2 76 7b f8 89 59 13 e9 ab b1 cb dc |.....v{..Y......|
|
||||
00000060 1f a8 89 f4 2f |..../|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 16 03 01 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
|
||||
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
|
||||
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
|
||||
00000030 6d ec a4 83 61 a4 a1 9c 14 de f8 59 c8 c7 f0 10 |m...a......Y....|
|
||||
00000040 08 fe c9 37 29 ed 47 05 d2 bd a8 4c 05 b9 8c f8 |...7).G....L....|
|
||||
00000050 b5 4d e4 a6 30 0f 49 4a b1 73 1f 89 73 c8 bb 36 |.M..0.IJ.s..s..6|
|
||||
00000060 14 9d d2 95 70 33 94 fb 82 e6 fe 3e 64 8c 9d e8 |....p3.....>d...|
|
||||
00000070 e3 e5 93 3d fe 4e 23 a3 97 8a a3 91 80 c9 00 01 |...=.N#.........|
|
||||
00000080 a6 f0 47 cf 11 a6 90 14 03 01 00 01 01 16 03 01 |..G.............|
|
||||
00000090 00 30 1f 70 17 a1 30 82 5a 32 e7 aa a1 7f 1b f6 |.0.p..0.Z2......|
|
||||
000000a0 d8 aa 6a 51 64 1b 4a f1 94 12 08 2f 5d 95 fe 83 |..jQd.J..../]...|
|
||||
000000b0 52 c8 3b d4 58 73 50 19 b8 08 61 b3 3a 5d f6 d3 |R.;.XsP...a.:]..|
|
||||
000000c0 67 e6 17 03 01 00 20 bd 79 44 08 9d 86 cf 5e e9 |g..... .yD....^.|
|
||||
000000d0 e4 3c 80 ed b7 18 10 07 0f 42 85 ca a4 51 fd 9b |.<.......B...Q..|
|
||||
000000e0 38 3e 04 7e 72 6e 80 17 03 01 00 30 2c 46 c2 71 |8>.~rn.....0,F.q|
|
||||
000000f0 4a 83 46 eb 63 87 f5 83 b4 72 70 4f a3 59 b3 ff |J.F.c....rpO.Y..|
|
||||
00000100 3c 00 74 12 db 33 51 4c 7c e0 c1 27 44 20 68 25 |<.t..3QL|..'D h%|
|
||||
00000110 95 f1 37 2a 24 f1 85 a3 5a e4 50 fe 15 03 01 00 |..7*$...Z.P.....|
|
||||
00000120 20 72 01 cc 74 d5 b4 6b 05 ce de f0 b4 fe 4f 6b | r..t..k......Ok|
|
||||
00000130 a8 8f ad 5a c2 7d 40 65 d6 a2 57 52 b8 8a c5 4f |...Z.}@e..WR...O|
|
||||
00000140 d9 |.|
|
||||
92
src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial
vendored
Normal file
92
src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
>>> Flow 1 (client to server)
|
||||
00000000 16 03 01 00 ab 01 00 00 a7 03 03 7a 49 9d 20 62 |...........zI. b|
|
||||
00000010 45 8d 0c 1e 8e eb b1 5e 73 62 6d 48 61 31 cb 1a |E......^sbmHa1..|
|
||||
00000020 89 b2 68 1b 2c cb 35 87 2a 17 fb 00 00 38 c0 2c |..h.,.5.*....8.,|
|
||||
00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..|
|
||||
00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....|
|
||||
00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<|
|
||||
00000060 00 35 00 2f 00 ff 01 00 00 46 00 0b 00 04 03 00 |.5./.....F......|
|
||||
00000070 01 02 00 0a 00 0a 00 08 00 1d 00 17 00 19 00 18 |................|
|
||||
00000080 00 23 00 00 00 16 00 00 00 17 00 00 00 0d 00 20 |.#............. |
|
||||
00000090 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................|
|
||||
000000a0 04 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 |................|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
|
||||
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 00 c0 30 00 00 |.............0..|
|
||||
00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 59 0b |..#...........Y.|
|
||||
00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..|
|
||||
00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.|
|
||||
00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
|
||||
00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1|
|
||||
00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
|
||||
00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000|
|
||||
000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
|
||||
000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go|
|
||||
000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..|
|
||||
000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........|
|
||||
000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...|
|
||||
000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R|
|
||||
00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....|
|
||||
00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y.@.Om..+.....g.|
|
||||
00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..|
|
||||
00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.|
|
||||
00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.|
|
||||
00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C|
|
||||
00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......|
|
||||
00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......|
|
||||
00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.|
|
||||
00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...|
|
||||
000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......|
|
||||
000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........|
|
||||
000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..|
|
||||
000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~|
|
||||
000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.|
|
||||
000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g|
|
||||
00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....|
|
||||
00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0.@+[P.|
|
||||
00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.|
|
||||
00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....|
|
||||
00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ |
|
||||
00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\|
|
||||
00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...|
|
||||
00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |....@.a.Lr+...F.|
|
||||
00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`|
|
||||
00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 00 |.\!.;...........|
|
||||
000002a0 a8 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 da |.... /.}.G.bC.(.|
|
||||
000002b0 ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 |._.).0..........|
|
||||
000002c0 5f 58 cb 3b 74 06 01 00 80 7f ee dd 6b 38 23 29 |_X.;t.......k8#)|
|
||||
000002d0 56 ff d2 c2 08 86 52 b6 e3 8a d5 fe 47 79 5e ef |V.....R.....Gy^.|
|
||||
000002e0 99 7a 0b d7 44 84 b9 2f 7a 2c 64 4f b3 7c aa 44 |.z..D../z,dO.|.D|
|
||||
000002f0 aa 38 5d 1b 69 16 9f f2 7d f8 24 43 47 ad 31 bc |.8].i...}.$CG.1.|
|
||||
00000300 f5 3d b8 c8 33 6e 3f 6f 2b ea 19 a2 30 32 2b 2a |.=..3n?o+...02+*|
|
||||
00000310 81 64 3c ee ed 78 4c fa 80 fd e7 5f ef 85 98 d4 |.d<..xL...._....|
|
||||
00000320 48 06 b8 f5 5e 1e e6 f3 42 a8 2f 99 5f ea b3 ba |H...^...B./._...|
|
||||
00000330 8e a8 31 99 85 f2 46 11 a3 d2 c6 81 4b f1 22 7d |..1...F.....K."}|
|
||||
00000340 d7 45 04 f1 a6 d6 7e 8f 9d 16 03 03 00 04 0e 00 |.E....~.........|
|
||||
00000350 00 00 |..|
|
||||
>>> Flow 3 (client to server)
|
||||
00000000 16 03 03 00 25 10 00 00 21 20 22 e7 e7 61 a9 27 |....%...! "..a.'|
|
||||
00000010 7b 93 d1 42 76 dd 16 32 e8 92 37 37 2f fd 0d 92 |{..Bv..2..77/...|
|
||||
00000020 1f 8e b7 c5 69 40 d3 1a 7d 06 14 03 03 00 01 01 |....i@..}.......|
|
||||
00000030 16 03 03 00 28 4e 7f b2 a2 20 5d cf a1 5a de 42 |....(N... ]..Z.B|
|
||||
00000040 c5 72 c3 ef c3 23 a7 2c f3 5b 3d a4 81 21 ac db |.r...#.,.[=..!..|
|
||||
00000050 44 1c f3 a1 83 aa a1 b7 85 9a c7 23 03 |D..........#.|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
|
||||
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
|
||||
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
|
||||
00000030 6f ec 80 83 61 3f 55 e3 9d ab 39 87 5b d0 ba 44 |o...a?U...9.[..D|
|
||||
00000040 07 91 a8 d0 37 8a 7e 51 0d 00 97 ec 1b 61 f3 3b |....7.~Q.....a.;|
|
||||
00000050 9f 29 24 d5 98 f7 4d 3b 80 ef 2f 4d aa 02 98 93 |.)$...M;../M....|
|
||||
00000060 81 03 87 d8 06 33 94 f5 ed 5d cc 8f 57 97 70 26 |.....3...]..W.p&|
|
||||
00000070 00 dc 0d d2 96 16 a2 6d fc be 8d 4b fa 5f b3 04 |.......m...K._..|
|
||||
00000080 ce bb 48 ee c0 75 23 14 03 03 00 01 01 16 03 03 |..H..u#.........|
|
||||
00000090 00 28 00 00 00 00 00 00 00 00 3a 69 e0 40 e2 d1 |.(........:i.@..|
|
||||
000000a0 a6 96 33 0f b3 58 5a dc 41 ea d1 80 44 66 9f 2e |..3..XZ.A...Df..|
|
||||
000000b0 00 e4 9e 10 13 56 b4 1b c9 42 17 03 03 00 25 00 |.....V...B....%.|
|
||||
000000c0 00 00 00 00 00 00 01 88 f3 d9 5b ed 6b 3c 70 0c |..........[.k<p.|
|
||||
000000d0 df 36 9d 1c f6 f6 83 38 53 ad e2 06 47 3c e2 9f |.6.....8S...G<..|
|
||||
000000e0 42 87 d7 8a 15 03 03 00 1a 00 00 00 00 00 00 00 |B...............|
|
||||
000000f0 02 df 4a 92 13 c4 e6 ac 76 25 c6 72 27 be d6 09 |..J.....v%.r'...|
|
||||
00000100 eb 90 ed |...|
|
||||
@@ -7,6 +7,7 @@ package tls
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
@@ -907,3 +908,11 @@ func BenchmarkLatency(b *testing.B) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnectionStateMarshal(t *testing.T) {
|
||||
cs := &ConnectionState{}
|
||||
_, err := json.Marshal(cs)
|
||||
if err != nil {
|
||||
t.Errorf("json.Marshal failed on ConnectionState: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,32 +65,21 @@ func SystemCertPool() (*CertPool, error) {
|
||||
return loadSystemRoots()
|
||||
}
|
||||
|
||||
// findVerifiedParents attempts to find certificates in s which have signed the
|
||||
// given certificate. If any candidates were rejected then errCert will be set
|
||||
// to one of them, arbitrarily, and err will contain the reason that it was
|
||||
// rejected.
|
||||
func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) {
|
||||
// findPotentialParents returns the indexes of certificates in s which might
|
||||
// have signed cert. The caller must not modify the returned slice.
|
||||
func (s *CertPool) findPotentialParents(cert *Certificate) []int {
|
||||
if s == nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
var candidates []int
|
||||
|
||||
var candidates []int
|
||||
if len(cert.AuthorityKeyId) > 0 {
|
||||
candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
|
||||
}
|
||||
if len(candidates) == 0 {
|
||||
candidates = s.byName[string(cert.RawIssuer)]
|
||||
}
|
||||
|
||||
for _, c := range candidates {
|
||||
if err = cert.CheckSignatureFrom(s.certs[c]); err == nil {
|
||||
parents = append(parents, c)
|
||||
} else {
|
||||
errCert = s.certs[c]
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
return candidates
|
||||
}
|
||||
|
||||
func (s *CertPool) contains(cert *Certificate) bool {
|
||||
|
||||
@@ -16,7 +16,135 @@ package x509
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Security/Security.h>
|
||||
|
||||
// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
|
||||
static Boolean isSSLPolicy(SecPolicyRef policyRef) {
|
||||
if (!policyRef) {
|
||||
return false;
|
||||
}
|
||||
CFDictionaryRef properties = SecPolicyCopyProperties(policyRef);
|
||||
if (properties == NULL) {
|
||||
return false;
|
||||
}
|
||||
Boolean isSSL = false;
|
||||
CFTypeRef value = NULL;
|
||||
if (CFDictionaryGetValueIfPresent(properties, kSecPolicyOid, (const void **)&value)) {
|
||||
isSSL = CFEqual(value, kSecPolicyAppleSSL);
|
||||
}
|
||||
CFRelease(properties);
|
||||
return isSSL;
|
||||
}
|
||||
|
||||
// sslTrustSettingsResult obtains the final kSecTrustSettingsResult value
|
||||
// for a certificate in the user or admin domain, combining usage constraints
|
||||
// for the SSL SecTrustSettingsPolicy, ignoring SecTrustSettingsKeyUsage and
|
||||
// kSecTrustSettingsAllowedError.
|
||||
// https://developer.apple.com/documentation/security/1400261-sectrustsettingscopytrustsetting
|
||||
static SInt32 sslTrustSettingsResult(SecCertificateRef cert) {
|
||||
CFArrayRef trustSettings = NULL;
|
||||
OSStatus err = SecTrustSettingsCopyTrustSettings(cert, kSecTrustSettingsDomainUser, &trustSettings);
|
||||
|
||||
// According to Apple's SecTrustServer.c, "user trust settings overrule admin trust settings",
|
||||
// but the rules of the override are unclear. Let's assume admin trust settings are applicable
|
||||
// if and only if user trust settings fail to load or are NULL.
|
||||
if (err != errSecSuccess || trustSettings == NULL) {
|
||||
if (trustSettings != NULL) CFRelease(trustSettings);
|
||||
err = SecTrustSettingsCopyTrustSettings(cert, kSecTrustSettingsDomainAdmin, &trustSettings);
|
||||
}
|
||||
|
||||
// > no trust settings [...] means "this certificate must be verified to a known trusted certificate”
|
||||
if (err != errSecSuccess || trustSettings == NULL) {
|
||||
if (trustSettings != NULL) CFRelease(trustSettings);
|
||||
return kSecTrustSettingsResultUnspecified;
|
||||
}
|
||||
|
||||
// > An empty trust settings array means "always trust this certificate” with an
|
||||
// > overall trust setting for the certificate of kSecTrustSettingsResultTrustRoot.
|
||||
if (CFArrayGetCount(trustSettings) == 0) {
|
||||
CFRelease(trustSettings);
|
||||
return kSecTrustSettingsResultTrustRoot;
|
||||
}
|
||||
|
||||
// kSecTrustSettingsResult is defined as CFSTR("kSecTrustSettingsResult"),
|
||||
// but the Go linker's internal linking mode can't handle CFSTR relocations.
|
||||
// Create our own dynamic string instead and release it below.
|
||||
CFStringRef _kSecTrustSettingsResult = CFStringCreateWithCString(
|
||||
NULL, "kSecTrustSettingsResult", kCFStringEncodingUTF8);
|
||||
CFStringRef _kSecTrustSettingsPolicy = CFStringCreateWithCString(
|
||||
NULL, "kSecTrustSettingsPolicy", kCFStringEncodingUTF8);
|
||||
CFStringRef _kSecTrustSettingsPolicyString = CFStringCreateWithCString(
|
||||
NULL, "kSecTrustSettingsPolicyString", kCFStringEncodingUTF8);
|
||||
|
||||
CFIndex m; SInt32 result = 0;
|
||||
for (m = 0; m < CFArrayGetCount(trustSettings); m++) {
|
||||
CFDictionaryRef tSetting = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, m);
|
||||
|
||||
// First, check if this trust setting applies to our policy. We assume
|
||||
// only one will. The docs suggest that there might be multiple applying
|
||||
// but don't explain how to combine them.
|
||||
SecPolicyRef policyRef;
|
||||
if (CFDictionaryGetValueIfPresent(tSetting, _kSecTrustSettingsPolicy, (const void**)&policyRef)) {
|
||||
if (!isSSLPolicy(policyRef)) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CFDictionaryContainsKey(tSetting, _kSecTrustSettingsPolicyString)) {
|
||||
// Restricted to a hostname, not a root.
|
||||
continue;
|
||||
}
|
||||
|
||||
CFNumberRef cfNum;
|
||||
if (CFDictionaryGetValueIfPresent(tSetting, _kSecTrustSettingsResult, (const void**)&cfNum)) {
|
||||
CFNumberGetValue(cfNum, kCFNumberSInt32Type, &result);
|
||||
} else {
|
||||
// > If the value of the kSecTrustSettingsResult component is not
|
||||
// > kSecTrustSettingsResultUnspecified for a usage constraints dictionary that has
|
||||
// > no constraints, the default value kSecTrustSettingsResultTrustRoot is assumed.
|
||||
result = kSecTrustSettingsResultTrustRoot;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// If trust settings are present, but none of them match the policy...
|
||||
// the docs don't tell us what to do.
|
||||
//
|
||||
// "Trust settings for a given use apply if any of the dictionaries in the
|
||||
// certificate’s trust settings array satisfies the specified use." suggests
|
||||
// that it's as if there were no trust settings at all, so we should probably
|
||||
// fallback to the admin trust settings. TODO.
|
||||
if (result == 0) {
|
||||
result = kSecTrustSettingsResultUnspecified;
|
||||
}
|
||||
|
||||
CFRelease(_kSecTrustSettingsPolicy);
|
||||
CFRelease(_kSecTrustSettingsPolicyString);
|
||||
CFRelease(_kSecTrustSettingsResult);
|
||||
CFRelease(trustSettings);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// isRootCertificate reports whether Subject and Issuer match.
|
||||
static Boolean isRootCertificate(SecCertificateRef cert, CFErrorRef *errRef) {
|
||||
CFDataRef subjectName = SecCertificateCopyNormalizedSubjectContent(cert, errRef);
|
||||
if (*errRef != NULL) {
|
||||
return false;
|
||||
}
|
||||
CFDataRef issuerName = SecCertificateCopyNormalizedIssuerContent(cert, errRef);
|
||||
if (*errRef != NULL) {
|
||||
CFRelease(subjectName);
|
||||
return false;
|
||||
}
|
||||
Boolean equal = CFEqual(subjectName, issuerName);
|
||||
CFRelease(subjectName);
|
||||
CFRelease(issuerName);
|
||||
return equal;
|
||||
}
|
||||
|
||||
// FetchPEMRoots fetches the system's list of trusted X.509 root certificates
|
||||
// for the kSecTrustSettingsPolicy SSL.
|
||||
//
|
||||
// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
|
||||
// certificates of the system. On failure, the function returns -1.
|
||||
@@ -24,26 +152,28 @@ package x509
|
||||
//
|
||||
// Note: The CFDataRef returned in pemRoots and untrustedPemRoots must
|
||||
// be released (using CFRelease) after we've consumed its content.
|
||||
int FetchPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots) {
|
||||
int FetchPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots, bool debugDarwinRoots) {
|
||||
int i;
|
||||
|
||||
if (debugDarwinRoots) {
|
||||
printf("crypto/x509: kSecTrustSettingsResultInvalid = %d\n", kSecTrustSettingsResultInvalid);
|
||||
printf("crypto/x509: kSecTrustSettingsResultTrustRoot = %d\n", kSecTrustSettingsResultTrustRoot);
|
||||
printf("crypto/x509: kSecTrustSettingsResultTrustAsRoot = %d\n", kSecTrustSettingsResultTrustAsRoot);
|
||||
printf("crypto/x509: kSecTrustSettingsResultDeny = %d\n", kSecTrustSettingsResultDeny);
|
||||
printf("crypto/x509: kSecTrustSettingsResultUnspecified = %d\n", kSecTrustSettingsResultUnspecified);
|
||||
}
|
||||
|
||||
// Get certificates from all domains, not just System, this lets
|
||||
// the user add CAs to their "login" keychain, and Admins to add
|
||||
// to the "System" keychain
|
||||
SecTrustSettingsDomain domains[] = { kSecTrustSettingsDomainSystem,
|
||||
kSecTrustSettingsDomainAdmin,
|
||||
kSecTrustSettingsDomainUser };
|
||||
kSecTrustSettingsDomainAdmin, kSecTrustSettingsDomainUser };
|
||||
|
||||
int numDomains = sizeof(domains)/sizeof(SecTrustSettingsDomain);
|
||||
if (pemRoots == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// kSecTrustSettingsResult is defined as CFSTR("kSecTrustSettingsResult"),
|
||||
// but the Go linker's internal linking mode can't handle CFSTR relocations.
|
||||
// Create our own dynamic string instead and release it below.
|
||||
CFStringRef policy = CFStringCreateWithCString(NULL, "kSecTrustSettingsResult", kCFStringEncodingUTF8);
|
||||
|
||||
CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
||||
CFMutableDataRef combinedUntrustedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
||||
for (i = 0; i < numDomains; i++) {
|
||||
@@ -57,102 +187,81 @@ int FetchPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots) {
|
||||
CFIndex numCerts = CFArrayGetCount(certs);
|
||||
for (j = 0; j < numCerts; j++) {
|
||||
CFDataRef data = NULL;
|
||||
CFErrorRef errRef = NULL;
|
||||
CFArrayRef trustSettings = NULL;
|
||||
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, j);
|
||||
if (cert == NULL) {
|
||||
continue;
|
||||
}
|
||||
// We only want trusted certs.
|
||||
int untrusted = 0;
|
||||
int trustAsRoot = 0;
|
||||
int trustRoot = 0;
|
||||
if (i == 0) {
|
||||
trustAsRoot = 1;
|
||||
} else {
|
||||
int k;
|
||||
CFIndex m;
|
||||
|
||||
SInt32 result;
|
||||
if (domains[i] == kSecTrustSettingsDomainSystem) {
|
||||
// Certs found in the system domain are always trusted. If the user
|
||||
// configures "Never Trust" on such a cert, it will also be found in the
|
||||
// admin or user domain, causing it to be added to untrustedPemRoots. The
|
||||
// Go code will then clean this up.
|
||||
result = kSecTrustSettingsResultTrustRoot;
|
||||
} else {
|
||||
result = sslTrustSettingsResult(cert);
|
||||
if (debugDarwinRoots) {
|
||||
CFErrorRef errRef = NULL;
|
||||
CFStringRef summary = SecCertificateCopyShortDescription(NULL, cert, &errRef);
|
||||
if (errRef != NULL) {
|
||||
printf("crypto/x509: SecCertificateCopyShortDescription failed\n");
|
||||
CFRelease(errRef);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Trust may be stored in any of the domains. According to Apple's
|
||||
// SecTrustServer.c, "user trust settings overrule admin trust settings",
|
||||
// so take the last trust settings array we find.
|
||||
// Skip the system domain since it is always trusted.
|
||||
for (k = i; k < numDomains; k++) {
|
||||
CFArrayRef domainTrustSettings = NULL;
|
||||
err = SecTrustSettingsCopyTrustSettings(cert, domains[k], &domainTrustSettings);
|
||||
if (err == errSecSuccess && domainTrustSettings != NULL) {
|
||||
if (trustSettings) {
|
||||
CFRelease(trustSettings);
|
||||
}
|
||||
trustSettings = domainTrustSettings;
|
||||
CFIndex length = CFStringGetLength(summary);
|
||||
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
|
||||
char *buffer = malloc(maxSize);
|
||||
if (CFStringGetCString(summary, buffer, maxSize, kCFStringEncodingUTF8)) {
|
||||
printf("crypto/x509: %s returned %d\n", buffer, (int)result);
|
||||
}
|
||||
free(buffer);
|
||||
CFRelease(summary);
|
||||
}
|
||||
if (trustSettings == NULL) {
|
||||
// "this certificate must be verified to a known trusted certificate"; aka not a root.
|
||||
continue;
|
||||
}
|
||||
for (m = 0; m < CFArrayGetCount(trustSettings); m++) {
|
||||
CFNumberRef cfNum;
|
||||
CFDictionaryRef tSetting = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, m);
|
||||
if (CFDictionaryGetValueIfPresent(tSetting, policy, (const void**)&cfNum)){
|
||||
SInt32 result = 0;
|
||||
CFNumberGetValue(cfNum, kCFNumberSInt32Type, &result);
|
||||
// TODO: The rest of the dictionary specifies conditions for evaluation.
|
||||
if (result == kSecTrustSettingsResultDeny) {
|
||||
untrusted = 1;
|
||||
} else if (result == kSecTrustSettingsResultTrustAsRoot) {
|
||||
trustAsRoot = 1;
|
||||
} else if (result == kSecTrustSettingsResultTrustRoot) {
|
||||
trustRoot = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(trustSettings);
|
||||
}
|
||||
|
||||
if (trustRoot) {
|
||||
// We only want to add Root CAs, so make sure Subject and Issuer Name match
|
||||
CFDataRef subjectName = SecCertificateCopyNormalizedSubjectContent(cert, &errRef);
|
||||
if (errRef != NULL) {
|
||||
CFRelease(errRef);
|
||||
CFMutableDataRef appendTo;
|
||||
// > Note the distinction between the results kSecTrustSettingsResultTrustRoot
|
||||
// > and kSecTrustSettingsResultTrustAsRoot: The former can only be applied to
|
||||
// > root (self-signed) certificates; the latter can only be applied to
|
||||
// > non-root certificates.
|
||||
if (result == kSecTrustSettingsResultTrustRoot) {
|
||||
CFErrorRef errRef = NULL;
|
||||
if (!isRootCertificate(cert, &errRef) || errRef != NULL) {
|
||||
if (errRef != NULL) CFRelease(errRef);
|
||||
continue;
|
||||
}
|
||||
CFDataRef issuerName = SecCertificateCopyNormalizedIssuerContent(cert, &errRef);
|
||||
if (errRef != NULL) {
|
||||
CFRelease(subjectName);
|
||||
CFRelease(errRef);
|
||||
continue;
|
||||
}
|
||||
Boolean equal = CFEqual(subjectName, issuerName);
|
||||
CFRelease(subjectName);
|
||||
CFRelease(issuerName);
|
||||
if (!equal) {
|
||||
|
||||
appendTo = combinedData;
|
||||
} else if (result == kSecTrustSettingsResultTrustAsRoot) {
|
||||
CFErrorRef errRef = NULL;
|
||||
if (isRootCertificate(cert, &errRef) || errRef != NULL) {
|
||||
if (errRef != NULL) CFRelease(errRef);
|
||||
continue;
|
||||
}
|
||||
|
||||
appendTo = combinedData;
|
||||
} else if (result == kSecTrustSettingsResultDeny) {
|
||||
appendTo = combinedUntrustedData;
|
||||
} else if (result == kSecTrustSettingsResultUnspecified) {
|
||||
continue;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
err = SecItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
|
||||
if (err != noErr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data != NULL) {
|
||||
if (!trustRoot && !trustAsRoot) {
|
||||
untrusted = 1;
|
||||
}
|
||||
CFMutableDataRef appendTo = untrusted ? combinedUntrustedData : combinedData;
|
||||
CFDataAppendBytes(appendTo, CFDataGetBytePtr(data), CFDataGetLength(data));
|
||||
CFRelease(data);
|
||||
}
|
||||
}
|
||||
CFRelease(certs);
|
||||
}
|
||||
CFRelease(policy);
|
||||
*pemRoots = combinedData;
|
||||
*untrustedPemRoots = combinedUntrustedData;
|
||||
return 0;
|
||||
@@ -169,9 +278,8 @@ func loadSystemRoots() (*CertPool, error) {
|
||||
|
||||
var data C.CFDataRef = 0
|
||||
var untrustedData C.CFDataRef = 0
|
||||
err := C.FetchPEMRoots(&data, &untrustedData)
|
||||
err := C.FetchPEMRoots(&data, &untrustedData, C.bool(debugDarwinRoots))
|
||||
if err == -1 {
|
||||
// TODO: better error message
|
||||
return nil, errors.New("crypto/x509: failed to load darwin system roots with cgo")
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var debugExecDarwinRoots = strings.Contains(os.Getenv("GODEBUG"), "x509roots=1")
|
||||
var debugDarwinRoots = strings.Contains(os.Getenv("GODEBUG"), "x509roots=1")
|
||||
|
||||
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
||||
return nil, nil
|
||||
@@ -40,8 +40,8 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
|
||||
//
|
||||
// 1. Run "security trust-settings-export" and "security
|
||||
// trust-settings-export -d" to discover the set of certs with some
|
||||
// user-tweaked trust policy. We're too lazy to parse the XML (at
|
||||
// least at this stage of Go 1.8) to understand what the trust
|
||||
// user-tweaked trust policy. We're too lazy to parse the XML
|
||||
// (Issue 26830) to understand what the trust
|
||||
// policy actually is. We just learn that there is _some_ policy.
|
||||
//
|
||||
// 2. Run "security find-certificate" to dump the list of system root
|
||||
@@ -58,22 +58,19 @@ func execSecurityRoots() (*CertPool, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if debugExecDarwinRoots {
|
||||
println(fmt.Sprintf("crypto/x509: %d certs have a trust policy", len(hasPolicy)))
|
||||
if debugDarwinRoots {
|
||||
fmt.Printf("crypto/x509: %d certs have a trust policy\n", len(hasPolicy))
|
||||
}
|
||||
|
||||
args := []string{"find-certificate", "-a", "-p",
|
||||
"/System/Library/Keychains/SystemRootCertificates.keychain",
|
||||
"/Library/Keychains/System.keychain",
|
||||
}
|
||||
keychains := []string{"/Library/Keychains/System.keychain"}
|
||||
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
if debugExecDarwinRoots {
|
||||
println(fmt.Sprintf("crypto/x509: get current user: %v", err))
|
||||
if debugDarwinRoots {
|
||||
fmt.Printf("crypto/x509: can't get user home directory: %v\n", err)
|
||||
}
|
||||
} else {
|
||||
args = append(args,
|
||||
keychains = append(keychains,
|
||||
filepath.Join(u.HomeDir, "/Library/Keychains/login.keychain"),
|
||||
|
||||
// Fresh installs of Sierra use a slightly different path for the login keychain
|
||||
@@ -81,21 +78,19 @@ func execSecurityRoots() (*CertPool, error) {
|
||||
)
|
||||
}
|
||||
|
||||
cmd := exec.Command("/usr/bin/security", args...)
|
||||
data, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
type rootCandidate struct {
|
||||
c *Certificate
|
||||
system bool
|
||||
}
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
roots = NewCertPool()
|
||||
numVerified int // number of execs of 'security verify-cert', for debug stats
|
||||
wg sync.WaitGroup
|
||||
verifyCh = make(chan rootCandidate)
|
||||
)
|
||||
|
||||
blockCh := make(chan *pem.Block)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// Using 4 goroutines to pipe into verify-cert seems to be
|
||||
// about the best we can do. The verify-cert binary seems to
|
||||
// just RPC to another server with coarse locking anyway, so
|
||||
@@ -109,31 +104,62 @@ func execSecurityRoots() (*CertPool, error) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for block := range blockCh {
|
||||
cert, err := ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
sha1CapHex := fmt.Sprintf("%X", sha1.Sum(block.Bytes))
|
||||
for cert := range verifyCh {
|
||||
sha1CapHex := fmt.Sprintf("%X", sha1.Sum(cert.c.Raw))
|
||||
|
||||
valid := true
|
||||
var valid bool
|
||||
verifyChecks := 0
|
||||
if hasPolicy[sha1CapHex] {
|
||||
verifyChecks++
|
||||
if !verifyCertWithSystem(block, cert) {
|
||||
valid = false
|
||||
}
|
||||
valid = verifyCertWithSystem(cert.c)
|
||||
} else {
|
||||
// Certificates not in SystemRootCertificates without user
|
||||
// or admin trust settings are not trusted.
|
||||
valid = cert.system
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
numVerified += verifyChecks
|
||||
if valid {
|
||||
roots.AddCert(cert)
|
||||
roots.AddCert(cert.c)
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
err = forEachCertInKeychains(keychains, func(cert *Certificate) {
|
||||
verifyCh <- rootCandidate{c: cert, system: false}
|
||||
})
|
||||
if err != nil {
|
||||
close(verifyCh)
|
||||
return nil, err
|
||||
}
|
||||
err = forEachCertInKeychains([]string{
|
||||
"/System/Library/Keychains/SystemRootCertificates.keychain",
|
||||
}, func(cert *Certificate) {
|
||||
verifyCh <- rootCandidate{c: cert, system: true}
|
||||
})
|
||||
if err != nil {
|
||||
close(verifyCh)
|
||||
return nil, err
|
||||
}
|
||||
close(verifyCh)
|
||||
wg.Wait()
|
||||
|
||||
if debugDarwinRoots {
|
||||
fmt.Printf("crypto/x509: ran security verify-cert %d times\n", numVerified)
|
||||
}
|
||||
|
||||
return roots, nil
|
||||
}
|
||||
|
||||
func forEachCertInKeychains(paths []string, f func(*Certificate)) error {
|
||||
args := append([]string{"find-certificate", "-a", "-p"}, paths...)
|
||||
cmd := exec.Command("/usr/bin/security", args...)
|
||||
data, err := cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for len(data) > 0 {
|
||||
var block *pem.Block
|
||||
block, data = pem.Decode(data)
|
||||
@@ -143,22 +169,19 @@ func execSecurityRoots() (*CertPool, error) {
|
||||
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
|
||||
continue
|
||||
}
|
||||
blockCh <- block
|
||||
cert, err := ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
f(cert)
|
||||
}
|
||||
close(blockCh)
|
||||
wg.Wait()
|
||||
|
||||
if debugExecDarwinRoots {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
println(fmt.Sprintf("crypto/x509: ran security verify-cert %d times", numVerified))
|
||||
}
|
||||
|
||||
return roots, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifyCertWithSystem(block *pem.Block, cert *Certificate) bool {
|
||||
data := pem.EncodeToMemory(block)
|
||||
func verifyCertWithSystem(cert *Certificate) bool {
|
||||
data := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE", Bytes: cert.Raw,
|
||||
})
|
||||
|
||||
f, err := ioutil.TempFile("", "cert")
|
||||
if err != nil {
|
||||
@@ -174,19 +197,19 @@ func verifyCertWithSystem(block *pem.Block, cert *Certificate) bool {
|
||||
fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
|
||||
return false
|
||||
}
|
||||
cmd := exec.Command("/usr/bin/security", "verify-cert", "-c", f.Name(), "-l", "-L")
|
||||
cmd := exec.Command("/usr/bin/security", "verify-cert", "-p", "ssl", "-c", f.Name(), "-l", "-L")
|
||||
var stderr bytes.Buffer
|
||||
if debugExecDarwinRoots {
|
||||
if debugDarwinRoots {
|
||||
cmd.Stderr = &stderr
|
||||
}
|
||||
if err := cmd.Run(); err != nil {
|
||||
if debugExecDarwinRoots {
|
||||
println(fmt.Sprintf("crypto/x509: verify-cert rejected %s: %q", cert.Subject, bytes.TrimSpace(stderr.Bytes())))
|
||||
if debugDarwinRoots {
|
||||
fmt.Printf("crypto/x509: verify-cert rejected %s: %q\n", cert.Subject, bytes.TrimSpace(stderr.Bytes()))
|
||||
}
|
||||
return false
|
||||
}
|
||||
if debugExecDarwinRoots {
|
||||
println(fmt.Sprintf("crypto/x509: verify-cert approved %s", cert.Subject))
|
||||
if debugDarwinRoots {
|
||||
fmt.Printf("crypto/x509: verify-cert approved %s\n", cert.Subject)
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -218,8 +241,8 @@ func getCertsWithTrustPolicy() (map[string]bool, error) {
|
||||
// Rather than match on English substrings that are probably
|
||||
// localized on macOS, just interpret any failure to mean that
|
||||
// there are no trust settings.
|
||||
if debugExecDarwinRoots {
|
||||
println(fmt.Sprintf("crypto/x509: exec %q: %v, %s", cmd.Args, err, stderr.Bytes()))
|
||||
if debugDarwinRoots {
|
||||
fmt.Printf("crypto/x509: exec %q: %v, %s\n", cmd.Args, err, stderr.Bytes())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -765,7 +765,7 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
|
||||
if opts.Roots.contains(c) {
|
||||
candidateChains = append(candidateChains, []*Certificate{c})
|
||||
} else {
|
||||
if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
|
||||
if candidateChains, err = c.buildChains(nil, []*Certificate{c}, nil, &opts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -802,58 +802,74 @@ func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate
|
||||
return n
|
||||
}
|
||||
|
||||
func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
||||
possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
|
||||
nextRoot:
|
||||
for _, rootNum := range possibleRoots {
|
||||
root := opts.Roots.certs[rootNum]
|
||||
// maxChainSignatureChecks is the maximum number of CheckSignatureFrom calls
|
||||
// that an invocation of buildChains will (tranistively) make. Most chains are
|
||||
// less than 15 certificates long, so this leaves space for multiple chains and
|
||||
// for failed checks due to different intermediates having the same Subject.
|
||||
const maxChainSignatureChecks = 100
|
||||
|
||||
func (c *Certificate) buildChains(cache map[*Certificate][][]*Certificate, currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
||||
var (
|
||||
hintErr error
|
||||
hintCert *Certificate
|
||||
)
|
||||
|
||||
considerCandidate := func(certType int, candidate *Certificate) {
|
||||
for _, cert := range currentChain {
|
||||
if cert.Equal(root) {
|
||||
continue nextRoot
|
||||
if cert.Equal(candidate) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = root.isValid(rootCertificate, currentChain, opts)
|
||||
if err != nil {
|
||||
continue
|
||||
if sigChecks == nil {
|
||||
sigChecks = new(int)
|
||||
}
|
||||
*sigChecks++
|
||||
if *sigChecks > maxChainSignatureChecks {
|
||||
err = errors.New("x509: signature check attempts limit reached while verifying certificate chain")
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.CheckSignatureFrom(candidate); err != nil {
|
||||
if hintErr == nil {
|
||||
hintErr = err
|
||||
hintCert = candidate
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
err = candidate.isValid(certType, currentChain, opts)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch certType {
|
||||
case rootCertificate:
|
||||
chains = append(chains, appendToFreshChain(currentChain, candidate))
|
||||
case intermediateCertificate:
|
||||
if cache == nil {
|
||||
cache = make(map[*Certificate][][]*Certificate)
|
||||
}
|
||||
childChains, ok := cache[candidate]
|
||||
if !ok {
|
||||
childChains, err = candidate.buildChains(cache, appendToFreshChain(currentChain, candidate), sigChecks, opts)
|
||||
cache[candidate] = childChains
|
||||
}
|
||||
chains = append(chains, childChains...)
|
||||
}
|
||||
chains = append(chains, appendToFreshChain(currentChain, root))
|
||||
}
|
||||
|
||||
possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c)
|
||||
nextIntermediate:
|
||||
for _, intermediateNum := range possibleIntermediates {
|
||||
intermediate := opts.Intermediates.certs[intermediateNum]
|
||||
for _, cert := range currentChain {
|
||||
if cert.Equal(intermediate) {
|
||||
continue nextIntermediate
|
||||
}
|
||||
}
|
||||
err = intermediate.isValid(intermediateCertificate, currentChain, opts)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
var childChains [][]*Certificate
|
||||
childChains, ok := cache[intermediateNum]
|
||||
if !ok {
|
||||
childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
|
||||
cache[intermediateNum] = childChains
|
||||
}
|
||||
chains = append(chains, childChains...)
|
||||
for _, rootNum := range opts.Roots.findPotentialParents(c) {
|
||||
considerCandidate(rootCertificate, opts.Roots.certs[rootNum])
|
||||
}
|
||||
for _, intermediateNum := range opts.Intermediates.findPotentialParents(c) {
|
||||
considerCandidate(intermediateCertificate, opts.Intermediates.certs[intermediateNum])
|
||||
}
|
||||
|
||||
if len(chains) > 0 {
|
||||
err = nil
|
||||
}
|
||||
|
||||
if len(chains) == 0 && err == nil {
|
||||
hintErr := rootErr
|
||||
hintCert := failedRoot
|
||||
if hintErr == nil {
|
||||
hintErr = intermediateErr
|
||||
hintCert = failedIntermediate
|
||||
}
|
||||
err = UnknownAuthorityError{c, hintErr, hintCert}
|
||||
}
|
||||
|
||||
@@ -894,8 +910,8 @@ func validHostname(host string) bool {
|
||||
if c == '-' && j != 0 {
|
||||
continue
|
||||
}
|
||||
if c == '_' {
|
||||
// _ is not a valid character in hostnames, but it's commonly
|
||||
if c == '_' || c == ':' {
|
||||
// Not valid characters in hostnames, but commonly
|
||||
// found in deployments outside the WebPKI.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -5,10 +5,15 @@
|
||||
package x509
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -381,6 +386,19 @@ var verifyTests = []verifyTest{
|
||||
|
||||
errorCallback: expectHostnameError("not valid for any names"),
|
||||
},
|
||||
{
|
||||
// A certificate with an AKID should still chain to a parent without SKID.
|
||||
// See Issue 30079.
|
||||
leaf: leafWithAKID,
|
||||
roots: []string{rootWithoutSKID},
|
||||
currentTime: 1550000000,
|
||||
dnsName: "example",
|
||||
systemSkip: true,
|
||||
|
||||
expectedChains: [][]string{
|
||||
{"Acme LLC", "Acme Co"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func expectHostnameError(msg string) func(*testing.T, int, error) bool {
|
||||
@@ -1674,6 +1692,109 @@ h7olHCpY9yMRiz0=
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
|
||||
const (
|
||||
rootWithoutSKID = `
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number:
|
||||
78:29:2a:dc:2f:12:39:7f:c9:33:93:ea:61:39:7d:70
|
||||
Signature Algorithm: ecdsa-with-SHA256
|
||||
Issuer: O = Acme Co
|
||||
Validity
|
||||
Not Before: Feb 4 22:56:34 2019 GMT
|
||||
Not After : Feb 1 22:56:34 2029 GMT
|
||||
Subject: O = Acme Co
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: id-ecPublicKey
|
||||
Public-Key: (256 bit)
|
||||
pub:
|
||||
04:84:a6:8c:69:53:af:87:4b:39:64:fe:04:24:e6:
|
||||
d8:fc:d6:46:39:35:0e:92:dc:48:08:7e:02:5f:1e:
|
||||
07:53:5c:d9:e0:56:c5:82:07:f6:a3:e2:ad:f6:ad:
|
||||
be:a0:4e:03:87:39:67:0c:9c:46:91:68:6b:0e:8e:
|
||||
f8:49:97:9d:5b
|
||||
ASN1 OID: prime256v1
|
||||
NIST CURVE: P-256
|
||||
X509v3 extensions:
|
||||
X509v3 Key Usage: critical
|
||||
Digital Signature, Key Encipherment, Certificate Sign
|
||||
X509v3 Extended Key Usage:
|
||||
TLS Web Server Authentication
|
||||
X509v3 Basic Constraints: critical
|
||||
CA:TRUE
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:example
|
||||
Signature Algorithm: ecdsa-with-SHA256
|
||||
30:46:02:21:00:c6:81:61:61:42:8d:37:e7:d0:c3:72:43:44:
|
||||
17:bd:84:ff:88:81:68:9a:99:08:ab:3c:3a:c0:1e:ea:8c:ba:
|
||||
c0:02:21:00:de:c9:fa:e5:5e:c6:e2:db:23:64:43:a9:37:42:
|
||||
72:92:7f:6e:89:38:ea:9e:2a:a7:fd:2f:ea:9a:ff:20:21:e7
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBbzCCARSgAwIBAgIQeCkq3C8SOX/JM5PqYTl9cDAKBggqhkjOPQQDAjASMRAw
|
||||
DgYDVQQKEwdBY21lIENvMB4XDTE5MDIwNDIyNTYzNFoXDTI5MDIwMTIyNTYzNFow
|
||||
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABISm
|
||||
jGlTr4dLOWT+BCTm2PzWRjk1DpLcSAh+Al8eB1Nc2eBWxYIH9qPirfatvqBOA4c5
|
||||
ZwycRpFoaw6O+EmXnVujTDBKMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
|
||||
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MBIGA1UdEQQLMAmCB2V4YW1wbGUwCgYI
|
||||
KoZIzj0EAwIDSQAwRgIhAMaBYWFCjTfn0MNyQ0QXvYT/iIFompkIqzw6wB7qjLrA
|
||||
AiEA3sn65V7G4tsjZEOpN0Jykn9uiTjqniqn/S/qmv8gIec=
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
leafWithAKID = `
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number:
|
||||
f0:8a:62:f0:03:84:a2:cf:69:63:ad:71:3b:b6:5d:8c
|
||||
Signature Algorithm: ecdsa-with-SHA256
|
||||
Issuer: O = Acme Co
|
||||
Validity
|
||||
Not Before: Feb 4 23:06:52 2019 GMT
|
||||
Not After : Feb 1 23:06:52 2029 GMT
|
||||
Subject: O = Acme LLC
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: id-ecPublicKey
|
||||
Public-Key: (256 bit)
|
||||
pub:
|
||||
04:5a:4e:4d:fb:ff:17:f7:b6:13:e8:29:45:34:81:
|
||||
39:ff:8c:9c:d9:8c:0a:9f:dd:b5:97:4c:2b:20:91:
|
||||
1c:4f:6b:be:53:27:66:ec:4a:ad:08:93:6d:66:36:
|
||||
0c:02:70:5d:01:ca:7f:c3:29:e9:4f:00:ba:b4:14:
|
||||
ec:c5:c3:34:b3
|
||||
ASN1 OID: prime256v1
|
||||
NIST CURVE: P-256
|
||||
X509v3 extensions:
|
||||
X509v3 Key Usage: critical
|
||||
Digital Signature, Key Encipherment
|
||||
X509v3 Extended Key Usage:
|
||||
TLS Web Server Authentication
|
||||
X509v3 Basic Constraints: critical
|
||||
CA:FALSE
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:C2:2B:5F:91:78:34:26:09:42:8D:6F:51:B2:C5:AF:4C:0B:DE:6A:42
|
||||
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:example
|
||||
Signature Algorithm: ecdsa-with-SHA256
|
||||
30:44:02:20:64:e0:ba:56:89:63:ce:22:5e:4f:22:15:fd:3c:
|
||||
35:64:9a:3a:6b:7b:9a:32:a0:7f:f7:69:8c:06:f0:00:58:b8:
|
||||
02:20:09:e4:9f:6d:8b:9e:38:e1:b6:01:d5:ee:32:a4:94:65:
|
||||
93:2a:78:94:bb:26:57:4b:c7:dd:6c:3d:40:2b:63:90
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBjTCCATSgAwIBAgIRAPCKYvADhKLPaWOtcTu2XYwwCgYIKoZIzj0EAwIwEjEQ
|
||||
MA4GA1UEChMHQWNtZSBDbzAeFw0xOTAyMDQyMzA2NTJaFw0yOTAyMDEyMzA2NTJa
|
||||
MBMxETAPBgNVBAoTCEFjbWUgTExDMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
||||
Wk5N+/8X97YT6ClFNIE5/4yc2YwKn921l0wrIJEcT2u+Uydm7EqtCJNtZjYMAnBd
|
||||
Acp/wynpTwC6tBTsxcM0s6NqMGgwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG
|
||||
CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUwitfkXg0JglCjW9R
|
||||
ssWvTAveakIwEgYDVR0RBAswCYIHZXhhbXBsZTAKBggqhkjOPQQDAgNHADBEAiBk
|
||||
4LpWiWPOIl5PIhX9PDVkmjpre5oyoH/3aYwG8ABYuAIgCeSfbYueOOG2AdXuMqSU
|
||||
ZZMqeJS7JldLx91sPUArY5A=
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
)
|
||||
|
||||
var unknownAuthorityErrorTests = []struct {
|
||||
cert string
|
||||
expected string
|
||||
@@ -1881,6 +2002,7 @@ func TestValidHostname(t *testing.T) {
|
||||
{"foo.*.example.com", false},
|
||||
{"exa_mple.com", true},
|
||||
{"foo,bar", false},
|
||||
{"project-dev:us-central1:main", true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if got := validHostname(tt.host); got != tt.want {
|
||||
@@ -1888,3 +2010,117 @@ func TestValidHostname(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func generateCert(cn string, isCA bool, issuer *Certificate, issuerKey crypto.PrivateKey) (*Certificate, crypto.PrivateKey, error) {
|
||||
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
|
||||
|
||||
template := &Certificate{
|
||||
SerialNumber: serialNumber,
|
||||
Subject: pkix.Name{CommonName: cn},
|
||||
NotBefore: time.Now().Add(-1 * time.Hour),
|
||||
NotAfter: time.Now().Add(24 * time.Hour),
|
||||
|
||||
KeyUsage: KeyUsageKeyEncipherment | KeyUsageDigitalSignature | KeyUsageCertSign,
|
||||
ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: isCA,
|
||||
}
|
||||
if issuer == nil {
|
||||
issuer = template
|
||||
issuerKey = priv
|
||||
}
|
||||
|
||||
derBytes, err := CreateCertificate(rand.Reader, template, issuer, priv.Public(), issuerKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cert, err := ParseCertificate(derBytes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return cert, priv, nil
|
||||
}
|
||||
|
||||
func TestPathologicalChain(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping generation of a long chain of certificates in short mode")
|
||||
}
|
||||
|
||||
// Build a chain where all intermediates share the same subject, to hit the
|
||||
// path building worst behavior.
|
||||
roots, intermediates := NewCertPool(), NewCertPool()
|
||||
|
||||
parent, parentKey, err := generateCert("Root CA", true, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
roots.AddCert(parent)
|
||||
|
||||
for i := 1; i < 100; i++ {
|
||||
parent, parentKey, err = generateCert("Intermediate CA", true, parent, parentKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
intermediates.AddCert(parent)
|
||||
}
|
||||
|
||||
leaf, _, err := generateCert("Leaf", false, parent, parentKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
_, err = leaf.Verify(VerifyOptions{
|
||||
Roots: roots,
|
||||
Intermediates: intermediates,
|
||||
})
|
||||
t.Logf("verification took %v", time.Since(start))
|
||||
|
||||
if err == nil || !strings.Contains(err.Error(), "signature check attempts limit") {
|
||||
t.Errorf("expected verification to fail with a signature checks limit error; got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLongChain(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping generation of a long chain of certificates in short mode")
|
||||
}
|
||||
|
||||
roots, intermediates := NewCertPool(), NewCertPool()
|
||||
|
||||
parent, parentKey, err := generateCert("Root CA", true, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
roots.AddCert(parent)
|
||||
|
||||
for i := 1; i < 15; i++ {
|
||||
name := fmt.Sprintf("Intermediate CA #%d", i)
|
||||
parent, parentKey, err = generateCert(name, true, parent, parentKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
intermediates.AddCert(parent)
|
||||
}
|
||||
|
||||
leaf, _, err := generateCert("Leaf", false, parent, parentKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
if _, err := leaf.Verify(VerifyOptions{
|
||||
Roots: roots,
|
||||
Intermediates: intermediates,
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Logf("verification took %v", time.Since(start))
|
||||
}
|
||||
|
||||
@@ -1322,11 +1322,13 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
|
||||
err: err,
|
||||
}
|
||||
return true
|
||||
} else if err == nil && !db.closed && db.maxIdleConnsLocked() > len(db.freeConn) {
|
||||
db.freeConn = append(db.freeConn, dc)
|
||||
} else if err == nil && !db.closed {
|
||||
if db.maxIdleConnsLocked() > len(db.freeConn) {
|
||||
db.freeConn = append(db.freeConn, dc)
|
||||
db.startCleanerLocked()
|
||||
return true
|
||||
}
|
||||
db.maxIdleClosed++
|
||||
db.startCleanerLocked()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -3415,6 +3415,58 @@ func TestConnectionLeak(t *testing.T) {
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestStatsMaxIdleClosedZero(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
db.SetMaxOpenConns(1)
|
||||
db.SetMaxIdleConns(1)
|
||||
db.SetConnMaxLifetime(0)
|
||||
|
||||
preMaxIdleClosed := db.Stats().MaxIdleClosed
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
rows, err := db.Query("SELECT|people|name|")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
|
||||
st := db.Stats()
|
||||
maxIdleClosed := st.MaxIdleClosed - preMaxIdleClosed
|
||||
t.Logf("MaxIdleClosed: %d", maxIdleClosed)
|
||||
if maxIdleClosed != 0 {
|
||||
t.Fatal("expected 0 max idle closed conns, got: ", maxIdleClosed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsMaxIdleClosedTen(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
db.SetMaxOpenConns(1)
|
||||
db.SetMaxIdleConns(0)
|
||||
db.SetConnMaxLifetime(0)
|
||||
|
||||
preMaxIdleClosed := db.Stats().MaxIdleClosed
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
rows, err := db.Query("SELECT|people|name|")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
|
||||
st := db.Stats()
|
||||
maxIdleClosed := st.MaxIdleClosed - preMaxIdleClosed
|
||||
t.Logf("MaxIdleClosed: %d", maxIdleClosed)
|
||||
if maxIdleClosed != 10 {
|
||||
t.Fatal("expected 0 max idle closed conns, got: ", maxIdleClosed)
|
||||
}
|
||||
}
|
||||
|
||||
type nvcDriver struct {
|
||||
fakeDriver
|
||||
skipNamedValueCheck bool
|
||||
|
||||
@@ -179,7 +179,7 @@ func (d *decodeState) unmarshal(v interface{}) error {
|
||||
// test must be applied at the top level of the value.
|
||||
err := d.value(rv)
|
||||
if err != nil {
|
||||
return err
|
||||
return d.addErrorContext(err)
|
||||
}
|
||||
return d.savedError
|
||||
}
|
||||
@@ -672,6 +672,7 @@ func (d *decodeState) object(v reflect.Value) error {
|
||||
}
|
||||
|
||||
var mapElem reflect.Value
|
||||
originalErrorContext := d.errorContext
|
||||
|
||||
for {
|
||||
// Read opening " of string key or closing }.
|
||||
@@ -832,8 +833,7 @@ func (d *decodeState) object(v reflect.Value) error {
|
||||
return errPhase
|
||||
}
|
||||
|
||||
d.errorContext.Struct = ""
|
||||
d.errorContext.Field = ""
|
||||
d.errorContext = originalErrorContext
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -991,7 +991,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||
if fromQuoted {
|
||||
return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())
|
||||
}
|
||||
return &UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}
|
||||
d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())})
|
||||
case reflect.Interface:
|
||||
n, err := d.convertNumber(s)
|
||||
if err != nil {
|
||||
|
||||
@@ -41,6 +41,16 @@ type VOuter struct {
|
||||
V V
|
||||
}
|
||||
|
||||
type W struct {
|
||||
S SS
|
||||
}
|
||||
|
||||
type SS string
|
||||
|
||||
func (*SS) UnmarshalJSON(data []byte) error {
|
||||
return &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(SS(""))}
|
||||
}
|
||||
|
||||
// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and
|
||||
// without UseNumber
|
||||
var ifaceNumAsFloat64 = map[string]interface{}{
|
||||
@@ -371,6 +381,10 @@ func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error {
|
||||
return (*intWithMarshalText)(b).UnmarshalText(data)
|
||||
}
|
||||
|
||||
type mapStringToStringData struct {
|
||||
Data map[string]string `json:"data"`
|
||||
}
|
||||
|
||||
type unmarshalTest struct {
|
||||
in string
|
||||
ptr interface{}
|
||||
@@ -401,8 +415,10 @@ var unmarshalTests = []unmarshalTest{
|
||||
{in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
|
||||
{in: "null", ptr: new(interface{}), out: nil},
|
||||
{in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7, "T", "X"}},
|
||||
{in: `{"X": 23}`, ptr: new(T), out: T{}, err: &UnmarshalTypeError{"number", reflect.TypeOf(""), 8, "T", "X"}}, {in: `{"x": 1}`, ptr: new(tx), out: tx{}},
|
||||
{in: `{"x": 1}`, ptr: new(tx), out: tx{}},
|
||||
{in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true},
|
||||
{in: `{"S": 23}`, ptr: new(W), out: W{}, err: &UnmarshalTypeError{"number", reflect.TypeOf(SS("")), 0, "W", "S"}},
|
||||
{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
|
||||
{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
|
||||
{in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64},
|
||||
@@ -866,6 +882,18 @@ var unmarshalTests = []unmarshalTest{
|
||||
err: fmt.Errorf("json: unknown field \"extra\""),
|
||||
disallowUnknownFields: true,
|
||||
},
|
||||
// issue 26444
|
||||
// UnmarshalTypeError without field & struct values
|
||||
{
|
||||
in: `{"data":{"test1": "bob", "test2": 123}}`,
|
||||
ptr: new(mapStringToStringData),
|
||||
err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 37, Struct: "mapStringToStringData", Field: "data"},
|
||||
},
|
||||
{
|
||||
in: `{"data":{"test1": 123, "test2": "bob"}}`,
|
||||
ptr: new(mapStringToStringData),
|
||||
err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 21, Struct: "mapStringToStringData", Field: "data"},
|
||||
},
|
||||
}
|
||||
|
||||
func TestMarshal(t *testing.T) {
|
||||
|
||||
@@ -261,6 +261,8 @@ func TestTypesInfo(t *testing.T) {
|
||||
{`package x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
|
||||
{`package x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
|
||||
{`package x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a; f: b;}}`, `b`, `string`},
|
||||
{`package x3; var x = panic("");`, `panic`, `func(interface{})`},
|
||||
{`package x4; func _() { panic("") }`, `panic`, `func(interface{})`},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -476,7 +476,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
// panic(x)
|
||||
// record panic call if inside a function with result parameters
|
||||
// (for use in Checker.isTerminating)
|
||||
if check.sig.results.Len() > 0 {
|
||||
if check.sig != nil && check.sig.results.Len() > 0 {
|
||||
// function has result parameters
|
||||
p := check.isPanic
|
||||
if p == nil {
|
||||
|
||||
@@ -355,3 +355,70 @@ func TestIssue25627(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue28005(t *testing.T) {
|
||||
// method names must match defining interface name for this test
|
||||
// (see last comment in this function)
|
||||
sources := [...]string{
|
||||
"package p; type A interface{ A() }",
|
||||
"package p; type B interface{ B() }",
|
||||
"package p; type X interface{ A; B }",
|
||||
}
|
||||
|
||||
// compute original file ASTs
|
||||
var orig [len(sources)]*ast.File
|
||||
for i, src := range sources {
|
||||
f, err := parser.ParseFile(fset, "", src, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
orig[i] = f
|
||||
}
|
||||
|
||||
// run the test for all order permutations of the incoming files
|
||||
for _, perm := range [][len(sources)]int{
|
||||
{0, 1, 2},
|
||||
{0, 2, 1},
|
||||
{1, 0, 2},
|
||||
{1, 2, 0},
|
||||
{2, 0, 1},
|
||||
{2, 1, 0},
|
||||
} {
|
||||
// create file order permutation
|
||||
files := make([]*ast.File, len(sources))
|
||||
for i := range perm {
|
||||
files[i] = orig[perm[i]]
|
||||
}
|
||||
|
||||
// type-check package with given file order permutation
|
||||
var conf Config
|
||||
info := &Info{Defs: make(map[*ast.Ident]Object)}
|
||||
_, err := conf.Check("", fset, files, info)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// look for interface object X
|
||||
var obj Object
|
||||
for name, def := range info.Defs {
|
||||
if name.Name == "X" {
|
||||
obj = def
|
||||
break
|
||||
}
|
||||
}
|
||||
if obj == nil {
|
||||
t.Fatal("interface not found")
|
||||
}
|
||||
iface := obj.Type().Underlying().(*Interface) // I must be an interface
|
||||
|
||||
// Each iface method m is embedded; and m's receiver base type name
|
||||
// must match the method's name per the choice in the source file.
|
||||
for i := 0; i < iface.NumMethods(); i++ {
|
||||
m := iface.Method(i)
|
||||
recvName := m.Type().(*Signature).Recv().Type().(*Named).Obj().Name()
|
||||
if recvName != m.Name() {
|
||||
t.Errorf("perm %v: got recv %s; want %s", perm, recvName, m.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,7 +538,25 @@ func (check *Checker) packageObjects() {
|
||||
// pre-allocate space for type declaration paths so that the underlying array is reused
|
||||
typePath := make([]*TypeName, 0, 8)
|
||||
|
||||
// We process non-alias declarations first, in order to avoid situations where
|
||||
// the type of an alias declaration is needed before it is available. In general
|
||||
// this is still not enough, as it is possible to create sufficiently convoluted
|
||||
// recursive type definitions that will cause a type alias to be needed before it
|
||||
// is available (see issue #25838 for examples).
|
||||
// As an aside, the cmd/compiler suffers from the same problem (#25838).
|
||||
var aliasList []*TypeName
|
||||
// phase 1
|
||||
for _, obj := range objList {
|
||||
// If we have a type alias, collect it for the 2nd phase.
|
||||
if tname, _ := obj.(*TypeName); tname != nil && check.objMap[tname].alias {
|
||||
aliasList = append(aliasList, tname)
|
||||
continue
|
||||
}
|
||||
|
||||
check.objDecl(obj, nil, typePath)
|
||||
}
|
||||
// phase 2
|
||||
for _, obj := range aliasList {
|
||||
check.objDecl(obj, nil, typePath)
|
||||
}
|
||||
|
||||
|
||||
@@ -176,6 +176,7 @@ func TestStdFixed(t *testing.T) {
|
||||
"issue22200b.go", // go/types does not have constraints on stack size
|
||||
"issue25507.go", // go/types does not have constraints on stack size
|
||||
"issue20780.go", // go/types does not have constraints on stack size
|
||||
"issue27232.go", // go/types has a bug with alias type (issue #28576)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -571,6 +571,15 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
|
||||
recvTyp = def
|
||||
}
|
||||
|
||||
// Correct receiver type for all methods explicitly declared
|
||||
// by this interface after we're done with type-checking at
|
||||
// this level. See comment below for details.
|
||||
check.later(func() {
|
||||
for _, m := range ityp.methods {
|
||||
m.typ.(*Signature).recv.typ = recvTyp
|
||||
}
|
||||
})
|
||||
|
||||
// collect methods
|
||||
var sigfix []*methodInfo
|
||||
for i, minfo := range info.methods {
|
||||
@@ -580,9 +589,27 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
|
||||
pos := name.Pos()
|
||||
// Don't type-check signature yet - use an
|
||||
// empty signature now and update it later.
|
||||
// Since we know the receiver, set it up now
|
||||
// (required to avoid crash in ptrRecv; see
|
||||
// e.g. test case for issue 6638).
|
||||
// But set up receiver since we know it and
|
||||
// its position, and because interface method
|
||||
// signatures don't get a receiver via regular
|
||||
// type-checking (there isn't a receiver in the
|
||||
// method's AST). Setting the receiver type is
|
||||
// also important for ptrRecv() (see methodset.go).
|
||||
//
|
||||
// Note: For embedded methods, the receiver type
|
||||
// should be the type of the interface that declared
|
||||
// the methods in the first place. Since we get the
|
||||
// methods here via methodInfo, which may be computed
|
||||
// before we have all relevant interface types, we use
|
||||
// the current interface's type (recvType). This may be
|
||||
// the type of the interface embedding the interface that
|
||||
// declared the methods. This doesn't matter for type-
|
||||
// checking (we only care about the receiver type for
|
||||
// the ptrRecv predicate, and it's never a pointer recv
|
||||
// for interfaces), but it matters for go/types clients
|
||||
// and for printing. We correct the receiver after type-
|
||||
// checking.
|
||||
//
|
||||
// TODO(gri) Consider marking methods signatures
|
||||
// as incomplete, for better error messages. See
|
||||
// also the T4 and T5 tests in testdata/cycles2.src.
|
||||
|
||||
@@ -32,11 +32,17 @@ func SendFile(fd *FD, src syscall.Handle, n int64) (int64, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
o.o.OffsetHigh = uint32(curpos)
|
||||
o.o.Offset = uint32(curpos >> 32)
|
||||
o.o.Offset = uint32(curpos)
|
||||
o.o.OffsetHigh = uint32(curpos >> 32)
|
||||
|
||||
done, err := wsrv.ExecIO(o, func(o *operation) error {
|
||||
return syscall.TransmitFile(o.fd.Sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
|
||||
})
|
||||
if err == nil {
|
||||
// Some versions of Windows (Windows 10 1803) do not set
|
||||
// file position after TransmitFile completes.
|
||||
// So just use Seek to set file position.
|
||||
_, err = syscall.Seek(o.handle, curpos+int64(done), 0)
|
||||
}
|
||||
return int64(done), err
|
||||
}
|
||||
|
||||
@@ -27,6 +27,20 @@ import (
|
||||
"golang_org/x/net/dns/dnsmessage"
|
||||
)
|
||||
|
||||
var (
|
||||
errLameReferral = errors.New("lame referral")
|
||||
errCannotUnmarshalDNSMessage = errors.New("cannot unmarshal DNS message")
|
||||
errCannotMarshalDNSMessage = errors.New("cannot marshal DNS message")
|
||||
errServerMisbehaving = errors.New("server misbehaving")
|
||||
errInvalidDNSResponse = errors.New("invalid DNS response")
|
||||
errNoAnswerFromDNSServer = errors.New("no answer from DNS server")
|
||||
|
||||
// errServerTemporarlyMisbehaving is like errServerMisbehaving, except
|
||||
// that when it gets translated to a DNSError, the IsTemporary field
|
||||
// gets set to true.
|
||||
errServerTemporarlyMisbehaving = errors.New("server misbehaving")
|
||||
)
|
||||
|
||||
func newRequest(q dnsmessage.Question) (id uint16, udpReq, tcpReq []byte, err error) {
|
||||
id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
|
||||
b := dnsmessage.NewBuilder(make([]byte, 2, 514), dnsmessage.Header{ID: id, RecursionDesired: true})
|
||||
@@ -105,14 +119,14 @@ func dnsStreamRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte)
|
||||
var p dnsmessage.Parser
|
||||
h, err := p.Start(b[:n])
|
||||
if err != nil {
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot unmarshal DNS message")
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
|
||||
}
|
||||
q, err := p.Question()
|
||||
if err != nil {
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot unmarshal DNS message")
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
|
||||
}
|
||||
if !checkResponse(id, query, h, q) {
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("invalid DNS response")
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
|
||||
}
|
||||
return p, h, nil
|
||||
}
|
||||
@@ -122,7 +136,7 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que
|
||||
q.Class = dnsmessage.ClassINET
|
||||
id, udpReq, tcpReq, err := newRequest(q)
|
||||
if err != nil {
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot marshal DNS message")
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotMarshalDNSMessage
|
||||
}
|
||||
for _, network := range []string{"udp", "tcp"} {
|
||||
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
|
||||
@@ -147,31 +161,31 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, mapErr(err)
|
||||
}
|
||||
if err := p.SkipQuestion(); err != dnsmessage.ErrSectionDone {
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("invalid DNS response")
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
|
||||
}
|
||||
if h.Truncated { // see RFC 5966
|
||||
continue
|
||||
}
|
||||
return p, h, nil
|
||||
}
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("no answer from DNS server")
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errNoAnswerFromDNSServer
|
||||
}
|
||||
|
||||
// checkHeader performs basic sanity checks on the header.
|
||||
func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header, name, server string) error {
|
||||
if h.RCode == dnsmessage.RCodeNameError {
|
||||
return errNoSuchHost
|
||||
}
|
||||
|
||||
_, err := p.AnswerHeader()
|
||||
if err != nil && err != dnsmessage.ErrSectionDone {
|
||||
return &DNSError{
|
||||
Err: "cannot unmarshal DNS message",
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
return errCannotUnmarshalDNSMessage
|
||||
}
|
||||
|
||||
// libresolv continues to the next server when it receives
|
||||
// an invalid referral response. See golang.org/issue/15434.
|
||||
if h.RCode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone {
|
||||
return &DNSError{Err: "lame referral", Name: name, Server: server}
|
||||
return errLameReferral
|
||||
}
|
||||
|
||||
if h.RCode != dnsmessage.RCodeSuccess && h.RCode != dnsmessage.RCodeNameError {
|
||||
@@ -180,11 +194,10 @@ func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header, name, server string)
|
||||
// a name error and we didn't get success,
|
||||
// the server is behaving incorrectly or
|
||||
// having temporary trouble.
|
||||
err := &DNSError{Err: "server misbehaving", Name: name, Server: server}
|
||||
if h.RCode == dnsmessage.RCodeServerFailure {
|
||||
err.IsTemporary = true
|
||||
return errServerTemporarlyMisbehaving
|
||||
}
|
||||
return err
|
||||
return errServerMisbehaving
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -194,28 +207,16 @@ func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type, name, server stri
|
||||
for {
|
||||
h, err := p.AnswerHeader()
|
||||
if err == dnsmessage.ErrSectionDone {
|
||||
return &DNSError{
|
||||
Err: errNoSuchHost.Error(),
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
return errNoSuchHost
|
||||
}
|
||||
if err != nil {
|
||||
return &DNSError{
|
||||
Err: "cannot unmarshal DNS message",
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
return errCannotUnmarshalDNSMessage
|
||||
}
|
||||
if h.Type == qtype {
|
||||
return nil
|
||||
}
|
||||
if err := p.SkipAnswer(); err != nil {
|
||||
return &DNSError{
|
||||
Err: "cannot unmarshal DNS message",
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
return errCannotUnmarshalDNSMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,7 +230,7 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string,
|
||||
|
||||
n, err := dnsmessage.NewName(name)
|
||||
if err != nil {
|
||||
return dnsmessage.Parser{}, "", errors.New("cannot marshal DNS message")
|
||||
return dnsmessage.Parser{}, "", errCannotMarshalDNSMessage
|
||||
}
|
||||
q := dnsmessage.Question{
|
||||
Name: n,
|
||||
@@ -243,38 +244,62 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string,
|
||||
|
||||
p, h, err := r.exchange(ctx, server, q, cfg.timeout)
|
||||
if err != nil {
|
||||
lastErr = &DNSError{
|
||||
dnsErr := &DNSError{
|
||||
Err: err.Error(),
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
if nerr, ok := err.(Error); ok && nerr.Timeout() {
|
||||
lastErr.(*DNSError).IsTimeout = true
|
||||
dnsErr.IsTimeout = true
|
||||
}
|
||||
// Set IsTemporary for socket-level errors. Note that this flag
|
||||
// may also be used to indicate a SERVFAIL response.
|
||||
if _, ok := err.(*OpError); ok {
|
||||
lastErr.(*DNSError).IsTemporary = true
|
||||
dnsErr.IsTemporary = true
|
||||
}
|
||||
lastErr = dnsErr
|
||||
continue
|
||||
}
|
||||
|
||||
// The name does not exist, so trying another server won't help.
|
||||
//
|
||||
// TODO: indicate this in a more obvious way, such as a field on DNSError?
|
||||
if h.RCode == dnsmessage.RCodeNameError {
|
||||
return dnsmessage.Parser{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server}
|
||||
}
|
||||
|
||||
lastErr = checkHeader(&p, h, name, server)
|
||||
if lastErr != nil {
|
||||
if err := checkHeader(&p, h, name, server); err != nil {
|
||||
dnsErr := &DNSError{
|
||||
Err: err.Error(),
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
if err == errServerTemporarlyMisbehaving {
|
||||
dnsErr.IsTemporary = true
|
||||
}
|
||||
if err == errNoSuchHost {
|
||||
// The name does not exist, so trying
|
||||
// another server won't help.
|
||||
//
|
||||
// TODO: indicate this in a more
|
||||
// obvious way, such as a field on
|
||||
// DNSError?
|
||||
return p, server, dnsErr
|
||||
}
|
||||
lastErr = dnsErr
|
||||
continue
|
||||
}
|
||||
|
||||
lastErr = skipToAnswer(&p, qtype, name, server)
|
||||
if lastErr == nil {
|
||||
err = skipToAnswer(&p, qtype, name, server)
|
||||
if err == nil {
|
||||
return p, server, nil
|
||||
}
|
||||
lastErr = &DNSError{
|
||||
Err: err.Error(),
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
if err == errNoSuchHost {
|
||||
// The name does not exist, so trying another
|
||||
// server won't help.
|
||||
//
|
||||
// TODO: indicate this in a more obvious way,
|
||||
// such as a field on DNSError?
|
||||
return p, server, lastErr
|
||||
}
|
||||
}
|
||||
}
|
||||
return dnsmessage.Parser{}, "", lastErr
|
||||
|
||||
@@ -1427,28 +1427,35 @@ func TestDNSGoroutineRace(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func lookupWithFake(fake fakeDNSServer, name string, typ dnsmessage.Type) error {
|
||||
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
||||
|
||||
resolvConf.mu.RLock()
|
||||
conf := resolvConf.dnsConfig
|
||||
resolvConf.mu.RUnlock()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
_, _, err := r.tryOneName(ctx, conf, name, typ)
|
||||
return err
|
||||
}
|
||||
|
||||
// Issue 8434: verify that Temporary returns true on an error when rcode
|
||||
// is SERVFAIL
|
||||
func TestIssue8434(t *testing.T) {
|
||||
msg := dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
RCode: dnsmessage.RCodeServerFailure,
|
||||
err := lookupWithFake(fakeDNSServer{
|
||||
rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
|
||||
return dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
ID: q.ID,
|
||||
Response: true,
|
||||
RCode: dnsmessage.RCodeServerFailure,
|
||||
},
|
||||
Questions: q.Questions,
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
b, err := msg.Pack()
|
||||
if err != nil {
|
||||
t.Fatal("Pack failed:", err)
|
||||
}
|
||||
var p dnsmessage.Parser
|
||||
h, err := p.Start(b)
|
||||
if err != nil {
|
||||
t.Fatal("Start failed:", err)
|
||||
}
|
||||
if err := p.SkipAllQuestions(); err != nil {
|
||||
t.Fatal("SkipAllQuestions failed:", err)
|
||||
}
|
||||
|
||||
err = checkHeader(&p, h, "golang.org", "foo:53")
|
||||
}, "golang.org.", dnsmessage.TypeALL)
|
||||
if err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
@@ -1464,50 +1471,76 @@ func TestIssue8434(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 12778: verify that NXDOMAIN without RA bit errors as
|
||||
// "no such host" and not "server misbehaving"
|
||||
// TestNoSuchHost verifies that tryOneName works correctly when the domain does
|
||||
// not exist.
|
||||
//
|
||||
// Issue 12778: verify that NXDOMAIN without RA bit errors as "no such host"
|
||||
// and not "server misbehaving"
|
||||
//
|
||||
// Issue 25336: verify that NXDOMAIN errors fail fast.
|
||||
func TestIssue12778(t *testing.T) {
|
||||
lookups := 0
|
||||
fake := fakeDNSServer{
|
||||
rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
|
||||
lookups++
|
||||
return dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
ID: q.ID,
|
||||
Response: true,
|
||||
RCode: dnsmessage.RCodeNameError,
|
||||
RecursionAvailable: false,
|
||||
},
|
||||
Questions: q.Questions,
|
||||
}, nil
|
||||
//
|
||||
// Issue 27525: verify that empty answers fail fast.
|
||||
func TestNoSuchHost(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
f func(string, string, dnsmessage.Message, time.Time) (dnsmessage.Message, error)
|
||||
}{
|
||||
{
|
||||
"NXDOMAIN",
|
||||
func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
|
||||
return dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
ID: q.ID,
|
||||
Response: true,
|
||||
RCode: dnsmessage.RCodeNameError,
|
||||
RecursionAvailable: false,
|
||||
},
|
||||
Questions: q.Questions,
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
"no answers",
|
||||
func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
|
||||
return dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
ID: q.ID,
|
||||
Response: true,
|
||||
RCode: dnsmessage.RCodeSuccess,
|
||||
RecursionAvailable: false,
|
||||
Authoritative: true,
|
||||
},
|
||||
Questions: q.Questions,
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
||||
|
||||
resolvConf.mu.RLock()
|
||||
conf := resolvConf.dnsConfig
|
||||
resolvConf.mu.RUnlock()
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
lookups := 0
|
||||
err := lookupWithFake(fakeDNSServer{
|
||||
rh: func(n, s string, q dnsmessage.Message, d time.Time) (dnsmessage.Message, error) {
|
||||
lookups++
|
||||
return test.f(n, s, q, d)
|
||||
},
|
||||
}, ".", dnsmessage.TypeALL)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
if lookups != 1 {
|
||||
t.Errorf("got %d lookups, wanted 1", lookups)
|
||||
}
|
||||
|
||||
_, _, err := r.tryOneName(ctx, conf, ".", dnsmessage.TypeALL)
|
||||
|
||||
if lookups != 1 {
|
||||
t.Errorf("got %d lookups, wanted 1", lookups)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
de, ok := err.(*DNSError)
|
||||
if !ok {
|
||||
t.Fatalf("err = %#v; wanted a *net.DNSError", err)
|
||||
}
|
||||
if de.Err != errNoSuchHost.Error() {
|
||||
t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error())
|
||||
if err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
de, ok := err.(*DNSError)
|
||||
if !ok {
|
||||
t.Fatalf("err = %#v; wanted a *net.DNSError", err)
|
||||
}
|
||||
if de.Err != errNoSuchHost.Error() {
|
||||
t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1535,3 +1568,56 @@ func TestDNSDialTCP(t *testing.T) {
|
||||
t.Fatal("exhange failed:", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 27763: verify that two strings in one TXT record are concatenated.
|
||||
func TestTXTRecordTwoStrings(t *testing.T) {
|
||||
fake := fakeDNSServer{
|
||||
rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
|
||||
r := dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
ID: q.Header.ID,
|
||||
Response: true,
|
||||
RCode: dnsmessage.RCodeSuccess,
|
||||
},
|
||||
Questions: q.Questions,
|
||||
Answers: []dnsmessage.Resource{
|
||||
{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: q.Questions[0].Name,
|
||||
Type: dnsmessage.TypeA,
|
||||
Class: dnsmessage.ClassINET,
|
||||
},
|
||||
Body: &dnsmessage.TXTResource{
|
||||
TXT: []string{"string1 ", "string2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: q.Questions[0].Name,
|
||||
Type: dnsmessage.TypeA,
|
||||
Class: dnsmessage.ClassINET,
|
||||
},
|
||||
Body: &dnsmessage.TXTResource{
|
||||
TXT: []string{"onestring"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return r, nil
|
||||
},
|
||||
}
|
||||
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
||||
txt, err := r.lookupTXT(context.Background(), "golang.org")
|
||||
if err != nil {
|
||||
t.Fatal("LookupTXT failed:", err)
|
||||
}
|
||||
if want := 2; len(txt) != want {
|
||||
t.Fatalf("len(txt), got %d, want %d", len(txt), want)
|
||||
}
|
||||
if want := "string1 string2"; txt[0] != want {
|
||||
t.Errorf("txt[0], got %q, want %q", txt[0], want)
|
||||
}
|
||||
if want := "onestring"; txt[1] != want {
|
||||
t.Errorf("txt[1], got %q, want %q", txt[1], want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,16 +583,23 @@ func TestFileServerZeroByte(t *testing.T) {
|
||||
ts := httptest.NewServer(FileServer(Dir(".")))
|
||||
defer ts.Close()
|
||||
|
||||
res, err := Get(ts.URL + "/..\x00")
|
||||
c, err := net.Dial("tcp", ts.Listener.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b, err := ioutil.ReadAll(res.Body)
|
||||
defer c.Close()
|
||||
_, err = fmt.Fprintf(c, "GET /..\x00 HTTP/1.0\r\n\r\n")
|
||||
if err != nil {
|
||||
t.Fatal("reading Body:", err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
var got bytes.Buffer
|
||||
bufr := bufio.NewReader(io.TeeReader(c, &got))
|
||||
res, err := ReadResponse(bufr, nil)
|
||||
if err != nil {
|
||||
t.Fatal("ReadResponse: ", err)
|
||||
}
|
||||
if res.StatusCode == 200 {
|
||||
t.Errorf("got status 200; want an error. Body is:\n%s", string(b))
|
||||
t.Errorf("got status 200; want an error. Body is:\n%s", got.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user