mirror of
https://github.com/golang/go.git
synced 2026-01-29 23:22:06 +03:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac7c0ee26d | ||
|
|
ff5bff8a5f | ||
|
|
76b63aaab9 | ||
|
|
051e204c79 | ||
|
|
e069f90e17 | ||
|
|
04c58320c9 | ||
|
|
67582b1669 | ||
|
|
eef2fd28ca | ||
|
|
4bc847d8c9 | ||
|
|
c917b3c32b | ||
|
|
9f7d0c968f | ||
|
|
4e19a5498d | ||
|
|
df9d6204b9 | ||
|
|
67b6956270 | ||
|
|
8d90bb4b19 | ||
|
|
24879947d5 | ||
|
|
1188eb9c5b | ||
|
|
ee97231599 | ||
|
|
69a7f73de8 | ||
|
|
853155f384 | ||
|
|
b8c62b1a89 | ||
|
|
176900a7b7 | ||
|
|
e1c0834592 | ||
|
|
fe0d248f29 | ||
|
|
b3398f8fa8 | ||
|
|
6936a87ce1 | ||
|
|
678dede7bc | ||
|
|
bf86aec259 | ||
|
|
0b3f04d5f9 | ||
|
|
d1fbe07092 | ||
|
|
c622ec556b | ||
|
|
07a153e0a4 | ||
|
|
65b209897f | ||
|
|
a68e93791d | ||
|
|
419e6f0835 |
@@ -23,6 +23,24 @@ in supported releases as needed by issuing minor revisions
|
||||
(for example, Go 1.9.1, Go 1.9.2, and so on).
|
||||
</p>
|
||||
|
||||
<h2 id="go1.10">go1.10 (released 2018/02/16)</h2>
|
||||
|
||||
<p>
|
||||
Go 1.10 is a major release of Go.
|
||||
Read the <a href="/doc/go1.10">Go 1.10 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="go1.10.minor">Minor revisions</h3>
|
||||
|
||||
<p>
|
||||
go1.10.1 (released 2018/03/28) includes fixes to the compiler, runtime, and the
|
||||
<code>archive/zip</code>, <code>crypto/tls</code>, <code>crypto/x509</code>,
|
||||
<code>encoding/json</code>, <code>net</code>, <code>net/http</code>, and
|
||||
<code>net/http/pprof</code> packages.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.1">Go
|
||||
1.10.1 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.9">go1.9 (released 2017/08/24)</h2>
|
||||
|
||||
<p>
|
||||
@@ -63,6 +81,13 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.9.4">Go
|
||||
1.9.4</a> milestone on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.9.5 (released 2018/03/28) includes fixes to the compiler, go command, and
|
||||
<code>net/http/pprof</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.9.5">Go
|
||||
1.9.5 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.8">go1.8 (released 2017/02/16)</h2>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -15,12 +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.10</h2>
|
||||
|
||||
<p><strong>
|
||||
Go 1.10 is not yet released. These are work-in-progress
|
||||
release notes. Go 1.10 is expected to be released in February 2018.
|
||||
</strong></p>
|
||||
<h2 id="introduction">Introduction to Go 1.10</h2>
|
||||
|
||||
<p>
|
||||
The latest Go release, version 1.10, arrives six months after <a href="go1.9">Go 1.9</a>.
|
||||
@@ -35,6 +30,10 @@ adds <a href="#test">caching of successful test results</a>,
|
||||
runs <a href="#test-vet">vet automatically during tests</a>,
|
||||
and
|
||||
permits <a href="#cgo">passing string values directly between Go and C using cgo</a>.
|
||||
A new <a href="#cgo">compiler option whitelist</a> may cause
|
||||
unexpected <a href="https://golang.org/s/invalidflag"><code>invalid
|
||||
flag</code></a> errors in code that built successfully with older
|
||||
releases.
|
||||
</p>
|
||||
|
||||
<h2 id="language">Changes to the language</h2>
|
||||
@@ -266,6 +265,18 @@ and the <a href="/cmd/test2json/">test2json documentation</a>.
|
||||
|
||||
<h3 id="cgo">Cgo</h3>
|
||||
|
||||
<p>
|
||||
Options specified by cgo using <code>#cgo CFLAGS</code> and the like
|
||||
are now checked against a whitelist of permitted options.
|
||||
This closes a security hole in which a downloaded package uses
|
||||
compiler options like
|
||||
<span style="white-space: nowrap"><code>-fplugin</code></span>
|
||||
to run arbitrary code on the machine where it is being built.
|
||||
This can cause a build error such as <code>invalid flag in #cgo CFLAGS</code>.
|
||||
For more background, and how to handle this error, see
|
||||
<a href="https://golang.org/s/invalidflag">https://golang.org/s/invalidflag</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Cgo now implements a C typedef like “<code>typedef</code> <code>X</code> <code>Y</code>” using a Go type alias,
|
||||
so that Go code may use the types <code>C.X</code> and <code>C.Y</code> interchangeably.
|
||||
@@ -1214,6 +1225,10 @@ The content-serving handlers also now omit the <code>Content-Type</code> header
|
||||
if passed an invalid (non-3-digit) status code.
|
||||
</p>
|
||||
<p>
|
||||
<!-- CL 46631 -->
|
||||
The <code>Server</code> will no longer add an implicit Content-Type when a <code>Handler</code> does not write any output.
|
||||
</p>
|
||||
<p>
|
||||
<a href="/pkg/net/http/#Redirect"><code>Redirect</code></a> now sets the <code>Content-Type</code> header before writing its HTTP response.
|
||||
</p>
|
||||
</dl>
|
||||
|
||||
21
misc/cgo/testplugin/src/issue24351/main.go
Normal file
21
misc/cgo/testplugin/src/issue24351/main.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// 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 main
|
||||
|
||||
import "plugin"
|
||||
|
||||
func main() {
|
||||
p, err := plugin.Open("issue24351.so")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
f, err := p.Lookup("B")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c := make(chan bool)
|
||||
f.(func(chan bool))(c)
|
||||
<-c
|
||||
}
|
||||
14
misc/cgo/testplugin/src/issue24351/plugin.go
Normal file
14
misc/cgo/testplugin/src/issue24351/plugin.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// 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 main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func B(c chan bool) {
|
||||
go func() {
|
||||
fmt.Println(1.5)
|
||||
c <- true
|
||||
}()
|
||||
}
|
||||
@@ -85,3 +85,8 @@ GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22175 src/issue22175/main.
|
||||
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue.22295.so issue22295.pkg
|
||||
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22295 src/issue22295.pkg/main.go
|
||||
./issue22295
|
||||
|
||||
# Test for issue 24351
|
||||
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue24351.so src/issue24351/plugin.go
|
||||
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue24351 src/issue24351/main.go
|
||||
./issue24351
|
||||
|
||||
@@ -366,7 +366,7 @@ parseExtras:
|
||||
epoch := time.Date(1601, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||
modified = time.Unix(epoch.Unix()+secs, nsecs)
|
||||
}
|
||||
case unixExtraID:
|
||||
case unixExtraID, infoZipUnixExtraID:
|
||||
if len(fieldBuf) < 8 {
|
||||
continue parseExtras
|
||||
}
|
||||
@@ -379,12 +379,6 @@ parseExtras:
|
||||
}
|
||||
ts := int64(fieldBuf.uint32()) // ModTime since Unix epoch
|
||||
modified = time.Unix(ts, 0)
|
||||
case infoZipUnixExtraID:
|
||||
if len(fieldBuf) < 4 {
|
||||
continue parseExtras
|
||||
}
|
||||
ts := int64(fieldBuf.uint32()) // ModTime since Unix epoch
|
||||
modified = time.Unix(ts, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -414,7 +414,7 @@ var tests = []ZipTest{
|
||||
Name: "test.txt",
|
||||
Content: []byte{},
|
||||
Size: 1<<32 - 1,
|
||||
Modified: time.Date(2017, 10, 31, 21, 17, 27, 0, timeZone(-7*time.Hour)),
|
||||
Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)),
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1346,8 +1346,22 @@ func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma {
|
||||
}
|
||||
p.linknames = append(p.linknames, linkname{pos, f[1], f[2]})
|
||||
|
||||
case strings.HasPrefix(text, "go:cgo_import_dynamic "):
|
||||
// This is permitted for general use because Solaris
|
||||
// code relies on it in golang.org/x/sys/unix and others.
|
||||
fields := pragmaFields(text)
|
||||
if len(fields) >= 4 {
|
||||
lib := strings.Trim(fields[3], `"`)
|
||||
if lib != "" && !safeArg(lib) && !isCgoGeneratedFile(pos) {
|
||||
p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("invalid library name %q in cgo_import_dynamic directive", lib)})
|
||||
}
|
||||
p.pragcgobuf += p.pragcgo(pos, text)
|
||||
return pragmaValue("go:cgo_import_dynamic")
|
||||
}
|
||||
fallthrough
|
||||
case strings.HasPrefix(text, "go:cgo_"):
|
||||
// For security, we disallow //go:cgo_* directives outside cgo-generated files.
|
||||
// For security, we disallow //go:cgo_* directives other
|
||||
// than cgo_import_dynamic outside cgo-generated files.
|
||||
// Exception: they are allowed in the standard library, for runtime and syscall.
|
||||
if !isCgoGeneratedFile(pos) && !compiling_std {
|
||||
p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in cgo-generated code", text)})
|
||||
@@ -1383,6 +1397,18 @@ func isCgoGeneratedFile(pos src.Pos) bool {
|
||||
return strings.HasPrefix(filepath.Base(filepath.Clean(pos.AbsFilename())), "_cgo_")
|
||||
}
|
||||
|
||||
// safeArg reports whether arg is a "safe" command-line argument,
|
||||
// meaning that when it appears in a command-line, it probably
|
||||
// doesn't have some special meaning other than its own name.
|
||||
// This is copied from SafeArg in cmd/go/internal/load/pkg.go.
|
||||
func safeArg(name string) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
}
|
||||
c := name[0]
|
||||
return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf
|
||||
}
|
||||
|
||||
func mkname(sym *types.Sym) *Node {
|
||||
n := oldname(sym)
|
||||
if n.Name != nil && n.Name.Pack != nil {
|
||||
|
||||
@@ -1647,9 +1647,9 @@
|
||||
(SUBQconst (MOVQconst [d]) [c]) -> (MOVQconst [d-c])
|
||||
(SUBQconst (SUBQconst x [d]) [c]) && is32Bit(-c-d) -> (ADDQconst [-c-d] x)
|
||||
(SARQconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
|
||||
(SARLconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
|
||||
(SARWconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
|
||||
(SARBconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
|
||||
(SARLconst [c] (MOVQconst [d])) -> (MOVQconst [int64(int32(d))>>uint64(c)])
|
||||
(SARWconst [c] (MOVQconst [d])) -> (MOVQconst [int64(int16(d))>>uint64(c)])
|
||||
(SARBconst [c] (MOVQconst [d])) -> (MOVQconst [int64(int8(d))>>uint64(c)])
|
||||
(NEGQ (MOVQconst [c])) -> (MOVQconst [-c])
|
||||
(NEGL (MOVLconst [c])) -> (MOVLconst [int64(int32(-c))])
|
||||
(MULQconst [c] (MOVQconst [d])) -> (MOVQconst [c*d])
|
||||
|
||||
@@ -270,22 +270,22 @@ func init() {
|
||||
// Note: x86 is weird, the 16 and 8 byte shifts still use all 5 bits of shift amount!
|
||||
|
||||
{name: "SHRQ", argLength: 2, reg: gp21shift, asm: "SHRQ", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 64
|
||||
{name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true, clobberFlags: true}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true, clobberFlags: true}, // unsigned uint16(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true, clobberFlags: true}, // unsigned uint8(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SHRQconst", argLength: 1, reg: gp11, asm: "SHRQ", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-63
|
||||
{name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-31
|
||||
{name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-15
|
||||
{name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-7
|
||||
{name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned uint32(arg0) >> auxint, shift amount 0-31
|
||||
{name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned uint16(arg0) >> auxint, shift amount 0-15
|
||||
{name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned uint8(arg0) >> auxint, shift amount 0-7
|
||||
|
||||
{name: "SARQ", argLength: 2, reg: gp21shift, asm: "SARQ", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 64
|
||||
{name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true}, // signed int32(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true, clobberFlags: true}, // signed int16(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true, clobberFlags: true}, // signed int8(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SARQconst", argLength: 1, reg: gp11, asm: "SARQ", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63
|
||||
{name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-31
|
||||
{name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-15
|
||||
{name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-7
|
||||
{name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed int32(arg0) >> auxint, shift amount 0-31
|
||||
{name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed int16(arg0) >> auxint, shift amount 0-15
|
||||
{name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed int8(arg0) >> auxint, shift amount 0-7
|
||||
|
||||
{name: "ROLQ", argLength: 2, reg: gp21shift, asm: "ROLQ", resultInArg0: true, clobberFlags: true}, // arg0 rotate left arg1 bits.
|
||||
{name: "ROLL", argLength: 2, reg: gp21shift, asm: "ROLL", resultInArg0: true, clobberFlags: true}, // arg0 rotate left arg1 bits.
|
||||
|
||||
@@ -1088,7 +1088,7 @@
|
||||
(SUBconst (MOVDconst [d]) [c]) -> (MOVDconst [d-c])
|
||||
(SUBconst (SUBconst x [d]) [c]) && is32Bit(-c-d) -> (ADDconst [-c-d] x)
|
||||
(SRADconst [c] (MOVDconst [d])) -> (MOVDconst [d>>uint64(c)])
|
||||
(SRAWconst [c] (MOVDconst [d])) -> (MOVDconst [d>>uint64(c)])
|
||||
(SRAWconst [c] (MOVDconst [d])) -> (MOVDconst [int64(int32(d))>>uint64(c)])
|
||||
(NEG (MOVDconst [c])) -> (MOVDconst [-c])
|
||||
(NEGW (MOVDconst [c])) -> (MOVDconst [int64(int32(-c))])
|
||||
(MULLDconst [c] (MOVDconst [d])) -> (MOVDconst [c*d])
|
||||
|
||||
@@ -309,15 +309,15 @@ func init() {
|
||||
{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int8"}, // arg0 << auxint, shift amount 0-31
|
||||
|
||||
{name: "SRD", argLength: 2, reg: sh21, asm: "SRD"}, // unsigned arg0 >> arg1, shift amount is mod 64
|
||||
{name: "SRW", argLength: 2, reg: sh21, asm: "SRW"}, // unsigned arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SRW", argLength: 2, reg: sh21, asm: "SRW"}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-63
|
||||
{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-31
|
||||
{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int8"}, // unsigned uint32(arg0) >> auxint, shift amount 0-31
|
||||
|
||||
// Arithmetic shifts clobber flags.
|
||||
{name: "SRAD", argLength: 2, reg: sh21, asm: "SRAD", clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 64
|
||||
{name: "SRAW", argLength: 2, reg: sh21, asm: "SRAW", clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SRAW", argLength: 2, reg: sh21, asm: "SRAW", clobberFlags: true}, // signed int32(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int8", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63
|
||||
{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int8", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-31
|
||||
{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int8", clobberFlags: true}, // signed int32(arg0) >> auxint, shift amount 0-31
|
||||
|
||||
{name: "RLLGconst", argLength: 1, reg: gp11, asm: "RLLG", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-63
|
||||
{name: "RLLconst", argLength: 1, reg: gp11, asm: "RLL", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-31
|
||||
@@ -485,8 +485,8 @@ func init() {
|
||||
// Atomic adds.
|
||||
// *(arg0+auxint+aux) += arg1. arg2=mem.
|
||||
// Returns a tuple of <old contents of *(arg0+auxint+aux), memory>.
|
||||
{name: "LAA", argLength: 3, reg: gpstorelaa, asm: "LAA", typ: "(UInt32,Mem)", aux: "SymOff", faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
|
||||
{name: "LAAG", argLength: 3, reg: gpstorelaa, asm: "LAAG", typ: "(UInt64,Mem)", aux: "SymOff", faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
|
||||
{name: "LAA", argLength: 3, reg: gpstorelaa, asm: "LAA", typ: "(UInt32,Mem)", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
|
||||
{name: "LAAG", argLength: 3, reg: gpstorelaa, asm: "LAAG", typ: "(UInt64,Mem)", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
|
||||
{name: "AddTupleFirst32", argLength: 2}, // arg1=tuple <x,y>. Returns <x+arg0,y>.
|
||||
{name: "AddTupleFirst64", argLength: 2}, // arg1=tuple <x,y>. Returns <x+arg0,y>.
|
||||
|
||||
|
||||
@@ -22080,6 +22080,7 @@ var opcodeTable = [...]opInfo{
|
||||
name: "LAA",
|
||||
auxType: auxSymOff,
|
||||
argLen: 3,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
symEffect: SymRdWr,
|
||||
@@ -22098,6 +22099,7 @@ var opcodeTable = [...]opInfo{
|
||||
name: "LAAG",
|
||||
auxType: auxSymOff,
|
||||
argLen: 3,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
symEffect: SymRdWr,
|
||||
|
||||
@@ -34892,7 +34892,7 @@ func rewriteValueAMD64_OpAMD64SARBconst_0(v *Value) bool {
|
||||
}
|
||||
// match: (SARBconst [c] (MOVQconst [d]))
|
||||
// cond:
|
||||
// result: (MOVQconst [d>>uint64(c)])
|
||||
// result: (MOVQconst [int64(int8(d))>>uint64(c)])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
v_0 := v.Args[0]
|
||||
@@ -34901,7 +34901,7 @@ func rewriteValueAMD64_OpAMD64SARBconst_0(v *Value) bool {
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
v.reset(OpAMD64MOVQconst)
|
||||
v.AuxInt = d >> uint64(c)
|
||||
v.AuxInt = int64(int8(d)) >> uint64(c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -35147,7 +35147,7 @@ func rewriteValueAMD64_OpAMD64SARLconst_0(v *Value) bool {
|
||||
}
|
||||
// match: (SARLconst [c] (MOVQconst [d]))
|
||||
// cond:
|
||||
// result: (MOVQconst [d>>uint64(c)])
|
||||
// result: (MOVQconst [int64(int32(d))>>uint64(c)])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
v_0 := v.Args[0]
|
||||
@@ -35156,7 +35156,7 @@ func rewriteValueAMD64_OpAMD64SARLconst_0(v *Value) bool {
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
v.reset(OpAMD64MOVQconst)
|
||||
v.AuxInt = d >> uint64(c)
|
||||
v.AuxInt = int64(int32(d)) >> uint64(c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -35467,7 +35467,7 @@ func rewriteValueAMD64_OpAMD64SARWconst_0(v *Value) bool {
|
||||
}
|
||||
// match: (SARWconst [c] (MOVQconst [d]))
|
||||
// cond:
|
||||
// result: (MOVQconst [d>>uint64(c)])
|
||||
// result: (MOVQconst [int64(int16(d))>>uint64(c)])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
v_0 := v.Args[0]
|
||||
@@ -35476,7 +35476,7 @@ func rewriteValueAMD64_OpAMD64SARWconst_0(v *Value) bool {
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
v.reset(OpAMD64MOVQconst)
|
||||
v.AuxInt = d >> uint64(c)
|
||||
v.AuxInt = int64(int16(d)) >> uint64(c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -37197,7 +37197,7 @@ func rewriteValueS390X_OpS390XSRAW_0(v *Value) bool {
|
||||
func rewriteValueS390X_OpS390XSRAWconst_0(v *Value) bool {
|
||||
// match: (SRAWconst [c] (MOVDconst [d]))
|
||||
// cond:
|
||||
// result: (MOVDconst [d>>uint64(c)])
|
||||
// result: (MOVDconst [int64(int32(d))>>uint64(c)])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
v_0 := v.Args[0]
|
||||
@@ -37206,7 +37206,7 @@ func rewriteValueS390X_OpS390XSRAWconst_0(v *Value) bool {
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
v.reset(OpS390XMOVDconst)
|
||||
v.AuxInt = d >> uint64(c)
|
||||
v.AuxInt = int64(int32(d)) >> uint64(c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -238,23 +238,28 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
|
||||
// if y {
|
||||
// }
|
||||
// }
|
||||
f.edit.Insert(f.offset(n.Body.End()), "else{")
|
||||
elseOffset := f.findText(n.Body.End(), "else")
|
||||
if elseOffset < 0 {
|
||||
panic("lost else")
|
||||
}
|
||||
f.edit.Delete(elseOffset, elseOffset+4)
|
||||
f.edit.Insert(elseOffset+4, "{")
|
||||
f.edit.Insert(f.offset(n.Else.End()), "}")
|
||||
|
||||
// We just created a block, now walk it.
|
||||
// Adjust the position of the new block to start after
|
||||
// the "else". That will cause it to follow the "{"
|
||||
// we inserted above.
|
||||
pos := f.fset.File(n.Body.End()).Pos(elseOffset + 4)
|
||||
switch stmt := n.Else.(type) {
|
||||
case *ast.IfStmt:
|
||||
block := &ast.BlockStmt{
|
||||
Lbrace: n.Body.End(), // Start at end of the "if" block so the covered part looks like it starts at the "else".
|
||||
Lbrace: pos,
|
||||
List: []ast.Stmt{stmt},
|
||||
Rbrace: stmt.End(),
|
||||
}
|
||||
n.Else = block
|
||||
case *ast.BlockStmt:
|
||||
stmt.Lbrace = n.Body.End() // Start at end of the "if" block so the covered part looks like it starts at the "else".
|
||||
stmt.Lbrace = pos
|
||||
default:
|
||||
panic("unexpected node type in if")
|
||||
}
|
||||
|
||||
@@ -59,6 +59,17 @@ func TestCover(t *testing.T) {
|
||||
for i, line := range lines {
|
||||
lines[i] = bytes.Replace(line, []byte("LINE"), []byte(fmt.Sprint(i+1)), -1)
|
||||
}
|
||||
|
||||
// Add a function that is not gofmt'ed. This used to cause a crash.
|
||||
// We don't put it in test.go because then we would have to gofmt it.
|
||||
// Issue 23927.
|
||||
lines = append(lines, []byte("func unFormatted() {"),
|
||||
[]byte("\tif true {"),
|
||||
[]byte("\t}else{"),
|
||||
[]byte("\t}"),
|
||||
[]byte("}"))
|
||||
lines = append(lines, []byte("func unFormatted2(b bool) {if b{}else{}}"))
|
||||
|
||||
if err := ioutil.WriteFile(coverInput, bytes.Join(lines, []byte("\n")), 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -246,6 +257,7 @@ func TestCoverFunc(t *testing.T) {
|
||||
}
|
||||
|
||||
func run(c *exec.Cmd, t *testing.T) {
|
||||
t.Helper()
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stderr
|
||||
err := c.Run()
|
||||
|
||||
@@ -3233,6 +3233,16 @@ func TestGoVetWithOnlyTestFiles(t *testing.T) {
|
||||
tg.run("vet", "p")
|
||||
}
|
||||
|
||||
// Issue 24193.
|
||||
func TestVetWithOnlyCgoFiles(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempFile("src/p/p.go", "package p; import \"C\"; func F() {}")
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.run("vet", "p")
|
||||
}
|
||||
|
||||
// Issue 9767, 19769.
|
||||
func TestGoGetDotSlashDownload(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
@@ -5740,6 +5750,21 @@ func TestAtomicCoverpkgAll(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 23882.
|
||||
func TestCoverpkgAllRuntime(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
|
||||
tg.tempFile("src/x/x.go", `package x; import _ "runtime"; func F() {}`)
|
||||
tg.tempFile("src/x/x_test.go", `package x; import "testing"; func TestF(t *testing.T) { F() }`)
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.run("test", "-coverpkg=all", "x")
|
||||
if canRace {
|
||||
tg.run("test", "-coverpkg=all", "-race", "x")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadCommandLines(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
@@ -5888,3 +5913,36 @@ func TestBadCgoDirectives(t *testing.T) {
|
||||
tg.run("build", "-n", "x")
|
||||
tg.grepStderr("-D@foo", "did not find -D@foo in commands")
|
||||
}
|
||||
|
||||
func TestTwoPkgConfigs(t *testing.T) {
|
||||
if !canCgo {
|
||||
t.Skip("no cgo")
|
||||
}
|
||||
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
|
||||
t.Skipf("no shell scripts on %s", runtime.GOOS)
|
||||
}
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempFile("src/x/a.go", `package x
|
||||
// #cgo pkg-config: --static a
|
||||
import "C"
|
||||
`)
|
||||
tg.tempFile("src/x/b.go", `package x
|
||||
// #cgo pkg-config: --static a
|
||||
import "C"
|
||||
`)
|
||||
tg.tempFile("pkg-config.sh", `#!/bin/sh
|
||||
echo $* >>`+tg.path("pkg-config.out"))
|
||||
tg.must(os.Chmod(tg.path("pkg-config.sh"), 0755))
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.setenv("PKG_CONFIG", tg.path("pkg-config.sh"))
|
||||
tg.run("build", "x")
|
||||
out, err := ioutil.ReadFile(tg.path("pkg-config.out"))
|
||||
tg.must(err)
|
||||
out = bytes.TrimSpace(out)
|
||||
want := "--cflags --static --static -- a a\n--libs --static --static -- a a"
|
||||
if !bytes.Equal(out, []byte(want)) {
|
||||
t.Errorf("got %q want %q", out, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -809,8 +809,8 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.Contains(mmi.RepoRoot, "://") {
|
||||
return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, mmi.RepoRoot)
|
||||
if err := validateRepoRootScheme(mmi.RepoRoot); err != nil {
|
||||
return nil, fmt.Errorf("%s: invalid repo root %q: %v", urlStr, mmi.RepoRoot, err)
|
||||
}
|
||||
rr := &repoRoot{
|
||||
vcs: vcsByCmd(mmi.VCS),
|
||||
@@ -824,6 +824,36 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re
|
||||
return rr, nil
|
||||
}
|
||||
|
||||
// validateRepoRootScheme returns an error if repoRoot does not seem
|
||||
// to have a valid URL scheme. At this point we permit things that
|
||||
// aren't valid URLs, although later, if not using -insecure, we will
|
||||
// restrict repoRoots to be valid URLs. This is only because we've
|
||||
// historically permitted them, and people may depend on that.
|
||||
func validateRepoRootScheme(repoRoot string) error {
|
||||
end := strings.Index(repoRoot, "://")
|
||||
if end <= 0 {
|
||||
return errors.New("no scheme")
|
||||
}
|
||||
|
||||
// RFC 3986 section 3.1.
|
||||
for i := 0; i < end; i++ {
|
||||
c := repoRoot[i]
|
||||
switch {
|
||||
case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
|
||||
// OK.
|
||||
case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
|
||||
// OK except at start.
|
||||
if i == 0 {
|
||||
return errors.New("invalid scheme")
|
||||
}
|
||||
default:
|
||||
return errors.New("invalid scheme")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var fetchGroup singleflight.Group
|
||||
var (
|
||||
fetchCacheMu sync.Mutex
|
||||
|
||||
@@ -408,3 +408,46 @@ func TestMatchGoImport(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRepoRootScheme(t *testing.T) {
|
||||
tests := []struct {
|
||||
root string
|
||||
err string
|
||||
}{
|
||||
{
|
||||
root: "",
|
||||
err: "no scheme",
|
||||
},
|
||||
{
|
||||
root: "http://",
|
||||
err: "",
|
||||
},
|
||||
{
|
||||
root: "a://",
|
||||
err: "",
|
||||
},
|
||||
{
|
||||
root: "a#://",
|
||||
err: "invalid scheme",
|
||||
},
|
||||
{
|
||||
root: "-config://",
|
||||
err: "invalid scheme",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
err := validateRepoRootScheme(test.root)
|
||||
if err == nil {
|
||||
if test.err != "" {
|
||||
t.Errorf("validateRepoRootScheme(%q) = nil, want %q", test.root, test.err)
|
||||
}
|
||||
} else if test.err == "" {
|
||||
if err != nil {
|
||||
t.Errorf("validateRepoRootScheme(%q) = %q, want nil", test.root, test.err)
|
||||
}
|
||||
} else if err.Error() != test.err {
|
||||
t.Errorf("validateRepoRootScheme(%q) = %q, want %q", test.root, err, test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1206,6 +1206,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
|
||||
// GNU binutils flagfile specifiers, sometimes called "response files").
|
||||
// To be conservative, we reject almost any arg beginning with non-alphanumeric ASCII.
|
||||
// We accept leading . _ and / as likely in file system paths.
|
||||
// There is a copy of this function in cmd/compile/internal/gc/noder.go.
|
||||
func SafeArg(name string) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
|
||||
@@ -668,6 +668,14 @@ func runTest(cmd *base.Command, args []string) {
|
||||
continue
|
||||
}
|
||||
|
||||
// If using the race detector, silently ignore
|
||||
// attempts to run coverage on the runtime
|
||||
// packages. It will cause the race detector
|
||||
// to be invoked before it has been initialized.
|
||||
if cfg.BuildRace && p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal")) {
|
||||
continue
|
||||
}
|
||||
|
||||
if haveMatch {
|
||||
testCoverPkgs = append(testCoverPkgs, p)
|
||||
}
|
||||
|
||||
@@ -62,11 +62,11 @@ func runVet(cmd *base.Command, args []string) {
|
||||
base.Errorf("%v", err)
|
||||
continue
|
||||
}
|
||||
if len(ptest.GoFiles) == 0 && pxtest == nil {
|
||||
if len(ptest.GoFiles) == 0 && len(ptest.CgoFiles) == 0 && pxtest == nil {
|
||||
base.Errorf("go vet %s: no Go files in %s", p.ImportPath, p.Dir)
|
||||
continue
|
||||
}
|
||||
if len(ptest.GoFiles) > 0 {
|
||||
if len(ptest.GoFiles) > 0 || len(ptest.CgoFiles) > 0 {
|
||||
root.Deps = append(root.Deps, b.VetAction(work.ModeBuild, work.ModeBuild, ptest))
|
||||
}
|
||||
if pxtest != nil {
|
||||
|
||||
@@ -934,16 +934,29 @@ func splitPkgConfigOutput(out []byte) []string {
|
||||
|
||||
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
|
||||
func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) {
|
||||
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
|
||||
if pcargs := p.CgoPkgConfig; len(pcargs) > 0 {
|
||||
// pkg-config permits arguments to appear anywhere in
|
||||
// the command line. Move them all to the front, before --.
|
||||
var pcflags []string
|
||||
var pkgs []string
|
||||
for _, pcarg := range pcargs {
|
||||
if pcarg == "--" {
|
||||
// We're going to add our own "--" argument.
|
||||
} else if strings.HasPrefix(pcarg, "--") {
|
||||
pcflags = append(pcflags, pcarg)
|
||||
} else {
|
||||
pkgs = append(pkgs, pcarg)
|
||||
}
|
||||
}
|
||||
for _, pkg := range pkgs {
|
||||
if !load.SafeArg(pkg) {
|
||||
return nil, nil, fmt.Errorf("invalid pkg-config package name: %s", pkg)
|
||||
}
|
||||
}
|
||||
var out []byte
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--cflags", "--", pkgs)
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--cflags", pcflags, "--", pkgs)
|
||||
if err != nil {
|
||||
b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out))
|
||||
b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pcflags, " ")+strings.Join(pkgs, " "), string(out))
|
||||
b.Print(err.Error() + "\n")
|
||||
return nil, nil, errPrintedOutput
|
||||
}
|
||||
@@ -953,15 +966,15 @@ func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string,
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--libs", "--", pkgs)
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--libs", pcflags, "--", pkgs)
|
||||
if err != nil {
|
||||
b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out))
|
||||
b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pcflags, " ")+strings.Join(pkgs, " "), string(out))
|
||||
b.Print(err.Error() + "\n")
|
||||
return nil, nil, errPrintedOutput
|
||||
}
|
||||
if len(out) > 0 {
|
||||
ldflags = strings.Fields(string(out))
|
||||
if err := checkLinkerFlags("CFLAGS", "pkg-config --cflags", ldflags); err != nil {
|
||||
if err := checkLinkerFlags("LDFLAGS", "pkg-config --libs", ldflags); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var re = regexp.MustCompile
|
||||
@@ -45,27 +46,65 @@ var validCompilerFlags = []*regexp.Regexp{
|
||||
re(`-O([^@\-].*)`),
|
||||
re(`-W`),
|
||||
re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
|
||||
re(`-Wa,-mbig-obj`),
|
||||
re(`-ansi`),
|
||||
re(`-f(no-)?blocks`),
|
||||
re(`-f(no-)?common`),
|
||||
re(`-f(no-)?constant-cfstrings`),
|
||||
re(`-fdiagnostics-show-note-include-stack`),
|
||||
re(`-f(no-)?exceptions`),
|
||||
re(`-f(no-)?inline-functions`),
|
||||
re(`-finput-charset=([^@\-].*)`),
|
||||
re(`-f(no-)?fat-lto-objects`),
|
||||
re(`-f(no-)?lto`),
|
||||
re(`-fmacro-backtrace-limit=(.+)`),
|
||||
re(`-fmessage-length=(.+)`),
|
||||
re(`-f(no-)?modules`),
|
||||
re(`-f(no-)?objc-arc`),
|
||||
re(`-f(no-)?omit-frame-pointer`),
|
||||
re(`-f(no-)?openmp(-simd)?`),
|
||||
re(`-f(no-)?permissive`),
|
||||
re(`-f(no-)?(pic|PIC|pie|PIE)`),
|
||||
re(`-f(no-)?rtti`),
|
||||
re(`-f(no-)?split-stack`),
|
||||
re(`-f(no-)?stack-(.+)`),
|
||||
re(`-f(no-)?strict-aliasing`),
|
||||
re(`-f(un)signed-char`),
|
||||
re(`-f(no-)?use-linker-plugin`), // safe if -B is not used; we don't permit -B
|
||||
re(`-fsanitize=(.+)`),
|
||||
re(`-ftemplate-depth-(.+)`),
|
||||
re(`-fvisibility=(.+)`),
|
||||
re(`-g([^@\-].*)?`),
|
||||
re(`-m32`),
|
||||
re(`-m64`),
|
||||
re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
|
||||
re(`-m(no-)?avx[0-9a-z.]*`),
|
||||
re(`-m(no-)?ms-bitfields`),
|
||||
re(`-m(no-)?stack-(.+)`),
|
||||
re(`-mmacosx-(.+)`),
|
||||
re(`-mios-simulator-version-min=(.+)`),
|
||||
re(`-miphoneos-version-min=(.+)`),
|
||||
re(`-mnop-fun-dllimport`),
|
||||
re(`-m(no-)?sse[0-9.]*`),
|
||||
re(`-mwindows`),
|
||||
re(`-pedantic(-errors)?`),
|
||||
re(`-pipe`),
|
||||
re(`-pthread`),
|
||||
re(`-std=([^@\-].*)`),
|
||||
re(`-?-std=([^@\-].*)`),
|
||||
re(`-?-stdlib=([^@\-].*)`),
|
||||
re(`-w`),
|
||||
re(`-x([^@\-].*)`),
|
||||
}
|
||||
|
||||
var validCompilerFlagsWithNextArg = []string{
|
||||
"-arch",
|
||||
"-D",
|
||||
"-I",
|
||||
"-framework",
|
||||
"-isysroot",
|
||||
"-isystem",
|
||||
"--sysroot",
|
||||
"-target",
|
||||
"-x",
|
||||
}
|
||||
|
||||
@@ -73,29 +112,65 @@ var validLinkerFlags = []*regexp.Regexp{
|
||||
re(`-F([^@\-].*)`),
|
||||
re(`-l([^@\-].*)`),
|
||||
re(`-L([^@\-].*)`),
|
||||
re(`-O`),
|
||||
re(`-O([^@\-].*)`),
|
||||
re(`-f(no-)?(pic|PIC|pie|PIE)`),
|
||||
re(`-fsanitize=([^@\-].*)`),
|
||||
re(`-g([^@\-].*)?`),
|
||||
re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
|
||||
re(`-mmacosx-(.+)`),
|
||||
re(`-mios-simulator-version-min=(.+)`),
|
||||
re(`-miphoneos-version-min=(.+)`),
|
||||
re(`-mwindows`),
|
||||
re(`-(pic|PIC|pie|PIE)`),
|
||||
re(`-pthread`),
|
||||
re(`-shared`),
|
||||
re(`-?-static([-a-z0-9+]*)`),
|
||||
re(`-?-stdlib=([^@\-].*)`),
|
||||
|
||||
// Note that any wildcards in -Wl need to exclude comma,
|
||||
// since -Wl splits its argument at commas and passes
|
||||
// them all to the linker uninterpreted. Allowing comma
|
||||
// in a wildcard would allow tunnelling arbitrary additional
|
||||
// linker arguments through one of these.
|
||||
re(`-Wl,-rpath,([^,@\-][^,]+)`),
|
||||
re(`-Wl,--(no-)?allow-multiple-definition`),
|
||||
re(`-Wl,--(no-)?as-needed`),
|
||||
re(`-Wl,-Bdynamic`),
|
||||
re(`-Wl,-Bstatic`),
|
||||
re(`-Wl,-d[ny]`),
|
||||
re(`-Wl,--disable-new-dtags`),
|
||||
re(`-Wl,--enable-new-dtags`),
|
||||
re(`-Wl,--end-group`),
|
||||
re(`-Wl,-framework,[^,@\-][^,]+`),
|
||||
re(`-Wl,-headerpad_max_install_names`),
|
||||
re(`-Wl,--no-undefined`),
|
||||
re(`-Wl,-rpath[=,]([^,@\-][^,]+)`),
|
||||
re(`-Wl,-search_paths_first`),
|
||||
re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`),
|
||||
re(`-Wl,--start-group`),
|
||||
re(`-Wl,-?-static`),
|
||||
re(`-Wl,--subsystem,(native|windows|console|posix|xbox)`),
|
||||
re(`-Wl,-undefined[=,]([^,@\-][^,]+)`),
|
||||
re(`-Wl,-?-unresolved-symbols=[^,]+`),
|
||||
re(`-Wl,--(no-)?warn-([^,]+)`),
|
||||
re(`-Wl,-z,(no)?execstack`),
|
||||
re(`-Wl,-z,relro`),
|
||||
|
||||
re(`[a-zA-Z0-9_].*\.(o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
|
||||
re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
|
||||
}
|
||||
|
||||
var validLinkerFlagsWithNextArg = []string{
|
||||
"-arch",
|
||||
"-F",
|
||||
"-l",
|
||||
"-L",
|
||||
"-framework",
|
||||
"-isysroot",
|
||||
"--sysroot",
|
||||
"-target",
|
||||
"-Wl,-framework",
|
||||
"-Wl,-rpath",
|
||||
"-Wl,-undefined",
|
||||
}
|
||||
|
||||
func checkCompilerFlags(name, source string, list []string) error {
|
||||
@@ -147,10 +222,21 @@ Args:
|
||||
i++
|
||||
continue Args
|
||||
}
|
||||
if i+1 < len(list) {
|
||||
return fmt.Errorf("invalid flag in %s: %s %s", source, arg, list[i+1])
|
||||
|
||||
// Permit -Wl,-framework -Wl,name.
|
||||
if i+1 < len(list) &&
|
||||
strings.HasPrefix(arg, "-Wl,") &&
|
||||
strings.HasPrefix(list[i+1], "-Wl,") &&
|
||||
load.SafeArg(list[i+1][4:]) &&
|
||||
!strings.Contains(list[i+1][4:], ",") {
|
||||
i++
|
||||
continue Args
|
||||
}
|
||||
return fmt.Errorf("invalid flag in %s: %s without argument", source, arg)
|
||||
|
||||
if i+1 < len(list) {
|
||||
return fmt.Errorf("invalid flag in %s: %s %s (see https://golang.org/s/invalidflag)", source, arg, list[i+1])
|
||||
}
|
||||
return fmt.Errorf("invalid flag in %s: %s without argument (see https://golang.org/s/invalidflag)", source, arg)
|
||||
}
|
||||
}
|
||||
Bad:
|
||||
|
||||
@@ -132,14 +132,14 @@ var goodLinkerFlags = [][]string{
|
||||
{"-l", "世界"},
|
||||
{"-L", "framework"},
|
||||
{"-framework", "Chocolate"},
|
||||
{"-Wl,-framework", "-Wl,Chocolate"},
|
||||
{"-Wl,-framework,Chocolate"},
|
||||
{"-Wl,-unresolved-symbols=ignore-all"},
|
||||
}
|
||||
|
||||
var badLinkerFlags = [][]string{
|
||||
{"-DFOO"},
|
||||
{"-Dfoo=bar"},
|
||||
{"-O"},
|
||||
{"-O2"},
|
||||
{"-Osmall"},
|
||||
{"-W"},
|
||||
{"-Wall"},
|
||||
{"-fobjc-arc"},
|
||||
@@ -152,7 +152,6 @@ var badLinkerFlags = [][]string{
|
||||
{"-fno-stack-xxx"},
|
||||
{"-mstack-overflow"},
|
||||
{"-mno-stack-overflow"},
|
||||
{"-mmacosx-version"},
|
||||
{"-mnop-fun-dllimport"},
|
||||
{"-std=c99"},
|
||||
{"-xc"},
|
||||
@@ -185,6 +184,10 @@ var badLinkerFlags = [][]string{
|
||||
{"-l", "-foo"},
|
||||
{"-framework", "-Caffeine"},
|
||||
{"-framework", "@Home"},
|
||||
{"-Wl,-framework,-Caffeine"},
|
||||
{"-Wl,-framework", "-Wl,@Home"},
|
||||
{"-Wl,-framework", "@Home"},
|
||||
{"-Wl,-framework,Chocolate,@Home"},
|
||||
{"-x", "--c"},
|
||||
{"-x", "@obj"},
|
||||
{"-Wl,-rpath,@foo"},
|
||||
|
||||
34
src/cmd/internal/objabi/funcid.go
Normal file
34
src/cmd/internal/objabi/funcid.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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 objabi
|
||||
|
||||
// A FuncID identifies particular functions that need to be treated
|
||||
// specially by the runtime.
|
||||
// Note that in some situations involving plugins, there may be multiple
|
||||
// copies of a particular special runtime function.
|
||||
// Note: this list must match the list in runtime/symtab.go.
|
||||
type FuncID uint32
|
||||
|
||||
const (
|
||||
FuncID_normal FuncID = iota // not a special function
|
||||
FuncID_goexit
|
||||
FuncID_jmpdefer
|
||||
FuncID_mcall
|
||||
FuncID_morestack
|
||||
FuncID_mstart
|
||||
FuncID_rt0_go
|
||||
FuncID_asmcgocall
|
||||
FuncID_sigpanic
|
||||
FuncID_runfinq
|
||||
FuncID_bgsweep
|
||||
FuncID_forcegchelper
|
||||
FuncID_timerproc
|
||||
FuncID_gcBgMarkWorker
|
||||
FuncID_systemstack_switch
|
||||
FuncID_systemstack
|
||||
FuncID_cgocallback_gofunc
|
||||
FuncID_gogo
|
||||
FuncID_externalthreadhandler
|
||||
)
|
||||
@@ -312,12 +312,47 @@ func (ctxt *Link) pclntab() {
|
||||
}
|
||||
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), args))
|
||||
|
||||
// frame int32
|
||||
// This has been removed (it was never set quite correctly anyway).
|
||||
// Nothing should use it.
|
||||
// Leave an obviously incorrect value.
|
||||
// TODO: Remove entirely.
|
||||
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), 0x1234567))
|
||||
// funcID uint32
|
||||
funcID := objabi.FuncID_normal
|
||||
switch s.Name {
|
||||
case "runtime.goexit":
|
||||
funcID = objabi.FuncID_goexit
|
||||
case "runtime.jmpdefer":
|
||||
funcID = objabi.FuncID_jmpdefer
|
||||
case "runtime.mcall":
|
||||
funcID = objabi.FuncID_mcall
|
||||
case "runtime.morestack":
|
||||
funcID = objabi.FuncID_morestack
|
||||
case "runtime.mstart":
|
||||
funcID = objabi.FuncID_mstart
|
||||
case "runtime.rt0_go":
|
||||
funcID = objabi.FuncID_rt0_go
|
||||
case "runtime.asmcgocall":
|
||||
funcID = objabi.FuncID_asmcgocall
|
||||
case "runtime.sigpanic":
|
||||
funcID = objabi.FuncID_sigpanic
|
||||
case "runtime.runfinq":
|
||||
funcID = objabi.FuncID_runfinq
|
||||
case "runtime.bgsweep":
|
||||
funcID = objabi.FuncID_bgsweep
|
||||
case "runtime.forcegchelper":
|
||||
funcID = objabi.FuncID_forcegchelper
|
||||
case "runtime.timerproc":
|
||||
funcID = objabi.FuncID_timerproc
|
||||
case "runtime.gcBgMarkWorker":
|
||||
funcID = objabi.FuncID_gcBgMarkWorker
|
||||
case "runtime.systemstack_switch":
|
||||
funcID = objabi.FuncID_systemstack_switch
|
||||
case "runtime.systemstack":
|
||||
funcID = objabi.FuncID_systemstack
|
||||
case "runtime.cgocallback_gofunc":
|
||||
funcID = objabi.FuncID_cgocallback_gofunc
|
||||
case "runtime.gogo":
|
||||
funcID = objabi.FuncID_gogo
|
||||
case "runtime.externalthreadhandler":
|
||||
funcID = objabi.FuncID_externalthreadhandler
|
||||
}
|
||||
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(funcID)))
|
||||
|
||||
if pcln != &pclntabZpcln {
|
||||
renumberfiles(ctxt, pcln.File, &pcln.Pcfile)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"crypto/rand"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@@ -42,6 +43,7 @@ type nameConstraintsTest struct {
|
||||
roots []constraintsSpec
|
||||
intermediates [][]constraintsSpec
|
||||
leaf leafSpec
|
||||
requestedEKUs []ExtKeyUsage
|
||||
expectedError string
|
||||
noOpenSSL bool
|
||||
}
|
||||
@@ -1444,6 +1446,118 @@ var nameConstraintsTests = []nameConstraintsTest{
|
||||
},
|
||||
expectedError: "\"https://example.com/test\" is excluded",
|
||||
},
|
||||
|
||||
// #75: While serverAuth in a CA certificate permits clientAuth in a leaf,
|
||||
// serverAuth in a leaf shouldn't permit clientAuth when requested in
|
||||
// VerifyOptions.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"dns:example.com"},
|
||||
ekus: []string{"serverAuth"},
|
||||
},
|
||||
requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
|
||||
expectedError: "incompatible key usage",
|
||||
},
|
||||
|
||||
// #76: However, MSSGC in a leaf should match a request for serverAuth.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"dns:example.com"},
|
||||
ekus: []string{"msSGC"},
|
||||
},
|
||||
requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
|
||||
},
|
||||
|
||||
// An invalid DNS SAN should be detected only at validation time so
|
||||
// that we can process CA certificates in the wild that have invalid SANs.
|
||||
// See https://github.com/golang/go/issues/23995
|
||||
|
||||
// #77: an invalid DNS or mail SAN will not be detected if name constaint
|
||||
// checking is not triggered.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"dns:this is invalid", "email:this @ is invalid"},
|
||||
},
|
||||
},
|
||||
|
||||
// #78: an invalid DNS SAN will be detected if any name constraint checking
|
||||
// is triggered.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{
|
||||
bad: []string{"uri:"},
|
||||
},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"dns:this is invalid"},
|
||||
},
|
||||
expectedError: "cannot parse dnsName",
|
||||
},
|
||||
|
||||
// #79: an invalid email SAN will be detected if any name constraint
|
||||
// checking is triggered.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{
|
||||
bad: []string{"uri:"},
|
||||
},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"email:this @ is invalid"},
|
||||
},
|
||||
expectedError: "cannot parse rfc822Name",
|
||||
},
|
||||
|
||||
// #80: if several EKUs are requested, satisfying any of them is sufficient.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"dns:example.com"},
|
||||
ekus: []string{"email"},
|
||||
},
|
||||
requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection},
|
||||
},
|
||||
}
|
||||
|
||||
func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
|
||||
@@ -1512,6 +1626,13 @@ func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certi
|
||||
}
|
||||
template.IPAddresses = append(template.IPAddresses, ip)
|
||||
|
||||
case strings.HasPrefix(name, "invalidip:"):
|
||||
ipBytes, err := hex.DecodeString(name[10:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse invalid IP: %s", err)
|
||||
}
|
||||
template.IPAddresses = append(template.IPAddresses, net.IP(ipBytes))
|
||||
|
||||
case strings.HasPrefix(name, "email:"):
|
||||
template.EmailAddresses = append(template.EmailAddresses, name[6:])
|
||||
|
||||
@@ -1781,6 +1902,7 @@ func TestConstraintCases(t *testing.T) {
|
||||
Roots: rootPool,
|
||||
Intermediates: intermediatePool,
|
||||
CurrentTime: time.Unix(1500, 0),
|
||||
KeyUsages: test.requestedEKUs,
|
||||
}
|
||||
_, err = leafCert.Verify(verifyOpts)
|
||||
|
||||
@@ -1972,12 +2094,13 @@ func TestBadNamesInConstraints(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBadNamesInSANs(t *testing.T) {
|
||||
// Bad names in SANs should not parse.
|
||||
// Bad names in URI and IP SANs should not parse. Bad DNS and email SANs
|
||||
// will parse and are tested in name constraint tests at the top of this
|
||||
// file.
|
||||
badNames := []string{
|
||||
"dns:foo.com.",
|
||||
"email:abc@foo.com.",
|
||||
"email:foo.com.",
|
||||
"uri:https://example.com./dsf",
|
||||
"invalidip:0102",
|
||||
"invalidip:0102030405",
|
||||
}
|
||||
|
||||
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
|
||||
@@ -6,12 +6,14 @@ package x509
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
@@ -178,10 +180,14 @@ type VerifyOptions struct {
|
||||
Intermediates *CertPool
|
||||
Roots *CertPool // if nil, the system roots are used
|
||||
CurrentTime time.Time // if zero, the current time is used
|
||||
// KeyUsage specifies which Extended Key Usage values are acceptable.
|
||||
// An empty list means ExtKeyUsageServerAuth. Key usage is considered a
|
||||
// constraint down the chain which mirrors Windows CryptoAPI behavior,
|
||||
// but not the spec. To accept any key usage, include ExtKeyUsageAny.
|
||||
// KeyUsage specifies which Extended Key Usage values are acceptable. A leaf
|
||||
// certificate is accepted if it contains any of the listed values. An empty
|
||||
// list means ExtKeyUsageServerAuth. To accept any key usage, include
|
||||
// ExtKeyUsageAny.
|
||||
//
|
||||
// Certificate chains are required to nest extended key usage values,
|
||||
// irrespective of this value. This matches the Windows CryptoAPI behavior,
|
||||
// but not the spec.
|
||||
KeyUsages []ExtKeyUsage
|
||||
// MaxConstraintComparisions is the maximum number of comparisons to
|
||||
// perform when checking a given certificate's name constraints. If
|
||||
@@ -543,11 +549,16 @@ func (c *Certificate) checkNameConstraints(count *int,
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
checkingAgainstIssuerCert = iota
|
||||
checkingAgainstLeafCert
|
||||
)
|
||||
|
||||
// ekuPermittedBy returns true iff the given extended key usage is permitted by
|
||||
// the given EKU from a certificate. Normally, this would be a simple
|
||||
// comparison plus a special case for the “any” EKU. But, in order to support
|
||||
// existing certificates, some exceptions are made.
|
||||
func ekuPermittedBy(eku, certEKU ExtKeyUsage) bool {
|
||||
func ekuPermittedBy(eku, certEKU ExtKeyUsage, context int) bool {
|
||||
if certEKU == ExtKeyUsageAny || eku == certEKU {
|
||||
return true
|
||||
}
|
||||
@@ -564,18 +575,23 @@ func ekuPermittedBy(eku, certEKU ExtKeyUsage) bool {
|
||||
eku = mapServerAuthEKUs(eku)
|
||||
certEKU = mapServerAuthEKUs(certEKU)
|
||||
|
||||
if eku == certEKU ||
|
||||
// ServerAuth in a CA permits ClientAuth in the leaf.
|
||||
(eku == ExtKeyUsageClientAuth && certEKU == ExtKeyUsageServerAuth) ||
|
||||
if eku == certEKU {
|
||||
return true
|
||||
}
|
||||
|
||||
// If checking a requested EKU against the list in a leaf certificate there
|
||||
// are fewer exceptions.
|
||||
if context == checkingAgainstLeafCert {
|
||||
return false
|
||||
}
|
||||
|
||||
// ServerAuth in a CA permits ClientAuth in the leaf.
|
||||
return (eku == ExtKeyUsageClientAuth && certEKU == ExtKeyUsageServerAuth) ||
|
||||
// Any CA may issue an OCSP responder certificate.
|
||||
eku == ExtKeyUsageOCSPSigning ||
|
||||
// Code-signing CAs can use Microsoft's commercial and
|
||||
// kernel-mode EKUs.
|
||||
((eku == ExtKeyUsageMicrosoftCommercialCodeSigning || eku == ExtKeyUsageMicrosoftKernelCodeSigning) && certEKU == ExtKeyUsageCodeSigning) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
(eku == ExtKeyUsageMicrosoftCommercialCodeSigning || eku == ExtKeyUsageMicrosoftKernelCodeSigning) && certEKU == ExtKeyUsageCodeSigning
|
||||
}
|
||||
|
||||
// isValid performs validity checks on c given that it is a candidate to append
|
||||
@@ -630,8 +646,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
|
||||
name := string(data)
|
||||
mailbox, ok := parseRFC2821Mailbox(name)
|
||||
if !ok {
|
||||
// This certificate should not have parsed.
|
||||
return errors.New("x509: internal error: rfc822Name SAN failed to parse")
|
||||
return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox)
|
||||
}
|
||||
|
||||
if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox,
|
||||
@@ -643,6 +658,10 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
|
||||
|
||||
case nameTypeDNS:
|
||||
name := string(data)
|
||||
if _, ok := domainToReverseLabels(name); !ok {
|
||||
return fmt.Errorf("x509: cannot parse dnsName %q", name)
|
||||
}
|
||||
|
||||
if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name,
|
||||
func(parsedName, constraint interface{}) (bool, error) {
|
||||
return matchDomainConstraint(parsedName.(string), constraint.(string))
|
||||
@@ -716,7 +735,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
|
||||
|
||||
for _, caEKU := range c.ExtKeyUsage {
|
||||
comparisonCount++
|
||||
if ekuPermittedBy(eku, caEKU) {
|
||||
if ekuPermittedBy(eku, caEKU, checkingAgainstIssuerCert) {
|
||||
continue NextEKU
|
||||
}
|
||||
}
|
||||
@@ -773,6 +792,18 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
|
||||
return nil
|
||||
}
|
||||
|
||||
// formatOID formats an ASN.1 OBJECT IDENTIFER in the common, dotted style.
|
||||
func formatOID(oid asn1.ObjectIdentifier) string {
|
||||
ret := ""
|
||||
for i, v := range oid {
|
||||
if i > 0 {
|
||||
ret += "."
|
||||
}
|
||||
ret += strconv.Itoa(v)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Verify attempts to verify c by building one or more chains from c to a
|
||||
// certificate in opts.Roots, using certificates in opts.Intermediates if
|
||||
// needed. If successful, it returns one or more chains where the first
|
||||
@@ -847,16 +878,33 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
|
||||
}
|
||||
|
||||
if checkEKU {
|
||||
foundMatch := false
|
||||
NextUsage:
|
||||
for _, eku := range requestedKeyUsages {
|
||||
for _, leafEKU := range c.ExtKeyUsage {
|
||||
if ekuPermittedBy(eku, leafEKU) {
|
||||
continue NextUsage
|
||||
if ekuPermittedBy(eku, leafEKU, checkingAgainstLeafCert) {
|
||||
foundMatch = true
|
||||
break NextUsage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
oid, _ := oidFromExtKeyUsage(eku)
|
||||
return nil, CertificateInvalidError{c, IncompatibleUsage, fmt.Sprintf("%#v", oid)}
|
||||
if !foundMatch {
|
||||
msg := "leaf contains the following, recognized EKUs: "
|
||||
|
||||
for i, leafEKU := range c.ExtKeyUsage {
|
||||
oid, ok := oidFromExtKeyUsage(leafEKU)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
msg += ", "
|
||||
}
|
||||
msg += formatOID(oid)
|
||||
}
|
||||
|
||||
return nil, CertificateInvalidError{c, IncompatibleUsage, msg}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -706,7 +706,9 @@ type Certificate struct {
|
||||
OCSPServer []string
|
||||
IssuingCertificateURL []string
|
||||
|
||||
// Subject Alternate Name values
|
||||
// Subject Alternate Name values. (Note that these values may not be valid
|
||||
// if invalid values were contained within a parsed certificate. For
|
||||
// example, an element of DNSNames may not be a valid DNS domain name.)
|
||||
DNSNames []string
|
||||
EmailAddresses []string
|
||||
IPAddresses []net.IP
|
||||
@@ -1126,17 +1128,9 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre
|
||||
err = forEachSAN(value, func(tag int, data []byte) error {
|
||||
switch tag {
|
||||
case nameTypeEmail:
|
||||
mailbox := string(data)
|
||||
if _, ok := parseRFC2821Mailbox(mailbox); !ok {
|
||||
return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox)
|
||||
}
|
||||
emailAddresses = append(emailAddresses, mailbox)
|
||||
emailAddresses = append(emailAddresses, string(data))
|
||||
case nameTypeDNS:
|
||||
domain := string(data)
|
||||
if _, ok := domainToReverseLabels(domain); !ok {
|
||||
return fmt.Errorf("x509: cannot parse dnsName %q", string(data))
|
||||
}
|
||||
dnsNames = append(dnsNames, domain)
|
||||
dnsNames = append(dnsNames, string(data))
|
||||
case nameTypeURI:
|
||||
uri, err := url.Parse(string(data))
|
||||
if err != nil {
|
||||
@@ -1153,7 +1147,7 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre
|
||||
case net.IPv4len, net.IPv6len:
|
||||
ipAddresses = append(ipAddresses, data)
|
||||
default:
|
||||
return errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(data)))
|
||||
return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -443,10 +443,25 @@ func (d *decodeState) valueQuoted() interface{} {
|
||||
// if it encounters an Unmarshaler, indirect stops and returns that.
|
||||
// if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
|
||||
func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) {
|
||||
// Issue #24153 indicates that it is generally not a guaranteed property
|
||||
// that you may round-trip a reflect.Value by calling Value.Addr().Elem()
|
||||
// and expect the value to still be settable for values derived from
|
||||
// unexported embedded struct fields.
|
||||
//
|
||||
// The logic below effectively does this when it first addresses the value
|
||||
// (to satisfy possible pointer methods) and continues to dereference
|
||||
// subsequent pointers as necessary.
|
||||
//
|
||||
// After the first round-trip, we set v back to the original value to
|
||||
// preserve the original RW flags contained in reflect.Value.
|
||||
v0 := v
|
||||
haveAddr := false
|
||||
|
||||
// If v is a named type and is addressable,
|
||||
// start with its address, so that if the type has pointer methods,
|
||||
// we find them.
|
||||
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
|
||||
haveAddr = true
|
||||
v = v.Addr()
|
||||
}
|
||||
for {
|
||||
@@ -455,6 +470,7 @@ func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler,
|
||||
if v.Kind() == reflect.Interface && !v.IsNil() {
|
||||
e := v.Elem()
|
||||
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
|
||||
haveAddr = false
|
||||
v = e
|
||||
continue
|
||||
}
|
||||
@@ -480,7 +496,13 @@ func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler,
|
||||
}
|
||||
}
|
||||
}
|
||||
v = v.Elem()
|
||||
|
||||
if haveAddr {
|
||||
v = v0 // restore original value after round-trip Value.Addr().Elem()
|
||||
haveAddr = false
|
||||
} else {
|
||||
v = v.Elem()
|
||||
}
|
||||
}
|
||||
return nil, nil, v
|
||||
}
|
||||
|
||||
@@ -2089,10 +2089,14 @@ func TestInvalidStringOption(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test unmarshal behavior with regards to embedded pointers to unexported structs.
|
||||
// If unallocated, this returns an error because unmarshal cannot set the field.
|
||||
// Issue 21357.
|
||||
func TestUnmarshalEmbeddedPointerUnexported(t *testing.T) {
|
||||
// Test unmarshal behavior with regards to embedded unexported structs.
|
||||
//
|
||||
// (Issue 21357) If the embedded struct is a pointer and is unallocated,
|
||||
// this returns an error because unmarshal cannot set the field.
|
||||
//
|
||||
// (Issue 24152) If the embedded struct is given an explicit name,
|
||||
// ensure that the normal unmarshal logic does not panic in reflect.
|
||||
func TestUnmarshalEmbeddedUnexported(t *testing.T) {
|
||||
type (
|
||||
embed1 struct{ Q int }
|
||||
embed2 struct{ Q int }
|
||||
@@ -2119,6 +2123,18 @@ func TestUnmarshalEmbeddedPointerUnexported(t *testing.T) {
|
||||
*embed3
|
||||
R int
|
||||
}
|
||||
S6 struct {
|
||||
embed1 `json:"embed1"`
|
||||
}
|
||||
S7 struct {
|
||||
embed1 `json:"embed1"`
|
||||
embed2
|
||||
}
|
||||
S8 struct {
|
||||
embed1 `json:"embed1"`
|
||||
embed2 `json:"embed2"`
|
||||
Q int
|
||||
}
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
@@ -2154,6 +2170,32 @@ func TestUnmarshalEmbeddedPointerUnexported(t *testing.T) {
|
||||
ptr: new(S5),
|
||||
out: &S5{R: 2},
|
||||
err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed3"),
|
||||
}, {
|
||||
// Issue 24152, ensure decodeState.indirect does not panic.
|
||||
in: `{"embed1": {"Q": 1}}`,
|
||||
ptr: new(S6),
|
||||
out: &S6{embed1{1}},
|
||||
}, {
|
||||
// Issue 24153, check that we can still set forwarded fields even in
|
||||
// the presence of a name conflict.
|
||||
//
|
||||
// This relies on obscure behavior of reflect where it is possible
|
||||
// to set a forwarded exported field on an unexported embedded struct
|
||||
// even though there is a name conflict, even when it would have been
|
||||
// impossible to do so according to Go visibility rules.
|
||||
// Go forbids this because it is ambiguous whether S7.Q refers to
|
||||
// S7.embed1.Q or S7.embed2.Q. Since embed1 and embed2 are unexported,
|
||||
// it should be impossible for an external package to set either Q.
|
||||
//
|
||||
// It is probably okay for a future reflect change to break this.
|
||||
in: `{"embed1": {"Q": 1}, "Q": 2}`,
|
||||
ptr: new(S7),
|
||||
out: &S7{embed1{1}, embed2{2}},
|
||||
}, {
|
||||
// Issue 24153, similar to the S7 case.
|
||||
in: `{"embed1": {"Q": 1}, "embed2": {"Q": 2}, "Q": 3}`,
|
||||
ptr: new(S8),
|
||||
out: &S8{embed1{1}, embed2{2}, 3},
|
||||
}}
|
||||
|
||||
for i, tt := range tests {
|
||||
|
||||
@@ -44,9 +44,9 @@ func New(ctxt *build.Context, fset *token.FileSet, packages map[string]*types.Pa
|
||||
// for a package that is in the process of being imported.
|
||||
var importing types.Package
|
||||
|
||||
// Import(path) is a shortcut for ImportFrom(path, "", 0).
|
||||
// Import(path) is a shortcut for ImportFrom(path, ".", 0).
|
||||
func (p *Importer) Import(path string) (*types.Package, error) {
|
||||
return p.ImportFrom(path, "", 0)
|
||||
return p.ImportFrom(path, ".", 0) // use "." rather than "" (see issue #24441)
|
||||
}
|
||||
|
||||
// ImportFrom imports the package with the given import path resolved from the given srcDir,
|
||||
@@ -60,23 +60,10 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type
|
||||
panic("non-zero import mode")
|
||||
}
|
||||
|
||||
// determine package path (do vendor resolution)
|
||||
var bp *build.Package
|
||||
var err error
|
||||
switch {
|
||||
default:
|
||||
if abs, err := p.absPath(srcDir); err == nil { // see issue #14282
|
||||
srcDir = abs
|
||||
}
|
||||
bp, err = p.ctxt.Import(path, srcDir, build.FindOnly)
|
||||
|
||||
case build.IsLocalImport(path):
|
||||
// "./x" -> "srcDir/x"
|
||||
bp, err = p.ctxt.ImportDir(filepath.Join(srcDir, path), build.FindOnly)
|
||||
|
||||
case p.isAbsPath(path):
|
||||
return nil, fmt.Errorf("invalid absolute import path %q", path)
|
||||
if abs, err := p.absPath(srcDir); err == nil { // see issue #14282
|
||||
srcDir = abs
|
||||
}
|
||||
bp, err := p.ctxt.Import(path, srcDir, 0)
|
||||
if err != nil {
|
||||
return nil, err // err may be *build.NoGoError - return as is
|
||||
}
|
||||
@@ -113,11 +100,6 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type
|
||||
}
|
||||
}()
|
||||
|
||||
// collect package files
|
||||
bp, err = p.ctxt.ImportDir(bp.Dir, 0)
|
||||
if err != nil {
|
||||
return nil, err // err may be *build.NoGoError - return as is
|
||||
}
|
||||
var filenames []string
|
||||
filenames = append(filenames, bp.GoFiles...)
|
||||
filenames = append(filenames, bp.CgoFiles...)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"go/types"
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
@@ -162,3 +163,34 @@ func TestIssue20855(t *testing.T) {
|
||||
t.Error("got no package despite no hard errors")
|
||||
}
|
||||
}
|
||||
|
||||
func testImportPath(t *testing.T, pkgPath string) {
|
||||
if !testenv.HasSrc() {
|
||||
t.Skip("no source code available")
|
||||
}
|
||||
|
||||
pkgName := path.Base(pkgPath)
|
||||
|
||||
pkg, err := importer.Import(pkgPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if pkg.Name() != pkgName {
|
||||
t.Errorf("got %q; want %q", pkg.Name(), pkgName)
|
||||
}
|
||||
|
||||
if pkg.Path() != pkgPath {
|
||||
t.Errorf("got %q; want %q", pkg.Path(), pkgPath)
|
||||
}
|
||||
}
|
||||
|
||||
// TestIssue23092 tests relative imports.
|
||||
func TestIssue23092(t *testing.T) {
|
||||
testImportPath(t, "./testdata/issue23092")
|
||||
}
|
||||
|
||||
// TestIssue24392 tests imports against a path containing 'testdata'.
|
||||
func TestIssue24392(t *testing.T) {
|
||||
testImportPath(t, "go/internal/srcimporter/testdata/issue24392")
|
||||
}
|
||||
|
||||
5
src/go/internal/srcimporter/testdata/issue23092/issue23092.go
vendored
Normal file
5
src/go/internal/srcimporter/testdata/issue23092/issue23092.go
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// 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 issue23092
|
||||
5
src/go/internal/srcimporter/testdata/issue24392/issue24392.go
vendored
Normal file
5
src/go/internal/srcimporter/testdata/issue24392/issue24392.go
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// 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 issue24392
|
||||
@@ -103,11 +103,21 @@ func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) {
|
||||
g.mu.Unlock()
|
||||
}
|
||||
|
||||
// Forget tells the singleflight to forget about a key. Future calls
|
||||
// to Do for this key will call the function rather than waiting for
|
||||
// an earlier call to complete.
|
||||
func (g *Group) Forget(key string) {
|
||||
// ForgetUnshared tells the singleflight to forget about a key if it is not
|
||||
// shared with any other goroutines. Future calls to Do for a forgotten key
|
||||
// will call the function rather than waiting for an earlier call to complete.
|
||||
// Returns whether the key was forgotten or unknown--that is, whether no
|
||||
// other goroutines are waiting for the result.
|
||||
func (g *Group) ForgetUnshared(key string) bool {
|
||||
g.mu.Lock()
|
||||
delete(g.m, key)
|
||||
g.mu.Unlock()
|
||||
defer g.mu.Unlock()
|
||||
c, ok := g.m[key]
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
if c.dups == 0 {
|
||||
delete(g.m, key)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ func init() {
|
||||
// command line, with arguments separated by NUL bytes.
|
||||
// The package initialization registers it as /debug/pprof/cmdline.
|
||||
func Cmdline(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
|
||||
}
|
||||
@@ -100,33 +101,36 @@ func durationExceedsWriteTimeout(r *http.Request, seconds float64) bool {
|
||||
return ok && srv.WriteTimeout != 0 && seconds >= srv.WriteTimeout.Seconds()
|
||||
}
|
||||
|
||||
func serveError(w http.ResponseWriter, status int, txt string) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.Header().Del("Content-Disposition")
|
||||
w.WriteHeader(status)
|
||||
fmt.Fprintln(w, txt)
|
||||
}
|
||||
|
||||
// Profile responds with the pprof-formatted cpu profile.
|
||||
// The package initialization registers it as /debug/pprof/profile.
|
||||
func Profile(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
|
||||
if sec == 0 {
|
||||
sec = 30
|
||||
}
|
||||
|
||||
if durationExceedsWriteTimeout(r, float64(sec)) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintln(w, "profile duration exceeds server's WriteTimeout")
|
||||
serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout")
|
||||
return
|
||||
}
|
||||
|
||||
// Set Content Type assuming StartCPUProfile will work,
|
||||
// because if it does it starts writing.
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="profile"`)
|
||||
if err := pprof.StartCPUProfile(w); err != nil {
|
||||
// StartCPUProfile failed, so no writes yet.
|
||||
// Can change header back to text content
|
||||
// and send error code.
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
|
||||
serveError(w, http.StatusInternalServerError,
|
||||
fmt.Sprintf("Could not enable CPU profiling: %s", err))
|
||||
return
|
||||
}
|
||||
sleep(w, time.Duration(sec)*time.Second)
|
||||
@@ -137,29 +141,25 @@ func Profile(w http.ResponseWriter, r *http.Request) {
|
||||
// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.
|
||||
// The package initialization registers it as /debug/pprof/trace.
|
||||
func Trace(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
sec, err := strconv.ParseFloat(r.FormValue("seconds"), 64)
|
||||
if sec <= 0 || err != nil {
|
||||
sec = 1
|
||||
}
|
||||
|
||||
if durationExceedsWriteTimeout(r, sec) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintln(w, "profile duration exceeds server's WriteTimeout")
|
||||
serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout")
|
||||
return
|
||||
}
|
||||
|
||||
// Set Content Type assuming trace.Start will work,
|
||||
// because if it does it starts writing.
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="trace"`)
|
||||
if err := trace.Start(w); err != nil {
|
||||
// trace.Start failed, so no writes yet.
|
||||
// Can change header back to text content and send error code.
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
|
||||
serveError(w, http.StatusInternalServerError,
|
||||
fmt.Sprintf("Could not enable tracing: %s", err))
|
||||
return
|
||||
}
|
||||
sleep(w, time.Duration(sec*float64(time.Second)))
|
||||
@@ -170,6 +170,7 @@ func Trace(w http.ResponseWriter, r *http.Request) {
|
||||
// responding with a table mapping program counters to function names.
|
||||
// The package initialization registers it as /debug/pprof/symbol.
|
||||
func Symbol(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
|
||||
// We have to read the whole POST body before
|
||||
@@ -222,18 +223,23 @@ func Handler(name string) http.Handler {
|
||||
type handler string
|
||||
|
||||
func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
debug, _ := strconv.Atoi(r.FormValue("debug"))
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
p := pprof.Lookup(string(name))
|
||||
if p == nil {
|
||||
w.WriteHeader(404)
|
||||
fmt.Fprintf(w, "Unknown profile: %s\n", name)
|
||||
serveError(w, http.StatusNotFound, "Unknown profile")
|
||||
return
|
||||
}
|
||||
gc, _ := strconv.Atoi(r.FormValue("gc"))
|
||||
if name == "heap" && gc > 0 {
|
||||
runtime.GC()
|
||||
}
|
||||
debug, _ := strconv.Atoi(r.FormValue("debug"))
|
||||
if debug != 0 {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name))
|
||||
}
|
||||
p.WriteTo(w, debug)
|
||||
}
|
||||
|
||||
|
||||
69
src/net/http/pprof/pprof_test.go
Normal file
69
src/net/http/pprof/pprof_test.go
Normal file
@@ -0,0 +1,69 @@
|
||||
// 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 pprof
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHandlers(t *testing.T) {
|
||||
testCases := []struct {
|
||||
path string
|
||||
handler http.HandlerFunc
|
||||
statusCode int
|
||||
contentType string
|
||||
contentDisposition string
|
||||
resp []byte
|
||||
}{
|
||||
{"/debug/pprof/<script>scripty<script>", Index, http.StatusNotFound, "text/plain; charset=utf-8", "", []byte("Unknown profile\n")},
|
||||
{"/debug/pprof/heap", Index, http.StatusOK, "application/octet-stream", `attachment; filename="heap"`, nil},
|
||||
{"/debug/pprof/heap?debug=1", Index, http.StatusOK, "text/plain; charset=utf-8", "", nil},
|
||||
{"/debug/pprof/cmdline", Cmdline, http.StatusOK, "text/plain; charset=utf-8", "", nil},
|
||||
{"/debug/pprof/profile?seconds=1", Profile, http.StatusOK, "application/octet-stream", `attachment; filename="profile"`, nil},
|
||||
{"/debug/pprof/symbol", Symbol, http.StatusOK, "text/plain; charset=utf-8", "", nil},
|
||||
{"/debug/pprof/trace", Trace, http.StatusOK, "application/octet-stream", `attachment; filename="trace"`, nil},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.path, func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "http://example.com"+tc.path, nil)
|
||||
w := httptest.NewRecorder()
|
||||
tc.handler(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
if got, want := resp.StatusCode, tc.statusCode; got != want {
|
||||
t.Errorf("status code: got %d; want %d", got, want)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Errorf("when reading response body, expected non-nil err; got %v", err)
|
||||
}
|
||||
if got, want := resp.Header.Get("X-Content-Type-Options"), "nosniff"; got != want {
|
||||
t.Errorf("X-Content-Type-Options: got %q; want %q", got, want)
|
||||
}
|
||||
if got, want := resp.Header.Get("Content-Type"), tc.contentType; got != want {
|
||||
t.Errorf("Content-Type: got %q; want %q", got, want)
|
||||
}
|
||||
if got, want := resp.Header.Get("Content-Disposition"), tc.contentDisposition; got != want {
|
||||
t.Errorf("Content-Disposition: got %q; want %q", got, want)
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
return
|
||||
}
|
||||
if got, want := resp.Header.Get("X-Go-Pprof"), "1"; got != want {
|
||||
t.Errorf("X-Go-Pprof: got %q; want %q", got, want)
|
||||
}
|
||||
if !bytes.Equal(body, tc.resp) {
|
||||
t.Errorf("response: got %q; want %q", body, tc.resp)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -194,10 +194,16 @@ func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, err
|
||||
resolverFunc = alt
|
||||
}
|
||||
|
||||
// We don't want a cancelation of ctx to affect the
|
||||
// lookupGroup operation. Otherwise if our context gets
|
||||
// canceled it might cause an error to be returned to a lookup
|
||||
// using a completely different context.
|
||||
lookupGroupCtx, lookupGroupCancel := context.WithCancel(context.Background())
|
||||
|
||||
dnsWaitGroup.Add(1)
|
||||
ch, called := lookupGroup.DoChan(host, func() (interface{}, error) {
|
||||
defer dnsWaitGroup.Done()
|
||||
return testHookLookupIP(ctx, resolverFunc, host)
|
||||
return testHookLookupIP(lookupGroupCtx, resolverFunc, host)
|
||||
})
|
||||
if !called {
|
||||
dnsWaitGroup.Done()
|
||||
@@ -205,20 +211,28 @@ func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, err
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// If the DNS lookup timed out for some reason, force
|
||||
// future requests to start the DNS lookup again
|
||||
// rather than waiting for the current lookup to
|
||||
// complete. See issue 8602.
|
||||
ctxErr := ctx.Err()
|
||||
if ctxErr == context.DeadlineExceeded {
|
||||
lookupGroup.Forget(host)
|
||||
// Our context was canceled. If we are the only
|
||||
// goroutine looking up this key, then drop the key
|
||||
// from the lookupGroup and cancel the lookup.
|
||||
// If there are other goroutines looking up this key,
|
||||
// let the lookup continue uncanceled, and let later
|
||||
// lookups with the same key share the result.
|
||||
// See issues 8602, 20703, 22724.
|
||||
if lookupGroup.ForgetUnshared(host) {
|
||||
lookupGroupCancel()
|
||||
} else {
|
||||
go func() {
|
||||
<-ch
|
||||
lookupGroupCancel()
|
||||
}()
|
||||
}
|
||||
err := mapErr(ctxErr)
|
||||
err := mapErr(ctx.Err())
|
||||
if trace != nil && trace.DNSDone != nil {
|
||||
trace.DNSDone(nil, false, err)
|
||||
}
|
||||
return nil, err
|
||||
case r := <-ch:
|
||||
lookupGroupCancel()
|
||||
if trace != nil && trace.DNSDone != nil {
|
||||
addrs, _ := r.Val.([]IPAddr)
|
||||
trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
|
||||
|
||||
@@ -791,3 +791,28 @@ func TestLookupNonLDH(t *testing.T) {
|
||||
t.Fatalf("lookup error = %v, want %v", err, errNoSuchHost)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLookupContextCancel(t *testing.T) {
|
||||
if testenv.Builder() == "" {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
}
|
||||
if runtime.GOOS == "nacl" {
|
||||
t.Skip("skip on nacl")
|
||||
}
|
||||
|
||||
defer dnsWaitGroup.Wait()
|
||||
|
||||
ctx, ctxCancel := context.WithCancel(context.Background())
|
||||
ctxCancel()
|
||||
_, err := DefaultResolver.LookupIPAddr(ctx, "google.com")
|
||||
if err != errCanceled {
|
||||
testenv.SkipFlakyNet(t)
|
||||
t.Fatal(err)
|
||||
}
|
||||
ctx = context.Background()
|
||||
_, err = DefaultResolver.LookupIPAddr(ctx, "google.com")
|
||||
if err != nil {
|
||||
testenv.SkipFlakyNet(t)
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ func TestTCPSpuriousConnSetupCompletionWithCancel(t *testing.T) {
|
||||
if testenv.Builder() == "" {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
}
|
||||
defer dnsWaitGroup.Wait()
|
||||
t.Parallel()
|
||||
const tries = 10000
|
||||
var wg sync.WaitGroup
|
||||
|
||||
@@ -73,14 +73,12 @@ func typestring(x interface{}) string {
|
||||
}
|
||||
|
||||
// printany prints an argument passed to panic.
|
||||
// If panic is called with a value that has a String or Error method,
|
||||
// it has already been converted into a string by preprintpanics.
|
||||
func printany(i interface{}) {
|
||||
switch v := i.(type) {
|
||||
case nil:
|
||||
print("nil")
|
||||
case stringer:
|
||||
print(v.String())
|
||||
case error:
|
||||
print(v.Error())
|
||||
case bool:
|
||||
print(v)
|
||||
case int:
|
||||
|
||||
@@ -113,6 +113,14 @@ func (t *itabTableType) find(inter *interfacetype, typ *_type) *itab {
|
||||
// itabAdd adds the given itab to the itab hash table.
|
||||
// itabLock must be held.
|
||||
func itabAdd(m *itab) {
|
||||
// Bugs can lead to calling this while mallocing is set,
|
||||
// typically because this is called while panicing.
|
||||
// Crash reliably, rather than only when we need to grow
|
||||
// the hash table.
|
||||
if getg().m.mallocing != 0 {
|
||||
throw("malloc deadlock")
|
||||
}
|
||||
|
||||
t := itabTable
|
||||
if t.count >= 3*(t.size/4) { // 75% load factor
|
||||
// Grow hash table.
|
||||
|
||||
@@ -304,8 +304,6 @@ func osinit() {
|
||||
|
||||
disableWER()
|
||||
|
||||
externalthreadhandlerp = funcPC(externalthreadhandler)
|
||||
|
||||
initExceptionHandler()
|
||||
|
||||
stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
|
||||
|
||||
@@ -389,7 +389,6 @@ func Goexit() {
|
||||
|
||||
// Call all Error and String methods before freezing the world.
|
||||
// Used when crashing with panicking.
|
||||
// This must match types handled by printany.
|
||||
func preprintpanics(p *_panic) {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
@@ -415,8 +414,6 @@ func printpanics(p *_panic) {
|
||||
print("\t")
|
||||
}
|
||||
print("panic: ")
|
||||
// Because of preprintpanics, p.arg cannot be an error or
|
||||
// stringer, so this won't call into user code.
|
||||
printany(p.arg)
|
||||
if p.recovered {
|
||||
print(" [recovered]")
|
||||
|
||||
@@ -393,6 +393,11 @@ func releaseSudog(s *sudog) {
|
||||
|
||||
// funcPC returns the entry PC of the function f.
|
||||
// It assumes that f is a func value. Otherwise the behavior is undefined.
|
||||
// CAREFUL: In programs with plugins, funcPC can return different values
|
||||
// for the same function (because there are actually multiple copies of
|
||||
// the same function in the address space). To be safe, don't use the
|
||||
// results of this function in any == expression. It is only safe to
|
||||
// use the result as an address at which to start executing code.
|
||||
//go:nosplit
|
||||
func funcPC(f interface{}) uintptr {
|
||||
return **(**uintptr)(add(unsafe.Pointer(&f), sys.PtrSize))
|
||||
@@ -3798,8 +3803,8 @@ func setsSP(pc uintptr) bool {
|
||||
// so assume the worst and stop traceback
|
||||
return true
|
||||
}
|
||||
switch f.entry {
|
||||
case gogoPC, systemstackPC, mcallPC, morestackPC:
|
||||
switch f.funcID {
|
||||
case funcID_gogo, funcID_systemstack, funcID_mcall, funcID_morestack:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -635,8 +635,8 @@ type _func struct {
|
||||
entry uintptr // start pc
|
||||
nameoff int32 // function name
|
||||
|
||||
args int32 // in/out args size
|
||||
_ int32 // previously legacy frame size; kept for layout compatibility
|
||||
args int32 // in/out args size
|
||||
funcID funcID // set for certain special runtime functions
|
||||
|
||||
pcsp int32
|
||||
pcfile int32
|
||||
|
||||
@@ -619,7 +619,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
|
||||
if stackDebug >= 2 {
|
||||
print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n")
|
||||
}
|
||||
if f.entry == systemstack_switchPC {
|
||||
if f.funcID == funcID_systemstack_switch {
|
||||
// A special routine at the bottom of stack of a goroutine that does an systemstack call.
|
||||
// We will allow it to be copied even though we don't
|
||||
// have full GC info for it (because it is written in asm).
|
||||
@@ -1110,7 +1110,8 @@ func shrinkstack(gp *g) {
|
||||
if debug.gcshrinkstackoff > 0 {
|
||||
return
|
||||
}
|
||||
if gp.startpc == gcBgMarkWorkerPC {
|
||||
f := findfunc(gp.startpc)
|
||||
if f.valid() && f.funcID == funcID_gcBgMarkWorker {
|
||||
// We're not allowed to shrink the gcBgMarkWorker
|
||||
// stack (see gcBgMarkWorker for explanation).
|
||||
return
|
||||
|
||||
@@ -133,7 +133,7 @@ again:
|
||||
}
|
||||
se.pcExpander.init(ncallers[0], se.wasPanic)
|
||||
ncallers = ncallers[1:]
|
||||
se.wasPanic = se.pcExpander.funcInfo.valid() && se.pcExpander.funcInfo.entry == sigpanicPC
|
||||
se.wasPanic = se.pcExpander.funcInfo.valid() && se.pcExpander.funcInfo.funcID == funcID_sigpanic
|
||||
if se.skip > 0 {
|
||||
for ; se.skip > 0; se.skip-- {
|
||||
se.pcExpander.next()
|
||||
@@ -349,6 +349,35 @@ const (
|
||||
_ArgsSizeUnknown = -0x80000000
|
||||
)
|
||||
|
||||
// A FuncID identifies particular functions that need to be treated
|
||||
// specially by the runtime.
|
||||
// Note that in some situations involving plugins, there may be multiple
|
||||
// copies of a particular special runtime function.
|
||||
// Note: this list must match the list in cmd/internal/objabi/funcid.go.
|
||||
type funcID uint32
|
||||
|
||||
const (
|
||||
funcID_normal funcID = iota // not a special function
|
||||
funcID_goexit
|
||||
funcID_jmpdefer
|
||||
funcID_mcall
|
||||
funcID_morestack
|
||||
funcID_mstart
|
||||
funcID_rt0_go
|
||||
funcID_asmcgocall
|
||||
funcID_sigpanic
|
||||
funcID_runfinq
|
||||
funcID_bgsweep
|
||||
funcID_forcegchelper
|
||||
funcID_timerproc
|
||||
funcID_gcBgMarkWorker
|
||||
funcID_systemstack_switch
|
||||
funcID_systemstack
|
||||
funcID_cgocallback_gofunc
|
||||
funcID_gogo
|
||||
funcID_externalthreadhandler
|
||||
)
|
||||
|
||||
// moduledata records information about the layout of the executable
|
||||
// image. It is written by the linker. Any changes here must be
|
||||
// matched changes to the code in cmd/internal/ld/symtab.go:symtab.
|
||||
@@ -648,7 +677,6 @@ func findfunc(pc uintptr) funcInfo {
|
||||
idx = uint32(len(datap.ftab) - 1)
|
||||
}
|
||||
if pc < datap.ftab[idx].entry {
|
||||
|
||||
// With multiple text sections, the idx might reference a function address that
|
||||
// is higher than the pc being searched, so search backward until the matching address is found.
|
||||
|
||||
@@ -659,7 +687,6 @@ func findfunc(pc uintptr) funcInfo {
|
||||
throw("findfunc: bad findfunctab entry idx")
|
||||
}
|
||||
} else {
|
||||
|
||||
// linear search to find func with pc >= entry.
|
||||
for datap.ftab[idx+1].entry <= pc {
|
||||
idx++
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
#include "go_tls.h"
|
||||
#include "textflag.h"
|
||||
|
||||
#define AT_FDCWD -100
|
||||
|
||||
#define SYS_read 0
|
||||
#define SYS_write 1
|
||||
#define SYS_open 2
|
||||
#define SYS_close 3
|
||||
#define SYS_mmap 9
|
||||
#define SYS_munmap 11
|
||||
@@ -20,7 +21,6 @@
|
||||
#define SYS_rt_sigaction 13
|
||||
#define SYS_rt_sigprocmask 14
|
||||
#define SYS_rt_sigreturn 15
|
||||
#define SYS_access 21
|
||||
#define SYS_sched_yield 24
|
||||
#define SYS_mincore 27
|
||||
#define SYS_madvise 28
|
||||
@@ -41,9 +41,11 @@
|
||||
#define SYS_sched_getaffinity 204
|
||||
#define SYS_epoll_create 213
|
||||
#define SYS_exit_group 231
|
||||
#define SYS_epoll_wait 232
|
||||
#define SYS_epoll_ctl 233
|
||||
#define SYS_openat 257
|
||||
#define SYS_faccessat 269
|
||||
#define SYS_pselect6 270
|
||||
#define SYS_epoll_pwait 281
|
||||
#define SYS_epoll_create1 291
|
||||
|
||||
TEXT runtime·exit(SB),NOSPLIT,$0-4
|
||||
@@ -65,10 +67,12 @@ TEXT runtime·exitThread(SB),NOSPLIT,$0-8
|
||||
JMP 0(PC)
|
||||
|
||||
TEXT runtime·open(SB),NOSPLIT,$0-20
|
||||
MOVQ name+0(FP), DI
|
||||
MOVL mode+8(FP), SI
|
||||
MOVL perm+12(FP), DX
|
||||
MOVL $SYS_open, AX
|
||||
// This uses openat instead of open, because Android O blocks open.
|
||||
MOVL $AT_FDCWD, DI // AT_FDCWD, so this acts like open
|
||||
MOVQ name+0(FP), SI
|
||||
MOVL mode+8(FP), DX
|
||||
MOVL perm+12(FP), R10
|
||||
MOVL $SYS_openat, AX
|
||||
SYSCALL
|
||||
CMPQ AX, $0xfffffffffffff001
|
||||
JLS 2(PC)
|
||||
@@ -599,7 +603,7 @@ TEXT runtime·settls(SB),NOSPLIT,$32
|
||||
// Same as in sys_darwin_386.s:/ugliness, different constant.
|
||||
// DI currently holds m->tls, which must be fs:0x1d0.
|
||||
// See cgo/gcc_android_amd64.c for the derivation of the constant.
|
||||
SUBQ $0x1d0, DI // In android, the tls base
|
||||
SUBQ $0x1d0, DI // In android, the tls base
|
||||
#else
|
||||
ADDQ $8, DI // ELF wants to use -8(FS)
|
||||
#endif
|
||||
@@ -655,11 +659,13 @@ TEXT runtime·epollctl(SB),NOSPLIT,$0
|
||||
|
||||
// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
|
||||
TEXT runtime·epollwait(SB),NOSPLIT,$0
|
||||
// This uses pwait instead of wait, because Android O blocks wait.
|
||||
MOVL epfd+0(FP), DI
|
||||
MOVQ ev+8(FP), SI
|
||||
MOVL nev+16(FP), DX
|
||||
MOVL timeout+20(FP), R10
|
||||
MOVL $SYS_epoll_wait, AX
|
||||
MOVQ $0, R8
|
||||
MOVL $SYS_epoll_pwait, AX
|
||||
SYSCALL
|
||||
MOVL AX, ret+24(FP)
|
||||
RET
|
||||
@@ -676,9 +682,12 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0
|
||||
|
||||
// int access(const char *name, int mode)
|
||||
TEXT runtime·access(SB),NOSPLIT,$0
|
||||
MOVQ name+0(FP), DI
|
||||
MOVL mode+8(FP), SI
|
||||
MOVL $SYS_access, AX
|
||||
// This uses faccessat instead of access, because Android O blocks access.
|
||||
MOVL $AT_FDCWD, DI // AT_FDCWD, so this acts like access
|
||||
MOVQ name+0(FP), SI
|
||||
MOVL mode+8(FP), DX
|
||||
MOVL $0, R10
|
||||
MOVL $SYS_faccessat, AX
|
||||
SYSCALL
|
||||
MOVL AX, ret+16(FP)
|
||||
RET
|
||||
|
||||
@@ -13,10 +13,11 @@
|
||||
#include "go_tls.h"
|
||||
#include "textflag.h"
|
||||
|
||||
#define AT_FDCWD -100
|
||||
|
||||
#define SYS_exit 5058
|
||||
#define SYS_read 5000
|
||||
#define SYS_write 5001
|
||||
#define SYS_open 5002
|
||||
#define SYS_close 5003
|
||||
#define SYS_getpid 5038
|
||||
#define SYS_kill 5060
|
||||
@@ -42,7 +43,8 @@
|
||||
#define SYS_exit_group 5205
|
||||
#define SYS_epoll_create 5207
|
||||
#define SYS_epoll_ctl 5208
|
||||
#define SYS_epoll_wait 5209
|
||||
#define SYS_openat 5247
|
||||
#define SYS_epoll_pwait 5272
|
||||
#define SYS_clock_gettime 5222
|
||||
#define SYS_epoll_create1 5285
|
||||
#define SYS_brk 5012
|
||||
@@ -66,11 +68,13 @@ TEXT runtime·exitThread(SB),NOSPLIT,$-8-8
|
||||
SYSCALL
|
||||
JMP 0(PC)
|
||||
|
||||
TEXT runtime·open(SB),NOSPLIT,$-8-20
|
||||
MOVV name+0(FP), R4
|
||||
MOVW mode+8(FP), R5
|
||||
MOVW perm+12(FP), R6
|
||||
MOVV $SYS_open, R2
|
||||
TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0-20
|
||||
// This uses openat instead of open, because Android O blocks open.
|
||||
MOVW $AT_FDCWD, R4 // AT_FDCWD, so this acts like open
|
||||
MOVV name+0(FP), R5
|
||||
MOVW mode+8(FP), R6
|
||||
MOVW perm+12(FP), R7
|
||||
MOVV $SYS_openat, R2
|
||||
SYSCALL
|
||||
BEQ R7, 2(PC)
|
||||
MOVW $-1, R2
|
||||
@@ -422,12 +426,14 @@ TEXT runtime·epollctl(SB),NOSPLIT,$-8
|
||||
RET
|
||||
|
||||
// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
|
||||
TEXT runtime·epollwait(SB),NOSPLIT,$-8
|
||||
TEXT runtime·epollwait(SB),NOSPLIT|NOFRAME,$0
|
||||
// This uses pwait instead of wait, because Android O blocks wait.
|
||||
MOVW epfd+0(FP), R4
|
||||
MOVV ev+8(FP), R5
|
||||
MOVW nev+16(FP), R6
|
||||
MOVW timeout+20(FP), R7
|
||||
MOVV $SYS_epoll_wait, R2
|
||||
MOVV $0, R8
|
||||
MOVV $SYS_epoll_pwait, R2
|
||||
SYSCALL
|
||||
MOVW R2, ret+24(FP)
|
||||
RET
|
||||
|
||||
@@ -35,56 +35,14 @@ import (
|
||||
|
||||
const usesLR = sys.MinFrameSize > 0
|
||||
|
||||
var (
|
||||
// initialized in tracebackinit
|
||||
goexitPC uintptr
|
||||
jmpdeferPC uintptr
|
||||
mcallPC uintptr
|
||||
morestackPC uintptr
|
||||
mstartPC uintptr
|
||||
rt0_goPC uintptr
|
||||
asmcgocallPC uintptr
|
||||
sigpanicPC uintptr
|
||||
runfinqPC uintptr
|
||||
bgsweepPC uintptr
|
||||
forcegchelperPC uintptr
|
||||
timerprocPC uintptr
|
||||
gcBgMarkWorkerPC uintptr
|
||||
systemstack_switchPC uintptr
|
||||
systemstackPC uintptr
|
||||
cgocallback_gofuncPC uintptr
|
||||
skipPC uintptr
|
||||
|
||||
gogoPC uintptr
|
||||
|
||||
externalthreadhandlerp uintptr // initialized elsewhere
|
||||
)
|
||||
var skipPC uintptr
|
||||
|
||||
func tracebackinit() {
|
||||
// Go variable initialization happens late during runtime startup.
|
||||
// Instead of initializing the variables above in the declarations,
|
||||
// schedinit calls this function so that the variables are
|
||||
// initialized and available earlier in the startup sequence.
|
||||
goexitPC = funcPC(goexit)
|
||||
jmpdeferPC = funcPC(jmpdefer)
|
||||
mcallPC = funcPC(mcall)
|
||||
morestackPC = funcPC(morestack)
|
||||
mstartPC = funcPC(mstart)
|
||||
rt0_goPC = funcPC(rt0_go)
|
||||
asmcgocallPC = funcPC(asmcgocall)
|
||||
sigpanicPC = funcPC(sigpanic)
|
||||
runfinqPC = funcPC(runfinq)
|
||||
bgsweepPC = funcPC(bgsweep)
|
||||
forcegchelperPC = funcPC(forcegchelper)
|
||||
timerprocPC = funcPC(timerproc)
|
||||
gcBgMarkWorkerPC = funcPC(gcBgMarkWorker)
|
||||
systemstack_switchPC = funcPC(systemstack_switch)
|
||||
systemstackPC = funcPC(systemstack)
|
||||
cgocallback_gofuncPC = funcPC(cgocallback_gofunc)
|
||||
skipPC = funcPC(skipPleaseUseCallersFrames)
|
||||
|
||||
// used by sigprof handler
|
||||
gogoPC = funcPC(gogo)
|
||||
}
|
||||
|
||||
// Traceback over the deferred function calls.
|
||||
@@ -137,9 +95,6 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
if skip > 0 && callback != nil {
|
||||
throw("gentraceback callback cannot be used with non-zero skip")
|
||||
}
|
||||
if goexitPC == 0 {
|
||||
throw("gentraceback before goexitPC initialization")
|
||||
}
|
||||
g := getg()
|
||||
if g == gp && g == g.m.curg {
|
||||
// The starting sp has been passed in as a uintptr, and the caller may
|
||||
@@ -241,7 +196,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
// g0, this systemstack is at the top of the stack.
|
||||
// if we're not on g0 or there's a no curg, then this is a regular call.
|
||||
sp := frame.sp
|
||||
if flags&_TraceJumpStack != 0 && f.entry == systemstackPC && gp == g.m.g0 && gp.m.curg != nil {
|
||||
if flags&_TraceJumpStack != 0 && f.funcID == funcID_systemstack && gp == g.m.g0 && gp.m.curg != nil {
|
||||
sp = gp.m.curg.sched.sp
|
||||
frame.sp = sp
|
||||
cgoCtxt = gp.m.curg.cgoCtxt
|
||||
@@ -256,7 +211,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
if topofstack(f, gp.m != nil && gp == gp.m.g0) {
|
||||
frame.lr = 0
|
||||
flr = funcInfo{}
|
||||
} else if usesLR && f.entry == jmpdeferPC {
|
||||
} else if usesLR && f.funcID == funcID_jmpdefer {
|
||||
// jmpdefer modifies SP/LR/PC non-atomically.
|
||||
// If a profiling interrupt arrives during jmpdefer,
|
||||
// the stack unwind may see a mismatched register set
|
||||
@@ -287,7 +242,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
// But if callback is set, we're doing a garbage collection and must
|
||||
// get everything, so crash loudly.
|
||||
doPrint := printing
|
||||
if doPrint && gp.m.incgo {
|
||||
if doPrint && gp.m.incgo && f.funcID == funcID_sigpanic {
|
||||
// We can inject sigpanic
|
||||
// calls directly into C code,
|
||||
// in which case we'll see a C
|
||||
@@ -396,8 +351,8 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
// if there's room, pcbuf[1] is a skip PC that encodes the number of skipped frames in pcbuf[0]
|
||||
if n+1 < max {
|
||||
n++
|
||||
skipPC := funcPC(skipPleaseUseCallersFrames) + uintptr(logicalSkipped)
|
||||
(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = skipPC
|
||||
pc := skipPC + uintptr(logicalSkipped)
|
||||
(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = pc
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -466,7 +421,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
n++
|
||||
|
||||
skipped:
|
||||
if f.entry == cgocallback_gofuncPC && len(cgoCtxt) > 0 {
|
||||
if f.funcID == funcID_cgocallback_gofunc && len(cgoCtxt) > 0 {
|
||||
ctxt := cgoCtxt[len(cgoCtxt)-1]
|
||||
cgoCtxt = cgoCtxt[:len(cgoCtxt)-1]
|
||||
|
||||
@@ -478,7 +433,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
}
|
||||
}
|
||||
|
||||
waspanic = f.entry == sigpanicPC
|
||||
waspanic = f.funcID == funcID_sigpanic
|
||||
|
||||
// Do not unwind past the bottom of the stack.
|
||||
if !flr.valid() {
|
||||
@@ -931,30 +886,32 @@ func tracebackHexdump(stk stack, frame *stkframe, bad uintptr) {
|
||||
|
||||
// Does f mark the top of a goroutine stack?
|
||||
func topofstack(f funcInfo, g0 bool) bool {
|
||||
pc := f.entry
|
||||
return pc == goexitPC ||
|
||||
pc == mstartPC ||
|
||||
pc == mcallPC ||
|
||||
pc == morestackPC ||
|
||||
pc == rt0_goPC ||
|
||||
externalthreadhandlerp != 0 && pc == externalthreadhandlerp ||
|
||||
return f.funcID == funcID_goexit ||
|
||||
f.funcID == funcID_mstart ||
|
||||
f.funcID == funcID_mcall ||
|
||||
f.funcID == funcID_morestack ||
|
||||
f.funcID == funcID_rt0_go ||
|
||||
f.funcID == funcID_externalthreadhandler ||
|
||||
// asmcgocall is TOS on the system stack because it
|
||||
// switches to the system stack, but in this case we
|
||||
// can come back to the regular stack and still want
|
||||
// to be able to unwind through the call that appeared
|
||||
// on the regular stack.
|
||||
(g0 && pc == asmcgocallPC)
|
||||
(g0 && f.funcID == funcID_asmcgocall)
|
||||
}
|
||||
|
||||
// isSystemGoroutine reports whether the goroutine g must be omitted in
|
||||
// stack dumps and deadlock detector.
|
||||
func isSystemGoroutine(gp *g) bool {
|
||||
pc := gp.startpc
|
||||
return pc == runfinqPC && !fingRunning ||
|
||||
pc == bgsweepPC ||
|
||||
pc == forcegchelperPC ||
|
||||
pc == timerprocPC ||
|
||||
pc == gcBgMarkWorkerPC
|
||||
f := findfunc(gp.startpc)
|
||||
if !f.valid() {
|
||||
return false
|
||||
}
|
||||
return f.funcID == funcID_runfinq && !fingRunning ||
|
||||
f.funcID == funcID_bgsweep ||
|
||||
f.funcID == funcID_forcegchelper ||
|
||||
f.funcID == funcID_timerproc ||
|
||||
f.funcID == funcID_gcBgMarkWorker
|
||||
}
|
||||
|
||||
// SetCgoTraceback records three C functions to use to gather
|
||||
|
||||
@@ -39,7 +39,6 @@ const (
|
||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
||||
//sys Shutdown(fd int, how int) (err error)
|
||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
||||
//sys Stat(path string, stat *Stat_t) (err error)
|
||||
//sys Statfs(path string, buf *Statfs_t) (err error)
|
||||
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
|
||||
//sys Truncate(path string, length int64) (err error)
|
||||
@@ -47,6 +46,7 @@ const (
|
||||
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
|
||||
//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
//sys fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_NEWFSTATAT
|
||||
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error)
|
||||
//sysnb setgroups(n int, list *_Gid_t) (err error)
|
||||
//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
|
||||
@@ -61,6 +61,10 @@ const (
|
||||
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
|
||||
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
|
||||
|
||||
func Stat(path string, stat *Stat_t) (err error) {
|
||||
return fstatat(_AT_FDCWD, path, stat, 0)
|
||||
}
|
||||
|
||||
//go:noescape
|
||||
func gettimeofday(tv *Timeval) (err Errno)
|
||||
|
||||
|
||||
@@ -1476,21 +1476,6 @@ func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n i
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Stat(path string, stat *Stat_t) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Statfs(path string, buf *Statfs_t) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
@@ -1573,6 +1558,21 @@ func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func fstatat(fd int, path string, stat *Stat_t, flags int) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, _, e1 := Syscall6(SYS_NEWFSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func getgroups(n int, list *_Gid_t) (nn int, err error) {
|
||||
r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
|
||||
nn = int(r0)
|
||||
|
||||
34
test/fixedbugs/issue23812.go
Normal file
34
test/fixedbugs/issue23812.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// run
|
||||
|
||||
// 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 main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
want := int32(0x3edae8)
|
||||
got := foo(1)
|
||||
if want != got {
|
||||
panic(fmt.Sprintf("want %x, got %x", want, got))
|
||||
}
|
||||
}
|
||||
|
||||
func foo(a int32) int32 {
|
||||
return shr1(int32(shr2(int64(0x14ff6e2207db5d1f), int(a))), 4)
|
||||
}
|
||||
|
||||
func shr1(n int32, m int) int32 { return n >> uint(m) }
|
||||
|
||||
func shr2(n int64, m int) int64 {
|
||||
if m < 0 {
|
||||
m = -m
|
||||
}
|
||||
if m >= 64 {
|
||||
return n
|
||||
}
|
||||
|
||||
return n >> uint(m)
|
||||
}
|
||||
62
test/fixedbugs/issue24449.go
Normal file
62
test/fixedbugs/issue24449.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// run
|
||||
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
var cnt32 int32
|
||||
|
||||
//go:noinline
|
||||
func test32(a, b []int) bool {
|
||||
// Try to generate flag value, issue atomic
|
||||
// adds and then re-use the flag value to see if
|
||||
// the atomic add has clobbered them.
|
||||
atomic.AddInt32(&cnt32, 1)
|
||||
if len(a) == len(b) {
|
||||
atomic.AddInt32(&cnt32, 2)
|
||||
}
|
||||
atomic.AddInt32(&cnt32, 4)
|
||||
if len(a) >= len(b) {
|
||||
atomic.AddInt32(&cnt32, 8)
|
||||
}
|
||||
if len(a) <= len(b) {
|
||||
atomic.AddInt32(&cnt32, 16)
|
||||
}
|
||||
return atomic.LoadInt32(&cnt32) == 31
|
||||
}
|
||||
|
||||
var cnt64 int64
|
||||
|
||||
//go:noinline
|
||||
func test64(a, b []int) bool {
|
||||
// Try to generate flag value, issue atomic
|
||||
// adds and then re-use the flag value to see if
|
||||
// the atomic add has clobbered them.
|
||||
atomic.AddInt64(&cnt64, 1)
|
||||
if len(a) == len(b) {
|
||||
atomic.AddInt64(&cnt64, 2)
|
||||
}
|
||||
atomic.AddInt64(&cnt64, 4)
|
||||
if len(a) >= len(b) {
|
||||
atomic.AddInt64(&cnt64, 8)
|
||||
}
|
||||
if len(a) <= len(b) {
|
||||
atomic.AddInt64(&cnt64, 16)
|
||||
}
|
||||
return atomic.LoadInt64(&cnt64) == 31
|
||||
}
|
||||
|
||||
func main() {
|
||||
if !test32([]int{}, []int{}) {
|
||||
panic("test32")
|
||||
}
|
||||
if !test64([]int{}, []int{}) {
|
||||
panic("test64")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user