[dev.boringcrypto.go1.16] all: merge go1.16.3 into dev.boringcrypto.go1.16

Change-Id: I037c70c43855beee7f2f817cf4304133dfe2ecfa
This commit is contained in:
Filippo Valsorda 2021-04-21 17:08:39 +02:00
commit fcee6b930a
36 changed files with 778 additions and 129 deletions

View File

@ -209,3 +209,10 @@ func TestMethod2(t *testing.T) {
goCmd(t, "build", "-o", "method2.exe", "./method2/main.go")
run(t, "./method2.exe")
}
func TestIssue44956(t *testing.T) {
goCmd(t, "build", "-buildmode=plugin", "-o", "issue44956p1.so", "./issue44956/plugin1.go")
goCmd(t, "build", "-buildmode=plugin", "-o", "issue44956p2.so", "./issue44956/plugin2.go")
goCmd(t, "build", "-o", "issue44956.exe", "./issue44956/main.go")
run(t, "./issue44956.exe")
}

View File

@ -0,0 +1,7 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package base
var X = &map[int]int{123: 456}

View File

@ -0,0 +1,47 @@
// Copyright 2021 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 44956: writable static temp is not exported correctly.
// In the test below, package base is
//
// X = &map{...}
//
// which compiles to
//
// X = &stmp // static
// stmp = makemap(...) // in init function
//
// plugin1 and plugin2 both import base. plugin1 doesn't use
// base.X, so that symbol is deadcoded in plugin1.
//
// plugin1 is loaded first. base.init runs at that point, which
// initialize base.stmp.
//
// plugin2 is then loaded. base.init already ran, so it doesn't run
// again. When base.stmp is not exported, plugin2's base.X points to
// its own private base.stmp, which is not initialized, fail.
package main
import "plugin"
func main() {
_, err := plugin.Open("issue44956p1.so")
if err != nil {
panic("FAIL")
}
p2, err := plugin.Open("issue44956p2.so")
if err != nil {
panic("FAIL")
}
f, err := p2.Lookup("F")
if err != nil {
panic("FAIL")
}
x := f.(func() *map[int]int)()
if x == nil || (*x)[123] != 456 {
panic("FAIL")
}
}

View File

@ -0,0 +1,9 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import _ "testplugin/issue44956/base"
func main() {}

View File

@ -0,0 +1,11 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "testplugin/issue44956/base"
func F() *map[int]int { return base.X }
func main() {}

View File

@ -363,15 +363,15 @@ func staticname(t *types.Type) *Node {
n := newname(lookup(fmt.Sprintf("%s%d", obj.StaticNamePref, statuniqgen)))
statuniqgen++
addvar(n, t, PEXTERN)
n.Sym.Linksym().Set(obj.AttrLocal, true)
return n
}
// readonlystaticname returns a name backed by a (writable) static data symbol.
// readonlystaticname returns a name backed by a read-only static data symbol.
func readonlystaticname(t *types.Type) *Node {
n := staticname(t)
n.MarkReadonly()
n.Sym.Linksym().Set(obj.AttrContentAddressable, true)
n.Sym.Linksym().Set(obj.AttrLocal, true)
return n
}

View File

@ -623,6 +623,14 @@
// Recognize bit setting (a |= 1<<b) and toggling (a ^= 1<<b)
(OR(Q|L) (SHL(Q|L) (MOV(Q|L)const [1]) y) x) => (BTS(Q|L) x y)
(XOR(Q|L) (SHL(Q|L) (MOV(Q|L)const [1]) y) x) => (BTC(Q|L) x y)
(ORLmodify [off] {sym} ptr s:(SHLL (MOVLconst [1]) <t> x) mem) =>
(BTSLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
(ORQmodify [off] {sym} ptr s:(SHLQ (MOVQconst [1]) <t> x) mem) =>
(BTSQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
(XORLmodify [off] {sym} ptr s:(SHLL (MOVLconst [1]) <t> x) mem) =>
(BTCLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
(XORQmodify [off] {sym} ptr s:(SHLQ (MOVQconst [1]) <t> x) mem) =>
(BTCQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
// Convert ORconst into BTS, if the code gets smaller, with boundary being
// (ORL $40,AX is 3 bytes, ORL $80,AX is 6 bytes).
@ -645,6 +653,10 @@
=> (BTRQconst [int8(log64(^c))] x)
(ANDL (MOVLconst [c]) x) && isUint32PowerOfTwo(int64(^c)) && uint64(^c) >= 128
=> (BTRLconst [int8(log32(^c))] x)
(ANDLmodify [off] {sym} ptr (NOTL s:(SHLL (MOVLconst [1]) <t> x)) mem) =>
(BTRLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
(ANDQmodify [off] {sym} ptr (NOTQ s:(SHLQ (MOVQconst [1]) <t> x)) mem) =>
(BTRQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
// Special-case bit patterns on first/last bit.
// generic.rules changes ANDs of high-part/low-part masks into a couple of shifts,
@ -2050,11 +2062,15 @@
((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem)
((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem)
(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) => ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
(MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Lmodify [off] {sym} ptr x mem)
(MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
((ADD|SUB|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
(MOVLstore {sym} [off] ptr y:((BTC|BTR|BTS)L l:(MOVLload [off] {sym} ptr mem) <t> x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
((BTC|BTR|BTS)Lmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
(MOVQstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Qload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) => ((ADD|AND|OR|XOR)Qmodify [off] {sym} ptr x mem)
(MOVQstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Q l:(MOVQload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Qmodify [off] {sym} ptr x mem)
(MOVQstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)Q l:(MOVQload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
((ADD|SUB|AND|OR|XOR)Qmodify [off] {sym} ptr x mem)
(MOVQstore {sym} [off] ptr y:((BTC|BTR|BTS)Q l:(MOVQload [off] {sym} ptr mem) <t> x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
((BTC|BTR|BTS)Qmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
// Merge ADDQconst and LEAQ into atomic loads.
(MOV(Q|L|B)atomicload [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) =>

View File

@ -358,6 +358,11 @@ func init() {
{name: "BTSQconst", argLength: 1, reg: gp11, asm: "BTSQ", resultInArg0: true, clobberFlags: true, aux: "Int8"}, // set bit auxint in arg0, 0 <= auxint < 64
// direct bit operation on memory operand
//
// Note that these operations do not mask the bit offset (arg1), and will write beyond their expected
// bounds if that argument is larger than 64/32 (for BT*Q and BT*L, respectively). If the compiler
// cannot prove that arg1 is in range, it must be explicitly masked (see e.g. the patterns that produce
// BT*modify from (MOVstore (BT* (MOVLload ptr mem) x) mem)).
{name: "BTCQmodify", argLength: 3, reg: gpstore, asm: "BTCQ", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // complement bit arg1 in 64-bit arg0+auxint+aux, arg2=mem
{name: "BTCLmodify", argLength: 3, reg: gpstore, asm: "BTCL", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // complement bit arg1 in 32-bit arg0+auxint+aux, arg2=mem
{name: "BTSQmodify", argLength: 3, reg: gpstore, asm: "BTSQ", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // set bit arg1 in 64-bit arg0+auxint+aux, arg2=mem

View File

@ -2998,6 +2998,36 @@ func rewriteValueAMD64_OpAMD64ANDLmodify(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
// match: (ANDLmodify [off] {sym} ptr (NOTL s:(SHLL (MOVLconst [1]) <t> x)) mem)
// result: (BTRLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
ptr := v_0
if v_1.Op != OpAMD64NOTL {
break
}
s := v_1.Args[0]
if s.Op != OpAMD64SHLL {
break
}
t := s.Type
x := s.Args[1]
s_0 := s.Args[0]
if s_0.Op != OpAMD64MOVLconst || auxIntToInt32(s_0.AuxInt) != 1 {
break
}
mem := v_2
v.reset(OpAMD64BTRLmodify)
v.AuxInt = int32ToAuxInt(off)
v.Aux = symToAux(sym)
v0 := b.NewValue0(v.Pos, OpAMD64ANDLconst, t)
v0.AuxInt = int32ToAuxInt(31)
v0.AddArg(x)
v.AddArg3(ptr, v0, mem)
return true
}
// match: (ANDLmodify [off1] {sym} (ADDQconst [off2] base) val mem)
// cond: is32Bit(int64(off1)+int64(off2))
// result: (ANDLmodify [off1+off2] {sym} base val mem)
@ -3377,6 +3407,36 @@ func rewriteValueAMD64_OpAMD64ANDQmodify(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
// match: (ANDQmodify [off] {sym} ptr (NOTQ s:(SHLQ (MOVQconst [1]) <t> x)) mem)
// result: (BTRQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
ptr := v_0
if v_1.Op != OpAMD64NOTQ {
break
}
s := v_1.Args[0]
if s.Op != OpAMD64SHLQ {
break
}
t := s.Type
x := s.Args[1]
s_0 := s.Args[0]
if s_0.Op != OpAMD64MOVQconst || auxIntToInt64(s_0.AuxInt) != 1 {
break
}
mem := v_2
v.reset(OpAMD64BTRQmodify)
v.AuxInt = int32ToAuxInt(off)
v.Aux = symToAux(sym)
v0 := b.NewValue0(v.Pos, OpAMD64ANDQconst, t)
v0.AuxInt = int32ToAuxInt(63)
v0.AddArg(x)
v.AddArg3(ptr, v0, mem)
return true
}
// match: (ANDQmodify [off1] {sym} (ADDQconst [off2] base) val mem)
// cond: is32Bit(int64(off1)+int64(off2))
// result: (ANDQmodify [off1+off2] {sym} base val mem)
@ -12709,9 +12769,9 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
}
break
}
// match: (MOVLstore {sym} [off] ptr y:(BTCL l:(MOVLload [off] {sym} ptr mem) x) mem)
// match: (MOVLstore {sym} [off] ptr y:(BTCL l:(MOVLload [off] {sym} ptr mem) <t> x) mem)
// cond: y.Uses==1 && l.Uses==1 && clobber(y, l)
// result: (BTCLmodify [off] {sym} ptr x mem)
// result: (BTCLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -12720,6 +12780,7 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
if y.Op != OpAMD64BTCL {
break
}
t := y.Type
x := y.Args[1]
l := y.Args[0]
if l.Op != OpAMD64MOVLload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym {
@ -12732,12 +12793,15 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
v.reset(OpAMD64BTCLmodify)
v.AuxInt = int32ToAuxInt(off)
v.Aux = symToAux(sym)
v.AddArg3(ptr, x, mem)
v0 := b.NewValue0(l.Pos, OpAMD64ANDLconst, t)
v0.AuxInt = int32ToAuxInt(31)
v0.AddArg(x)
v.AddArg3(ptr, v0, mem)
return true
}
// match: (MOVLstore {sym} [off] ptr y:(BTRL l:(MOVLload [off] {sym} ptr mem) x) mem)
// match: (MOVLstore {sym} [off] ptr y:(BTRL l:(MOVLload [off] {sym} ptr mem) <t> x) mem)
// cond: y.Uses==1 && l.Uses==1 && clobber(y, l)
// result: (BTRLmodify [off] {sym} ptr x mem)
// result: (BTRLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -12746,6 +12810,7 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
if y.Op != OpAMD64BTRL {
break
}
t := y.Type
x := y.Args[1]
l := y.Args[0]
if l.Op != OpAMD64MOVLload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym {
@ -12758,12 +12823,15 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
v.reset(OpAMD64BTRLmodify)
v.AuxInt = int32ToAuxInt(off)
v.Aux = symToAux(sym)
v.AddArg3(ptr, x, mem)
v0 := b.NewValue0(l.Pos, OpAMD64ANDLconst, t)
v0.AuxInt = int32ToAuxInt(31)
v0.AddArg(x)
v.AddArg3(ptr, v0, mem)
return true
}
// match: (MOVLstore {sym} [off] ptr y:(BTSL l:(MOVLload [off] {sym} ptr mem) x) mem)
// match: (MOVLstore {sym} [off] ptr y:(BTSL l:(MOVLload [off] {sym} ptr mem) <t> x) mem)
// cond: y.Uses==1 && l.Uses==1 && clobber(y, l)
// result: (BTSLmodify [off] {sym} ptr x mem)
// result: (BTSLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -12772,6 +12840,7 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
if y.Op != OpAMD64BTSL {
break
}
t := y.Type
x := y.Args[1]
l := y.Args[0]
if l.Op != OpAMD64MOVLload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym {
@ -12784,7 +12853,10 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
v.reset(OpAMD64BTSLmodify)
v.AuxInt = int32ToAuxInt(off)
v.Aux = symToAux(sym)
v.AddArg3(ptr, x, mem)
v0 := b.NewValue0(l.Pos, OpAMD64ANDLconst, t)
v0.AuxInt = int32ToAuxInt(31)
v0.AddArg(x)
v.AddArg3(ptr, v0, mem)
return true
}
// match: (MOVLstore [off] {sym} ptr a:(ADDLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem)
@ -13525,6 +13597,7 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
// match: (MOVQstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
// cond: is32Bit(int64(off1)+int64(off2))
// result: (MOVQstore [off1+off2] {sym} ptr val mem)
@ -13890,9 +13963,9 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
}
break
}
// match: (MOVQstore {sym} [off] ptr y:(BTCQ l:(MOVQload [off] {sym} ptr mem) x) mem)
// match: (MOVQstore {sym} [off] ptr y:(BTCQ l:(MOVQload [off] {sym} ptr mem) <t> x) mem)
// cond: y.Uses==1 && l.Uses==1 && clobber(y, l)
// result: (BTCQmodify [off] {sym} ptr x mem)
// result: (BTCQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -13901,6 +13974,7 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
if y.Op != OpAMD64BTCQ {
break
}
t := y.Type
x := y.Args[1]
l := y.Args[0]
if l.Op != OpAMD64MOVQload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym {
@ -13913,12 +13987,15 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
v.reset(OpAMD64BTCQmodify)
v.AuxInt = int32ToAuxInt(off)
v.Aux = symToAux(sym)
v.AddArg3(ptr, x, mem)
v0 := b.NewValue0(l.Pos, OpAMD64ANDQconst, t)
v0.AuxInt = int32ToAuxInt(63)
v0.AddArg(x)
v.AddArg3(ptr, v0, mem)
return true
}
// match: (MOVQstore {sym} [off] ptr y:(BTRQ l:(MOVQload [off] {sym} ptr mem) x) mem)
// match: (MOVQstore {sym} [off] ptr y:(BTRQ l:(MOVQload [off] {sym} ptr mem) <t> x) mem)
// cond: y.Uses==1 && l.Uses==1 && clobber(y, l)
// result: (BTRQmodify [off] {sym} ptr x mem)
// result: (BTRQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -13927,6 +14004,7 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
if y.Op != OpAMD64BTRQ {
break
}
t := y.Type
x := y.Args[1]
l := y.Args[0]
if l.Op != OpAMD64MOVQload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym {
@ -13939,12 +14017,15 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
v.reset(OpAMD64BTRQmodify)
v.AuxInt = int32ToAuxInt(off)
v.Aux = symToAux(sym)
v.AddArg3(ptr, x, mem)
v0 := b.NewValue0(l.Pos, OpAMD64ANDQconst, t)
v0.AuxInt = int32ToAuxInt(63)
v0.AddArg(x)
v.AddArg3(ptr, v0, mem)
return true
}
// match: (MOVQstore {sym} [off] ptr y:(BTSQ l:(MOVQload [off] {sym} ptr mem) x) mem)
// match: (MOVQstore {sym} [off] ptr y:(BTSQ l:(MOVQload [off] {sym} ptr mem) <t> x) mem)
// cond: y.Uses==1 && l.Uses==1 && clobber(y, l)
// result: (BTSQmodify [off] {sym} ptr x mem)
// result: (BTSQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -13953,6 +14034,7 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
if y.Op != OpAMD64BTSQ {
break
}
t := y.Type
x := y.Args[1]
l := y.Args[0]
if l.Op != OpAMD64MOVQload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym {
@ -13965,7 +14047,10 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
v.reset(OpAMD64BTSQmodify)
v.AuxInt = int32ToAuxInt(off)
v.Aux = symToAux(sym)
v.AddArg3(ptr, x, mem)
v0 := b.NewValue0(l.Pos, OpAMD64ANDQconst, t)
v0.AuxInt = int32ToAuxInt(63)
v0.AddArg(x)
v.AddArg3(ptr, v0, mem)
return true
}
// match: (MOVQstore [off] {sym} ptr a:(ADDQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem)
@ -18352,6 +18437,33 @@ func rewriteValueAMD64_OpAMD64ORLmodify(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
// match: (ORLmodify [off] {sym} ptr s:(SHLL (MOVLconst [1]) <t> x) mem)
// result: (BTSLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
ptr := v_0
s := v_1
if s.Op != OpAMD64SHLL {
break
}
t := s.Type
x := s.Args[1]
s_0 := s.Args[0]
if s_0.Op != OpAMD64MOVLconst || auxIntToInt32(s_0.AuxInt) != 1 {
break
}
mem := v_2
v.reset(OpAMD64BTSLmodify)
v.AuxInt = int32ToAuxInt(off)
v.Aux = symToAux(sym)
v0 := b.NewValue0(v.Pos, OpAMD64ANDLconst, t)
v0.AuxInt = int32ToAuxInt(31)
v0.AddArg(x)
v.AddArg3(ptr, v0, mem)
return true
}
// match: (ORLmodify [off1] {sym} (ADDQconst [off2] base) val mem)
// cond: is32Bit(int64(off1)+int64(off2))
// result: (ORLmodify [off1+off2] {sym} base val mem)
@ -19979,6 +20091,33 @@ func rewriteValueAMD64_OpAMD64ORQmodify(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
// match: (ORQmodify [off] {sym} ptr s:(SHLQ (MOVQconst [1]) <t> x) mem)
// result: (BTSQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
ptr := v_0
s := v_1
if s.Op != OpAMD64SHLQ {
break
}
t := s.Type
x := s.Args[1]
s_0 := s.Args[0]
if s_0.Op != OpAMD64MOVQconst || auxIntToInt64(s_0.AuxInt) != 1 {
break
}
mem := v_2
v.reset(OpAMD64BTSQmodify)
v.AuxInt = int32ToAuxInt(off)
v.Aux = symToAux(sym)
v0 := b.NewValue0(v.Pos, OpAMD64ANDQconst, t)
v0.AuxInt = int32ToAuxInt(63)
v0.AddArg(x)
v.AddArg3(ptr, v0, mem)
return true
}
// match: (ORQmodify [off1] {sym} (ADDQconst [off2] base) val mem)
// cond: is32Bit(int64(off1)+int64(off2))
// result: (ORQmodify [off1+off2] {sym} base val mem)
@ -28014,6 +28153,33 @@ func rewriteValueAMD64_OpAMD64XORLmodify(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
// match: (XORLmodify [off] {sym} ptr s:(SHLL (MOVLconst [1]) <t> x) mem)
// result: (BTCLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
ptr := v_0
s := v_1
if s.Op != OpAMD64SHLL {
break
}
t := s.Type
x := s.Args[1]
s_0 := s.Args[0]
if s_0.Op != OpAMD64MOVLconst || auxIntToInt32(s_0.AuxInt) != 1 {
break
}
mem := v_2
v.reset(OpAMD64BTCLmodify)
v.AuxInt = int32ToAuxInt(off)
v.Aux = symToAux(sym)
v0 := b.NewValue0(v.Pos, OpAMD64ANDLconst, t)
v0.AuxInt = int32ToAuxInt(31)
v0.AddArg(x)
v.AddArg3(ptr, v0, mem)
return true
}
// match: (XORLmodify [off1] {sym} (ADDQconst [off2] base) val mem)
// cond: is32Bit(int64(off1)+int64(off2))
// result: (XORLmodify [off1+off2] {sym} base val mem)
@ -28382,6 +28548,33 @@ func rewriteValueAMD64_OpAMD64XORQmodify(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
// match: (XORQmodify [off] {sym} ptr s:(SHLQ (MOVQconst [1]) <t> x) mem)
// result: (BTCQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
ptr := v_0
s := v_1
if s.Op != OpAMD64SHLQ {
break
}
t := s.Type
x := s.Args[1]
s_0 := s.Args[0]
if s_0.Op != OpAMD64MOVQconst || auxIntToInt64(s_0.AuxInt) != 1 {
break
}
mem := v_2
v.reset(OpAMD64BTCQmodify)
v.AuxInt = int32ToAuxInt(off)
v.Aux = symToAux(sym)
v0 := b.NewValue0(v.Pos, OpAMD64ANDQconst, t)
v0.AuxInt = int32ToAuxInt(63)
v0.AddArg(x)
v.AddArg3(ptr, v0, mem)
return true
}
// match: (XORQmodify [off1] {sym} (ADDQconst [off2] base) val mem)
// cond: is32Bit(int64(off1)+int64(off2))
// result: (XORQmodify [off1+off2] {sym} base val mem)

View File

@ -138,6 +138,24 @@ func shortcircuitBlock(b *Block) bool {
if len(b.Values) != nval+nOtherPhi {
return false
}
if nOtherPhi > 0 {
// Check for any phi which is the argument of another phi.
// These cases are tricky, as substitutions done by replaceUses
// are no longer trivial to do in any ordering. See issue 45175.
m := make(map[*Value]bool, 1+nOtherPhi)
for _, v := range b.Values {
if v.Op == OpPhi {
m[v] = true
}
}
for v := range m {
for _, a := range v.Args {
if a != v && m[a] {
return false
}
}
}
}
// Locate index of first const phi arg.
cidx := -1

View File

@ -6,7 +6,7 @@ require (
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
golang.org/x/mod v0.4.2-0.20210302225053-d515b24adc21
golang.org/x/mod v0.4.2-0.20210325185522-dbbbf8a3c6ea
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 // indirect
golang.org/x/tools v0.0.0-20210107193943-4ed967dd8eff
)

View File

@ -14,8 +14,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2-0.20210302225053-d515b24adc21 h1:FnWKa8BJXkVQ+16E52jkfBOJPx2cG8y/6X376nOgSM4=
golang.org/x/mod v0.4.2-0.20210302225053-d515b24adc21/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2-0.20210325185522-dbbbf8a3c6ea h1:zAn46O7Vmm6KdLXx+635hPZSArrt/wNctv4Ab70Jw3k=
golang.org/x/mod v0.4.2-0.20210325185522-dbbbf8a3c6ea/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=

View File

@ -692,18 +692,22 @@
// arguments must satisfy the following constraints:
//
// - Arguments must be package paths or package patterns (with "..." wildcards).
// They must not be standard packages (like fmt), meta-patterns (std, cmd,
// all), or relative or absolute file paths.
// They must not be standard packages (like fmt), meta-patterns (std, cmd,
// all), or relative or absolute file paths.
//
// - All arguments must have the same version suffix. Different queries are not
// allowed, even if they refer to the same version.
// allowed, even if they refer to the same version.
//
// - All arguments must refer to packages in the same module at the same version.
//
// - No module is considered the "main" module. If the module containing
// packages named on the command line has a go.mod file, it must not contain
// directives (replace and exclude) that would cause it to be interpreted
// differently than if it were the main module. The module must not require
// a higher version of itself.
// packages named on the command line has a go.mod file, it must not contain
// directives (replace and exclude) that would cause it to be interpreted
// differently than if it were the main module. The module must not require
// a higher version of itself.
//
// - Package path arguments must refer to main packages. Pattern arguments
// will only match main packages.
// will only match main packages.
//
// If the arguments don't have version suffixes, "go install" may run in
// module-aware mode or GOPATH mode, depending on the GO111MODULE environment

View File

@ -84,6 +84,7 @@ func DownloadDir(m module.Version) (string, error) {
return "", err
}
// Check whether the directory itself exists.
dir := filepath.Join(cfg.GOMODCACHE, enc+"@"+encVer)
if fi, err := os.Stat(dir); os.IsNotExist(err) {
return dir, err
@ -92,6 +93,9 @@ func DownloadDir(m module.Version) (string, error) {
} else if !fi.IsDir() {
return dir, &DownloadDirPartialError{dir, errors.New("not a directory")}
}
// Check if a .partial file exists. This is created at the beginning of
// a download and removed after the zip is extracted.
partialPath, err := CachePath(m, "partial")
if err != nil {
return dir, err
@ -101,6 +105,19 @@ func DownloadDir(m module.Version) (string, error) {
} else if !os.IsNotExist(err) {
return dir, err
}
// Check if a .ziphash file exists. It should be created before the
// zip is extracted, but if it was deleted (by another program?), we need
// to re-calculate it.
ziphashPath, err := CachePath(m, "ziphash")
if err != nil {
return dir, err
}
if _, err := os.Stat(ziphashPath); os.IsNotExist(err) {
return dir, &DownloadDirPartialError{dir, errors.New("ziphash file is missing")}
} else if err != nil {
return dir, err
}
return dir, nil
}

View File

@ -170,13 +170,16 @@ func DownloadZip(ctx context.Context, mod module.Version) (zipfile string, err e
if err != nil {
return cached{"", err}
}
ziphashfile := zipfile + "hash"
// Skip locking if the zipfile already exists.
// Return without locking if the zip and ziphash files exist.
if _, err := os.Stat(zipfile); err == nil {
return cached{zipfile, nil}
if _, err := os.Stat(ziphashfile); err == nil {
return cached{zipfile, nil}
}
}
// The zip file does not exist. Acquire the lock and create it.
// The zip or ziphash file does not exist. Acquire the lock and create them.
if cfg.CmdName != "mod download" {
fmt.Fprintf(os.Stderr, "go: downloading %s %s\n", mod.Path, mod.Version)
}
@ -186,14 +189,6 @@ func DownloadZip(ctx context.Context, mod module.Version) (zipfile string, err e
}
defer unlock()
// Double-check that the zipfile was not created while we were waiting for
// the lock.
if _, err := os.Stat(zipfile); err == nil {
return cached{zipfile, nil}
}
if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil {
return cached{"", err}
}
if err := downloadZip(ctx, mod, zipfile); err != nil {
return cached{"", err}
}
@ -206,6 +201,25 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e
ctx, span := trace.StartSpan(ctx, "modfetch.downloadZip "+zipfile)
defer span.Done()
// Double-check that the zipfile was not created while we were waiting for
// the lock in DownloadZip.
ziphashfile := zipfile + "hash"
var zipExists, ziphashExists bool
if _, err := os.Stat(zipfile); err == nil {
zipExists = true
}
if _, err := os.Stat(ziphashfile); err == nil {
ziphashExists = true
}
if zipExists && ziphashExists {
return nil
}
// Create parent directories.
if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil {
return err
}
// Clean up any remaining tempfiles from previous runs.
// This is only safe to do because the lock file ensures that their
// writers are no longer active.
@ -217,6 +231,12 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e
}
}
// If the zip file exists, the ziphash file must have been deleted
// or lost after a file system crash. Re-hash the zip without downloading.
if zipExists {
return hashZip(mod, zipfile, ziphashfile)
}
// From here to the os.Rename call below is functionally almost equivalent to
// renameio.WriteToFile, with one key difference: we want to validate the
// contents of the file (by hashing it) before we commit it. Because the file
@ -289,15 +309,7 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e
}
// Hash the zip file and check the sum before renaming to the final location.
hash, err := dirhash.HashZip(f.Name(), dirhash.DefaultHash)
if err != nil {
return err
}
if err := checkModSum(mod, hash); err != nil {
return err
}
if err := renameio.WriteFile(zipfile+"hash", []byte(hash), 0666); err != nil {
if err := hashZip(mod, f.Name(), ziphashfile); err != nil {
return err
}
if err := os.Rename(f.Name(), zipfile); err != nil {
@ -309,6 +321,22 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e
return nil
}
// hashZip reads the zip file opened in f, then writes the hash to ziphashfile,
// overwriting that file if it exists.
//
// If the hash does not match go.sum (or the sumdb if enabled), hashZip returns
// an error and does not write ziphashfile.
func hashZip(mod module.Version, zipfile, ziphashfile string) error {
hash, err := dirhash.HashZip(zipfile, dirhash.DefaultHash)
if err != nil {
return err
}
if err := checkModSum(mod, hash); err != nil {
return err
}
return renameio.WriteFile(ziphashfile, []byte(hash), 0666)
}
// makeDirsReadOnly makes a best-effort attempt to remove write permissions for dir
// and its transitive contents.
func makeDirsReadOnly(dir string) {
@ -452,11 +480,6 @@ func HaveSum(mod module.Version) bool {
// checkMod checks the given module's checksum.
func checkMod(mod module.Version) {
if cfg.GOMODCACHE == "" {
// Do not use current directory.
return
}
// Do the file I/O before acquiring the go.sum lock.
ziphash, err := CachePath(mod, "ziphash")
if err != nil {
@ -464,10 +487,6 @@ func checkMod(mod module.Version) {
}
data, err := renameio.ReadFile(ziphash)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
// This can happen if someone does rm -rf GOPATH/src/cache/download. So it goes.
return
}
base.Fatalf("verifying %v", module.VersionError(mod, err))
}
h := strings.TrimSpace(string(data))

View File

@ -482,18 +482,22 @@ To eliminate ambiguity about which module versions are used in the build, the
arguments must satisfy the following constraints:
- Arguments must be package paths or package patterns (with "..." wildcards).
They must not be standard packages (like fmt), meta-patterns (std, cmd,
all), or relative or absolute file paths.
They must not be standard packages (like fmt), meta-patterns (std, cmd,
all), or relative or absolute file paths.
- All arguments must have the same version suffix. Different queries are not
allowed, even if they refer to the same version.
allowed, even if they refer to the same version.
- All arguments must refer to packages in the same module at the same version.
- No module is considered the "main" module. If the module containing
packages named on the command line has a go.mod file, it must not contain
directives (replace and exclude) that would cause it to be interpreted
differently than if it were the main module. The module must not require
a higher version of itself.
packages named on the command line has a go.mod file, it must not contain
directives (replace and exclude) that would cause it to be interpreted
differently than if it were the main module. The module must not require
a higher version of itself.
- Package path arguments must refer to main packages. Pattern arguments
will only match main packages.
will only match main packages.
If the arguments don't have version suffixes, "go install" may run in
module-aware mode or GOPATH mode, depending on the GO111MODULE environment

View File

@ -0,0 +1,55 @@
# Test that if the module cache contains an extracted source directory but not
# a ziphash, 'go build' complains about a missing sum, and 'go get' adds
# the sum. Verifies #44749.
# With a tidy go.sum, go build succeeds. This also populates the module cache.
cp go.sum.tidy go.sum
go build -n use
env GOPROXY=off
env GOSUMDB=off
# Control case: if we delete the hash for rsc.io/quote v1.5.2,
# 'go build' reports an error. 'go get' adds the sum.
cp go.sum.bug go.sum
! go build -n use
stderr '^use.go:3:8: missing go.sum entry for module providing package rsc.io/quote \(imported by use\); to add:\n\tgo get use$'
go get -d use
cmp go.sum go.sum.tidy
go build -n use
# If we delete the hash *and* the ziphash file, we should see the same behavior.
cp go.sum.bug go.sum
rm $WORK/gopath/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.ziphash
! go build -n use
stderr '^use.go:3:8: missing go.sum entry for module providing package rsc.io/quote \(imported by use\); to add:\n\tgo get use$'
go get -d use
cmp go.sum go.sum.tidy
go build -n use
-- go.mod --
module use
go 1.17
require rsc.io/quote v1.5.2
-- go.sum.tidy --
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0=
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64=
rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY=
-- go.sum.bug --
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64=
rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY=
-- use.go --
package use
import _ "rsc.io/quote"

View File

@ -0,0 +1,32 @@
# https://golang.org/issue/44776
# The '+' character should be disallowed in module paths, but allowed in package
# paths within valid modules.
go get -d example.net/cmd
go list example.net/cmd/x++
! go list -versions -m 'example.net/bad++'
stderr '^go list -m: module example.net/bad\+\+: malformed module path "example.net/bad\+\+": invalid char ''\+''$'
# TODO(bcmills): 'go get -d example.net/cmd/x++' should also work, but currently
# it does not. This might be fixed by https://golang.org/cl/297891.
! go get -d example.net/cmd/x++
stderr '^go get: malformed module path "example.net/cmd/x\+\+": invalid char ''\+''$'
-- go.mod --
module example.com/m
go 1.16
replace (
example.net/cmd => ./cmd
)
-- cmd/go.mod --
module example.net/cmd
go 1.16
-- cmd/x++/main.go --
package main
func main() {}

View File

@ -48,10 +48,13 @@ go mod tidy
grep '^rsc.io/quote v1.1.0/go.mod ' go.sum
grep '^rsc.io/quote v1.1.0 ' go.sum
# sync should ignore missing ziphash; verify should not
# verify should fail on a missing ziphash. tidy should restore it.
rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash
go mod tidy
! go mod verify
stderr '^rsc.io/quote v1.1.0: missing ziphash: open '$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]rsc.io[/\\]quote[/\\]@v[/\\]v1.1.0.ziphash'
go mod tidy
exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash
go mod verify
# Packages below module root should not be mentioned in go.sum.
rm go.sum

View File

@ -370,10 +370,16 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
r := relocs.At(ri)
switch r.Type() {
case objabi.R_CALLARM:
// r.Add is the instruction
// low 24-bit encodes the target address
t := (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4
if t > 0x7fffff || t < -0x800000 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
var t int64
// ldr.SymValue(rs) == 0 indicates a cross-package jump to a function that is not yet
// laid out. Conservatively use a trampoline. This should be rare, as we lay out packages
// in dependency order.
if ldr.SymValue(rs) != 0 {
// r.Add is the instruction
// low 24-bit encodes the target address
t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4
}
if t > 0x7fffff || t < -0x800000 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
// direct call too far, need to insert trampoline.
// look up existing trampolines first. if we found one within the range
// of direct call, we can reuse it. otherwise create a new one.
@ -445,7 +451,7 @@ func gentramp(arch *sys.Arch, linkmode ld.LinkMode, ldr *loader.Loader, tramp *l
arch.ByteOrder.PutUint32(P[8:], o3)
tramp.SetData(P)
if linkmode == ld.LinkExternal {
if linkmode == ld.LinkExternal || ldr.SymValue(target) == 0 {
r, _ := tramp.AddRel(objabi.R_ADDR)
r.SetOff(8)
r.SetSiz(4)

View File

@ -106,14 +106,12 @@ func trampoline(ctxt *Link, s loader.Sym) {
}
rs = ldr.ResolveABIAlias(rs)
if ldr.SymValue(rs) == 0 && (ldr.SymType(rs) != sym.SDYNIMPORT && ldr.SymType(rs) != sym.SUNDEFEXT) {
if ldr.SymPkg(rs) != ldr.SymPkg(s) {
if !isRuntimeDepPkg(ldr.SymPkg(s)) || !isRuntimeDepPkg(ldr.SymPkg(rs)) {
ctxt.Errorf(s, "unresolved inter-package jump to %s(%s) from %s", ldr.SymName(rs), ldr.SymPkg(rs), ldr.SymPkg(s))
}
// runtime and its dependent packages may call to each other.
// they are fine, as they will be laid down together.
if ldr.SymPkg(rs) == ldr.SymPkg(s) {
continue // symbols in the same package are laid out together
}
if isRuntimeDepPkg(ldr.SymPkg(s)) && isRuntimeDepPkg(ldr.SymPkg(rs)) {
continue // runtime packages are laid out together
}
continue
}
thearch.Trampoline(ctxt, ldr, ri, rs, s)

View File

@ -31,6 +31,7 @@
package ld
import (
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
@ -102,10 +103,14 @@ func putelfsym(ctxt *Link, x loader.Sym, typ elf.SymType, curbind elf.SymBind) {
elfshnum = xosect.Elfsect.(*ElfShdr).shnum
}
sname := ldr.SymExtname(x)
// One pass for each binding: elf.STB_LOCAL, elf.STB_GLOBAL,
// maybe one day elf.STB_WEAK.
bind := elf.STB_GLOBAL
if ldr.IsFileLocal(x) || ldr.AttrVisibilityHidden(x) || ldr.AttrLocal(x) {
if ldr.IsFileLocal(x) && !isStaticTmp(sname) || ldr.AttrVisibilityHidden(x) || ldr.AttrLocal(x) {
// Static tmp is package local, but a package can be shared among multiple DSOs.
// They need to have a single view of the static tmp that are writable.
bind = elf.STB_LOCAL
}
@ -140,8 +145,6 @@ func putelfsym(ctxt *Link, x loader.Sym, typ elf.SymType, curbind elf.SymBind) {
other |= 3 << 5
}
sname := ldr.SymExtname(x)
// When dynamically linking, we create Symbols by reading the names from
// the symbol tables of the shared libraries and so the names need to
// match exactly. Tools like DTrace will have to wait for now.
@ -823,3 +826,7 @@ func setCarrierSize(typ sym.SymKind, sz int64) {
}
CarrierSymByType[typ].Size = sz
}
func isStaticTmp(name string) bool {
return strings.Contains(name, "."+obj.StaticNamePref)
}

View File

@ -656,13 +656,19 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
relocs := ldr.Relocs(s)
r := relocs.At(ri)
t := ldr.SymValue(rs) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
var t int64
// ldr.SymValue(rs) == 0 indicates a cross-package jump to a function that is not yet
// laid out. Conservatively use a trampoline. This should be rare, as we lay out packages
// in dependency order.
if ldr.SymValue(rs) != 0 {
t = ldr.SymValue(rs) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
}
switch r.Type() {
case objabi.R_CALLPOWER:
// If branch offset is too far then create a trampoline.
if (ctxt.IsExternal() && ldr.SymSect(s) != ldr.SymSect(rs)) || (ctxt.IsInternal() && int64(int32(t<<6)>>6) != t) || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
if (ctxt.IsExternal() && ldr.SymSect(s) != ldr.SymSect(rs)) || (ctxt.IsInternal() && int64(int32(t<<6)>>6) != t) || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
var tramp loader.Sym
for i := 0; ; i++ {
@ -749,7 +755,7 @@ func gentramp(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, ta
// With external linking, the target address must be
// relocated using LO and HA
if ctxt.IsExternal() {
if ctxt.IsExternal() || ldr.SymValue(target) == 0 {
r, _ := tramp.AddRel(objabi.R_ADDRPOWER)
r.SetOff(0)
r.SetSiz(8) // generates 2 relocations: HA + LO

View File

@ -224,12 +224,16 @@ func firstPathOK(r rune) bool {
'a' <= r && r <= 'z'
}
// pathOK reports whether r can appear in an import path element.
// modPathOK reports whether r can appear in a module path element.
// Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~.
// This matches what "go get" has historically recognized in import paths.
//
// This matches what "go get" has historically recognized in import paths,
// and avoids confusing sequences like '%20' or '+' that would change meaning
// if used in a URL.
//
// TODO(rsc): We would like to allow Unicode letters, but that requires additional
// care in the safe encoding (see "escaped paths" above).
func pathOK(r rune) bool {
func modPathOK(r rune) bool {
if r < utf8.RuneSelf {
return r == '-' || r == '.' || r == '_' || r == '~' ||
'0' <= r && r <= '9' ||
@ -239,6 +243,17 @@ func pathOK(r rune) bool {
return false
}
// modPathOK reports whether r can appear in a package import path element.
//
// Import paths are intermediate between module paths and file paths: we allow
// disallow characters that would be confusing or ambiguous as arguments to
// 'go get' (such as '@' and ' ' ), but allow certain characters that are
// otherwise-unambiguous on the command line and historically used for some
// binary names (such as '++' as a suffix for compiler binaries and wrappers).
func importPathOK(r rune) bool {
return modPathOK(r) || r == '+'
}
// fileNameOK reports whether r can appear in a file name.
// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters.
// If we expand the set of allowed characters here, we have to
@ -394,12 +409,19 @@ func checkElem(elem string, kind pathKind) error {
if elem[len(elem)-1] == '.' {
return fmt.Errorf("trailing dot in path element")
}
charOK := pathOK
if kind == filePath {
charOK = fileNameOK
}
for _, r := range elem {
if !charOK(r) {
ok := false
switch kind {
case modulePath:
ok = modPathOK(r)
case importPath:
ok = importPathOK(r)
case filePath:
ok = fileNameOK(r)
default:
panic(fmt.Sprintf("internal error: invalid kind %v", kind))
}
if !ok {
return fmt.Errorf("invalid char %q", r)
}
}

View File

@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm
golang.org/x/crypto/ed25519
golang.org/x/crypto/ed25519/internal/edwards25519
golang.org/x/crypto/ssh/terminal
# golang.org/x/mod v0.4.2-0.20210302225053-d515b24adc21
# golang.org/x/mod v0.4.2-0.20210325185522-dbbbf8a3c6ea
## explicit
golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/modfile

View File

@ -23,15 +23,7 @@ fi
eval $(../bin/go env)
export GOROOT # The api test requires GOROOT to be set, so set it to match ../bin/go.
# We disallow local import for non-local packages, if $GOROOT happens
# to be under $GOPATH, then some tests below will fail. $GOPATH needs
# to be set to a non-empty string, else Go will set a default value
# that may also conflict with $GOROOT. The $GOPATH value doesn't need
# to point to an actual directory, it just needs to pass the semantic
# checks performed by Go. Use $GOROOT to define $GOPATH so that we
# don't blunder into a user-defined symbolic link.
export GOPATH=/dev/null
export GOPATH=/nonexist-gopath
unset CDPATH # in case user has it set
export GOBIN=$GOROOT/bin # Issue 14340

View File

@ -18,9 +18,7 @@ setlocal
set GOBUILDFAIL=0
:: we disallow local import for non-local packages, if %GOROOT% happens
:: to be under %GOPATH%, then some tests below will fail
set GOPATH=
set GOPATH=c:\nonexist-gopath
:: Issue 14340: ignore GOBIN during all.bat.
set GOBIN=
set GOFLAGS=

View File

@ -12,10 +12,9 @@ if(! test -f ../bin/go){
eval `{../bin/go env}
GOPATH = () # we disallow local import for non-local packages, if $GOROOT happens
# to be under $GOPATH, then some tests below will fail
GOBIN = () # Issue 14340
GOFLAGS = ()
GO111MODULE = ()
GOPATH=/nonexist-gopath
GOBIN=() # Issue 14340
GOFLAGS=()
GO111MODULE=()
exec ../bin/go tool dist test -rebuild $*

View File

@ -102,7 +102,9 @@ func (ci *Frames) Next() (frame Frame, more bool) {
name := funcname(funcInfo)
if inldata := funcdata(funcInfo, _FUNCDATA_InlTree); inldata != nil {
inltree := (*[1 << 20]inlinedCall)(inldata)
ix := pcdatavalue(funcInfo, _PCDATA_InlTreeIndex, pc, nil)
// Non-strict as cgoTraceback may have added bogus PCs
// with a valid funcInfo but invalid PCDATA.
ix := pcdatavalue1(funcInfo, _PCDATA_InlTreeIndex, pc, nil, false)
if ix >= 0 {
// Note: entry is not modified. It always refers to a real frame, not an inlined one.
f = nil

View File

@ -8,6 +8,7 @@ import (
"runtime"
"strings"
"testing"
"unsafe"
)
func TestCaller(t *testing.T) {
@ -165,3 +166,87 @@ func TestNilName(t *testing.T) {
t.Errorf("Name() = %q, want %q", got, "")
}
}
var dummy int
func inlined() {
// Side effect to prevent elimination of this entire function.
dummy = 42
}
// A function with an InlTree. Returns a PC within the function body.
//
// No inline to ensure this complete function appears in output.
//
//go:noinline
func tracebackFunc(t *testing.T) uintptr {
// This body must be more complex than a single call to inlined to get
// an inline tree.
inlined()
inlined()
// Acquire a PC in this function.
pc, _, _, ok := runtime.Caller(0)
if !ok {
t.Fatalf("Caller(0) got ok false, want true")
}
return pc
}
// Test that CallersFrames handles PCs in the alignment region between
// functions (int 3 on amd64) without crashing.
//
// Go will never generate a stack trace containing such an address, as it is
// not a valid call site. However, the cgo traceback function passed to
// runtime.SetCgoTraceback may not be completely accurate and may incorrect
// provide PCs in Go code or the alignement region between functions.
//
// Go obviously doesn't easily expose the problematic PCs to running programs,
// so this test is a bit fragile. Some details:
//
// * tracebackFunc is our target function. We want to get a PC in the
// alignment region following this function. This function also has other
// functions inlined into it to ensure it has an InlTree (this was the source
// of the bug in issue 44971).
//
// * We acquire a PC in tracebackFunc, walking forwards until FuncForPC says
// we're in a new function. The last PC of the function according to FuncForPC
// should be in the alignment region (assuming the function isn't already
// perfectly aligned).
//
// This is a regression test for issue 44971.
func TestFunctionAlignmentTraceback(t *testing.T) {
pc := tracebackFunc(t)
// Double-check we got the right PC.
f := runtime.FuncForPC(pc)
if !strings.HasSuffix(f.Name(), "tracebackFunc") {
t.Fatalf("Caller(0) = %+v, want tracebackFunc", f)
}
// Iterate forward until we find a different function. Back up one
// instruction is (hopefully) an alignment instruction.
for runtime.FuncForPC(pc) == f {
pc++
}
pc--
// Is this an alignment region filler instruction? We only check this
// on amd64 for simplicity. If this function has no filler, then we may
// get a false negative, but will never get a false positive.
if runtime.GOARCH == "amd64" {
code := *(*uint8)(unsafe.Pointer(pc))
if code != 0xcc { // INT $3
t.Errorf("PC %v code got %#x want 0xcc", pc, code)
}
}
// Finally ensure that Frames.Next doesn't crash when processing this
// PC.
frames := runtime.CallersFrames([]uintptr{pc})
frame, _ := frames.Next()
if frame.Func != f {
t.Errorf("frames.Next() got %+v want %+v", frame.Func, f)
}
}

View File

@ -263,6 +263,9 @@ func addtimer(t *timer) {
when := t.when
// Disable preemption while using pp to avoid changing another P's heap.
mp := acquirem()
pp := getg().m.p.ptr()
lock(&pp.timersLock)
cleantimers(pp)
@ -270,6 +273,8 @@ func addtimer(t *timer) {
unlock(&pp.timersLock)
wakeNetPoller(when)
releasem(mp)
}
// doaddtimer adds t to the current P's heap.

View File

@ -71,6 +71,38 @@ func TestTBHelperParallel(t *T) {
}
}
func TestTBHelperLineNumer(t *T) {
var buf bytes.Buffer
ctx := newTestContext(1, newMatcher(regexp.MatchString, "", ""))
t1 := &T{
common: common{
signal: make(chan bool),
w: &buf,
},
context: ctx,
}
t1.Run("Test", func(t *T) {
helperA := func(t *T) {
t.Helper()
t.Run("subtest", func(t *T) {
t.Helper()
t.Fatal("fatal error message")
})
}
helperA(t)
})
want := "helper_test.go:92: fatal error message"
got := ""
lines := strings.Split(strings.TrimSpace(buf.String()), "\n")
if len(lines) > 0 {
got = strings.TrimSpace(lines[len(lines)-1])
}
if got != want {
t.Errorf("got output:\n\n%v\nwant:\n\n%v", got, want)
}
}
type noopWriter int
func (nw *noopWriter) Write(b []byte) (int, error) { return len(b), nil }

View File

@ -509,6 +509,13 @@ func (c *common) frameSkip(skip int) runtime.Frame {
}
return prevFrame
}
// If more helper PCs have been added since we last did the conversion
if c.helperNames == nil {
c.helperNames = make(map[string]struct{})
for pc := range c.helperPCs {
c.helperNames[pcToName(pc)] = struct{}{}
}
}
if _, ok := c.helperNames[frame.Function]; !ok {
// Found a frame that wasn't inside a helper function.
return frame
@ -521,14 +528,6 @@ func (c *common) frameSkip(skip int) runtime.Frame {
// and inserts the final newline if needed and indentation spaces for formatting.
// This function must be called with c.mu held.
func (c *common) decorate(s string, skip int) string {
// If more helper PCs have been added since we last did the conversion
if c.helperNames == nil {
c.helperNames = make(map[string]struct{})
for pc := range c.helperPCs {
c.helperNames[pcToName(pc)] = struct{}{}
}
}
frame := c.frameSkip(skip)
file := frame.File
line := frame.Line

View File

@ -511,6 +511,22 @@ func TestZeroTimerStopPanics(t *testing.T) {
tr.Stop()
}
// Test that zero duration timers aren't missed by the scheduler. Regression test for issue 44868.
func TestZeroTimer(t *testing.T) {
if testing.Short() {
t.Skip("-short")
}
for i := 0; i < 1000000; i++ {
s := Now()
ti := NewTimer(0)
<-ti.C
if diff := Since(s); diff > 2*Second {
t.Errorf("Expected time to get value from Timer channel in less than 2 sec, took %v", diff)
}
}
}
// Benchmark timer latency when the thread that creates the timer is busy with
// other work and the timers must be serviced by other threads.
// https://golang.org/issue/38860

View File

@ -262,8 +262,8 @@ func bitcompl32(a, b uint32) (n uint32) {
return n
}
// check direct operation on memory with constant source
func bitOpOnMem(a []uint32) {
// check direct operation on memory with constant and shifted constant sources
func bitOpOnMem(a []uint32, b, c, d uint32) {
// amd64:`ANDL\s[$]200,\s\([A-Z]+\)`
a[0] &= 200
// amd64:`ORL\s[$]220,\s4\([A-Z]+\)`
@ -276,6 +276,12 @@ func bitOpOnMem(a []uint32) {
a[4] |= 0x4000
// amd64:`BTCL\s[$]13,\s20\([A-Z]+\)`,-`XORL`
a[5] ^= 0x2000
// amd64:`BTRL\s[A-Z]+,\s24\([A-Z]+\)`
a[6] &^= 1 << (b & 31)
// amd64:`BTSL\s[A-Z]+,\s28\([A-Z]+\)`
a[7] |= 1 << (c & 31)
// amd64:`BTCL\s[A-Z]+,\s32\([A-Z]+\)`
a[8] ^= 1 << (d & 31)
}
func bitcheckMostNegative(b uint8) bool {

View File

@ -0,0 +1,29 @@
// run
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
//go:noinline
func f(c bool) int {
b := true
x := 0
y := 1
for b {
b = false
y = x
x = 2
if c {
return 3
}
}
return y
}
func main() {
if got := f(false); got != 0 {
panic(got)
}
}