mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.link] all: merge branch 'master' into dev.link
Change-Id: I85b653b621ad8cb2ef27886210ea2c4b7409b60d
This commit is contained in:
commit
6097f7cf7a
45 changed files with 485 additions and 151 deletions
103
doc/go1.15.html
103
doc/go1.15.html
|
|
@ -33,6 +33,12 @@ TODO
|
||||||
|
|
||||||
<h3 id="darwin">Darwin</h3>
|
<h3 id="darwin">Darwin</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
As <a href="go1.14#darwin">announced</a> in the Go 1.14 release notes,
|
||||||
|
Go 1.15 now requires macOS 10.12 Sierra or later;
|
||||||
|
support for previous versions has been discontinued.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p> <!-- golang.org/issue/37610, golang.org/issue/37611 -->
|
<p> <!-- golang.org/issue/37610, golang.org/issue/37611 -->
|
||||||
As <a href="/doc/go1.14#darwin">announced</a> in the Go 1.14 release
|
As <a href="/doc/go1.14#darwin">announced</a> in the Go 1.14 release
|
||||||
notes, Go 1.15 drops support for 32-bit binaries on macOS, iOS,
|
notes, Go 1.15 drops support for 32-bit binaries on macOS, iOS,
|
||||||
|
|
@ -116,6 +122,73 @@ TODO
|
||||||
<code>GODEBUG=modcacheunzipinplace=1</code>.
|
<code>GODEBUG=modcacheunzipinplace=1</code>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3 id="vet">Vet</h3>
|
||||||
|
|
||||||
|
<h4 id="vet-string-int">New warning for string(x)</h4>
|
||||||
|
|
||||||
|
<p><!-- CL 212919, 232660 -->
|
||||||
|
The vet tool now warns about conversions of the
|
||||||
|
form <code>string(x)</code> where <code>x</code> has an integer type
|
||||||
|
other than <code>rune</code> or <code>byte</code>.
|
||||||
|
Experience with Go has shown that many conversions of this form
|
||||||
|
erroneously assume that <code>string(x)</code> evaluates to the
|
||||||
|
string representation of the integer <code>x</code>.
|
||||||
|
It actually evaluates to a string containing the UTF-8 encoding of
|
||||||
|
the value of <code>x</code>.
|
||||||
|
For example, <code>string(9786)</code> does not evaluate to the
|
||||||
|
string <code>"9786"</code>; it evaluates to the
|
||||||
|
string <code>"\xe2\x98\xba"</code>, or <code>"☺"</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Code that is using <code>string(x)</code> correctly can be rewritten
|
||||||
|
to <code>string(rune(x))</code>.
|
||||||
|
Or, in some cases, calling <code>utf8.EncodeRune(buf, x)</code> with
|
||||||
|
a suitable byte slice <code>buf</code> may be the right solution.
|
||||||
|
Other code should most likely use <code>strconv.Itoa</code>
|
||||||
|
or <code>fmt.Sprint</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This new vet check is enabled by default when using <code>go test</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
We are considering prohibiting the conversion in a future release of Go.
|
||||||
|
That is, the language would change to only
|
||||||
|
permit <code>string(x)</code> for integer <code>x</code> when the
|
||||||
|
type of <code>x</code> is <code>rune</code> or <code>byte</code>.
|
||||||
|
Such a language change would not be backward compatible.
|
||||||
|
We are using this vet check as a first trial step toward changing
|
||||||
|
the language.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4 id="vet-impossible-interface">New warning for impossible interface conversions</h4>
|
||||||
|
|
||||||
|
<p><!-- CL 218779, 232660 -->
|
||||||
|
The vet tool now warns about type assertions from one interface type
|
||||||
|
to another interface type when the type assertion will always fail.
|
||||||
|
This will happen if both interface types implement a method with the
|
||||||
|
same name but with a different type signature.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
There is no reason to write a type assertion that always fails, so
|
||||||
|
any code that triggers this vet check should be rewritten.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This new vet check is enabled by default when using <code>go test</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
We are considering prohibiting impossible interface type assertions
|
||||||
|
in a future release of Go.
|
||||||
|
Such a language change would not be backward compatible.
|
||||||
|
We are using this vet check as a first trial step toward changing
|
||||||
|
the language.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h2 id="runtime">Runtime</h2>
|
<h2 id="runtime">Runtime</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -155,22 +228,6 @@ TODO
|
||||||
TODO
|
TODO
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- golang.org/issue/28135 -->
|
|
||||||
The <code>testing.T</code> type now has a <code>Deadline</code> method
|
|
||||||
that reports the time at which the test binary will have exceeded its
|
|
||||||
timeout.
|
|
||||||
</p>
|
|
||||||
<p><!-- golang.org/issue/34129 -->
|
|
||||||
A <code>TestMain</code> function is no longer required to call
|
|
||||||
<code>os.Exit</code>. If a <code>TestMain</code> function returns,
|
|
||||||
the test binary will call <code>os.Exit</code> with the value returned
|
|
||||||
by <code>m.Run</code>.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- testing -->
|
|
||||||
|
|
||||||
<h3 id="minor_library_changes">Minor changes to the library</h3>
|
<h3 id="minor_library_changes">Minor changes to the library</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -375,6 +432,20 @@ TODO
|
||||||
|
|
||||||
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
|
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
<p><!-- golang.org/issue/28135 -->
|
||||||
|
The <code>testing.T</code> type now has a
|
||||||
|
<a href="/pkg/testing/#T.Deadline"><code>Deadline</code></a> method
|
||||||
|
that reports the time at which the test binary will have exceeded its
|
||||||
|
timeout.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><!-- golang.org/issue/34129 -->
|
||||||
|
A <code>TestMain</code> function is no longer required to call
|
||||||
|
<code>os.Exit</code>. If a <code>TestMain</code> function returns,
|
||||||
|
the test binary will call <code>os.Exit</code> with the value returned
|
||||||
|
by <code>m.Run</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p><!-- CL 226877, golang.org/issue/35998 -->
|
<p><!-- CL 226877, golang.org/issue/35998 -->
|
||||||
The new methods
|
The new methods
|
||||||
<a href="/pkg/testing/#T.TempDir"><code>T.TempDir</code></a> and
|
<a href="/pkg/testing/#T.TempDir"><code>T.TempDir</code></a> and
|
||||||
|
|
|
||||||
|
|
@ -501,7 +501,7 @@ These default to the values of <code>$GOHOSTOS</code> and
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Choices for <code>$GOOS</code> are
|
Choices for <code>$GOOS</code> are
|
||||||
<code>android</code>, <code>darwin</code> (macOS 10.11 and above and iOS),
|
<code>android</code>, <code>darwin</code> (macOS/iOS),
|
||||||
<code>dragonfly</code>, <code>freebsd</code>, <code>illumos</code>, <code>js</code>,
|
<code>dragonfly</code>, <code>freebsd</code>, <code>illumos</code>, <code>js</code>,
|
||||||
<code>linux</code>, <code>netbsd</code>, <code>openbsd</code>,
|
<code>linux</code>, <code>netbsd</code>, <code>openbsd</code>,
|
||||||
<code>plan9</code>, <code>solaris</code> and <code>windows</code>.
|
<code>plan9</code>, <code>solaris</code> and <code>windows</code>.
|
||||||
|
|
|
||||||
|
|
@ -271,7 +271,7 @@ func compile(fn *Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if compilenow() {
|
if compilenow(fn) {
|
||||||
compileSSA(fn, 0)
|
compileSSA(fn, 0)
|
||||||
} else {
|
} else {
|
||||||
compilequeue = append(compilequeue, fn)
|
compilequeue = append(compilequeue, fn)
|
||||||
|
|
@ -282,10 +282,31 @@ func compile(fn *Node) {
|
||||||
// If functions are not compiled immediately,
|
// If functions are not compiled immediately,
|
||||||
// they are enqueued in compilequeue,
|
// they are enqueued in compilequeue,
|
||||||
// which is drained by compileFunctions.
|
// which is drained by compileFunctions.
|
||||||
func compilenow() bool {
|
func compilenow(fn *Node) bool {
|
||||||
|
// Issue 38068: if this function is a method AND an inline
|
||||||
|
// candidate AND was not inlined (yet), put it onto the compile
|
||||||
|
// queue instead of compiling it immediately. This is in case we
|
||||||
|
// wind up inlining it into a method wrapper that is generated by
|
||||||
|
// compiling a function later on in the xtop list.
|
||||||
|
if fn.IsMethod() && isInlinableButNotInlined(fn) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return nBackendWorkers == 1 && Debug_compilelater == 0
|
return nBackendWorkers == 1 && Debug_compilelater == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isInlinableButNotInlined returns true if 'fn' was marked as an
|
||||||
|
// inline candidate but then never inlined (presumably because we
|
||||||
|
// found no call sites).
|
||||||
|
func isInlinableButNotInlined(fn *Node) bool {
|
||||||
|
if fn.Func.Nname.Func.Inl == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if fn.Sym == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return !fn.Sym.Linksym().WasInlined()
|
||||||
|
}
|
||||||
|
|
||||||
const maxStackSize = 1 << 30
|
const maxStackSize = 1 << 30
|
||||||
|
|
||||||
// compileSSA builds an SSA backend function,
|
// compileSSA builds an SSA backend function,
|
||||||
|
|
|
||||||
11
src/cmd/dist/build.go
vendored
11
src/cmd/dist/build.go
vendored
|
|
@ -31,7 +31,6 @@ var (
|
||||||
goos string
|
goos string
|
||||||
goarm string
|
goarm string
|
||||||
go386 string
|
go386 string
|
||||||
goamd64 string
|
|
||||||
gomips string
|
gomips string
|
||||||
gomips64 string
|
gomips64 string
|
||||||
goppc64 string
|
goppc64 string
|
||||||
|
|
@ -152,12 +151,6 @@ func xinit() {
|
||||||
}
|
}
|
||||||
go386 = b
|
go386 = b
|
||||||
|
|
||||||
b = os.Getenv("GOAMD64")
|
|
||||||
if b == "" {
|
|
||||||
b = "alignedjumps"
|
|
||||||
}
|
|
||||||
goamd64 = b
|
|
||||||
|
|
||||||
b = os.Getenv("GOMIPS")
|
b = os.Getenv("GOMIPS")
|
||||||
if b == "" {
|
if b == "" {
|
||||||
b = "hardfloat"
|
b = "hardfloat"
|
||||||
|
|
@ -230,7 +223,6 @@ func xinit() {
|
||||||
|
|
||||||
// For tools being invoked but also for os.ExpandEnv.
|
// For tools being invoked but also for os.ExpandEnv.
|
||||||
os.Setenv("GO386", go386)
|
os.Setenv("GO386", go386)
|
||||||
os.Setenv("GOAMD64", goamd64)
|
|
||||||
os.Setenv("GOARCH", goarch)
|
os.Setenv("GOARCH", goarch)
|
||||||
os.Setenv("GOARM", goarm)
|
os.Setenv("GOARM", goarm)
|
||||||
os.Setenv("GOHOSTARCH", gohostarch)
|
os.Setenv("GOHOSTARCH", gohostarch)
|
||||||
|
|
@ -1171,9 +1163,6 @@ func cmdenv() {
|
||||||
if goarch == "386" {
|
if goarch == "386" {
|
||||||
xprintf(format, "GO386", go386)
|
xprintf(format, "GO386", go386)
|
||||||
}
|
}
|
||||||
if goarch == "amd64" {
|
|
||||||
xprintf(format, "GOAMD64", goamd64)
|
|
||||||
}
|
|
||||||
if goarch == "mips" || goarch == "mipsle" {
|
if goarch == "mips" || goarch == "mipsle" {
|
||||||
xprintf(format, "GOMIPS", gomips)
|
xprintf(format, "GOMIPS", gomips)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
src/cmd/dist/buildruntime.go
vendored
2
src/cmd/dist/buildruntime.go
vendored
|
|
@ -42,7 +42,6 @@ func mkzversion(dir, file string) {
|
||||||
//
|
//
|
||||||
// const defaultGOROOT = <goroot>
|
// const defaultGOROOT = <goroot>
|
||||||
// const defaultGO386 = <go386>
|
// const defaultGO386 = <go386>
|
||||||
// const defaultGOAMD64 = <goamd64>
|
|
||||||
// const defaultGOARM = <goarm>
|
// const defaultGOARM = <goarm>
|
||||||
// const defaultGOMIPS = <gomips>
|
// const defaultGOMIPS = <gomips>
|
||||||
// const defaultGOMIPS64 = <gomips64>
|
// const defaultGOMIPS64 = <gomips64>
|
||||||
|
|
@ -72,7 +71,6 @@ func mkzbootstrap(file string) {
|
||||||
fmt.Fprintf(&buf, "import \"runtime\"\n")
|
fmt.Fprintf(&buf, "import \"runtime\"\n")
|
||||||
fmt.Fprintln(&buf)
|
fmt.Fprintln(&buf)
|
||||||
fmt.Fprintf(&buf, "const defaultGO386 = `%s`\n", go386)
|
fmt.Fprintf(&buf, "const defaultGO386 = `%s`\n", go386)
|
||||||
fmt.Fprintf(&buf, "const defaultGOAMD64 = `%s`\n", goamd64)
|
|
||||||
fmt.Fprintf(&buf, "const defaultGOARM = `%s`\n", goarm)
|
fmt.Fprintf(&buf, "const defaultGOARM = `%s`\n", goarm)
|
||||||
fmt.Fprintf(&buf, "const defaultGOMIPS = `%s`\n", gomips)
|
fmt.Fprintf(&buf, "const defaultGOMIPS = `%s`\n", gomips)
|
||||||
fmt.Fprintf(&buf, "const defaultGOMIPS64 = `%s`\n", gomips64)
|
fmt.Fprintf(&buf, "const defaultGOMIPS64 = `%s`\n", gomips64)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ require (
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
|
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
|
||||||
golang.org/x/arch v0.0.0-20200511175325-f7c78586839d
|
golang.org/x/arch v0.0.0-20200511175325-f7c78586839d
|
||||||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
|
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
|
||||||
golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2
|
golang.org/x/mod v0.3.0
|
||||||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
|
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
|
||||||
golang.org/x/tools v0.0.0-20200504152539-33427f1b0364
|
golang.org/x/tools v0.0.0-20200504152539-33427f1b0364
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
|
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
|
||||||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2 h1:VUsRDZIYpMs3R7PyYeN7BSbDfYjhxaX6HlWvM5iAEqs=
|
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||||
golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
|
|
||||||
|
|
@ -1754,9 +1754,6 @@
|
||||||
// GO386
|
// GO386
|
||||||
// For GOARCH=386, the floating point instruction set.
|
// For GOARCH=386, the floating point instruction set.
|
||||||
// Valid values are 387, sse2.
|
// Valid values are 387, sse2.
|
||||||
// GOAMD64
|
|
||||||
// For GOARCH=amd64, jumps can be optionally be aligned such that they do not end on
|
|
||||||
// or cross 32 byte boundaries. Valid values are alignedjumps (default), normaljumps.
|
|
||||||
// GOMIPS
|
// GOMIPS
|
||||||
// For GOARCH=mips{,le}, whether to use floating point instructions.
|
// For GOARCH=mips{,le}, whether to use floating point instructions.
|
||||||
// Valid values are hardfloat (default), softfloat.
|
// Valid values are hardfloat (default), softfloat.
|
||||||
|
|
|
||||||
|
|
@ -241,7 +241,6 @@ var (
|
||||||
// Used in envcmd.MkEnv and build ID computations.
|
// Used in envcmd.MkEnv and build ID computations.
|
||||||
GOARM = envOr("GOARM", fmt.Sprint(objabi.GOARM))
|
GOARM = envOr("GOARM", fmt.Sprint(objabi.GOARM))
|
||||||
GO386 = envOr("GO386", objabi.GO386)
|
GO386 = envOr("GO386", objabi.GO386)
|
||||||
GOAMD64 = envOr("GOAMD64", objabi.GOAMD64)
|
|
||||||
GOMIPS = envOr("GOMIPS", objabi.GOMIPS)
|
GOMIPS = envOr("GOMIPS", objabi.GOMIPS)
|
||||||
GOMIPS64 = envOr("GOMIPS64", objabi.GOMIPS64)
|
GOMIPS64 = envOr("GOMIPS64", objabi.GOMIPS64)
|
||||||
GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", objabi.GOPPC64))
|
GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", objabi.GOPPC64))
|
||||||
|
|
@ -267,8 +266,6 @@ func GetArchEnv() (key, val string) {
|
||||||
return "GOARM", GOARM
|
return "GOARM", GOARM
|
||||||
case "386":
|
case "386":
|
||||||
return "GO386", GO386
|
return "GO386", GO386
|
||||||
case "amd64":
|
|
||||||
return "GOAMD64", GOAMD64
|
|
||||||
case "mips", "mipsle":
|
case "mips", "mipsle":
|
||||||
return "GOMIPS", GOMIPS
|
return "GOMIPS", GOMIPS
|
||||||
case "mips64", "mips64le":
|
case "mips64", "mips64le":
|
||||||
|
|
|
||||||
|
|
@ -582,9 +582,6 @@ Architecture-specific environment variables:
|
||||||
GO386
|
GO386
|
||||||
For GOARCH=386, the floating point instruction set.
|
For GOARCH=386, the floating point instruction set.
|
||||||
Valid values are 387, sse2.
|
Valid values are 387, sse2.
|
||||||
GOAMD64
|
|
||||||
For GOARCH=amd64, jumps can be optionally be aligned such that they do not end on
|
|
||||||
or cross 32 byte boundaries. Valid values are alignedjumps (default), normaljumps.
|
|
||||||
GOMIPS
|
GOMIPS
|
||||||
For GOARCH=mips{,le}, whether to use floating point instructions.
|
For GOARCH=mips{,le}, whether to use floating point instructions.
|
||||||
Valid values are hardfloat (default), softfloat.
|
Valid values are hardfloat (default), softfloat.
|
||||||
|
|
|
||||||
|
|
@ -196,8 +196,12 @@ func TryProxies(f func(proxy string) error) error {
|
||||||
|
|
||||||
// We try to report the most helpful error to the user. "direct" and "noproxy"
|
// We try to report the most helpful error to the user. "direct" and "noproxy"
|
||||||
// errors are best, followed by proxy errors other than ErrNotExist, followed
|
// errors are best, followed by proxy errors other than ErrNotExist, followed
|
||||||
// by ErrNotExist. Note that errProxyOff, errNoproxy, and errUseProxy are
|
// by ErrNotExist.
|
||||||
// equivalent to ErrNotExist.
|
//
|
||||||
|
// Note that errProxyOff, errNoproxy, and errUseProxy are equivalent to
|
||||||
|
// ErrNotExist. errUseProxy should only be returned if "noproxy" is the only
|
||||||
|
// proxy. errNoproxy should never be returned, since there should always be a
|
||||||
|
// more useful error from "noproxy" first.
|
||||||
const (
|
const (
|
||||||
notExistRank = iota
|
notExistRank = iota
|
||||||
proxyRank
|
proxyRank
|
||||||
|
|
@ -212,7 +216,7 @@ func TryProxies(f func(proxy string) error) error {
|
||||||
}
|
}
|
||||||
isNotExistErr := errors.Is(err, os.ErrNotExist)
|
isNotExistErr := errors.Is(err, os.ErrNotExist)
|
||||||
|
|
||||||
if proxy.url == "direct" || proxy.url == "noproxy" {
|
if proxy.url == "direct" || (proxy.url == "noproxy" && err != errUseProxy) {
|
||||||
bestErr = err
|
bestErr = err
|
||||||
bestErrRank = directRank
|
bestErrRank = directRank
|
||||||
} else if bestErrRank <= proxyRank && !isNotExistErr {
|
} else if bestErrRank <= proxyRank && !isNotExistErr {
|
||||||
|
|
|
||||||
|
|
@ -2434,13 +2434,25 @@ func (b *Builder) gccSupportsFlag(compiler []string, flag string) bool {
|
||||||
if b.flagCache == nil {
|
if b.flagCache == nil {
|
||||||
b.flagCache = make(map[[2]string]bool)
|
b.flagCache = make(map[[2]string]bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmp := os.DevNull
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
f, err := ioutil.TempFile(b.WorkDir, "")
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
tmp = f.Name()
|
||||||
|
defer os.Remove(tmp)
|
||||||
|
}
|
||||||
|
|
||||||
// We used to write an empty C file, but that gets complicated with
|
// We used to write an empty C file, but that gets complicated with
|
||||||
// go build -n. We tried using a file that does not exist, but that
|
// go build -n. We tried using a file that does not exist, but that
|
||||||
// fails on systems with GCC version 4.2.1; that is the last GPLv2
|
// fails on systems with GCC version 4.2.1; that is the last GPLv2
|
||||||
// version of GCC, so some systems have frozen on it.
|
// version of GCC, so some systems have frozen on it.
|
||||||
// Now we pass an empty file on stdin, which should work at least for
|
// Now we pass an empty file on stdin, which should work at least for
|
||||||
// GCC and clang.
|
// GCC and clang.
|
||||||
cmdArgs := str.StringList(compiler, flag, "-c", "-x", "c", "-", "-o", os.DevNull)
|
cmdArgs := str.StringList(compiler, flag, "-c", "-x", "c", "-", "-o", tmp)
|
||||||
if cfg.BuildN || cfg.BuildX {
|
if cfg.BuildN || cfg.BuildX {
|
||||||
b.Showcmd(b.WorkDir, "%s || true", joinUnambiguously(cmdArgs))
|
b.Showcmd(b.WorkDir, "%s || true", joinUnambiguously(cmdArgs))
|
||||||
if cfg.BuildN {
|
if cfg.BuildN {
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ func TestNoteReading(t *testing.T) {
|
||||||
// we've had trouble reading the notes generated by gold.
|
// we've had trouble reading the notes generated by gold.
|
||||||
err := tg.doRun([]string{"build", "-ldflags", "-buildid=" + buildID + " -linkmode=external -extldflags=-fuse-ld=gold", "-o", tg.path("hello3.exe"), tg.path("hello.go")})
|
err := tg.doRun([]string{"build", "-ldflags", "-buildid=" + buildID + " -linkmode=external -extldflags=-fuse-ld=gold", "-o", tg.path("hello3.exe"), tg.path("hello.go")})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if tg.grepCountBoth("(invalid linker|gold|cannot find 'ld')") > 0 {
|
if tg.grepCountBoth("(invalid linker|gold|cannot find [‘']ld[’'])") > 0 {
|
||||||
// It's not an error if gold isn't there. gcc claims it "cannot find 'ld'" if
|
// It's not an error if gold isn't there. gcc claims it "cannot find 'ld'" if
|
||||||
// ld.gold is missing, see issue #22340.
|
// ld.gold is missing, see issue #22340.
|
||||||
t.Log("skipping gold test")
|
t.Log("skipping gold test")
|
||||||
|
|
|
||||||
6
src/cmd/go/testdata/script/issue36000.txt
vendored
Normal file
6
src/cmd/go/testdata/script/issue36000.txt
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
# Tests golang.org/issue/36000
|
||||||
|
|
||||||
|
[!cgo] skip
|
||||||
|
|
||||||
|
# go env with CGO flags should not make NUL file
|
||||||
|
go env CGO_CFLAGS
|
||||||
10
src/cmd/go/testdata/script/mod_gonoproxy.txt
vendored
10
src/cmd/go/testdata/script/mod_gonoproxy.txt
vendored
|
|
@ -10,7 +10,7 @@ env GOSUMDB=$sumdb' '$proxy/sumdb-wrong
|
||||||
! go get rsc.io/quote
|
! go get rsc.io/quote
|
||||||
stderr 'SECURITY ERROR'
|
stderr 'SECURITY ERROR'
|
||||||
|
|
||||||
# but GONOSUMDB bypasses sumdb, for rsc.io/quote, rsc.io/sampler, golang.org/x/text
|
# GONOSUMDB bypasses sumdb, for rsc.io/quote, rsc.io/sampler, golang.org/x/text
|
||||||
env GONOSUMDB='*/quote,*/*mple*,golang.org/x'
|
env GONOSUMDB='*/quote,*/*mple*,golang.org/x'
|
||||||
go get rsc.io/quote
|
go get rsc.io/quote
|
||||||
rm go.sum
|
rm go.sum
|
||||||
|
|
@ -18,7 +18,13 @@ env GOPRIVATE='*/quote,*/*mple*,golang.org/x'
|
||||||
env GONOPROXY=none # that is, proxy all despite GOPRIVATE
|
env GONOPROXY=none # that is, proxy all despite GOPRIVATE
|
||||||
go get rsc.io/quote
|
go get rsc.io/quote
|
||||||
|
|
||||||
# and GONOPROXY bypasses proxy
|
# When GOPROXY=off, fetching modules not matched by GONOPROXY fails.
|
||||||
|
env GONOPROXY=*/fortune
|
||||||
|
env GOPROXY=off
|
||||||
|
! go get golang.org/x/text
|
||||||
|
stderr '^go get golang.org/x/text: module lookup disabled by GOPROXY=off$'
|
||||||
|
|
||||||
|
# GONOPROXY bypasses proxy
|
||||||
[!net] skip
|
[!net] skip
|
||||||
[!exec:git] skip
|
[!exec:git] skip
|
||||||
env GOPRIVATE=none
|
env GOPRIVATE=none
|
||||||
|
|
|
||||||
|
|
@ -425,6 +425,14 @@ func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
|
||||||
absfn.Type = objabi.SDWARFINFO
|
absfn.Type = objabi.SDWARFINFO
|
||||||
ft.ctxt.Data = append(ft.ctxt.Data, absfn)
|
ft.ctxt.Data = append(ft.ctxt.Data, absfn)
|
||||||
|
|
||||||
|
// In the case of "late" inlining (inlines that happen during
|
||||||
|
// wrapper generation as opposed to the main inlining phase) it's
|
||||||
|
// possible that we didn't cache the abstract function sym for the
|
||||||
|
// text symbol -- do so now if needed. See issue 38068.
|
||||||
|
if s.Func != nil && s.Func.dwarfAbsFnSym == nil {
|
||||||
|
s.Func.dwarfAbsFnSym = absfn
|
||||||
|
}
|
||||||
|
|
||||||
ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
|
ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,16 +37,13 @@ var (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ElfRelocOffset = 256
|
ElfRelocOffset = 256
|
||||||
MachoRelocOffset = 2048 // reserve enough space for ELF relocations
|
MachoRelocOffset = 2048 // reserve enough space for ELF relocations
|
||||||
|
Go115AMD64 = "alignedjumps" // Should be "alignedjumps" or "normaljumps"; this replaces environment variable introduced in CL 219357.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO(1.16): assuming no issues in 1.15 release, remove this and related constant.
|
||||||
func goamd64() string {
|
func goamd64() string {
|
||||||
switch v := envOr("GOAMD64", defaultGOAMD64); v {
|
return Go115AMD64
|
||||||
case "normaljumps", "alignedjumps":
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
log.Fatalf("Invalid GOAMD64 value. Must be normaljumps or alignedjumps.")
|
|
||||||
panic("unreachable")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func goarm() int {
|
func goarm() int {
|
||||||
|
|
|
||||||
|
|
@ -385,12 +385,16 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
|
||||||
offset := (signext24(r.Add()&0xffffff) + 2) * 4
|
offset := (signext24(r.Add()&0xffffff) + 2) * 4
|
||||||
var tramp loader.Sym
|
var tramp loader.Sym
|
||||||
for i := 0; ; i++ {
|
for i := 0; ; i++ {
|
||||||
name := ldr.SymName(rs) + fmt.Sprintf("%+d-tramp%d", offset, i)
|
oName := ldr.SymName(rs)
|
||||||
|
name := oName + fmt.Sprintf("%+d-tramp%d", offset, i)
|
||||||
tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs)))
|
tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs)))
|
||||||
if ldr.SymType(tramp) == sym.SDYNIMPORT {
|
if ldr.SymType(tramp) == sym.SDYNIMPORT {
|
||||||
// don't reuse trampoline defined in other module
|
// don't reuse trampoline defined in other module
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if oName == "runtime.deferreturn" {
|
||||||
|
ldr.SetIsDeferReturnTramp(tramp, true)
|
||||||
|
}
|
||||||
if ldr.SymValue(tramp) == 0 {
|
if ldr.SymValue(tramp) == 0 {
|
||||||
// either the trampoline does not exist -- we need to create one,
|
// either the trampoline does not exist -- we need to create one,
|
||||||
// or found one the address which is not assigned -- this will be
|
// or found one the address which is not assigned -- this will be
|
||||||
|
|
|
||||||
50
src/cmd/link/internal/ld/fallocate_test.go
Normal file
50
src/cmd/link/internal/ld/fallocate_test.go
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build darwin linux
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFallocate(t *testing.T) {
|
||||||
|
dir, err := ioutil.TempDir("", "TestFallocate")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
filename := filepath.Join(dir, "a.out")
|
||||||
|
out := NewOutBuf(nil)
|
||||||
|
err = out.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Open file failed: %v", err)
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
// Mmap 1 MiB initially, and grow to 2 and 3 MiB.
|
||||||
|
// Check if the file size and disk usage is expected.
|
||||||
|
for _, sz := range []int64{1 << 20, 2 << 20, 3 << 20} {
|
||||||
|
err = out.Mmap(uint64(sz))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Mmap failed: %v", err)
|
||||||
|
}
|
||||||
|
stat, err := os.Stat(filename)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Stat failed: %v", err)
|
||||||
|
}
|
||||||
|
if got := stat.Size(); got != sz {
|
||||||
|
t.Errorf("unexpected file size: got %d, want %d", got, sz)
|
||||||
|
}
|
||||||
|
if got, want := stat.Sys().(*syscall.Stat_t).Blocks, (sz+511)/512; got != want {
|
||||||
|
t.Errorf("unexpected disk usage: got %d blocks, want %d", got, want)
|
||||||
|
}
|
||||||
|
out.munmap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,16 +10,25 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (out *OutBuf) fallocate(size uint64) error {
|
func (out *OutBuf) fallocate(size uint64) error {
|
||||||
|
stat, err := out.f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cursize := uint64(stat.Size())
|
||||||
|
if size <= cursize {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
store := &syscall.Fstore_t{
|
store := &syscall.Fstore_t{
|
||||||
Flags: syscall.F_ALLOCATEALL,
|
Flags: syscall.F_ALLOCATEALL,
|
||||||
Posmode: syscall.F_PEOFPOSMODE,
|
Posmode: syscall.F_PEOFPOSMODE,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
Length: int64(size),
|
Length: int64(size - cursize), // F_PEOFPOSMODE allocates from the end of the file, so we want the size difference here
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store)))
|
_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store)))
|
||||||
if err != 0 {
|
if errno != 0 {
|
||||||
return err
|
return errno
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,7 @@ func (state *pclnState) computeDeferReturn(target *Target, s loader.Sym) uint32
|
||||||
// set the resumption point to PC_B.
|
// set the resumption point to PC_B.
|
||||||
lastWasmAddr = uint32(r.Add())
|
lastWasmAddr = uint32(r.Add())
|
||||||
}
|
}
|
||||||
if r.Type().IsDirectCall() && r.Sym() == state.deferReturnSym {
|
if r.Type().IsDirectCall() && (r.Sym() == state.deferReturnSym || state.ldr.IsDeferReturnTramp(r.Sym())) {
|
||||||
if target.IsWasm() {
|
if target.IsWasm() {
|
||||||
deferreturn = lastWasmAddr - 1
|
deferreturn = lastWasmAddr - 1
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,8 @@ type Loader struct {
|
||||||
outdata [][]byte // symbol's data in the output buffer
|
outdata [][]byte // symbol's data in the output buffer
|
||||||
extRelocs [][]ExtReloc // symbol's external relocations
|
extRelocs [][]ExtReloc // symbol's external relocations
|
||||||
|
|
||||||
itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
|
itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
|
||||||
|
deferReturnTramp map[Sym]bool // whether the symbol is a trampoline of a deferreturn call
|
||||||
|
|
||||||
objByPkg map[string]*oReader // map package path to its Go object reader
|
objByPkg map[string]*oReader // map package path to its Go object reader
|
||||||
|
|
||||||
|
|
@ -354,6 +355,7 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorRepor
|
||||||
attrCgoExportDynamic: make(map[Sym]struct{}),
|
attrCgoExportDynamic: make(map[Sym]struct{}),
|
||||||
attrCgoExportStatic: make(map[Sym]struct{}),
|
attrCgoExportStatic: make(map[Sym]struct{}),
|
||||||
itablink: make(map[Sym]struct{}),
|
itablink: make(map[Sym]struct{}),
|
||||||
|
deferReturnTramp: make(map[Sym]bool),
|
||||||
extStaticSyms: make(map[nameVer]Sym),
|
extStaticSyms: make(map[nameVer]Sym),
|
||||||
builtinSyms: make([]Sym, nbuiltin),
|
builtinSyms: make([]Sym, nbuiltin),
|
||||||
flags: flags,
|
flags: flags,
|
||||||
|
|
@ -1050,6 +1052,16 @@ func (l *Loader) IsItabLink(i Sym) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return whether this is a trampoline of a deferreturn call.
|
||||||
|
func (l *Loader) IsDeferReturnTramp(i Sym) bool {
|
||||||
|
return l.deferReturnTramp[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set that i is a trampoline of a deferreturn call.
|
||||||
|
func (l *Loader) SetIsDeferReturnTramp(i Sym, v bool) {
|
||||||
|
l.deferReturnTramp[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
// growValues grows the slice used to store symbol values.
|
// growValues grows the slice used to store symbol values.
|
||||||
func (l *Loader) growValues(reqLen int) {
|
func (l *Loader) growValues(reqLen int) {
|
||||||
curLen := len(l.values)
|
curLen := len(l.values)
|
||||||
|
|
|
||||||
|
|
@ -686,16 +686,20 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
|
||||||
// target is at some offset within the function. Calls to duff+8 and duff+256 must appear as
|
// target is at some offset within the function. Calls to duff+8 and duff+256 must appear as
|
||||||
// distinct trampolines.
|
// distinct trampolines.
|
||||||
|
|
||||||
name := ldr.SymName(rs)
|
oName := ldr.SymName(rs)
|
||||||
|
name := oName
|
||||||
if r.Add() == 0 {
|
if r.Add() == 0 {
|
||||||
name = name + fmt.Sprintf("-tramp%d", i)
|
name += fmt.Sprintf("-tramp%d", i)
|
||||||
} else {
|
} else {
|
||||||
name = name + fmt.Sprintf("%+x-tramp%d", r.Add(), i)
|
name += fmt.Sprintf("%+x-tramp%d", r.Add(), i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up the trampoline in case it already exists
|
// Look up the trampoline in case it already exists
|
||||||
|
|
||||||
tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs)))
|
tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs)))
|
||||||
|
if oName == "runtime.deferreturn" {
|
||||||
|
ldr.SetIsDeferReturnTramp(tramp, true)
|
||||||
|
}
|
||||||
if ldr.SymValue(tramp) == 0 {
|
if ldr.SymValue(tramp) == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -605,10 +605,23 @@ func TestFuncAlign(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const helloSrc = `
|
const testTrampSrc = `
|
||||||
package main
|
package main
|
||||||
import "fmt"
|
import "fmt"
|
||||||
func main() { fmt.Println("hello") }
|
func main() {
|
||||||
|
fmt.Println("hello")
|
||||||
|
|
||||||
|
defer func(){
|
||||||
|
if e := recover(); e == nil {
|
||||||
|
panic("did not panic")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
f1()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test deferreturn trampolines. See issue #39049.
|
||||||
|
func f1() { defer f2() }
|
||||||
|
func f2() { panic("XXX") }
|
||||||
`
|
`
|
||||||
|
|
||||||
func TestTrampoline(t *testing.T) {
|
func TestTrampoline(t *testing.T) {
|
||||||
|
|
@ -631,7 +644,7 @@ func TestTrampoline(t *testing.T) {
|
||||||
defer os.RemoveAll(tmpdir)
|
defer os.RemoveAll(tmpdir)
|
||||||
|
|
||||||
src := filepath.Join(tmpdir, "hello.go")
|
src := filepath.Join(tmpdir, "hello.go")
|
||||||
err = ioutil.WriteFile(src, []byte(helloSrc), 0666)
|
err = ioutil.WriteFile(src, []byte(testTrampSrc), 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
src/cmd/vendor/modules.txt
vendored
2
src/cmd/vendor/modules.txt
vendored
|
|
@ -29,7 +29,7 @@ golang.org/x/arch/x86/x86asm
|
||||||
golang.org/x/crypto/ed25519
|
golang.org/x/crypto/ed25519
|
||||||
golang.org/x/crypto/ed25519/internal/edwards25519
|
golang.org/x/crypto/ed25519/internal/edwards25519
|
||||||
golang.org/x/crypto/ssh/terminal
|
golang.org/x/crypto/ssh/terminal
|
||||||
# golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2
|
# golang.org/x/mod v0.3.0
|
||||||
## explicit
|
## explicit
|
||||||
golang.org/x/mod/internal/lazyregexp
|
golang.org/x/mod/internal/lazyregexp
|
||||||
golang.org/x/mod/modfile
|
golang.org/x/mod/modfile
|
||||||
|
|
|
||||||
|
|
@ -980,7 +980,28 @@ func testResumption(t *testing.T, version uint16) {
|
||||||
if bytes.Equal(ticket, getTicket()) {
|
if bytes.Equal(ticket, getTicket()) {
|
||||||
t.Fatal("new ticket wasn't provided after old ticket expired")
|
t.Fatal("new ticket wasn't provided after old ticket expired")
|
||||||
}
|
}
|
||||||
testResumeState("FreshSessionTicket", true)
|
|
||||||
|
// Age the session ticket a bit at a time, but don't expire it.
|
||||||
|
d := 0 * time.Hour
|
||||||
|
for i := 0; i < 13; i++ {
|
||||||
|
d += 12 * time.Hour
|
||||||
|
serverConfig.Time = func() time.Time { return time.Now().Add(d) }
|
||||||
|
testResumeState("OldSessionTicket", true)
|
||||||
|
}
|
||||||
|
// Expire it (now a little more than 7 days) and make sure a full
|
||||||
|
// handshake occurs for TLS 1.2. Resumption should still occur for
|
||||||
|
// TLS 1.3 since the client should be using a fresh ticket sent over
|
||||||
|
// by the server.
|
||||||
|
d += 12 * time.Hour
|
||||||
|
serverConfig.Time = func() time.Time { return time.Now().Add(d) }
|
||||||
|
if version == VersionTLS13 {
|
||||||
|
testResumeState("ExpiredSessionTicket", true)
|
||||||
|
} else {
|
||||||
|
testResumeState("ExpiredSessionTicket", false)
|
||||||
|
}
|
||||||
|
if bytes.Equal(ticket, getTicket()) {
|
||||||
|
t.Fatal("new ticket wasn't provided after old ticket expired")
|
||||||
|
}
|
||||||
|
|
||||||
// Reset serverConfig to ensure that calling SetSessionTicketKeys
|
// Reset serverConfig to ensure that calling SetSessionTicketKeys
|
||||||
// before the serverConfig is used works.
|
// before the serverConfig is used works.
|
||||||
|
|
|
||||||
|
|
@ -75,13 +75,8 @@ func (hs *serverHandshakeState) handshake() error {
|
||||||
if err := hs.establishKeys(); err != nil {
|
if err := hs.establishKeys(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// ticketSupported is set in a resumption handshake if the
|
if err := hs.sendSessionTicket(); err != nil {
|
||||||
// ticket from the client was encrypted with an old session
|
return err
|
||||||
// ticket key and thus a refreshed ticket should be sent.
|
|
||||||
if hs.hello.ticketSupported {
|
|
||||||
if err := hs.sendSessionTicket(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err := hs.sendFinished(c.serverFinished[:]); err != nil {
|
if err := hs.sendFinished(c.serverFinished[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -688,6 +683,9 @@ func (hs *serverHandshakeState) readFinished(out []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hs *serverHandshakeState) sendSessionTicket() error {
|
func (hs *serverHandshakeState) sendSessionTicket() error {
|
||||||
|
// ticketSupported is set in a resumption handshake if the
|
||||||
|
// ticket from the client was encrypted with an old session
|
||||||
|
// ticket key and thus a refreshed ticket should be sent.
|
||||||
if !hs.hello.ticketSupported {
|
if !hs.hello.ticketSupported {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -695,6 +693,13 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
|
||||||
c := hs.c
|
c := hs.c
|
||||||
m := new(newSessionTicketMsg)
|
m := new(newSessionTicketMsg)
|
||||||
|
|
||||||
|
createdAt := uint64(c.config.time().Unix())
|
||||||
|
if hs.sessionState != nil {
|
||||||
|
// If this is re-wrapping an old key, then keep
|
||||||
|
// the original time it was created.
|
||||||
|
createdAt = hs.sessionState.createdAt
|
||||||
|
}
|
||||||
|
|
||||||
var certsFromClient [][]byte
|
var certsFromClient [][]byte
|
||||||
for _, cert := range c.peerCertificates {
|
for _, cert := range c.peerCertificates {
|
||||||
certsFromClient = append(certsFromClient, cert.Raw)
|
certsFromClient = append(certsFromClient, cert.Raw)
|
||||||
|
|
@ -702,7 +707,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
|
||||||
state := sessionState{
|
state := sessionState{
|
||||||
vers: c.vers,
|
vers: c.vers,
|
||||||
cipherSuite: hs.suite.id,
|
cipherSuite: hs.suite.id,
|
||||||
createdAt: uint64(c.config.time().Unix()),
|
createdAt: createdAt,
|
||||||
masterSecret: hs.masterSecret,
|
masterSecret: hs.masterSecret,
|
||||||
certificates: certsFromClient,
|
certificates: certsFromClient,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,6 @@ func (m *sessionState) unmarshal(data []byte) bool {
|
||||||
*m = sessionState{usedOldKey: m.usedOldKey}
|
*m = sessionState{usedOldKey: m.usedOldKey}
|
||||||
s := cryptobyte.String(data)
|
s := cryptobyte.String(data)
|
||||||
if ok := s.ReadUint16(&m.vers) &&
|
if ok := s.ReadUint16(&m.vers) &&
|
||||||
m.vers != VersionTLS13 &&
|
|
||||||
s.ReadUint16(&m.cipherSuite) &&
|
s.ReadUint16(&m.cipherSuite) &&
|
||||||
readUint64(&s, &m.createdAt) &&
|
readUint64(&s, &m.createdAt) &&
|
||||||
readUint16LengthPrefixed(&s, &m.masterSecret) &&
|
readUint16LengthPrefixed(&s, &m.masterSecret) &&
|
||||||
|
|
|
||||||
|
|
@ -204,7 +204,8 @@ func TestLoadSystemCertsLoadColonSeparatedDirs(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadUniqueDirectoryEntries(t *testing.T) {
|
func TestReadUniqueDirectoryEntries(t *testing.T) {
|
||||||
temp := func(base string) string { return filepath.Join(t.TempDir(), base) }
|
tmp := t.TempDir()
|
||||||
|
temp := func(base string) string { return filepath.Join(tmp, base) }
|
||||||
if f, err := os.Create(temp("file")); err != nil {
|
if f, err := os.Create(temp("file")); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -216,7 +217,7 @@ func TestReadUniqueDirectoryEntries(t *testing.T) {
|
||||||
if err := os.Symlink("../target-out", temp("link-out")); err != nil {
|
if err := os.Symlink("../target-out", temp("link-out")); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
got, err := readUniqueDirectoryEntries(t.TempDir())
|
got, err := readUniqueDirectoryEntries(tmp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ const KnownEnv = `
|
||||||
GCCGO
|
GCCGO
|
||||||
GO111MODULE
|
GO111MODULE
|
||||||
GO386
|
GO386
|
||||||
GOAMD64
|
|
||||||
GOARCH
|
GOARCH
|
||||||
GOARM
|
GOARM
|
||||||
GOBIN
|
GOBIN
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,9 @@ func TestLinkerGC(t *testing.T) {
|
||||||
t.Skip("skipping in short mode")
|
t.Skip("skipping in short mode")
|
||||||
}
|
}
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
tmp := t.TempDir()
|
||||||
goBin := testenv.GoToolPath(t)
|
goBin := testenv.GoToolPath(t)
|
||||||
goFile := filepath.Join(t.TempDir(), "x.go")
|
goFile := filepath.Join(tmp, "x.go")
|
||||||
file := []byte(`package main
|
file := []byte(`package main
|
||||||
import _ "math/big"
|
import _ "math/big"
|
||||||
func main() {}
|
func main() {}
|
||||||
|
|
@ -30,13 +31,13 @@ func main() {}
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
cmd := exec.Command(goBin, "build", "-o", "x.exe", "x.go")
|
cmd := exec.Command(goBin, "build", "-o", "x.exe", "x.go")
|
||||||
cmd.Dir = t.TempDir()
|
cmd.Dir = tmp
|
||||||
if out, err := cmd.CombinedOutput(); err != nil {
|
if out, err := cmd.CombinedOutput(); err != nil {
|
||||||
t.Fatalf("compile: %v, %s", err, out)
|
t.Fatalf("compile: %v, %s", err, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = exec.Command(goBin, "tool", "nm", "x.exe")
|
cmd = exec.Command(goBin, "tool", "nm", "x.exe")
|
||||||
cmd.Dir = t.TempDir()
|
cmd.Dir = tmp
|
||||||
nm, err := cmd.CombinedOutput()
|
nm, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("nm: %v, %s", err, nm)
|
t.Fatalf("nm: %v, %s", err, nm)
|
||||||
|
|
|
||||||
|
|
@ -2539,3 +2539,34 @@ func isDeadlineExceeded(err error) bool {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that opening a file does not change its permissions. Issue 38225.
|
||||||
|
func TestOpenFileKeepsPermissions(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
dir := t.TempDir()
|
||||||
|
name := filepath.Join(dir, "x")
|
||||||
|
f, err := Create(name)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
f, err = OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if fi, err := f.Stat(); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else if fi.Mode()&0222 == 0 {
|
||||||
|
t.Errorf("f.Stat.Mode after OpenFile is %v, should be writable", fi.Mode())
|
||||||
|
}
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if fi, err := Stat(name); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else if fi.Mode()&0222 == 0 {
|
||||||
|
t.Errorf("Stat after OpenFile is %v, should be writable", fi.Mode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -249,14 +249,15 @@ func newCopyFileRangeTest(t *testing.T, size int64) (dst, src *File, data []byte
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
hook = hookCopyFileRange(t)
|
hook = hookCopyFileRange(t)
|
||||||
|
tmp := t.TempDir()
|
||||||
|
|
||||||
src, err := Create(filepath.Join(t.TempDir(), "src"))
|
src, err := Create(filepath.Join(tmp, "src"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() { src.Close() })
|
t.Cleanup(func() { src.Close() })
|
||||||
|
|
||||||
dst, err = Create(filepath.Join(t.TempDir(), "dst"))
|
dst, err = Create(filepath.Join(tmp, "dst"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ const (
|
||||||
lockRankDummy lockRank = iota
|
lockRankDummy lockRank = iota
|
||||||
|
|
||||||
// Locks held above sched
|
// Locks held above sched
|
||||||
|
lockRankSysmon
|
||||||
lockRankScavenge
|
lockRankScavenge
|
||||||
lockRankForcegc
|
lockRankForcegc
|
||||||
lockRankSweepWaiters
|
lockRankSweepWaiters
|
||||||
|
|
@ -113,6 +114,7 @@ const lockRankLeafRank lockRank = 1000
|
||||||
var lockNames = []string{
|
var lockNames = []string{
|
||||||
lockRankDummy: "",
|
lockRankDummy: "",
|
||||||
|
|
||||||
|
lockRankSysmon: "sysmon",
|
||||||
lockRankScavenge: "scavenge",
|
lockRankScavenge: "scavenge",
|
||||||
lockRankForcegc: "forcegc",
|
lockRankForcegc: "forcegc",
|
||||||
lockRankSweepWaiters: "sweepWaiters",
|
lockRankSweepWaiters: "sweepWaiters",
|
||||||
|
|
@ -194,48 +196,49 @@ func (rank lockRank) String() string {
|
||||||
// hchan lock can be held immediately above it when it is acquired.
|
// hchan lock can be held immediately above it when it is acquired.
|
||||||
var lockPartialOrder [][]lockRank = [][]lockRank{
|
var lockPartialOrder [][]lockRank = [][]lockRank{
|
||||||
lockRankDummy: {},
|
lockRankDummy: {},
|
||||||
lockRankScavenge: {},
|
lockRankSysmon: {},
|
||||||
lockRankForcegc: {},
|
lockRankScavenge: {lockRankSysmon},
|
||||||
|
lockRankForcegc: {lockRankSysmon},
|
||||||
lockRankSweepWaiters: {},
|
lockRankSweepWaiters: {},
|
||||||
lockRankAssistQueue: {},
|
lockRankAssistQueue: {},
|
||||||
lockRankCpuprof: {},
|
lockRankCpuprof: {},
|
||||||
lockRankSweep: {},
|
lockRankSweep: {},
|
||||||
lockRankSched: {lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep},
|
lockRankSched: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep},
|
||||||
lockRankDeadlock: {lockRankDeadlock},
|
lockRankDeadlock: {lockRankDeadlock},
|
||||||
lockRankPanic: {lockRankDeadlock},
|
lockRankPanic: {lockRankDeadlock},
|
||||||
lockRankAllg: {lockRankSched, lockRankPanic},
|
lockRankAllg: {lockRankSysmon, lockRankSched, lockRankPanic},
|
||||||
lockRankAllp: {lockRankSched},
|
lockRankAllp: {lockRankSysmon, lockRankSched},
|
||||||
lockRankPollDesc: {},
|
lockRankPollDesc: {},
|
||||||
lockRankTimers: {lockRankScavenge, lockRankSched, lockRankAllp, lockRankPollDesc, lockRankTimers},
|
lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankSched, lockRankAllp, lockRankPollDesc, lockRankTimers},
|
||||||
lockRankItab: {},
|
lockRankItab: {},
|
||||||
lockRankReflectOffs: {lockRankItab},
|
lockRankReflectOffs: {lockRankItab},
|
||||||
lockRankHchan: {lockRankScavenge, lockRankSweep, lockRankHchan},
|
lockRankHchan: {lockRankScavenge, lockRankSweep, lockRankHchan},
|
||||||
lockRankFin: {lockRankSched, lockRankAllg, lockRankTimers, lockRankHchan},
|
lockRankFin: {lockRankSched, lockRankAllg, lockRankTimers, lockRankHchan},
|
||||||
lockRankNotifyList: {},
|
lockRankNotifyList: {},
|
||||||
lockRankTraceBuf: {lockRankScavenge},
|
lockRankTraceBuf: {lockRankSysmon, lockRankScavenge},
|
||||||
lockRankTraceStrings: {lockRankTraceBuf},
|
lockRankTraceStrings: {lockRankTraceBuf},
|
||||||
lockRankMspanSpecial: {lockRankScavenge, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings},
|
lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings},
|
||||||
lockRankProf: {lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
|
lockRankProf: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
|
||||||
lockRankGcBitsArenas: {lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
|
lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
|
||||||
lockRankRoot: {},
|
lockRankRoot: {},
|
||||||
lockRankTrace: {lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankSched, lockRankHchan, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankSweep},
|
lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankSched, lockRankHchan, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankSweep},
|
||||||
lockRankTraceStackTab: {lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankSched, lockRankAllg, lockRankTimers, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankTrace},
|
lockRankTraceStackTab: {lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankSched, lockRankAllg, lockRankTimers, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankTrace},
|
||||||
lockRankNetpollInit: {lockRankTimers},
|
lockRankNetpollInit: {lockRankTimers},
|
||||||
|
|
||||||
lockRankRwmutexW: {},
|
lockRankRwmutexW: {},
|
||||||
lockRankRwmutexR: {lockRankRwmutexW},
|
lockRankRwmutexR: {lockRankRwmutexW},
|
||||||
|
|
||||||
lockRankMcentral: {lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
|
lockRankMcentral: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
|
||||||
lockRankSpine: {lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
|
lockRankSpine: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
|
||||||
lockRankSpanSetSpine: {lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
|
lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
|
||||||
lockRankGscan: {lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankNotifyList, lockRankProf, lockRankGcBitsArenas, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankMcentral, lockRankSpine, lockRankSpanSetSpine},
|
lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankNotifyList, lockRankProf, lockRankGcBitsArenas, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankMcentral, lockRankSpine, lockRankSpanSetSpine},
|
||||||
lockRankStackpool: {lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankRwmutexR, lockRankMcentral, lockRankSpine, lockRankSpanSetSpine, lockRankGscan},
|
lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankRwmutexR, lockRankMcentral, lockRankSpine, lockRankSpanSetSpine, lockRankGscan},
|
||||||
lockRankStackLarge: {lockRankAssistQueue, lockRankSched, lockRankItab, lockRankHchan, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankMcentral, lockRankSpanSetSpine, lockRankGscan},
|
lockRankStackLarge: {lockRankSysmon, lockRankAssistQueue, lockRankSched, lockRankItab, lockRankHchan, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankMcentral, lockRankSpanSetSpine, lockRankGscan},
|
||||||
lockRankDefer: {},
|
lockRankDefer: {},
|
||||||
lockRankSudog: {lockRankNotifyList, lockRankHchan},
|
lockRankSudog: {lockRankNotifyList, lockRankHchan},
|
||||||
lockRankWbufSpans: {lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankSched, lockRankAllg, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceStrings, lockRankMspanSpecial, lockRankProf, lockRankRoot, lockRankGscan, lockRankDefer, lockRankSudog},
|
lockRankWbufSpans: {lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankSched, lockRankAllg, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceStrings, lockRankMspanSpecial, lockRankProf, lockRankRoot, lockRankGscan, lockRankDefer, lockRankSudog},
|
||||||
lockRankMheap: {lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan, lockRankMspanSpecial, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankMcentral, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankDefer, lockRankSudog, lockRankWbufSpans, lockRankSpanSetSpine},
|
lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan, lockRankMspanSpecial, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankMcentral, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankDefer, lockRankSudog, lockRankWbufSpans, lockRankSpanSetSpine},
|
||||||
lockRankMheapSpecial: {lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
|
lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
|
||||||
lockRankGlobalAlloc: {lockRankProf, lockRankSpine, lockRankSpanSetSpine, lockRankMheap, lockRankMheapSpecial},
|
lockRankGlobalAlloc: {lockRankProf, lockRankSpine, lockRankSpanSetSpine, lockRankMheap, lockRankMheapSpecial},
|
||||||
|
|
||||||
lockRankGFree: {lockRankSched},
|
lockRankGFree: {lockRankSched},
|
||||||
|
|
|
||||||
|
|
@ -1283,9 +1283,10 @@ HaveSpan:
|
||||||
// Publish the span in various locations.
|
// Publish the span in various locations.
|
||||||
|
|
||||||
// This is safe to call without the lock held because the slots
|
// This is safe to call without the lock held because the slots
|
||||||
// related to this span will only every be read or modified by
|
// related to this span will only ever be read or modified by
|
||||||
// this thread until pointers into the span are published or
|
// this thread until pointers into the span are published (and
|
||||||
// pageInUse is updated.
|
// we execute a publication barrier at the end of this function
|
||||||
|
// before that happens) or pageInUse is updated.
|
||||||
h.setSpans(s.base(), npages, s)
|
h.setSpans(s.base(), npages, s)
|
||||||
|
|
||||||
if !manual {
|
if !manual {
|
||||||
|
|
@ -1315,6 +1316,11 @@ HaveSpan:
|
||||||
traceHeapAlloc()
|
traceHeapAlloc()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure the newly allocated span will be observed
|
||||||
|
// by the GC before pointers into the span are published.
|
||||||
|
publicationBarrier()
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,18 @@ func (a addrRange) subtract(b addrRange) addrRange {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// removeGreaterEqual removes all addresses in a greater than or equal
|
||||||
|
// to addr and returns the new range.
|
||||||
|
func (a addrRange) removeGreaterEqual(addr uintptr) addrRange {
|
||||||
|
if (offAddr{addr}).lessEqual(a.base) {
|
||||||
|
return addrRange{}
|
||||||
|
}
|
||||||
|
if a.limit.lessEqual(offAddr{addr}) {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return makeAddrRange(a.base.addr(), addr)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// minOffAddr is the minimum address in the offset space, and
|
// minOffAddr is the minimum address in the offset space, and
|
||||||
// it corresponds to the virtual address arenaBaseOffset.
|
// it corresponds to the virtual address arenaBaseOffset.
|
||||||
|
|
@ -281,7 +293,7 @@ func (a *addrRanges) removeGreaterEqual(addr uintptr) {
|
||||||
}
|
}
|
||||||
if r := a.ranges[pivot-1]; r.contains(addr) {
|
if r := a.ranges[pivot-1]; r.contains(addr) {
|
||||||
removed += r.size()
|
removed += r.size()
|
||||||
r = r.subtract(makeAddrRange(addr, maxOffAddr.addr()))
|
r = r.removeGreaterEqual(addr)
|
||||||
if r.size() == 0 {
|
if r.size() == 0 {
|
||||||
pivot--
|
pivot--
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -293,7 +293,6 @@ func osinit() {
|
||||||
ncpu = getproccount()
|
ncpu = getproccount()
|
||||||
physPageSize = getPageSize()
|
physPageSize = getPageSize()
|
||||||
getg().m.procid = getpid()
|
getg().m.procid = getpid()
|
||||||
notify(unsafe.Pointer(funcPC(sigtramp)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
|
|
@ -311,6 +310,9 @@ func goenvs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func initsig(preinit bool) {
|
func initsig(preinit bool) {
|
||||||
|
if !preinit {
|
||||||
|
notify(unsafe.Pointer(funcPC(sigtramp)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
|
|
|
||||||
|
|
@ -533,6 +533,7 @@ func cpuinit() {
|
||||||
// The new G calls runtime·main.
|
// The new G calls runtime·main.
|
||||||
func schedinit() {
|
func schedinit() {
|
||||||
lockInit(&sched.lock, lockRankSched)
|
lockInit(&sched.lock, lockRankSched)
|
||||||
|
lockInit(&sched.sysmonlock, lockRankSysmon)
|
||||||
lockInit(&sched.deferlock, lockRankDefer)
|
lockInit(&sched.deferlock, lockRankDefer)
|
||||||
lockInit(&sched.sudoglock, lockRankSudog)
|
lockInit(&sched.sudoglock, lockRankSudog)
|
||||||
lockInit(&deadlock, lockRankDeadlock)
|
lockInit(&deadlock, lockRankDeadlock)
|
||||||
|
|
@ -4613,6 +4614,18 @@ func sysmon() {
|
||||||
}
|
}
|
||||||
unlock(&sched.lock)
|
unlock(&sched.lock)
|
||||||
}
|
}
|
||||||
|
lock(&sched.sysmonlock)
|
||||||
|
{
|
||||||
|
// If we spent a long time blocked on sysmonlock
|
||||||
|
// then we want to update now and next since it's
|
||||||
|
// likely stale.
|
||||||
|
now1 := nanotime()
|
||||||
|
if now1-now > 50*1000 /* 50µs */ {
|
||||||
|
next, _ = timeSleepUntil()
|
||||||
|
}
|
||||||
|
now = now1
|
||||||
|
}
|
||||||
|
|
||||||
// trigger libc interceptors if needed
|
// trigger libc interceptors if needed
|
||||||
if *cgo_yield != nil {
|
if *cgo_yield != nil {
|
||||||
asmcgocall(*cgo_yield, nil)
|
asmcgocall(*cgo_yield, nil)
|
||||||
|
|
@ -4665,6 +4678,7 @@ func sysmon() {
|
||||||
lasttrace = now
|
lasttrace = now
|
||||||
schedtrace(debug.scheddetail > 0)
|
schedtrace(debug.scheddetail > 0)
|
||||||
}
|
}
|
||||||
|
unlock(&sched.sysmonlock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,6 @@ import "fmt"
|
||||||
import "runtime"
|
import "runtime"
|
||||||
var gslice []string
|
var gslice []string
|
||||||
func main() {
|
func main() {
|
||||||
go func() { select{} }() // ensure a second goroutine is running
|
|
||||||
mapvar := make(map[string]string, 13)
|
mapvar := make(map[string]string, 13)
|
||||||
mapvar["abc"] = "def"
|
mapvar["abc"] = "def"
|
||||||
mapvar["ghi"] = "jkl"
|
mapvar["ghi"] = "jkl"
|
||||||
|
|
@ -231,9 +230,6 @@ func testGdbPython(t *testing.T, cgo bool) {
|
||||||
"-ex", "echo BEGIN goroutine 1 bt\n",
|
"-ex", "echo BEGIN goroutine 1 bt\n",
|
||||||
"-ex", "goroutine 1 bt",
|
"-ex", "goroutine 1 bt",
|
||||||
"-ex", "echo END\n",
|
"-ex", "echo END\n",
|
||||||
"-ex", "echo BEGIN goroutine 2 bt\n",
|
|
||||||
"-ex", "goroutine 2 bt",
|
|
||||||
"-ex", "echo END\n",
|
|
||||||
"-ex", "echo BEGIN goroutine all bt\n",
|
"-ex", "echo BEGIN goroutine all bt\n",
|
||||||
"-ex", "goroutine all bt",
|
"-ex", "goroutine all bt",
|
||||||
"-ex", "echo END\n",
|
"-ex", "echo END\n",
|
||||||
|
|
@ -310,7 +306,6 @@ func testGdbPython(t *testing.T, cgo bool) {
|
||||||
|
|
||||||
// Check that the backtraces are well formed.
|
// Check that the backtraces are well formed.
|
||||||
checkCleanBacktrace(t, blocks["goroutine 1 bt"])
|
checkCleanBacktrace(t, blocks["goroutine 1 bt"])
|
||||||
checkCleanBacktrace(t, blocks["goroutine 2 bt"])
|
|
||||||
checkCleanBacktrace(t, blocks["goroutine 1 bt at the end"])
|
checkCleanBacktrace(t, blocks["goroutine 1 bt at the end"])
|
||||||
|
|
||||||
btGoroutine1Re := regexp.MustCompile(`(?m)^#0\s+(0x[0-9a-f]+\s+in\s+)?main\.main.+at`)
|
btGoroutine1Re := regexp.MustCompile(`(?m)^#0\s+(0x[0-9a-f]+\s+in\s+)?main\.main.+at`)
|
||||||
|
|
@ -318,12 +313,7 @@ func testGdbPython(t *testing.T, cgo bool) {
|
||||||
t.Fatalf("goroutine 1 bt failed: %s", bl)
|
t.Fatalf("goroutine 1 bt failed: %s", bl)
|
||||||
}
|
}
|
||||||
|
|
||||||
btGoroutine2Re := regexp.MustCompile(`(?m)^#0\s+(0x[0-9a-f]+\s+in\s+)?runtime.+at`)
|
if bl := blocks["goroutine all bt"]; !btGoroutine1Re.MatchString(bl) {
|
||||||
if bl := blocks["goroutine 2 bt"]; !btGoroutine2Re.MatchString(bl) {
|
|
||||||
t.Fatalf("goroutine 2 bt failed: %s", bl)
|
|
||||||
}
|
|
||||||
|
|
||||||
if bl := blocks["goroutine all bt"]; !btGoroutine1Re.MatchString(bl) || !btGoroutine2Re.MatchString(bl) {
|
|
||||||
t.Fatalf("goroutine all bt failed: %s", bl)
|
t.Fatalf("goroutine all bt failed: %s", bl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -349,9 +349,9 @@ type sudog struct {
|
||||||
|
|
||||||
g *g
|
g *g
|
||||||
|
|
||||||
next *sudog
|
next *sudog
|
||||||
prev *sudog
|
prev *sudog
|
||||||
elem unsafe.Pointer // data element (may point to stack)
|
elem unsafe.Pointer // data element (may point to stack)
|
||||||
|
|
||||||
// The following fields are never accessed concurrently.
|
// The following fields are never accessed concurrently.
|
||||||
// For channels, waitlink is only accessed by g.
|
// For channels, waitlink is only accessed by g.
|
||||||
|
|
@ -366,10 +366,10 @@ type sudog struct {
|
||||||
// g.selectDone must be CAS'd to win the wake-up race.
|
// g.selectDone must be CAS'd to win the wake-up race.
|
||||||
isSelect bool
|
isSelect bool
|
||||||
|
|
||||||
parent *sudog // semaRoot binary tree
|
parent *sudog // semaRoot binary tree
|
||||||
waitlink *sudog // g.waiting list or semaRoot
|
waitlink *sudog // g.waiting list or semaRoot
|
||||||
waittail *sudog // semaRoot
|
waittail *sudog // semaRoot
|
||||||
c *hchan // channel
|
c *hchan // channel
|
||||||
}
|
}
|
||||||
|
|
||||||
type libcall struct {
|
type libcall struct {
|
||||||
|
|
@ -768,6 +768,12 @@ type schedt struct {
|
||||||
|
|
||||||
procresizetime int64 // nanotime() of last change to gomaxprocs
|
procresizetime int64 // nanotime() of last change to gomaxprocs
|
||||||
totaltime int64 // ∫gomaxprocs dt up to procresizetime
|
totaltime int64 // ∫gomaxprocs dt up to procresizetime
|
||||||
|
|
||||||
|
// sysmonlock protects sysmon's actions on the runtime.
|
||||||
|
//
|
||||||
|
// Acquire and hold this mutex to block sysmon from interacting
|
||||||
|
// with the rest of the runtime.
|
||||||
|
sysmonlock mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values for the flags field of a sigTabT.
|
// Values for the flags field of a sigTabT.
|
||||||
|
|
|
||||||
31
src/runtime/testdata/testprogcgo/eintr.go
vendored
31
src/runtime/testdata/testprogcgo/eintr.go
vendored
|
|
@ -32,11 +32,11 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/signal"
|
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -71,14 +71,15 @@ func EINTR() {
|
||||||
// spin does CPU bound spinning and allocating for a millisecond,
|
// spin does CPU bound spinning and allocating for a millisecond,
|
||||||
// to get a SIGURG.
|
// to get a SIGURG.
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func spin() (float64, [][]byte) {
|
func spin() (float64, []byte) {
|
||||||
stop := time.Now().Add(time.Millisecond)
|
stop := time.Now().Add(time.Millisecond)
|
||||||
r1 := 0.0
|
r1 := 0.0
|
||||||
var r2 [][]byte
|
r2 := make([]byte, 200)
|
||||||
for time.Now().Before(stop) {
|
for time.Now().Before(stop) {
|
||||||
for i := 1; i < 1e6; i++ {
|
for i := 1; i < 1e6; i++ {
|
||||||
r1 += r1 / float64(i)
|
r1 += r1 / float64(i)
|
||||||
r2 = append(r2, bytes.Repeat([]byte{byte(i)}, 100))
|
r2 = append(r2, bytes.Repeat([]byte{byte(i)}, 100)...)
|
||||||
|
r2 = r2[100:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r1, r2
|
return r1, r2
|
||||||
|
|
@ -96,8 +97,13 @@ func winch() {
|
||||||
|
|
||||||
// sendSomeSignals triggers a few SIGURG and SIGWINCH signals.
|
// sendSomeSignals triggers a few SIGURG and SIGWINCH signals.
|
||||||
func sendSomeSignals() {
|
func sendSomeSignals() {
|
||||||
spin()
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
spin()
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
winch()
|
winch()
|
||||||
|
<-done
|
||||||
}
|
}
|
||||||
|
|
||||||
// testPipe tests pipe operations.
|
// testPipe tests pipe operations.
|
||||||
|
|
@ -212,6 +218,10 @@ func testExec(wg *sync.WaitGroup) {
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
cmd := exec.Command(os.Args[0], "Block")
|
cmd := exec.Command(os.Args[0], "Block")
|
||||||
|
stdin, err := cmd.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
cmd.Stderr = new(bytes.Buffer)
|
cmd.Stderr = new(bytes.Buffer)
|
||||||
cmd.Stdout = cmd.Stderr
|
cmd.Stdout = cmd.Stderr
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
|
|
@ -220,9 +230,7 @@ func testExec(wg *sync.WaitGroup) {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
sendSomeSignals()
|
sendSomeSignals()
|
||||||
if err := cmd.Process.Signal(os.Interrupt); err != nil {
|
stdin.Close()
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err := cmd.Wait(); err != nil {
|
if err := cmd.Wait(); err != nil {
|
||||||
|
|
@ -231,10 +239,7 @@ func testExec(wg *sync.WaitGroup) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block blocks until the process receives os.Interrupt.
|
// Block blocks until stdin is closed.
|
||||||
func Block() {
|
func Block() {
|
||||||
c := make(chan os.Signal, 1)
|
io.Copy(ioutil.Discard, os.Stdin)
|
||||||
signal.Notify(c, os.Interrupt)
|
|
||||||
defer signal.Stop(c)
|
|
||||||
<-c
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,9 @@ func StartTrace() error {
|
||||||
// paired with an end).
|
// paired with an end).
|
||||||
stopTheWorldGC("start tracing")
|
stopTheWorldGC("start tracing")
|
||||||
|
|
||||||
|
// Prevent sysmon from running any code that could generate events.
|
||||||
|
lock(&sched.sysmonlock)
|
||||||
|
|
||||||
// We are in stop-the-world, but syscalls can finish and write to trace concurrently.
|
// We are in stop-the-world, but syscalls can finish and write to trace concurrently.
|
||||||
// Exitsyscall could check trace.enabled long before and then suddenly wake up
|
// Exitsyscall could check trace.enabled long before and then suddenly wake up
|
||||||
// and decide to write to trace at a random point in time.
|
// and decide to write to trace at a random point in time.
|
||||||
|
|
@ -196,6 +199,7 @@ func StartTrace() error {
|
||||||
|
|
||||||
if trace.enabled || trace.shutdown {
|
if trace.enabled || trace.shutdown {
|
||||||
unlock(&trace.bufLock)
|
unlock(&trace.bufLock)
|
||||||
|
unlock(&sched.sysmonlock)
|
||||||
startTheWorldGC()
|
startTheWorldGC()
|
||||||
return errorString("tracing is already enabled")
|
return errorString("tracing is already enabled")
|
||||||
}
|
}
|
||||||
|
|
@ -267,6 +271,8 @@ func StartTrace() error {
|
||||||
|
|
||||||
unlock(&trace.bufLock)
|
unlock(&trace.bufLock)
|
||||||
|
|
||||||
|
unlock(&sched.sysmonlock)
|
||||||
|
|
||||||
startTheWorldGC()
|
startTheWorldGC()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -278,11 +284,15 @@ func StopTrace() {
|
||||||
// and also to avoid races with traceEvent.
|
// and also to avoid races with traceEvent.
|
||||||
stopTheWorldGC("stop tracing")
|
stopTheWorldGC("stop tracing")
|
||||||
|
|
||||||
|
// See the comment in StartTrace.
|
||||||
|
lock(&sched.sysmonlock)
|
||||||
|
|
||||||
// See the comment in StartTrace.
|
// See the comment in StartTrace.
|
||||||
lock(&trace.bufLock)
|
lock(&trace.bufLock)
|
||||||
|
|
||||||
if !trace.enabled {
|
if !trace.enabled {
|
||||||
unlock(&trace.bufLock)
|
unlock(&trace.bufLock)
|
||||||
|
unlock(&sched.sysmonlock)
|
||||||
startTheWorldGC()
|
startTheWorldGC()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -320,6 +330,8 @@ func StopTrace() {
|
||||||
trace.shutdown = true
|
trace.shutdown = true
|
||||||
unlock(&trace.bufLock)
|
unlock(&trace.bufLock)
|
||||||
|
|
||||||
|
unlock(&sched.sysmonlock)
|
||||||
|
|
||||||
startTheWorldGC()
|
startTheWorldGC()
|
||||||
|
|
||||||
// The world is started but we've set trace.shutdown, so new tracing can't start.
|
// The world is started but we've set trace.shutdown, so new tracing can't start.
|
||||||
|
|
|
||||||
|
|
@ -339,6 +339,26 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) {
|
||||||
var attrs uint32 = FILE_ATTRIBUTE_NORMAL
|
var attrs uint32 = FILE_ATTRIBUTE_NORMAL
|
||||||
if perm&S_IWRITE == 0 {
|
if perm&S_IWRITE == 0 {
|
||||||
attrs = FILE_ATTRIBUTE_READONLY
|
attrs = FILE_ATTRIBUTE_READONLY
|
||||||
|
if createmode == CREATE_ALWAYS {
|
||||||
|
// We have been asked to create a read-only file.
|
||||||
|
// If the file already exists, the semantics of
|
||||||
|
// the Unix open system call is to preserve the
|
||||||
|
// existing permissions. If we pass CREATE_ALWAYS
|
||||||
|
// and FILE_ATTRIBUTE_READONLY to CreateFile,
|
||||||
|
// and the file already exists, CreateFile will
|
||||||
|
// change the file permissions.
|
||||||
|
// Avoid that to preserve the Unix semantics.
|
||||||
|
h, e := CreateFile(pathp, access, sharemode, sa, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
|
||||||
|
switch e {
|
||||||
|
case ERROR_FILE_NOT_FOUND, _ERROR_BAD_NETPATH, ERROR_PATH_NOT_FOUND:
|
||||||
|
// File does not exist. These are the same
|
||||||
|
// errors as Errno.Is checks for ErrNotExist.
|
||||||
|
// Carry on to create the file.
|
||||||
|
default:
|
||||||
|
// Success or some different error.
|
||||||
|
return h, e
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
h, e := CreateFile(pathp, access, sharemode, sa, createmode, attrs, 0)
|
h, e := CreateFile(pathp, access, sharemode, sa, createmode, attrs, 0)
|
||||||
return h, e
|
return h, e
|
||||||
|
|
|
||||||
|
|
@ -372,6 +372,7 @@ type common struct {
|
||||||
tempDirOnce sync.Once
|
tempDirOnce sync.Once
|
||||||
tempDir string
|
tempDir string
|
||||||
tempDirErr error
|
tempDirErr error
|
||||||
|
tempDirSeq int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short reports whether the -test.short flag is set.
|
// Short reports whether the -test.short flag is set.
|
||||||
|
|
@ -821,12 +822,13 @@ var tempDirReplacer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TempDir returns a temporary directory for the test to use.
|
// TempDir returns a temporary directory for the test to use.
|
||||||
// It is lazily created on first access, and calls t.Fatal if the directory
|
|
||||||
// creation fails.
|
|
||||||
// Subsequent calls to t.TempDir return the same directory.
|
|
||||||
// The directory is automatically removed by Cleanup when the test and
|
// The directory is automatically removed by Cleanup when the test and
|
||||||
// all its subtests complete.
|
// all its subtests complete.
|
||||||
|
// Each subsequent call to t.TempDir returns a unique directory;
|
||||||
|
// if the directory creation fails, TempDir terminates the test by calling Fatal.
|
||||||
func (c *common) TempDir() string {
|
func (c *common) TempDir() string {
|
||||||
|
// Use a single parent directory for all the temporary directories
|
||||||
|
// created by a test, each numbered sequentially.
|
||||||
c.tempDirOnce.Do(func() {
|
c.tempDirOnce.Do(func() {
|
||||||
c.Helper()
|
c.Helper()
|
||||||
|
|
||||||
|
|
@ -849,7 +851,12 @@ func (c *common) TempDir() string {
|
||||||
if c.tempDirErr != nil {
|
if c.tempDirErr != nil {
|
||||||
c.Fatalf("TempDir: %v", c.tempDirErr)
|
c.Fatalf("TempDir: %v", c.tempDirErr)
|
||||||
}
|
}
|
||||||
return c.tempDir
|
seq := atomic.AddInt32(&c.tempDirSeq, 1)
|
||||||
|
dir := fmt.Sprintf("%s%c%03d", c.tempDir, os.PathSeparator, seq)
|
||||||
|
if err := os.Mkdir(dir, 0777); err != nil {
|
||||||
|
c.Fatalf("TempDir: %v", err)
|
||||||
|
}
|
||||||
|
return dir
|
||||||
}
|
}
|
||||||
|
|
||||||
// panicHanding is an argument to runCleanup.
|
// panicHanding is an argument to runCleanup.
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ package testing_test
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -55,8 +56,11 @@ func testTempDir(t *testing.T) {
|
||||||
t.Fatal("expected dir")
|
t.Fatal("expected dir")
|
||||||
}
|
}
|
||||||
dir2 := t.TempDir()
|
dir2 := t.TempDir()
|
||||||
if dir != dir2 {
|
if dir == dir2 {
|
||||||
t.Fatal("directory changed between calls")
|
t.Fatal("subsequent calls to TempDir returned the same directory")
|
||||||
|
}
|
||||||
|
if filepath.Dir(dir) != filepath.Dir(dir2) {
|
||||||
|
t.Fatalf("calls to TempDir do not share a parent; got %q, %q", dir, dir2)
|
||||||
}
|
}
|
||||||
dirCh <- dir
|
dirCh <- dir
|
||||||
fi, err := os.Stat(dir)
|
fi, err := os.Stat(dir)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue