aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippo Valsorda <filippo@golang.org>2020-11-13 03:04:52 +0100
committerFilippo Valsorda <filippo@golang.org>2020-11-13 03:04:52 +0100
commit11087322f85d5ace6494fc194982d92f0a34df0f (patch)
tree1fc71e2b2e13647ad4a2a86f95794b47ca950e99
parented9dc25d693c02aeeb8ed084b28b6d7f9489dc5a (diff)
parentc53315d6cf1b4bfea6ff356b4a1524778c683bb9 (diff)
downloadgo-11087322f85d5ace6494fc194982d92f0a34df0f.tar.gz
go-11087322f85d5ace6494fc194982d92f0a34df0f.zip
[dev.boringcrypto.go1.15] all: merge go1.15.5 into dev.boringcrypto.go1.15
Change-Id: I075fd29b5d035cac905c7bc3145405bf622a981b
-rw-r--r--misc/cgo/errors/badsym_test.go216
-rw-r--r--src/cmd/cgo/out.go23
-rw-r--r--src/cmd/compile/internal/gc/ssa.go8
-rw-r--r--src/cmd/compile/internal/gc/subr.go6
-rw-r--r--src/cmd/compile/internal/gc/typecheck.go2
-rw-r--r--src/cmd/go/internal/modfetch/coderepo_test.go5
-rw-r--r--src/cmd/go/internal/work/exec.go60
-rw-r--r--src/cmd/go/internal/work/security.go8
-rw-r--r--src/cmd/go/internal/work/security_test.go5
-rw-r--r--src/cmd/internal/obj/dwarf.go46
-rw-r--r--src/cmd/link/internal/ld/dwarf.go16
-rw-r--r--src/cmd/link/internal/ld/dwarf_test.go119
-rw-r--r--src/cmd/link/internal/ld/testdata/issue39757/issue39757main.go15
-rw-r--r--src/compress/flate/deflate_test.go57
-rw-r--r--src/compress/flate/deflatefast.go11
-rw-r--r--src/go.mod2
-rw-r--r--src/go.sum4
-rw-r--r--src/math/big/nat.go2
-rw-r--r--src/net/http/h2_bundle.go11
-rw-r--r--src/net/http/request.go2
-rw-r--r--src/net/http/request_test.go21
-rw-r--r--src/reflect/deepequal.go12
-rw-r--r--src/reflect/value.go12
-rw-r--r--src/runtime/netpoll.go47
-rw-r--r--src/runtime/proc.go21
-rw-r--r--src/runtime/signal_unix.go22
-rw-r--r--src/syscall/exec_unix_test.go46
-rw-r--r--src/time/zoneinfo_read.go19
-rw-r--r--src/time/zoneinfo_test.go19
-rw-r--r--src/vendor/modules.txt2
-rw-r--r--test/fixedbugs/issue42032.go27
-rw-r--r--test/fixedbugs/issue42076.go21
32 files changed, 809 insertions, 78 deletions
diff --git a/misc/cgo/errors/badsym_test.go b/misc/cgo/errors/badsym_test.go
new file mode 100644
index 00000000000..b2701bf922e
--- /dev/null
+++ b/misc/cgo/errors/badsym_test.go
@@ -0,0 +1,216 @@
+// 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.
+
+package errorstest
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+ "unicode"
+)
+
+// A manually modified object file could pass unexpected characters
+// into the files generated by cgo.
+
+const magicInput = "abcdefghijklmnopqrstuvwxyz0123"
+const magicReplace = "\n//go:cgo_ldflag \"-badflag\"\n//"
+
+const cSymbol = "BadSymbol" + magicInput + "Name"
+const cDefSource = "int " + cSymbol + " = 1;"
+const cRefSource = "extern int " + cSymbol + "; int F() { return " + cSymbol + "; }"
+
+// goSource is the source code for the trivial Go file we use.
+// We will replace TMPDIR with the temporary directory name.
+const goSource = `
+package main
+
+// #cgo LDFLAGS: TMPDIR/cbad.o TMPDIR/cbad.so
+// extern int F();
+import "C"
+
+func main() {
+ println(C.F())
+}
+`
+
+func TestBadSymbol(t *testing.T) {
+ dir := t.TempDir()
+
+ mkdir := func(base string) string {
+ ret := filepath.Join(dir, base)
+ if err := os.Mkdir(ret, 0755); err != nil {
+ t.Fatal(err)
+ }
+ return ret
+ }
+
+ cdir := mkdir("c")
+ godir := mkdir("go")
+
+ makeFile := func(mdir, base, source string) string {
+ ret := filepath.Join(mdir, base)
+ if err := ioutil.WriteFile(ret, []byte(source), 0644); err != nil {
+ t.Fatal(err)
+ }
+ return ret
+ }
+
+ cDefFile := makeFile(cdir, "cdef.c", cDefSource)
+ cRefFile := makeFile(cdir, "cref.c", cRefSource)
+
+ ccCmd := cCompilerCmd(t)
+
+ cCompile := func(arg, base, src string) string {
+ out := filepath.Join(cdir, base)
+ run := append(ccCmd, arg, "-o", out, src)
+ output, err := exec.Command(run[0], run[1:]...).CombinedOutput()
+ if err != nil {
+ t.Log(run)
+ t.Logf("%s", output)
+ t.Fatal(err)
+ }
+ if err := os.Remove(src); err != nil {
+ t.Fatal(err)
+ }
+ return out
+ }
+
+ // Build a shared library that defines a symbol whose name
+ // contains magicInput.
+
+ cShared := cCompile("-shared", "c.so", cDefFile)
+
+ // Build an object file that refers to the symbol whose name
+ // contains magicInput.
+
+ cObj := cCompile("-c", "c.o", cRefFile)
+
+ // Rewrite the shared library and the object file, replacing
+ // magicInput with magicReplace. This will have the effect of
+ // introducing a symbol whose name looks like a cgo command.
+ // The cgo tool will use that name when it generates the
+ // _cgo_import.go file, thus smuggling a magic //go:cgo_ldflag
+ // pragma into a Go file. We used to not check the pragmas in
+ // _cgo_import.go.
+
+ rewrite := func(from, to string) {
+ obj, err := ioutil.ReadFile(from)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if bytes.Count(obj, []byte(magicInput)) == 0 {
+ t.Fatalf("%s: did not find magic string", from)
+ }
+
+ if len(magicInput) != len(magicReplace) {
+ t.Fatalf("internal test error: different magic lengths: %d != %d", len(magicInput), len(magicReplace))
+ }
+
+ obj = bytes.ReplaceAll(obj, []byte(magicInput), []byte(magicReplace))
+
+ if err := ioutil.WriteFile(to, obj, 0644); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ cBadShared := filepath.Join(godir, "cbad.so")
+ rewrite(cShared, cBadShared)
+
+ cBadObj := filepath.Join(godir, "cbad.o")
+ rewrite(cObj, cBadObj)
+
+ goSourceBadObject := strings.ReplaceAll(goSource, "TMPDIR", godir)
+ makeFile(godir, "go.go", goSourceBadObject)
+
+ makeFile(godir, "go.mod", "module badsym")
+
+ // Try to build our little package.
+ cmd := exec.Command("go", "build", "-ldflags=-v")
+ cmd.Dir = godir
+ output, err := cmd.CombinedOutput()
+
+ // The build should fail, but we want it to fail because we
+ // detected the error, not because we passed a bad flag to the
+ // C linker.
+
+ if err == nil {
+ t.Errorf("go build succeeded unexpectedly")
+ }
+
+ t.Logf("%s", output)
+
+ for _, line := range bytes.Split(output, []byte("\n")) {
+ if bytes.Contains(line, []byte("dynamic symbol")) && bytes.Contains(line, []byte("contains unsupported character")) {
+ // This is the error from cgo.
+ continue
+ }
+
+ // We passed -ldflags=-v to see the external linker invocation,
+ // which should not include -badflag.
+ if bytes.Contains(line, []byte("-badflag")) {
+ t.Error("output should not mention -badflag")
+ }
+
+ // Also check for compiler errors, just in case.
+ // GCC says "unrecognized command line option".
+ // clang says "unknown argument".
+ if bytes.Contains(line, []byte("unrecognized")) || bytes.Contains(output, []byte("unknown")) {
+ t.Error("problem should have been caught before invoking C linker")
+ }
+ }
+}
+
+func cCompilerCmd(t *testing.T) []string {
+ cc := []string{goEnv(t, "CC")}
+
+ out := goEnv(t, "GOGCCFLAGS")
+ quote := '\000'
+ start := 0
+ lastSpace := true
+ backslash := false
+ s := string(out)
+ for i, c := range s {
+ if quote == '\000' && unicode.IsSpace(c) {
+ if !lastSpace {
+ cc = append(cc, s[start:i])
+ lastSpace = true
+ }
+ } else {
+ if lastSpace {
+ start = i
+ lastSpace = false
+ }
+ if quote == '\000' && !backslash && (c == '"' || c == '\'') {
+ quote = c
+ backslash = false
+ } else if !backslash && quote == c {
+ quote = '\000'
+ } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
+ backslash = true
+ } else {
+ backslash = false
+ }
+ }
+ }
+ if !lastSpace {
+ cc = append(cc, s[start:])
+ }
+ return cc
+}
+
+func goEnv(t *testing.T, key string) string {
+ out, err := exec.Command("go", "env", key).CombinedOutput()
+ if err != nil {
+ t.Logf("go env %s\n", key)
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+ return strings.TrimSpace(string(out))
+}
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index cbdb4e0f5b2..dcd69edb44b 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -336,6 +336,8 @@ func dynimport(obj string) {
if s.Version != "" {
targ += "#" + s.Version
}
+ checkImportSymName(s.Name)
+ checkImportSymName(targ)
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
}
lib, _ := f.ImportedLibraries()
@@ -351,6 +353,7 @@ func dynimport(obj string) {
if len(s) > 0 && s[0] == '_' {
s = s[1:]
}
+ checkImportSymName(s)
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
}
lib, _ := f.ImportedLibraries()
@@ -365,6 +368,8 @@ func dynimport(obj string) {
for _, s := range sym {
ss := strings.Split(s, ":")
name := strings.Split(ss[0], "@")[0]
+ checkImportSymName(name)
+ checkImportSymName(ss[0])
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
}
return
@@ -382,6 +387,7 @@ func dynimport(obj string) {
// Go symbols.
continue
}
+ checkImportSymName(s.Name)
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, s.Name, s.Library)
}
lib, err := f.ImportedLibraries()
@@ -397,6 +403,23 @@ func dynimport(obj string) {
fatalf("cannot parse %s as ELF, Mach-O, PE or XCOFF", obj)
}
+// checkImportSymName checks a symbol name we are going to emit as part
+// of a //go:cgo_import_dynamic pragma. These names come from object
+// files, so they may be corrupt. We are going to emit them unquoted,
+// so while they don't need to be valid symbol names (and in some cases,
+// involving symbol versions, they won't be) they must contain only
+// graphic characters and must not contain Go comments.
+func checkImportSymName(s string) {
+ for _, c := range s {
+ if !unicode.IsGraphic(c) || unicode.IsSpace(c) {
+ fatalf("dynamic symbol %q contains unsupported character", s)
+ }
+ }
+ if strings.Index(s, "//") >= 0 || strings.Index(s, "/*") >= 0 {
+ fatalf("dynamic symbol %q contains Go comment")
+ }
+}
+
// Construct a gcc struct matching the gc argument frame.
// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
// These assumptions are checked by the gccProlog.
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 3e21450deb5..7da04547c22 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -4976,7 +4976,10 @@ func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip ski
case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
s.store(t, left, right)
case t.IsPtrShaped():
- // no scalar fields.
+ if t.IsPtr() && t.Elem().NotInHeap() {
+ s.store(t, left, right) // see issue 42032
+ }
+ // otherwise, no scalar fields.
case t.IsString():
if skip&skipLen != 0 {
return
@@ -5020,6 +5023,9 @@ func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip ski
func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) {
switch {
case t.IsPtrShaped():
+ if t.IsPtr() && t.Elem().NotInHeap() {
+ break // see issue 42032
+ }
s.store(t, left, right)
case t.IsString():
ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, right)
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index c82eefb63d2..9118405fb1a 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -1876,8 +1876,10 @@ func isdirectiface(t *types.Type) bool {
}
switch t.Etype {
- case TPTR,
- TCHAN,
+ case TPTR:
+ // Pointers to notinheap types must be stored indirectly. See issue 42076.
+ return !t.Elem().NotInHeap()
+ case TCHAN,
TMAP,
TFUNC,
TUNSAFEPTR:
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 98b52a506af..b187612b9b7 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -2502,7 +2502,7 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field {
n.Left = nod(OADDR, n.Left, nil)
n.Left.SetImplicit(true)
n.Left = typecheck(n.Left, ctxType|ctxExpr)
- } else if tt.IsPtr() && !rcvr.IsPtr() && types.Identical(tt.Elem(), rcvr) {
+ } else if tt.IsPtr() && (!rcvr.IsPtr() || rcvr.IsPtr() && rcvr.Elem().NotInHeap()) && types.Identical(tt.Elem(), rcvr) {
n.Left = nod(ODEREF, n.Left, nil)
n.Left.SetImplicit(true)
n.Left = typecheck(n.Left, ctxType|ctxExpr)
diff --git a/src/cmd/go/internal/modfetch/coderepo_test.go b/src/cmd/go/internal/modfetch/coderepo_test.go
index f69c193b86c..9a0cd7dba69 100644
--- a/src/cmd/go/internal/modfetch/coderepo_test.go
+++ b/src/cmd/go/internal/modfetch/coderepo_test.go
@@ -657,11 +657,6 @@ var codeRepoVersionsTests = []struct {
},
{
vcs: "git",
- path: "gopkg.in/russross/blackfriday.v2",
- versions: []string{"v2.0.0", "v2.0.1"},
- },
- {
- vcs: "git",
path: "gopkg.in/natefinch/lumberjack.v2",
versions: []string{"v2.0.0"},
},
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index 071c9d2db98..13d4c8cbb45 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -2711,6 +2711,66 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
noCompiler()
}
+ // Double check the //go:cgo_ldflag comments in the generated files.
+ // The compiler only permits such comments in files whose base name
+ // starts with "_cgo_". Make sure that the comments in those files
+ // are safe. This is a backstop against people somehow smuggling
+ // such a comment into a file generated by cgo.
+ if cfg.BuildToolchainName == "gc" && !cfg.BuildN {
+ var flags []string
+ for _, f := range outGo {
+ if !strings.HasPrefix(filepath.Base(f), "_cgo_") {
+ continue
+ }
+
+ src, err := ioutil.ReadFile(f)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ const cgoLdflag = "//go:cgo_ldflag"
+ idx := bytes.Index(src, []byte(cgoLdflag))
+ for idx >= 0 {
+ // We are looking at //go:cgo_ldflag.
+ // Find start of line.
+ start := bytes.LastIndex(src[:idx], []byte("\n"))
+ if start == -1 {
+ start = 0
+ }
+
+ // Find end of line.
+ end := bytes.Index(src[idx:], []byte("\n"))
+ if end == -1 {
+ end = len(src)
+ } else {
+ end += idx
+ }
+
+ // Check for first line comment in line.
+ // We don't worry about /* */ comments,
+ // which normally won't appear in files
+ // generated by cgo.
+ commentStart := bytes.Index(src[start:], []byte("//"))
+ commentStart += start
+ // If that line comment is //go:cgo_ldflag,
+ // it's a match.
+ if bytes.HasPrefix(src[commentStart:], []byte(cgoLdflag)) {
+ // Pull out the flag, and unquote it.
+ // This is what the compiler does.
+ flag := string(src[idx+len(cgoLdflag) : end])
+ flag = strings.TrimSpace(flag)
+ flag = strings.Trim(flag, `"`)
+ flags = append(flags, flag)
+ }
+ src = src[end:]
+ idx = bytes.Index(src, []byte(cgoLdflag))
+ }
+ }
+ if err := checkLinkerFlags("LDFLAGS", "go:cgo_ldflag", flags); err != nil {
+ return nil, nil, err
+ }
+ }
+
return outGo, outObj, nil
}
diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go
index 3ee68ac1b41..0d9628241fd 100644
--- a/src/cmd/go/internal/work/security.go
+++ b/src/cmd/go/internal/work/security.go
@@ -42,8 +42,8 @@ import (
var re = lazyregexp.New
var validCompilerFlags = []*lazyregexp.Regexp{
- re(`-D([A-Za-z_].*)`),
- re(`-U([A-Za-z_]*)`),
+ re(`-D([A-Za-z_][A-Za-z0-9_]*)(=[^@\-]*)?`),
+ re(`-U([A-Za-z_][A-Za-z0-9_]*)`),
re(`-F([^@\-].*)`),
re(`-I([^@\-].*)`),
re(`-O`),
@@ -51,8 +51,8 @@ var validCompilerFlags = []*lazyregexp.Regexp{
re(`-W`),
re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
re(`-Wa,-mbig-obj`),
- re(`-Wp,-D([A-Za-z_].*)`),
- re(`-Wp,-U([A-Za-z_]*)`),
+ re(`-Wp,-D([A-Za-z_][A-Za-z0-9_]*)(=[^@,\-]*)?`),
+ re(`-Wp,-U([A-Za-z_][A-Za-z0-9_]*)`),
re(`-ansi`),
re(`-f(no-)?asynchronous-unwind-tables`),
re(`-f(no-)?blocks`),
diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go
index 11e74f29c6a..aec9789185e 100644
--- a/src/cmd/go/internal/work/security_test.go
+++ b/src/cmd/go/internal/work/security_test.go
@@ -13,6 +13,7 @@ var goodCompilerFlags = [][]string{
{"-DFOO"},
{"-Dfoo=bar"},
{"-Ufoo"},
+ {"-Ufoo1"},
{"-F/Qt"},
{"-I/"},
{"-I/etc/passwd"},
@@ -24,6 +25,8 @@ var goodCompilerFlags = [][]string{
{"-Wall"},
{"-Wp,-Dfoo=bar"},
{"-Wp,-Ufoo"},
+ {"-Wp,-Dfoo1"},
+ {"-Wp,-Ufoo1"},
{"-fobjc-arc"},
{"-fno-objc-arc"},
{"-fomit-frame-pointer"},
@@ -78,6 +81,8 @@ var badCompilerFlags = [][]string{
{"-O@1"},
{"-Wa,-foo"},
{"-W@foo"},
+ {"-Wp,-DX,-D@X"},
+ {"-Wp,-UX,-U@X"},
{"-g@gdb"},
{"-g-gdb"},
{"-march=@dawn"},
diff --git a/src/cmd/internal/obj/dwarf.go b/src/cmd/internal/obj/dwarf.go
index 4118c6442c1..cd1d5b86878 100644
--- a/src/cmd/internal/obj/dwarf.go
+++ b/src/cmd/internal/obj/dwarf.go
@@ -44,14 +44,12 @@ func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) {
}
}
- // Set up the debug_lines state machine.
- // NB: This state machine is reset to this state when we've finished
- // generating the line table. See below.
- // TODO: Once delve can support multiple DW_LNS_end_statements, we don't have
- // to do this.
+ // Set up the debug_lines state machine to the default values
+ // we expect at the start of a new sequence.
stmt := true
line := int64(1)
pc := s.Func.Text.Pc
+ var lastpc int64 // last PC written to line table, not last PC in func
name := ""
prologue, wrotePrologue := false, false
// Walk the progs, generating the DWARF table.
@@ -86,30 +84,32 @@ func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) {
if line != int64(newLine) || wrote {
pcdelta := p.Pc - pc
+ lastpc = p.Pc
putpclcdelta(ctxt, dctxt, lines, uint64(pcdelta), int64(newLine)-line)
line, pc = int64(newLine), p.Pc
}
}
- // Because these symbols will be concatenated together by the linker, we need
- // to reset the state machine that controls the debug symbols. The fields in
- // the state machine that need to be reset are:
- // file = 1
- // line = 1
- // column = 0
- // stmt = set in header, we assume true
- // basic_block = false
- // Careful readers of the DWARF specification will note that we don't reset
- // the address of the state machine -- but this will happen at the beginning
- // of the NEXT block of opcodes.
- dctxt.AddUint8(lines, dwarf.DW_LNS_set_file)
+ // Because these symbols will be concatenated together by the
+ // linker, we need to reset the state machine that controls the
+ // debug symbols. Do this using an end-of-sequence operator.
+ //
+ // Note: at one point in time, Delve did not support multiple end
+ // sequence ops within a compilation unit (bug for this:
+ // https://github.com/go-delve/delve/issues/1694), however the bug
+ // has since been fixed (Oct 2019).
+ //
+ // Issue 38192: the DWARF standard specifies that when you issue
+ // an end-sequence op, the PC value should be one past the last
+ // text address in the translation unit, so apply a delta to the
+ // text address before the end sequence op. If this isn't done,
+ // GDB will assign a line number of zero the last row in the line
+ // table, which we don't want.
+ lastlen := uint64(s.Size - (lastpc - s.Func.Text.Pc))
+ putpclcdelta(ctxt, dctxt, lines, lastlen, 0)
+ dctxt.AddUint8(lines, 0) // start extended opcode
dwarf.Uleb128put(dctxt, lines, 1)
- dctxt.AddUint8(lines, dwarf.DW_LNS_advance_line)
- dwarf.Sleb128put(dctxt, lines, int64(1-line))
- if !stmt {
- dctxt.AddUint8(lines, dwarf.DW_LNS_negate_stmt)
- }
- dctxt.AddUint8(lines, dwarf.DW_LNS_copy)
+ dctxt.AddUint8(lines, dwarf.DW_LNE_end_sequence)
}
func putpclcdelta(linkctxt *Link, dctxt dwCtxt, s *LSym, deltaPC uint64, deltaLC int64) {
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index 8df03d74f1d..6d330061ab2 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -1264,22 +1264,6 @@ func (d *dwctxt2) writelines(unit *sym.CompilationUnit, ls loader.Sym) {
}
}
- // Issue 38192: the DWARF standard specifies that when you issue
- // an end-sequence op, the PC value should be one past the last
- // text address in the translation unit, so apply a delta to the
- // text address before the end sequence op. If this isn't done,
- // GDB will assign a line number of zero the last row in the line
- // table, which we don't want. The 1 + ptrsize amount is somewhat
- // arbitrary, this is chosen to be consistent with the way LLVM
- // emits its end sequence ops.
- lsu.AddUint8(dwarf.DW_LNS_advance_pc)
- dwarf.Uleb128put(d, lsDwsym, int64(1+d.arch.PtrSize))
-
- // Emit an end-sequence at the end of the unit.
- lsu.AddUint8(0) // start extended opcode
- dwarf.Uleb128put(d, lsDwsym, 1)
- lsu.AddUint8(dwarf.DW_LNE_end_sequence)
-
if d.linkctxt.HeadType == objabi.Haix {
saveDwsectCUSize(".debug_line", unit.Lib.Pkg, uint64(lsu.Size()-unitLengthOffset))
}
diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go
index fb9c45b07d0..f3dd53792a9 100644
--- a/src/cmd/link/internal/ld/dwarf_test.go
+++ b/src/cmd/link/internal/ld/dwarf_test.go
@@ -1479,3 +1479,122 @@ func TestIssue38192(t *testing.T) {
t.Logf("row %d: A=%x F=%s L=%d\n", i, r.Address, r.File.Name, r.Line)
}
}
+
+func TestIssue39757(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping on plan9; no DWARF symbol table in executables")
+ }
+
+ // In this bug the DWARF line table contents for the last couple of
+ // instructions in a function were incorrect (bad file/line). This
+ // test verifies that all of the line table rows for a function
+ // of interest have the same file (no "autogenerated").
+ //
+ // Note: the function in this test was written with an eye towards
+ // ensuring that there are no inlined routines from other packages
+ // (which could introduce other source files into the DWARF); it's
+ // possible that at some point things could evolve in the
+ // compiler/runtime in ways that aren't happening now, so this
+ // might be something to check for if it does start failing.
+
+ tmpdir, err := ioutil.TempDir("", "TestIssue38192")
+ if err != nil {
+ t.Fatalf("could not create directory: %v", err)
+ }
+ defer os.RemoveAll(tmpdir)
+ wd, err := os.Getwd()
+ if err != nil {
+ t.Fatalf("where am I? %v", err)
+ }
+ pdir := filepath.Join(wd, "testdata", "issue39757")
+ f := gobuildTestdata(t, tmpdir, pdir, DefaultOpt)
+
+ syms, err := f.Symbols()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var addr uint64
+ for _, sym := range syms {
+ if sym.Name == "main.main" {
+ addr = sym.Addr
+ break
+ }
+ }
+ if addr == 0 {
+ t.Fatal("cannot find main.main in symbols")
+ }
+
+ // Open the resulting binary and examine the DWARF it contains.
+ // Look for the function of interest ("main.main")
+ // and verify that all line table entries show the same source
+ // file.
+ dw, err := f.DWARF()
+ if err != nil {
+ t.Fatalf("error parsing DWARF: %v", err)
+ }
+ rdr := dw.Reader()
+ ex := examiner{}
+ if err := ex.populate(rdr); err != nil {
+ t.Fatalf("error reading DWARF: %v", err)
+ }
+
+ // Locate the main.main DIE
+ mains := ex.Named("main.main")
+ if len(mains) == 0 {
+ t.Fatalf("unable to locate DIE for main.main")
+ }
+ if len(mains) != 1 {
+ t.Fatalf("more than one main.main DIE")
+ }
+ maindie := mains[0]
+
+ // Collect the start/end PC for main.main
+ lowpc := maindie.Val(dwarf.AttrLowpc).(uint64)
+ highpc := maindie.Val(dwarf.AttrHighpc).(uint64)
+
+ // Now read the line table for the 'main' compilation unit.
+ mainIdx := ex.idxFromOffset(maindie.Offset)
+ cuentry := ex.Parent(mainIdx)
+ if cuentry == nil {
+ t.Fatalf("main.main DIE appears orphaned")
+ }
+ lnrdr, lerr := dw.LineReader(cuentry)
+ if lerr != nil {
+ t.Fatalf("error creating DWARF line reader: %v", err)
+ }
+ if lnrdr == nil {
+ t.Fatalf("no line table for main.main compilation unit")
+ }
+ rows := []dwarf.LineEntry{}
+ mainrows := 0
+ var lne dwarf.LineEntry
+ for {
+ err := lnrdr.Next(&lne)
+ if err == io.EOF {
+ break
+ }
+ rows = append(rows, lne)
+ if err != nil {
+ t.Fatalf("error reading next DWARF line: %v", err)
+ }
+ if lne.Address < lowpc || lne.Address > highpc {
+ continue
+ }
+ if !strings.HasSuffix(lne.File.Name, "issue39757main.go") {
+ t.Errorf("found row with file=%s (not issue39757main.go)", lne.File.Name)
+ }
+ mainrows++
+ }
+ f.Close()
+
+ // Make sure we saw a few rows.
+ if mainrows < 3 {
+ t.Errorf("not enough line table rows for main.main (got %d, wanted > 3", mainrows)
+ for i, r := range rows {
+ t.Logf("row %d: A=%x F=%s L=%d\n", i, r.Address, r.File.Name, r.Line)
+ }
+ }
+}
diff --git a/src/cmd/link/internal/ld/testdata/issue39757/issue39757main.go b/src/cmd/link/internal/ld/testdata/issue39757/issue39757main.go
new file mode 100644
index 00000000000..76e0ea1b08c
--- /dev/null
+++ b/src/cmd/link/internal/ld/testdata/issue39757/issue39757main.go
@@ -0,0 +1,15 @@
+// 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.
+
+package main
+
+var G int
+
+func main() {
+ if G != 101 {
+ println("not 101")
+ } else {
+ println("well now that's interesting")
+ }
+}
diff --git a/src/compress/flate/deflate_test.go b/src/compress/flate/deflate_test.go
index 49a0345fd1d..b19cbec5a9a 100644
--- a/src/compress/flate/deflate_test.go
+++ b/src/compress/flate/deflate_test.go
@@ -11,6 +11,7 @@ import (
"internal/testenv"
"io"
"io/ioutil"
+ "math/rand"
"reflect"
"runtime/debug"
"sync"
@@ -896,6 +897,62 @@ func TestBestSpeedMaxMatchOffset(t *testing.T) {
}
}
+func TestBestSpeedShiftOffsets(t *testing.T) {
+ // Test if shiftoffsets properly preserves matches and resets out-of-range matches
+ // seen in https://github.com/golang/go/issues/4142
+ enc := newDeflateFast()
+
+ // testData may not generate internal matches.
+ testData := make([]byte, 32)
+ rng := rand.New(rand.NewSource(0))
+ for i := range testData {
+ testData[i] = byte(rng.Uint32())
+ }
+
+ // Encode the testdata with clean state.
+ // Second part should pick up matches from the first block.
+ wantFirstTokens := len(enc.encode(nil, testData))
+ wantSecondTokens := len(enc.encode(nil, testData))
+
+ if wantFirstTokens <= wantSecondTokens {
+ t.Fatalf("test needs matches between inputs to be generated")
+ }
+ // Forward the current indicator to before wraparound.
+ enc.cur = bufferReset - int32(len(testData))
+
+ // Part 1 before wrap, should match clean state.
+ got := len(enc.encode(nil, testData))
+ if wantFirstTokens != got {
+ t.Errorf("got %d, want %d tokens", got, wantFirstTokens)
+ }
+
+ // Verify we are about to wrap.
+ if enc.cur != bufferReset {
+ t.Errorf("got %d, want e.cur to be at bufferReset (%d)", enc.cur, bufferReset)
+ }
+
+ // Part 2 should match clean state as well even if wrapped.
+ got = len(enc.encode(nil, testData))
+ if wantSecondTokens != got {
+ t.Errorf("got %d, want %d token", got, wantSecondTokens)
+ }
+
+ // Verify that we wrapped.
+ if enc.cur >= bufferReset {
+ t.Errorf("want e.cur to be < bufferReset (%d), got %d", bufferReset, enc.cur)
+ }
+
+ // Forward the current buffer, leaving the matches at the bottom.
+ enc.cur = bufferReset
+ enc.shiftOffsets()
+
+ // Ensure that no matches were picked up.
+ got = len(enc.encode(nil, testData))
+ if wantFirstTokens != got {
+ t.Errorf("got %d, want %d tokens", got, wantFirstTokens)
+ }
+}
+
func TestMaxStackSize(t *testing.T) {
// This test must not run in parallel with other tests as debug.SetMaxStack
// affects all goroutines.
diff --git a/src/compress/flate/deflatefast.go b/src/compress/flate/deflatefast.go
index 24f8be9d5db..6aa439f13d9 100644
--- a/src/compress/flate/deflatefast.go
+++ b/src/compress/flate/deflatefast.go
@@ -270,6 +270,7 @@ func (e *deflateFast) matchLen(s, t int32, src []byte) int32 {
func (e *deflateFast) reset() {
e.prev = e.prev[:0]
// Bump the offset, so all matches will fail distance check.
+ // Nothing should be >= e.cur in the table.
e.cur += maxMatchOffset
// Protect against e.cur wraparound.
@@ -288,17 +289,21 @@ func (e *deflateFast) shiftOffsets() {
for i := range e.table[:] {
e.table[i] = tableEntry{}
}
- e.cur = maxMatchOffset
+ e.cur = maxMatchOffset + 1
return
}
// Shift down everything in the table that isn't already too far away.
for i := range e.table[:] {
- v := e.table[i].offset - e.cur + maxMatchOffset
+ v := e.table[i].offset - e.cur + maxMatchOffset + 1
if v < 0 {
+ // We want to reset e.cur to maxMatchOffset + 1, so we need to shift
+ // all table entries down by (e.cur - (maxMatchOffset + 1)).
+ // Because we ignore matches > maxMatchOffset, we can cap
+ // any negative offsets at 0.
v = 0
}
e.table[i].offset = v
}
- e.cur = maxMatchOffset
+ e.cur = maxMatchOffset + 1
}
diff --git a/src/go.mod b/src/go.mod
index b002f8e5165..6b97366bbe6 100644
--- a/src/go.mod
+++ b/src/go.mod
@@ -4,7 +4,7 @@ go 1.15
require (
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
- golang.org/x/net v0.0.0-20200707034311-ab3426394381
+ golang.org/x/net v0.0.0-20201008223702-a5fa9d4b7c91
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
golang.org/x/text v0.3.3-0.20200430171850-afb9336c4530 // indirect
)
diff --git a/src/go.sum b/src/go.sum
index 528f7e460e5..fbd3279aade 100644
--- a/src/go.sum
+++ b/src/go.sum
@@ -2,8 +2,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201008223702-a5fa9d4b7c91 h1:zd7kl5i5PDM0OnFbRWVM6B8mXojzv8LOkHN9LsOrRf4=
+golang.org/x/net v0.0.0-20201008223702-a5fa9d4b7c91/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/src/math/big/nat.go b/src/math/big/nat.go
index 6a3989bf9d8..8c43de69d33 100644
--- a/src/math/big/nat.go
+++ b/src/math/big/nat.go
@@ -928,7 +928,7 @@ func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) {
// Now u < (v<<B), compute lower bits in the same way.
// Choose shift = B-1 again.
- s := B
+ s := B - 1
qhat := *temps[depth]
qhat.clear()
qhat.divRecursiveStep(u[s:].norm(), v[s:], depth+1, tmp, temps)
diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
index 81c3671f853..b03b84d2f30 100644
--- a/src/net/http/h2_bundle.go
+++ b/src/net/http/h2_bundle.go
@@ -5265,6 +5265,7 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
if len(data) > 0 {
wrote, err := st.body.Write(data)
if err != nil {
+ sc.sendWindowUpdate(nil, int(f.Length)-wrote)
return http2streamError(id, http2ErrCodeStreamClosed)
}
if wrote != len(data) {
@@ -7167,6 +7168,7 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client
cc.inflow.add(http2transportDefaultConnFlow + http2initialWindowSize)
cc.bw.Flush()
if cc.werr != nil {
+ cc.Close()
return nil, cc.werr
}
@@ -7532,6 +7534,15 @@ func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterRe
bodyWriter := cc.t.getBodyWriterState(cs, body)
cs.on100 = bodyWriter.on100
+ defer func() {
+ cc.wmu.Lock()
+ werr := cc.werr
+ cc.wmu.Unlock()
+ if werr != nil {
+ cc.Close()
+ }
+ }()
+
cc.wmu.Lock()
endStream := !hasBody && !hasTrailers
werr := cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs)
diff --git a/src/net/http/request.go b/src/net/http/request.go
index fe6b60982cd..54ec1c5593c 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -382,7 +382,7 @@ func (r *Request) Clone(ctx context.Context) *Request {
if s := r.TransferEncoding; s != nil {
s2 := make([]string, len(s))
copy(s2, s)
- r2.TransferEncoding = s
+ r2.TransferEncoding = s2
}
r2.Form = cloneURLValues(r.Form)
r2.PostForm = cloneURLValues(r.PostForm)
diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go
index 42c16d00ea8..461d66e05d7 100644
--- a/src/net/http/request_test.go
+++ b/src/net/http/request_test.go
@@ -828,6 +828,27 @@ func TestWithContextDeepCopiesURL(t *testing.T) {
}
}
+// Ensure that Request.Clone creates a deep copy of TransferEncoding.
+// See issue 41907.
+func TestRequestCloneTransferEncoding(t *testing.T) {
+ body := strings.NewReader("body")
+ req, _ := NewRequest("POST", "https://example.org/", body)
+ req.TransferEncoding = []string{
+ "encoding1",
+ }
+
+ clonedReq := req.Clone(context.Background())
+ // modify original after deep copy
+ req.TransferEncoding[0] = "encoding2"
+
+ if req.TransferEncoding[0] != "encoding2" {
+ t.Error("expected req.TransferEncoding to be changed")
+ }
+ if clonedReq.TransferEncoding[0] != "encoding1" {
+ t.Error("expected clonedReq.TransferEncoding to be unchanged")
+ }
+}
+
func TestNoPanicOnRoundTripWithBasicAuth_h1(t *testing.T) {
testNoPanicWithBasicAuth(t, h1Mode)
}
diff --git a/src/reflect/deepequal.go b/src/reflect/deepequal.go
index 8a2bf8b09e2..b99c345e7bf 100644
--- a/src/reflect/deepequal.go
+++ b/src/reflect/deepequal.go
@@ -37,7 +37,17 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
// and it's safe and valid to get Value's internal pointer.
hard := func(v1, v2 Value) bool {
switch v1.Kind() {
- case Map, Slice, Ptr, Interface:
+ case Ptr:
+ if v1.typ.ptrdata == 0 {
+ // go:notinheap pointers can't be cyclic.
+ // At least, all of our current uses of go:notinheap have
+ // that property. The runtime ones aren't cyclic (and we don't use
+ // DeepEqual on them anyway), and the cgo-generated ones are
+ // all empty structs.
+ return false
+ }
+ fallthrough
+ case Map, Slice, Interface:
// Nil pointers cannot be cyclic. Avoid putting them in the visited map.
return !v1.IsNil() && !v2.IsNil()
}
diff --git a/src/reflect/value.go b/src/reflect/value.go
index c6f24a56095..1bd11c8707b 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -90,6 +90,7 @@ func (f flag) ro() flag {
// pointer returns the underlying pointer represented by v.
// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer
+// if v.Kind() == Ptr, the base type must not be go:notinheap.
func (v Value) pointer() unsafe.Pointer {
if v.typ.size != ptrSize || !v.typ.pointers() {
panic("can't call pointer on a non-pointer Value")
@@ -1452,7 +1453,16 @@ func (v Value) Pointer() uintptr {
// TODO: deprecate
k := v.kind()
switch k {
- case Chan, Map, Ptr, UnsafePointer:
+ case Ptr:
+ if v.typ.ptrdata == 0 {
+ // Handle pointers to go:notinheap types directly,
+ // so we never materialize such pointers as an
+ // unsafe.Pointer. (Such pointers are always indirect.)
+ // See issue 42076.
+ return *(*uintptr)(v.ptr)
+ }
+ fallthrough
+ case Chan, Map, UnsafePointer:
return uintptr(v.pointer())
case Func:
if v.flag&flagMethod != 0 {
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index 34ea82a7fae..77eb3aa4c63 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -79,16 +79,17 @@ type pollDesc struct {
lock mutex // protects the following fields
fd uintptr
closing bool
- everr bool // marks event scanning error happened
- user uint32 // user settable cookie
- rseq uintptr // protects from stale read timers
- rg uintptr // pdReady, pdWait, G waiting for read or nil
- rt timer // read deadline timer (set if rt.f != nil)
- rd int64 // read deadline
- wseq uintptr // protects from stale write timers
- wg uintptr // pdReady, pdWait, G waiting for write or nil
- wt timer // write deadline timer
- wd int64 // write deadline
+ everr bool // marks event scanning error happened
+ user uint32 // user settable cookie
+ rseq uintptr // protects from stale read timers
+ rg uintptr // pdReady, pdWait, G waiting for read or nil
+ rt timer // read deadline timer (set if rt.f != nil)
+ rd int64 // read deadline
+ wseq uintptr // protects from stale write timers
+ wg uintptr // pdReady, pdWait, G waiting for write or nil
+ wt timer // write deadline timer
+ wd int64 // write deadline
+ self *pollDesc // storage for indirect interface. See (*pollDesc).makeArg.
}
type pollCache struct {
@@ -157,6 +158,7 @@ func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
pd.wseq++
pd.wg = 0
pd.wd = 0
+ pd.self = pd
unlock(&pd.lock)
var errno int32
@@ -271,14 +273,14 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
// Copy current seq into the timer arg.
// Timer func will check the seq against current descriptor seq,
// if they differ the descriptor was reused or timers were reset.
- pd.rt.arg = pd
+ pd.rt.arg = pd.makeArg()
pd.rt.seq = pd.rseq
resettimer(&pd.rt, pd.rd)
}
} else if pd.rd != rd0 || combo != combo0 {
pd.rseq++ // invalidate current timers
if pd.rd > 0 {
- modtimer(&pd.rt, pd.rd, 0, rtf, pd, pd.rseq)
+ modtimer(&pd.rt, pd.rd, 0, rtf, pd.makeArg(), pd.rseq)
} else {
deltimer(&pd.rt)
pd.rt.f = nil
@@ -287,14 +289,14 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
if pd.wt.f == nil {
if pd.wd > 0 && !combo {
pd.wt.f = netpollWriteDeadline
- pd.wt.arg = pd
+ pd.wt.arg = pd.makeArg()
pd.wt.seq = pd.wseq
resettimer(&pd.wt, pd.wd)
}
} else if pd.wd != wd0 || combo != combo0 {
pd.wseq++ // invalidate current timers
if pd.wd > 0 && !combo {
- modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd, pd.wseq)
+ modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd.makeArg(), pd.wseq)
} else {
deltimer(&pd.wt)
pd.wt.f = nil
@@ -547,3 +549,20 @@ func (c *pollCache) alloc() *pollDesc {
unlock(&c.lock)
return pd
}
+
+// makeArg converts pd to an interface{}.
+// makeArg does not do any allocation. Normally, such
+// a conversion requires an allocation because pointers to
+// go:notinheap types (which pollDesc is) must be stored
+// in interfaces indirectly. See issue 42076.
+func (pd *pollDesc) makeArg() (i interface{}) {
+ x := (*eface)(unsafe.Pointer(&i))
+ x._type = pdType
+ x.data = unsafe.Pointer(&pd.self)
+ return
+}
+
+var (
+ pdEface interface{} = (*pollDesc)(nil)
+ pdType *_type = efaceOf(&pdEface)._type
+)
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 035822216d2..2f1272d310b 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -1281,6 +1281,14 @@ found:
checkdead()
unlock(&sched.lock)
+ if GOOS == "darwin" {
+ // Make sure pendingPreemptSignals is correct when an M exits.
+ // For #41702.
+ if atomic.Load(&m.signalPending) != 0 {
+ atomic.Xadd(&pendingPreemptSignals, -1)
+ }
+ }
+
if osStack {
// Return from mstart and let the system thread
// library free the g0 stack and terminate the thread.
@@ -3475,11 +3483,24 @@ func syscall_runtime_AfterForkInChild() {
inForkedChild = false
}
+// pendingPreemptSignals is the number of preemption signals
+// that have been sent but not received. This is only used on Darwin.
+// For #41702.
+var pendingPreemptSignals uint32
+
// Called from syscall package before Exec.
//go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec
func syscall_runtime_BeforeExec() {
// Prevent thread creation during exec.
execLock.lock()
+
+ // On Darwin, wait for all pending preemption signals to
+ // be received. See issue #41702.
+ if GOOS == "darwin" {
+ for int32(atomic.Load(&pendingPreemptSignals)) > 0 {
+ osyield()
+ }
+ }
}
// Called from syscall package after Exec.
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index dd6d79f8ecf..80fd2d66049 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -336,6 +336,10 @@ func doSigPreempt(gp *g, ctxt *sigctxt) {
// Acknowledge the preemption.
atomic.Xadd(&gp.m.preemptGen, 1)
atomic.Store(&gp.m.signalPending, 0)
+
+ if GOOS == "darwin" {
+ atomic.Xadd(&pendingPreemptSignals, -1)
+ }
}
const preemptMSupported = true
@@ -357,7 +361,18 @@ func preemptM(mp *m) {
// required).
return
}
+
+ // On Darwin, don't try to preempt threads during exec.
+ // Issue #41702.
+ if GOOS == "darwin" {
+ execLock.rlock()
+ }
+
if atomic.Cas(&mp.signalPending, 0, 1) {
+ if GOOS == "darwin" {
+ atomic.Xadd(&pendingPreemptSignals, 1)
+ }
+
// If multiple threads are preempting the same M, it may send many
// signals to the same M such that it hardly make progress, causing
// live-lock problem. Apparently this could happen on darwin. See
@@ -365,6 +380,10 @@ func preemptM(mp *m) {
// Only send a signal if there isn't already one pending.
signalM(mp, sigPreempt)
}
+
+ if GOOS == "darwin" {
+ execLock.runlock()
+ }
}
// sigFetchG fetches the value of G safely when running in a signal handler.
@@ -425,6 +444,9 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
// no non-Go signal handler for sigPreempt.
// The default behavior for sigPreempt is to ignore
// the signal, so badsignal will be a no-op anyway.
+ if GOOS == "darwin" {
+ atomic.Xadd(&pendingPreemptSignals, -1)
+ }
return
}
c.fixsigcode(sig)
diff --git a/src/syscall/exec_unix_test.go b/src/syscall/exec_unix_test.go
index 4eb3c5c6c8a..4431f7fc900 100644
--- a/src/syscall/exec_unix_test.go
+++ b/src/syscall/exec_unix_test.go
@@ -9,11 +9,14 @@ package syscall_test
import (
"internal/testenv"
"io"
+ "math/rand"
"os"
"os/exec"
"os/signal"
+ "runtime"
"syscall"
"testing"
+ "time"
"unsafe"
)
@@ -241,3 +244,46 @@ func TestInvalidExec(t *testing.T) {
}
})
}
+
+// TestExec is for issue #41702.
+func TestExec(t *testing.T) {
+ testenv.MustHaveExec(t)
+ cmd := exec.Command(os.Args[0], "-test.run=TestExecHelper")
+ cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=2")
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Errorf("%s\n%v", o, err)
+ }
+}
+
+// TestExecHelper is used by TestExec. It does nothing by itself.
+// In testing on macOS 10.14, this used to fail with
+// "signal: illegal instruction" more than half the time.
+func TestExecHelper(t *testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "2" {
+ return
+ }
+
+ // We don't have to worry about restoring these values.
+ // We are in a child process that only runs this test,
+ // and we are going to call syscall.Exec anyhow.
+ runtime.GOMAXPROCS(50)
+ os.Setenv("GO_WANT_HELPER_PROCESS", "3")
+
+ stop := time.Now().Add(time.Second)
+ for i := 0; i < 100; i++ {
+ go func(i int) {
+ r := rand.New(rand.NewSource(int64(i)))
+ for time.Now().Before(stop) {
+ r.Uint64()
+ }
+ }(i)
+ }
+
+ time.Sleep(10 * time.Millisecond)
+
+ argv := []string{os.Args[0], "-test.run=TestExecHelper"}
+ syscall.Exec(os.Args[0], argv, os.Environ())
+
+ t.Error("syscall.Exec returned")
+}
diff --git a/src/time/zoneinfo_read.go b/src/time/zoneinfo_read.go
index 6f789be92a7..22a60f32116 100644
--- a/src/time/zoneinfo_read.go
+++ b/src/time/zoneinfo_read.go
@@ -323,10 +323,27 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
l.cacheStart = tx[i].when
l.cacheEnd = omega
+ zoneIdx := tx[i].index
if i+1 < len(tx) {
l.cacheEnd = tx[i+1].when
+ } else if l.extend != "" {
+ // If we're at the end of the known zone transitions,
+ // try the extend string.
+ if name, _, estart, eend, ok := tzset(l.extend, l.cacheEnd, sec); ok {
+ l.cacheStart = estart
+ l.cacheEnd = eend
+ // Find the zone that is returned by tzset,
+ // the last transition is not always the correct zone.
+ for i, z := range l.zone {
+ if z.name == name {
+ zoneIdx = uint8(i)
+ break
+ }
+ }
+ }
}
- l.cacheZone = &l.zone[tx[i].index]
+ l.cacheZone = &l.zone[zoneIdx]
+ break
}
}
diff --git a/src/time/zoneinfo_test.go b/src/time/zoneinfo_test.go
index 72829bc9fb2..277b68f798d 100644
--- a/src/time/zoneinfo_test.go
+++ b/src/time/zoneinfo_test.go
@@ -183,6 +183,25 @@ func TestMalformedTZData(t *testing.T) {
}
}
+func TestLoadLocationFromTZDataSlim(t *testing.T) {
+ // A 2020b slim tzdata for Europe/Berlin
+ tzData := "TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\f\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9cٮ\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\tq\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xffͩ\x17\x90\xff\xff\xff\xff\u03a2C\x10\xff\xff\xff\xffϒ4\x10\xff\xff\xff\xffЂ%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xffѶ\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xffҡO\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xffըs\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\t\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13ܐ\x00\x00\x00\x00\x17\x03͐\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18㯐\x00\x00\x00\x00\x19Ӡ\x90\x00\x00\x00\x00\x1aÑ\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\\c\x10\x00\x00\x00\x00\"LT\x10\x00\x00\x00\x00#<E\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%\x1c'\x10\x00\x00\x00\x00&\f\x18\x10\x00\x00\x00\x00'\x05C\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00(\xe5%\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xc5\a\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xa4\xe9\x90\x00\x00\x00\x00-\x94ڐ\x00\x00\x00\x00.\x84ː\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000d\xad\x90\x00\x00\x00\x001]\xd9\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\f\x88\x00\x00\x00\x00\x1c \x01\x04\x00\x00\x0e\x10\x00\t\x00\x00*0\x01\rLMT\x00CEST\x00CET\x00CEMT\x00\nCET-1CEST,M3.5.0,M10.5.0/3\n"
+
+ reference, err := time.LoadLocationFromTZData("Europe/Berlin", []byte(tzData))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ d := time.Date(2020, time.October, 29, 15, 30, 0, 0, reference)
+ tzName, tzOffset := d.Zone()
+ if want := "CET"; tzName != want {
+ t.Errorf("Zone name == %s, want %s", tzName, want)
+ }
+ if want := 3600; tzOffset != want {
+ t.Errorf("Zone offset == %d, want %d", tzOffset, want)
+ }
+}
+
func TestTzset(t *testing.T) {
for _, test := range []struct {
inStr string
diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt
index e687d77b4d3..03ca3c3ae4c 100644
--- a/src/vendor/modules.txt
+++ b/src/vendor/modules.txt
@@ -8,7 +8,7 @@ golang.org/x/crypto/curve25519
golang.org/x/crypto/hkdf
golang.org/x/crypto/internal/subtle
golang.org/x/crypto/poly1305
-# golang.org/x/net v0.0.0-20200707034311-ab3426394381
+# golang.org/x/net v0.0.0-20201008223702-a5fa9d4b7c91
## explicit
golang.org/x/net/dns/dnsmessage
golang.org/x/net/http/httpguts
diff --git a/test/fixedbugs/issue42032.go b/test/fixedbugs/issue42032.go
new file mode 100644
index 00000000000..c456b1db02c
--- /dev/null
+++ b/test/fixedbugs/issue42032.go
@@ -0,0 +1,27 @@
+// run
+
+// 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.
+
+package main
+
+//go:notinheap
+type NIH struct {
+}
+
+type T struct {
+ x *NIH
+ p *int
+}
+
+var y NIH
+var z int
+
+func main() {
+ a := []T{{&y, &z}}
+ a = append(a, T{&y, &z})
+ if a[1].x == nil {
+ panic("pointer not written")
+ }
+}
diff --git a/test/fixedbugs/issue42076.go b/test/fixedbugs/issue42076.go
new file mode 100644
index 00000000000..3e954813c93
--- /dev/null
+++ b/test/fixedbugs/issue42076.go
@@ -0,0 +1,21 @@
+// run
+
+// 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.
+
+package main
+
+import "reflect"
+
+//go:notinheap
+type NIH struct {
+}
+
+var x, y NIH
+
+func main() {
+ if reflect.DeepEqual(&x, &y) != true {
+ panic("should report true")
+ }
+}