aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippo Valsorda <filippo@golang.org>2019-05-13 17:40:12 -0400
committerFilippo Valsorda <filippo@golang.org>2019-05-13 17:40:12 -0400
commitad495d31d9081dbe491972d276f790d76c47af62 (patch)
treedc07af576a65e2b551a4592b294063b32398a52f
parent88e20e81a61fe07f438f3a07534405ba47414ae0 (diff)
parent3a1b4e75f8b6c1b57db73bccf7ca871bf1a97ca9 (diff)
downloadgo-ad495d31d9081dbe491972d276f790d76c47af62.tar.gz
go-ad495d31d9081dbe491972d276f790d76c47af62.zip
[dev.boringcrypto.go1.12] all: merge go1.12.5 into dev.boringcrypto.go1.12
Change-Id: Ib678f7648515435e990b051579a6dda2e7e6a14e
-rw-r--r--doc/contribute.html3
-rw-r--r--doc/devel/release.html58
-rw-r--r--doc/go1.12.html2
-rw-r--r--src/cmd/compile/internal/gc/dwinl.go2
-rw-r--r--src/cmd/compile/internal/gc/obj.go2
-rw-r--r--src/cmd/compile/internal/gc/order.go6
-rw-r--r--src/cmd/compile/internal/gc/pgen.go18
-rw-r--r--src/cmd/compile/internal/ssa/writebarrier.go78
-rw-r--r--src/cmd/go/internal/get/vcs.go4
-rw-r--r--src/cmd/go/internal/imports/scan.go2
-rw-r--r--src/cmd/go/internal/load/pkg.go53
-rw-r--r--src/cmd/go/internal/load/test.go23
-rw-r--r--src/cmd/go/internal/test/test.go2
-rw-r--r--src/cmd/go/internal/work/build.go5
-rw-r--r--src/cmd/go/internal/work/exec.go1
-rw-r--r--src/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt6
-rw-r--r--src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt28
-rw-r--r--src/cmd/go/testdata/script/mod_build_versioned.txt16
-rw-r--r--src/cmd/go/testdata/script/mod_symlink.txt29
-rw-r--r--src/cmd/link/elf_test.go113
-rw-r--r--src/cmd/link/internal/loadelf/ldelf.go8
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go1
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go2
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go3
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go8
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go11
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go6
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go28
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go5
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go31
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go5
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go1
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go2
-rw-r--r--src/cmd/vet/testdata/src/print2/big.go17
-rw-r--r--src/cmd/vet/testdata/src/structtag/structtag.go14
-rw-r--r--src/cmd/vet/vet_test.go1
-rw-r--r--src/internal/poll/fd_windows.go6
-rw-r--r--src/net/http/httputil/reverseproxy.go5
-rw-r--r--src/net/http/httputil/reverseproxy_test.go42
-rw-r--r--src/net/lookup.go5
-rw-r--r--src/net/lookup_test.go89
-rw-r--r--src/os/export_unix_test.go9
-rw-r--r--src/os/os_unix_test.go25
-rw-r--r--src/os/path.go1
-rw-r--r--src/os/path_unix.go18
-rw-r--r--src/os/removeall_at.go38
-rw-r--r--src/os/removeall_test.go15
-rw-r--r--src/runtime/asm_wasm.s2
-rw-r--r--src/runtime/export_test.go113
-rw-r--r--src/runtime/mgclarge.go31
-rw-r--r--src/runtime/mheap.go10
-rw-r--r--src/runtime/os_windows.go64
-rw-r--r--src/runtime/runtime-lldb_test.go1
-rw-r--r--src/runtime/syscall_windows.go14
-rw-r--r--src/runtime/treap_test.go205
-rw-r--r--src/syscall/dll_windows.go28
-rw-r--r--src/syscall/security_windows.go1
-rw-r--r--src/syscall/zsyscall_windows.go14
-rw-r--r--test/fixedbugs/issue30956.go32
-rw-r--r--test/fixedbugs/issue30956.out1
-rw-r--r--test/fixedbugs/issue30977.go52
-rw-r--r--test/fixedbugs/issue31252.dir/a.go13
-rw-r--r--test/fixedbugs/issue31252.dir/b.go13
-rw-r--r--test/fixedbugs/issue31252.dir/c.go26
-rw-r--r--test/fixedbugs/issue31252.dir/main.go11
-rw-r--r--test/fixedbugs/issue31252.go7
66 files changed, 1263 insertions, 222 deletions
diff --git a/doc/contribute.html b/doc/contribute.html
index 68b2387d35..6f2287b410 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -46,7 +46,8 @@ CLA (Contributor License Agreement).
<li>
<b>Step 2</b>: Configure authentication credentials for the Go Git repository.
Visit <a href="https://go.googlesource.com/">go.googlesource.com</a>, click
-on "Generate Password" (top right), and follow the instructions.
+on the gear icon (top right), then on "Obtain password", and follow the
+instructions.
</li>
<li>
<b>Step 3</b>: Register for Gerrit, the code review tool used by the Go team,
diff --git a/doc/devel/release.html b/doc/devel/release.html
index 7a036db9a8..69eec330a8 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -30,6 +30,8 @@ Go 1.12 is a major release of Go.
Read the <a href="/doc/go1.12">Go 1.12 Release Notes</a> for more information.
</p>
+<h3 id="go1.12.minor">Minor revisions</h3>
+
<p>
go1.12.1 (released 2019/03/14) includes fixes to cgo, the compiler, the go
command, and the <code>fmt</code>, <code>net/smtp</code>, <code>os</code>,
@@ -38,6 +40,35 @@ packages. See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1
1.12.1 milestone</a> on our issue tracker for details.
</p>
+<p>
+go1.12.2 (released 2019/04/05) includes fixes to the compiler, the go
+command, the runtime, and the <code>doc</code>, <code>net</code>,
+<code>net/http/httputil</code>, and <code>os</code> packages. See the
+<a href="https://github.com/golang/go/issues?q=milestone%3AGo1.12.2">Go
+1.12.2 milestone</a> on our issue tracker for details.
+</p>
+
+<p>
+go1.12.3 (released 2019/04/08) was accidentally released without its
+intended fix. It is identical to go1.12.2, except for its version
+number. The intended fix is in go1.12.4.
+</p>
+
+<p>
+go1.12.4 (released 2019/04/11) fixes an issue where using the prebuilt binary
+releases on older versions of GNU/Linux
+<a href="https://golang.org/issues/31293">led to failures</a>
+when linking programs that used cgo.
+Only Linux users who hit this issue need to update.
+</p>
+
+<p>
+go1.12.5 (released 2019/05/06) includes fixes to the compiler, the linker,
+the go command, the runtime, and the <code>os</code> package. See the
+<a href="https://github.com/golang/go/issues?q=milestone%3AGo1.12.5">Go
+1.12.5 milestone</a> on our issue tracker for details.
+</p>
+
<h2 id="go1.11">go1.11 (released 2018/08/24)</h2>
<p>
@@ -96,6 +127,33 @@ runtime, go command, and the <code>crypto/x509</code>, <code>encoding/json</code
1.11.6 milestone</a> on our issue tracker for details.
</p>
+<p>
+go1.11.7 (released 2019/04/05) includes fixes to the runtime and the
+<code>net</code> packages. See the
+<a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.7">Go
+1.11.7 milestone</a> on our issue tracker for details.
+</p>
+
+<p>
+go1.11.8 (released 2019/04/08) was accidentally released without its
+intended fix. It is identical to go1.11.7, except for its version
+number. The intended fix is in go1.11.9.
+</p>
+
+<p>
+go1.11.9 (released 2019/04/11) fixes an issue where using the prebuilt binary
+releases on older versions of GNU/Linux
+<a href="https://golang.org/issues/31293">led to failures</a>
+when linking programs that used cgo.
+Only Linux users who hit this issue need to update.
+</p>
+
+<p>
+go1.11.10 (released 2019/05/06) includes fixes to the runtime and the linker.
+See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.10">Go
+1.11.10 milestone</a> on our issue tracker for details.
+</p>
+
<h2 id="go1.10">go1.10 (released 2018/02/16)</h2>
<p>
diff --git a/doc/go1.12.html b/doc/go1.12.html
index 2945eb1c43..cc19c0f31a 100644
--- a/doc/go1.12.html
+++ b/doc/go1.12.html
@@ -791,7 +791,7 @@ for {
A new <a href="/pkg/runtime/debug/#BuildInfo"><code>BuildInfo</code></a> type
exposes the build information read from the running binary, available only in
binaries built with module support. This includes the main package path, main
- module information, and the module dependencies. This type is given though the
+ module information, and the module dependencies. This type is given through the
<a href="/pkg/runtime/debug/#ReadBuildInfo"><code>ReadBuildInfo</code></a> function
on <a href="/pkg/runtime/debug/#BuildInfo"><code>BuildInfo</code></a>.
</p>
diff --git a/src/cmd/compile/internal/gc/dwinl.go b/src/cmd/compile/internal/gc/dwinl.go
index ade76f40f8..cc42a04c64 100644
--- a/src/cmd/compile/internal/gc/dwinl.go
+++ b/src/cmd/compile/internal/gc/dwinl.go
@@ -127,7 +127,7 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
DeclLine: v.DeclLine,
DeclCol: v.DeclCol,
}
- synthesized := strings.HasPrefix(v.Name, "~r") || canonName == "_"
+ synthesized := strings.HasPrefix(v.Name, "~r") || canonName == "_" || strings.HasPrefix(v.Name, "~b")
if idx, found := m[vp]; found {
v.ChildIndex = int32(idx)
v.IsInAbstract = !synthesized
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index 5630e12ace..86d52f5084 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -287,7 +287,7 @@ func addGCLocals() {
}
}
if x := s.Func.StackObjects; x != nil {
- ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.LOCAL)
+ ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
}
}
}
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index 0098242c79..c252e7ae20 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -1108,10 +1108,10 @@ func (o *Order) expr(n, lhs *Node) *Node {
if n.Left.Type.IsInterface() {
break
}
- if _, needsaddr := convFuncName(n.Left.Type, n.Type); needsaddr || consttype(n.Left) > 0 {
+ if _, needsaddr := convFuncName(n.Left.Type, n.Type); needsaddr || isStaticCompositeLiteral(n.Left) {
// Need a temp if we need to pass the address to the conversion function.
- // We also process constants here, making a named static global whose
- // address we can put directly in an interface (see OCONVIFACE case in walk).
+ // We also process static composite literal node here, making a named static global
+ // whose address we can put directly in an interface (see OCONVIFACE case in walk).
n.Left = o.addrTemp(n.Left)
}
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
index 1dc4b53427..5636ccd1db 100644
--- a/src/cmd/compile/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -267,7 +267,7 @@ func compile(fn *Node) {
// Also make sure we allocate a linker symbol
// for the stack object data, for the same reason.
if fn.Func.lsym.Func.StackObjects == nil {
- fn.Func.lsym.Func.StackObjects = lookup(fmt.Sprintf("%s.stkobj", fn.funcname())).Linksym()
+ fn.Func.lsym.Func.StackObjects = Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj")
}
}
}
@@ -597,8 +597,22 @@ func createDwarfVars(fnsym *obj.LSym, fn *Func, automDecls []*Node) ([]*Node, []
typename := dwarf.InfoPrefix + typesymname(n.Type)
decls = append(decls, n)
abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
+ isReturnValue := (n.Class() == PPARAMOUT)
if n.Class() == PPARAM || n.Class() == PPARAMOUT {
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
+ } else if n.Class() == PAUTOHEAP {
+ // If dcl in question has been promoted to heap, do a bit
+ // of extra work to recover original class (auto or param);
+ // see issue 30908. This insures that we get the proper
+ // signature in the abstract function DIE, but leaves a
+ // misleading location for the param (we want pointer-to-heap
+ // and not stack).
+ // TODO(thanm): generate a better location expression
+ stackcopy := n.Name.Param.Stackcopy
+ if stackcopy != nil && (stackcopy.Class() == PPARAM || stackcopy.Class() == PPARAMOUT) {
+ abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
+ isReturnValue = (stackcopy.Class() == PPARAMOUT)
+ }
}
inlIndex := 0
if genDwarfInline > 1 {
@@ -612,7 +626,7 @@ func createDwarfVars(fnsym *obj.LSym, fn *Func, automDecls []*Node) ([]*Node, []
declpos := Ctxt.InnermostPos(n.Pos)
vars = append(vars, &dwarf.Var{
Name: n.Sym.Name,
- IsReturnValue: n.Class() == PPARAMOUT,
+ IsReturnValue: isReturnValue,
Abbrev: abbrev,
StackOffset: int32(n.Xoffset),
Type: Ctxt.Lookup(typename),
diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go
index 1024ab25ab..8cb41b2935 100644
--- a/src/cmd/compile/internal/ssa/writebarrier.go
+++ b/src/cmd/compile/internal/ssa/writebarrier.go
@@ -196,6 +196,43 @@ func writebarrier(f *Func) {
// and simple store version to bElse
memThen := mem
memElse := mem
+
+ // If the source of a MoveWB is volatile (will be clobbered by a
+ // function call), we need to copy it to a temporary location, as
+ // marshaling the args of typedmemmove might clobber the value we're
+ // trying to move.
+ // Look for volatile source, copy it to temporary before we emit any
+ // call.
+ // It is unlikely to have more than one of them. Just do a linear
+ // search instead of using a map.
+ type volatileCopy struct {
+ src *Value // address of original volatile value
+ tmp *Value // address of temporary we've copied the volatile value into
+ }
+ var volatiles []volatileCopy
+ copyLoop:
+ for _, w := range stores {
+ if w.Op == OpMoveWB {
+ val := w.Args[1]
+ if isVolatile(val) {
+ for _, c := range volatiles {
+ if val == c.src {
+ continue copyLoop // already copied
+ }
+ }
+
+ t := val.Type.Elem()
+ tmp := f.fe.Auto(w.Pos, t)
+ memThen = bThen.NewValue1A(w.Pos, OpVarDef, types.TypeMem, tmp, memThen)
+ tmpaddr := bThen.NewValue2A(w.Pos, OpLocalAddr, t.PtrTo(), tmp, sp, memThen)
+ siz := t.Size()
+ memThen = bThen.NewValue3I(w.Pos, OpMove, types.TypeMem, siz, tmpaddr, val, memThen)
+ memThen.Aux = t
+ volatiles = append(volatiles, volatileCopy{val, tmpaddr})
+ }
+ }
+ }
+
for _, w := range stores {
ptr := w.Args[0]
pos := w.Pos
@@ -222,11 +259,19 @@ func writebarrier(f *Func) {
// then block: emit write barrier call
switch w.Op {
case OpStoreWB, OpMoveWB, OpZeroWB:
- volatile := w.Op == OpMoveWB && isVolatile(val)
if w.Op == OpStoreWB {
memThen = bThen.NewValue3A(pos, OpWB, types.TypeMem, gcWriteBarrier, ptr, val, memThen)
} else {
- memThen = wbcall(pos, bThen, fn, typ, ptr, val, memThen, sp, sb, volatile)
+ srcval := val
+ if w.Op == OpMoveWB && isVolatile(srcval) {
+ for _, c := range volatiles {
+ if srcval == c.src {
+ srcval = c.tmp
+ break
+ }
+ }
+ }
+ memThen = wbcall(pos, bThen, fn, typ, ptr, srcval, memThen, sp, sb)
}
// Note that we set up a writebarrier function call.
f.fe.SetWBPos(pos)
@@ -249,6 +294,12 @@ func writebarrier(f *Func) {
}
}
+ // mark volatile temps dead
+ for _, c := range volatiles {
+ tmpNode := c.tmp.Aux
+ memThen = bThen.NewValue1A(memThen.Pos, OpVarKill, types.TypeMem, tmpNode, memThen)
+ }
+
// merge memory
// Splice memory Phi into the last memory of the original sequence,
// which may be used in subsequent blocks. Other memories in the
@@ -302,25 +353,9 @@ func writebarrier(f *Func) {
}
// wbcall emits write barrier runtime call in b, returns memory.
-// if valIsVolatile, it moves val into temp space before making the call.
-func wbcall(pos src.XPos, b *Block, fn, typ *obj.LSym, ptr, val, mem, sp, sb *Value, valIsVolatile bool) *Value {
+func wbcall(pos src.XPos, b *Block, fn, typ *obj.LSym, ptr, val, mem, sp, sb *Value) *Value {
config := b.Func.Config
- var tmp GCNode
- if valIsVolatile {
- // Copy to temp location if the source is volatile (will be clobbered by
- // a function call). Marshaling the args to typedmemmove might clobber the
- // value we're trying to move.
- t := val.Type.Elem()
- tmp = b.Func.fe.Auto(val.Pos, t)
- mem = b.NewValue1A(pos, OpVarDef, types.TypeMem, tmp, mem)
- tmpaddr := b.NewValue2A(pos, OpLocalAddr, t.PtrTo(), tmp, sp, mem)
- siz := t.Size()
- mem = b.NewValue3I(pos, OpMove, types.TypeMem, siz, tmpaddr, val, mem)
- mem.Aux = t
- val = tmpaddr
- }
-
// put arguments on stack
off := config.ctxt.FixedFrameSize()
@@ -348,11 +383,6 @@ func wbcall(pos src.XPos, b *Block, fn, typ *obj.LSym, ptr, val, mem, sp, sb *Va
// issue call
mem = b.NewValue1A(pos, OpStaticCall, types.TypeMem, fn, mem)
mem.AuxInt = off - config.ctxt.FixedFrameSize()
-
- if valIsVolatile {
- mem = b.NewValue1A(pos, OpVarKill, types.TypeMem, tmp, mem) // mark temp dead
- }
-
return mem
}
diff --git a/src/cmd/go/internal/get/vcs.go b/src/cmd/go/internal/get/vcs.go
index a7a2ba32cc..ce34d5aca9 100644
--- a/src/cmd/go/internal/get/vcs.go
+++ b/src/cmd/go/internal/get/vcs.go
@@ -424,8 +424,8 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool)
cmd.Dir = dir
cmd.Env = base.EnvForDir(cmd.Dir, os.Environ())
if cfg.BuildX {
- fmt.Printf("cd %s\n", dir)
- fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " "))
+ fmt.Fprintf(os.Stderr, "cd %s\n", dir)
+ fmt.Fprintf(os.Stderr, "%s %s\n", v.cmd, strings.Join(args, " "))
}
out, err := cmd.Output()
if err != nil {
diff --git a/src/cmd/go/internal/imports/scan.go b/src/cmd/go/internal/imports/scan.go
index 966a38cfef..3d9b6132b1 100644
--- a/src/cmd/go/internal/imports/scan.go
+++ b/src/cmd/go/internal/imports/scan.go
@@ -26,7 +26,7 @@ func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) {
// If the directory entry is a symlink, stat it to obtain the info for the
// link target instead of the link itself.
if info.Mode()&os.ModeSymlink != 0 {
- info, err = os.Stat(name)
+ info, err = os.Stat(filepath.Join(dir, name))
if err != nil {
continue // Ignore broken symlinks.
}
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
index 49bd98216c..e8533ff325 100644
--- a/src/cmd/go/internal/load/pkg.go
+++ b/src/cmd/go/internal/load/pkg.go
@@ -1184,6 +1184,36 @@ var cgoSyscallExclude = map[string]bool{
var foldPath = make(map[string]string)
+// DefaultExecName returns the default executable name
+// for a package with the import path importPath.
+//
+// The default executable name is the last element of the import path.
+// In module-aware mode, an additional rule is used. If the last element
+// is a vN path element specifying the major version, then the second last
+// element of the import path is used instead.
+func DefaultExecName(importPath string) string {
+ _, elem := pathpkg.Split(importPath)
+ if cfg.ModulesEnabled {
+ // If this is example.com/mycmd/v2, it's more useful to install it as mycmd than as v2.
+ // See golang.org/issue/24667.
+ isVersion := func(v string) bool {
+ if len(v) < 2 || v[0] != 'v' || v[1] < '1' || '9' < v[1] {
+ return false
+ }
+ for i := 2; i < len(v); i++ {
+ if c := v[i]; c < '0' || '9' < c {
+ return false
+ }
+ }
+ return true
+ }
+ if isVersion(elem) {
+ _, elem = pathpkg.Split(pathpkg.Dir(importPath))
+ }
+ }
+ return elem
+}
+
// load populates p using information from bp, err, which should
// be the result of calling build.Context.Import.
func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
@@ -1226,7 +1256,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
}
_, elem := filepath.Split(p.Dir)
if cfg.ModulesEnabled {
- // NOTE(rsc): Using p.ImportPath instead of p.Dir
+ // NOTE(rsc,dmitshur): Using p.ImportPath instead of p.Dir
// makes sure we install a package in the root of a
// cached module directory as that package name
// not name@v1.2.3.
@@ -1235,26 +1265,9 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
// even for non-module-enabled code,
// but I'm not brave enough to change the
// non-module behavior this late in the
- // release cycle. Maybe for Go 1.12.
+ // release cycle. Can be done for Go 1.13.
// See golang.org/issue/26869.
- _, elem = pathpkg.Split(p.ImportPath)
-
- // If this is example.com/mycmd/v2, it's more useful to install it as mycmd than as v2.
- // See golang.org/issue/24667.
- isVersion := func(v string) bool {
- if len(v) < 2 || v[0] != 'v' || v[1] < '1' || '9' < v[1] {
- return false
- }
- for i := 2; i < len(v); i++ {
- if c := v[i]; c < '0' || '9' < c {
- return false
- }
- }
- return true
- }
- if isVersion(elem) {
- _, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath))
- }
+ elem = DefaultExecName(p.ImportPath)
}
full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem
if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH {
diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go
index 6293aea3c3..48d03d8fce 100644
--- a/src/cmd/go/internal/load/test.go
+++ b/src/cmd/go/internal/load/test.go
@@ -268,17 +268,8 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag
pmain.Imports = pmain.Imports[:w]
pmain.Internal.RawImports = str.StringList(pmain.Imports)
- if ptest != p {
- // We have made modifications to the package p being tested
- // and are rebuilding p (as ptest).
- // Arrange to rebuild all packages q such that
- // the test depends on q and q depends on p.
- // This makes sure that q sees the modifications to p.
- // Strictly speaking, the rebuild is only necessary if the
- // modifications to p change its export metadata, but
- // determining that is a bit tricky, so we rebuild always.
- recompileForTest(pmain, p, ptest, pxtest)
- }
+ // Replace pmain's transitive dependencies with test copies, as necessary.
+ recompileForTest(pmain, p, ptest, pxtest)
// Should we apply coverage analysis locally,
// only for this package and only for this test?
@@ -325,6 +316,14 @@ Search:
return stk
}
+// recompileForTest copies and replaces certain packages in pmain's dependency
+// graph. This is necessary for two reasons. First, if ptest is different than
+// preal, packages that import the package under test should get ptest instead
+// of preal. This is particularly important if pxtest depends on functionality
+// exposed in test sources in ptest. Second, if there is a main package
+// (other than pmain) anywhere, we need to clear p.Internal.BuildInfo in
+// the test copy to prevent link conflicts. This may happen if both -coverpkg
+// and the command line patterns include multiple main packages.
func recompileForTest(pmain, preal, ptest, pxtest *Package) {
// The "test copy" of preal is ptest.
// For each package that depends on preal, make a "test copy"
@@ -367,7 +366,7 @@ func recompileForTest(pmain, preal, ptest, pxtest *Package) {
// Don't compile build info from a main package. This can happen
// if -coverpkg patterns include main packages, since those packages
- // are imported by pmain.
+ // are imported by pmain. See golang.org/issue/30907.
if p.Internal.BuildInfo != "" && p != pmain {
split()
}
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
index 8dfb3df22d..52b1511efc 100644
--- a/src/cmd/go/internal/test/test.go
+++ b/src/cmd/go/internal/test/test.go
@@ -805,7 +805,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
if p.ImportPath == "command-line-arguments" {
elem = p.Name
} else {
- _, elem = path.Split(p.ImportPath)
+ elem = load.DefaultExecName(p.ImportPath)
}
testBinary := elem + ".test"
diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go
index 145b87513a..ed66df22c3 100644
--- a/src/cmd/go/internal/work/build.go
+++ b/src/cmd/go/internal/work/build.go
@@ -10,7 +10,6 @@ import (
"go/build"
"os"
"os/exec"
- "path"
"path/filepath"
"runtime"
"strings"
@@ -285,7 +284,7 @@ func runBuild(cmd *base.Command, args []string) {
pkgs := load.PackagesForBuild(args)
if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" {
- _, cfg.BuildO = path.Split(pkgs[0].ImportPath)
+ cfg.BuildO = load.DefaultExecName(pkgs[0].ImportPath)
cfg.BuildO += cfg.ExeSuffix
}
@@ -518,7 +517,7 @@ func InstallPackages(patterns []string, pkgs []*load.Package) {
if len(patterns) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" {
// Compute file 'go build' would have created.
// If it exists and is an executable file, remove it.
- _, targ := filepath.Split(pkgs[0].ImportPath)
+ targ := load.DefaultExecName(pkgs[0].ImportPath)
targ += cfg.ExeSuffix
if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory
fi, err := os.Stat(targ)
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index bbcbdd7568..0ab7976c56 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -214,6 +214,7 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
if p.Internal.CoverMode != "" {
fmt.Fprintf(h, "cover %q %q\n", p.Internal.CoverMode, b.toolID("cover"))
}
+ fmt.Fprintf(h, "modinfo %q\n", p.Internal.BuildInfo)
// Configuration specific to compiler toolchain.
switch cfg.BuildToolchainName {
diff --git a/src/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt
index cfa91f08a5..3acd637931 100644
--- a/src/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt
+++ b/src/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt
@@ -13,3 +13,9 @@ import "rsc.io/quote"
func main() {
println(quote.Hello())
}
+-- fortune_test.go --
+package main
+
+import "testing"
+
+func TestFortuneV2(t *testing.T) {}
diff --git a/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt b/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt
index 8ee4848d0a..ab7cd66949 100644
--- a/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt
+++ b/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt
@@ -6,32 +6,38 @@ env GO111MODULE=on
[short] skip
-go test -coverpkg=all ./main1 ./main2
+go test -coverpkg=all ./...
-- go.mod --
module example.com/cov
--- main1/main1.go --
+-- mainonly/mainonly.go --
package main
func main() {}
--- main1/main1_test.go --
+-- mainwithtest/mainwithtest.go --
package main
-import "testing"
+func main() {}
-func TestMain1(t *testing.T) {}
+func Foo() {}
--- main2/main2.go --
+-- mainwithtest/mainwithtest_test.go --
package main
-func main() {}
+import "testing"
--- main2/main2_test.go --
-package main
+func TestFoo(t *testing.T) {
+ Foo()
+}
-import "testing"
+-- xtest/x.go --
+package x
-func TestMain2(t *testing.T) {}
+-- xtest/x_test.go --
+package x_test
+
+import "testing"
+func TestX(t *testing.T) {}
diff --git a/src/cmd/go/testdata/script/mod_build_versioned.txt b/src/cmd/go/testdata/script/mod_build_versioned.txt
new file mode 100644
index 0000000000..eb081c9be1
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_build_versioned.txt
@@ -0,0 +1,16 @@
+env GO111MODULE=on
+
+go get -m rsc.io/fortune/v2
+
+# The default executable name shouldn't be v2$exe
+go build rsc.io/fortune/v2
+! exists v2$exe
+exists fortune$exe
+
+# The default test binary name shouldn't be v2.test$exe
+go test -c rsc.io/fortune/v2
+! exists v2.test$exe
+exists fortune.test$exe
+
+-- go.mod --
+module scratch
diff --git a/src/cmd/go/testdata/script/mod_symlink.txt b/src/cmd/go/testdata/script/mod_symlink.txt
index 61da3cc355..49bece2b84 100644
--- a/src/cmd/go/testdata/script/mod_symlink.txt
+++ b/src/cmd/go/testdata/script/mod_symlink.txt
@@ -2,16 +2,31 @@ env GO111MODULE=on
[!symlink] skip
# 'go list' should resolve modules of imported packages.
-go list -deps -f '{{.Module}}'
+go list -deps -f '{{.Module}}' .
stdout golang.org/x/text
-# They should continue to resolve if the importing file is a symlink.
+go list -deps -f '{{.Module}}' ./subpkg
+stdout golang.org/x/text
+
+# Create a copy of the module using symlinks in src/links.
mkdir links
+symlink links/go.mod -> $GOPATH/src/go.mod
+symlink links/issue.go -> $GOPATH/src/issue.go
+mkdir links/subpkg
+symlink links/subpkg/issue.go -> $GOPATH/src/subpkg/issue.go
+
+# We should see the copy as a valid module root.
cd links
-symlink go.mod -> ../go.mod
-symlink issue.go -> ../issue.go
+go env GOMOD
+stdout links[/\\]go.mod
+go list -m
+stdout golang.org/issue/28107
-go list -deps -f '{{.Module}}'
+# The symlink-based copy should contain the same packages
+# and have the same dependencies as the original.
+go list -deps -f '{{.Module}}' .
+stdout golang.org/x/text
+go list -deps -f '{{.Module}}' ./subpkg
stdout golang.org/x/text
-- go.mod --
@@ -21,3 +36,7 @@ module golang.org/issue/28107
package issue
import _ "golang.org/x/text/language"
+-- subpkg/issue.go --
+package issue
+
+import _ "golang.org/x/text/language"
diff --git a/src/cmd/link/elf_test.go b/src/cmd/link/elf_test.go
new file mode 100644
index 0000000000..3df9869284
--- /dev/null
+++ b/src/cmd/link/elf_test.go
@@ -0,0 +1,113 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build dragonfly freebsd linux netbsd openbsd
+
+package main
+
+import (
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+var asmSource = `
+ .section .text1,"ax"
+s1:
+ .byte 0
+ .section .text2,"ax"
+s2:
+ .byte 0
+`
+
+var goSource = `
+package main
+func main() {}
+`
+
+// The linker used to crash if an ELF input file had multiple text sections
+// with the same name.
+func TestSectionsWithSameName(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ testenv.MustHaveCGO(t)
+ t.Parallel()
+
+ objcopy, err := exec.LookPath("objcopy")
+ if err != nil {
+ t.Skipf("can't find objcopy: %v", err)
+ }
+
+ dir, err := ioutil.TempDir("", "go-link-TestSectionsWithSameName")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ gopath := filepath.Join(dir, "GOPATH")
+ env := append(os.Environ(), "GOPATH="+gopath)
+
+ if err := ioutil.WriteFile(filepath.Join(dir, "go.mod"), []byte("module elf_test\n"), 0666); err != nil {
+ t.Fatal(err)
+ }
+
+ asmFile := filepath.Join(dir, "x.s")
+ if err := ioutil.WriteFile(asmFile, []byte(asmSource), 0444); err != nil {
+ t.Fatal(err)
+ }
+
+ goTool := testenv.GoToolPath(t)
+ cmd := exec.Command(goTool, "env", "CC")
+ cmd.Env = env
+ ccb, err := cmd.Output()
+ if err != nil {
+ t.Fatal(err)
+ }
+ cc := strings.TrimSpace(string(ccb))
+
+ cmd = exec.Command(goTool, "env", "GOGCCFLAGS")
+ cmd.Env = env
+ cflagsb, err := cmd.Output()
+ if err != nil {
+ t.Fatal(err)
+ }
+ cflags := strings.Fields(string(cflagsb))
+
+ asmObj := filepath.Join(dir, "x.o")
+ t.Logf("%s %v -c -o %s %s", cc, cflags, asmObj, asmFile)
+ if out, err := exec.Command(cc, append(cflags, "-c", "-o", asmObj, asmFile)...).CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+
+ asm2Obj := filepath.Join(dir, "x2.syso")
+ t.Logf("%s --rename-section .text2=.text1 %s %s", objcopy, asmObj, asm2Obj)
+ if out, err := exec.Command(objcopy, "--rename-section", ".text2=.text1", asmObj, asm2Obj).CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+
+ for _, s := range []string{asmFile, asmObj} {
+ if err := os.Remove(s); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ goFile := filepath.Join(dir, "main.go")
+ if err := ioutil.WriteFile(goFile, []byte(goSource), 0444); err != nil {
+ t.Fatal(err)
+ }
+
+ cmd = exec.Command(goTool, "build")
+ cmd.Dir = dir
+ cmd.Env = env
+ t.Logf("%s build", goTool)
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+}
diff --git a/src/cmd/link/internal/loadelf/ldelf.go b/src/cmd/link/internal/loadelf/ldelf.go
index d85d91948a..251146d292 100644
--- a/src/cmd/link/internal/loadelf/ldelf.go
+++ b/src/cmd/link/internal/loadelf/ldelf.go
@@ -678,6 +678,8 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
// as well use one large chunk.
// create symbols for elfmapped sections
+ sectsymNames := make(map[string]bool)
+ counter := 0
for i := 0; uint(i) < elfobj.nsect; i++ {
sect = &elfobj.sect[i]
if sect.type_ == SHT_ARM_ATTRIBUTES && sect.name == ".ARM.attributes" {
@@ -709,6 +711,12 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
}
name := fmt.Sprintf("%s(%s)", pkg, sect.name)
+ for sectsymNames[name] {
+ counter++
+ name = fmt.Sprintf("%s(%s%d)", pkg, sect.name, counter)
+ }
+ sectsymNames[name] = true
+
s := syms.Lookup(name, localSymVersion)
switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go
index 21baa02a8d..4d8a6e5e7d 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go
@@ -87,6 +87,7 @@ type Pass struct {
OtherFiles []string // names of non-Go files of this package
Pkg *types.Package // type information about the package
TypesInfo *types.Info // type information about the syntax trees
+ TypesSizes types.Sizes // function for computing sizes of types
// Report reports a Diagnostic, a finding about a specific location
// in the analyzed source code such as a potential mistake.
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go
index f925849ab5..2d44b0458a 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go
@@ -246,7 +246,7 @@ An Analyzer that uses facts must declare their types:
var Analyzer = &analysis.Analyzer{
Name: "printf",
- FactTypes: []reflect.Type{reflect.TypeOf(new(isWrapper))},
+ FactTypes: []analysis.Fact{new(isWrapper)},
...
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
index dce1ef7bd5..6403d7783a 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
@@ -114,7 +114,8 @@ func init() {
// library we cannot assume types.SizesFor is consistent with arches.
// For now, assume 64-bit norms and print a warning.
// But this warning should really be deferred until we attempt to use
- // arch, which is very unlikely.
+ // arch, which is very unlikely. Better would be
+ // to defer size computation until we have Pass.TypesSizes.
arch.sizes = types.SizesFor("gc", "amd64")
log.Printf("unknown architecture %s", arch.name)
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
index 993f1ce3c4..1e4fac8595 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
@@ -9,7 +9,6 @@ package cgocall
import (
"fmt"
"go/ast"
- "go/build"
"go/format"
"go/parser"
"go/token"
@@ -45,7 +44,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
return nil, nil // doesn't use cgo
}
- cgofiles, info, err := typeCheckCgoSourceFiles(pass.Fset, pass.Pkg, pass.Files, pass.TypesInfo)
+ cgofiles, info, err := typeCheckCgoSourceFiles(pass.Fset, pass.Pkg, pass.Files, pass.TypesInfo, pass.TypesSizes)
if err != nil {
return nil, err
}
@@ -171,7 +170,7 @@ func checkCgo(fset *token.FileSet, f *ast.File, info *types.Info, reportf func(t
// limited ourselves here to preserving function bodies and initializer
// expressions since that is all that the cgocall analyzer needs.
//
-func typeCheckCgoSourceFiles(fset *token.FileSet, pkg *types.Package, files []*ast.File, info *types.Info) ([]*ast.File, *types.Info, error) {
+func typeCheckCgoSourceFiles(fset *token.FileSet, pkg *types.Package, files []*ast.File, info *types.Info, sizes types.Sizes) ([]*ast.File, *types.Info, error) {
const thispkg = "·this·"
// Which files are cgo files?
@@ -269,8 +268,7 @@ func typeCheckCgoSourceFiles(fset *token.FileSet, pkg *types.Package, files []*a
Importer: importerFunc(func(path string) (*types.Package, error) {
return importMap[path], nil
}),
- // TODO(adonovan): Sizes should probably be provided by analysis.Pass.
- Sizes: types.SizesFor("gc", build.Default.GOARCH),
+ Sizes: sizes,
Error: func(error) {}, // ignore errors (e.g. unused import)
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go
index 9cca7781d0..2abe7c6d51 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go
@@ -21,7 +21,16 @@ const Doc = `check for unkeyed composite literals
This analyzer reports a diagnostic for composite literals of struct
types imported from another package that do not use the field-keyed
syntax. Such literals are fragile because the addition of a new field
-(even if unexported) to the struct will cause compilation to fail.`
+(even if unexported) to the struct will cause compilation to fail.
+
+As an example,
+
+ err = &net.DNSConfigError{err}
+
+should be replaced by:
+
+ err = &net.DNSConfigError{Err: err}
+`
var Analyzer = &analysis.Analyzer{
Name: "composites",
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
index bd06549984..8213f63313 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
@@ -8,7 +8,11 @@
//
// Example of use in another analysis:
//
-// import "golang.org/x/tools/go/analysis/passes/inspect"
+// import (
+// "golang.org/x/tools/go/analysis"
+// "golang.org/x/tools/go/analysis/passes/inspect"
+// "golang.org/x/tools/go/ast/inspector"
+// )
//
// var Analyzer = &analysis.Analyzer{
// ...
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
index c0265aafee..b73ff5e0c3 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
@@ -453,15 +453,23 @@ func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func,
}
// isFormatter reports whether t satisfies fmt.Formatter.
-// Unlike fmt.Stringer, it's impossible to satisfy fmt.Formatter without importing fmt.
-func isFormatter(pass *analysis.Pass, t types.Type) bool {
- for _, imp := range pass.Pkg.Imports() {
- if imp.Path() == "fmt" {
- formatter := imp.Scope().Lookup("Formatter").Type().Underlying().(*types.Interface)
- return types.Implements(t, formatter)
- }
+// The only interface method to look for is "Format(State, rune)".
+func isFormatter(typ types.Type) bool {
+ obj, _, _ := types.LookupFieldOrMethod(typ, false, nil, "Format")
+ fn, ok := obj.(*types.Func)
+ if !ok {
+ return false
}
- return false
+ sig := fn.Type().(*types.Signature)
+ return sig.Params().Len() == 2 &&
+ sig.Results().Len() == 0 &&
+ isNamed(sig.Params().At(0).Type(), "fmt", "State") &&
+ types.Identical(sig.Params().At(1).Type(), types.Typ[types.Rune])
+}
+
+func isNamed(T types.Type, pkgpath, name string) bool {
+ named, ok := T.(*types.Named)
+ return ok && named.Obj().Pkg().Path() == pkgpath && named.Obj().Name() == name
}
// formatState holds the parsed representation of a printf directive such as "%3.*[4]d".
@@ -753,7 +761,7 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o
formatter := false
if state.argNum < len(call.Args) {
if tv, ok := pass.TypesInfo.Types[call.Args[state.argNum]]; ok {
- formatter = isFormatter(pass, tv.Type)
+ formatter = isFormatter(tv.Type)
}
}
@@ -831,7 +839,7 @@ func recursiveStringer(pass *analysis.Pass, e ast.Expr) bool {
typ := pass.TypesInfo.Types[e].Type
// It's unlikely to be a recursive stringer if it has a Format method.
- if isFormatter(pass, typ) {
+ if isFormatter(typ) {
return false
}
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go
index e8810464cd..12286fd5df 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go
@@ -2,7 +2,6 @@ package printf
import (
"go/ast"
- "go/build"
"go/types"
"golang.org/x/tools/go/analysis"
@@ -39,7 +38,7 @@ func matchArgTypeInternal(pass *analysis.Pass, t printfArgType, typ types.Type,
}
}
// If the type implements fmt.Formatter, we have nothing to check.
- if isFormatter(pass, typ) {
+ if isFormatter(typ) {
return true
}
// If we can use a string, might arg (dynamically) implement the Stringer or Error interface?
@@ -235,5 +234,3 @@ func matchStructArgType(pass *analysis.Pass, t printfArgType, typ *types.Struct,
}
return true
}
-
-var archSizes = types.SizesFor("gc", build.Default.GOARCH)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go
index 56b150b2b1..39f54573c9 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go
@@ -12,10 +12,8 @@ package shift
import (
"go/ast"
- "go/build"
"go/constant"
"go/token"
- "go/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
@@ -93,36 +91,9 @@ func checkLongShift(pass *analysis.Pass, node ast.Node, x, y ast.Expr) {
if t == nil {
return
}
- b, ok := t.Underlying().(*types.Basic)
- if !ok {
- return
- }
- var size int64
- switch b.Kind() {
- case types.Uint8, types.Int8:
- size = 8
- case types.Uint16, types.Int16:
- size = 16
- case types.Uint32, types.Int32:
- size = 32
- case types.Uint64, types.Int64:
- size = 64
- case types.Int, types.Uint:
- size = uintBitSize
- case types.Uintptr:
- size = uintptrBitSize
- default:
- return
- }
+ size := 8 * pass.TypesSizes.Sizeof(t)
if amt >= size {
ident := analysisutil.Format(pass.Fset, x)
pass.Reportf(node.Pos(), "%s (%d bits) too small for shift of %d", ident, size, amt)
}
}
-
-var (
- uintBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uint])
- uintptrBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uintptr])
-)
-
-var archSizes = types.SizesFor("gc", build.Default.GOARCH)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go
index 2b67c376ba..5b27208e91 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go
@@ -96,6 +96,11 @@ func checkTagDuplicates(pass *analysis.Pass, tag, key string, nearest, field *ty
}
if val == "" || val[0] == ',' {
if field.Anonymous() {
+ // Disable this check enhancement in Go 1.12.1; some
+ // false positives were spotted in the initial 1.12
+ // release. See https://golang.org/issues/30465.
+ return
+
typ, ok := field.Type().Underlying().(*types.Struct)
if !ok {
return
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
index 76dabc28b9..ba2e66fed2 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
@@ -329,6 +329,7 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
OtherFiles: cfg.NonGoFiles,
Pkg: pkg,
TypesInfo: info,
+ TypesSizes: tc.Sizes,
ResultOf: inputs,
Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) },
ImportObjectFact: facts.ImportObjectFact,
diff --git a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go
index db88a95109..ddbdd3f08f 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go
@@ -14,7 +14,7 @@
// Experiments suggest the inspector's traversals are about 2.5x faster
// than ast.Inspect, but it may take around 5 traversals for this
// benefit to amortize the inspector's construction cost.
-// If efficiency is the primary concern, do not use use Inspector for
+// If efficiency is the primary concern, do not use Inspector for
// one-off traversals.
package inspector
diff --git a/src/cmd/vet/testdata/src/print2/big.go b/src/cmd/vet/testdata/src/print2/big.go
new file mode 100644
index 0000000000..dd5bef55f6
--- /dev/null
+++ b/src/cmd/vet/testdata/src/print2/big.go
@@ -0,0 +1,17 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package print2
+
+import ( // NOTE: Does not import "fmt"
+ "log"
+ "math/big"
+)
+
+var fmt int
+
+func f() {
+ log.Printf("%d", new(big.Int))
+ log.Printf("%d", 1.0) // ERROR "Printf format %d has arg 1.0 of wrong type float64"
+}
diff --git a/src/cmd/vet/testdata/src/structtag/structtag.go b/src/cmd/vet/testdata/src/structtag/structtag.go
index cbcc453376..e40139e8b1 100644
--- a/src/cmd/vet/testdata/src/structtag/structtag.go
+++ b/src/cmd/vet/testdata/src/structtag/structtag.go
@@ -6,6 +6,20 @@
package structtag
+import "encoding/json"
+
type StructTagTest struct {
A int "hello" // ERROR "`hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
}
+
+func Issue30465() {
+ type T1 struct {
+ X string `json:"x"`
+ }
+ type T2 struct {
+ T1
+ X string `json:"x"`
+ }
+ var t2 T2
+ json.Marshal(&t2)
+}
diff --git a/src/cmd/vet/vet_test.go b/src/cmd/vet/vet_test.go
index d106c5c29c..f3b9a56515 100644
--- a/src/cmd/vet/vet_test.go
+++ b/src/cmd/vet/vet_test.go
@@ -88,6 +88,7 @@ func TestVet(t *testing.T) {
"method",
"nilfunc",
"print",
+ "print2",
"rangeloop",
"shift",
"structtag",
diff --git a/src/internal/poll/fd_windows.go b/src/internal/poll/fd_windows.go
index 19d9a12dad..f860b82c97 100644
--- a/src/internal/poll/fd_windows.go
+++ b/src/internal/poll/fd_windows.go
@@ -660,6 +660,10 @@ func (fd *FD) Write(buf []byte) (int, error) {
return 0, err
}
defer fd.writeUnlock()
+ if fd.isFile || fd.isDir || fd.isConsole {
+ fd.l.Lock()
+ defer fd.l.Unlock()
+ }
ntotal := 0
for len(buf) > 0 {
@@ -670,8 +674,6 @@ func (fd *FD) Write(buf []byte) (int, error) {
var n int
var err error
if fd.isFile || fd.isDir || fd.isConsole {
- fd.l.Lock()
- defer fd.l.Unlock()
if fd.isConsole {
n, err = fd.writeConsole(b)
} else {
diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go
index 4e10bf3997..4b165d65a6 100644
--- a/src/net/http/httputil/reverseproxy.go
+++ b/src/net/http/httputil/reverseproxy.go
@@ -389,6 +389,11 @@ func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader, flushInterval
latency: flushInterval,
}
defer mlw.stop()
+
+ // set up initial timer so headers get flushed even if body writes are delayed
+ mlw.flushPending = true
+ mlw.t = time.AfterFunc(flushInterval, mlw.delayedFlush)
+
dst = mlw
}
}
diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go
index 5edefa08e5..367ba73ae2 100644
--- a/src/net/http/httputil/reverseproxy_test.go
+++ b/src/net/http/httputil/reverseproxy_test.go
@@ -9,6 +9,7 @@ package httputil
import (
"bufio"
"bytes"
+ "context"
"errors"
"fmt"
"io"
@@ -317,6 +318,47 @@ func TestReverseProxyFlushInterval(t *testing.T) {
}
}
+func TestReverseProxyFlushIntervalHeaders(t *testing.T) {
+ const expected = "hi"
+ stopCh := make(chan struct{})
+ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Add("MyHeader", expected)
+ w.WriteHeader(200)
+ w.(http.Flusher).Flush()
+ <-stopCh
+ }))
+ defer backend.Close()
+ defer close(stopCh)
+
+ backendURL, err := url.Parse(backend.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ proxyHandler := NewSingleHostReverseProxy(backendURL)
+ proxyHandler.FlushInterval = time.Microsecond
+
+ frontend := httptest.NewServer(proxyHandler)
+ defer frontend.Close()
+
+ req, _ := http.NewRequest("GET", frontend.URL, nil)
+ req.Close = true
+
+ ctx, cancel := context.WithTimeout(req.Context(), 10*time.Second)
+ defer cancel()
+ req = req.WithContext(ctx)
+
+ res, err := frontend.Client().Do(req)
+ if err != nil {
+ t.Fatalf("Get: %v", err)
+ }
+ defer res.Body.Close()
+
+ if res.Header.Get("MyHeader") != expected {
+ t.Errorf("got header %q; expected %q", res.Header.Get("MyHeader"), expected)
+ }
+}
+
func TestReverseProxyCancelation(t *testing.T) {
const backendResponse = "I am the backend"
diff --git a/src/net/lookup.go b/src/net/lookup.go
index e10889331e..08e8d01385 100644
--- a/src/net/lookup.go
+++ b/src/net/lookup.go
@@ -262,8 +262,9 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IP
// only the values in context. See Issue 28600.
lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
+ lookupKey := network + "\000" + host
dnsWaitGroup.Add(1)
- ch, called := r.getLookupGroup().DoChan(host, func() (interface{}, error) {
+ ch, called := r.getLookupGroup().DoChan(lookupKey, func() (interface{}, error) {
defer dnsWaitGroup.Done()
return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
})
@@ -280,7 +281,7 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IP
// let the lookup continue uncanceled, and let later
// lookups with the same key share the result.
// See issues 8602, 20703, 22724.
- if r.getLookupGroup().ForgetUnshared(host) {
+ if r.getLookupGroup().ForgetUnshared(lookupKey) {
lookupGroupCancel()
} else {
go func() {
diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go
index 85bcb2b896..28a895e15d 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -16,6 +16,7 @@ import (
"sort"
"strings"
"sync"
+ "sync/atomic"
"testing"
"time"
)
@@ -253,14 +254,11 @@ func TestLookupGmailTXT(t *testing.T) {
}
}
-var lookupGooglePublicDNSAddrTests = []struct {
- addr, name string
-}{
- {"8.8.8.8", ".google.com."},
- {"8.8.4.4", ".google.com."},
-
- {"2001:4860:4860::8888", ".google.com."},
- {"2001:4860:4860::8844", ".google.com."},
+var lookupGooglePublicDNSAddrTests = []string{
+ "8.8.8.8",
+ "8.8.4.4",
+ "2001:4860:4860::8888",
+ "2001:4860:4860::8844",
}
func TestLookupGooglePublicDNSAddr(t *testing.T) {
@@ -272,8 +270,8 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
defer dnsWaitGroup.Wait()
- for _, tt := range lookupGooglePublicDNSAddrTests {
- names, err := LookupAddr(tt.addr)
+ for _, ip := range lookupGooglePublicDNSAddrTests {
+ names, err := LookupAddr(ip)
if err != nil {
t.Fatal(err)
}
@@ -281,8 +279,8 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
t.Error("got no record")
}
for _, name := range names {
- if !strings.HasSuffix(name, tt.name) {
- t.Errorf("got %s; want a record containing %s", name, tt.name)
+ if !strings.HasSuffix(name, ".google.com.") && !strings.HasSuffix(name, ".google.") {
+ t.Errorf("got %q; want a record ending in .google.com. or .google.", name)
}
}
}
@@ -658,8 +656,8 @@ func testDots(t *testing.T, mode string) {
t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode)
} else {
for _, name := range names {
- if !strings.HasSuffix(name, ".google.com.") {
- t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names, mode)
+ if !strings.HasSuffix(name, ".google.com.") && !strings.HasSuffix(name, ".google.") {
+ t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com or .google with trailing dot (mode=%v)", names, mode)
break
}
}
@@ -1096,6 +1094,69 @@ func TestLookupIPAddrPreservesContextValues(t *testing.T) {
}
}
+// Issue 30521: The lookup group should call the resolver for each network.
+func TestLookupIPAddrConcurrentCallsForNetworks(t *testing.T) {
+ origTestHookLookupIP := testHookLookupIP
+ defer func() { testHookLookupIP = origTestHookLookupIP }()
+
+ queries := [][]string{
+ {"udp", "golang.org"},
+ {"udp4", "golang.org"},
+ {"udp6", "golang.org"},
+ {"udp", "golang.org"},
+ {"udp", "golang.org"},
+ }
+ results := map[[2]string][]IPAddr{
+ {"udp", "golang.org"}: {
+ {IP: IPv4(127, 0, 0, 1)},
+ {IP: IPv6loopback},
+ },
+ {"udp4", "golang.org"}: {
+ {IP: IPv4(127, 0, 0, 1)},
+ },
+ {"udp6", "golang.org"}: {
+ {IP: IPv6loopback},
+ },
+ }
+ calls := int32(0)
+ waitCh := make(chan struct{})
+ testHookLookupIP = func(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
+ // We'll block until this is called one time for each different
+ // expected result. This will ensure that the lookup group would wait
+ // for the existing call if it was to be reused.
+ if atomic.AddInt32(&calls, 1) == int32(len(results)) {
+ close(waitCh)
+ }
+ select {
+ case <-waitCh:
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ }
+ return results[[2]string{network, host}], nil
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+ wg := sync.WaitGroup{}
+ for _, q := range queries {
+ network := q[0]
+ host := q[1]
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ gotIPs, err := DefaultResolver.lookupIPAddr(ctx, network, host)
+ if err != nil {
+ t.Errorf("lookupIPAddr(%v, %v): unexpected error: %v", network, host, err)
+ }
+ wantIPs := results[[2]string{network, host}]
+ if !reflect.DeepEqual(gotIPs, wantIPs) {
+ t.Errorf("lookupIPAddr(%v, %v): mismatched IPAddr results\n\tGot: %v\n\tWant: %v", network, host, gotIPs, wantIPs)
+ }
+ }()
+ }
+ wg.Wait()
+}
+
func TestWithUnexpiredValuesPreserved(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
diff --git a/src/os/export_unix_test.go b/src/os/export_unix_test.go
new file mode 100644
index 0000000000..032b1a9dbf
--- /dev/null
+++ b/src/os/export_unix_test.go
@@ -0,0 +1,9 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+
+package os
+
+var SplitPath = splitPath
diff --git a/src/os/os_unix_test.go b/src/os/os_unix_test.go
index 2aa930ea80..c9e5541cb4 100644
--- a/src/os/os_unix_test.go
+++ b/src/os/os_unix_test.go
@@ -281,3 +281,28 @@ func TestNewFileNonBlock(t *testing.T) {
t.Parallel()
newFileTest(t, false)
}
+
+func TestSplitPath(t *testing.T) {
+ t.Parallel()
+ for _, tt := range []struct{ path, wantDir, wantBase string }{
+ {"a", ".", "a"},
+ {"a/", ".", "a"},
+ {"a//", ".", "a"},
+ {"a/b", "a", "b"},
+ {"a/b/", "a", "b"},
+ {"a/b/c", "a/b", "c"},
+ {"/a", "/", "a"},
+ {"/a/", "/", "a"},
+ {"/a/b", "/a", "b"},
+ {"/a/b/", "/a", "b"},
+ {"/a/b/c", "/a/b", "c"},
+ {"//a", "/", "a"},
+ {"//a/", "/", "a"},
+ {"///a", "/", "a"},
+ {"///a/", "/", "a"},
+ } {
+ if dir, base := SplitPath(tt.path); dir != tt.wantDir || base != tt.wantBase {
+ t.Errorf("splitPath(%q) = %q, %q, want %q, %q", tt.path, dir, base, tt.wantDir, tt.wantBase)
+ }
+ }
+}
diff --git a/src/os/path.go b/src/os/path.go
index 104b7ceaf7..ba43ea3525 100644
--- a/src/os/path.go
+++ b/src/os/path.go
@@ -62,6 +62,7 @@ func MkdirAll(path string, perm FileMode) error {
// It removes everything it can but returns the first error
// it encounters. If the path does not exist, RemoveAll
// returns nil (no error).
+// If there is an error, it will be of type *PathError.
func RemoveAll(path string) error {
return removeAll(path)
}
diff --git a/src/os/path_unix.go b/src/os/path_unix.go
index be373a50a9..df423d2c9d 100644
--- a/src/os/path_unix.go
+++ b/src/os/path_unix.go
@@ -38,20 +38,30 @@ func basename(name string) string {
func splitPath(path string) (string, string) {
// if no better parent is found, the path is relative from "here"
dirname := "."
- // if no slashes in path, base is path
- basename := path
+
+ // Remove all but one leading slash.
+ for len(path) > 1 && path[0] == '/' && path[1] == '/' {
+ path = path[1:]
+ }
i := len(path) - 1
- // Remove trailing slashes
+ // Remove trailing slashes.
for ; i > 0 && path[i] == '/'; i-- {
path = path[:i]
}
+ // if no slashes in path, base is path
+ basename := path
+
// Remove leading directory path
for i--; i >= 0; i-- {
if path[i] == '/' {
- dirname = path[:i+1]
+ if i == 0 {
+ dirname = path[:1]
+ } else {
+ dirname = path[:i]
+ }
basename = path[i+1:]
break
}
diff --git a/src/os/removeall_at.go b/src/os/removeall_at.go
index 94232cf556..330963b354 100644
--- a/src/os/removeall_at.go
+++ b/src/os/removeall_at.go
@@ -46,13 +46,20 @@ func removeAll(path string) error {
}
defer parent.Close()
- return removeAllFrom(parent, base)
+ if err := removeAllFrom(parent, base); err != nil {
+ if pathErr, ok := err.(*PathError); ok {
+ pathErr.Path = parentDir + string(PathSeparator) + pathErr.Path
+ err = pathErr
+ }
+ return err
+ }
+ return nil
}
-func removeAllFrom(parent *File, path string) error {
+func removeAllFrom(parent *File, base string) error {
parentFd := int(parent.Fd())
// Simple case: if Unlink (aka remove) works, we're done.
- err := unix.Unlinkat(parentFd, path, 0)
+ err := unix.Unlinkat(parentFd, base, 0)
if err == nil || IsNotExist(err) {
return nil
}
@@ -64,21 +71,21 @@ func removeAllFrom(parent *File, path string) error {
// whose contents need to be removed.
// Otherwise just return the error.
if err != syscall.EISDIR && err != syscall.EPERM && err != syscall.EACCES {
- return err
+ return &PathError{"unlinkat", base, err}
}
// Is this a directory we need to recurse into?
var statInfo syscall.Stat_t
- statErr := unix.Fstatat(parentFd, path, &statInfo, unix.AT_SYMLINK_NOFOLLOW)
+ statErr := unix.Fstatat(parentFd, base, &statInfo, unix.AT_SYMLINK_NOFOLLOW)
if statErr != nil {
if IsNotExist(statErr) {
return nil
}
- return statErr
+ return &PathError{"fstatat", base, statErr}
}
if statInfo.Mode&syscall.S_IFMT != syscall.S_IFDIR {
- // Not a directory; return the error from the Remove.
- return err
+ // Not a directory; return the error from the unix.Unlinkat.
+ return &PathError{"unlinkat", base, err}
}
// Remove the directory's entries.
@@ -87,12 +94,12 @@ func removeAllFrom(parent *File, path string) error {
const request = 1024
// Open the directory to recurse into
- file, err := openFdAt(parentFd, path)
+ file, err := openFdAt(parentFd, base)
if err != nil {
if IsNotExist(err) {
return nil
}
- recurseErr = err
+ recurseErr = &PathError{"openfdat", base, err}
break
}
@@ -103,12 +110,15 @@ func removeAllFrom(parent *File, path string) error {
if IsNotExist(readErr) {
return nil
}
- return readErr
+ return &PathError{"readdirnames", base, readErr}
}
for _, name := range names {
err := removeAllFrom(file, name)
if err != nil {
+ if pathErr, ok := err.(*PathError); ok {
+ pathErr.Path = base + string(PathSeparator) + pathErr.Path
+ }
recurseErr = err
}
}
@@ -127,7 +137,7 @@ func removeAllFrom(parent *File, path string) error {
}
// Remove the directory itself.
- unlinkError := unix.Unlinkat(parentFd, path, unix.AT_REMOVEDIR)
+ unlinkError := unix.Unlinkat(parentFd, base, unix.AT_REMOVEDIR)
if unlinkError == nil || IsNotExist(unlinkError) {
return nil
}
@@ -135,7 +145,7 @@ func removeAllFrom(parent *File, path string) error {
if recurseErr != nil {
return recurseErr
}
- return unlinkError
+ return &PathError{"unlinkat", base, unlinkError}
}
// openFdAt opens path relative to the directory in fd.
@@ -157,7 +167,7 @@ func openFdAt(dirfd int, name string) (*File, error) {
continue
}
- return nil, &PathError{"openat", name, e}
+ return nil, e
}
if !supportsCloseOnExec {
diff --git a/src/os/removeall_test.go b/src/os/removeall_test.go
index 21371d8776..945a38e8e0 100644
--- a/src/os/removeall_test.go
+++ b/src/os/removeall_test.go
@@ -294,7 +294,7 @@ func TestRemoveReadOnlyDir(t *testing.T) {
}
// Issue #29983.
-func TestRemoveAllButReadOnly(t *testing.T) {
+func TestRemoveAllButReadOnlyAndPathError(t *testing.T) {
switch runtime.GOOS {
case "nacl", "js", "windows":
t.Skipf("skipping test on %s", runtime.GOOS)
@@ -355,10 +355,21 @@ func TestRemoveAllButReadOnly(t *testing.T) {
defer Chmod(d, 0777)
}
- if err := RemoveAll(tempDir); err == nil {
+ err = RemoveAll(tempDir)
+ if err == nil {
t.Fatal("RemoveAll succeeded unexpectedly")
}
+ // The error should be of type *PathError.
+ // see issue 30491 for details.
+ if pathErr, ok := err.(*PathError); ok {
+ if g, w := pathErr.Path, filepath.Join(tempDir, "b", "y"); g != w {
+ t.Errorf("got %q, expected pathErr.path %q", g, w)
+ }
+ } else {
+ t.Errorf("got %T, expected *os.PathError", err)
+ }
+
for _, dir := range dirs {
_, err := Stat(filepath.Join(tempDir, dir))
if inReadonly(dir) {
diff --git a/src/runtime/asm_wasm.s b/src/runtime/asm_wasm.s
index 374b9f73db..6ce1c7070a 100644
--- a/src/runtime/asm_wasm.s
+++ b/src/runtime/asm_wasm.s
@@ -443,7 +443,7 @@ TEXT runtime·gcWriteBarrier(SB), NOSPLIT, $16
// Record value
MOVD R1, 0(R5)
// Record *slot
- MOVD R0, 8(R5)
+ MOVD (R0), 8(R5)
// Increment wbBuf.next
Get R5
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go
index 9eaf92dc7c..9be501d627 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -513,3 +513,116 @@ func MapTombstoneCheck(m map[int]int) {
}
}
}
+
+// Span is a safe wrapper around an mspan, whose memory
+// is managed manually.
+type Span struct {
+ *mspan
+}
+
+func AllocSpan(base, npages uintptr) Span {
+ lock(&mheap_.lock)
+ s := (*mspan)(mheap_.spanalloc.alloc())
+ unlock(&mheap_.lock)
+ s.init(base, npages)
+ return Span{s}
+}
+
+func (s *Span) Free() {
+ lock(&mheap_.lock)
+ mheap_.spanalloc.free(unsafe.Pointer(s.mspan))
+ unlock(&mheap_.lock)
+ s.mspan = nil
+}
+
+func (s Span) Base() uintptr {
+ return s.mspan.base()
+}
+
+func (s Span) Pages() uintptr {
+ return s.mspan.npages
+}
+
+type TreapIter struct {
+ treapIter
+}
+
+func (t TreapIter) Span() Span {
+ return Span{t.span()}
+}
+
+func (t TreapIter) Valid() bool {
+ return t.valid()
+}
+
+func (t TreapIter) Next() TreapIter {
+ return TreapIter{t.next()}
+}
+
+func (t TreapIter) Prev() TreapIter {
+ return TreapIter{t.prev()}
+}
+
+// Treap is a safe wrapper around mTreap for testing.
+//
+// It must never be heap-allocated because mTreap is
+// notinheap.
+//
+//go:notinheap
+type Treap struct {
+ mTreap
+}
+
+func (t *Treap) Start() TreapIter {
+ return TreapIter{t.start()}
+}
+
+func (t *Treap) End() TreapIter {
+ return TreapIter{t.end()}
+}
+
+func (t *Treap) Insert(s Span) {
+ // mTreap uses a fixalloc in mheap_ for treapNode
+ // allocation which requires the mheap_ lock to manipulate.
+ // Locking here is safe because the treap itself never allocs
+ // or otherwise ends up grabbing this lock.
+ lock(&mheap_.lock)
+ t.insert(s.mspan)
+ unlock(&mheap_.lock)
+ t.CheckInvariants()
+}
+
+func (t *Treap) Find(npages uintptr) TreapIter {
+ return TreapIter{treapIter{t.find(npages)}}
+}
+
+func (t *Treap) Erase(i TreapIter) {
+ // mTreap uses a fixalloc in mheap_ for treapNode
+ // freeing which requires the mheap_ lock to manipulate.
+ // Locking here is safe because the treap itself never allocs
+ // or otherwise ends up grabbing this lock.
+ lock(&mheap_.lock)
+ t.erase(i.treapIter)
+ unlock(&mheap_.lock)
+ t.CheckInvariants()
+}
+
+func (t *Treap) RemoveSpan(s Span) {
+ // See Erase about locking.
+ lock(&mheap_.lock)
+ t.removeSpan(s.mspan)
+ unlock(&mheap_.lock)
+ t.CheckInvariants()
+}
+
+func (t *Treap) Size() int {
+ i := 0
+ t.mTreap.treap.walkTreap(func(t *treapNode) {
+ i++
+ })
+ return i
+}
+
+func (t *Treap) CheckInvariants() {
+ t.mTreap.treap.walkTreap(checkTreapNode)
+}
diff --git a/src/runtime/mgclarge.go b/src/runtime/mgclarge.go
index 7b01a11780..0e39c66dc3 100644
--- a/src/runtime/mgclarge.go
+++ b/src/runtime/mgclarge.go
@@ -134,16 +134,19 @@ func checkTreapNode(t *treapNode) {
return t.npagesKey < npages
}
// t.npagesKey == npages
- return uintptr(unsafe.Pointer(t.spanKey)) < uintptr(unsafe.Pointer(s))
+ return t.spanKey.base() < s.base()
}
if t == nil {
return
}
- if t.spanKey.npages != t.npagesKey || t.spanKey.next != nil {
+ if t.spanKey.next != nil || t.spanKey.prev != nil || t.spanKey.list != nil {
+ throw("span may be on an mSpanList while simultaneously in the treap")
+ }
+ if t.spanKey.npages != t.npagesKey {
println("runtime: checkTreapNode treapNode t=", t, " t.npagesKey=", t.npagesKey,
"t.spanKey.npages=", t.spanKey.npages)
- throw("why does span.npages and treap.ngagesKey do not match?")
+ throw("span.npages and treap.npagesKey do not match")
}
if t.left != nil && lessThan(t.left.npagesKey, t.left.spanKey) {
throw("t.lessThan(t.left.npagesKey, t.left.spanKey) is not false")
@@ -298,24 +301,30 @@ func (root *mTreap) removeNode(t *treapNode) {
// find searches for, finds, and returns the treap node containing the
// smallest span that can hold npages. If no span has at least npages
// it returns nil.
-// This is slightly more complicated than a simple binary tree search
-// since if an exact match is not found the next larger node is
-// returned.
+// This is a simple binary tree search that tracks the best-fit node found
+// so far. The best-fit node is guaranteed to be on the path to a
+// (maybe non-existent) lowest-base exact match.
func (root *mTreap) find(npages uintptr) *treapNode {
+ var best *treapNode
t := root.treap
for t != nil {
if t.spanKey == nil {
throw("treap node with nil spanKey found")
}
- if t.npagesKey < npages {
- t = t.right
- } else if t.left != nil && t.left.npagesKey >= npages {
+ // If we found an exact match, try to go left anyway. There could be
+ // a span there with a lower base address.
+ //
+ // Don't bother checking nil-ness of left and right here; even if t
+ // becomes nil, we already know the other path had nothing better for
+ // us anyway.
+ if t.npagesKey >= npages {
+ best = t
t = t.left
} else {
- return t
+ t = t.right
}
}
- return nil
+ return best
}
// removeSpan searches for, finds, deletes span along with
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index 47e3a33391..6c0ea1bded 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -1198,16 +1198,6 @@ HaveSpan:
// heap_released since we already did so earlier.
sysUsed(unsafe.Pointer(s.base()), s.npages<<_PageShift)
s.scavenged = false
-
- // Since we allocated out of a scavenged span, we just
- // grew the RSS. Mitigate this by scavenging enough free
- // space to make up for it.
- //
- // Also, scavengeLargest may cause coalescing, so prevent
- // coalescing with s by temporarily changing its state.
- s.state = mSpanManual
- h.scavengeLargest(s.npages * pageSize)
- s.state = mSpanFree
}
s.unusedsince = 0
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 2e1ec58a0d..d3e84fe3dc 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -29,6 +29,7 @@ const (
//go:cgo_import_dynamic runtime._GetProcessAffinityMask GetProcessAffinityMask%3 "kernel32.dll"
//go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus%5 "kernel32.dll"
//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle%1 "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetSystemDirectoryA GetSystemDirectoryA%2 "kernel32.dll"
//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll"
//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll"
//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll"
@@ -47,12 +48,9 @@ const (
//go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc%4 "kernel32.dll"
//go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll"
//go:cgo_import_dynamic runtime._VirtualQuery VirtualQuery%3 "kernel32.dll"
-//go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult%5 "ws2_32.dll"
//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll"
//go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll"
//go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll"
-//go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod%1 "winmm.dll"
-//go:cgo_import_dynamic runtime._timeEndPeriod timeEndPeriod%1 "winmm.dll"
type stdFunction unsafe.Pointer
@@ -75,6 +73,7 @@ var (
_GetProcessAffinityMask,
_GetQueuedCompletionStatus,
_GetStdHandle,
+ _GetSystemDirectoryA,
_GetSystemInfo,
_GetSystemTimeAsFileTime,
_GetThreadContext,
@@ -96,12 +95,9 @@ var (
_VirtualAlloc,
_VirtualFree,
_VirtualQuery,
- _WSAGetOverlappedResult,
_WaitForSingleObject,
_WriteConsoleW,
_WriteFile,
- _timeBeginPeriod,
- _timeEndPeriod,
_ stdFunction
// Following syscalls are only available on some Windows PCs.
@@ -109,6 +105,7 @@ var (
_AddDllDirectory,
_AddVectoredContinueHandler,
_GetQueuedCompletionStatusEx,
+ _LoadLibraryExA,
_LoadLibraryExW,
_ stdFunction
@@ -126,6 +123,12 @@ var (
// links wrong printf function to cgo executable (see issue
// 12030 for details).
_NtWaitForSingleObject stdFunction
+
+ // These are from non-kernel32.dll, so we prefer to LoadLibraryEx them.
+ _timeBeginPeriod,
+ _timeEndPeriod,
+ _WSAGetOverlappedResult,
+ _ stdFunction
)
// Function to be called by windows CreateThread
@@ -173,6 +176,26 @@ func windowsFindfunc(lib uintptr, name []byte) stdFunction {
return stdFunction(unsafe.Pointer(f))
}
+var sysDirectory [521]byte
+var sysDirectoryLen uintptr
+
+func windowsLoadSystemLib(name []byte) uintptr {
+ if useLoadLibraryEx {
+ return stdcall3(_LoadLibraryExA, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
+ } else {
+ if sysDirectoryLen == 0 {
+ l := stdcall2(_GetSystemDirectoryA, uintptr(unsafe.Pointer(&sysDirectory[0])), uintptr(len(sysDirectory)-1))
+ if l == 0 || l > uintptr(len(sysDirectory)-1) {
+ throw("Unable to determine system directory")
+ }
+ sysDirectory[l] = '\\'
+ sysDirectoryLen = l + 1
+ }
+ absName := append(sysDirectory[:sysDirectoryLen], name...)
+ return stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&absName[0])))
+ }
+}
+
func loadOptionalSyscalls() {
var kernel32dll = []byte("kernel32.dll\000")
k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0])))
@@ -182,17 +205,19 @@ func loadOptionalSyscalls() {
_AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000"))
_AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000"))
_GetQueuedCompletionStatusEx = windowsFindfunc(k32, []byte("GetQueuedCompletionStatusEx\000"))
+ _LoadLibraryExA = windowsFindfunc(k32, []byte("LoadLibraryExA\000"))
_LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
+ useLoadLibraryEx = (_LoadLibraryExW != nil && _LoadLibraryExA != nil && _AddDllDirectory != nil)
var advapi32dll = []byte("advapi32.dll\000")
- a32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&advapi32dll[0])))
+ a32 := windowsLoadSystemLib(advapi32dll)
if a32 == 0 {
throw("advapi32.dll not found")
}
_RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000"))
var ntdll = []byte("ntdll.dll\000")
- n32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&ntdll[0])))
+ n32 := windowsLoadSystemLib(ntdll)
if n32 == 0 {
throw("ntdll.dll not found")
}
@@ -205,6 +230,27 @@ func loadOptionalSyscalls() {
}
}
+ var winmmdll = []byte("winmm.dll\000")
+ m32 := windowsLoadSystemLib(winmmdll)
+ if m32 == 0 {
+ throw("winmm.dll not found")
+ }
+ _timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000"))
+ _timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000"))
+ if _timeBeginPeriod == nil || _timeEndPeriod == nil {
+ throw("timeBegin/EndPeriod not found")
+ }
+
+ var ws232dll = []byte("ws2_32.dll\000")
+ ws232 := windowsLoadSystemLib(ws232dll)
+ if ws232 == 0 {
+ throw("ws2_32.dll not found")
+ }
+ _WSAGetOverlappedResult = windowsFindfunc(ws232, []byte("WSAGetOverlappedResult\000"))
+ if _WSAGetOverlappedResult == nil {
+ throw("WSAGetOverlappedResult not found")
+ }
+
if windowsFindfunc(n32, []byte("wine_get_version\000")) != nil {
// running on Wine
initWine(k32)
@@ -311,8 +357,6 @@ func osinit() {
loadOptionalSyscalls()
- useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil)
-
disableWER()
initExceptionHandler()
diff --git a/src/runtime/runtime-lldb_test.go b/src/runtime/runtime-lldb_test.go
index fe3a0eb90d..08d6a34f50 100644
--- a/src/runtime/runtime-lldb_test.go
+++ b/src/runtime/runtime-lldb_test.go
@@ -139,6 +139,7 @@ func TestLldbPython(t *testing.T) {
if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final {
t.Skip("gdb test can fail with GOROOT_FINAL pending")
}
+ testenv.SkipFlaky(t, 31188)
checkLldbPython(t)
diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
index 8cfc71124a..36ad7511af 100644
--- a/src/runtime/syscall_windows.go
+++ b/src/runtime/syscall_windows.go
@@ -104,9 +104,13 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
+// When available, this function will use LoadLibraryEx with the filename
+// parameter and the important SEARCH_SYSTEM32 argument. But on systems that
+// do not have that option, absoluteFilepath should contain a fallback
+// to the full path inside of system32 for use with vanilla LoadLibrary.
//go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary
//go:nosplit
-func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
+func syscall_loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle, err uintptr) {
lockOSThread()
defer unlockOSThread()
c := &getg().m.syscall
@@ -121,15 +125,9 @@ func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
}{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32}
c.args = uintptr(noescape(unsafe.Pointer(&args)))
} else {
- // User doesn't have KB2533623 installed. The caller
- // wanted to only load the filename DLL from the
- // System32 directory but that facility doesn't exist,
- // so just load it the normal way. This is a potential
- // security risk, but so is not installing security
- // updates.
c.fn = getLoadLibrary()
c.n = 1
- c.args = uintptr(noescape(unsafe.Pointer(&filename)))
+ c.args = uintptr(noescape(unsafe.Pointer(&absoluteFilepath)))
}
cgocall(asmstdcallAddr, unsafe.Pointer(c))
diff --git a/src/runtime/treap_test.go b/src/runtime/treap_test.go
new file mode 100644
index 0000000000..76e4829d99
--- /dev/null
+++ b/src/runtime/treap_test.go
@@ -0,0 +1,205 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "runtime"
+ "testing"
+)
+
+var spanDesc = map[uintptr]uintptr{
+ 0xc0000000: 2,
+ 0xc0006000: 1,
+ 0xc0010000: 8,
+ 0xc0022000: 7,
+ 0xc0034000: 4,
+ 0xc0040000: 5,
+ 0xc0050000: 5,
+ 0xc0060000: 5000,
+}
+
+// Wrap the Treap one more time because go:notinheap doesn't
+// actually follow a structure across package boundaries.
+//
+//go:notinheap
+type treap struct {
+ runtime.Treap
+}
+
+// This test ensures that the treap implementation in the runtime
+// maintains all stated invariants after different sequences of
+// insert, removeSpan, find, and erase. Invariants specific to the
+// treap data structure are checked implicitly: after each mutating
+// operation, treap-related invariants are checked for the entire
+// treap.
+func TestTreap(t *testing.T) {
+ // Set up a bunch of spans allocated into mheap_.
+ spans := make([]runtime.Span, 0, len(spanDesc))
+ for base, pages := range spanDesc {
+ s := runtime.AllocSpan(base, pages)
+ defer s.Free()
+ spans = append(spans, s)
+ }
+ t.Run("Insert", func(t *testing.T) {
+ tr := treap{}
+ // Test just a very basic insert/remove for sanity.
+ tr.Insert(spans[0])
+ tr.RemoveSpan(spans[0])
+ })
+ t.Run("FindTrivial", func(t *testing.T) {
+ tr := treap{}
+ // Test just a very basic find operation for sanity.
+ tr.Insert(spans[0])
+ i := tr.Find(1)
+ if i.Span() != spans[0] {
+ t.Fatal("found unknown span in treap")
+ }
+ tr.RemoveSpan(spans[0])
+ })
+ t.Run("FindBestFit", func(t *testing.T) {
+ // Run this 10 times, recreating the treap each time.
+ // Because of the non-deterministic structure of a treap,
+ // we'll be able to test different structures this way.
+ for i := 0; i < 10; i++ {
+ tr := treap{}
+ for _, s := range spans {
+ tr.Insert(s)
+ }
+ i := tr.Find(5)
+ if i.Span().Pages() != 5 {
+ t.Fatalf("expected span of size 5, got span of size %d", i.Span().Pages())
+ } else if i.Span().Base() != 0xc0040000 {
+ t.Fatalf("expected span to have the lowest base address, instead got base %x", i.Span().Base())
+ }
+ for _, s := range spans {
+ tr.RemoveSpan(s)
+ }
+ }
+ })
+ t.Run("Iterate", func(t *testing.T) {
+ t.Run("StartToEnd", func(t *testing.T) {
+ // Ensure progressing an iterator actually goes over the whole treap
+ // from the start and that it iterates over the elements in order.
+ // Also ensures that Start returns a valid iterator.
+ tr := treap{}
+ for _, s := range spans {
+ tr.Insert(s)
+ }
+ nspans := 0
+ lastSize := uintptr(0)
+ for i := tr.Start(); i.Valid(); i = i.Next() {
+ nspans++
+ if lastSize > i.Span().Pages() {
+ t.Fatalf("not iterating in correct order: encountered size %d before %d", lastSize, i.Span().Pages())
+ }
+ lastSize = i.Span().Pages()
+ }
+ if nspans != len(spans) {
+ t.Fatal("failed to iterate forwards over full treap")
+ }
+ for _, s := range spans {
+ tr.RemoveSpan(s)
+ }
+ })
+ t.Run("EndToStart", func(t *testing.T) {
+ // Ensure progressing an iterator actually goes over the whole treap
+ // from the end and that it iterates over the elements in reverse
+ // order. Also ensures that End returns a valid iterator.
+ tr := treap{}
+ for _, s := range spans {
+ tr.Insert(s)
+ }
+ nspans := 0
+ lastSize := ^uintptr(0)
+ for i := tr.End(); i.Valid(); i = i.Prev() {
+ nspans++
+ if lastSize < i.Span().Pages() {
+ t.Fatalf("not iterating in correct order: encountered size %d before %d", lastSize, i.Span().Pages())
+ }
+ lastSize = i.Span().Pages()
+ }
+ if nspans != len(spans) {
+ t.Fatal("failed to iterate backwards over full treap")
+ }
+ for _, s := range spans {
+ tr.RemoveSpan(s)
+ }
+ })
+ t.Run("Prev", func(t *testing.T) {
+ // Test the iterator invariant that i.prev().next() == i.
+ tr := treap{}
+ for _, s := range spans {
+ tr.Insert(s)
+ }
+ i := tr.Start().Next().Next()
+ p := i.Prev()
+ if !p.Valid() {
+ t.Fatal("i.prev() is invalid")
+ }
+ if p.Next().Span() != i.Span() {
+ t.Fatal("i.prev().next() != i")
+ }
+ for _, s := range spans {
+ tr.RemoveSpan(s)
+ }
+ })
+ t.Run("Next", func(t *testing.T) {
+ // Test the iterator invariant that i.next().prev() == i.
+ tr := treap{}
+ for _, s := range spans {
+ tr.Insert(s)
+ }
+ i := tr.Start().Next().Next()
+ n := i.Next()
+ if !n.Valid() {
+ t.Fatal("i.next() is invalid")
+ }
+ if n.Prev().Span() != i.Span() {
+ t.Fatal("i.next().prev() != i")
+ }
+ for _, s := range spans {
+ tr.RemoveSpan(s)
+ }
+ })
+ })
+ t.Run("EraseOne", func(t *testing.T) {
+ // Test that erasing one iterator correctly retains
+ // all relationships between elements.
+ tr := treap{}
+ for _, s := range spans {
+ tr.Insert(s)
+ }
+ i := tr.Start().Next().Next().Next()
+ s := i.Span()
+ n := i.Next()
+ p := i.Prev()
+ tr.Erase(i)
+ if n.Prev().Span() != p.Span() {
+ t.Fatal("p, n := i.Prev(), i.Next(); n.prev() != p after i was erased")
+ }
+ if p.Next().Span() != n.Span() {
+ t.Fatal("p, n := i.Prev(), i.Next(); p.next() != n after i was erased")
+ }
+ tr.Insert(s)
+ for _, s := range spans {
+ tr.RemoveSpan(s)
+ }
+ })
+ t.Run("EraseAll", func(t *testing.T) {
+ // Test that erasing iterators actually removes nodes from the treap.
+ tr := treap{}
+ for _, s := range spans {
+ tr.Insert(s)
+ }
+ for i := tr.Start(); i.Valid(); {
+ n := i.Next()
+ tr.Erase(i)
+ i = n
+ }
+ if size := tr.Size(); size != 0 {
+ t.Fatalf("should have emptied out treap, %d spans left", size)
+ }
+ })
+}
diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go
index c57cd34f82..34925f74a4 100644
--- a/src/syscall/dll_windows.go
+++ b/src/syscall/dll_windows.go
@@ -28,7 +28,7 @@ func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 ui
func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)
func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2 uintptr, err Errno)
func loadlibrary(filename *uint16) (handle uintptr, err Errno)
-func loadsystemlibrary(filename *uint16) (handle uintptr, err Errno)
+func loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle uintptr, err Errno)
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
// A DLL implements access to a single DLL.
@@ -37,6 +37,26 @@ type DLL struct {
Handle Handle
}
+// We use this for computing the absolute path for system DLLs on systems
+// where SEARCH_SYSTEM32 is not available.
+var systemDirectoryPrefix string
+
+func init() {
+ n := uint32(MAX_PATH)
+ for {
+ b := make([]uint16, n)
+ l, e := getSystemDirectory(&b[0], n)
+ if e != nil {
+ panic("Unable to determine system directory: " + e.Error())
+ }
+ if l <= n {
+ systemDirectoryPrefix = UTF16ToString(b[:l]) + "\\"
+ break
+ }
+ n = l
+ }
+}
+
// LoadDLL loads the named DLL file into memory.
//
// If name is not an absolute path and is not a known system DLL used by
@@ -53,7 +73,11 @@ func LoadDLL(name string) (*DLL, error) {
var h uintptr
var e Errno
if sysdll.IsSystemDLL[name] {
- h, e = loadsystemlibrary(namep)
+ absoluteFilepathp, err := UTF16PtrFromString(systemDirectoryPrefix + name)
+ if err != nil {
+ return nil, err
+ }
+ h, e = loadsystemlibrary(namep, absoluteFilepathp)
} else {
h, e = loadlibrary(namep)
}
diff --git a/src/syscall/security_windows.go b/src/syscall/security_windows.go
index ae8b3a17bf..db80d98a08 100644
--- a/src/syscall/security_windows.go
+++ b/src/syscall/security_windows.go
@@ -290,6 +290,7 @@ type Tokenprimarygroup struct {
//sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
//sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation
//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
+//sys getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemDirectoryW
// An access token contains the security information for a logon session.
// The system creates an access token when a user logs on, and every
diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go
index de2d4f3adb..2348f6534f 100644
--- a/src/syscall/zsyscall_windows.go
+++ b/src/syscall/zsyscall_windows.go
@@ -190,6 +190,7 @@ var (
procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken")
procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation")
procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW")
+ procGetSystemDirectoryW = modkernel32.NewProc("GetSystemDirectoryW")
)
func GetLastError() (lasterr error) {
@@ -1916,3 +1917,16 @@ func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) {
}
return
}
+
+func getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) {
+ r0, _, e1 := Syscall(procGetSystemDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(dirLen), 0)
+ len = uint32(r0)
+ if len == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
diff --git a/test/fixedbugs/issue30956.go b/test/fixedbugs/issue30956.go
new file mode 100644
index 0000000000..021e6c5d47
--- /dev/null
+++ b/test/fixedbugs/issue30956.go
@@ -0,0 +1,32 @@
+// run
+
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for compile generated static data for literal
+// composite struct
+
+package main
+
+import "fmt"
+
+type X struct {
+ V interface{}
+
+ a int
+ b int
+ c int
+}
+
+func pr(x X) {
+ fmt.Println(x.V)
+}
+
+func main() {
+ pr(X{
+ V: struct {
+ A int
+ }{42},
+ })
+}
diff --git a/test/fixedbugs/issue30956.out b/test/fixedbugs/issue30956.out
new file mode 100644
index 0000000000..04f25e8ae7
--- /dev/null
+++ b/test/fixedbugs/issue30956.out
@@ -0,0 +1 @@
+{42}
diff --git a/test/fixedbugs/issue30977.go b/test/fixedbugs/issue30977.go
new file mode 100644
index 0000000000..2ca040d79a
--- /dev/null
+++ b/test/fixedbugs/issue30977.go
@@ -0,0 +1,52 @@
+// run
+
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 30977: write barrier call clobbers volatile
+// value when there are multiple uses of the value.
+
+package main
+
+import "runtime"
+
+type T struct {
+ a, b, c, d, e string
+}
+
+//go:noinline
+func g() T {
+ return T{"a", "b", "c", "d", "e"}
+}
+
+//go:noinline
+func f() {
+ // The compiler optimizes this to direct copying
+ // the call result to both globals, with write
+ // barriers. The first write barrier call clobbers
+ // the result of g on stack.
+ X = g()
+ Y = X
+}
+
+var X, Y T
+
+const N = 1000
+
+func main() {
+ // Keep GC running so the write barrier is on.
+ go func() {
+ for {
+ runtime.GC()
+ }
+ }()
+
+ for i := 0; i < N; i++ {
+ runtime.Gosched()
+ f()
+ if X != Y {
+ panic("FAIL")
+ }
+ }
+}
diff --git a/test/fixedbugs/issue31252.dir/a.go b/test/fixedbugs/issue31252.dir/a.go
new file mode 100644
index 0000000000..fa431502c0
--- /dev/null
+++ b/test/fixedbugs/issue31252.dir/a.go
@@ -0,0 +1,13 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import "fmt"
+
+type IndexController struct{}
+
+func (this *IndexController) Index(m *string) {
+ fmt.Println(m)
+}
diff --git a/test/fixedbugs/issue31252.dir/b.go b/test/fixedbugs/issue31252.dir/b.go
new file mode 100644
index 0000000000..9bfc0ff92e
--- /dev/null
+++ b/test/fixedbugs/issue31252.dir/b.go
@@ -0,0 +1,13 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "fmt"
+
+type IndexController struct{}
+
+func (this *IndexController) Index(m *string) {
+ fmt.Println(m)
+}
diff --git a/test/fixedbugs/issue31252.dir/c.go b/test/fixedbugs/issue31252.dir/c.go
new file mode 100644
index 0000000000..928c8eee1c
--- /dev/null
+++ b/test/fixedbugs/issue31252.dir/c.go
@@ -0,0 +1,26 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package c
+
+import (
+ "a"
+ "b"
+)
+
+type HandlerFunc func(*string)
+
+func RouterInit() {
+ //home API
+ homeIndex := &a.IndexController{}
+ GET("/home/index/index", homeIndex.Index)
+ //admin API
+ adminIndex := &b.IndexController{}
+ GET("/admin/index/index", adminIndex.Index)
+ return
+}
+
+func GET(path string, handlers ...HandlerFunc) {
+ return
+}
diff --git a/test/fixedbugs/issue31252.dir/main.go b/test/fixedbugs/issue31252.dir/main.go
new file mode 100644
index 0000000000..25a7548668
--- /dev/null
+++ b/test/fixedbugs/issue31252.dir/main.go
@@ -0,0 +1,11 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "c"
+
+func main() {
+ c.RouterInit()
+}
diff --git a/test/fixedbugs/issue31252.go b/test/fixedbugs/issue31252.go
new file mode 100644
index 0000000000..973ae1dcef
--- /dev/null
+++ b/test/fixedbugs/issue31252.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored