[dev.link] all: merge branch 'master' into dev.link
Change-Id: I85b653b621ad8cb2ef27886210ea2c4b7409b60d
diff --git a/doc/go1.15.html b/doc/go1.15.html
index af0b3ba..79b18a3 100644
--- a/doc/go1.15.html
+++ b/doc/go1.15.html
@@ -33,6 +33,12 @@
<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 -->
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,
@@ -116,6 +122,73 @@
<code>GODEBUG=modcacheunzipinplace=1</code>.
</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>
<p>
@@ -155,22 +228,6 @@
TODO
</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>
<p>
@@ -375,6 +432,20 @@
<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
+ <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 -->
The new methods
<a href="/pkg/testing/#T.TempDir"><code>T.TempDir</code></a> and
diff --git a/doc/install-source.html b/doc/install-source.html
index 8f0d3a9..b5b422e 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -501,7 +501,7 @@
<p>
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>linux</code>, <code>netbsd</code>, <code>openbsd</code>,
<code>plan9</code>, <code>solaris</code> and <code>windows</code>.
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
index 6ccd0b8..74654c8 100644
--- a/src/cmd/compile/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -271,7 +271,7 @@
}
}
- if compilenow() {
+ if compilenow(fn) {
compileSSA(fn, 0)
} else {
compilequeue = append(compilequeue, fn)
@@ -282,10 +282,31 @@
// If functions are not compiled immediately,
// they are enqueued in compilequeue,
// 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
}
+// 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
// compileSSA builds an SSA backend function,
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index d22ee1d..9e2b4f3 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -31,7 +31,6 @@
goos string
goarm string
go386 string
- goamd64 string
gomips string
gomips64 string
goppc64 string
@@ -152,12 +151,6 @@
}
go386 = b
- b = os.Getenv("GOAMD64")
- if b == "" {
- b = "alignedjumps"
- }
- goamd64 = b
-
b = os.Getenv("GOMIPS")
if b == "" {
b = "hardfloat"
@@ -230,7 +223,6 @@
// For tools being invoked but also for os.ExpandEnv.
os.Setenv("GO386", go386)
- os.Setenv("GOAMD64", goamd64)
os.Setenv("GOARCH", goarch)
os.Setenv("GOARM", goarm)
os.Setenv("GOHOSTARCH", gohostarch)
@@ -1171,9 +1163,6 @@
if goarch == "386" {
xprintf(format, "GO386", go386)
}
- if goarch == "amd64" {
- xprintf(format, "GOAMD64", goamd64)
- }
if goarch == "mips" || goarch == "mipsle" {
xprintf(format, "GOMIPS", gomips)
}
diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go
index f11933c..2744951 100644
--- a/src/cmd/dist/buildruntime.go
+++ b/src/cmd/dist/buildruntime.go
@@ -42,7 +42,6 @@
//
// const defaultGOROOT = <goroot>
// const defaultGO386 = <go386>
-// const defaultGOAMD64 = <goamd64>
// const defaultGOARM = <goarm>
// const defaultGOMIPS = <gomips>
// const defaultGOMIPS64 = <gomips64>
@@ -72,7 +71,6 @@
fmt.Fprintf(&buf, "import \"runtime\"\n")
fmt.Fprintln(&buf)
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 defaultGOMIPS = `%s`\n", gomips)
fmt.Fprintf(&buf, "const defaultGOMIPS64 = `%s`\n", gomips64)
diff --git a/src/cmd/go.mod b/src/cmd/go.mod
index 9c78cd1..d56dde8 100644
--- a/src/cmd/go.mod
+++ b/src/cmd/go.mod
@@ -7,7 +7,7 @@
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
golang.org/x/arch v0.0.0-20200511175325-f7c78586839d
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/tools v0.0.0-20200504152539-33427f1b0364
)
diff --git a/src/cmd/go.sum b/src/cmd/go.sum
index f1b3754..922df77 100644
--- a/src/cmd/go.sum
+++ b/src/cmd/go.sum
@@ -14,8 +14,8 @@
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/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.2.1-0.20200429172858-859b3ef565e2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
+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-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=
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index 5c1f725..fdeef65 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -1754,9 +1754,6 @@
// GO386
// For GOARCH=386, the floating point instruction set.
// 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
// For GOARCH=mips{,le}, whether to use floating point instructions.
// Valid values are hardfloat (default), softfloat.
diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go
index 21f55e8..7f8f8e9 100644
--- a/src/cmd/go/internal/cfg/cfg.go
+++ b/src/cmd/go/internal/cfg/cfg.go
@@ -241,7 +241,6 @@
// Used in envcmd.MkEnv and build ID computations.
GOARM = envOr("GOARM", fmt.Sprint(objabi.GOARM))
GO386 = envOr("GO386", objabi.GO386)
- GOAMD64 = envOr("GOAMD64", objabi.GOAMD64)
GOMIPS = envOr("GOMIPS", objabi.GOMIPS)
GOMIPS64 = envOr("GOMIPS64", objabi.GOMIPS64)
GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", objabi.GOPPC64))
@@ -267,8 +266,6 @@
return "GOARM", GOARM
case "386":
return "GO386", GO386
- case "amd64":
- return "GOAMD64", GOAMD64
case "mips", "mipsle":
return "GOMIPS", GOMIPS
case "mips64", "mips64le":
diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go
index 9583b3f..693de8f 100644
--- a/src/cmd/go/internal/help/helpdoc.go
+++ b/src/cmd/go/internal/help/helpdoc.go
@@ -582,9 +582,6 @@
GO386
For GOARCH=386, the floating point instruction set.
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
For GOARCH=mips{,le}, whether to use floating point instructions.
Valid values are hardfloat (default), softfloat.
diff --git a/src/cmd/go/internal/modfetch/proxy.go b/src/cmd/go/internal/modfetch/proxy.go
index 0ca43d4..3971598 100644
--- a/src/cmd/go/internal/modfetch/proxy.go
+++ b/src/cmd/go/internal/modfetch/proxy.go
@@ -196,8 +196,12 @@
// 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
- // by ErrNotExist. Note that errProxyOff, errNoproxy, and errUseProxy are
- // equivalent to ErrNotExist.
+ // by 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 (
notExistRank = iota
proxyRank
@@ -212,7 +216,7 @@
}
isNotExistErr := errors.Is(err, os.ErrNotExist)
- if proxy.url == "direct" || proxy.url == "noproxy" {
+ if proxy.url == "direct" || (proxy.url == "noproxy" && err != errUseProxy) {
bestErr = err
bestErrRank = directRank
} else if bestErrRank <= proxyRank && !isNotExistErr {
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index 6ab3498..071c9d2 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -2434,13 +2434,25 @@
if b.flagCache == nil {
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
// 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
// version of GCC, so some systems have frozen on it.
// Now we pass an empty file on stdin, which should work at least for
// 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 {
b.Showcmd(b.WorkDir, "%s || true", joinUnambiguously(cmdArgs))
if cfg.BuildN {
diff --git a/src/cmd/go/note_test.go b/src/cmd/go/note_test.go
index 089e2f3..659366d 100644
--- a/src/cmd/go/note_test.go
+++ b/src/cmd/go/note_test.go
@@ -53,7 +53,7 @@
// 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")})
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
// ld.gold is missing, see issue #22340.
t.Log("skipping gold test")
diff --git a/src/cmd/go/testdata/script/issue36000.txt b/src/cmd/go/testdata/script/issue36000.txt
new file mode 100644
index 0000000..4173275
--- /dev/null
+++ b/src/cmd/go/testdata/script/issue36000.txt
@@ -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
diff --git a/src/cmd/go/testdata/script/mod_gonoproxy.txt b/src/cmd/go/testdata/script/mod_gonoproxy.txt
index 2bd94cd..d7848c7 100644
--- a/src/cmd/go/testdata/script/mod_gonoproxy.txt
+++ b/src/cmd/go/testdata/script/mod_gonoproxy.txt
@@ -10,7 +10,7 @@
! go get rsc.io/quote
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'
go get rsc.io/quote
rm go.sum
@@ -18,7 +18,13 @@
env GONOPROXY=none # that is, proxy all despite GOPRIVATE
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
[!exec:git] skip
env GOPRIVATE=none
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index 6701b9b..5e7018e 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -425,6 +425,14 @@
absfn.Type = objabi.SDWARFINFO
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}
}
diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go
index 72dd585..2f94ec6 100644
--- a/src/cmd/internal/objabi/util.go
+++ b/src/cmd/internal/objabi/util.go
@@ -37,16 +37,13 @@
const (
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 {
- switch v := envOr("GOAMD64", defaultGOAMD64); v {
- case "normaljumps", "alignedjumps":
- return v
- }
- log.Fatalf("Invalid GOAMD64 value. Must be normaljumps or alignedjumps.")
- panic("unreachable")
+ return Go115AMD64
}
func goarm() int {
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go
index 08f6c76..357a22b 100644
--- a/src/cmd/link/internal/arm/asm.go
+++ b/src/cmd/link/internal/arm/asm.go
@@ -385,12 +385,16 @@
offset := (signext24(r.Add()&0xffffff) + 2) * 4
var tramp loader.Sym
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)))
if ldr.SymType(tramp) == sym.SDYNIMPORT {
// don't reuse trampoline defined in other module
continue
}
+ if oName == "runtime.deferreturn" {
+ ldr.SetIsDeferReturnTramp(tramp, true)
+ }
if ldr.SymValue(tramp) == 0 {
// either the trampoline does not exist -- we need to create one,
// or found one the address which is not assigned -- this will be
diff --git a/src/cmd/link/internal/ld/fallocate_test.go b/src/cmd/link/internal/ld/fallocate_test.go
new file mode 100644
index 0000000..a064bea
--- /dev/null
+++ b/src/cmd/link/internal/ld/fallocate_test.go
@@ -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()
+ }
+}
diff --git a/src/cmd/link/internal/ld/outbuf_darwin.go b/src/cmd/link/internal/ld/outbuf_darwin.go
index 299902e..9a74ba8 100644
--- a/src/cmd/link/internal/ld/outbuf_darwin.go
+++ b/src/cmd/link/internal/ld/outbuf_darwin.go
@@ -10,16 +10,25 @@
)
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{
Flags: syscall.F_ALLOCATEALL,
Posmode: syscall.F_PEOFPOSMODE,
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)))
- if err != 0 {
- return err
+ _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store)))
+ if errno != 0 {
+ return errno
}
return nil
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index dc2fb70..a5f776e 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -161,7 +161,7 @@
// set the resumption point to PC_B.
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() {
deferreturn = lastWasmAddr - 1
} else {
diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go
index b9e0632..e340506 100644
--- a/src/cmd/link/internal/loader/loader.go
+++ b/src/cmd/link/internal/loader/loader.go
@@ -229,7 +229,8 @@
outdata [][]byte // symbol's data in the output buffer
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
@@ -354,6 +355,7 @@
attrCgoExportDynamic: make(map[Sym]struct{}),
attrCgoExportStatic: make(map[Sym]struct{}),
itablink: make(map[Sym]struct{}),
+ deferReturnTramp: make(map[Sym]bool),
extStaticSyms: make(map[nameVer]Sym),
builtinSyms: make([]Sym, nbuiltin),
flags: flags,
@@ -1050,6 +1052,16 @@
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.
func (l *Loader) growValues(reqLen int) {
curLen := len(l.values)
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index ee14601..aae42c0 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -686,16 +686,20 @@
// target is at some offset within the function. Calls to duff+8 and duff+256 must appear as
// distinct trampolines.
- name := ldr.SymName(rs)
+ oName := ldr.SymName(rs)
+ name := oName
if r.Add() == 0 {
- name = name + fmt.Sprintf("-tramp%d", i)
+ name += fmt.Sprintf("-tramp%d", i)
} 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
tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs)))
+ if oName == "runtime.deferreturn" {
+ ldr.SetIsDeferReturnTramp(tramp, true)
+ }
if ldr.SymValue(tramp) == 0 {
break
}
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
index 145eb3c..635c55d 100644
--- a/src/cmd/link/link_test.go
+++ b/src/cmd/link/link_test.go
@@ -605,10 +605,23 @@
}
}
-const helloSrc = `
+const testTrampSrc = `
package main
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) {
@@ -631,7 +644,7 @@
defer os.RemoveAll(tmpdir)
src := filepath.Join(tmpdir, "hello.go")
- err = ioutil.WriteFile(src, []byte(helloSrc), 0666)
+ err = ioutil.WriteFile(src, []byte(testTrampSrc), 0666)
if err != nil {
t.Fatal(err)
}
diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt
index 0a3ea66..8a7976a 100644
--- a/src/cmd/vendor/modules.txt
+++ b/src/cmd/vendor/modules.txt
@@ -29,7 +29,7 @@
golang.org/x/crypto/ed25519
golang.org/x/crypto/ed25519/internal/edwards25519
golang.org/x/crypto/ssh/terminal
-# golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2
+# golang.org/x/mod v0.3.0
## explicit
golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/modfile
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
index 313872c..de93e1b 100644
--- a/src/crypto/tls/handshake_client_test.go
+++ b/src/crypto/tls/handshake_client_test.go
@@ -980,7 +980,28 @@
if bytes.Equal(ticket, getTicket()) {
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
// before the serverConfig is used works.
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index 6aacfa1..57fba10 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -75,13 +75,8 @@
if err := hs.establishKeys(); err != nil {
return err
}
- // 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 err := hs.sendSessionTicket(); err != nil {
- return err
- }
+ if err := hs.sendSessionTicket(); err != nil {
+ return err
}
if err := hs.sendFinished(c.serverFinished[:]); err != nil {
return err
@@ -688,6 +683,9 @@
}
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 {
return nil
}
@@ -695,6 +693,13 @@
c := hs.c
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
for _, cert := range c.peerCertificates {
certsFromClient = append(certsFromClient, cert.Raw)
@@ -702,7 +707,7 @@
state := sessionState{
vers: c.vers,
cipherSuite: hs.suite.id,
- createdAt: uint64(c.config.time().Unix()),
+ createdAt: createdAt,
masterSecret: hs.masterSecret,
certificates: certsFromClient,
}
diff --git a/src/crypto/tls/ticket.go b/src/crypto/tls/ticket.go
index 38b01fc..6c1d20d 100644
--- a/src/crypto/tls/ticket.go
+++ b/src/crypto/tls/ticket.go
@@ -54,7 +54,6 @@
*m = sessionState{usedOldKey: m.usedOldKey}
s := cryptobyte.String(data)
if ok := s.ReadUint16(&m.vers) &&
- m.vers != VersionTLS13 &&
s.ReadUint16(&m.cipherSuite) &&
readUint64(&s, &m.createdAt) &&
readUint16LengthPrefixed(&s, &m.masterSecret) &&
diff --git a/src/crypto/x509/root_unix_test.go b/src/crypto/x509/root_unix_test.go
index 39556ae..5a80154 100644
--- a/src/crypto/x509/root_unix_test.go
+++ b/src/crypto/x509/root_unix_test.go
@@ -204,7 +204,8 @@
}
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 {
t.Fatal(err)
} else {
@@ -216,7 +217,7 @@
if err := os.Symlink("../target-out", temp("link-out")); err != nil {
t.Fatal(err)
}
- got, err := readUniqueDirectoryEntries(t.TempDir())
+ got, err := readUniqueDirectoryEntries(tmp)
if err != nil {
t.Fatal(err)
}
diff --git a/src/internal/cfg/cfg.go b/src/internal/cfg/cfg.go
index e40b7b4..bdbe9df 100644
--- a/src/internal/cfg/cfg.go
+++ b/src/internal/cfg/cfg.go
@@ -33,7 +33,6 @@
GCCGO
GO111MODULE
GO386
- GOAMD64
GOARCH
GOARM
GOBIN
diff --git a/src/math/big/link_test.go b/src/math/big/link_test.go
index ad4359c..2212bd4 100644
--- a/src/math/big/link_test.go
+++ b/src/math/big/link_test.go
@@ -20,8 +20,9 @@
t.Skip("skipping in short mode")
}
t.Parallel()
+ tmp := t.TempDir()
goBin := testenv.GoToolPath(t)
- goFile := filepath.Join(t.TempDir(), "x.go")
+ goFile := filepath.Join(tmp, "x.go")
file := []byte(`package main
import _ "math/big"
func main() {}
@@ -30,13 +31,13 @@
t.Fatal(err)
}
cmd := exec.Command(goBin, "build", "-o", "x.exe", "x.go")
- cmd.Dir = t.TempDir()
+ cmd.Dir = tmp
if out, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("compile: %v, %s", err, out)
}
cmd = exec.Command(goBin, "tool", "nm", "x.exe")
- cmd.Dir = t.TempDir()
+ cmd.Dir = tmp
nm, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("nm: %v, %s", err, nm)
diff --git a/src/os/os_test.go b/src/os/os_test.go
index f86428b..e8c6451 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -2539,3 +2539,34 @@
}
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())
+ }
+}
diff --git a/src/os/readfrom_linux_test.go b/src/os/readfrom_linux_test.go
index cecaed5..b6f5cb7 100644
--- a/src/os/readfrom_linux_test.go
+++ b/src/os/readfrom_linux_test.go
@@ -249,14 +249,15 @@
t.Helper()
hook = hookCopyFileRange(t)
+ tmp := t.TempDir()
- src, err := Create(filepath.Join(t.TempDir(), "src"))
+ src, err := Create(filepath.Join(tmp, "src"))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { src.Close() })
- dst, err = Create(filepath.Join(t.TempDir(), "dst"))
+ dst, err = Create(filepath.Join(tmp, "dst"))
if err != nil {
t.Fatal(err)
}
diff --git a/src/runtime/lockrank.go b/src/runtime/lockrank.go
index 899c4e2..a4fe921 100644
--- a/src/runtime/lockrank.go
+++ b/src/runtime/lockrank.go
@@ -33,6 +33,7 @@
lockRankDummy lockRank = iota
// Locks held above sched
+ lockRankSysmon
lockRankScavenge
lockRankForcegc
lockRankSweepWaiters
@@ -113,6 +114,7 @@
var lockNames = []string{
lockRankDummy: "",
+ lockRankSysmon: "sysmon",
lockRankScavenge: "scavenge",
lockRankForcegc: "forcegc",
lockRankSweepWaiters: "sweepWaiters",
@@ -194,48 +196,49 @@
// hchan lock can be held immediately above it when it is acquired.
var lockPartialOrder [][]lockRank = [][]lockRank{
lockRankDummy: {},
- lockRankScavenge: {},
- lockRankForcegc: {},
+ lockRankSysmon: {},
+ lockRankScavenge: {lockRankSysmon},
+ lockRankForcegc: {lockRankSysmon},
lockRankSweepWaiters: {},
lockRankAssistQueue: {},
lockRankCpuprof: {},
lockRankSweep: {},
- lockRankSched: {lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep},
+ lockRankSched: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep},
lockRankDeadlock: {lockRankDeadlock},
lockRankPanic: {lockRankDeadlock},
- lockRankAllg: {lockRankSched, lockRankPanic},
- lockRankAllp: {lockRankSched},
+ lockRankAllg: {lockRankSysmon, lockRankSched, lockRankPanic},
+ lockRankAllp: {lockRankSysmon, lockRankSched},
lockRankPollDesc: {},
- lockRankTimers: {lockRankScavenge, lockRankSched, lockRankAllp, lockRankPollDesc, lockRankTimers},
+ lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankSched, lockRankAllp, lockRankPollDesc, lockRankTimers},
lockRankItab: {},
lockRankReflectOffs: {lockRankItab},
lockRankHchan: {lockRankScavenge, lockRankSweep, lockRankHchan},
lockRankFin: {lockRankSched, lockRankAllg, lockRankTimers, lockRankHchan},
lockRankNotifyList: {},
- lockRankTraceBuf: {lockRankScavenge},
+ lockRankTraceBuf: {lockRankSysmon, lockRankScavenge},
lockRankTraceStrings: {lockRankTraceBuf},
- lockRankMspanSpecial: {lockRankScavenge, 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},
- lockRankGcBitsArenas: {lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
+ lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings},
+ lockRankProf: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
+ lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
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},
lockRankNetpollInit: {lockRankTimers},
lockRankRwmutexW: {},
lockRankRwmutexR: {lockRankRwmutexW},
- lockRankMcentral: {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},
- lockRankSpanSetSpine: {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},
- 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},
- lockRankStackLarge: {lockRankAssistQueue, lockRankSched, lockRankItab, lockRankHchan, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankMcentral, lockRankSpanSetSpine, lockRankGscan},
+ lockRankMcentral: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
+ lockRankSpine: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, 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: {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: {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: {lockRankSysmon, lockRankAssistQueue, lockRankSched, lockRankItab, lockRankHchan, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankMcentral, lockRankSpanSetSpine, lockRankGscan},
lockRankDefer: {},
lockRankSudog: {lockRankNotifyList, lockRankHchan},
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},
- lockRankMheapSpecial: {lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
+ 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: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
lockRankGlobalAlloc: {lockRankProf, lockRankSpine, lockRankSpanSetSpine, lockRankMheap, lockRankMheapSpecial},
lockRankGFree: {lockRankSched},
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index 6f7dc6e..2c7bfd8 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -1283,9 +1283,10 @@
// Publish the span in various locations.
// This is safe to call without the lock held because the slots
- // related to this span will only every be read or modified by
- // this thread until pointers into the span are published or
- // pageInUse is updated.
+ // related to this span will only ever be read or modified by
+ // this thread until pointers into the span are published (and
+ // we execute a publication barrier at the end of this function
+ // before that happens) or pageInUse is updated.
h.setSpans(s.base(), npages, s)
if !manual {
@@ -1315,6 +1316,11 @@
traceHeapAlloc()
}
}
+
+ // Make sure the newly allocated span will be observed
+ // by the GC before pointers into the span are published.
+ publicationBarrier()
+
return s
}
diff --git a/src/runtime/mranges.go b/src/runtime/mranges.go
index c2b8e71..e23d077 100644
--- a/src/runtime/mranges.go
+++ b/src/runtime/mranges.go
@@ -69,6 +69,18 @@
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 (
// minOffAddr is the minimum address in the offset space, and
// it corresponds to the virtual address arenaBaseOffset.
@@ -281,7 +293,7 @@
}
if r := a.ranges[pivot-1]; r.contains(addr) {
removed += r.size()
- r = r.subtract(makeAddrRange(addr, maxOffAddr.addr()))
+ r = r.removeGreaterEqual(addr)
if r.size() == 0 {
pivot--
} else {
diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go
index b534cdb..2bea105 100644
--- a/src/runtime/os_plan9.go
+++ b/src/runtime/os_plan9.go
@@ -293,7 +293,6 @@
ncpu = getproccount()
physPageSize = getPageSize()
getg().m.procid = getpid()
- notify(unsafe.Pointer(funcPC(sigtramp)))
}
//go:nosplit
@@ -311,6 +310,9 @@
}
func initsig(preinit bool) {
+ if !preinit {
+ notify(unsafe.Pointer(funcPC(sigtramp)))
+ }
}
//go:nosplit
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index ca99870..b423026 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -533,6 +533,7 @@
// The new G calls runtime·main.
func schedinit() {
lockInit(&sched.lock, lockRankSched)
+ lockInit(&sched.sysmonlock, lockRankSysmon)
lockInit(&sched.deferlock, lockRankDefer)
lockInit(&sched.sudoglock, lockRankSudog)
lockInit(&deadlock, lockRankDeadlock)
@@ -4613,6 +4614,18 @@
}
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
if *cgo_yield != nil {
asmcgocall(*cgo_yield, nil)
@@ -4665,6 +4678,7 @@
lasttrace = now
schedtrace(debug.scheddetail > 0)
}
+ unlock(&sched.sysmonlock)
}
}
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go
index 2dfa473..bb625aa 100644
--- a/src/runtime/runtime-gdb_test.go
+++ b/src/runtime/runtime-gdb_test.go
@@ -108,7 +108,6 @@
import "runtime"
var gslice []string
func main() {
- go func() { select{} }() // ensure a second goroutine is running
mapvar := make(map[string]string, 13)
mapvar["abc"] = "def"
mapvar["ghi"] = "jkl"
@@ -231,9 +230,6 @@
"-ex", "echo BEGIN goroutine 1 bt\n",
"-ex", "goroutine 1 bt",
"-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", "goroutine all bt",
"-ex", "echo END\n",
@@ -310,7 +306,6 @@
// Check that the backtraces are well formed.
checkCleanBacktrace(t, blocks["goroutine 1 bt"])
- checkCleanBacktrace(t, blocks["goroutine 2 bt"])
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`)
@@ -318,12 +313,7 @@
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 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) {
+ if bl := blocks["goroutine all bt"]; !btGoroutine1Re.MatchString(bl) {
t.Fatalf("goroutine all bt failed: %s", bl)
}
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index 1fe41cf..cffdb0b 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -349,9 +349,9 @@
g *g
- next *sudog
- prev *sudog
- elem unsafe.Pointer // data element (may point to stack)
+ next *sudog
+ prev *sudog
+ elem unsafe.Pointer // data element (may point to stack)
// The following fields are never accessed concurrently.
// For channels, waitlink is only accessed by g.
@@ -366,10 +366,10 @@
// g.selectDone must be CAS'd to win the wake-up race.
isSelect bool
- parent *sudog // semaRoot binary tree
- waitlink *sudog // g.waiting list or semaRoot
- waittail *sudog // semaRoot
- c *hchan // channel
+ parent *sudog // semaRoot binary tree
+ waitlink *sudog // g.waiting list or semaRoot
+ waittail *sudog // semaRoot
+ c *hchan // channel
}
type libcall struct {
@@ -768,6 +768,12 @@
procresizetime int64 // nanotime() of last change to gomaxprocs
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.
diff --git a/src/runtime/testdata/testprogcgo/eintr.go b/src/runtime/testdata/testprogcgo/eintr.go
index 58f0dd2..9d9435d 100644
--- a/src/runtime/testdata/testprogcgo/eintr.go
+++ b/src/runtime/testdata/testprogcgo/eintr.go
@@ -32,11 +32,11 @@
"errors"
"fmt"
"io"
+ "io/ioutil"
"log"
"net"
"os"
"os/exec"
- "os/signal"
"sync"
"syscall"
"time"
@@ -71,14 +71,15 @@
// spin does CPU bound spinning and allocating for a millisecond,
// to get a SIGURG.
//go:noinline
-func spin() (float64, [][]byte) {
+func spin() (float64, []byte) {
stop := time.Now().Add(time.Millisecond)
r1 := 0.0
- var r2 [][]byte
+ r2 := make([]byte, 200)
for time.Now().Before(stop) {
for i := 1; i < 1e6; 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
@@ -96,8 +97,13 @@
// sendSomeSignals triggers a few SIGURG and SIGWINCH signals.
func sendSomeSignals() {
- spin()
+ done := make(chan struct{})
+ go func() {
+ spin()
+ close(done)
+ }()
winch()
+ <-done
}
// testPipe tests pipe operations.
@@ -212,6 +218,10 @@
go func() {
defer wg.Done()
cmd := exec.Command(os.Args[0], "Block")
+ stdin, err := cmd.StdinPipe()
+ if err != nil {
+ log.Fatal(err)
+ }
cmd.Stderr = new(bytes.Buffer)
cmd.Stdout = cmd.Stderr
if err := cmd.Start(); err != nil {
@@ -220,9 +230,7 @@
go func() {
sendSomeSignals()
- if err := cmd.Process.Signal(os.Interrupt); err != nil {
- panic(err)
- }
+ stdin.Close()
}()
if err := cmd.Wait(); err != nil {
@@ -231,10 +239,7 @@
}()
}
-// Block blocks until the process receives os.Interrupt.
+// Block blocks until stdin is closed.
func Block() {
- c := make(chan os.Signal, 1)
- signal.Notify(c, os.Interrupt)
- defer signal.Stop(c)
- <-c
+ io.Copy(ioutil.Discard, os.Stdin)
}
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
index 33062da..169b650 100644
--- a/src/runtime/trace.go
+++ b/src/runtime/trace.go
@@ -187,6 +187,9 @@
// paired with an end).
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.
// Exitsyscall could check trace.enabled long before and then suddenly wake up
// and decide to write to trace at a random point in time.
@@ -196,6 +199,7 @@
if trace.enabled || trace.shutdown {
unlock(&trace.bufLock)
+ unlock(&sched.sysmonlock)
startTheWorldGC()
return errorString("tracing is already enabled")
}
@@ -267,6 +271,8 @@
unlock(&trace.bufLock)
+ unlock(&sched.sysmonlock)
+
startTheWorldGC()
return nil
}
@@ -279,10 +285,14 @@
stopTheWorldGC("stop tracing")
// See the comment in StartTrace.
+ lock(&sched.sysmonlock)
+
+ // See the comment in StartTrace.
lock(&trace.bufLock)
if !trace.enabled {
unlock(&trace.bufLock)
+ unlock(&sched.sysmonlock)
startTheWorldGC()
return
}
@@ -320,6 +330,8 @@
trace.shutdown = true
unlock(&trace.bufLock)
+ unlock(&sched.sysmonlock)
+
startTheWorldGC()
// The world is started but we've set trace.shutdown, so new tracing can't start.
diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index 89c0a93..f62c00d 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -339,6 +339,26 @@
var attrs uint32 = FILE_ATTRIBUTE_NORMAL
if perm&S_IWRITE == 0 {
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)
return h, e
diff --git a/src/testing/testing.go b/src/testing/testing.go
index 216e46e..608bb39 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -372,6 +372,7 @@
tempDirOnce sync.Once
tempDir string
tempDirErr error
+ tempDirSeq int32
}
// Short reports whether the -test.short flag is set.
@@ -821,12 +822,13 @@
}
// 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
// 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 {
+ // Use a single parent directory for all the temporary directories
+ // created by a test, each numbered sequentially.
c.tempDirOnce.Do(func() {
c.Helper()
@@ -849,7 +851,12 @@
if c.tempDirErr != nil {
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.
diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go
index 1340dae..dbef706 100644
--- a/src/testing/testing_test.go
+++ b/src/testing/testing_test.go
@@ -7,6 +7,7 @@
import (
"io/ioutil"
"os"
+ "path/filepath"
"testing"
)
@@ -55,8 +56,11 @@
t.Fatal("expected dir")
}
dir2 := t.TempDir()
- if dir != dir2 {
- t.Fatal("directory changed between calls")
+ if dir == dir2 {
+ 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
fi, err := os.Stat(dir)