[dev.boringcrypto.go1.11] all: merge go1.11.2 into dev.boringcrypto.go1.11

Change-Id: I05b1fd8b4d3354935b44fc8fce6ae86dd652c94b
This commit is contained in:
Filippo Valsorda 2018-12-03 14:22:20 -05:00
commit 35cf0d9f6b
73 changed files with 1367 additions and 331 deletions

View File

@ -34,6 +34,7 @@ We encourage all Go users to subscribe to
<p>A <a href="/doc/devel/release.html">summary</a> of the changes between Go releases. Notes for the major releases:</p>
<ul>
<li><a href="/doc/go1.11">Go 1.11</a> <small>(August 2018)</small></li>
<li><a href="/doc/go1.10">Go 1.10</a> <small>(February 2018)</small></li>
<li><a href="/doc/go1.9">Go 1.9</a> <small>(August 2017)</small></li>
<li><a href="/doc/go1.8">Go 1.8</a> <small>(February 2017)</small></li>

View File

@ -23,6 +23,32 @@ in supported releases as needed by issuing minor revisions
(for example, Go 1.6.1, Go 1.6.2, and so on).
</p>
<h2 id="go1.11">go1.11 (released 2018/08/24)</h2>
<p>
Go 1.11 is a major release of Go.
Read the <a href="/doc/go1.11">Go 1.11 Release Notes</a> for more information.
</p>
<h3 id="go1.11.minor">Minor revisions</h3>
<p>
go1.11.1 (released 2018/10/01) includes fixes to the compiler, documentation, go
command, runtime, and the <code>crypto/x509</code>, <code>encoding/json</code>,
<code>go/types</code>, <code>net</code>, <code>net/http</code>, and
<code>reflect</code> packages.
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.1">Go
1.11.1 milestone</a> on our issue tracker for details.
</p>
<p>
go1.11.2 (released 2018/11/02) includes fixes to the compiler, linker,
documentation, go command, and the <code>database/sql</code> and
<code>go/types</code> packages.
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.2">Go
1.11.2 milestone</a> on our issue tracker for details.
</p>
<h2 id="go1.10">go1.10 (released 2018/02/16)</h2>
<p>
@ -65,6 +91,13 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.4">Go
1.10.4 milestone</a> on our issue tracker for details.
</p>
<p>
go1.10.5 (released 2018/11/02) includes fixes to the go command, linker, runtime
and the <code>database/sql</code> package.
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.5">Go
1.10.5 milestone</a> on our issue tracker for details.
</p>
<h2 id="go1.9">go1.9 (released 2017/08/24)</h2>
<p>

View File

@ -50,10 +50,10 @@ learned. You can {{if not $.GoogleCN}}<a href="//tour.golang.org/">take the tour
online</a> or{{end}} install it locally with:
</p>
<pre>
$ go get golang.org/x/tour/gotour
$ go get golang.org/x/tour
</pre>
<p>
This will place the <code>gotour</code> binary in your workspace's <code>bin</code> directory.
This will place the <code>tour</code> binary in your workspace's <code>bin</code> directory.
</p>
<h3 id="code"><a href="code.html">How to write Go code</a></h3>

View File

@ -348,6 +348,20 @@ updating. See the <a href="go1.10.html#cgo">Go 1.10 release notes</a> for
details. <!-- CL 126275, CL 127156, CL 122217, CL 122575, CL 123177 -->
</p>
<h3 id="go_command">Go command</h3>
<p><!-- CL 126656 -->
The environment variable <code>GOFLAGS</code> may now be used
to set default flags for the <code>go</code> command.
This is useful in certain situations.
Linking can be noticeably slower on underpowered systems due to DWARF,
and users may want to set <code>-ldflags=-w</code> by default.
For modules, some users and CI systems will want vendoring always,
so they should set <code>-mod=vendor</code> by default.
For more information, see the <a href="/cmd/go/#hdr-Environment_variables"><code>go</code>
command documentation</a>.
</p>
<h3 id="godoc">Godoc</h3>
<p>
@ -396,7 +410,7 @@ details. <!-- CL 126275, CL 127156, CL 122217, CL 122575, CL 123177 -->
</p>
<p><!-- CL 108679, CL 106156 -->
On macOS and iOS, the runtime now uses <code>libSystem.so</code> instead of
On macOS and iOS, the runtime now uses <code>libSystem.dylib</code> instead of
calling the kernel directly. This should make Go binaries more
compatible with future versions of macOS and iOS.
The <a href="/pkg/syscall">syscall</a> package still makes direct

View File

@ -12,6 +12,11 @@ license that can be found in the LICENSE file.
</head>
<body>
<!--
Add the following polyfill for Microsoft Edge 17/18 support:
<script src="https://cdn.jsdelivr.net/npm/text-encoding@0.7.0/lib/encoding.min.js"></script>
(see https://caniuse.com/#feat=textencoder)
-->
<script src="wasm_exec.js"></script>
<script>
if (!WebAssembly.instantiateStreaming) { // polyfill

View File

@ -121,6 +121,17 @@ func (n *Node) Int64() int64 {
return n.Val().U.(*Mpint).Int64()
}
// CanInt64 reports whether it is safe to call Int64() on n.
func (n *Node) CanInt64() bool {
if !Isconst(n, CTINT) {
return false
}
// if the value inside n cannot be represented as an int64, the
// return value of Int64 is undefined
return n.Val().U.(*Mpint).CmpInt64(n.Int64()) == 0
}
// Bool returns n as a bool.
// n must be a boolean constant.
func (n *Node) Bool() bool {

View File

@ -1263,7 +1263,7 @@ func typecheck1(n *Node, top int) *Node {
n.Op = OCALLFUNC
if t.Etype != TFUNC {
name := l.String()
if isBuiltinFuncName(name) {
if isBuiltinFuncName(name) && l.Name.Defn != nil {
// be more specific when the function
// name matches a predeclared function
yyerror("cannot call non-function %s (type %v), declared at %s",

View File

@ -3701,6 +3701,12 @@ func walkinrange(n *Node, init *Nodes) *Node {
return n
}
// Ensure that Int64() does not overflow on a and c (it'll happen
// for any const above 2**63; see issue #27143).
if !a.CanInt64() || !c.CanInt64() {
return n
}
if opl == OLT {
// We have a < b && ...
// We need a ≤ b && ... to safely use unsigned comparison tricks.

View File

@ -197,7 +197,8 @@ func elimDeadAutosGeneric(f *Func) {
panic("unhandled op with sym effect")
}
if v.Uses == 0 || len(args) == 0 {
if v.Uses == 0 && v.Op != OpNilCheck || len(args) == 0 {
// Nil check has no use, but we need to keep it.
return
}

View File

@ -1539,8 +1539,8 @@
// Don't Move from memory if the values are likely to already be
// in registers.
(Move {t1} [n] dst p1
mem:(Store {t2} op2:(OffPtr [o2] p2) d1
(Store {t3} op3:(OffPtr [0] p3) d2 _)))
mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
(Store {t3} op3:(OffPtr <tt3> [0] p3) d2 _)))
&& isSamePtr(p1, p2) && isSamePtr(p2, p3)
&& alignof(t2) <= alignof(t1)
&& alignof(t3) <= alignof(t1)
@ -1548,12 +1548,12 @@
&& registerizable(b, t3)
&& o2 == sizeof(t3)
&& n == sizeof(t2) + sizeof(t3)
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
(Store {t3} (OffPtr <t3.(*types.Type)> [0] dst) d2 mem))
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
(Store {t3} (OffPtr <tt3> [0] dst) d2 mem))
(Move {t1} [n] dst p1
mem:(Store {t2} op2:(OffPtr [o2] p2) d1
(Store {t3} op3:(OffPtr [o3] p3) d2
(Store {t4} op4:(OffPtr [0] p4) d3 _))))
mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
(Store {t3} op3:(OffPtr <tt3> [o3] p3) d2
(Store {t4} op4:(OffPtr <tt4> [0] p4) d3 _))))
&& isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4)
&& alignof(t2) <= alignof(t1)
&& alignof(t3) <= alignof(t1)
@ -1564,14 +1564,14 @@
&& o3 == sizeof(t4)
&& o2-o3 == sizeof(t3)
&& n == sizeof(t2) + sizeof(t3) + sizeof(t4)
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
(Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2
(Store {t4} (OffPtr <t4.(*types.Type)> [0] dst) d3 mem)))
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
(Store {t3} (OffPtr <tt3> [o3] dst) d2
(Store {t4} (OffPtr <tt4> [0] dst) d3 mem)))
(Move {t1} [n] dst p1
mem:(Store {t2} op2:(OffPtr [o2] p2) d1
(Store {t3} op3:(OffPtr [o3] p3) d2
(Store {t4} op4:(OffPtr [o4] p4) d3
(Store {t5} op5:(OffPtr [0] p5) d4 _)))))
mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
(Store {t3} op3:(OffPtr <tt3> [o3] p3) d2
(Store {t4} op4:(OffPtr <tt4> [o4] p4) d3
(Store {t5} op5:(OffPtr <tt5> [0] p5) d4 _)))))
&& isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && isSamePtr(p4, p5)
&& alignof(t2) <= alignof(t1)
&& alignof(t3) <= alignof(t1)
@ -1585,16 +1585,16 @@
&& o3-o4 == sizeof(t4)
&& o2-o3 == sizeof(t3)
&& n == sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5)
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
(Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2
(Store {t4} (OffPtr <t4.(*types.Type)> [o4] dst) d3
(Store {t5} (OffPtr <t5.(*types.Type)> [0] dst) d4 mem))))
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
(Store {t3} (OffPtr <tt3> [o3] dst) d2
(Store {t4} (OffPtr <tt4> [o4] dst) d3
(Store {t5} (OffPtr <tt5> [0] dst) d4 mem))))
// Same thing but with VarDef in the middle.
(Move {t1} [n] dst p1
mem:(VarDef
(Store {t2} op2:(OffPtr [o2] p2) d1
(Store {t3} op3:(OffPtr [0] p3) d2 _))))
(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
(Store {t3} op3:(OffPtr <tt3> [0] p3) d2 _))))
&& isSamePtr(p1, p2) && isSamePtr(p2, p3)
&& alignof(t2) <= alignof(t1)
&& alignof(t3) <= alignof(t1)
@ -1602,13 +1602,13 @@
&& registerizable(b, t3)
&& o2 == sizeof(t3)
&& n == sizeof(t2) + sizeof(t3)
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
(Store {t3} (OffPtr <t3.(*types.Type)> [0] dst) d2 mem))
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
(Store {t3} (OffPtr <tt3> [0] dst) d2 mem))
(Move {t1} [n] dst p1
mem:(VarDef
(Store {t2} op2:(OffPtr [o2] p2) d1
(Store {t3} op3:(OffPtr [o3] p3) d2
(Store {t4} op4:(OffPtr [0] p4) d3 _)))))
(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
(Store {t3} op3:(OffPtr <tt3> [o3] p3) d2
(Store {t4} op4:(OffPtr <tt4> [0] p4) d3 _)))))
&& isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4)
&& alignof(t2) <= alignof(t1)
&& alignof(t3) <= alignof(t1)
@ -1619,15 +1619,15 @@
&& o3 == sizeof(t4)
&& o2-o3 == sizeof(t3)
&& n == sizeof(t2) + sizeof(t3) + sizeof(t4)
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
(Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2
(Store {t4} (OffPtr <t4.(*types.Type)> [0] dst) d3 mem)))
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
(Store {t3} (OffPtr <tt3> [o3] dst) d2
(Store {t4} (OffPtr <tt4> [0] dst) d3 mem)))
(Move {t1} [n] dst p1
mem:(VarDef
(Store {t2} op2:(OffPtr [o2] p2) d1
(Store {t3} op3:(OffPtr [o3] p3) d2
(Store {t4} op4:(OffPtr [o4] p4) d3
(Store {t5} op5:(OffPtr [0] p5) d4 _))))))
(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
(Store {t3} op3:(OffPtr <tt3> [o3] p3) d2
(Store {t4} op4:(OffPtr <tt4> [o4] p4) d3
(Store {t5} op5:(OffPtr <tt5> [0] p5) d4 _))))))
&& isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && isSamePtr(p4, p5)
&& alignof(t2) <= alignof(t1)
&& alignof(t3) <= alignof(t1)
@ -1641,10 +1641,10 @@
&& o3-o4 == sizeof(t4)
&& o2-o3 == sizeof(t3)
&& n == sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5)
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
(Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2
(Store {t4} (OffPtr <t4.(*types.Type)> [o4] dst) d3
(Store {t5} (OffPtr <t5.(*types.Type)> [0] dst) d4 mem))))
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
(Store {t3} (OffPtr <tt3> [o3] dst) d2
(Store {t4} (OffPtr <tt4> [o4] dst) d3
(Store {t5} (OffPtr <tt5> [0] dst) d4 mem))))
// Prefer to Zero and Store than to Move.
(Move {t1} [n] dst p1

View File

@ -425,13 +425,13 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
//
// Useful for i > 0; s[i-1].
lim, ok := ft.limits[x.ID]
if ok && lim.min > opMin[v.Op] {
if ok && ((d == signed && lim.min > opMin[v.Op]) || (d == unsigned && lim.umin > 0)) {
ft.update(parent, x, w, d, gt)
}
} else if x, delta := isConstDelta(w); x != nil && delta == 1 {
// v >= x+1 && x < max ⇒ v > x
lim, ok := ft.limits[x.ID]
if ok && lim.max < opMax[w.Op] {
if ok && ((d == signed && lim.max < opMax[w.Op]) || (d == unsigned && lim.umax < opUMax[w.Op])) {
ft.update(parent, v, x, d, gt)
}
}
@ -527,6 +527,11 @@ var opMax = map[Op]int64{
OpAdd32: math.MaxInt32, OpSub32: math.MaxInt32,
}
var opUMax = map[Op]uint64{
OpAdd64: math.MaxUint64, OpSub64: math.MaxUint64,
OpAdd32: math.MaxUint32, OpSub32: math.MaxUint32,
}
// isNonNegative reports whether v is known to be non-negative.
func (ft *factsTable) isNonNegative(v *Value) bool {
if isNonNegative(v) {

View File

@ -16223,9 +16223,9 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
v.AddArg(v0)
return true
}
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [0] p3) d2 _)))
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [0] p3) d2 _)))
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && o2 == sizeof(t3) && n == sizeof(t2) + sizeof(t3)
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [0] dst) d2 mem))
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [0] dst) d2 mem))
for {
n := v.AuxInt
t1 := v.Aux
@ -16242,6 +16242,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
if op2.Op != OpOffPtr {
break
}
tt2 := op2.Type
o2 := op2.AuxInt
p2 := op2.Args[0]
d1 := mem.Args[1]
@ -16255,6 +16256,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
if op3.Op != OpOffPtr {
break
}
tt3 := op3.Type
if op3.AuxInt != 0 {
break
}
@ -16265,14 +16267,14 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
}
v.reset(OpStore)
v.Aux = t2
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
v0.AuxInt = o2
v0.AddArg(dst)
v.AddArg(v0)
v.AddArg(d1)
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
v1.Aux = t3
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
v2.AuxInt = 0
v2.AddArg(dst)
v1.AddArg(v2)
@ -16281,9 +16283,9 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
v.AddArg(v1)
return true
}
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [o3] p3) d2 (Store {t4} op4:(OffPtr [0] p4) d3 _))))
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [o3] p3) d2 (Store {t4} op4:(OffPtr <tt4> [0] p4) d3 _))))
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && alignof(t4) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && registerizable(b, t4) && o3 == sizeof(t4) && o2-o3 == sizeof(t3) && n == sizeof(t2) + sizeof(t3) + sizeof(t4)
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2 (Store {t4} (OffPtr <t4.(*types.Type)> [0] dst) d3 mem)))
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [0] dst) d3 mem)))
for {
n := v.AuxInt
t1 := v.Aux
@ -16300,6 +16302,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
if op2.Op != OpOffPtr {
break
}
tt2 := op2.Type
o2 := op2.AuxInt
p2 := op2.Args[0]
d1 := mem.Args[1]
@ -16313,6 +16316,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
if op3.Op != OpOffPtr {
break
}
tt3 := op3.Type
o3 := op3.AuxInt
p3 := op3.Args[0]
d2 := mem_2.Args[1]
@ -16326,6 +16330,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
if op4.Op != OpOffPtr {
break
}
tt4 := op4.Type
if op4.AuxInt != 0 {
break
}
@ -16336,21 +16341,21 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
}
v.reset(OpStore)
v.Aux = t2
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
v0.AuxInt = o2
v0.AddArg(dst)
v.AddArg(v0)
v.AddArg(d1)
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
v1.Aux = t3
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
v2.AuxInt = o3
v2.AddArg(dst)
v1.AddArg(v2)
v1.AddArg(d2)
v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
v3.Aux = t4
v4 := b.NewValue0(v.Pos, OpOffPtr, t4.(*types.Type))
v4 := b.NewValue0(v.Pos, OpOffPtr, tt4)
v4.AuxInt = 0
v4.AddArg(dst)
v3.AddArg(v4)
@ -16360,9 +16365,9 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
v.AddArg(v1)
return true
}
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [o3] p3) d2 (Store {t4} op4:(OffPtr [o4] p4) d3 (Store {t5} op5:(OffPtr [0] p5) d4 _)))))
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [o3] p3) d2 (Store {t4} op4:(OffPtr <tt4> [o4] p4) d3 (Store {t5} op5:(OffPtr <tt5> [0] p5) d4 _)))))
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && isSamePtr(p4, p5) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && alignof(t4) <= alignof(t1) && alignof(t5) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && registerizable(b, t4) && registerizable(b, t5) && o4 == sizeof(t5) && o3-o4 == sizeof(t4) && o2-o3 == sizeof(t3) && n == sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5)
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2 (Store {t4} (OffPtr <t4.(*types.Type)> [o4] dst) d3 (Store {t5} (OffPtr <t5.(*types.Type)> [0] dst) d4 mem))))
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [o4] dst) d3 (Store {t5} (OffPtr <tt5> [0] dst) d4 mem))))
for {
n := v.AuxInt
t1 := v.Aux
@ -16379,6 +16384,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
if op2.Op != OpOffPtr {
break
}
tt2 := op2.Type
o2 := op2.AuxInt
p2 := op2.Args[0]
d1 := mem.Args[1]
@ -16392,6 +16398,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
if op3.Op != OpOffPtr {
break
}
tt3 := op3.Type
o3 := op3.AuxInt
p3 := op3.Args[0]
d2 := mem_2.Args[1]
@ -16405,6 +16412,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
if op4.Op != OpOffPtr {
break
}
tt4 := op4.Type
o4 := op4.AuxInt
p4 := op4.Args[0]
d3 := mem_2_2.Args[1]
@ -16418,6 +16426,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
if op5.Op != OpOffPtr {
break
}
tt5 := op5.Type
if op5.AuxInt != 0 {
break
}
@ -16428,28 +16437,28 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
}
v.reset(OpStore)
v.Aux = t2
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
v0.AuxInt = o2
v0.AddArg(dst)
v.AddArg(v0)
v.AddArg(d1)
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
v1.Aux = t3
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
v2.AuxInt = o3
v2.AddArg(dst)
v1.AddArg(v2)
v1.AddArg(d2)
v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
v3.Aux = t4
v4 := b.NewValue0(v.Pos, OpOffPtr, t4.(*types.Type))
v4 := b.NewValue0(v.Pos, OpOffPtr, tt4)
v4.AuxInt = o4
v4.AddArg(dst)
v3.AddArg(v4)
v3.AddArg(d3)
v5 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
v5.Aux = t5
v6 := b.NewValue0(v.Pos, OpOffPtr, t5.(*types.Type))
v6 := b.NewValue0(v.Pos, OpOffPtr, tt5)
v6.AuxInt = 0
v6.AddArg(dst)
v5.AddArg(v6)
@ -16465,9 +16474,9 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
func rewriteValuegeneric_OpMove_10(v *Value) bool {
b := v.Block
_ = b
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [0] p3) d2 _))))
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [0] p3) d2 _))))
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && o2 == sizeof(t3) && n == sizeof(t2) + sizeof(t3)
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [0] dst) d2 mem))
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [0] dst) d2 mem))
for {
n := v.AuxInt
t1 := v.Aux
@ -16488,6 +16497,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
if op2.Op != OpOffPtr {
break
}
tt2 := op2.Type
o2 := op2.AuxInt
p2 := op2.Args[0]
d1 := mem_0.Args[1]
@ -16501,6 +16511,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
if op3.Op != OpOffPtr {
break
}
tt3 := op3.Type
if op3.AuxInt != 0 {
break
}
@ -16511,14 +16522,14 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
}
v.reset(OpStore)
v.Aux = t2
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
v0.AuxInt = o2
v0.AddArg(dst)
v.AddArg(v0)
v.AddArg(d1)
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
v1.Aux = t3
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
v2.AuxInt = 0
v2.AddArg(dst)
v1.AddArg(v2)
@ -16527,9 +16538,9 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
v.AddArg(v1)
return true
}
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [o3] p3) d2 (Store {t4} op4:(OffPtr [0] p4) d3 _)))))
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [o3] p3) d2 (Store {t4} op4:(OffPtr <tt4> [0] p4) d3 _)))))
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && alignof(t4) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && registerizable(b, t4) && o3 == sizeof(t4) && o2-o3 == sizeof(t3) && n == sizeof(t2) + sizeof(t3) + sizeof(t4)
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2 (Store {t4} (OffPtr <t4.(*types.Type)> [0] dst) d3 mem)))
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [0] dst) d3 mem)))
for {
n := v.AuxInt
t1 := v.Aux
@ -16550,6 +16561,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
if op2.Op != OpOffPtr {
break
}
tt2 := op2.Type
o2 := op2.AuxInt
p2 := op2.Args[0]
d1 := mem_0.Args[1]
@ -16563,6 +16575,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
if op3.Op != OpOffPtr {
break
}
tt3 := op3.Type
o3 := op3.AuxInt
p3 := op3.Args[0]
d2 := mem_0_2.Args[1]
@ -16576,6 +16589,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
if op4.Op != OpOffPtr {
break
}
tt4 := op4.Type
if op4.AuxInt != 0 {
break
}
@ -16586,21 +16600,21 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
}
v.reset(OpStore)
v.Aux = t2
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
v0.AuxInt = o2
v0.AddArg(dst)
v.AddArg(v0)
v.AddArg(d1)
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
v1.Aux = t3
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
v2.AuxInt = o3
v2.AddArg(dst)
v1.AddArg(v2)
v1.AddArg(d2)
v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
v3.Aux = t4
v4 := b.NewValue0(v.Pos, OpOffPtr, t4.(*types.Type))
v4 := b.NewValue0(v.Pos, OpOffPtr, tt4)
v4.AuxInt = 0
v4.AddArg(dst)
v3.AddArg(v4)
@ -16610,9 +16624,9 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
v.AddArg(v1)
return true
}
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [o3] p3) d2 (Store {t4} op4:(OffPtr [o4] p4) d3 (Store {t5} op5:(OffPtr [0] p5) d4 _))))))
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [o3] p3) d2 (Store {t4} op4:(OffPtr <tt4> [o4] p4) d3 (Store {t5} op5:(OffPtr <tt5> [0] p5) d4 _))))))
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && isSamePtr(p4, p5) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && alignof(t4) <= alignof(t1) && alignof(t5) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && registerizable(b, t4) && registerizable(b, t5) && o4 == sizeof(t5) && o3-o4 == sizeof(t4) && o2-o3 == sizeof(t3) && n == sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5)
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2 (Store {t4} (OffPtr <t4.(*types.Type)> [o4] dst) d3 (Store {t5} (OffPtr <t5.(*types.Type)> [0] dst) d4 mem))))
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [o4] dst) d3 (Store {t5} (OffPtr <tt5> [0] dst) d4 mem))))
for {
n := v.AuxInt
t1 := v.Aux
@ -16633,6 +16647,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
if op2.Op != OpOffPtr {
break
}
tt2 := op2.Type
o2 := op2.AuxInt
p2 := op2.Args[0]
d1 := mem_0.Args[1]
@ -16646,6 +16661,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
if op3.Op != OpOffPtr {
break
}
tt3 := op3.Type
o3 := op3.AuxInt
p3 := op3.Args[0]
d2 := mem_0_2.Args[1]
@ -16659,6 +16675,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
if op4.Op != OpOffPtr {
break
}
tt4 := op4.Type
o4 := op4.AuxInt
p4 := op4.Args[0]
d3 := mem_0_2_2.Args[1]
@ -16672,6 +16689,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
if op5.Op != OpOffPtr {
break
}
tt5 := op5.Type
if op5.AuxInt != 0 {
break
}
@ -16682,28 +16700,28 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
}
v.reset(OpStore)
v.Aux = t2
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
v0.AuxInt = o2
v0.AddArg(dst)
v.AddArg(v0)
v.AddArg(d1)
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
v1.Aux = t3
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
v2.AuxInt = o3
v2.AddArg(dst)
v1.AddArg(v2)
v1.AddArg(d2)
v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
v3.Aux = t4
v4 := b.NewValue0(v.Pos, OpOffPtr, t4.(*types.Type))
v4 := b.NewValue0(v.Pos, OpOffPtr, tt4)
v4.AuxInt = o4
v4.AddArg(dst)
v3.AddArg(v4)
v3.AddArg(d3)
v5 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
v5.Aux = t5
v6 := b.NewValue0(v.Pos, OpOffPtr, t5.(*types.Type))
v6 := b.NewValue0(v.Pos, OpOffPtr, tt5)
v6.AuxInt = 0
v6.AddArg(dst)
v5.AddArg(v6)

View File

@ -817,7 +817,7 @@ func (t *Type) ChanArgs() *Type {
return t.Extra.(ChanArgs).T
}
// FuncArgs returns the channel type for TFUNCARGS type t.
// FuncArgs returns the func type for TFUNCARGS type t.
func (t *Type) FuncArgs() *Type {
t.wantEtype(TFUNCARGS)
return t.Extra.(FuncArgs).T

View File

@ -144,7 +144,7 @@
// link against shared libraries previously created with
// -buildmode=shared.
// -mod mode
// module download mode to use: readonly, release, or vendor.
// module download mode to use: readonly or vendor.
// See 'go help modules' for more.
// -pkgdir dir
// install and load all packages from dir instead of the usual locations.
@ -889,7 +889,7 @@
//
// Usage:
//
// go mod download [-dir] [-json] [modules]
// go mod download [-json] [modules]
//
// Download downloads the named modules, which can be module patterns selecting
// dependencies of the main module or module queries of the form path@version.
@ -1449,6 +1449,12 @@
// The directory where the go command will write
// temporary source files, packages, and binaries.
//
// Each entry in the GOFLAGS list must be a standalone flag.
// Because the entries are space-separated, flag values must
// not contain spaces. In some cases, you can provide multiple flag
// values instead: for example, to set '-ldflags=-s -w'
// you can use 'GOFLAGS=-ldflags=-s -ldflags=-w'.
//
// Environment variables for use with cgo:
//
// CC

View File

@ -507,6 +507,12 @@ General-purpose environment variables:
The directory where the go command will write
temporary source files, packages, and binaries.
Each entry in the GOFLAGS list must be a standalone flag.
Because the entries are space-separated, flag values must
not contain spaces. In some cases, you can provide multiple flag
values instead: for example, to set '-ldflags=-s -w'
you can use 'GOFLAGS=-ldflags=-s -ldflags=-w'.
Environment variables for use with cgo:
CC

View File

@ -15,7 +15,7 @@ import (
)
var cmdDownload = &base.Command{
UsageLine: "go mod download [-dir] [-json] [modules]",
UsageLine: "go mod download [-json] [modules]",
Short: "download modules to local cache",
Long: `
Download downloads the named modules, which can be module patterns selecting

View File

@ -694,6 +694,10 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
return nil, "", err
}
if err := ensureGitAttributes(r.dir); err != nil {
return nil, "", err
}
// Incredibly, git produces different archives depending on whether
// it is running on a Windows system or not, in an attempt to normalize
// text file line endings. Setting -c core.autocrlf=input means only
@ -709,3 +713,43 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
return ioutil.NopCloser(bytes.NewReader(archive)), "", nil
}
// ensureGitAttributes makes sure export-subst and export-ignore features are
// disabled for this repo. This is intended to be run prior to running git
// archive so that zip files are generated that produce consistent ziphashes
// for a given revision, independent of variables such as git version and the
// size of the repo.
//
// See: https://github.com/golang/go/issues/27153
func ensureGitAttributes(repoDir string) (err error) {
const attr = "\n* -export-subst -export-ignore\n"
d := repoDir + "/info"
p := d + "/attributes"
if err := os.MkdirAll(d, 0755); err != nil {
return err
}
f, err := os.OpenFile(p, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
return err
}
defer func() {
closeErr := f.Close()
if closeErr != nil {
err = closeErr
}
}()
b, err := ioutil.ReadAll(f)
if err != nil {
return err
}
if !bytes.HasSuffix(b, []byte(attr)) {
_, err := f.WriteString(attr)
return err
}
return nil
}

View File

@ -99,7 +99,7 @@ and test commands:
link against shared libraries previously created with
-buildmode=shared.
-mod mode
module download mode to use: readonly, release, or vendor.
module download mode to use: readonly or vendor.
See 'go help modules' for more.
-pkgdir dir
install and load all packages from dir instead of the usual locations.

View File

@ -224,7 +224,9 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
if len(p.SFiles) > 0 {
fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags)
}
fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(cfg.BuildContext.GOARCH))) // GO386, GOARM, etc
// GO386, GOARM, GOMIPS, etc.
baseArch := strings.TrimSuffix(cfg.BuildContext.GOARCH, "le")
fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(baseArch)))
// TODO(rsc): Convince compiler team not to add more magic environment variables,
// or perhaps restrict the environment variables passed to subprocesses.
@ -2075,14 +2077,37 @@ func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []s
}
// gccld runs the gcc linker to create an executable from a set of object files.
func (b *Builder) gccld(p *load.Package, objdir, out string, flags []string, objs []string) error {
func (b *Builder) gccld(p *load.Package, objdir, outfile string, flags []string, objs []string) error {
var cmd []string
if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
cmd = b.GxxCmd(p.Dir, objdir)
} else {
cmd = b.GccCmd(p.Dir, objdir)
}
return b.run(nil, p.Dir, p.ImportPath, b.cCompilerEnv(), cmd, "-o", out, objs, flags)
cmdargs := []interface{}{cmd, "-o", outfile, objs, flags}
dir := p.Dir
out, err := b.runOut(dir, b.cCompilerEnv(), cmdargs...)
if len(out) > 0 {
// Filter out useless linker warnings caused by bugs outside Go.
// See also cmd/link/internal/ld's hostlink method.
var save [][]byte
for _, line := range bytes.SplitAfter(out, []byte("\n")) {
// golang.org/issue/26073 - Apple Xcode bug
if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
continue
}
save = append(save, line)
}
out = bytes.Join(save, nil)
if len(out) > 0 {
b.showOutput(nil, dir, p.ImportPath, b.processOutput(out))
if err != nil {
err = errPrintedOutput
}
}
}
return err
}
// Grab these before main helpfully overwrites them.

View File

@ -170,6 +170,7 @@ var validLinkerFlags = []*regexp.Regexp{
re(`-Wl,-e[=,][a-zA-Z0-9]*`),
re(`-Wl,--enable-new-dtags`),
re(`-Wl,--end-group`),
re(`-Wl,--(no-)?export-dynamic`),
re(`-Wl,-framework,[^,@\-][^,]+`),
re(`-Wl,-headerpad_max_install_names`),
re(`-Wl,--no-undefined`),

View File

@ -629,6 +629,9 @@ func scriptMatch(ts *testScript, neg bool, args []string, text, name string) {
text = string(data)
}
// Matching against workdir would be misleading.
text = strings.Replace(text, ts.workdir, "$WORK", -1)
if neg {
if re.MatchString(text) {
if isGrep {

View File

@ -0,0 +1,37 @@
# Set up fresh GOCACHE.
env GOCACHE=$WORK/gocache
mkdir $GOCACHE
# Building for mipsle without setting GOMIPS will use floating point registers.
env GOARCH=mipsle
env GOOS=linux
go build -gcflags=-S f.go
stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+
# Clean cache
go clean -cache
# Building with GOMIPS=softfloat will not use floating point registers
env GOMIPS=softfloat
go build -gcflags=-S f.go
! stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+
# Clean cache
go clean -cache
# Build without setting GOMIPS
env GOMIPS=
go build -gcflags=-S f.go
stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+
# Building with GOMIPS should still not use floating point registers.
env GOMIPS=softfloat
go build -gcflags=-S f.go
! stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+
-- f.go --
package f
func F(x float64) float64 {
return x + x
}

View File

@ -0,0 +1,21 @@
env GO111MODULE=on
env GOPROXY=
# Testing that git export-subst is disabled
[!net] skip
[!exec:git] skip
go build
-- x.go --
package x
import _ "github.com/jasonkeene/export-subst"
-- go.mod --
module x
require github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626
-- go.sum --
github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626 h1:AUkXi/xFnm7lH2pgtvVkGb7buRn1ywFHw+xDpZ29Rz0=
github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626/go.mod h1:DwJXqVtrgrQkv3Giuf2Jh4YyubVe7y41S1eOIaysTJw=

View File

@ -1324,9 +1324,24 @@ func (ctxt *Link) hostlink() {
ctxt.Logf("\n")
}
if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput()
if err != nil {
Exitf("running %s failed: %v\n%s", argv[0], err, out)
} else if len(out) > 0 {
}
// Filter out useless linker warnings caused by bugs outside Go.
// See also cmd/go/internal/work/exec.go's gccld method.
var save [][]byte
for _, line := range bytes.SplitAfter(out, []byte("\n")) {
// golang.org/issue/26073 - Apple Xcode bug
if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
continue
}
save = append(save, line)
}
out = bytes.Join(save, nil)
if len(out) > 0 {
// always print external output even if the command is successful, so that we don't
// swallow linker warnings (see https://golang.org/issue/17935).
ctxt.Logf("%s", out)

View File

@ -685,13 +685,14 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
}
ctx.emitSlice(&fakeMarkStart, text)
case trace.EvGCSweepStart:
slice := ctx.emitSlice(ev, "SWEEP")
slice := ctx.makeSlice(ev, "SWEEP")
if done := ev.Link; done != nil && done.Args[0] != 0 {
slice.Arg = struct {
Swept uint64 `json:"Swept bytes"`
Reclaimed uint64 `json:"Reclaimed bytes"`
}{done.Args[0], done.Args[1]}
}
ctx.emit(slice)
case trace.EvGoStart, trace.EvGoStartLabel:
info := getGInfo(ev.G)
if ev.Type == trace.EvGoStartLabel {
@ -846,7 +847,11 @@ func (ctx *traceContext) proc(ev *trace.Event) uint64 {
}
}
func (ctx *traceContext) emitSlice(ev *trace.Event, name string) *ViewerEvent {
func (ctx *traceContext) emitSlice(ev *trace.Event, name string) {
ctx.emit(ctx.makeSlice(ev, name))
}
func (ctx *traceContext) makeSlice(ev *trace.Event, name string) *ViewerEvent {
// If ViewerEvent.Dur is not a positive value,
// trace viewer handles it as a non-terminating time interval.
// Avoid it by setting the field with a small value.
@ -885,7 +890,6 @@ func (ctx *traceContext) emitSlice(ev *trace.Event, name string) *ViewerEvent {
sl.Cname = colorLightGrey
}
}
ctx.emit(sl)
return sl
}

View File

@ -906,8 +906,8 @@ func validHostname(host string) bool {
if c == '-' && j != 0 {
continue
}
if c == '_' {
// _ is not a valid character in hostnames, but it's commonly
if c == '_' || c == ':' {
// Not valid characters in hostnames, but commonly
// found in deployments outside the WebPKI.
continue
}

View File

@ -1881,6 +1881,7 @@ func TestValidHostname(t *testing.T) {
{"foo.*.example.com", false},
{"exa_mple.com", true},
{"foo,bar", false},
{"project-dev:us-central1:main", true},
}
for _, tt := range tests {
if got := validHostname(tt.host); got != tt.want {

View File

@ -1322,11 +1322,13 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
err: err,
}
return true
} else if err == nil && !db.closed && db.maxIdleConnsLocked() > len(db.freeConn) {
db.freeConn = append(db.freeConn, dc)
} else if err == nil && !db.closed {
if db.maxIdleConnsLocked() > len(db.freeConn) {
db.freeConn = append(db.freeConn, dc)
db.startCleanerLocked()
return true
}
db.maxIdleClosed++
db.startCleanerLocked()
return true
}
return false
}

View File

@ -3415,6 +3415,58 @@ func TestConnectionLeak(t *testing.T) {
wg.Wait()
}
func TestStatsMaxIdleClosedZero(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(1)
db.SetConnMaxLifetime(0)
preMaxIdleClosed := db.Stats().MaxIdleClosed
for i := 0; i < 10; i++ {
rows, err := db.Query("SELECT|people|name|")
if err != nil {
t.Fatal(err)
}
rows.Close()
}
st := db.Stats()
maxIdleClosed := st.MaxIdleClosed - preMaxIdleClosed
t.Logf("MaxIdleClosed: %d", maxIdleClosed)
if maxIdleClosed != 0 {
t.Fatal("expected 0 max idle closed conns, got: ", maxIdleClosed)
}
}
func TestStatsMaxIdleClosedTen(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(0)
db.SetConnMaxLifetime(0)
preMaxIdleClosed := db.Stats().MaxIdleClosed
for i := 0; i < 10; i++ {
rows, err := db.Query("SELECT|people|name|")
if err != nil {
t.Fatal(err)
}
rows.Close()
}
st := db.Stats()
maxIdleClosed := st.MaxIdleClosed - preMaxIdleClosed
t.Logf("MaxIdleClosed: %d", maxIdleClosed)
if maxIdleClosed != 10 {
t.Fatal("expected 0 max idle closed conns, got: ", maxIdleClosed)
}
}
type nvcDriver struct {
fakeDriver
skipNamedValueCheck bool

View File

@ -672,6 +672,7 @@ func (d *decodeState) object(v reflect.Value) error {
}
var mapElem reflect.Value
originalErrorContext := d.errorContext
for {
// Read opening " of string key or closing }.
@ -832,8 +833,7 @@ func (d *decodeState) object(v reflect.Value) error {
return errPhase
}
d.errorContext.Struct = ""
d.errorContext.Field = ""
d.errorContext = originalErrorContext
}
return nil
}
@ -991,7 +991,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if fromQuoted {
return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())
}
return &UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}
d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())})
case reflect.Interface:
n, err := d.convertNumber(s)
if err != nil {

View File

@ -371,6 +371,10 @@ func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error {
return (*intWithMarshalText)(b).UnmarshalText(data)
}
type mapStringToStringData struct {
Data map[string]string `json:"data"`
}
type unmarshalTest struct {
in string
ptr interface{}
@ -401,6 +405,7 @@ var unmarshalTests = []unmarshalTest{
{in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
{in: "null", ptr: new(interface{}), out: nil},
{in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7, "T", "X"}},
{in: `{"X": 23}`, ptr: new(T), out: T{}, err: &UnmarshalTypeError{"number", reflect.TypeOf(""), 8, "T", "X"}}, {in: `{"x": 1}`, ptr: new(tx), out: tx{}},
{in: `{"x": 1}`, ptr: new(tx), out: tx{}},
{in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true},
{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
@ -866,6 +871,18 @@ var unmarshalTests = []unmarshalTest{
err: fmt.Errorf("json: unknown field \"extra\""),
disallowUnknownFields: true,
},
// issue 26444
// UnmarshalTypeError without field & struct values
{
in: `{"data":{"test1": "bob", "test2": 123}}`,
ptr: new(mapStringToStringData),
err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 37, Struct: "mapStringToStringData", Field: "data"},
},
{
in: `{"data":{"test1": 123, "test2": "bob"}}`,
ptr: new(mapStringToStringData),
err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 21, Struct: "mapStringToStringData", Field: "data"},
},
}
func TestMarshal(t *testing.T) {

View File

@ -261,6 +261,8 @@ func TestTypesInfo(t *testing.T) {
{`package x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
{`package x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
{`package x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a; f: b;}}`, `b`, `string`},
{`package x3; var x = panic("");`, `panic`, `func(interface{})`},
{`package x4; func _() { panic("") }`, `panic`, `func(interface{})`},
}
for _, test := range tests {

View File

@ -476,7 +476,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// panic(x)
// record panic call if inside a function with result parameters
// (for use in Checker.isTerminating)
if check.sig.results.Len() > 0 {
if check.sig != nil && check.sig.results.Len() > 0 {
// function has result parameters
p := check.isPanic
if p == nil {

View File

@ -355,3 +355,70 @@ func TestIssue25627(t *testing.T) {
})
}
}
func TestIssue28005(t *testing.T) {
// method names must match defining interface name for this test
// (see last comment in this function)
sources := [...]string{
"package p; type A interface{ A() }",
"package p; type B interface{ B() }",
"package p; type X interface{ A; B }",
}
// compute original file ASTs
var orig [len(sources)]*ast.File
for i, src := range sources {
f, err := parser.ParseFile(fset, "", src, 0)
if err != nil {
t.Fatal(err)
}
orig[i] = f
}
// run the test for all order permutations of the incoming files
for _, perm := range [][len(sources)]int{
{0, 1, 2},
{0, 2, 1},
{1, 0, 2},
{1, 2, 0},
{2, 0, 1},
{2, 1, 0},
} {
// create file order permutation
files := make([]*ast.File, len(sources))
for i := range perm {
files[i] = orig[perm[i]]
}
// type-check package with given file order permutation
var conf Config
info := &Info{Defs: make(map[*ast.Ident]Object)}
_, err := conf.Check("", fset, files, info)
if err != nil {
t.Fatal(err)
}
// look for interface object X
var obj Object
for name, def := range info.Defs {
if name.Name == "X" {
obj = def
break
}
}
if obj == nil {
t.Fatal("interface not found")
}
iface := obj.Type().Underlying().(*Interface) // I must be an interface
// Each iface method m is embedded; and m's receiver base type name
// must match the method's name per the choice in the source file.
for i := 0; i < iface.NumMethods(); i++ {
m := iface.Method(i)
recvName := m.Type().(*Signature).Recv().Type().(*Named).Obj().Name()
if recvName != m.Name() {
t.Errorf("perm %v: got recv %s; want %s", perm, recvName, m.Name())
}
}
}
}

View File

@ -571,6 +571,15 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
recvTyp = def
}
// Correct receiver type for all methods explicitly declared
// by this interface after we're done with type-checking at
// this level. See comment below for details.
check.later(func() {
for _, m := range ityp.methods {
m.typ.(*Signature).recv.typ = recvTyp
}
})
// collect methods
var sigfix []*methodInfo
for i, minfo := range info.methods {
@ -580,9 +589,27 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
pos := name.Pos()
// Don't type-check signature yet - use an
// empty signature now and update it later.
// Since we know the receiver, set it up now
// (required to avoid crash in ptrRecv; see
// e.g. test case for issue 6638).
// But set up receiver since we know it and
// its position, and because interface method
// signatures don't get a receiver via regular
// type-checking (there isn't a receiver in the
// method's AST). Setting the receiver type is
// also important for ptrRecv() (see methodset.go).
//
// Note: For embedded methods, the receiver type
// should be the type of the interface that declared
// the methods in the first place. Since we get the
// methods here via methodInfo, which may be computed
// before we have all relevant interface types, we use
// the current interface's type (recvType). This may be
// the type of the interface embedding the interface that
// declared the methods. This doesn't matter for type-
// checking (we only care about the receiver type for
// the ptrRecv predicate, and it's never a pointer recv
// for interfaces), but it matters for go/types clients
// and for printing. We correct the receiver after type-
// checking.
//
// TODO(gri) Consider marking methods signatures
// as incomplete, for better error messages. See
// also the T4 and T5 tests in testdata/cycles2.src.

View File

@ -38,5 +38,11 @@ func SendFile(fd *FD, src syscall.Handle, n int64) (int64, error) {
done, err := wsrv.ExecIO(o, func(o *operation) error {
return syscall.TransmitFile(o.fd.Sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
})
if err == nil {
// Some versions of Windows (Windows 10 1803) do not set
// file position after TransmitFile completes.
// So just use Seek to set file position.
_, err = syscall.Seek(o.handle, curpos+int64(done), 0)
}
return int64(done), err
}

View File

@ -27,6 +27,20 @@ import (
"golang_org/x/net/dns/dnsmessage"
)
var (
errLameReferral = errors.New("lame referral")
errCannotUnmarshalDNSMessage = errors.New("cannot unmarshal DNS message")
errCannotMarshalDNSMessage = errors.New("cannot marshal DNS message")
errServerMisbehaving = errors.New("server misbehaving")
errInvalidDNSResponse = errors.New("invalid DNS response")
errNoAnswerFromDNSServer = errors.New("no answer from DNS server")
// errServerTemporarlyMisbehaving is like errServerMisbehaving, except
// that when it gets translated to a DNSError, the IsTemporary field
// gets set to true.
errServerTemporarlyMisbehaving = errors.New("server misbehaving")
)
func newRequest(q dnsmessage.Question) (id uint16, udpReq, tcpReq []byte, err error) {
id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
b := dnsmessage.NewBuilder(make([]byte, 2, 514), dnsmessage.Header{ID: id, RecursionDesired: true})
@ -105,14 +119,14 @@ func dnsStreamRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte)
var p dnsmessage.Parser
h, err := p.Start(b[:n])
if err != nil {
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot unmarshal DNS message")
return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
}
q, err := p.Question()
if err != nil {
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot unmarshal DNS message")
return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
}
if !checkResponse(id, query, h, q) {
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("invalid DNS response")
return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
}
return p, h, nil
}
@ -122,7 +136,7 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que
q.Class = dnsmessage.ClassINET
id, udpReq, tcpReq, err := newRequest(q)
if err != nil {
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot marshal DNS message")
return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotMarshalDNSMessage
}
for _, network := range []string{"udp", "tcp"} {
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
@ -147,31 +161,31 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que
return dnsmessage.Parser{}, dnsmessage.Header{}, mapErr(err)
}
if err := p.SkipQuestion(); err != dnsmessage.ErrSectionDone {
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("invalid DNS response")
return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
}
if h.Truncated { // see RFC 5966
continue
}
return p, h, nil
}
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("no answer from DNS server")
return dnsmessage.Parser{}, dnsmessage.Header{}, errNoAnswerFromDNSServer
}
// checkHeader performs basic sanity checks on the header.
func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header, name, server string) error {
if h.RCode == dnsmessage.RCodeNameError {
return errNoSuchHost
}
_, err := p.AnswerHeader()
if err != nil && err != dnsmessage.ErrSectionDone {
return &DNSError{
Err: "cannot unmarshal DNS message",
Name: name,
Server: server,
}
return errCannotUnmarshalDNSMessage
}
// libresolv continues to the next server when it receives
// an invalid referral response. See golang.org/issue/15434.
if h.RCode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone {
return &DNSError{Err: "lame referral", Name: name, Server: server}
return errLameReferral
}
if h.RCode != dnsmessage.RCodeSuccess && h.RCode != dnsmessage.RCodeNameError {
@ -180,11 +194,10 @@ func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header, name, server string)
// a name error and we didn't get success,
// the server is behaving incorrectly or
// having temporary trouble.
err := &DNSError{Err: "server misbehaving", Name: name, Server: server}
if h.RCode == dnsmessage.RCodeServerFailure {
err.IsTemporary = true
return errServerTemporarlyMisbehaving
}
return err
return errServerMisbehaving
}
return nil
@ -194,28 +207,16 @@ func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type, name, server stri
for {
h, err := p.AnswerHeader()
if err == dnsmessage.ErrSectionDone {
return &DNSError{
Err: errNoSuchHost.Error(),
Name: name,
Server: server,
}
return errNoSuchHost
}
if err != nil {
return &DNSError{
Err: "cannot unmarshal DNS message",
Name: name,
Server: server,
}
return errCannotUnmarshalDNSMessage
}
if h.Type == qtype {
return nil
}
if err := p.SkipAnswer(); err != nil {
return &DNSError{
Err: "cannot unmarshal DNS message",
Name: name,
Server: server,
}
return errCannotUnmarshalDNSMessage
}
}
}
@ -229,7 +230,7 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string,
n, err := dnsmessage.NewName(name)
if err != nil {
return dnsmessage.Parser{}, "", errors.New("cannot marshal DNS message")
return dnsmessage.Parser{}, "", errCannotMarshalDNSMessage
}
q := dnsmessage.Question{
Name: n,
@ -243,38 +244,62 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string,
p, h, err := r.exchange(ctx, server, q, cfg.timeout)
if err != nil {
lastErr = &DNSError{
dnsErr := &DNSError{
Err: err.Error(),
Name: name,
Server: server,
}
if nerr, ok := err.(Error); ok && nerr.Timeout() {
lastErr.(*DNSError).IsTimeout = true
dnsErr.IsTimeout = true
}
// Set IsTemporary for socket-level errors. Note that this flag
// may also be used to indicate a SERVFAIL response.
if _, ok := err.(*OpError); ok {
lastErr.(*DNSError).IsTemporary = true
dnsErr.IsTemporary = true
}
lastErr = dnsErr
continue
}
// The name does not exist, so trying another server won't help.
//
// TODO: indicate this in a more obvious way, such as a field on DNSError?
if h.RCode == dnsmessage.RCodeNameError {
return dnsmessage.Parser{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server}
}
lastErr = checkHeader(&p, h, name, server)
if lastErr != nil {
if err := checkHeader(&p, h, name, server); err != nil {
dnsErr := &DNSError{
Err: err.Error(),
Name: name,
Server: server,
}
if err == errServerTemporarlyMisbehaving {
dnsErr.IsTemporary = true
}
if err == errNoSuchHost {
// The name does not exist, so trying
// another server won't help.
//
// TODO: indicate this in a more
// obvious way, such as a field on
// DNSError?
return p, server, dnsErr
}
lastErr = dnsErr
continue
}
lastErr = skipToAnswer(&p, qtype, name, server)
if lastErr == nil {
err = skipToAnswer(&p, qtype, name, server)
if err == nil {
return p, server, nil
}
lastErr = &DNSError{
Err: err.Error(),
Name: name,
Server: server,
}
if err == errNoSuchHost {
// The name does not exist, so trying another
// server won't help.
//
// TODO: indicate this in a more obvious way,
// such as a field on DNSError?
return p, server, lastErr
}
}
}
return dnsmessage.Parser{}, "", lastErr

View File

@ -1427,28 +1427,35 @@ func TestDNSGoroutineRace(t *testing.T) {
}
}
func lookupWithFake(fake fakeDNSServer, name string, typ dnsmessage.Type) error {
r := Resolver{PreferGo: true, Dial: fake.DialContext}
resolvConf.mu.RLock()
conf := resolvConf.dnsConfig
resolvConf.mu.RUnlock()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
_, _, err := r.tryOneName(ctx, conf, name, typ)
return err
}
// Issue 8434: verify that Temporary returns true on an error when rcode
// is SERVFAIL
func TestIssue8434(t *testing.T) {
msg := dnsmessage.Message{
Header: dnsmessage.Header{
RCode: dnsmessage.RCodeServerFailure,
err := lookupWithFake(fakeDNSServer{
rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
return dnsmessage.Message{
Header: dnsmessage.Header{
ID: q.ID,
Response: true,
RCode: dnsmessage.RCodeServerFailure,
},
Questions: q.Questions,
}, nil
},
}
b, err := msg.Pack()
if err != nil {
t.Fatal("Pack failed:", err)
}
var p dnsmessage.Parser
h, err := p.Start(b)
if err != nil {
t.Fatal("Start failed:", err)
}
if err := p.SkipAllQuestions(); err != nil {
t.Fatal("SkipAllQuestions failed:", err)
}
err = checkHeader(&p, h, "golang.org", "foo:53")
}, "golang.org.", dnsmessage.TypeALL)
if err == nil {
t.Fatal("expected an error")
}
@ -1464,50 +1471,76 @@ func TestIssue8434(t *testing.T) {
}
}
// Issue 12778: verify that NXDOMAIN without RA bit errors as
// "no such host" and not "server misbehaving"
// TestNoSuchHost verifies that tryOneName works correctly when the domain does
// not exist.
//
// Issue 12778: verify that NXDOMAIN without RA bit errors as "no such host"
// and not "server misbehaving"
//
// Issue 25336: verify that NXDOMAIN errors fail fast.
func TestIssue12778(t *testing.T) {
lookups := 0
fake := fakeDNSServer{
rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
lookups++
return dnsmessage.Message{
Header: dnsmessage.Header{
ID: q.ID,
Response: true,
RCode: dnsmessage.RCodeNameError,
RecursionAvailable: false,
},
Questions: q.Questions,
}, nil
//
// Issue 27525: verify that empty answers fail fast.
func TestNoSuchHost(t *testing.T) {
tests := []struct {
name string
f func(string, string, dnsmessage.Message, time.Time) (dnsmessage.Message, error)
}{
{
"NXDOMAIN",
func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
return dnsmessage.Message{
Header: dnsmessage.Header{
ID: q.ID,
Response: true,
RCode: dnsmessage.RCodeNameError,
RecursionAvailable: false,
},
Questions: q.Questions,
}, nil
},
},
{
"no answers",
func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
return dnsmessage.Message{
Header: dnsmessage.Header{
ID: q.ID,
Response: true,
RCode: dnsmessage.RCodeSuccess,
RecursionAvailable: false,
Authoritative: true,
},
Questions: q.Questions,
}, nil
},
},
}
r := Resolver{PreferGo: true, Dial: fake.DialContext}
resolvConf.mu.RLock()
conf := resolvConf.dnsConfig
resolvConf.mu.RUnlock()
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
lookups := 0
err := lookupWithFake(fakeDNSServer{
rh: func(n, s string, q dnsmessage.Message, d time.Time) (dnsmessage.Message, error) {
lookups++
return test.f(n, s, q, d)
},
}, ".", dnsmessage.TypeALL)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if lookups != 1 {
t.Errorf("got %d lookups, wanted 1", lookups)
}
_, _, err := r.tryOneName(ctx, conf, ".", dnsmessage.TypeALL)
if lookups != 1 {
t.Errorf("got %d lookups, wanted 1", lookups)
}
if err == nil {
t.Fatal("expected an error")
}
de, ok := err.(*DNSError)
if !ok {
t.Fatalf("err = %#v; wanted a *net.DNSError", err)
}
if de.Err != errNoSuchHost.Error() {
t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error())
if err == nil {
t.Fatal("expected an error")
}
de, ok := err.(*DNSError)
if !ok {
t.Fatalf("err = %#v; wanted a *net.DNSError", err)
}
if de.Err != errNoSuchHost.Error() {
t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error())
}
})
}
}
@ -1535,3 +1568,56 @@ func TestDNSDialTCP(t *testing.T) {
t.Fatal("exhange failed:", err)
}
}
// Issue 27763: verify that two strings in one TXT record are concatenated.
func TestTXTRecordTwoStrings(t *testing.T) {
fake := fakeDNSServer{
rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
r := dnsmessage.Message{
Header: dnsmessage.Header{
ID: q.Header.ID,
Response: true,
RCode: dnsmessage.RCodeSuccess,
},
Questions: q.Questions,
Answers: []dnsmessage.Resource{
{
Header: dnsmessage.ResourceHeader{
Name: q.Questions[0].Name,
Type: dnsmessage.TypeA,
Class: dnsmessage.ClassINET,
},
Body: &dnsmessage.TXTResource{
TXT: []string{"string1 ", "string2"},
},
},
{
Header: dnsmessage.ResourceHeader{
Name: q.Questions[0].Name,
Type: dnsmessage.TypeA,
Class: dnsmessage.ClassINET,
},
Body: &dnsmessage.TXTResource{
TXT: []string{"onestring"},
},
},
},
}
return r, nil
},
}
r := Resolver{PreferGo: true, Dial: fake.DialContext}
txt, err := r.lookupTXT(context.Background(), "golang.org")
if err != nil {
t.Fatal("LookupTXT failed:", err)
}
if want := 2; len(txt) != want {
t.Fatalf("len(txt), got %d, want %d", len(txt), want)
}
if want := "string1 string2"; txt[0] != want {
t.Errorf("txt[0], got %q, want %q", txt[0], want)
}
if want := "onestring"; txt[1] != want {
t.Errorf("txt[1], got %q, want %q", txt[1], want)
}
}

View File

@ -116,7 +116,9 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
b := result.Get("body")
var body io.ReadCloser
if b != js.Undefined() {
// The body is undefined when the browser does not support streaming response bodies (Firefox),
// and null in certain error cases, i.e. when the request is blocked because of CORS settings.
if b != js.Undefined() && b != js.Null() {
body = &streamReader{stream: b.Call("getReader")}
} else {
// Fall back to using ArrayBuffer

View File

@ -299,11 +299,21 @@ func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error)
Server: server,
}
}
if len(txts) == 0 {
txts = txt.TXT
} else {
txts = append(txts, txt.TXT...)
// Multiple strings in one TXT record need to be
// concatenated without separator to be consistent
// with previous Go resolver.
n := 0
for _, s := range txt.TXT {
n += len(s)
}
txtJoin := make([]byte, 0, n)
for _, s := range txt.TXT {
txtJoin = append(txtJoin, s...)
}
if len(txts) == 0 {
txts = make([]string, 0, 1)
}
txts = append(txts, string(txtJoin))
}
return txts, nil
}

View File

@ -122,6 +122,7 @@ func testSpliceBig(t *testing.T) {
func testSpliceHonorsLimitedReader(t *testing.T) {
t.Run("stopsAfterN", testSpliceStopsAfterN)
t.Run("updatesN", testSpliceUpdatesN)
t.Run("readerAtLimit", testSpliceReaderAtLimit)
}
func testSpliceStopsAfterN(t *testing.T) {
@ -208,7 +209,7 @@ func testSpliceUpdatesN(t *testing.T) {
}
}
func testSpliceReaderAtEOF(t *testing.T) {
func testSpliceReaderAtLimit(t *testing.T) {
clientUp, serverUp, err := spliceTestSocketPair("tcp")
if err != nil {
t.Fatal(err)
@ -222,21 +223,63 @@ func testSpliceReaderAtEOF(t *testing.T) {
defer clientDown.Close()
defer serverDown.Close()
serverUp.Close()
_, err, handled := splice(serverDown.(*TCPConn).fd, serverUp)
if !handled {
t.Errorf("closed connection: got err = %v, handled = %t, want handled = true", err, handled)
}
lr := &io.LimitedReader{
N: 0,
R: serverUp,
}
_, err, handled = splice(serverDown.(*TCPConn).fd, lr)
_, err, handled := splice(serverDown.(*TCPConn).fd, lr)
if !handled {
t.Errorf("exhausted LimitedReader: got err = %v, handled = %t, want handled = true", err, handled)
}
}
func testSpliceReaderAtEOF(t *testing.T) {
clientUp, serverUp, err := spliceTestSocketPair("tcp")
if err != nil {
t.Fatal(err)
}
defer clientUp.Close()
clientDown, serverDown, err := spliceTestSocketPair("tcp")
if err != nil {
t.Fatal(err)
}
defer clientDown.Close()
serverUp.Close()
// We'd like to call net.splice here and check the handled return
// value, but we disable splice on old Linux kernels.
//
// In that case, poll.Splice and net.splice return a non-nil error
// and handled == false. We'd ideally like to see handled == true
// because the source reader is at EOF, but if we're running on an old
// kernel, and splice is disabled, we won't see EOF from net.splice,
// because we won't touch the reader at all.
//
// Trying to untangle the errors from net.splice and match them
// against the errors created by the poll package would be brittle,
// so this is a higher level test.
//
// The following ReadFrom should return immediately, regardless of
// whether splice is disabled or not. The other side should then
// get a goodbye signal. Test for the goodbye signal.
msg := "bye"
go func() {
serverDown.(*TCPConn).ReadFrom(serverUp)
io.WriteString(serverDown, msg)
serverDown.Close()
}()
buf := make([]byte, 3)
_, err = io.ReadFull(clientDown, buf)
if err != nil {
t.Errorf("clientDown: %v", err)
}
if string(buf) != msg {
t.Errorf("clientDown got %q, want %q", buf, msg)
}
}
func testSpliceIssue25985(t *testing.T) {
front, err := newLocalListener("tcp")
if err != nil {

View File

@ -5844,7 +5844,7 @@ func clobber() {
type funcLayoutTest struct {
rcvr, t Type
size, argsize, retOffset uintptr
stack []byte // pointer bitmap: 1 is pointer, 0 is scalar (or uninitialized)
stack []byte // pointer bitmap: 1 is pointer, 0 is scalar
gc []byte
}
@ -5866,7 +5866,7 @@ func init() {
6 * PtrSize,
4 * PtrSize,
4 * PtrSize,
[]byte{1, 0, 1},
[]byte{1, 0, 1, 0, 1},
[]byte{1, 0, 1, 0, 1},
})

View File

@ -9,11 +9,14 @@
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVL DX, 0(SP)
LEAL argframe+0(FP), CX
MOVL CX, 4(SP)
MOVB $0, 12(SP)
LEAL 12(SP), AX
MOVL AX, 8(SP)
CALL ·callReflect(SB)
RET
@ -21,10 +24,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVL DX, 0(SP)
LEAL argframe+0(FP), CX
MOVL CX, 4(SP)
MOVB $0, 12(SP)
LEAL 12(SP), AX
MOVL AX, 8(SP)
CALL ·callMethod(SB)
RET

View File

@ -9,11 +9,14 @@
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVQ DX, 0(SP)
LEAQ argframe+0(FP), CX
MOVQ CX, 8(SP)
MOVB $0, 24(SP)
LEAQ 24(SP), AX
MOVQ AX, 16(SP)
CALL ·callReflect(SB)
RET
@ -21,10 +24,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVQ DX, 0(SP)
LEAQ argframe+0(FP), CX
MOVQ CX, 8(SP)
MOVB $0, 24(SP)
LEAQ 24(SP), AX
MOVQ AX, 16(SP)
CALL ·callMethod(SB)
RET

View File

@ -9,11 +9,14 @@
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVL DX, 0(SP)
LEAL argframe+0(FP), CX
MOVL CX, 4(SP)
MOVB $0, 12(SP)
LEAL 12(SP), AX
MOVL AX, 8(SP)
CALL ·callReflect(SB)
RET
@ -21,10 +24,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVL DX, 0(SP)
LEAL argframe+0(FP), CX
MOVL CX, 4(SP)
MOVB $0, 12(SP)
LEAL 12(SP), AX
MOVL AX, 8(SP)
CALL ·callMethod(SB)
RET

View File

@ -9,11 +9,15 @@
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVW R7, 4(R13)
MOVW $argframe+0(FP), R1
MOVW R1, 8(R13)
MOVW $0, R1
MOVB R1, 16(R13)
ADD $16, R13, R1
MOVW R1, 12(R13)
BL ·callReflect(SB)
RET
@ -21,10 +25,14 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVW R7, 4(R13)
MOVW $argframe+0(FP), R1
MOVW R1, 8(R13)
MOVW $0, R1
MOVB R1, 16(R13)
ADD $16, R13, R1
MOVW R1, 12(R13)
BL ·callMethod(SB)
RET

View File

@ -9,11 +9,14 @@
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here, runtime pulls arg map out of the func value.
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$24
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$40
NO_LOCAL_POINTERS
MOVD R26, 8(RSP)
MOVD $argframe+0(FP), R3
MOVD R3, 16(RSP)
MOVB $0, 32(RSP)
ADD $32, RSP, R3
MOVD R3, 24(RSP)
BL ·callReflect(SB)
RET
@ -21,10 +24,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$24
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$24
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$40
NO_LOCAL_POINTERS
MOVD R26, 8(RSP)
MOVD $argframe+0(FP), R3
MOVD R3, 16(RSP)
MOVB $0, 32(RSP)
ADD $32, RSP, R3
MOVD R3, 24(RSP)
BL ·callMethod(SB)
RET

View File

@ -13,11 +13,14 @@
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here, runtime pulls arg map out of the func value.
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVV REGCTXT, 8(R29)
MOVV $argframe+0(FP), R1
MOVV R1, 16(R29)
MOVB R0, 32(R29)
ADDV $32, R29, R1
MOVV R1, 24(R29)
JAL ·callReflect(SB)
RET
@ -25,10 +28,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVV REGCTXT, 8(R29)
MOVV $argframe+0(FP), R1
MOVV R1, 16(R29)
MOVB R0, 32(R29)
ADDV $32, R29, R1
MOVV R1, 24(R29)
JAL ·callMethod(SB)
RET

View File

@ -13,11 +13,14 @@
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here, runtime pulls arg map out of the func value.
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVW REGCTXT, 4(R29)
MOVW $argframe+0(FP), R1
MOVW R1, 8(R29)
MOVB R0, 16(R29)
ADD $16, R29, R1
MOVW R1, 12(R29)
JAL ·callReflect(SB)
RET
@ -25,10 +28,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVW REGCTXT, 4(R29)
MOVW $argframe+0(FP), R1
MOVW R1, 8(R29)
MOVB R0, 16(R29)
ADD $16, R29, R1
MOVW R1, 12(R29)
JAL ·callMethod(SB)
RET

View File

@ -12,11 +12,14 @@
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here, runtime pulls arg map out of the func value.
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVD R11, FIXED_FRAME+0(R1)
MOVD $argframe+0(FP), R3
MOVD R3, FIXED_FRAME+8(R1)
MOVB R0, FIXED_FRAME+24(R1)
ADD $FIXED_FRAME+24, R1, R3
MOVD R3, FIXED_FRAME+16(R1)
BL ·callReflect(SB)
RET
@ -24,10 +27,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVD R11, FIXED_FRAME+0(R1)
MOVD $argframe+0(FP), R3
MOVD R3, FIXED_FRAME+8(R1)
MOVB R0, FIXED_FRAME+24(R1)
ADD $FIXED_FRAME+24, R1, R3
MOVD R3, FIXED_FRAME+16(R1)
BL ·callMethod(SB)
RET

View File

@ -9,11 +9,14 @@
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here, runtime pulls arg map out of the func value.
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVD R12, 8(R15)
MOVD $argframe+0(FP), R3
MOVD R3, 16(R15)
MOVB $0, 32(R15)
ADD $32, R15, R3
MOVD R3, 24(R15)
BL ·callReflect(SB)
RET
@ -21,10 +24,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVD R12, 8(R15)
MOVD $argframe+0(FP), R3
MOVD R3, 16(R15)
MOVB $0, 32(R15)
ADD $32, R15, R3
MOVD R3, 24(R15)
BL ·callMethod(SB)
RET

View File

@ -9,7 +9,7 @@
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVD CTXT, 0(SP)
@ -21,6 +21,9 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
I64Add
I64Store $8
MOVB $0, 24(SP)
MOVD $24(SP), 16(SP)
CALL ·callReflect(SB)
RET
@ -28,7 +31,7 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVD CTXT, 0(SP)
@ -40,5 +43,8 @@ TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
I64Add
I64Store $8
MOVB $0, 24(SP)
MOVD $24(SP), 16(SP)
CALL ·callMethod(SB)
RET

View File

@ -25,9 +25,9 @@ func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr,
var ft *rtype
var s *bitVector
if rcvr != nil {
ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), rcvr.(*rtype))
ft, argSize, retOffset, s, _ = funcLayout((*funcType)(unsafe.Pointer(t.(*rtype))), rcvr.(*rtype))
} else {
ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), nil)
ft, argSize, retOffset, s, _ = funcLayout((*funcType)(unsafe.Pointer(t.(*rtype))), nil)
}
frametype = ft
for i := uint32(0); i < s.n; i++ {

View File

@ -12,14 +12,15 @@ import (
// makeFuncImpl is the closure value implementing the function
// returned by MakeFunc.
// The first two words of this type must be kept in sync with
// The first three words of this type must be kept in sync with
// methodValue and runtime.reflectMethodValue.
// Any changes should be reflected in all three.
type makeFuncImpl struct {
code uintptr
stack *bitVector
typ *funcType
fn func([]Value) []Value
code uintptr
stack *bitVector // ptrmap for both args and results
argLen uintptr // just args
ftyp *funcType
fn func([]Value) []Value
}
// MakeFunc returns a new function of the given Type
@ -59,9 +60,9 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
code := **(**uintptr)(unsafe.Pointer(&dummy))
// makeFuncImpl contains a stack map for use by the runtime
_, _, _, stack, _ := funcLayout(t, nil)
_, argLen, _, stack, _ := funcLayout(ftyp, nil)
impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn}
impl := &makeFuncImpl{code: code, stack: stack, argLen: argLen, ftyp: ftyp, fn: fn}
return Value{t, unsafe.Pointer(impl), flag(Func)}
}
@ -73,12 +74,13 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
// word in the passed-in argument frame.
func makeFuncStub()
// The first two words of this type must be kept in sync with
// The first 3 words of this type must be kept in sync with
// makeFuncImpl and runtime.reflectMethodValue.
// Any changes should be reflected in all three.
type methodValue struct {
fn uintptr
stack *bitVector
stack *bitVector // ptrmap for both args and results
argLen uintptr // just args
method int
rcvr Value
}
@ -101,7 +103,7 @@ func makeMethodValue(op string, v Value) Value {
rcvr := Value{v.typ, v.ptr, fl}
// v.Type returns the actual type of the method value.
funcType := v.Type().(*rtype)
ftyp := (*funcType)(unsafe.Pointer(v.Type().(*rtype)))
// Indirect Go func value (dummy) to obtain
// actual code address. (A Go func value is a pointer
@ -110,11 +112,12 @@ func makeMethodValue(op string, v Value) Value {
code := **(**uintptr)(unsafe.Pointer(&dummy))
// methodValue contains a stack map for use by the runtime
_, _, _, stack, _ := funcLayout(funcType, nil)
_, argLen, _, stack, _ := funcLayout(ftyp, nil)
fv := &methodValue{
fn: code,
stack: stack,
argLen: argLen,
method: int(v.flag) >> flagMethodShift,
rcvr: rcvr,
}
@ -124,7 +127,7 @@ func makeMethodValue(op string, v Value) Value {
// but we want Interface() and other operations to fail early.
methodReceiver(op, fv.rcvr, fv.method)
return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
return Value{&ftyp.rtype, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
}
// methodValueCall is an assembly function that is the code half of

View File

@ -3022,8 +3022,8 @@ func toType(t *rtype) Type {
}
type layoutKey struct {
t *rtype // function signature
rcvr *rtype // receiver type, or nil if none
ftyp *funcType // function signature
rcvr *rtype // receiver type, or nil if none
}
type layoutType struct {
@ -3042,7 +3042,7 @@ var layoutCache sync.Map // map[layoutKey]layoutType
// The returned type exists only for GC, so we only fill out GC relevant info.
// Currently, that's just size and the GC program. We also fill in
// the name for possible debugging use.
func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stk *bitVector, framePool *sync.Pool) {
func funcLayout(t *funcType, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stk *bitVector, framePool *sync.Pool) {
if t.Kind() != Func {
panic("reflect: funcLayout of non-func type")
}
@ -3055,8 +3055,6 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
return lt.t, lt.argSize, lt.retOffset, lt.stack, lt.framePool
}
tt := (*funcType)(unsafe.Pointer(t))
// compute gc program & stack bitmap for arguments
ptrmap := new(bitVector)
var offset uintptr
@ -3066,22 +3064,23 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
// space no matter how big they actually are.
if ifaceIndir(rcvr) || rcvr.pointers() {
ptrmap.append(1)
} else {
ptrmap.append(0)
}
offset += ptrSize
}
for _, arg := range tt.in() {
for _, arg := range t.in() {
offset += -offset & uintptr(arg.align-1)
addTypeBits(ptrmap, offset, arg)
offset += arg.size
}
argN := ptrmap.n
argSize = offset
if runtime.GOARCH == "amd64p32" {
offset += -offset & (8 - 1)
}
offset += -offset & (ptrSize - 1)
retOffset = offset
for _, res := range tt.out() {
for _, res := range t.out() {
offset += -offset & uintptr(res.align-1)
addTypeBits(ptrmap, offset, res)
offset += res.size
@ -3102,7 +3101,6 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
} else {
x.kind |= kindNoPointers
}
ptrmap.n = argN
var s string
if rcvr != nil {

View File

@ -325,7 +325,7 @@ var callGC bool // for testing; see TestCallMethodJump
func (v Value) call(op string, in []Value) []Value {
// Get function pointer, type.
t := v.typ
t := (*funcType)(unsafe.Pointer(v.typ))
var (
fn unsafe.Pointer
rcvr Value
@ -453,15 +453,14 @@ func (v Value) call(op string, in []Value) []Value {
var ret []Value
if nout == 0 {
// This is untyped because the frame is really a
// stack, even though it's a heap object.
memclrNoHeapPointers(args, frametype.size)
typedmemclr(frametype, args)
framePool.Put(args)
} else {
// Zero the now unused input area of args,
// because the Values returned by this function contain pointers to the args object,
// and will thus keep the args object alive indefinitely.
memclrNoHeapPointers(args, retOffset)
typedmemclrpartial(frametype, args, 0, retOffset)
// Wrap Values around return values in args.
ret = make([]Value, nout)
off = retOffset
@ -472,6 +471,10 @@ func (v Value) call(op string, in []Value) []Value {
if tv.Size() != 0 {
fl := flagIndir | flag(tv.Kind())
ret[i] = Value{tv.common(), add(args, off, "tv.Size() != 0"), fl}
// Note: this does introduce false sharing between results -
// if any result is live, they are all live.
// (And the space for the args is live as well, but as we've
// cleared that space it isn't as big a deal.)
} else {
// For zero-sized return value, args+off may point to the next object.
// In this case, return the zero value instead.
@ -496,8 +499,13 @@ func (v Value) call(op string, in []Value) []Value {
// NOTE: This function must be marked as a "wrapper" in the generated code,
// so that the linker can make it work correctly for panic and recover.
// The gc compilers know to do that for the name "reflect.callReflect".
func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
ftyp := ctxt.typ
//
// ctxt is the "closure" generated by MakeFunc.
// frame is a pointer to the arguments to that closure on the stack.
// retValid points to a boolean which should be set when the results
// section of frame is set.
func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool) {
ftyp := ctxt.ftyp
f := ctxt.fn
// Copy argument frame into Values.
@ -562,6 +570,16 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
}
}
// Announce that the return values are valid.
// After this point the runtime can depend on the return values being valid.
*retValid = true
// We have to make sure that the out slice lives at least until
// the runtime knows the return values are valid. Otherwise, the
// return values might not be scanned by anyone during a GC.
// (out would be dead, and the return slots not yet alive.)
runtime.KeepAlive(out)
// runtime.getArgInfo expects to be able to find ctxt on the
// stack when it finds our caller, makeFuncStub. Make sure it
// doesn't get garbage collected.
@ -575,7 +593,7 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
// The return value rcvrtype gives the method's actual receiver type.
// The return value t gives the method type signature (without the receiver).
// The return value fn is a pointer to the method code.
func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn unsafe.Pointer) {
func methodReceiver(op string, v Value, methodIndex int) (rcvrtype *rtype, t *funcType, fn unsafe.Pointer) {
i := methodIndex
if v.typ.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(v.typ))
@ -592,7 +610,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn
}
rcvrtype = iface.itab.typ
fn = unsafe.Pointer(&iface.itab.fun[i])
t = tt.typeOff(m.typ)
t = (*funcType)(unsafe.Pointer(tt.typeOff(m.typ)))
} else {
rcvrtype = v.typ
ms := v.typ.exportedMethods()
@ -605,7 +623,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn
}
ifn := v.typ.textOff(m.ifn)
fn = unsafe.Pointer(&ifn)
t = v.typ.typeOff(m.mtyp)
t = (*funcType)(unsafe.Pointer(v.typ.typeOff(m.mtyp)))
}
return
}
@ -644,23 +662,31 @@ func align(x, n uintptr) uintptr {
// NOTE: This function must be marked as a "wrapper" in the generated code,
// so that the linker can make it work correctly for panic and recover.
// The gc compilers know to do that for the name "reflect.callMethod".
func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
//
// ctxt is the "closure" generated by makeVethodValue.
// frame is a pointer to the arguments to that closure on the stack.
// retValid points to a boolean which should be set when the results
// section of frame is set.
func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool) {
rcvr := ctxt.rcvr
rcvrtype, t, fn := methodReceiver("call", rcvr, ctxt.method)
frametype, argSize, retOffset, _, framePool := funcLayout(t, rcvrtype)
// Make a new frame that is one word bigger so we can store the receiver.
args := framePool.Get().(unsafe.Pointer)
// This space is used for both arguments and return values.
scratch := framePool.Get().(unsafe.Pointer)
// Copy in receiver and rest of args.
// Avoid constructing out-of-bounds pointers if there are no args.
storeRcvr(rcvr, args)
storeRcvr(rcvr, scratch)
if argSize-ptrSize > 0 {
typedmemmovepartial(frametype, add(args, ptrSize, "argSize > ptrSize"), frame, ptrSize, argSize-ptrSize)
typedmemmovepartial(frametype, add(scratch, ptrSize, "argSize > ptrSize"), frame, ptrSize, argSize-ptrSize)
}
// Call.
call(frametype, fn, args, uint32(frametype.size), uint32(retOffset))
// Call copies the arguments from scratch to the stack, calls fn,
// and then copies the results back into scratch.
call(frametype, fn, scratch, uint32(frametype.size), uint32(retOffset))
// Copy return values. On amd64p32, the beginning of return values
// is 64-bit aligned, so the caller's frame layout (which doesn't have
@ -673,17 +699,21 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
if runtime.GOARCH == "amd64p32" {
callerRetOffset = align(argSize-ptrSize, 8)
}
typedmemmovepartial(frametype,
add(frame, callerRetOffset, "frametype.size > retOffset"),
add(args, retOffset, "frametype.size > retOffset"),
retOffset,
// This copies to the stack. Write barriers are not needed.
memmove(add(frame, callerRetOffset, "frametype.size > retOffset"),
add(scratch, retOffset, "frametype.size > retOffset"),
frametype.size-retOffset)
}
// This is untyped because the frame is really a stack, even
// though it's a heap object.
memclrNoHeapPointers(args, frametype.size)
framePool.Put(args)
// Tell the runtime it can now depend on the return values
// being properly initialized.
*retValid = true
// Clear the scratch space and put it back in the pool.
// This must happen after the statement above, so that the return
// values will always be scanned by someone.
typedmemclr(frametype, scratch)
framePool.Put(scratch)
// See the comment in callReflect.
runtime.KeepAlive(ctxt)
@ -2569,6 +2599,10 @@ func call(argtype *rtype, fn, arg unsafe.Pointer, n uint32, retoffset uint32)
func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer)
// memmove copies size bytes to dst from src. No write barriers are used.
//go:noescape
func memmove(dst, src unsafe.Pointer, size uintptr)
// typedmemmove copies a value of type t to dst from src.
//go:noescape
func typedmemmove(t *rtype, dst, src unsafe.Pointer)
@ -2578,14 +2612,20 @@ func typedmemmove(t *rtype, dst, src unsafe.Pointer)
//go:noescape
func typedmemmovepartial(t *rtype, dst, src unsafe.Pointer, off, size uintptr)
// typedmemclr zeros the value at ptr of type t.
//go:noescape
func typedmemclr(t *rtype, ptr unsafe.Pointer)
// typedmemclrpartial is like typedmemclr but assumes that
// dst points off bytes into the value and only clears size bytes.
//go:noescape
func typedmemclrpartial(t *rtype, ptr unsafe.Pointer, off, size uintptr)
// typedslicecopy copies a slice of elemType values from src to dst,
// returning the number of elements copied.
//go:noescape
func typedslicecopy(elemType *rtype, dst, src sliceHeader) int
//go:noescape
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
// Dummy annotation marking that the value x escapes,
// for use in cases where the reflect code is so clever that
// the compiler cannot follow.

View File

@ -92,7 +92,7 @@ func makechan(t *chantype, size int) *hchan {
// Queue or element size is zero.
c = (*hchan)(mallocgc(hchanSize, nil, true))
// Race detector uses this location for synchronization.
c.buf = unsafe.Pointer(c)
c.buf = c.raceaddr()
case elem.kind&kindNoPointers != 0:
// Elements do not contain pointers.
// Allocate hchan and buf in one call.
@ -151,7 +151,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
}
if raceenabled {
racereadpc(unsafe.Pointer(c), callerpc, funcPC(chansend))
racereadpc(c.raceaddr(), callerpc, funcPC(chansend))
}
// Fast path: check for failed non-blocking operation without acquiring the lock.
@ -337,8 +337,8 @@ func closechan(c *hchan) {
if raceenabled {
callerpc := getcallerpc()
racewritepc(unsafe.Pointer(c), callerpc, funcPC(closechan))
racerelease(unsafe.Pointer(c))
racewritepc(c.raceaddr(), callerpc, funcPC(closechan))
racerelease(c.raceaddr())
}
c.closed = 1
@ -361,7 +361,7 @@ func closechan(c *hchan) {
gp := sg.g
gp.param = nil
if raceenabled {
raceacquireg(gp, unsafe.Pointer(c))
raceacquireg(gp, c.raceaddr())
}
gp.schedlink.set(glist)
glist = gp
@ -380,7 +380,7 @@ func closechan(c *hchan) {
gp := sg.g
gp.param = nil
if raceenabled {
raceacquireg(gp, unsafe.Pointer(c))
raceacquireg(gp, c.raceaddr())
}
gp.schedlink.set(glist)
glist = gp
@ -457,7 +457,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
if c.closed != 0 && c.qcount == 0 {
if raceenabled {
raceacquire(unsafe.Pointer(c))
raceacquire(c.raceaddr())
}
unlock(&c.lock)
if ep != nil {
@ -735,6 +735,15 @@ func (q *waitq) dequeue() *sudog {
}
}
func (c *hchan) raceaddr() unsafe.Pointer {
// Treat read-like and write-like operations on the channel to
// happen at this address. Avoid using the address of qcount
// or dataqsiz, because the len() and cap() builtins read
// those addresses, and we don't want them racing with
// operations like close().
return unsafe.Pointer(&c.buf)
}
func racesync(c *hchan, sg *sudog) {
racerelease(chanbuf(c, 0))
raceacquireg(sg.g, chanbuf(c, 0))

View File

@ -320,6 +320,19 @@ func typedmemclr(typ *_type, ptr unsafe.Pointer) {
memclrNoHeapPointers(ptr, typ.size)
}
//go:linkname reflect_typedmemclr reflect.typedmemclr
func reflect_typedmemclr(typ *_type, ptr unsafe.Pointer) {
typedmemclr(typ, ptr)
}
//go:linkname reflect_typedmemclrpartial reflect.typedmemclrpartial
func reflect_typedmemclrpartial(typ *_type, ptr unsafe.Pointer, off, size uintptr) {
if typ.kind&kindNoPointers == 0 {
bulkBarrierPreWrite(uintptr(ptr), 0, size)
}
memclrNoHeapPointers(ptr, size)
}
// memclrHasPointers clears n bytes of typed memory starting at ptr.
// The caller must ensure that the type of the object at ptr has
// pointers, usually by checking typ.kind&kindNoPointers. However, ptr

View File

@ -34,6 +34,10 @@ func semacreate(mp *m) {
//go:nosplit
func semasleep(ns int64) int32 {
var start int64
if ns >= 0 {
start = nanotime()
}
mp := getg().m
pthread_mutex_lock(&mp.mutex)
for {
@ -43,8 +47,13 @@ func semasleep(ns int64) int32 {
return 0
}
if ns >= 0 {
spent := nanotime() - start
if spent >= ns {
pthread_mutex_unlock(&mp.mutex)
return -1
}
var t timespec
t.set_nsec(ns)
t.set_nsec(ns - spent)
err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t)
if err == _ETIMEDOUT {
pthread_mutex_unlock(&mp.mutex)

View File

@ -197,23 +197,23 @@ func semacreate(mp *m) {
//go:nosplit
func semasleep(ns int64) int32 {
var ret int32
systemstack(func() {
_g_ := getg()
if nacl_mutex_lock(_g_.m.waitsemalock) < 0 {
throw("semasleep")
}
var ts timespec
if ns >= 0 {
end := ns + nanotime()
ts.tv_sec = end / 1e9
ts.tv_nsec = int32(end % 1e9)
}
for _g_.m.waitsemacount == 0 {
if ns < 0 {
if nacl_cond_wait(_g_.m.waitsema, _g_.m.waitsemalock) < 0 {
throw("semasleep")
}
} else {
var ts timespec
end := ns + nanotime()
ts.tv_sec = end / 1e9
ts.tv_nsec = int32(end % 1e9)
r := nacl_cond_timed_wait_abs(_g_.m.waitsema, _g_.m.waitsemalock, &ts)
if r == -_ETIMEDOUT {
nacl_mutex_unlock(_g_.m.waitsemalock)

View File

@ -126,15 +126,9 @@ func semacreate(mp *m) {
//go:nosplit
func semasleep(ns int64) int32 {
_g_ := getg()
// Compute sleep deadline.
var tsp *timespec
var ts timespec
var deadline int64
if ns >= 0 {
var nsec int32
ts.set_sec(timediv(ns, 1000000000, &nsec))
ts.set_nsec(nsec)
tsp = &ts
deadline = nanotime() + ns
}
for {
@ -147,18 +141,21 @@ func semasleep(ns int64) int32 {
}
// Sleep until unparked by semawakeup or timeout.
var tsp *timespec
var ts timespec
if ns >= 0 {
wait := deadline - nanotime()
if wait <= 0 {
return -1
}
var nsec int32
ts.set_sec(timediv(wait, 1000000000, &nsec))
ts.set_nsec(nsec)
tsp = &ts
}
ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
if ret == _ETIMEDOUT {
return -1
} else if ret == _EINTR && ns >= 0 {
// Avoid sleeping forever if we keep getting
// interrupted (for example by the profiling
// timer). It would be if tsp upon return had the
// remaining time to sleep, but this is good enough.
var nsec int32
ns /= 2
ts.set_sec(timediv(ns, 1000000000, &nsec))
ts.set_nsec(nsec)
}
}
}

View File

@ -577,18 +577,32 @@ func TestRaceChanItselfCap(t *testing.T) {
<-compl
}
func TestRaceChanCloseLen(t *testing.T) {
v := 0
_ = v
func TestNoRaceChanCloseLen(t *testing.T) {
c := make(chan int, 10)
c <- 0
r := make(chan int, 10)
go func() {
v = 1
close(c)
r <- len(c)
}()
time.Sleep(1e7)
_ = len(c)
v = 2
go func() {
close(c)
r <- 0
}()
<-r
<-r
}
func TestNoRaceChanCloseCap(t *testing.T) {
c := make(chan int, 10)
r := make(chan int, 10)
go func() {
r <- cap(c)
}()
go func() {
close(c)
r <- 0
}()
<-r
<-r
}
func TestRaceChanCloseSend(t *testing.T) {

View File

@ -245,7 +245,7 @@ loop:
case caseSend:
if raceenabled {
racereadpc(unsafe.Pointer(c), cas.pc, chansendpc)
racereadpc(c.raceaddr(), cas.pc, chansendpc)
}
if c.closed != 0 {
goto sclose
@ -462,7 +462,7 @@ rclose:
typedmemclr(c.elemtype, cas.elem)
}
if raceenabled {
raceacquire(unsafe.Pointer(c))
raceacquire(c.raceaddr())
}
goto retc

View File

@ -24,13 +24,13 @@ type traceContextKey struct{}
// If the end function is called multiple times, only the first
// call is used in the latency measurement.
//
// ctx, task := trace.NewTask(ctx, "awesome task")
// trace.WithRegion(ctx, prepWork)
// ctx, task := trace.NewTask(ctx, "awesomeTask")
// trace.WithRegion(ctx, "preparation", prepWork)
// // preparation of the task
// go func() { // continue processing the task in a separate goroutine.
// defer task.End()
// trace.WithRegion(ctx, remainingWork)
// }
// trace.WithRegion(ctx, "remainingWork", remainingWork)
// }()
func NewTask(pctx context.Context, taskType string) (ctx context.Context, task *Task) {
pid := fromContext(pctx).id
id := newID()

View File

@ -557,8 +557,9 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
// reflectMethodValue is a partial duplicate of reflect.makeFuncImpl
// and reflect.methodValue.
type reflectMethodValue struct {
fn uintptr
stack *bitvector // args bitmap
fn uintptr
stack *bitvector // ptrmap for both args and results
argLen uintptr // just args
}
// getArgInfoFast returns the argument frame information for a call to f.
@ -587,6 +588,7 @@ func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (ar
// These take a *reflect.methodValue as their
// context register.
var mv *reflectMethodValue
var retValid bool
if ctxt != nil {
// This is not an actual call, but a
// deferred call. The function value
@ -600,6 +602,10 @@ func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (ar
// 0(SP).
arg0 := frame.sp + sys.MinFrameSize
mv = *(**reflectMethodValue)(unsafe.Pointer(arg0))
// Figure out whether the return values are valid.
// Reflect will update this value after it copies
// in the return values.
retValid = *(*bool)(unsafe.Pointer(arg0 + 3*sys.PtrSize))
}
if mv.fn != f.entry {
print("runtime: confused by ", funcname(f), "\n")
@ -607,6 +613,9 @@ func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (ar
}
bv := mv.stack
arglen = uintptr(bv.n * sys.PtrSize)
if !retValid {
arglen = uintptr(mv.argLen) &^ (sys.PtrSize - 1)
}
argmap = bv
}
}

View File

@ -0,0 +1,17 @@
// compile
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Issue 27143: cmd/compile: erroneous application of walkinrange
// optimization for const over 2**63
package p
var c uint64
var b1 bool = 0x7fffffffffffffff < c && c < 0x8000000000000000
var b2 bool = c < 0x8000000000000000 && 0x7fffffffffffffff < c
var b3 bool = 0x8000000000000000 < c && c < 0x8000000000000001
var b4 bool = c < 0x8000000000000001 && 0x8000000000000000 < c

View File

@ -0,0 +1,63 @@
// run
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Issue 27278: dead auto elim deletes an auto and its
// initialization, but it is live because of a nil check.
package main
type T struct {
_ [3]string
T2
}
func (t *T) M() []string {
return t.T2.M()
}
type T2 struct {
T3
}
func (t *T2) M() []string {
return t.T3.M()
}
type T3 struct {
a string
}
func (t *T3) M() []string {
return []string{}
}
func main() {
poison()
f()
}
//go:noinline
func f() {
(&T{}).M()
grow(10000)
}
// grow stack, triggers stack copy
func grow(n int) {
if n == 0 {
return
}
grow(n-1)
}
// put some junk on stack, which cannot be valid address
//go:noinline
func poison() {
x := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
g = x
}
var g [10]int

View File

@ -0,0 +1,24 @@
// run
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Make sure we don't prove that the bounds check failure branch is unreachable.
package main
//go:noinline
func f(a []int) {
_ = a[len(a)-1]
}
func main() {
defer func() {
if err := recover(); err != nil {
return
}
panic("f should panic")
}()
f(nil)
}

View File

@ -0,0 +1,19 @@
// errorcheck
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Issue 27356: function parameter hiding built-in function results in compiler crash
package p
var a = []int{1,2,3}
func _(len int) {
_ = len(a) // ERROR "cannot call non-function"
}
var cap = false
var _ = cap(a) // ERROR "cannot call non-function"

View File

@ -0,0 +1,62 @@
// run
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Make sure return values are always scanned, when
// calling methods (+functions, TODO) with reflect.
package main
import (
"reflect"
"runtime/debug"
"sync"
)
func main() {
debug.SetGCPercent(1) // run GC frequently
var wg sync.WaitGroup
for i := 0; i < 20; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; i < 2000; i++ {
_test()
}
}()
}
wg.Wait()
}
type Stt struct {
Data interface{}
}
type My struct {
b byte
}
func (this *My) Run(rawData []byte) (Stt, error) {
var data string = "hello"
stt := Stt{
Data: data,
}
return stt, nil
}
func _test() (interface{}, error) {
f := reflect.ValueOf(&My{}).MethodByName("Run")
if method, ok := f.Interface().(func([]byte) (Stt, error)); ok {
s, e := method(nil)
// The bug in issue27695 happens here, during the return
// from the above call (at the end of reflect.callMethod
// when preparing to return). The result value that
// is assigned to s was not being scanned if GC happens
// to occur there.
i := interface{}(s)
return i, e
}
return nil, nil
}

View File

@ -0,0 +1,64 @@
// run
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Make sure return values aren't scanned until they
// are initialized, when calling functions and methods
// via reflect.
package main
import (
"reflect"
"runtime"
"unsafe"
)
var badPtr uintptr
var sink []byte
func init() {
// Allocate large enough to use largeAlloc.
b := make([]byte, 1<<16-1)
sink = b // force heap allocation
// Any space between the object and the end of page is invalid to point to.
badPtr = uintptr(unsafe.Pointer(&b[len(b)-1])) + 1
}
func f(d func() *byte) *byte {
// Initialize callee args section with a bad pointer.
g(badPtr)
// Then call a function which returns a pointer.
// That return slot starts out holding a bad pointer.
return d()
}
//go:noinline
func g(x uintptr) {
}
type T struct {
}
func (t *T) Foo() *byte {
runtime.GC()
return nil
}
func main() {
// Functions
d := reflect.MakeFunc(reflect.TypeOf(func() *byte { return nil }),
func(args []reflect.Value) []reflect.Value {
runtime.GC()
return []reflect.Value{reflect.ValueOf((*byte)(nil))}
}).Interface().(func() *byte)
f(d)
// Methods
e := reflect.ValueOf(&T{}).Method(0).Interface().(func() *byte)
f(e)
}

View File

@ -0,0 +1,35 @@
// run
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Issue 27961: some optimizations generate OffPtr with wrong
// types, which causes invalid bytecode on Wasm.
package main
import "math"
type Vec2 [2]float64
func main() {
var a Vec2
a.A().B().C().D()
}
func (v Vec2) A() Vec2 {
return Vec2{v[0], v[0]}
}
func (v Vec2) B() Vec2 {
return Vec2{1.0 / v.D(), 0}
}
func (v Vec2) C() Vec2 {
return Vec2{v[0], v[0]}
}
func (v Vec2) D() float64 {
return math.Sqrt(v[0])
}

View File

@ -542,7 +542,7 @@ func fence2(x, y int) {
}
}
func fence3(b []int, x, y int64) {
func fence3(b, c []int, x, y int64) {
if x-1 >= y {
if x <= y { // Can't prove because x may have wrapped.
return
@ -555,6 +555,8 @@ func fence3(b []int, x, y int64) {
}
}
c[len(c)-1] = 0 // Can't prove because len(c) might be 0
if n := len(b); n > 0 {
b[n-1] = 0 // ERROR "Proved IsInBounds$"
}