mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
Compare commits
59 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
49860cf92a | ||
|
f3a302358f | ||
|
1d755aa488 | ||
|
9204aca6c2 | ||
|
0ae3ca0a20 | ||
|
dae59b594c | ||
|
b7fd97ae3e | ||
|
311096a6a2 | ||
|
e9162e7e22 | ||
|
d107ee90df | ||
|
213f1566ee | ||
|
ac1f5aa3d6 | ||
|
fd29397dca | ||
|
4524009ba6 | ||
|
bd1bc8a6e7 | ||
|
c2a34bedee | ||
|
0ace2d8aca | ||
|
e4119e9b74 | ||
|
339c903a75 | ||
|
334de7982f | ||
|
5d6920842b | ||
|
949eae84df | ||
|
0bfde51e0d | ||
|
45a52718e3 | ||
|
7f375e2c22 | ||
|
4070531920 | ||
|
5ffdb9c88b | ||
|
becc17ebcd | ||
|
d418e224ae | ||
|
456eaf5c29 | ||
|
e4ef83383e | ||
|
4e6d3468cc | ||
|
f5c388313f | ||
|
af236716b2 | ||
|
0f7b7600fb | ||
|
eb58df7dbf | ||
|
30f4d9e117 | ||
|
bb0e5c2045 | ||
|
cd0e528d3d | ||
|
80e2e474b8 | ||
|
3901409b5d | ||
|
35c0ea22a9 | ||
|
6d399e9da6 | ||
|
b7b4c60585 | ||
|
18068cb96a | ||
|
c43ac38b3b | ||
|
4241f582fc | ||
|
8a4c24f9bb | ||
|
3de5aca7d0 | ||
|
8336dfde70 | ||
|
6b60550504 | ||
|
468fad45a2 | ||
|
e06b6fc58d | ||
|
b3799ba634 | ||
|
16afa6a740 | ||
|
817d7bdc0a | ||
|
14bb1e11b9 | ||
|
2297c34cdf | ||
|
26682773ca |
@ -1 +1,2 @@
|
||||
branch: master
|
||||
branch: release-branch.go1.24
|
||||
parent-branch: master
|
||||
|
@ -153,6 +153,17 @@ and the [go command documentation](/cmd/go#hdr-Build_and_test_caching).
|
||||
|
||||
### Go 1.24
|
||||
|
||||
Go 1.24 added a new `fips140` setting that controls whether the Go
|
||||
Cryptographic Module operates in FIPS 140-3 mode.
|
||||
The possible values are:
|
||||
- "off": no special support for FIPS 140-3 mode. This is the default.
|
||||
- "on": the Go Cryptographic Module operates in FIPS 140-3 mode.
|
||||
- "only": like "on", but cryptographic algorithms not approved by
|
||||
FIPS 140-3 return an error or panic.
|
||||
For more information, see [FIPS 140-3 Compliance](/doc/security/fips140).
|
||||
This setting is fixed at program startup time, and can't be modified
|
||||
by changing the `GODEBUG` environment variable after the program starts.
|
||||
|
||||
Go 1.24 changed the global [`math/rand.Seed`](/pkg/math/rand/#Seed) to be a
|
||||
no-op. This behavior is controlled by the `randseednop` setting.
|
||||
For Go 1.24 it defaults to `randseednop=1`.
|
||||
|
@ -67,26 +67,26 @@ func splitSeq(s, sep []byte, sepSave int) iter.Seq[[]byte] {
|
||||
}
|
||||
}
|
||||
|
||||
// SplitSeq returns an iterator over all substrings of s separated by sep.
|
||||
// The iterator yields the same strings that would be returned by [Split](s, sep),
|
||||
// but without constructing the slice.
|
||||
// SplitSeq returns an iterator over all subslices of s separated by sep.
|
||||
// The iterator yields the same subslices that would be returned by [Split](s, sep),
|
||||
// but without constructing a new slice containing the subslices.
|
||||
// It returns a single-use iterator.
|
||||
func SplitSeq(s, sep []byte) iter.Seq[[]byte] {
|
||||
return splitSeq(s, sep, 0)
|
||||
}
|
||||
|
||||
// SplitAfterSeq returns an iterator over substrings of s split after each instance of sep.
|
||||
// The iterator yields the same strings that would be returned by [SplitAfter](s, sep),
|
||||
// but without constructing the slice.
|
||||
// SplitAfterSeq returns an iterator over subslices of s split after each instance of sep.
|
||||
// The iterator yields the same subslices that would be returned by [SplitAfter](s, sep),
|
||||
// but without constructing a new slice containing the subslices.
|
||||
// It returns a single-use iterator.
|
||||
func SplitAfterSeq(s, sep []byte) iter.Seq[[]byte] {
|
||||
return splitSeq(s, sep, len(sep))
|
||||
}
|
||||
|
||||
// FieldsSeq returns an iterator over substrings of s split around runs of
|
||||
// FieldsSeq returns an iterator over subslices of s split around runs of
|
||||
// whitespace characters, as defined by [unicode.IsSpace].
|
||||
// The iterator yields the same strings that would be returned by [Fields](s),
|
||||
// but without constructing the slice.
|
||||
// The iterator yields the same subslices that would be returned by [Fields](s),
|
||||
// but without constructing a new slice containing the subslices.
|
||||
func FieldsSeq(s []byte) iter.Seq[[]byte] {
|
||||
return func(yield func([]byte) bool) {
|
||||
start := -1
|
||||
@ -116,10 +116,10 @@ func FieldsSeq(s []byte) iter.Seq[[]byte] {
|
||||
}
|
||||
}
|
||||
|
||||
// FieldsFuncSeq returns an iterator over substrings of s split around runs of
|
||||
// FieldsFuncSeq returns an iterator over subslices of s split around runs of
|
||||
// Unicode code points satisfying f(c).
|
||||
// The iterator yields the same strings that would be returned by [FieldsFunc](s),
|
||||
// but without constructing the slice.
|
||||
// The iterator yields the same subslices that would be returned by [FieldsFunc](s),
|
||||
// but without constructing a new slice containing the subslices.
|
||||
func FieldsFuncSeq(s []byte, f func(rune) bool) iter.Seq[[]byte] {
|
||||
return func(yield func([]byte) bool) {
|
||||
start := -1
|
||||
|
@ -42,6 +42,7 @@ import (
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/pgo"
|
||||
"cmd/internal/src"
|
||||
)
|
||||
|
||||
// Inlining budget parameters, gathered in one place
|
||||
@ -974,6 +975,16 @@ func inlineCostOK(n *ir.CallExpr, caller, callee *ir.Func, bigCaller, closureCal
|
||||
return true, 0, metric, hot
|
||||
}
|
||||
|
||||
// parsePos returns all the inlining positions and the innermost position.
|
||||
func parsePos(pos src.XPos, posTmp []src.Pos) ([]src.Pos, src.Pos) {
|
||||
ctxt := base.Ctxt
|
||||
ctxt.AllPos(pos, func(p src.Pos) {
|
||||
posTmp = append(posTmp, p)
|
||||
})
|
||||
l := len(posTmp) - 1
|
||||
return posTmp[:l], posTmp[l]
|
||||
}
|
||||
|
||||
// canInlineCallExpr returns true if the call n from caller to callee
|
||||
// can be inlined, plus the score computed for the call expr in question,
|
||||
// and whether the callee is hot according to PGO.
|
||||
@ -1001,6 +1012,17 @@ func canInlineCallExpr(callerfn *ir.Func, n *ir.CallExpr, callee *ir.Func, bigCa
|
||||
return false, 0, false
|
||||
}
|
||||
|
||||
callees, calleeInner := parsePos(n.Pos(), make([]src.Pos, 0, 10))
|
||||
|
||||
for _, p := range callees {
|
||||
if p.Line() == calleeInner.Line() && p.Col() == calleeInner.Col() && p.AbsFilename() == calleeInner.AbsFilename() {
|
||||
if log && logopt.Enabled() {
|
||||
logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", ir.FuncName(callerfn)))
|
||||
}
|
||||
return false, 0, false
|
||||
}
|
||||
}
|
||||
|
||||
if callee == callerfn {
|
||||
// Can't recursively inline a function into itself.
|
||||
if log && logopt.Enabled() {
|
||||
@ -1009,6 +1031,60 @@ func canInlineCallExpr(callerfn *ir.Func, n *ir.CallExpr, callee *ir.Func, bigCa
|
||||
return false, 0, false
|
||||
}
|
||||
|
||||
isClosureParent := func(closure, parent *ir.Func) bool {
|
||||
for p := closure.ClosureParent; p != nil; p = p.ClosureParent {
|
||||
if p == parent {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
if isClosureParent(callerfn, callee) {
|
||||
// Can't recursively inline a parent of the closure into itself.
|
||||
if log && logopt.Enabled() {
|
||||
logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to closure parent: %s, %s", ir.FuncName(callerfn), ir.FuncName(callee)))
|
||||
}
|
||||
return false, 0, false
|
||||
}
|
||||
if isClosureParent(callee, callerfn) {
|
||||
// Can't recursively inline a closure if there's a call to the parent in closure body.
|
||||
if ir.Any(callee, func(node ir.Node) bool {
|
||||
if call, ok := node.(*ir.CallExpr); ok {
|
||||
if name, ok := call.Fun.(*ir.Name); ok && isClosureParent(callerfn, name.Func) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}) {
|
||||
if log && logopt.Enabled() {
|
||||
logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to closure parent: %s, %s", ir.FuncName(callerfn), ir.FuncName(callee)))
|
||||
}
|
||||
return false, 0, false
|
||||
}
|
||||
}
|
||||
do := func(fn *ir.Func) bool {
|
||||
// Can't recursively inline a function if the function body contains
|
||||
// a call to a function f, which the function f is one of the call arguments.
|
||||
return ir.Any(fn, func(node ir.Node) bool {
|
||||
if call, ok := node.(*ir.CallExpr); ok {
|
||||
for _, arg := range call.Args {
|
||||
if call.Fun == arg {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
for _, fn := range []*ir.Func{callerfn, callee} {
|
||||
if do(fn) {
|
||||
if log && logopt.Enabled() {
|
||||
logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to function: %s", ir.FuncName(fn)))
|
||||
}
|
||||
return false, 0, false
|
||||
}
|
||||
}
|
||||
|
||||
if base.Flag.Cfg.Instrumenting && types.IsNoInstrumentPkg(callee.Sym().Pkg) {
|
||||
// Runtime package must not be instrumented.
|
||||
// Instrument skips runtime package. However, some runtime code can be
|
||||
|
@ -253,7 +253,7 @@ func (s *inlClosureState) mark(n ir.Node) ir.Node {
|
||||
|
||||
if isTestingBLoop(n) {
|
||||
// No inlining nor devirtualization performed on b.Loop body
|
||||
if base.Flag.LowerM > 1 {
|
||||
if base.Flag.LowerM > 0 {
|
||||
fmt.Printf("%v: skip inlining within testing.B.loop for %v\n", ir.Line(n), n)
|
||||
}
|
||||
// We still want to explore inlining opportunities in other parts of ForStmt.
|
||||
|
@ -1148,10 +1148,12 @@
|
||||
(SUB a l:(MNEGW x y)) && v.Type.Size() <= 4 && l.Uses==1 && clobber(l) => (MADDW a x y)
|
||||
|
||||
// madd/msub can't take constant arguments, so do a bit of reordering if a non-constant is available.
|
||||
(ADD a p:(ADDconst [c] m:((MUL|MULW|MNEG|MNEGW) _ _))) && p.Uses==1 && m.Uses==1 => (ADDconst [c] (ADD <v.Type> a m))
|
||||
(ADD a p:(SUBconst [c] m:((MUL|MULW|MNEG|MNEGW) _ _))) && p.Uses==1 && m.Uses==1 => (SUBconst [c] (ADD <v.Type> a m))
|
||||
(SUB a p:(ADDconst [c] m:((MUL|MULW|MNEG|MNEGW) _ _))) && p.Uses==1 && m.Uses==1 => (SUBconst [c] (SUB <v.Type> a m))
|
||||
(SUB a p:(SUBconst [c] m:((MUL|MULW|MNEG|MNEGW) _ _))) && p.Uses==1 && m.Uses==1 => (ADDconst [c] (SUB <v.Type> a m))
|
||||
// Note: don't reorder arithmetic concerning pointers, as we must ensure that
|
||||
// no intermediate computations are invalid pointers.
|
||||
(ADD <t> a p:(ADDconst [c] m:((MUL|MULW|MNEG|MNEGW) _ _))) && p.Uses==1 && m.Uses==1 && !t.IsPtrShaped() => (ADDconst [c] (ADD <v.Type> a m))
|
||||
(ADD <t> a p:(SUBconst [c] m:((MUL|MULW|MNEG|MNEGW) _ _))) && p.Uses==1 && m.Uses==1 && !t.IsPtrShaped() => (SUBconst [c] (ADD <v.Type> a m))
|
||||
(SUB <t> a p:(ADDconst [c] m:((MUL|MULW|MNEG|MNEGW) _ _))) && p.Uses==1 && m.Uses==1 && !t.IsPtrShaped() => (SUBconst [c] (SUB <v.Type> a m))
|
||||
(SUB <t> a p:(SUBconst [c] m:((MUL|MULW|MNEG|MNEGW) _ _))) && p.Uses==1 && m.Uses==1 && !t.IsPtrShaped() => (ADDconst [c] (SUB <v.Type> a m))
|
||||
|
||||
// optimize ADCSflags, SBCSflags and friends
|
||||
(ADCSflags x y (Select1 <types.TypeFlags> (ADDSconstflags [-1] (ADCzerocarry <typ.UInt64> c)))) => (ADCSflags x y c)
|
||||
|
@ -41,11 +41,12 @@ type Func struct {
|
||||
ABISelf *abi.ABIConfig // ABI for function being compiled
|
||||
ABIDefault *abi.ABIConfig // ABI for rtcall and other no-parsed-signature/pragma functions.
|
||||
|
||||
scheduled bool // Values in Blocks are in final order
|
||||
laidout bool // Blocks are ordered
|
||||
NoSplit bool // true if function is marked as nosplit. Used by schedule check pass.
|
||||
dumpFileSeq uint8 // the sequence numbers of dump file. (%s_%02d__%s.dump", funcname, dumpFileSeq, phaseName)
|
||||
IsPgoHot bool
|
||||
scheduled bool // Values in Blocks are in final order
|
||||
laidout bool // Blocks are ordered
|
||||
NoSplit bool // true if function is marked as nosplit. Used by schedule check pass.
|
||||
dumpFileSeq uint8 // the sequence numbers of dump file. (%s_%02d__%s.dump", funcname, dumpFileSeq, phaseName)
|
||||
IsPgoHot bool
|
||||
HasDeferRangeFunc bool // if true, needs a deferreturn so deferrangefunc can use it for recover() return PC
|
||||
|
||||
// when register allocation is done, maps value ids to locations
|
||||
RegAlloc []Location
|
||||
|
@ -552,8 +552,9 @@ func (ft *factsTable) newLimit(v *Value, newLim limit) bool {
|
||||
}
|
||||
|
||||
if lim.unsat() {
|
||||
r := !ft.unsat
|
||||
ft.unsat = true
|
||||
return true
|
||||
return r
|
||||
}
|
||||
|
||||
// Check for recursion. This normally happens because in unsatisfiable
|
||||
|
@ -1670,6 +1670,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
}
|
||||
tmpReg = s.allocReg(m, &tmpVal)
|
||||
s.nospill |= regMask(1) << tmpReg
|
||||
s.tmpused |= regMask(1) << tmpReg
|
||||
}
|
||||
|
||||
// Now that all args are in regs, we're ready to issue the value itself.
|
||||
|
@ -1331,10 +1331,11 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (ADD a p:(ADDconst [c] m:(MUL _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (ADD <t> a p:(ADDconst [c] m:(MUL _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (ADDconst [c] (ADD <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
a := v_0
|
||||
p := v_1
|
||||
@ -1343,7 +1344,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MUL || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MUL || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpARM64ADDconst)
|
||||
@ -1355,10 +1356,11 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (ADD a p:(ADDconst [c] m:(MULW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (ADD <t> a p:(ADDconst [c] m:(MULW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (ADDconst [c] (ADD <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
a := v_0
|
||||
p := v_1
|
||||
@ -1367,7 +1369,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MULW || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MULW || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpARM64ADDconst)
|
||||
@ -1379,10 +1381,11 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (ADD a p:(ADDconst [c] m:(MNEG _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (ADD <t> a p:(ADDconst [c] m:(MNEG _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (ADDconst [c] (ADD <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
a := v_0
|
||||
p := v_1
|
||||
@ -1391,7 +1394,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MNEG || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MNEG || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpARM64ADDconst)
|
||||
@ -1403,10 +1406,11 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (ADD a p:(ADDconst [c] m:(MNEGW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (ADD <t> a p:(ADDconst [c] m:(MNEGW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (ADDconst [c] (ADD <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
a := v_0
|
||||
p := v_1
|
||||
@ -1415,7 +1419,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MNEGW || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MNEGW || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpARM64ADDconst)
|
||||
@ -1427,10 +1431,11 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (ADD a p:(SUBconst [c] m:(MUL _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (ADD <t> a p:(SUBconst [c] m:(MUL _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (SUBconst [c] (ADD <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
a := v_0
|
||||
p := v_1
|
||||
@ -1439,7 +1444,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MUL || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MUL || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpARM64SUBconst)
|
||||
@ -1451,10 +1456,11 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (ADD a p:(SUBconst [c] m:(MULW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (ADD <t> a p:(SUBconst [c] m:(MULW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (SUBconst [c] (ADD <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
a := v_0
|
||||
p := v_1
|
||||
@ -1463,7 +1469,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MULW || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MULW || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpARM64SUBconst)
|
||||
@ -1475,10 +1481,11 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (ADD a p:(SUBconst [c] m:(MNEG _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (ADD <t> a p:(SUBconst [c] m:(MNEG _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (SUBconst [c] (ADD <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
a := v_0
|
||||
p := v_1
|
||||
@ -1487,7 +1494,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MNEG || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MNEG || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpARM64SUBconst)
|
||||
@ -1499,10 +1506,11 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (ADD a p:(SUBconst [c] m:(MNEGW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (ADD <t> a p:(SUBconst [c] m:(MNEGW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (SUBconst [c] (ADD <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
a := v_0
|
||||
p := v_1
|
||||
@ -1511,7 +1519,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MNEGW || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MNEGW || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpARM64SUBconst)
|
||||
@ -16604,10 +16612,11 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
v.AddArg3(a, x, y)
|
||||
return true
|
||||
}
|
||||
// match: (SUB a p:(ADDconst [c] m:(MUL _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (SUB <t> a p:(ADDconst [c] m:(MUL _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (SUBconst [c] (SUB <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
a := v_0
|
||||
p := v_1
|
||||
if p.Op != OpARM64ADDconst {
|
||||
@ -16615,7 +16624,7 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MUL || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MUL || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64SUBconst)
|
||||
@ -16625,10 +16634,11 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (SUB a p:(ADDconst [c] m:(MULW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (SUB <t> a p:(ADDconst [c] m:(MULW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (SUBconst [c] (SUB <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
a := v_0
|
||||
p := v_1
|
||||
if p.Op != OpARM64ADDconst {
|
||||
@ -16636,7 +16646,7 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MULW || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MULW || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64SUBconst)
|
||||
@ -16646,10 +16656,11 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (SUB a p:(ADDconst [c] m:(MNEG _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (SUB <t> a p:(ADDconst [c] m:(MNEG _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (SUBconst [c] (SUB <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
a := v_0
|
||||
p := v_1
|
||||
if p.Op != OpARM64ADDconst {
|
||||
@ -16657,7 +16668,7 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MNEG || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MNEG || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64SUBconst)
|
||||
@ -16667,10 +16678,11 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (SUB a p:(ADDconst [c] m:(MNEGW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (SUB <t> a p:(ADDconst [c] m:(MNEGW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (SUBconst [c] (SUB <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
a := v_0
|
||||
p := v_1
|
||||
if p.Op != OpARM64ADDconst {
|
||||
@ -16678,7 +16690,7 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MNEGW || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MNEGW || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64SUBconst)
|
||||
@ -16688,10 +16700,11 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (SUB a p:(SUBconst [c] m:(MUL _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (SUB <t> a p:(SUBconst [c] m:(MUL _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (ADDconst [c] (SUB <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
a := v_0
|
||||
p := v_1
|
||||
if p.Op != OpARM64SUBconst {
|
||||
@ -16699,7 +16712,7 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MUL || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MUL || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64ADDconst)
|
||||
@ -16709,10 +16722,11 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (SUB a p:(SUBconst [c] m:(MULW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (SUB <t> a p:(SUBconst [c] m:(MULW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (ADDconst [c] (SUB <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
a := v_0
|
||||
p := v_1
|
||||
if p.Op != OpARM64SUBconst {
|
||||
@ -16720,7 +16734,7 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MULW || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MULW || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64ADDconst)
|
||||
@ -16730,10 +16744,11 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (SUB a p:(SUBconst [c] m:(MNEG _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (SUB <t> a p:(SUBconst [c] m:(MNEG _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (ADDconst [c] (SUB <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
a := v_0
|
||||
p := v_1
|
||||
if p.Op != OpARM64SUBconst {
|
||||
@ -16741,7 +16756,7 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MNEG || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MNEG || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64ADDconst)
|
||||
@ -16751,10 +16766,11 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (SUB a p:(SUBconst [c] m:(MNEGW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1
|
||||
// match: (SUB <t> a p:(SUBconst [c] m:(MNEGW _ _)))
|
||||
// cond: p.Uses==1 && m.Uses==1 && !t.IsPtrShaped()
|
||||
// result: (ADDconst [c] (SUB <v.Type> a m))
|
||||
for {
|
||||
t := v.Type
|
||||
a := v_0
|
||||
p := v_1
|
||||
if p.Op != OpARM64SUBconst {
|
||||
@ -16762,7 +16778,7 @@ func rewriteValueARM64_OpARM64SUB(v *Value) bool {
|
||||
}
|
||||
c := auxIntToInt64(p.AuxInt)
|
||||
m := p.Args[0]
|
||||
if m.Op != OpARM64MNEGW || !(p.Uses == 1 && m.Uses == 1) {
|
||||
if m.Op != OpARM64MNEGW || !(p.Uses == 1 && m.Uses == 1 && !t.IsPtrShaped()) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64ADDconst)
|
||||
|
@ -4433,6 +4433,9 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool, deferExt
|
||||
callABI = s.f.ABI1
|
||||
}
|
||||
}
|
||||
if fn := n.Fun.Sym().Name; n.Fun.Sym().Pkg == ir.Pkgs.Runtime && fn == "deferrangefunc" {
|
||||
s.f.HasDeferRangeFunc = true
|
||||
}
|
||||
break
|
||||
}
|
||||
closure = s.expr(fn)
|
||||
@ -6566,10 +6569,13 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
|
||||
// nop (which will never execute) after the call.
|
||||
Arch.Ginsnop(s.pp)
|
||||
}
|
||||
if openDeferInfo != nil {
|
||||
if openDeferInfo != nil || f.HasDeferRangeFunc {
|
||||
// When doing open-coded defers, generate a disconnected call to
|
||||
// deferreturn and a return. This will be used to during panic
|
||||
// recovery to unwind the stack and return back to the runtime.
|
||||
//
|
||||
// deferrangefunc needs to be sure that at least one of these exists;
|
||||
// if all returns are dead-code eliminated, there might not be.
|
||||
s.pp.NextLive = s.livenessMap.DeferReturn
|
||||
p := s.pp.Prog(obj.ACALL)
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
|
@ -230,6 +230,9 @@ func TestIntendedInlining(t *testing.T) {
|
||||
"(*Pointer[go.shape.int]).Store",
|
||||
"(*Pointer[go.shape.int]).Swap",
|
||||
},
|
||||
"testing": {
|
||||
"(*B).Loop",
|
||||
},
|
||||
}
|
||||
|
||||
if !goexperiment.SwissMap {
|
||||
|
@ -204,7 +204,7 @@ func (check *Checker) lhsVar(lhs syntax.Expr) Type {
|
||||
// dot-imported variables.
|
||||
if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
|
||||
v = w
|
||||
v_used = v.used
|
||||
v_used = check.usedVars[v]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -213,7 +213,7 @@ func (check *Checker) lhsVar(lhs syntax.Expr) Type {
|
||||
check.expr(nil, &x, lhs)
|
||||
|
||||
if v != nil {
|
||||
v.used = v_used // restore v.used
|
||||
check.usedVars[v] = v_used // restore v.used
|
||||
}
|
||||
|
||||
if x.mode == invalid || !isValid(x.typ) {
|
||||
|
@ -687,7 +687,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *TypeName
|
||||
if pname, _ := obj.(*PkgName); pname != nil {
|
||||
assert(pname.pkg == check.pkg)
|
||||
check.recordUse(ident, pname)
|
||||
pname.used = true
|
||||
check.usedPkgNames[pname] = true
|
||||
pkg := pname.imported
|
||||
|
||||
var exp Object
|
||||
@ -972,13 +972,13 @@ func (check *Checker) use1(e syntax.Expr, lhs bool) bool {
|
||||
// dot-imported variables.
|
||||
if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
|
||||
v = w
|
||||
v_used = v.used
|
||||
v_used = check.usedVars[v]
|
||||
}
|
||||
}
|
||||
}
|
||||
check.exprOrType(&x, n, true)
|
||||
if v != nil {
|
||||
v.used = v_used // restore v.used
|
||||
check.usedVars[v] = v_used // restore v.used
|
||||
}
|
||||
case *syntax.ListExpr:
|
||||
return check.useN(n.ElemList, lhs)
|
||||
|
@ -162,6 +162,8 @@ type Checker struct {
|
||||
dotImportMap map[dotImportKey]*PkgName // maps dot-imported objects to the package they were dot-imported through
|
||||
brokenAliases map[*TypeName]bool // set of aliases with broken (not yet determined) types
|
||||
unionTypeSets map[*Union]*_TypeSet // computed type sets for union types
|
||||
usedVars map[*Var]bool // set of used variables
|
||||
usedPkgNames map[*PkgName]bool // set of used package names
|
||||
mono monoGraph // graph for detecting non-monomorphizable instantiation loops
|
||||
|
||||
firstErr error // first error encountered
|
||||
@ -285,12 +287,14 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
|
||||
// (previously, pkg.goVersion was mutated here: go.dev/issue/61212)
|
||||
|
||||
return &Checker{
|
||||
conf: conf,
|
||||
ctxt: conf.Context,
|
||||
pkg: pkg,
|
||||
Info: info,
|
||||
objMap: make(map[Object]*declInfo),
|
||||
impMap: make(map[importKey]*Package),
|
||||
conf: conf,
|
||||
ctxt: conf.Context,
|
||||
pkg: pkg,
|
||||
Info: info,
|
||||
objMap: make(map[Object]*declInfo),
|
||||
impMap: make(map[importKey]*Package),
|
||||
usedVars: make(map[*Var]bool),
|
||||
usedPkgNames: make(map[*PkgName]bool),
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,6 +302,8 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
|
||||
// The provided files must all belong to the same package.
|
||||
func (check *Checker) initFiles(files []*syntax.File) {
|
||||
// start with a clean slate (check.Files may be called multiple times)
|
||||
// TODO(gri): what determines which fields are zeroed out here, vs at the end
|
||||
// of checkFiles?
|
||||
check.files = nil
|
||||
check.imports = nil
|
||||
check.dotImportMap = nil
|
||||
@ -309,6 +315,13 @@ func (check *Checker) initFiles(files []*syntax.File) {
|
||||
check.objPath = nil
|
||||
check.cleaners = nil
|
||||
|
||||
// We must initialize usedVars and usedPkgNames both here and in NewChecker,
|
||||
// because initFiles is not called in the CheckExpr or Eval codepaths, yet we
|
||||
// want to free this memory at the end of Files ('used' predicates are
|
||||
// only needed in the context of a given file).
|
||||
check.usedVars = make(map[*Var]bool)
|
||||
check.usedPkgNames = make(map[*PkgName]bool)
|
||||
|
||||
// determine package name and collect valid files
|
||||
pkg := check.pkg
|
||||
for _, file := range files {
|
||||
@ -482,8 +495,11 @@ func (check *Checker) checkFiles(files []*syntax.File) {
|
||||
check.seenPkgMap = nil
|
||||
check.brokenAliases = nil
|
||||
check.unionTypeSets = nil
|
||||
check.usedVars = nil
|
||||
check.usedPkgNames = nil
|
||||
check.ctxt = nil
|
||||
|
||||
// TODO(gri): shouldn't the cleanup above occur after the bailout?
|
||||
// TODO(gri) There's more memory we should release at this point.
|
||||
}
|
||||
|
||||
|
@ -242,13 +242,12 @@ func (a *object) cmp(b *object) int {
|
||||
type PkgName struct {
|
||||
object
|
||||
imported *Package
|
||||
used bool // set if the package was used
|
||||
}
|
||||
|
||||
// NewPkgName returns a new PkgName object representing an imported package.
|
||||
// The remaining arguments set the attributes found with all Objects.
|
||||
func NewPkgName(pos syntax.Pos, pkg *Package, name string, imported *Package) *PkgName {
|
||||
return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, black, nopos}, imported, false}
|
||||
return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, black, nopos}, imported}
|
||||
}
|
||||
|
||||
// Imported returns the package that was imported.
|
||||
@ -331,10 +330,10 @@ func (obj *TypeName) IsAlias() bool {
|
||||
// A Variable represents a declared variable (including function parameters and results, and struct fields).
|
||||
type Var struct {
|
||||
object
|
||||
origin *Var // if non-nil, the Var from which this one was instantiated
|
||||
embedded bool // if set, the variable is an embedded struct field, and name is the type name
|
||||
isField bool // var is struct field
|
||||
used bool // set if the variable was used
|
||||
origin *Var // if non-nil, the Var from which this one was instantiated
|
||||
isParam bool // var is a param, for backport of 'used' check to go1.24 (go.dev/issue/72826)
|
||||
}
|
||||
|
||||
// NewVar returns a new variable.
|
||||
@ -345,7 +344,7 @@ func NewVar(pos syntax.Pos, pkg *Package, name string, typ Type) *Var {
|
||||
|
||||
// NewParam returns a new variable representing a function parameter.
|
||||
func NewParam(pos syntax.Pos, pkg *Package, name string, typ Type) *Var {
|
||||
return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, used: true} // parameters are always 'used'
|
||||
return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, isParam: true}
|
||||
}
|
||||
|
||||
// NewField returns a new variable representing a struct field.
|
||||
|
@ -295,7 +295,7 @@ func (check *Checker) collectObjects() {
|
||||
|
||||
if imp.fake {
|
||||
// match 1.17 cmd/compile (not prescribed by spec)
|
||||
pkgName.used = true
|
||||
check.usedPkgNames[pkgName] = true
|
||||
}
|
||||
|
||||
// add import to file scope
|
||||
@ -715,7 +715,7 @@ func (check *Checker) unusedImports() {
|
||||
// (initialization), use the blank identifier as explicit package name."
|
||||
|
||||
for _, obj := range check.imports {
|
||||
if !obj.used && obj.name != "_" {
|
||||
if obj.name != "_" && !check.usedPkgNames[obj] {
|
||||
check.errorUnusedPkg(obj)
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ func TestSizeof(t *testing.T) {
|
||||
{term{}, 12, 24},
|
||||
|
||||
// Objects
|
||||
{PkgName{}, 64, 104},
|
||||
{PkgName{}, 60, 96},
|
||||
{Const{}, 64, 104},
|
||||
{TypeName{}, 56, 88},
|
||||
{Var{}, 64, 104},
|
||||
|
@ -58,7 +58,7 @@ func (check *Checker) usage(scope *Scope) {
|
||||
var unused []*Var
|
||||
for name, elem := range scope.elems {
|
||||
elem = resolve(name, elem)
|
||||
if v, _ := elem.(*Var); v != nil && !v.used {
|
||||
if v, _ := elem.(*Var); v != nil && !v.isParam && !check.usedVars[v] {
|
||||
unused = append(unused, v)
|
||||
}
|
||||
}
|
||||
@ -824,10 +824,10 @@ func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, gu
|
||||
if lhs != nil {
|
||||
var used bool
|
||||
for _, v := range lhsVars {
|
||||
if v.used {
|
||||
if check.usedVars[v] {
|
||||
used = true
|
||||
}
|
||||
v.used = true // avoid usage error when checking entire function
|
||||
check.usedVars[v] = true // avoid usage error when checking entire function
|
||||
}
|
||||
if !used {
|
||||
check.softErrorf(lhs, UnusedVar, "%s declared and not used", lhs.Value)
|
||||
@ -934,7 +934,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
|
||||
if typ == nil || typ == Typ[Invalid] {
|
||||
// typ == Typ[Invalid] can happen if allowVersion fails.
|
||||
obj.typ = Typ[Invalid]
|
||||
obj.used = true // don't complain about unused variable
|
||||
check.usedVars[obj] = true // don't complain about unused variable
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType
|
||||
// avoid "declared but not used" errors
|
||||
// (don't use Checker.use - we don't want to evaluate too much)
|
||||
if v, _ := obj.(*Var); v != nil && v.pkg == check.pkg /* see Checker.use1 */ {
|
||||
v.used = true
|
||||
check.usedVars[v] = true
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -83,7 +83,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType
|
||||
// (This code is only needed for dot-imports. Without them,
|
||||
// we only have to mark variables, see *Var case below).
|
||||
if pkgName := check.dotImportMap[dotImportKey{scope, obj.Name()}]; pkgName != nil {
|
||||
pkgName.used = true
|
||||
check.usedPkgNames[pkgName] = true
|
||||
}
|
||||
|
||||
switch obj := obj.(type) {
|
||||
@ -120,7 +120,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType
|
||||
// from other packages to avoid potential race conditions with
|
||||
// dot-imported variables.
|
||||
if obj.pkg == check.pkg {
|
||||
obj.used = true
|
||||
check.usedVars[obj] = true
|
||||
}
|
||||
check.addDeclDep(obj)
|
||||
if !isValid(typ) {
|
||||
|
@ -128,7 +128,8 @@ func runGoAuth(client *http.Client, res *http.Response, url string) {
|
||||
// If no GOAUTH command provided a credential for the given url
|
||||
// and an error occurred, log the error.
|
||||
if cfg.BuildX && url != "" {
|
||||
if ok := loadCredential(&http.Request{}, url); !ok && len(cmdErrs) > 0 {
|
||||
req := &http.Request{Header: make(http.Header)}
|
||||
if ok := loadCredential(req, url); !ok && len(cmdErrs) > 0 {
|
||||
log.Printf("GOAUTH encountered errors for %s:", url)
|
||||
for _, err := range cmdErrs {
|
||||
log.Printf(" %v", err)
|
||||
|
@ -227,21 +227,6 @@ var validLinkerFlags = []*lazyregexp.Regexp{
|
||||
re(`\./.*\.(a|o|obj|dll|dylib|so|tbd)`),
|
||||
}
|
||||
|
||||
var validLinkerFlagsOnDarwin = []*lazyregexp.Regexp{
|
||||
// The GNU linker interprets `@file` as "read command-line options from
|
||||
// file". Thus, we forbid values starting with `@` on linker flags.
|
||||
// However, this causes a problem when targeting Darwin.
|
||||
// `@executable_path`, `@loader_path`, and `@rpath` are special values
|
||||
// used in Mach-O to change the library search path and can be used in
|
||||
// conjunction with the `-install_name` and `-rpath` linker flags.
|
||||
// Since the GNU linker does not support Mach-O, targeting Darwin
|
||||
// implies not using the GNU linker. Therefore, we allow @ in the linker
|
||||
// flags if and only if cfg.Goos == "darwin" || cfg.Goos == "ios".
|
||||
re(`-Wl,-dylib_install_name,@rpath(/[^,]*)?`),
|
||||
re(`-Wl,-install_name,@rpath(/[^,]*)?`),
|
||||
re(`-Wl,-rpath,@(executable_path|loader_path)(/[^,]*)?`),
|
||||
}
|
||||
|
||||
var validLinkerFlagsWithNextArg = []string{
|
||||
"-arch",
|
||||
"-F",
|
||||
@ -264,13 +249,8 @@ func checkCompilerFlags(name, source string, list []string) error {
|
||||
}
|
||||
|
||||
func checkLinkerFlags(name, source string, list []string) error {
|
||||
validLinkerFlagsForPlatform := validLinkerFlags
|
||||
if cfg.Goos == "darwin" || cfg.Goos == "ios" {
|
||||
validLinkerFlagsForPlatform = append(validLinkerFlags, validLinkerFlagsOnDarwin...)
|
||||
}
|
||||
|
||||
checkOverrides := true
|
||||
return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlagsForPlatform, validLinkerFlagsWithNextArg, checkOverrides)
|
||||
return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides)
|
||||
}
|
||||
|
||||
// checkCompilerFlagsForInternalLink returns an error if 'list'
|
||||
|
@ -8,8 +8,6 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"cmd/go/internal/cfg"
|
||||
)
|
||||
|
||||
var goodCompilerFlags = [][]string{
|
||||
@ -247,8 +245,6 @@ var badLinkerFlags = [][]string{
|
||||
{"-Wl,--hash-style=foo"},
|
||||
{"-x", "--c"},
|
||||
{"-x", "@obj"},
|
||||
{"-Wl,-dylib_install_name,@foo"},
|
||||
{"-Wl,-install_name,@foo"},
|
||||
{"-Wl,-rpath,@foo"},
|
||||
{"-Wl,-R,foo,bar"},
|
||||
{"-Wl,-R,@foo"},
|
||||
@ -265,21 +261,6 @@ var badLinkerFlags = [][]string{
|
||||
{"./-Wl,--push-state,-R.c"},
|
||||
}
|
||||
|
||||
var goodLinkerFlagsOnDarwin = [][]string{
|
||||
{"-Wl,-dylib_install_name,@rpath"},
|
||||
{"-Wl,-dylib_install_name,@rpath/"},
|
||||
{"-Wl,-dylib_install_name,@rpath/foo"},
|
||||
{"-Wl,-install_name,@rpath"},
|
||||
{"-Wl,-install_name,@rpath/"},
|
||||
{"-Wl,-install_name,@rpath/foo"},
|
||||
{"-Wl,-rpath,@executable_path"},
|
||||
{"-Wl,-rpath,@executable_path/"},
|
||||
{"-Wl,-rpath,@executable_path/foo"},
|
||||
{"-Wl,-rpath,@loader_path"},
|
||||
{"-Wl,-rpath,@loader_path/"},
|
||||
{"-Wl,-rpath,@loader_path/foo"},
|
||||
}
|
||||
|
||||
func TestCheckLinkerFlags(t *testing.T) {
|
||||
for _, f := range goodLinkerFlags {
|
||||
if err := checkLinkerFlags("test", "test", f); err != nil {
|
||||
@ -291,31 +272,6 @@ func TestCheckLinkerFlags(t *testing.T) {
|
||||
t.Errorf("missing error for %q", f)
|
||||
}
|
||||
}
|
||||
|
||||
goos := cfg.Goos
|
||||
|
||||
cfg.Goos = "darwin"
|
||||
for _, f := range goodLinkerFlagsOnDarwin {
|
||||
if err := checkLinkerFlags("test", "test", f); err != nil {
|
||||
t.Errorf("unexpected error for %q: %v", f, err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Goos = "ios"
|
||||
for _, f := range goodLinkerFlagsOnDarwin {
|
||||
if err := checkLinkerFlags("test", "test", f); err != nil {
|
||||
t.Errorf("unexpected error for %q: %v", f, err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Goos = "linux"
|
||||
for _, f := range goodLinkerFlagsOnDarwin {
|
||||
if err := checkLinkerFlags("test", "test", f); err == nil {
|
||||
t.Errorf("missing error for %q", f)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Goos = goos
|
||||
}
|
||||
|
||||
func TestCheckFlagAllowDisallow(t *testing.T) {
|
||||
|
2
src/cmd/go/testdata/script/goauth_git.txt
vendored
2
src/cmd/go/testdata/script/goauth_git.txt
vendored
@ -49,6 +49,8 @@ go get vcs-test.golang.org/auth/or401
|
||||
go mod tidy
|
||||
go list all
|
||||
stdout vcs-test.golang.org/auth/or404
|
||||
# With cached credentials, re-downloading in debug mode should succeed.
|
||||
go get -x vcs-test.golang.org/auth/or401
|
||||
|
||||
# Clearing GOAUTH credentials should result in failures.
|
||||
env GOAUTH='off'
|
||||
|
@ -43,6 +43,9 @@ type PkgSpecial struct {
|
||||
}
|
||||
|
||||
var runtimePkgs = []string{
|
||||
// TODO(panjf2000): consider syncing the list inside the
|
||||
// isAsyncSafePoint in preempt.go based on this list?
|
||||
|
||||
"runtime",
|
||||
|
||||
"internal/runtime/atomic",
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
"internal/godebug"
|
||||
)
|
||||
|
||||
var fips140GODEBUG = godebug.New("#fips140")
|
||||
var fips140GODEBUG = godebug.New("fips140")
|
||||
|
||||
// Enabled reports whether the cryptography libraries are operating in FIPS
|
||||
// 140-3 mode.
|
||||
|
@ -100,7 +100,7 @@ func init() {
|
||||
clear(nbuf[:])
|
||||
h.Reset()
|
||||
|
||||
if godebug.Value("#fips140") == "debug" {
|
||||
if godebug.Value("fips140") == "debug" {
|
||||
println("fips140: verified code+data")
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
|
||||
// Enabled reports whether FIPS 140-only mode is enabled, in which non-approved
|
||||
// cryptography returns an error or panics.
|
||||
var Enabled = godebug.New("#fips140").Value() == "only"
|
||||
var Enabled = godebug.New("fips140").Value() == "only"
|
||||
|
||||
func ApprovedHash(h hash.Hash) bool {
|
||||
switch h.(type) {
|
||||
|
@ -26,7 +26,7 @@ func TestFIPSCheckVerify(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
if godebug.New("#fips140").Value() == "on" {
|
||||
if godebug.New("fips140").Value() == "on" {
|
||||
t.Fatalf("GODEBUG=fips140=on but verification did not run")
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,8 @@ var defaultCipherSuitesTLS13NoAES = []uint16{
|
||||
}
|
||||
|
||||
// The FIPS-only policies below match BoringSSL's
|
||||
// ssl_compliance_policy_fips_202205, which is based on NIST SP 800-52r2.
|
||||
// ssl_compliance_policy_fips_202205, which is based on NIST SP 800-52r2, with
|
||||
// minor changes per https://go.dev/issue/71757.
|
||||
// https://cs.opensource.google/boringssl/boringssl/+/master:ssl/ssl_lib.cc;l=3289;drc=ea7a88fa
|
||||
|
||||
var defaultSupportedVersionsFIPS = []uint16{
|
||||
@ -102,7 +103,7 @@ var defaultSupportedVersionsFIPS = []uint16{
|
||||
|
||||
// defaultCurvePreferencesFIPS are the FIPS-allowed curves,
|
||||
// in preference order (most preferable first).
|
||||
var defaultCurvePreferencesFIPS = []CurveID{CurveP256, CurveP384}
|
||||
var defaultCurvePreferencesFIPS = []CurveID{CurveP256, CurveP384, CurveP521}
|
||||
|
||||
// defaultSupportedSignatureAlgorithmsFIPS currently are a subset of
|
||||
// defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1.
|
||||
@ -115,6 +116,7 @@ var defaultSupportedSignatureAlgorithmsFIPS = []SignatureScheme{
|
||||
PKCS1WithSHA384,
|
||||
ECDSAWithP384AndSHA384,
|
||||
PKCS1WithSHA512,
|
||||
ECDSAWithP521AndSHA512,
|
||||
}
|
||||
|
||||
// defaultCipherSuitesFIPS are the FIPS-allowed cipher suites.
|
||||
|
@ -106,7 +106,7 @@ func isFIPSCipherSuite(id uint16) bool {
|
||||
|
||||
func isFIPSCurve(id CurveID) bool {
|
||||
switch id {
|
||||
case CurveP256, CurveP384:
|
||||
case CurveP256, CurveP384, CurveP521:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -130,6 +130,7 @@ func isFIPSSignatureScheme(alg SignatureScheme) bool {
|
||||
PKCS1WithSHA384,
|
||||
ECDSAWithP384AndSHA384,
|
||||
PKCS1WithSHA512,
|
||||
ECDSAWithP521AndSHA512,
|
||||
PSSWithSHA256,
|
||||
PSSWithSHA384,
|
||||
PSSWithSHA512:
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"encoding/binary"
|
||||
"flag"
|
||||
"fmt"
|
||||
"internal/obscuretestdata"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"os/exec"
|
||||
@ -275,24 +276,16 @@ func TestReadFile(t *testing.T) {
|
||||
|
||||
// Test117 verifies that parsing of the old, pre-1.18 format works.
|
||||
func Test117(t *testing.T) {
|
||||
// go117 was generated for linux-amd64 with:
|
||||
//
|
||||
// main.go:
|
||||
//
|
||||
// package main
|
||||
// func main() {}
|
||||
//
|
||||
// GOTOOLCHAIN=go1.17 go mod init example.com/go117
|
||||
// GOTOOLCHAIN=go1.17 go build
|
||||
//
|
||||
// TODO(prattmic): Ideally this would be built on the fly to better
|
||||
// cover all executable formats, but then we need a network connection
|
||||
// to download an old Go toolchain.
|
||||
info, err := buildinfo.ReadFile("testdata/go117")
|
||||
b, err := obscuretestdata.ReadFile("testdata/go117/go117.base64")
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile got err %v, want nil", err)
|
||||
}
|
||||
|
||||
info, err := buildinfo.Read(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
t.Fatalf("Read got err %v, want nil", err)
|
||||
}
|
||||
|
||||
if info.GoVersion != "go1.17" {
|
||||
t.Errorf("GoVersion got %s want go1.17", info.GoVersion)
|
||||
}
|
||||
@ -306,20 +299,14 @@ func Test117(t *testing.T) {
|
||||
|
||||
// TestNotGo verifies that parsing of a non-Go binary returns the proper error.
|
||||
func TestNotGo(t *testing.T) {
|
||||
// notgo was generated for linux-amd64 with:
|
||||
//
|
||||
// main.c:
|
||||
//
|
||||
// int main(void) { return 0; }
|
||||
//
|
||||
// cc -o notgo main.c
|
||||
//
|
||||
// TODO(prattmic): Ideally this would be built on the fly to better
|
||||
// cover all executable formats, but then we need to encode the
|
||||
// intricacies of calling each platform's C compiler.
|
||||
_, err := buildinfo.ReadFile("testdata/notgo")
|
||||
b, err := obscuretestdata.ReadFile("testdata/notgo/notgo.base64")
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile got err %v, want nil", err)
|
||||
}
|
||||
|
||||
_, err = buildinfo.Read(bytes.NewReader(b))
|
||||
if err == nil {
|
||||
t.Fatalf("ReadFile got nil err, want non-nil")
|
||||
t.Fatalf("Read got nil err, want non-nil")
|
||||
}
|
||||
|
||||
// The precise error text here isn't critical, but we want something
|
||||
@ -410,13 +397,13 @@ func TestIssue54968(t *testing.T) {
|
||||
}
|
||||
|
||||
func FuzzRead(f *testing.F) {
|
||||
go117, err := os.ReadFile("testdata/go117")
|
||||
go117, err := obscuretestdata.ReadFile("testdata/go117/go117.base64")
|
||||
if err != nil {
|
||||
f.Errorf("Error reading go117: %v", err)
|
||||
}
|
||||
f.Add(go117)
|
||||
|
||||
notgo, err := os.ReadFile("testdata/notgo")
|
||||
notgo, err := obscuretestdata.ReadFile("testdata/notgo/notgo.base64")
|
||||
if err != nil {
|
||||
f.Errorf("Error reading notgo: %v", err)
|
||||
}
|
||||
|
BIN
src/debug/buildinfo/testdata/go117
vendored
BIN
src/debug/buildinfo/testdata/go117
vendored
Binary file not shown.
15
src/debug/buildinfo/testdata/go117/README.md
vendored
Normal file
15
src/debug/buildinfo/testdata/go117/README.md
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
go117.base64 is a base64-encoded Go 1.17 hello world binary used to test
|
||||
debug/buildinfo of pre-1.18 buildinfo encoding.
|
||||
|
||||
The binary is base64 encoded to hide it from security scanners that believe a
|
||||
Go 1.17 is inherently insecure.
|
||||
|
||||
Generate go117.base64 with:
|
||||
|
||||
$ GOTOOLCHAIN=go1.17 GOOS=linux GOARCH=amd64 go build -trimpath
|
||||
$ base64 go117 > go117.base64
|
||||
$ rm go117
|
||||
|
||||
TODO(prattmic): Ideally this would be built on the fly to better cover all
|
||||
executable formats, but then we need a network connection to download an old Go
|
||||
toolchain.
|
3
src/debug/buildinfo/testdata/go117/go.mod
vendored
Normal file
3
src/debug/buildinfo/testdata/go117/go.mod
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
module example.com/go117
|
||||
|
||||
go 1.17
|
20314
src/debug/buildinfo/testdata/go117/go117.base64
vendored
Normal file
20314
src/debug/buildinfo/testdata/go117/go117.base64
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
src/debug/buildinfo/testdata/go117/main.go
vendored
Normal file
7
src/debug/buildinfo/testdata/go117/main.go
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2025 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
|
||||
|
||||
func main() {}
|
BIN
src/debug/buildinfo/testdata/notgo
vendored
BIN
src/debug/buildinfo/testdata/notgo
vendored
Binary file not shown.
17
src/debug/buildinfo/testdata/notgo/README.md
vendored
Normal file
17
src/debug/buildinfo/testdata/notgo/README.md
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
notgo.base64 is a base64-encoded C hello world binary used to test
|
||||
debug/buildinfo errors on non-Go binaries.
|
||||
|
||||
The binary is base64 encoded to hide it from security scanners that might not
|
||||
like it.
|
||||
|
||||
Generate notgo.base64 on linux-amd64 with:
|
||||
|
||||
$ cc -o notgo main.c
|
||||
$ base64 notgo > notgo.base64
|
||||
$ rm notgo
|
||||
|
||||
The current binary was built with "gcc version 14.2.0 (Debian 14.2.0-3+build4)".
|
||||
|
||||
TODO(prattmic): Ideally this would be built on the fly to better cover all
|
||||
executable formats, but then we need to encode the intricacies of calling each
|
||||
platform's C compiler.
|
7
src/debug/buildinfo/testdata/notgo/main.c
vendored
Normal file
7
src/debug/buildinfo/testdata/notgo/main.c
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2025 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.
|
||||
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
278
src/debug/buildinfo/testdata/notgo/notgo.base64
vendored
Normal file
278
src/debug/buildinfo/testdata/notgo/notgo.base64
vendored
Normal file
@ -0,0 +1,278 @@
|
||||
f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAQBAAAAAAAABAAAAAAAAAAGA2AAAAAAAAAAAAAEAAOAAN
|
||||
AEAAHgAdAAYAAAAEAAAAQAAAAAAAAABAAAAAAAAAAEAAAAAAAAAA2AIAAAAAAADYAgAAAAAAAAgA
|
||||
AAAAAAAAAwAAAAQAAAAYAwAAAAAAABgDAAAAAAAAGAMAAAAAAAAcAAAAAAAAABwAAAAAAAAAAQAA
|
||||
AAAAAAABAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAFAAAAAAAA4AUAAAAAAAAAEAAA
|
||||
AAAAAAEAAAAFAAAAABAAAAAAAAAAEAAAAAAAAAAQAAAAAAAAPQEAAAAAAAA9AQAAAAAAAAAQAAAA
|
||||
AAAAAQAAAAQAAAAAIAAAAAAAAAAgAAAAAAAAACAAAAAAAADcAAAAAAAAANwAAAAAAAAAABAAAAAA
|
||||
AAABAAAABgAAAAAuAAAAAAAAAD4AAAAAAAAAPgAAAAAAABACAAAAAAAAGAIAAAAAAAAAEAAAAAAA
|
||||
AAIAAAAGAAAAEC4AAAAAAAAQPgAAAAAAABA+AAAAAAAAsAEAAAAAAACwAQAAAAAAAAgAAAAAAAAA
|
||||
BAAAAAQAAAA4AwAAAAAAADgDAAAAAAAAOAMAAAAAAAAgAAAAAAAAACAAAAAAAAAACAAAAAAAAAAE
|
||||
AAAABAAAAFgDAAAAAAAAWAMAAAAAAABYAwAAAAAAAEQAAAAAAAAARAAAAAAAAAAEAAAAAAAAAFPl
|
||||
dGQEAAAAOAMAAAAAAAA4AwAAAAAAADgDAAAAAAAAIAAAAAAAAAAgAAAAAAAAAAgAAAAAAAAAUOV0
|
||||
ZAQAAAAEIAAAAAAAAAQgAAAAAAAABCAAAAAAAAAsAAAAAAAAACwAAAAAAAAABAAAAAAAAABR5XRk
|
||||
BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAFLldGQE
|
||||
AAAAAC4AAAAAAAAAPgAAAAAAAAA+AAAAAAAAAAIAAAAAAAAAAgAAAAAAAAEAAAAAAAAAL2xpYjY0
|
||||
L2xkLWxpbnV4LXg4Ni02NC5zby4yAAAAAAAEAAAAEAAAAAUAAABHTlUAAoAAwAQAAAABAAAAAAAA
|
||||
AAQAAAAUAAAAAwAAAEdOVQB5fSf98eWTEBscIbS6nrsfguPLDgQAAAAQAAAAAQAAAEdOVQAAAAAA
|
||||
AwAAAAIAAAAAAAAAAAAAAAIAAAAFAAAAAQAAAAYAAAAAAIEAAAAAAAUAAAAAAAAA0WXObQAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAEgAAAAAAAAAAAAAAAAAAAAAAAABDAAAAIAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAABfAAAAIAAAAAAAAAAAAAAAAAAAAAAAAABuAAAAIAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAATAAAAIgAAAAAAAAAAAAAAAAAAAAAAAAAAX19saWJjX3N0YXJ0X21haW4AX19jeGFfZmlu
|
||||
YWxpemUAbGliYy5zby42AEdMSUJDXzIuMi41AEdMSUJDXzIuMzQAX0lUTV9kZXJlZ2lzdGVyVE1D
|
||||
bG9uZVRhYmxlAF9fZ21vbl9zdGFydF9fAF9JVE1fcmVnaXN0ZXJUTUNsb25lVGFibGUAAAACAAEA
|
||||
AQABAAMAAAAAAAEAAgAiAAAAEAAAAAAAAAB1GmkJAAADACwAAAAQAAAAtJGWBgAAAgA4AAAAAAAA
|
||||
AAA+AAAAAAAACAAAAAAAAAAgEQAAAAAAAAg+AAAAAAAACAAAAAAAAADgEAAAAAAAAAhAAAAAAAAA
|
||||
CAAAAAAAAAAIQAAAAAAAAMA/AAAAAAAABgAAAAEAAAAAAAAAAAAAAMg/AAAAAAAABgAAAAIAAAAA
|
||||
AAAAAAAAANA/AAAAAAAABgAAAAMAAAAAAAAAAAAAANg/AAAAAAAABgAAAAQAAAAAAAAAAAAAAOA/
|
||||
AAAAAAAABgAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEiD7AhIiwXF
|
||||
LwAASIXAdAL/0EiDxAjDAAAAAAAAAAAA/zXKLwAA/yXMLwAADx9AAP8lqi8AAGaQAAAAAAAAAAAx
|
||||
7UmJ0V5IieJIg+TwUFRFMcAxyUiNPc4AAAD/FV8vAAD0Zi4PH4QAAAAAAA8fQABIjT2ZLwAASI0F
|
||||
ki8AAEg5+HQVSIsFPi8AAEiFwHQJ/+APH4AAAAAAww8fgAAAAABIjT1pLwAASI01Yi8AAEgp/kiJ
|
||||
8EjB7j9IwfgDSAHGSNH+dBRIiwUNLwAASIXAdAj/4GYPH0QAAMMPH4AAAAAA8w8e+oA9JS8AAAB1
|
||||
K1VIgz3qLgAAAEiJ5XQMSIs9Bi8AAOgp////6GT////GBf0uAAABXcMPHwDDDx+AAAAAAPMPHvrp
|
||||
d////1VIieW4AAAAAF3DSIPsCEiDxAjDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAIAARsDOygAAAAEAAAA
|
||||
HPD//3QAAAAs8P//nAAAADzw//9EAAAAJfH//7QAAAAUAAAAAAAAAAF6UgABeBABGwwHCJABBxAU
|
||||
AAAAHAAAAPDv//8iAAAAAAAAAAAAAAAUAAAAAAAAAAF6UgABeBABGwwHCJABAAAkAAAAHAAAAKDv
|
||||
//8QAAAAAA4QRg4YSg8LdwiAAD8aOyozJCIAAAAAFAAAAEQAAACI7///CAAAAAAAAAAAAAAAHAAA
|
||||
AFwAAABp8P//CwAAAABBDhCGAkMNBkYMBwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACARAAAAAAAA4BAAAAAAAAABAAAAAAAA
|
||||
ACIAAAAAAAAADAAAAAAAAAAAEAAAAAAAAA0AAAAAAAAANBEAAAAAAAAZAAAAAAAAAAA+AAAAAAAA
|
||||
GwAAAAAAAAAIAAAAAAAAABoAAAAAAAAACD4AAAAAAAAcAAAAAAAAAAgAAAAAAAAA9f7/bwAAAACg
|
||||
AwAAAAAAAAUAAAAAAAAAWAQAAAAAAAAGAAAAAAAAAMgDAAAAAAAACgAAAAAAAACIAAAAAAAAAAsA
|
||||
AAAAAAAAGAAAAAAAAAAVAAAAAAAAAAAAAAAAAAAAAwAAAAAAAADoPwAAAAAAAAcAAAAAAAAAIAUA
|
||||
AAAAAAAIAAAAAAAAAMAAAAAAAAAACQAAAAAAAAAYAAAAAAAAAPv//28AAAAAAAAACAAAAAD+//9v
|
||||
AAAAAPAEAAAAAAAA////bwAAAAABAAAAAAAAAPD//28AAAAA4AQAAAAAAAD5//9vAAAAAAMAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAED4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIQAAAAAAAAEdDQzogKERl
|
||||
YmlhbiAxNC4yLjAtMytidWlsZDQpIDE0LjIuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB
|
||||
AAAABADx/wAAAAAAAAAAAAAAAAAAAAAJAAAAAQAEAHwDAAAAAAAAIAAAAAAAAAATAAAABADx/wAA
|
||||
AAAAAAAAAAAAAAAAAAAeAAAAAgAOAHAQAAAAAAAAAAAAAAAAAAAgAAAAAgAOAKAQAAAAAAAAAAAA
|
||||
AAAAAAAzAAAAAgAOAOAQAAAAAAAAAAAAAAAAAABJAAAAAQAZABBAAAAAAAAAAQAAAAAAAABVAAAA
|
||||
AQAUAAg+AAAAAAAAAAAAAAAAAAB8AAAAAgAOACARAAAAAAAAAAAAAAAAAACIAAAAAQATAAA+AAAA
|
||||
AAAAAAAAAAAAAACnAAAABADx/wAAAAAAAAAAAAAAAAAAAAATAAAABADx/wAAAAAAAAAAAAAAAAAA
|
||||
AACuAAAAAQASANggAAAAAAAAAAAAAAAAAAAAAAAABADx/wAAAAAAAAAAAAAAAAAAAAC8AAAAAQAV
|
||||
ABA+AAAAAAAAAAAAAAAAAADFAAAAAAARAAQgAAAAAAAAAAAAAAAAAADYAAAAAQAXAOg/AAAAAAAA
|
||||
AAAAAAAAAADuAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAALAQAAIAAAAAAAAAAAAAAAAAAAAAAAAAA2
|
||||
AQAAIAAYAABAAAAAAAAAAAAAAAAAAAAnAQAAEAAYABBAAAAAAAAAAAAAAAAAAAAuAQAAEgIPADQR
|
||||
AAAAAAAAAAAAAAAAAAA0AQAAEAAYAABAAAAAAAAAAAAAAAAAAABBAQAAIAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAABQAQAAEQIYAAhAAAAAAAAAAAAAAAAAAABdAQAAEQAQAAAgAAAAAAAABAAAAAAAAABsAQAA
|
||||
EAAZABhAAAAAAAAAAAAAAAAAAAA6AQAAEgAOAEAQAAAAAAAAIgAAAAAAAABxAQAAEAAZABBAAAAA
|
||||
AAAAAAAAAAAAAAB9AQAAEgAOACkRAAAAAAAACwAAAAAAAACCAQAAEQIYABBAAAAAAAAAAAAAAAAA
|
||||
AACOAQAAIAAAAAAAAAAAAAAAAAAAAAAAAACoAQAAIgAAAAAAAAAAAAAAAAAAAAAAAADDAQAAEgIL
|
||||
AAAQAAAAAAAAAAAAAAAAAAAAU2NydDEubwBfX2FiaV90YWcAY3J0c3R1ZmYuYwBkZXJlZ2lzdGVy
|
||||
X3RtX2Nsb25lcwBfX2RvX2dsb2JhbF9kdG9yc19hdXgAY29tcGxldGVkLjAAX19kb19nbG9iYWxf
|
||||
ZHRvcnNfYXV4X2ZpbmlfYXJyYXlfZW50cnkAZnJhbWVfZHVtbXkAX19mcmFtZV9kdW1teV9pbml0
|
||||
X2FycmF5X2VudHJ5AG1haW4uYwBfX0ZSQU1FX0VORF9fAF9EWU5BTUlDAF9fR05VX0VIX0ZSQU1F
|
||||
X0hEUgBfR0xPQkFMX09GRlNFVF9UQUJMRV8AX19saWJjX3N0YXJ0X21haW5AR0xJQkNfMi4zNABf
|
||||
SVRNX2RlcmVnaXN0ZXJUTUNsb25lVGFibGUAX2VkYXRhAF9maW5pAF9fZGF0YV9zdGFydABfX2dt
|
||||
b25fc3RhcnRfXwBfX2Rzb19oYW5kbGUAX0lPX3N0ZGluX3VzZWQAX2VuZABfX2Jzc19zdGFydABt
|
||||
YWluAF9fVE1DX0VORF9fAF9JVE1fcmVnaXN0ZXJUTUNsb25lVGFibGUAX19jeGFfZmluYWxpemVA
|
||||
R0xJQkNfMi4yLjUAX2luaXQAAC5zeW10YWIALnN0cnRhYgAuc2hzdHJ0YWIALmludGVycAAubm90
|
||||
ZS5nbnUucHJvcGVydHkALm5vdGUuZ251LmJ1aWxkLWlkAC5ub3RlLkFCSS10YWcALmdudS5oYXNo
|
||||
AC5keW5zeW0ALmR5bnN0cgAuZ251LnZlcnNpb24ALmdudS52ZXJzaW9uX3IALnJlbGEuZHluAC5p
|
||||
bml0AC5wbHQuZ290AC50ZXh0AC5maW5pAC5yb2RhdGEALmVoX2ZyYW1lX2hkcgAuZWhfZnJhbWUA
|
||||
LmluaXRfYXJyYXkALmZpbmlfYXJyYXkALmR5bmFtaWMALmdvdC5wbHQALmRhdGEALmJzcwAuY29t
|
||||
bWVudAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAABsAAAABAAAAAgAAAAAAAAAYAwAAAAAAABgDAAAAAAAAHAAAAAAA
|
||||
AAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAjAAAABwAAAAIAAAAAAAAAOAMAAAAAAAA4AwAAAAAA
|
||||
ACAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAANgAAAAcAAAACAAAAAAAAAFgDAAAAAAAA
|
||||
WAMAAAAAAAAkAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAEkAAAAHAAAAAgAAAAAAAAB8
|
||||
AwAAAAAAAHwDAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAABXAAAA9v//bwIA
|
||||
AAAAAAAAoAMAAAAAAACgAwAAAAAAACQAAAAAAAAABgAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAYQAA
|
||||
AAsAAAACAAAAAAAAAMgDAAAAAAAAyAMAAAAAAACQAAAAAAAAAAcAAAABAAAACAAAAAAAAAAYAAAA
|
||||
AAAAAGkAAAADAAAAAgAAAAAAAABYBAAAAAAAAFgEAAAAAAAAiAAAAAAAAAAAAAAAAAAAAAEAAAAA
|
||||
AAAAAAAAAAAAAABxAAAA////bwIAAAAAAAAA4AQAAAAAAADgBAAAAAAAAAwAAAAAAAAABgAAAAAA
|
||||
AAACAAAAAAAAAAIAAAAAAAAAfgAAAP7//28CAAAAAAAAAPAEAAAAAAAA8AQAAAAAAAAwAAAAAAAA
|
||||
AAcAAAABAAAACAAAAAAAAAAAAAAAAAAAAI0AAAAEAAAAAgAAAAAAAAAgBQAAAAAAACAFAAAAAAAA
|
||||
wAAAAAAAAAAGAAAAAAAAAAgAAAAAAAAAGAAAAAAAAACXAAAAAQAAAAYAAAAAAAAAABAAAAAAAAAA
|
||||
EAAAAAAAABcAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAA9wAAAAEAAAAGAAAAAAAAACAQ
|
||||
AAAAAAAAIBAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAAAAJ0AAAABAAAABgAA
|
||||
AAAAAAAwEAAAAAAAADAQAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAAAAAAACmAAAA
|
||||
AQAAAAYAAAAAAAAAQBAAAAAAAABAEAAAAAAAAPQAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAA
|
||||
AAAArAAAAAEAAAAGAAAAAAAAADQRAAAAAAAANBEAAAAAAAAJAAAAAAAAAAAAAAAAAAAABAAAAAAA
|
||||
AAAAAAAAAAAAALIAAAABAAAAEgAAAAAAAAAAIAAAAAAAAAAgAAAAAAAABAAAAAAAAAAAAAAAAAAA
|
||||
AAQAAAAAAAAABAAAAAAAAAC6AAAAAQAAAAIAAAAAAAAABCAAAAAAAAAEIAAAAAAAACwAAAAAAAAA
|
||||
AAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAyAAAAAEAAAACAAAAAAAAADAgAAAAAAAAMCAAAAAAAACs
|
||||
AAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAANIAAAAOAAAAAwAAAAAAAAAAPgAAAAAAAAAu
|
||||
AAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAAAAAAADeAAAADwAAAAMAAAAAAAAACD4A
|
||||
AAAAAAAILgAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAA6gAAAAYAAAADAAAA
|
||||
AAAAABA+AAAAAAAAEC4AAAAAAACwAQAAAAAAAAcAAAAAAAAACAAAAAAAAAAQAAAAAAAAAKEAAAAB
|
||||
AAAAAwAAAAAAAADAPwAAAAAAAMAvAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAAAAA
|
||||
AADzAAAAAQAAAAMAAAAAAAAA6D8AAAAAAADoLwAAAAAAABgAAAAAAAAAAAAAAAAAAAAIAAAAAAAA
|
||||
AAgAAAAAAAAA/AAAAAEAAAADAAAAAAAAAABAAAAAAAAAADAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA
|
||||
CAAAAAAAAAAAAAAAAAAAAAIBAAAIAAAAAwAAAAAAAAAQQAAAAAAAABAwAAAAAAAACAAAAAAAAAAA
|
||||
AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAHAQAAAQAAADAAAAAAAAAAAAAAAAAAAAAQMAAAAAAAACUA
|
||||
AAAAAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAAAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAODAA
|
||||
AAAAAABIAwAAAAAAABwAAAASAAAACAAAAAAAAAAYAAAAAAAAAAkAAAADAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAIAzAAAAAAAAyQEAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAARAAAAAwAAAAAAAAAA
|
||||
AAAAAAAAAAAAAABJNQAAAAAAABABAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA
|
@ -4,7 +4,7 @@ go 1.24
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.30.0
|
||||
golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98
|
||||
golang.org/x/net v0.32.1-0.20250304185419-76f9bf3279ef
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -1,7 +1,7 @@
|
||||
golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
|
||||
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98 h1:36bTiCRO7f/J3t+LumnLTJDXqxsp1x6Q7754SsRD9u4=
|
||||
golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
||||
golang.org/x/net v0.32.1-0.20250304185419-76f9bf3279ef h1:oQtTn7aH5kyi7dPmG2Eot3aG1XBwnkrX+zIq+lNeZeM=
|
||||
golang.org/x/net v0.32.1-0.20250304185419-76f9bf3279ef/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
|
@ -207,7 +207,7 @@ func (check *Checker) lhsVar(lhs ast.Expr) Type {
|
||||
// dot-imported variables.
|
||||
if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
|
||||
v = w
|
||||
v_used = v.used
|
||||
v_used = check.usedVars[v]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -216,7 +216,7 @@ func (check *Checker) lhsVar(lhs ast.Expr) Type {
|
||||
check.expr(nil, &x, lhs)
|
||||
|
||||
if v != nil {
|
||||
v.used = v_used // restore v.used
|
||||
check.usedVars[v] = v_used // restore v.used
|
||||
}
|
||||
|
||||
if x.mode == invalid || !isValid(x.typ) {
|
||||
|
@ -689,7 +689,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w
|
||||
if pname, _ := obj.(*PkgName); pname != nil {
|
||||
assert(pname.pkg == check.pkg)
|
||||
check.recordUse(ident, pname)
|
||||
pname.used = true
|
||||
check.usedPkgNames[pname] = true
|
||||
pkg := pname.imported
|
||||
|
||||
var exp Object
|
||||
@ -1020,13 +1020,13 @@ func (check *Checker) use1(e ast.Expr, lhs bool) bool {
|
||||
// dot-imported variables.
|
||||
if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
|
||||
v = w
|
||||
v_used = v.used
|
||||
v_used = check.usedVars[v]
|
||||
}
|
||||
}
|
||||
}
|
||||
check.exprOrType(&x, n, true)
|
||||
if v != nil {
|
||||
v.used = v_used // restore v.used
|
||||
check.usedVars[v] = v_used // restore v.used
|
||||
}
|
||||
default:
|
||||
check.rawExpr(nil, &x, e, nil, true)
|
||||
|
@ -182,6 +182,8 @@ type Checker struct {
|
||||
dotImportMap map[dotImportKey]*PkgName // maps dot-imported objects to the package they were dot-imported through
|
||||
brokenAliases map[*TypeName]bool // set of aliases with broken (not yet determined) types
|
||||
unionTypeSets map[*Union]*_TypeSet // computed type sets for union types
|
||||
usedVars map[*Var]bool // set of used variables
|
||||
usedPkgNames map[*PkgName]bool // set of used package names
|
||||
mono monoGraph // graph for detecting non-monomorphizable instantiation loops
|
||||
|
||||
firstErr error // first error encountered
|
||||
@ -308,13 +310,15 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
|
||||
conf._EnableAlias = gotypesalias.Value() != "0"
|
||||
|
||||
return &Checker{
|
||||
conf: conf,
|
||||
ctxt: conf.Context,
|
||||
fset: fset,
|
||||
pkg: pkg,
|
||||
Info: info,
|
||||
objMap: make(map[Object]*declInfo),
|
||||
impMap: make(map[importKey]*Package),
|
||||
conf: conf,
|
||||
ctxt: conf.Context,
|
||||
fset: fset,
|
||||
pkg: pkg,
|
||||
Info: info,
|
||||
objMap: make(map[Object]*declInfo),
|
||||
impMap: make(map[importKey]*Package),
|
||||
usedVars: make(map[*Var]bool),
|
||||
usedPkgNames: make(map[*PkgName]bool),
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,6 +326,8 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
|
||||
// The provided files must all belong to the same package.
|
||||
func (check *Checker) initFiles(files []*ast.File) {
|
||||
// start with a clean slate (check.Files may be called multiple times)
|
||||
// TODO(gri): what determines which fields are zeroed out here, vs at the end
|
||||
// of checkFiles?
|
||||
check.files = nil
|
||||
check.imports = nil
|
||||
check.dotImportMap = nil
|
||||
@ -333,6 +339,13 @@ func (check *Checker) initFiles(files []*ast.File) {
|
||||
check.objPath = nil
|
||||
check.cleaners = nil
|
||||
|
||||
// We must initialize usedVars and usedPkgNames both here and in NewChecker,
|
||||
// because initFiles is not called in the CheckExpr or Eval codepaths, yet we
|
||||
// want to free this memory at the end of Files ('used' predicates are
|
||||
// only needed in the context of a given file).
|
||||
check.usedVars = make(map[*Var]bool)
|
||||
check.usedPkgNames = make(map[*PkgName]bool)
|
||||
|
||||
// determine package name and collect valid files
|
||||
pkg := check.pkg
|
||||
for _, file := range files {
|
||||
@ -507,9 +520,12 @@ func (check *Checker) checkFiles(files []*ast.File) {
|
||||
check.seenPkgMap = nil
|
||||
check.brokenAliases = nil
|
||||
check.unionTypeSets = nil
|
||||
check.usedVars = nil
|
||||
check.usedPkgNames = nil
|
||||
check.ctxt = nil
|
||||
|
||||
// TODO(rFindley) There's more memory we should release at this point.
|
||||
// TODO(gri): shouldn't the cleanup above occur after the bailout?
|
||||
// TODO(gri) There's more memory we should release at this point.
|
||||
}
|
||||
|
||||
// processDelayed processes all delayed actions pushed after top.
|
||||
|
@ -245,13 +245,12 @@ func (a *object) cmp(b *object) int {
|
||||
type PkgName struct {
|
||||
object
|
||||
imported *Package
|
||||
used bool // set if the package was used
|
||||
}
|
||||
|
||||
// NewPkgName returns a new PkgName object representing an imported package.
|
||||
// The remaining arguments set the attributes found with all Objects.
|
||||
func NewPkgName(pos token.Pos, pkg *Package, name string, imported *Package) *PkgName {
|
||||
return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, black, nopos}, imported, false}
|
||||
return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, black, nopos}, imported}
|
||||
}
|
||||
|
||||
// Imported returns the package that was imported.
|
||||
@ -334,10 +333,10 @@ func (obj *TypeName) IsAlias() bool {
|
||||
// A Variable represents a declared variable (including function parameters and results, and struct fields).
|
||||
type Var struct {
|
||||
object
|
||||
origin *Var // if non-nil, the Var from which this one was instantiated
|
||||
embedded bool // if set, the variable is an embedded struct field, and name is the type name
|
||||
isField bool // var is struct field
|
||||
used bool // set if the variable was used
|
||||
origin *Var // if non-nil, the Var from which this one was instantiated
|
||||
isParam bool // var is a param, for backport of 'used' check to go1.24 (go.dev/issue/72826)
|
||||
}
|
||||
|
||||
// NewVar returns a new variable.
|
||||
@ -348,7 +347,7 @@ func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var {
|
||||
|
||||
// NewParam returns a new variable representing a function parameter.
|
||||
func NewParam(pos token.Pos, pkg *Package, name string, typ Type) *Var {
|
||||
return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, used: true} // parameters are always 'used'
|
||||
return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, isParam: true}
|
||||
}
|
||||
|
||||
// NewField returns a new variable representing a struct field.
|
||||
|
@ -310,7 +310,7 @@ func (check *Checker) collectObjects() {
|
||||
|
||||
if imp.fake {
|
||||
// match 1.17 cmd/compile (not prescribed by spec)
|
||||
pkgName.used = true
|
||||
check.usedPkgNames[pkgName] = true
|
||||
}
|
||||
|
||||
// add import to file scope
|
||||
@ -710,7 +710,7 @@ func (check *Checker) unusedImports() {
|
||||
// (initialization), use the blank identifier as explicit package name."
|
||||
|
||||
for _, obj := range check.imports {
|
||||
if !obj.used && obj.name != "_" {
|
||||
if obj.name != "_" && !check.usedPkgNames[obj] {
|
||||
check.errorUnusedPkg(obj)
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ func TestSizeof(t *testing.T) {
|
||||
{term{}, 12, 24},
|
||||
|
||||
// Objects
|
||||
{PkgName{}, 48, 88},
|
||||
{PkgName{}, 44, 80},
|
||||
{Const{}, 48, 88},
|
||||
{TypeName{}, 40, 72},
|
||||
{Var{}, 48, 88},
|
||||
|
@ -59,7 +59,7 @@ func (check *Checker) usage(scope *Scope) {
|
||||
var unused []*Var
|
||||
for name, elem := range scope.elems {
|
||||
elem = resolve(name, elem)
|
||||
if v, _ := elem.(*Var); v != nil && !v.used {
|
||||
if v, _ := elem.(*Var); v != nil && !v.isParam && !check.usedVars[v] {
|
||||
unused = append(unused, v)
|
||||
}
|
||||
}
|
||||
@ -777,13 +777,16 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||
}
|
||||
|
||||
// If lhs exists, we must have at least one lhs variable that was used.
|
||||
// (We can't use check.usage because that only looks at one scope; and
|
||||
// we don't want to use the same variable for all scopes and change the
|
||||
// variable type underfoot.)
|
||||
if lhs != nil {
|
||||
var used bool
|
||||
for _, v := range lhsVars {
|
||||
if v.used {
|
||||
if check.usedVars[v] {
|
||||
used = true
|
||||
}
|
||||
v.used = true // avoid usage error when checking entire function
|
||||
check.usedVars[v] = true // avoid usage error when checking entire function
|
||||
}
|
||||
if !used {
|
||||
check.softErrorf(lhs, UnusedVar, "%s declared and not used", lhs.Name)
|
||||
@ -952,7 +955,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) {
|
||||
if typ == nil || typ == Typ[Invalid] {
|
||||
// typ == Typ[Invalid] can happen if allowVersion fails.
|
||||
obj.typ = Typ[Invalid]
|
||||
obj.used = true // don't complain about unused variable
|
||||
check.usedVars[obj] = true // don't complain about unused variable
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *TypeName, wantType bo
|
||||
// avoid "declared but not used" errors
|
||||
// (don't use Checker.use - we don't want to evaluate too much)
|
||||
if v, _ := obj.(*Var); v != nil && v.pkg == check.pkg /* see Checker.use1 */ {
|
||||
v.used = true
|
||||
check.usedVars[v] = true
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -82,7 +82,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *TypeName, wantType bo
|
||||
// (This code is only needed for dot-imports. Without them,
|
||||
// we only have to mark variables, see *Var case below).
|
||||
if pkgName := check.dotImportMap[dotImportKey{scope, obj.Name()}]; pkgName != nil {
|
||||
pkgName.used = true
|
||||
check.usedPkgNames[pkgName] = true
|
||||
}
|
||||
|
||||
switch obj := obj.(type) {
|
||||
@ -119,7 +119,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *TypeName, wantType bo
|
||||
// from other packages to avoid potential race conditions with
|
||||
// dot-imported variables.
|
||||
if obj.pkg == check.pkg {
|
||||
obj.used = true
|
||||
check.usedVars[obj] = true
|
||||
}
|
||||
check.addDeclDep(obj)
|
||||
if !isValid(typ) {
|
||||
|
@ -28,6 +28,7 @@ var All = []Info{
|
||||
{Name: "asynctimerchan", Package: "time", Changed: 23, Old: "1"},
|
||||
{Name: "dataindependenttiming", Package: "crypto/subtle", Opaque: true},
|
||||
{Name: "execerrdot", Package: "os/exec"},
|
||||
{Name: "fips140", Package: "crypto/fips140", Opaque: true},
|
||||
{Name: "gocachehash", Package: "cmd/go"},
|
||||
{Name: "gocachetest", Package: "cmd/go"},
|
||||
{Name: "gocacheverify", Package: "cmd/go"},
|
||||
@ -58,8 +59,8 @@ var All = []Info{
|
||||
{Name: "tlsmlkem", Package: "crypto/tls", Changed: 24, Old: "0", Opaque: true},
|
||||
{Name: "tlsrsakex", Package: "crypto/tls", Changed: 22, Old: "1"},
|
||||
{Name: "tlsunsafeekm", Package: "crypto/tls", Changed: 22, Old: "1"},
|
||||
{Name: "winreadlinkvolume", Package: "os", Changed: 22, Old: "0"},
|
||||
{Name: "winsymlink", Package: "os", Changed: 22, Old: "0"},
|
||||
{Name: "winreadlinkvolume", Package: "os", Changed: 23, Old: "0"},
|
||||
{Name: "winsymlink", Package: "os", Changed: 23, Old: "0"},
|
||||
{Name: "x509keypairleaf", Package: "crypto/tls", Changed: 23, Old: "0"},
|
||||
{Name: "x509negativeserial", Package: "crypto/x509", Changed: 23, Old: "1"},
|
||||
{Name: "x509rsacrt", Package: "crypto/x509", Changed: 24, Old: "0"},
|
||||
|
@ -504,3 +504,26 @@ func ParallelOn64Bit(t *testing.T) {
|
||||
}
|
||||
t.Parallel()
|
||||
}
|
||||
|
||||
// CPUProfilingBroken returns true if CPU profiling has known issues on this
|
||||
// platform.
|
||||
func CPUProfilingBroken() bool {
|
||||
switch runtime.GOOS {
|
||||
case "plan9":
|
||||
// Profiling unimplemented.
|
||||
return true
|
||||
case "aix":
|
||||
// See https://golang.org/issue/45170.
|
||||
return true
|
||||
case "ios", "dragonfly", "netbsd", "illumos", "solaris":
|
||||
// See https://golang.org/issue/13841.
|
||||
return true
|
||||
case "openbsd":
|
||||
if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
|
||||
// See https://golang.org/issue/13841.
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
@ -164,6 +164,19 @@ func readChunkLine(b *bufio.Reader) ([]byte, error) {
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// RFC 9112 permits parsers to accept a bare \n as a line ending in headers,
|
||||
// but not in chunked encoding lines. See https://www.rfc-editor.org/errata/eid7633,
|
||||
// which explicitly rejects a clarification permitting \n as a chunk terminator.
|
||||
//
|
||||
// Verify that the line ends in a CRLF, and that no CRs appear before the end.
|
||||
if idx := bytes.IndexByte(p, '\r'); idx == -1 {
|
||||
return nil, errors.New("chunked line ends with bare LF")
|
||||
} else if idx != len(p)-2 {
|
||||
return nil, errors.New("invalid CR in chunked line")
|
||||
}
|
||||
p = p[:len(p)-2] // trim CRLF
|
||||
|
||||
if len(p) >= maxLineLength {
|
||||
return nil, ErrLineTooLong
|
||||
}
|
||||
@ -171,14 +184,14 @@ func readChunkLine(b *bufio.Reader) ([]byte, error) {
|
||||
}
|
||||
|
||||
func trimTrailingWhitespace(b []byte) []byte {
|
||||
for len(b) > 0 && isASCIISpace(b[len(b)-1]) {
|
||||
for len(b) > 0 && isOWS(b[len(b)-1]) {
|
||||
b = b[:len(b)-1]
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func isASCIISpace(b byte) bool {
|
||||
return b == ' ' || b == '\t' || b == '\n' || b == '\r'
|
||||
func isOWS(b byte) bool {
|
||||
return b == ' ' || b == '\t'
|
||||
}
|
||||
|
||||
var semi = []byte(";")
|
||||
|
@ -280,6 +280,33 @@ func TestChunkReaderByteAtATime(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestChunkInvalidInputs(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
b string
|
||||
}{{
|
||||
name: "bare LF in chunk size",
|
||||
b: "1\na\r\n0\r\n",
|
||||
}, {
|
||||
name: "extra LF in chunk size",
|
||||
b: "1\r\r\na\r\n0\r\n",
|
||||
}, {
|
||||
name: "bare LF in chunk data",
|
||||
b: "1\r\na\n0\r\n",
|
||||
}, {
|
||||
name: "bare LF in chunk extension",
|
||||
b: "1;\na\r\n0\r\n",
|
||||
}} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
r := NewChunkedReader(strings.NewReader(test.b))
|
||||
got, err := io.ReadAll(r)
|
||||
if err == nil {
|
||||
t.Fatalf("unexpectedly parsed invalid chunked data:\n%q", got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type funcReader struct {
|
||||
f func(iteration int) ([]byte, error)
|
||||
i int
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"compress/zlib"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -7303,3 +7304,120 @@ func testServerReadAfterHandlerAbort100Continue(t *testing.T, mode testMode) {
|
||||
readyc <- struct{}{} // server starts reading from the request body
|
||||
readyc <- struct{}{} // server finishes reading from the request body
|
||||
}
|
||||
|
||||
// Issue #72100: Verify that we don't modify the caller's TLS.Config.NextProtos slice.
|
||||
func TestServerTLSNextProtos(t *testing.T) {
|
||||
run(t, testServerTLSNextProtos, []testMode{https1Mode, http2Mode})
|
||||
}
|
||||
func testServerTLSNextProtos(t *testing.T, mode testMode) {
|
||||
CondSkipHTTP2(t)
|
||||
|
||||
cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
leafCert, err := x509.ParseCertificate(cert.Certificate[0])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
certpool := x509.NewCertPool()
|
||||
certpool.AddCert(leafCert)
|
||||
|
||||
protos := new(Protocols)
|
||||
switch mode {
|
||||
case https1Mode:
|
||||
protos.SetHTTP1(true)
|
||||
case http2Mode:
|
||||
protos.SetHTTP2(true)
|
||||
}
|
||||
|
||||
wantNextProtos := []string{"http/1.1", "h2", "other"}
|
||||
nextProtos := slices.Clone(wantNextProtos)
|
||||
|
||||
// We don't use httptest here because it overrides the tls.Config.
|
||||
srv := &Server{
|
||||
TLSConfig: &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
NextProtos: nextProtos,
|
||||
},
|
||||
Handler: HandlerFunc(func(w ResponseWriter, req *Request) {}),
|
||||
Protocols: protos,
|
||||
}
|
||||
tr := &Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
RootCAs: certpool,
|
||||
NextProtos: nextProtos,
|
||||
},
|
||||
Protocols: protos,
|
||||
}
|
||||
|
||||
listener := newLocalListener(t)
|
||||
srvc := make(chan error, 1)
|
||||
go func() {
|
||||
srvc <- srv.ServeTLS(listener, "", "")
|
||||
}()
|
||||
t.Cleanup(func() {
|
||||
srv.Close()
|
||||
<-srvc
|
||||
})
|
||||
|
||||
client := &Client{Transport: tr}
|
||||
resp, err := client.Get("https://" + listener.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
if !slices.Equal(nextProtos, wantNextProtos) {
|
||||
t.Fatalf("after running test: original NextProtos slice = %v, want %v", nextProtos, wantNextProtos)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidChunkedBodies(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
b string
|
||||
}{{
|
||||
name: "bare LF in chunk size",
|
||||
b: "1\na\r\n0\r\n\r\n",
|
||||
}, {
|
||||
name: "bare LF at body end",
|
||||
b: "1\r\na\r\n0\r\n\n",
|
||||
}} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
reqc := make(chan error)
|
||||
ts := newClientServerTest(t, http1Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||
got, err := io.ReadAll(r.Body)
|
||||
if err == nil {
|
||||
t.Logf("read body: %q", got)
|
||||
}
|
||||
reqc <- err
|
||||
})).ts
|
||||
|
||||
serverURL, err := url.Parse(ts.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
conn, err := net.Dial("tcp", serverURL.Host)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := conn.Write([]byte(
|
||||
"POST / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Transfer-Encoding: chunked\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n" +
|
||||
test.b)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
conn.(*net.TCPConn).CloseWrite()
|
||||
|
||||
if err := <-reqc; err == nil {
|
||||
t.Errorf("server handler: io.ReadAll(r.Body) succeeded, want error")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -3521,6 +3521,12 @@ func (s *Server) protocols() Protocols {
|
||||
// adjustNextProtos adds or removes "http/1.1" and "h2" entries from
|
||||
// a tls.Config.NextProtos list, according to the set of protocols in protos.
|
||||
func adjustNextProtos(nextProtos []string, protos Protocols) []string {
|
||||
// Make a copy of NextProtos since it might be shared with some other tls.Config.
|
||||
// (tls.Config.Clone doesn't do a deep copy.)
|
||||
//
|
||||
// We could avoid an allocation in the common case by checking to see if the slice
|
||||
// is already in order, but this is just one small allocation per connection.
|
||||
nextProtos = slices.Clone(nextProtos)
|
||||
var have Protocols
|
||||
nextProtos = slices.DeleteFunc(nextProtos, func(s string) bool {
|
||||
switch s {
|
||||
|
@ -11,12 +11,15 @@ import (
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
@ -24,6 +27,7 @@ import (
|
||||
|
||||
func init() {
|
||||
registerHelperCommand("pwd", cmdPwd)
|
||||
registerHelperCommand("signaltest", cmdSignalTest)
|
||||
}
|
||||
|
||||
func cmdPwd(...string) {
|
||||
@ -274,3 +278,55 @@ func TestExplicitPWD(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 71828.
|
||||
func TestSIGCHLD(t *testing.T) {
|
||||
cmd := helperCommand(t, "signaltest")
|
||||
out, err := cmd.CombinedOutput()
|
||||
t.Logf("%s", out)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// cmdSignaltest is for TestSIGCHLD.
|
||||
// This runs in a separate process because the bug only happened
|
||||
// the first time that a child process was started.
|
||||
func cmdSignalTest(...string) {
|
||||
chSig := make(chan os.Signal, 1)
|
||||
signal.Notify(chSig, syscall.SIGCHLD)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
c := 0
|
||||
for range chSig {
|
||||
c++
|
||||
fmt.Printf("SIGCHLD %d\n", c)
|
||||
if c > 1 {
|
||||
fmt.Println("too many SIGCHLD signals")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
signal.Reset(syscall.SIGCHLD)
|
||||
close(chSig)
|
||||
wg.Wait()
|
||||
}()
|
||||
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
fmt.Printf("os.Executable failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cmd := exec.Command(exe, "hang", "200ms")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
fmt.Printf("failed to run child process: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
@ -3848,3 +3848,14 @@ func TestRemoveReadOnlyFile(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestOpenFileDevNull(t *testing.T) {
|
||||
// See https://go.dev/issue/71752.
|
||||
t.Parallel()
|
||||
|
||||
f, err := OpenFile(DevNull, O_WRONLY|O_CREATE|O_TRUNC, 0o644)
|
||||
if err != nil {
|
||||
t.Fatalf("OpenFile(DevNull): %v", err)
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ func OpenInRoot(dir, name string) (*File, error) {
|
||||
// - When GOOS=plan9 or GOOS=js, Root does not track directories across renames.
|
||||
// On these platforms, a Root references a directory name, not a file descriptor.
|
||||
type Root struct {
|
||||
root root
|
||||
root *root
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -49,7 +49,7 @@ func newRoot(name string) (*Root, error) {
|
||||
if !fi.IsDir() {
|
||||
return nil, errors.New("not a directory")
|
||||
}
|
||||
return &Root{root{name: name}}, nil
|
||||
return &Root{&root{name: name}}, nil
|
||||
}
|
||||
|
||||
func (r *root) Close() error {
|
||||
|
@ -48,11 +48,11 @@ func newRoot(fd int, name string) (*Root, error) {
|
||||
syscall.CloseOnExec(fd)
|
||||
}
|
||||
|
||||
r := &Root{root{
|
||||
r := &Root{&root{
|
||||
fd: fd,
|
||||
name: name,
|
||||
}}
|
||||
runtime.SetFinalizer(&r.root, (*root).Close)
|
||||
runtime.SetFinalizer(r.root, (*root).Close)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
|
@ -105,11 +105,11 @@ func newRoot(fd syscall.Handle, name string) (*Root, error) {
|
||||
return nil, &PathError{Op: "open", Path: name, Err: errors.New("not a directory")}
|
||||
}
|
||||
|
||||
r := &Root{root{
|
||||
r := &Root{&root{
|
||||
fd: fd,
|
||||
name: name,
|
||||
}}
|
||||
runtime.SetFinalizer(&r.root, (*root).Close)
|
||||
runtime.SetFinalizer(r.root, (*root).Close)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
|
@ -4,15 +4,24 @@
|
||||
|
||||
package reflect
|
||||
|
||||
import "iter"
|
||||
import (
|
||||
"iter"
|
||||
)
|
||||
|
||||
func rangeNum[T int8 | int16 | int32 | int64 | int |
|
||||
uint8 | uint16 | uint32 | uint64 | uint |
|
||||
uintptr, N int64 | uint64](v N) iter.Seq[Value] {
|
||||
uintptr, N int64 | uint64](num N, t Type) iter.Seq[Value] {
|
||||
return func(yield func(v Value) bool) {
|
||||
convert := t.PkgPath() != ""
|
||||
// cannot use range T(v) because no core type.
|
||||
for i := T(0); i < T(v); i++ {
|
||||
if !yield(ValueOf(i)) {
|
||||
for i := T(0); i < T(num); i++ {
|
||||
tmp := ValueOf(i)
|
||||
// if the iteration value type is define by
|
||||
// type T built-in type.
|
||||
if convert {
|
||||
tmp = tmp.Convert(t)
|
||||
}
|
||||
if !yield(tmp) {
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -27,7 +36,7 @@ func rangeNum[T int8 | int16 | int32 | int64 | int |
|
||||
// Uint, Uint8, Uint16, Uint32, Uint64, Uintptr,
|
||||
// Array, Chan, Map, Slice, or String.
|
||||
func (v Value) Seq() iter.Seq[Value] {
|
||||
if canRangeFunc(v.typ()) {
|
||||
if canRangeFunc(v.abiType()) {
|
||||
return func(yield func(Value) bool) {
|
||||
rf := MakeFunc(v.Type().In(0), func(in []Value) []Value {
|
||||
return []Value{ValueOf(yield(in[0]))}
|
||||
@ -35,29 +44,29 @@ func (v Value) Seq() iter.Seq[Value] {
|
||||
v.Call([]Value{rf})
|
||||
}
|
||||
}
|
||||
switch v.Kind() {
|
||||
switch v.kind() {
|
||||
case Int:
|
||||
return rangeNum[int](v.Int())
|
||||
return rangeNum[int](v.Int(), v.Type())
|
||||
case Int8:
|
||||
return rangeNum[int8](v.Int())
|
||||
return rangeNum[int8](v.Int(), v.Type())
|
||||
case Int16:
|
||||
return rangeNum[int16](v.Int())
|
||||
return rangeNum[int16](v.Int(), v.Type())
|
||||
case Int32:
|
||||
return rangeNum[int32](v.Int())
|
||||
return rangeNum[int32](v.Int(), v.Type())
|
||||
case Int64:
|
||||
return rangeNum[int64](v.Int())
|
||||
return rangeNum[int64](v.Int(), v.Type())
|
||||
case Uint:
|
||||
return rangeNum[uint](v.Uint())
|
||||
return rangeNum[uint](v.Uint(), v.Type())
|
||||
case Uint8:
|
||||
return rangeNum[uint8](v.Uint())
|
||||
return rangeNum[uint8](v.Uint(), v.Type())
|
||||
case Uint16:
|
||||
return rangeNum[uint16](v.Uint())
|
||||
return rangeNum[uint16](v.Uint(), v.Type())
|
||||
case Uint32:
|
||||
return rangeNum[uint32](v.Uint())
|
||||
return rangeNum[uint32](v.Uint(), v.Type())
|
||||
case Uint64:
|
||||
return rangeNum[uint64](v.Uint())
|
||||
return rangeNum[uint64](v.Uint(), v.Type())
|
||||
case Uintptr:
|
||||
return rangeNum[uintptr](v.Uint())
|
||||
return rangeNum[uintptr](v.Uint(), v.Type())
|
||||
case Pointer:
|
||||
if v.Elem().kind() != Array {
|
||||
break
|
||||
@ -113,7 +122,7 @@ func (v Value) Seq() iter.Seq[Value] {
|
||||
// If v's kind is Pointer, the pointer element type must have kind Array.
|
||||
// Otherwise v's kind must be Array, Map, Slice, or String.
|
||||
func (v Value) Seq2() iter.Seq2[Value, Value] {
|
||||
if canRangeFunc2(v.typ()) {
|
||||
if canRangeFunc2(v.abiType()) {
|
||||
return func(yield func(Value, Value) bool) {
|
||||
rf := MakeFunc(v.Type().In(0), func(in []Value) []Value {
|
||||
return []Value{ValueOf(yield(in[0], in[1]))}
|
||||
|
@ -7,10 +7,13 @@ package reflect_test
|
||||
import (
|
||||
"iter"
|
||||
"maps"
|
||||
"reflect"
|
||||
. "reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type N int8
|
||||
|
||||
func TestValueSeq(t *testing.T) {
|
||||
m := map[string]int{
|
||||
"1": 1,
|
||||
@ -173,6 +176,33 @@ func TestValueSeq(t *testing.T) {
|
||||
t.Fatalf("should loop four times")
|
||||
}
|
||||
}},
|
||||
{"method", ValueOf(methodIter{}).Method(0), func(t *testing.T, s iter.Seq[Value]) {
|
||||
i := int64(0)
|
||||
for v := range s {
|
||||
if v.Int() != i {
|
||||
t.Fatalf("got %d, want %d", v.Int(), i)
|
||||
}
|
||||
i++
|
||||
}
|
||||
if i != 4 {
|
||||
t.Fatalf("should loop four times")
|
||||
}
|
||||
}},
|
||||
{"type N int8", ValueOf(N(4)), func(t *testing.T, s iter.Seq[Value]) {
|
||||
i := N(0)
|
||||
for v := range s {
|
||||
if v.Int() != int64(i) {
|
||||
t.Fatalf("got %d, want %d", v.Int(), i)
|
||||
}
|
||||
i++
|
||||
if v.Type() != reflect.TypeOf(i) {
|
||||
t.Fatalf("got %s, want %s", v.Type(), reflect.TypeOf(i))
|
||||
}
|
||||
}
|
||||
if i != 4 {
|
||||
t.Fatalf("should loop four times")
|
||||
}
|
||||
}},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
seq := tc.val.Seq()
|
||||
@ -293,9 +323,84 @@ func TestValueSeq2(t *testing.T) {
|
||||
t.Fatalf("should loop four times")
|
||||
}
|
||||
}},
|
||||
{"method", ValueOf(methodIter2{}).Method(0), func(t *testing.T, s iter.Seq2[Value, Value]) {
|
||||
i := int64(0)
|
||||
for v1, v2 := range s {
|
||||
if v1.Int() != i {
|
||||
t.Fatalf("got %d, want %d", v1.Int(), i)
|
||||
}
|
||||
i++
|
||||
if v2.Int() != i {
|
||||
t.Fatalf("got %d, want %d", v2.Int(), i)
|
||||
}
|
||||
}
|
||||
if i != 4 {
|
||||
t.Fatalf("should loop four times")
|
||||
}
|
||||
}},
|
||||
{"[4]N", ValueOf([4]N{0, 1, 2, 3}), func(t *testing.T, s iter.Seq2[Value, Value]) {
|
||||
i := N(0)
|
||||
for v1, v2 := range s {
|
||||
if v1.Int() != int64(i) {
|
||||
t.Fatalf("got %d, want %d", v1.Int(), i)
|
||||
}
|
||||
if v2.Int() != int64(i) {
|
||||
t.Fatalf("got %d, want %d", v2.Int(), i)
|
||||
}
|
||||
i++
|
||||
if v2.Type() != reflect.TypeOf(i) {
|
||||
t.Fatalf("got %s, want %s", v2.Type(), reflect.TypeOf(i))
|
||||
}
|
||||
}
|
||||
if i != 4 {
|
||||
t.Fatalf("should loop four times")
|
||||
}
|
||||
}},
|
||||
{"[]N", ValueOf([]N{1, 2, 3, 4}), func(t *testing.T, s iter.Seq2[Value, Value]) {
|
||||
i := N(0)
|
||||
for v1, v2 := range s {
|
||||
if v1.Int() != int64(i) {
|
||||
t.Fatalf("got %d, want %d", v1.Int(), i)
|
||||
}
|
||||
i++
|
||||
if v2.Int() != int64(i) {
|
||||
t.Fatalf("got %d, want %d", v2.Int(), i)
|
||||
}
|
||||
if v2.Type() != reflect.TypeOf(i) {
|
||||
t.Fatalf("got %s, want %s", v2.Type(), reflect.TypeOf(i))
|
||||
}
|
||||
}
|
||||
if i != 4 {
|
||||
t.Fatalf("should loop four times")
|
||||
}
|
||||
}},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
seq := tc.val.Seq2()
|
||||
tc.check(t, seq)
|
||||
}
|
||||
}
|
||||
|
||||
// methodIter is a type from which we can derive a method
|
||||
// value that is an iter.Seq.
|
||||
type methodIter struct{}
|
||||
|
||||
func (methodIter) Seq(yield func(int) bool) {
|
||||
for i := range 4 {
|
||||
if !yield(i) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// methodIter2 is a type from which we can derive a method
|
||||
// value that is an iter.Seq2.
|
||||
type methodIter2 struct{}
|
||||
|
||||
func (methodIter2) Seq2(yield func(int, int) bool) {
|
||||
for i := range 4 {
|
||||
if !yield(i, i+1) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,9 @@ func (f flag) ro() flag {
|
||||
return 0
|
||||
}
|
||||
|
||||
// typ returns the *abi.Type stored in the Value. This method is fast,
|
||||
// but it doesn't always return the correct type for the Value.
|
||||
// See abiType and Type, which do return the correct type.
|
||||
func (v Value) typ() *abi.Type {
|
||||
// Types are either static (for compiler-created types) or
|
||||
// heap-allocated but always reachable (for reflection-created
|
||||
@ -2380,14 +2383,26 @@ func (v Value) Type() Type {
|
||||
return v.typeSlow()
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func (v Value) typeSlow() Type {
|
||||
return toRType(v.abiTypeSlow())
|
||||
}
|
||||
|
||||
func (v Value) abiType() *abi.Type {
|
||||
if v.flag != 0 && v.flag&flagMethod == 0 {
|
||||
return v.typ()
|
||||
}
|
||||
return v.abiTypeSlow()
|
||||
}
|
||||
|
||||
func (v Value) abiTypeSlow() *abi.Type {
|
||||
if v.flag == 0 {
|
||||
panic(&ValueError{"reflect.Value.Type", Invalid})
|
||||
}
|
||||
|
||||
typ := v.typ()
|
||||
if v.flag&flagMethod == 0 {
|
||||
return toRType(v.typ())
|
||||
return v.typ()
|
||||
}
|
||||
|
||||
// Method value.
|
||||
@ -2400,7 +2415,7 @@ func (v Value) typeSlow() Type {
|
||||
panic("reflect: internal error: invalid method index")
|
||||
}
|
||||
m := &tt.Methods[i]
|
||||
return toRType(typeOffFor(typ, m.Typ))
|
||||
return typeOffFor(typ, m.Typ)
|
||||
}
|
||||
// Method on concrete type.
|
||||
ms := typ.ExportedMethods()
|
||||
@ -2408,7 +2423,7 @@ func (v Value) typeSlow() Type {
|
||||
panic("reflect: internal error: invalid method index")
|
||||
}
|
||||
m := ms[i]
|
||||
return toRType(typeOffFor(typ, m.Mtyp))
|
||||
return typeOffFor(typ, m.Mtyp)
|
||||
}
|
||||
|
||||
// CanUint reports whether [Value.Uint] can be used without panicking.
|
||||
|
@ -25,7 +25,8 @@ package cgo
|
||||
|
||||
// Use -fno-stack-protector to avoid problems locating the
|
||||
// proper support functions. See issues #52919, #54313, #58385.
|
||||
#cgo CFLAGS: -Wall -Werror -fno-stack-protector
|
||||
// Use -Wdeclaration-after-statement because some CI builds use it.
|
||||
#cgo CFLAGS: -Wall -Werror -fno-stack-protector -Wdeclaration-after-statement
|
||||
|
||||
#cgo solaris CPPFLAGS: -D_POSIX_PTHREAD_SEMANTICS
|
||||
|
||||
|
@ -76,19 +76,27 @@ threadentry(void *v)
|
||||
static void
|
||||
init_working_dir()
|
||||
{
|
||||
CFBundleRef bundle = CFBundleGetMainBundle();
|
||||
CFBundleRef bundle;
|
||||
CFURLRef url_ref;
|
||||
CFStringRef url_str_ref;
|
||||
char buf[MAXPATHLEN];
|
||||
Boolean res;
|
||||
int url_len;
|
||||
char *dir;
|
||||
CFStringRef wd_ref;
|
||||
|
||||
bundle = CFBundleGetMainBundle();
|
||||
if (bundle == NULL) {
|
||||
fprintf(stderr, "runtime/cgo: no main bundle\n");
|
||||
return;
|
||||
}
|
||||
CFURLRef url_ref = CFBundleCopyResourceURL(bundle, CFSTR("Info"), CFSTR("plist"), NULL);
|
||||
url_ref = CFBundleCopyResourceURL(bundle, CFSTR("Info"), CFSTR("plist"), NULL);
|
||||
if (url_ref == NULL) {
|
||||
// No Info.plist found. It can happen on Corellium virtual devices.
|
||||
return;
|
||||
}
|
||||
CFStringRef url_str_ref = CFURLGetString(url_ref);
|
||||
char buf[MAXPATHLEN];
|
||||
Boolean res = CFStringGetCString(url_str_ref, buf, sizeof(buf), kCFStringEncodingUTF8);
|
||||
url_str_ref = CFURLGetString(url_ref);
|
||||
res = CFStringGetCString(url_str_ref, buf, sizeof(buf), kCFStringEncodingUTF8);
|
||||
CFRelease(url_ref);
|
||||
if (!res) {
|
||||
fprintf(stderr, "runtime/cgo: cannot get URL string\n");
|
||||
@ -97,13 +105,13 @@ init_working_dir()
|
||||
|
||||
// url is of the form "file:///path/to/Info.plist".
|
||||
// strip it down to the working directory "/path/to".
|
||||
int url_len = strlen(buf);
|
||||
url_len = strlen(buf);
|
||||
if (url_len < sizeof("file://")+sizeof("/Info.plist")) {
|
||||
fprintf(stderr, "runtime/cgo: bad URL: %s\n", buf);
|
||||
return;
|
||||
}
|
||||
buf[url_len-sizeof("/Info.plist")+1] = 0;
|
||||
char *dir = &buf[0] + sizeof("file://")-1;
|
||||
dir = &buf[0] + sizeof("file://")-1;
|
||||
|
||||
if (chdir(dir) != 0) {
|
||||
fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", dir);
|
||||
@ -111,7 +119,7 @@ init_working_dir()
|
||||
|
||||
// The test harness in go_ios_exec passes the relative working directory
|
||||
// in the GoExecWrapperWorkingDirectory property of the app bundle.
|
||||
CFStringRef wd_ref = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("GoExecWrapperWorkingDirectory"));
|
||||
wd_ref = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("GoExecWrapperWorkingDirectory"));
|
||||
if (wd_ref != NULL) {
|
||||
if (!CFStringGetCString(wd_ref, buf, sizeof(buf), kCFStringEncodingUTF8)) {
|
||||
fprintf(stderr, "runtime/cgo: cannot get GoExecWrapperWorkingDirectory string\n");
|
||||
|
@ -39,10 +39,11 @@ void
|
||||
x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
|
||||
pthread_attr_t attr;
|
||||
pthread_t p;
|
||||
int err;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
int err = _cgo_try_pthread_create(&p, &attr, func, arg);
|
||||
err = _cgo_try_pthread_create(&p, &attr, func, arg);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "pthread_create failed: %s", strerror(err));
|
||||
abort();
|
||||
@ -52,9 +53,11 @@ x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
|
||||
uintptr_t
|
||||
_cgo_wait_runtime_init_done(void) {
|
||||
void (*pfn)(struct context_arg*);
|
||||
int done;
|
||||
|
||||
pfn = __atomic_load_n(&cgo_context_function, __ATOMIC_CONSUME);
|
||||
|
||||
int done = 2;
|
||||
done = 2;
|
||||
if (__atomic_load_n(&runtime_init_done, __ATOMIC_CONSUME) != done) {
|
||||
pthread_mutex_lock(&runtime_init_mu);
|
||||
while (__atomic_load_n(&runtime_init_done, __ATOMIC_CONSUME) == 0) {
|
||||
|
@ -75,8 +75,10 @@ x_cgo_sys_thread_create(void (*func)(void*), void* arg) {
|
||||
|
||||
int
|
||||
_cgo_is_runtime_initialized() {
|
||||
int status;
|
||||
|
||||
EnterCriticalSection(&runtime_init_cs);
|
||||
int status = runtime_init_done;
|
||||
status = runtime_init_done;
|
||||
LeaveCriticalSection(&runtime_init_cs);
|
||||
return status;
|
||||
}
|
||||
|
@ -355,7 +355,9 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) {
|
||||
gp.m.incgo = true
|
||||
unlockOSThread()
|
||||
|
||||
if gp.m.isextra {
|
||||
if gp.m.isextra && gp.m.ncgo == 0 {
|
||||
// There are no active cgocalls above this frame (ncgo == 0),
|
||||
// thus there can't be more Go frames above this frame.
|
||||
gp.m.isExtraInC = true
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,22 @@ func TestCgoCallbackGC(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCgoCallbackPprof(t *testing.T) {
|
||||
t.Parallel()
|
||||
switch runtime.GOOS {
|
||||
case "plan9", "windows":
|
||||
t.Skipf("no pthreads on %s", runtime.GOOS)
|
||||
}
|
||||
if testenv.CPUProfilingBroken() {
|
||||
t.Skip("skipping on platform with broken profiling")
|
||||
}
|
||||
|
||||
got := runTestProg(t, "testprogcgo", "CgoCallbackPprof")
|
||||
if want := "OK\n"; got != want {
|
||||
t.Fatalf("expected %q, but got:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCgoExternalThreadPanic(t *testing.T) {
|
||||
t.Parallel()
|
||||
if runtime.GOOS == "plan9" {
|
||||
|
@ -6,6 +6,7 @@ package runtime_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
@ -59,3 +60,36 @@ func ExampleFrames() {
|
||||
// - more:true | runtime_test.ExampleFrames.func3
|
||||
// - more:true | runtime_test.ExampleFrames
|
||||
}
|
||||
|
||||
func ExampleAddCleanup() {
|
||||
tempFile, err := os.CreateTemp(os.TempDir(), "file.*")
|
||||
if err != nil {
|
||||
fmt.Println("failed to create temp file:", err)
|
||||
return
|
||||
}
|
||||
|
||||
ch := make(chan struct{})
|
||||
|
||||
// Attach a cleanup function to the file object.
|
||||
runtime.AddCleanup(&tempFile, func(fileName string) {
|
||||
if err := os.Remove(fileName); err == nil {
|
||||
fmt.Println("temp file has been removed")
|
||||
}
|
||||
ch <- struct{}{}
|
||||
}, tempFile.Name())
|
||||
|
||||
if err := tempFile.Close(); err != nil {
|
||||
fmt.Println("failed to close temp file:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Run the garbage collector to reclaim unreachable objects
|
||||
// and enqueue their cleanup functions.
|
||||
runtime.GC()
|
||||
|
||||
// Wait until cleanup function is done.
|
||||
<-ch
|
||||
|
||||
// Output:
|
||||
// temp file has been removed
|
||||
}
|
||||
|
@ -30,8 +30,10 @@ import (
|
||||
// unreachable at the same time, their cleanups all become eligible to run
|
||||
// and can run in any order. This is true even if the objects form a cycle.
|
||||
//
|
||||
// A single goroutine runs all cleanup calls for a program, sequentially. If a
|
||||
// cleanup function must run for a long time, it should create a new goroutine.
|
||||
// Cleanups run concurrently with any user-created goroutines.
|
||||
// Cleanups may also run concurrently with one another (unlike finalizers).
|
||||
// If a cleanup function must run for a long time, it should create a new goroutine
|
||||
// to avoid blocking the execution of other cleanups.
|
||||
//
|
||||
// If ptr has both a cleanup and a finalizer, the cleanup will only run once
|
||||
// it has been finalized and becomes unreachable without an associated finalizer.
|
||||
|
@ -391,10 +391,15 @@ func deferrangefunc() any {
|
||||
throw("defer on system stack")
|
||||
}
|
||||
|
||||
fn := findfunc(sys.GetCallerPC())
|
||||
if fn.deferreturn == 0 {
|
||||
throw("no deferreturn")
|
||||
}
|
||||
|
||||
d := newdefer()
|
||||
d.link = gp._defer
|
||||
gp._defer = d
|
||||
d.pc = sys.GetCallerPC()
|
||||
d.pc = fn.entry() + uintptr(fn.deferreturn)
|
||||
// We must not be preempted between calling GetCallerSP and
|
||||
// storing it to d.sp because GetCallerSP's result is a
|
||||
// uintptr stack pointer.
|
||||
@ -1246,6 +1251,8 @@ func recovery(gp *g) {
|
||||
// only gets us to the caller's fp.
|
||||
gp.sched.bp = sp - goarch.PtrSize
|
||||
}
|
||||
// The value in ret is delivered IN A REGISTER, even if there is a
|
||||
// stack ABI.
|
||||
gp.sched.ret = 1
|
||||
gogo(&gp.sched)
|
||||
}
|
||||
|
@ -416,27 +416,6 @@ func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []*profile.Loca
|
||||
return p
|
||||
}
|
||||
|
||||
func cpuProfilingBroken() bool {
|
||||
switch runtime.GOOS {
|
||||
case "plan9":
|
||||
// Profiling unimplemented.
|
||||
return true
|
||||
case "aix":
|
||||
// See https://golang.org/issue/45170.
|
||||
return true
|
||||
case "ios", "dragonfly", "netbsd", "illumos", "solaris":
|
||||
// See https://golang.org/issue/13841.
|
||||
return true
|
||||
case "openbsd":
|
||||
if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
|
||||
// See https://golang.org/issue/13841.
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// testCPUProfile runs f under the CPU profiler, checking for some conditions specified by need,
|
||||
// as interpreted by matches, and returns the parsed profile.
|
||||
func testCPUProfile(t *testing.T, matches profileMatchFunc, f func(dur time.Duration)) *profile.Profile {
|
||||
@ -454,7 +433,7 @@ func testCPUProfile(t *testing.T, matches profileMatchFunc, f func(dur time.Dura
|
||||
t.Skip("skipping on wasip1")
|
||||
}
|
||||
|
||||
broken := cpuProfilingBroken()
|
||||
broken := testenv.CPUProfilingBroken()
|
||||
|
||||
deadline, ok := t.Deadline()
|
||||
if broken || !ok {
|
||||
|
@ -419,14 +419,21 @@ func isAsyncSafePoint(gp *g, pc, sp, lr uintptr) (bool, uintptr) {
|
||||
name := u.srcFunc(uf).name()
|
||||
if stringslite.HasPrefix(name, "runtime.") ||
|
||||
stringslite.HasPrefix(name, "runtime/internal/") ||
|
||||
stringslite.HasPrefix(name, "internal/runtime/") ||
|
||||
stringslite.HasPrefix(name, "reflect.") {
|
||||
// For now we never async preempt the runtime or
|
||||
// anything closely tied to the runtime. Known issues
|
||||
// include: various points in the scheduler ("don't
|
||||
// preempt between here and here"), much of the defer
|
||||
// implementation (untyped info on stack), bulk write
|
||||
// barriers (write barrier check),
|
||||
// reflect.{makeFuncStub,methodValueCall}.
|
||||
// barriers (write barrier check), atomic functions in
|
||||
// internal/runtime/atomic, reflect.{makeFuncStub,methodValueCall}.
|
||||
//
|
||||
// Note that this is a subset of the runtimePkgs in pkgspecial.go
|
||||
// and these checks are theoretically redundant because the compiler
|
||||
// marks "all points" in runtime functions as unsafe for async preemption.
|
||||
// But for some reason, we can't eliminate these checks until https://go.dev/issue/72031
|
||||
// is resolved.
|
||||
//
|
||||
// TODO(austin): We should improve this, or opt things
|
||||
// in incrementally.
|
||||
|
@ -556,7 +556,7 @@ type m struct {
|
||||
printlock int8
|
||||
incgo bool // m is executing a cgo call
|
||||
isextra bool // m is an extra m
|
||||
isExtraInC bool // m is an extra m that is not executing Go code
|
||||
isExtraInC bool // m is an extra m that does not have any Go frames
|
||||
isExtraInSig bool // m is an extra m in a signal handler
|
||||
freeWait atomic.Uint32 // Whether it is safe to free g0 and delete m (one of freeMRef, freeMStack, freeMWait)
|
||||
needextram bool
|
||||
|
@ -312,6 +312,16 @@ func asmcgocall(fn, arg unsafe.Pointer) int32
|
||||
|
||||
func morestack()
|
||||
|
||||
// morestack_noctxt should be an internal detail,
|
||||
// but widely used packages access it using linkname.
|
||||
// Notable members of the hall of shame include:
|
||||
// - github.com/bytedance/sonic
|
||||
//
|
||||
// Do not remove or change the type signature.
|
||||
// See go.dev/issues/67401.
|
||||
// See go.dev/issues/71672.
|
||||
//
|
||||
//go:linkname morestack_noctxt
|
||||
func morestack_noctxt()
|
||||
|
||||
func rt0_go()
|
||||
|
@ -480,7 +480,18 @@ var pinnedTypemaps []map[typeOff]*_type
|
||||
// the relocated one.
|
||||
var aixStaticDataBase uintptr // linker symbol
|
||||
|
||||
var firstmoduledata moduledata // linker symbol
|
||||
var firstmoduledata moduledata // linker symbol
|
||||
|
||||
// lastmoduledatap should be an internal detail,
|
||||
// but widely used packages access it using linkname.
|
||||
// Notable members of the hall of shame include:
|
||||
// - github.com/bytedance/sonic
|
||||
//
|
||||
// Do not remove or change the type signature.
|
||||
// See go.dev/issues/67401.
|
||||
// See go.dev/issues/71672.
|
||||
//
|
||||
//go:linkname lastmoduledatap
|
||||
var lastmoduledatap *moduledata // linker symbol
|
||||
|
||||
var modulesSlice *[]*moduledata // see activeModules
|
||||
@ -591,6 +602,16 @@ func moduledataverify() {
|
||||
|
||||
const debugPcln = false
|
||||
|
||||
// moduledataverify1 should be an internal detail,
|
||||
// but widely used packages access it using linkname.
|
||||
// Notable members of the hall of shame include:
|
||||
// - github.com/bytedance/sonic
|
||||
//
|
||||
// Do not remove or change the type signature.
|
||||
// See go.dev/issues/67401.
|
||||
// See go.dev/issues/71672.
|
||||
//
|
||||
//go:linkname moduledataverify1
|
||||
func moduledataverify1(datap *moduledata) {
|
||||
// Check that the pclntab's format is valid.
|
||||
hdr := datap.pcHeader
|
||||
|
@ -112,9 +112,10 @@ TEXT runtime·usleep(SB),NOSPLIT,$16-4
|
||||
MOVW $1000000, R3
|
||||
DIVD R3, R2
|
||||
MOVD R2, 8(R15)
|
||||
MOVW $1000, R3
|
||||
MULLD R2, R3
|
||||
MULLD R2, R3 // Convert sec to usec and subtract
|
||||
SUB R3, R4
|
||||
MOVW $1000, R3
|
||||
MULLD R3, R4 // Convert remaining usec into nsec.
|
||||
MOVD R4, 16(R15)
|
||||
|
||||
// nanosleep(&ts, 0)
|
||||
|
138
src/runtime/testdata/testprogcgo/callback_pprof.go
vendored
Normal file
138
src/runtime/testdata/testprogcgo/callback_pprof.go
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
// Copyright 2025 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.
|
||||
|
||||
//go:build !plan9 && !windows
|
||||
|
||||
package main
|
||||
|
||||
// Regression test for https://go.dev/issue/72870. Go code called from C should
|
||||
// never be reported as external code.
|
||||
|
||||
/*
|
||||
#include <pthread.h>
|
||||
|
||||
void go_callback1();
|
||||
void go_callback2();
|
||||
|
||||
static void *callback_pprof_thread(void *arg) {
|
||||
go_callback1();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void c_callback(void) {
|
||||
go_callback2();
|
||||
}
|
||||
|
||||
static void start_callback_pprof_thread() {
|
||||
pthread_t th;
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_create(&th, &attr, callback_pprof_thread, 0);
|
||||
// Don't join, caller will watch pprof.
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"internal/profile"
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
register("CgoCallbackPprof", CgoCallbackPprof)
|
||||
}
|
||||
|
||||
func CgoCallbackPprof() {
|
||||
C.start_callback_pprof_thread()
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := pprof.StartCPUProfile(&buf); err != nil {
|
||||
fmt.Printf("Error starting CPU profile: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
pprof.StopCPUProfile()
|
||||
|
||||
p, err := profile.Parse(&buf)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing profile: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
foundCallee := false
|
||||
for _, s := range p.Sample {
|
||||
funcs := flattenFrames(s)
|
||||
if len(funcs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
leaf := funcs[0]
|
||||
if leaf.Name != "main.go_callback1_callee" {
|
||||
continue
|
||||
}
|
||||
foundCallee = true
|
||||
|
||||
if len(funcs) < 2 {
|
||||
fmt.Printf("Profile: %s\n", p)
|
||||
frames := make([]string, len(funcs))
|
||||
for i := range funcs {
|
||||
frames[i] = funcs[i].Name
|
||||
}
|
||||
fmt.Printf("FAIL: main.go_callback1_callee sample missing caller in frames %v\n", frames)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if funcs[1].Name != "main.go_callback1" {
|
||||
// In https://go.dev/issue/72870, this will be runtime._ExternalCode.
|
||||
fmt.Printf("Profile: %s\n", p)
|
||||
frames := make([]string, len(funcs))
|
||||
for i := range funcs {
|
||||
frames[i] = funcs[i].Name
|
||||
}
|
||||
fmt.Printf("FAIL: main.go_callback1_callee sample caller got %s want main.go_callback1 in frames %v\n", funcs[1].Name, frames)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
if !foundCallee {
|
||||
fmt.Printf("Missing main.go_callback1_callee sample in profile %s\n", p)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("OK\n")
|
||||
}
|
||||
|
||||
// Return the frame functions in s, regardless of inlining.
|
||||
func flattenFrames(s *profile.Sample) []*profile.Function {
|
||||
ret := make([]*profile.Function, 0, len(s.Location))
|
||||
for _, loc := range s.Location {
|
||||
for _, line := range loc.Line {
|
||||
ret = append(ret, line.Function)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
//export go_callback1
|
||||
func go_callback1() {
|
||||
// This is a separate function just to ensure we have another Go
|
||||
// function as the caller in the profile.
|
||||
go_callback1_callee()
|
||||
}
|
||||
|
||||
func go_callback1_callee() {
|
||||
C.c_callback()
|
||||
|
||||
// Spin for CPU samples.
|
||||
for {
|
||||
}
|
||||
}
|
||||
|
||||
//export go_callback2
|
||||
func go_callback2() {
|
||||
}
|
@ -779,7 +779,12 @@ func os_checkClonePidfd() error {
|
||||
var err error
|
||||
for {
|
||||
var status WaitStatus
|
||||
_, err = Wait4(int(pid), &status, 0, nil)
|
||||
// WCLONE is an untyped constant that sets bit 31, so
|
||||
// it cannot convert directly to int on 32-bit
|
||||
// GOARCHes. We must convert through another type
|
||||
// first.
|
||||
flags := uint(WCLONE)
|
||||
_, err = Wait4(int(pid), &status, int(flags), nil)
|
||||
if err != EINTR {
|
||||
break
|
||||
}
|
||||
@ -797,7 +802,7 @@ func os_checkClonePidfd() error {
|
||||
|
||||
for {
|
||||
const _P_PIDFD = 3
|
||||
_, _, errno = Syscall6(SYS_WAITID, _P_PIDFD, uintptr(pidfd), 0, WEXITED, 0, 0)
|
||||
_, _, errno = Syscall6(SYS_WAITID, _P_PIDFD, uintptr(pidfd), 0, WEXITED | WCLONE, 0, 0)
|
||||
if errno != EINTR {
|
||||
break
|
||||
}
|
||||
@ -818,7 +823,7 @@ func os_checkClonePidfd() error {
|
||||
//
|
||||
//go:noinline
|
||||
func doCheckClonePidfd(pidfd *int32) (pid uintptr, errno Errno) {
|
||||
flags := uintptr(CLONE_VFORK | CLONE_VM | CLONE_PIDFD | SIGCHLD)
|
||||
flags := uintptr(CLONE_VFORK | CLONE_VM | CLONE_PIDFD)
|
||||
if runtime.GOARCH == "s390x" {
|
||||
// On Linux/s390, the first two arguments of clone(2) are swapped.
|
||||
pid, errno = rawVforkSyscall(SYS_CLONE, 0, flags, uintptr(unsafe.Pointer(pidfd)))
|
||||
|
@ -23,15 +23,26 @@ var constants = jsFS.Get("constants")
|
||||
var uint8Array = js.Global().Get("Uint8Array")
|
||||
|
||||
var (
|
||||
nodeWRONLY = constants.Get("O_WRONLY").Int()
|
||||
nodeRDWR = constants.Get("O_RDWR").Int()
|
||||
nodeCREATE = constants.Get("O_CREAT").Int()
|
||||
nodeTRUNC = constants.Get("O_TRUNC").Int()
|
||||
nodeAPPEND = constants.Get("O_APPEND").Int()
|
||||
nodeEXCL = constants.Get("O_EXCL").Int()
|
||||
nodeDIRECTORY = constants.Get("O_DIRECTORY").Int()
|
||||
nodeWRONLY = constants.Get("O_WRONLY").Int()
|
||||
nodeRDWR = constants.Get("O_RDWR").Int()
|
||||
nodeCREATE = constants.Get("O_CREAT").Int()
|
||||
nodeTRUNC = constants.Get("O_TRUNC").Int()
|
||||
nodeAPPEND = constants.Get("O_APPEND").Int()
|
||||
nodeEXCL = constants.Get("O_EXCL").Int()
|
||||
|
||||
// NodeJS on Windows does not support O_DIRECTORY, so we default
|
||||
// to -1 and assign it in init if available.
|
||||
// See https://nodejs.org/docs/latest/api/fs.html#file-open-constants.
|
||||
nodeDIRECTORY = -1
|
||||
)
|
||||
|
||||
func init() {
|
||||
oDir := constants.Get("O_DIRECTORY")
|
||||
if !oDir.IsUndefined() {
|
||||
nodeDIRECTORY = oDir.Int()
|
||||
}
|
||||
}
|
||||
|
||||
type jsFile struct {
|
||||
path string
|
||||
entries []string
|
||||
@ -85,7 +96,11 @@ func Open(path string, openmode int, perm uint32) (int, error) {
|
||||
return 0, errors.New("syscall.Open: O_SYNC is not supported by js/wasm")
|
||||
}
|
||||
if openmode&O_DIRECTORY != 0 {
|
||||
flags |= nodeDIRECTORY
|
||||
if nodeDIRECTORY != -1 {
|
||||
flags |= nodeDIRECTORY
|
||||
} else {
|
||||
return 0, errors.New("syscall.Open: O_DIRECTORY is not supported on Windows")
|
||||
}
|
||||
}
|
||||
|
||||
jsFD, err := fsCall("open", path, flags, perm)
|
||||
|
@ -235,7 +235,7 @@ func NewCallbackCDecl(fn any) uintptr {
|
||||
//sys GetVersion() (ver uint32, err error)
|
||||
//sys formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
|
||||
//sys ExitProcess(exitcode uint32)
|
||||
//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
|
||||
//sys createFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval == InvalidHandle || e1 == ERROR_ALREADY_EXISTS ] = CreateFileW
|
||||
//sys readFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) = ReadFile
|
||||
//sys writeFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) = WriteFile
|
||||
//sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) [failretval==0xffffffff]
|
||||
@ -404,8 +404,8 @@ func Open(name string, flag int, perm uint32) (fd Handle, err error) {
|
||||
const _FILE_FLAG_WRITE_THROUGH = 0x80000000
|
||||
attrs |= _FILE_FLAG_WRITE_THROUGH
|
||||
}
|
||||
h, err := CreateFile(namep, access, sharemode, sa, createmode, attrs, 0)
|
||||
if err != nil {
|
||||
h, err := createFile(namep, access, sharemode, sa, createmode, attrs, 0)
|
||||
if h == InvalidHandle {
|
||||
if err == ERROR_ACCESS_DENIED && (flag&O_WRONLY != 0 || flag&O_RDWR != 0) {
|
||||
// We should return EISDIR when we are trying to open a directory with write access.
|
||||
fa, e1 := GetFileAttributes(namep)
|
||||
@ -413,9 +413,11 @@ func Open(name string, flag int, perm uint32) (fd Handle, err error) {
|
||||
err = EISDIR
|
||||
}
|
||||
}
|
||||
return InvalidHandle, err
|
||||
return h, err
|
||||
}
|
||||
if flag&O_TRUNC == O_TRUNC {
|
||||
// Ignore O_TRUNC if the file has just been created.
|
||||
if flag&O_TRUNC == O_TRUNC &&
|
||||
(createmode == OPEN_EXISTING || (createmode == OPEN_ALWAYS && err == ERROR_ALREADY_EXISTS)) {
|
||||
err = Ftruncate(h, 0)
|
||||
if err != nil {
|
||||
CloseHandle(h)
|
||||
@ -1454,3 +1456,13 @@ func GetStartupInfo(startupInfo *StartupInfo) error {
|
||||
getStartupInfo(startupInfo)
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) {
|
||||
handle, err = createFile(name, access, mode, sa, createmode, attrs, templatefile)
|
||||
if handle != InvalidHandle {
|
||||
// CreateFileW can return ERROR_ALREADY_EXISTS with a valid handle.
|
||||
// We only want to return an error if the handle is invalid.
|
||||
err = nil
|
||||
}
|
||||
return handle, err
|
||||
}
|
||||
|
@ -502,10 +502,10 @@ func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxS
|
||||
return
|
||||
}
|
||||
|
||||
func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) {
|
||||
func createFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) {
|
||||
r0, _, e1 := Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
|
||||
handle = Handle(r0)
|
||||
if handle == InvalidHandle {
|
||||
if handle == InvalidHandle || e1 == ERROR_ALREADY_EXISTS {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
|
@ -114,10 +114,22 @@ type B struct {
|
||||
netBytes uint64
|
||||
// Extra metrics collected by ReportMetric.
|
||||
extra map[string]float64
|
||||
// For Loop() to be executed in benchFunc.
|
||||
// Loop() has its own control logic that skips the loop scaling.
|
||||
// See issue #61515.
|
||||
loopN int
|
||||
|
||||
// loop tracks the state of B.Loop
|
||||
loop struct {
|
||||
// n is the target number of iterations. It gets bumped up as we go.
|
||||
// When the benchmark loop is done, we commit this to b.N so users can
|
||||
// do reporting based on it, but we avoid exposing it until then.
|
||||
n uint64
|
||||
// i is the current Loop iteration. It's strictly monotonically
|
||||
// increasing toward n.
|
||||
//
|
||||
// The high bit is used to poison the Loop fast path and fall back to
|
||||
// the slow path.
|
||||
i uint64
|
||||
|
||||
done bool // set when B.Loop return false
|
||||
}
|
||||
}
|
||||
|
||||
// StartTimer starts timing a test. This function is called automatically
|
||||
@ -130,6 +142,7 @@ func (b *B) StartTimer() {
|
||||
b.startBytes = memStats.TotalAlloc
|
||||
b.start = highPrecisionTimeNow()
|
||||
b.timerOn = true
|
||||
b.loop.i &^= loopPoisonTimer
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,6 +155,8 @@ func (b *B) StopTimer() {
|
||||
b.netAllocs += memStats.Mallocs - b.startAllocs
|
||||
b.netBytes += memStats.TotalAlloc - b.startBytes
|
||||
b.timerOn = false
|
||||
// If we hit B.Loop with the timer stopped, fail.
|
||||
b.loop.i |= loopPoisonTimer
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,7 +207,9 @@ func (b *B) runN(n int) {
|
||||
runtime.GC()
|
||||
b.resetRaces()
|
||||
b.N = n
|
||||
b.loopN = 0
|
||||
b.loop.n = 0
|
||||
b.loop.i = 0
|
||||
b.loop.done = false
|
||||
b.ctx = ctx
|
||||
b.cancelCtx = cancelCtx
|
||||
|
||||
@ -203,6 +220,10 @@ func (b *B) runN(n int) {
|
||||
b.StopTimer()
|
||||
b.previousN = n
|
||||
b.previousDuration = b.duration
|
||||
|
||||
if b.loop.n > 0 && !b.loop.done && !b.failed {
|
||||
b.Error("benchmark function returned without B.Loop() == false (break or return in loop?)")
|
||||
}
|
||||
}
|
||||
|
||||
// run1 runs the first iteration of benchFunc. It reports whether more
|
||||
@ -312,8 +333,8 @@ func (b *B) launch() {
|
||||
}()
|
||||
|
||||
// b.Loop does its own ramp-up logic so we just need to run it once.
|
||||
// If b.loopN is non zero, it means b.Loop has already run.
|
||||
if b.loopN == 0 {
|
||||
// If b.loop.n is non zero, it means b.Loop has already run.
|
||||
if b.loop.n == 0 {
|
||||
// Run the benchmark for at least the specified amount of time.
|
||||
if b.benchTime.n > 0 {
|
||||
// We already ran a single iteration in run1.
|
||||
@ -368,38 +389,59 @@ func (b *B) ReportMetric(n float64, unit string) {
|
||||
}
|
||||
|
||||
func (b *B) stopOrScaleBLoop() bool {
|
||||
timeElapsed := highPrecisionTimeSince(b.start)
|
||||
if timeElapsed >= b.benchTime.d {
|
||||
t := b.Elapsed()
|
||||
if t >= b.benchTime.d {
|
||||
// Stop the timer so we don't count cleanup time
|
||||
b.StopTimer()
|
||||
// Commit iteration count
|
||||
b.N = int(b.loop.n)
|
||||
b.loop.done = true
|
||||
return false
|
||||
}
|
||||
// Loop scaling
|
||||
goalns := b.benchTime.d.Nanoseconds()
|
||||
prevIters := int64(b.N)
|
||||
b.N = predictN(goalns, prevIters, timeElapsed.Nanoseconds(), prevIters)
|
||||
b.loopN++
|
||||
prevIters := int64(b.loop.n)
|
||||
b.loop.n = uint64(predictN(goalns, prevIters, t.Nanoseconds(), prevIters))
|
||||
if b.loop.n&loopPoisonMask != 0 {
|
||||
// The iteration count should never get this high, but if it did we'd be
|
||||
// in big trouble.
|
||||
panic("loop iteration target overflow")
|
||||
}
|
||||
b.loop.i++
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *B) loopSlowPath() bool {
|
||||
if b.loopN == 0 {
|
||||
// Consistency checks
|
||||
if !b.timerOn {
|
||||
b.Fatal("B.Loop called with timer stopped")
|
||||
}
|
||||
if b.loop.i&loopPoisonMask != 0 {
|
||||
panic(fmt.Sprintf("unknown loop stop condition: %#x", b.loop.i))
|
||||
}
|
||||
|
||||
if b.loop.n == 0 {
|
||||
// If it's the first call to b.Loop() in the benchmark function.
|
||||
// Allows more precise measurement of benchmark loop cost counts.
|
||||
// Also initialize b.N to 1 to kick start loop scaling.
|
||||
b.N = 1
|
||||
b.loopN = 1
|
||||
// Also initialize target to 1 to kick start loop scaling.
|
||||
b.loop.n = 1
|
||||
// Within a b.Loop loop, we don't use b.N (to avoid confusion).
|
||||
b.N = 0
|
||||
b.loop.i++
|
||||
b.ResetTimer()
|
||||
return true
|
||||
}
|
||||
// Handles fixed iterations case
|
||||
if b.benchTime.n > 0 {
|
||||
if b.N < b.benchTime.n {
|
||||
b.N = b.benchTime.n
|
||||
b.loopN++
|
||||
if b.loop.n < uint64(b.benchTime.n) {
|
||||
b.loop.n = uint64(b.benchTime.n)
|
||||
b.loop.i++
|
||||
return true
|
||||
}
|
||||
b.StopTimer()
|
||||
// Commit iteration count
|
||||
b.N = int(b.loop.n)
|
||||
b.loop.done = true
|
||||
return false
|
||||
}
|
||||
// Handles fixed time case
|
||||
@ -440,13 +482,38 @@ func (b *B) loopSlowPath() bool {
|
||||
// whereas b.N-based benchmarks must run the benchmark function (and any
|
||||
// associated setup and cleanup) several times.
|
||||
func (b *B) Loop() bool {
|
||||
if b.loopN != 0 && b.loopN < b.N {
|
||||
b.loopN++
|
||||
// This is written such that the fast path is as fast as possible and can be
|
||||
// inlined.
|
||||
//
|
||||
// There are three cases where we'll fall out of the fast path:
|
||||
//
|
||||
// - On the first call, both i and n are 0.
|
||||
//
|
||||
// - If the loop reaches the n'th iteration, then i == n and we need
|
||||
// to figure out the new target iteration count or if we're done.
|
||||
//
|
||||
// - If the timer is stopped, it poisons the top bit of i so the slow
|
||||
// path can do consistency checks and fail.
|
||||
if b.loop.i < b.loop.n {
|
||||
b.loop.i++
|
||||
return true
|
||||
}
|
||||
return b.loopSlowPath()
|
||||
}
|
||||
|
||||
// The loopPoison constants can be OR'd into B.loop.i to cause it to fall back
|
||||
// to the slow path.
|
||||
const (
|
||||
loopPoisonTimer = uint64(1 << (63 - iota))
|
||||
// If necessary, add more poison bits here.
|
||||
|
||||
// loopPoisonMask is the set of all loop poison bits. (iota-1) is the index
|
||||
// of the bit we just set, from which we recreate that bit mask. We subtract
|
||||
// 1 to set all of the bits below that bit, then complement the result to
|
||||
// get the mask. Sorry, not sorry.
|
||||
loopPoisonMask = ^uint64((1 << (63 - (iota - 1))) - 1)
|
||||
)
|
||||
|
||||
// BenchmarkResult contains the results of a benchmark run.
|
||||
type BenchmarkResult struct {
|
||||
N int // The number of iterations.
|
||||
|
@ -4,13 +4,22 @@
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// See also TestBenchmarkBLoop* in other files.
|
||||
|
||||
func TestBenchmarkBLoop(t *T) {
|
||||
var initialStart highPrecisionTime
|
||||
var firstStart highPrecisionTime
|
||||
var lastStart highPrecisionTime
|
||||
var scaledStart highPrecisionTime
|
||||
var runningEnd bool
|
||||
runs := 0
|
||||
iters := 0
|
||||
firstBN := 0
|
||||
restBN := 0
|
||||
finalBN := 0
|
||||
bRet := Benchmark(func(b *B) {
|
||||
initialStart = b.start
|
||||
@ -18,8 +27,13 @@ func TestBenchmarkBLoop(t *T) {
|
||||
for b.Loop() {
|
||||
if iters == 0 {
|
||||
firstStart = b.start
|
||||
firstBN = b.N
|
||||
} else {
|
||||
restBN = max(restBN, b.N)
|
||||
}
|
||||
if iters == 1 {
|
||||
scaledStart = b.start
|
||||
}
|
||||
lastStart = b.start
|
||||
iters++
|
||||
}
|
||||
finalBN = b.N
|
||||
@ -37,6 +51,13 @@ func TestBenchmarkBLoop(t *T) {
|
||||
if finalBN != iters || bRet.N != iters {
|
||||
t.Errorf("benchmark iterations mismatch: %d loop iterations, final b.N=%d, bRet.N=%d", iters, finalBN, bRet.N)
|
||||
}
|
||||
// Verify that b.N was 0 inside the loop
|
||||
if firstBN != 0 {
|
||||
t.Errorf("want b.N == 0 on first iteration, got %d", firstBN)
|
||||
}
|
||||
if restBN != 0 {
|
||||
t.Errorf("want b.N == 0 on subsequent iterations, got %d", restBN)
|
||||
}
|
||||
// Make sure the benchmark ran for an appropriate amount of time.
|
||||
if bRet.T < benchTime.d {
|
||||
t.Fatalf("benchmark ran for %s, want >= %s", bRet.T, benchTime.d)
|
||||
@ -45,8 +66,8 @@ func TestBenchmarkBLoop(t *T) {
|
||||
if firstStart == initialStart {
|
||||
t.Errorf("b.Loop did not reset the timer")
|
||||
}
|
||||
if lastStart != firstStart {
|
||||
t.Errorf("timer was reset during iteration")
|
||||
if scaledStart != firstStart {
|
||||
t.Errorf("b.Loop stops and restarts the timer during iteration")
|
||||
}
|
||||
// Verify that it stopped the timer after the last loop.
|
||||
if runningEnd {
|
||||
@ -54,4 +75,80 @@ func TestBenchmarkBLoop(t *T) {
|
||||
}
|
||||
}
|
||||
|
||||
// See also TestBenchmarkBLoop* in other files.
|
||||
func TestBenchmarkBLoopBreak(t *T) {
|
||||
var bState *B
|
||||
var bLog bytes.Buffer
|
||||
bRet := Benchmark(func(b *B) {
|
||||
// The Benchmark function provides no access to the failure state and
|
||||
// discards the log, so capture the B and save its log.
|
||||
bState = b
|
||||
b.common.w = &bLog
|
||||
|
||||
for i := 0; b.Loop(); i++ {
|
||||
if i == 2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
if !bState.failed {
|
||||
t.Errorf("benchmark should have failed")
|
||||
}
|
||||
const wantLog = "benchmark function returned without B.Loop"
|
||||
if log := bLog.String(); !strings.Contains(log, wantLog) {
|
||||
t.Errorf("missing error %q in output:\n%s", wantLog, log)
|
||||
}
|
||||
// A benchmark that exits early should not report its target iteration count
|
||||
// because it's not meaningful.
|
||||
if bRet.N != 0 {
|
||||
t.Errorf("want N == 0, got %d", bRet.N)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBenchmarkBLoopError(t *T) {
|
||||
// Test that a benchmark that exits early because of an error doesn't *also*
|
||||
// complain that the benchmark exited early.
|
||||
var bState *B
|
||||
var bLog bytes.Buffer
|
||||
bRet := Benchmark(func(b *B) {
|
||||
bState = b
|
||||
b.common.w = &bLog
|
||||
|
||||
for i := 0; b.Loop(); i++ {
|
||||
b.Error("error")
|
||||
return
|
||||
}
|
||||
})
|
||||
if !bState.failed {
|
||||
t.Errorf("benchmark should have failed")
|
||||
}
|
||||
const noWantLog = "benchmark function returned without B.Loop"
|
||||
if log := bLog.String(); strings.Contains(log, noWantLog) {
|
||||
t.Errorf("unexpected error %q in output:\n%s", noWantLog, log)
|
||||
}
|
||||
if bRet.N != 0 {
|
||||
t.Errorf("want N == 0, got %d", bRet.N)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBenchmarkBLoopStop(t *T) {
|
||||
var bState *B
|
||||
var bLog bytes.Buffer
|
||||
bRet := Benchmark(func(b *B) {
|
||||
bState = b
|
||||
b.common.w = &bLog
|
||||
|
||||
for i := 0; b.Loop(); i++ {
|
||||
b.StopTimer()
|
||||
}
|
||||
})
|
||||
if !bState.failed {
|
||||
t.Errorf("benchmark should have failed")
|
||||
}
|
||||
const wantLog = "B.Loop called with timer stopped"
|
||||
if log := bLog.String(); !strings.Contains(log, wantLog) {
|
||||
t.Errorf("missing error %q in output:\n%s", wantLog, log)
|
||||
}
|
||||
if bRet.N != 0 {
|
||||
t.Errorf("want N == 0, got %d", bRet.N)
|
||||
}
|
||||
}
|
||||
|
10
src/vendor/golang.org/x/net/http/httpproxy/proxy.go
generated
vendored
10
src/vendor/golang.org/x/net/http/httpproxy/proxy.go
generated
vendored
@ -14,6 +14,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
@ -177,8 +178,10 @@ func (cfg *config) useProxy(addr string) bool {
|
||||
if host == "localhost" {
|
||||
return false
|
||||
}
|
||||
ip := net.ParseIP(host)
|
||||
if ip != nil {
|
||||
nip, err := netip.ParseAddr(host)
|
||||
var ip net.IP
|
||||
if err == nil {
|
||||
ip = net.IP(nip.AsSlice())
|
||||
if ip.IsLoopback() {
|
||||
return false
|
||||
}
|
||||
@ -360,6 +363,9 @@ type domainMatch struct {
|
||||
}
|
||||
|
||||
func (m domainMatch) match(host, port string, ip net.IP) bool {
|
||||
if ip != nil {
|
||||
return false
|
||||
}
|
||||
if strings.HasSuffix(host, m.host) || (m.matchHost && host == m.host[1:]) {
|
||||
return m.port == "" || m.port == port
|
||||
}
|
||||
|
2
src/vendor/modules.txt
vendored
2
src/vendor/modules.txt
vendored
@ -6,7 +6,7 @@ golang.org/x/crypto/cryptobyte
|
||||
golang.org/x/crypto/cryptobyte/asn1
|
||||
golang.org/x/crypto/internal/alias
|
||||
golang.org/x/crypto/internal/poly1305
|
||||
# golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98
|
||||
# golang.org/x/net v0.32.1-0.20250304185419-76f9bf3279ef
|
||||
## explicit; go 1.18
|
||||
golang.org/x/net/dns/dnsmessage
|
||||
golang.org/x/net/http/httpguts
|
||||
|
@ -56,6 +56,9 @@ import (
|
||||
// referenced object. Typically, this batching only happens for tiny
|
||||
// (on the order of 16 bytes or less) and pointer-free objects.
|
||||
type Pointer[T any] struct {
|
||||
// Mention T in the type definition to prevent conversions
|
||||
// between Pointer types, like we do for sync/atomic.Pointer.
|
||||
_ [0]*T
|
||||
u unsafe.Pointer
|
||||
}
|
||||
|
||||
@ -69,7 +72,7 @@ func Make[T any](ptr *T) Pointer[T] {
|
||||
u = runtime_registerWeakPointer(unsafe.Pointer(ptr))
|
||||
}
|
||||
runtime.KeepAlive(ptr)
|
||||
return Pointer[T]{u}
|
||||
return Pointer[T]{u: u}
|
||||
}
|
||||
|
||||
// Value returns the original pointer used to create the weak pointer.
|
||||
|
@ -6,10 +6,12 @@ package weak_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"internal/goarch"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
"unsafe"
|
||||
"weak"
|
||||
)
|
||||
|
||||
@ -155,6 +157,14 @@ func TestPointerFinalizer(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointerSize(t *testing.T) {
|
||||
var p weak.Pointer[T]
|
||||
size := unsafe.Sizeof(p)
|
||||
if size != goarch.PtrSize {
|
||||
t.Errorf("weak.Pointer[T] size = %d, want %d", size, goarch.PtrSize)
|
||||
}
|
||||
}
|
||||
|
||||
// Regression test for issue 69210.
|
||||
//
|
||||
// Weak-to-strong conversions must shade the new strong pointer, otherwise
|
||||
|
99
test/fixedbugs/issue71675.go
Normal file
99
test/fixedbugs/issue71675.go
Normal file
@ -0,0 +1,99 @@
|
||||
// run
|
||||
// Copyright 2025 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 i() {
|
||||
for range yieldInts {
|
||||
defer func() {
|
||||
println("I")
|
||||
recover()
|
||||
}()
|
||||
}
|
||||
// This panic causes dead code elimination of the return block.
|
||||
// The compiler should nonetheless emit a deferreturn.
|
||||
panic("i panic")
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func h() {
|
||||
defer func() {
|
||||
println("H first")
|
||||
}()
|
||||
for range yieldInts {
|
||||
defer func() {
|
||||
println("H second")
|
||||
}()
|
||||
}
|
||||
defer func() {
|
||||
println("H third")
|
||||
}()
|
||||
for range yieldIntsPanic {
|
||||
defer func() {
|
||||
println("h recover:called")
|
||||
recover()
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func yieldInts(yield func(int) bool) {
|
||||
if !yield(0) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func g() {
|
||||
defer func() {
|
||||
println("G first")
|
||||
}()
|
||||
for range yieldIntsPanic {
|
||||
defer func() {
|
||||
println("g recover:called")
|
||||
recover()
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func yieldIntsPanic(yield func(int) bool) {
|
||||
if !yield(0) {
|
||||
return
|
||||
}
|
||||
panic("yield stop")
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func next(i int) int {
|
||||
if i == 0 {
|
||||
panic("next stop")
|
||||
}
|
||||
return i + 1
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func f() {
|
||||
defer func() {
|
||||
println("F first")
|
||||
}()
|
||||
for i := 0; i < 1; i = next(i) {
|
||||
defer func() {
|
||||
println("f recover:called")
|
||||
recover()
|
||||
}()
|
||||
}
|
||||
}
|
||||
func main() {
|
||||
f()
|
||||
println("f returned")
|
||||
g()
|
||||
println("g returned")
|
||||
h()
|
||||
println("h returned")
|
||||
i()
|
||||
println("i returned")
|
||||
|
||||
}
|
13
test/fixedbugs/issue71675.out
Normal file
13
test/fixedbugs/issue71675.out
Normal file
@ -0,0 +1,13 @@
|
||||
f recover:called
|
||||
F first
|
||||
f returned
|
||||
g recover:called
|
||||
G first
|
||||
g returned
|
||||
h recover:called
|
||||
H third
|
||||
H second
|
||||
H first
|
||||
h returned
|
||||
I
|
||||
i returned
|
28
test/fixedbugs/issue71680.go
Normal file
28
test/fixedbugs/issue71680.go
Normal file
@ -0,0 +1,28 @@
|
||||
// compile
|
||||
|
||||
// Copyright 2025 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 p
|
||||
|
||||
type Parser struct{}
|
||||
type Node struct{}
|
||||
|
||||
type parserState func(p *Parser) parserState
|
||||
|
||||
func parserStateData(root *Node) parserState {
|
||||
return func(p *Parser) parserState {
|
||||
return parserStateOpenMap(root)(p)
|
||||
}
|
||||
}
|
||||
|
||||
func parserStateOpenMap(root *Node) parserState {
|
||||
return func(p *Parser) parserState {
|
||||
switch {
|
||||
case p != nil:
|
||||
return parserStateData(root)(p)
|
||||
}
|
||||
return parserStateOpenMap(root)(p)
|
||||
}
|
||||
}
|
23
test/fixedbugs/issue71852.go
Normal file
23
test/fixedbugs/issue71852.go
Normal file
@ -0,0 +1,23 @@
|
||||
// compile
|
||||
|
||||
// Copyright 2025 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 (
|
||||
"math"
|
||||
)
|
||||
|
||||
func main() {
|
||||
test(2)
|
||||
}
|
||||
|
||||
func test(i int) {
|
||||
if i <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
_ = math.Pow10(i + 2)
|
||||
}
|
29
test/fixedbugs/issue71857.go
Normal file
29
test/fixedbugs/issue71857.go
Normal file
@ -0,0 +1,29 @@
|
||||
// run
|
||||
|
||||
// Copyright 2025 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 "sync/atomic"
|
||||
|
||||
//go:noinline
|
||||
func f(p0, p1, p2, p3, p4, p5, p6, p7 *uint64, a *atomic.Uint64) {
|
||||
old := a.Or(0xaaa)
|
||||
*p0 = old
|
||||
*p1 = old
|
||||
*p2 = old
|
||||
*p3 = old
|
||||
*p4 = old
|
||||
*p5 = old
|
||||
*p6 = old
|
||||
*p7 = old
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := new(atomic.Uint64)
|
||||
p := new(uint64)
|
||||
f(p, p, p, p, p, p, p, p, a)
|
||||
|
||||
}
|
50
test/fixedbugs/issue71932.go
Normal file
50
test/fixedbugs/issue71932.go
Normal file
@ -0,0 +1,50 @@
|
||||
// run
|
||||
|
||||
// Copyright 2025 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 "runtime"
|
||||
|
||||
const C = 16
|
||||
|
||||
type T [C * C]byte
|
||||
|
||||
func main() {
|
||||
var ts []*T
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
t := new(T)
|
||||
// Save every even object.
|
||||
if i%2 == 0 {
|
||||
ts = append(ts, t)
|
||||
}
|
||||
}
|
||||
// Make sure the odd objects are collected.
|
||||
runtime.GC()
|
||||
|
||||
for _, t := range ts {
|
||||
f(t, C, C)
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func f(t *T, i, j uint) {
|
||||
if i == 0 || i > C || j == 0 || j > C {
|
||||
return // gets rid of bounds check below (via prove pass)
|
||||
}
|
||||
p := &t[i*j-1]
|
||||
*p = 0
|
||||
runtime.GC()
|
||||
*p = 0
|
||||
|
||||
// This goes badly if compiled to
|
||||
// q := &t[i*j]
|
||||
// *(q-1) = 0
|
||||
// runtime.GC()
|
||||
// *(q-1) = 0
|
||||
// as at the GC call, q is an invalid pointer
|
||||
// (it points past the end of t's allocation).
|
||||
}
|
40
test/fixedbugs/issue72063.go
Normal file
40
test/fixedbugs/issue72063.go
Normal file
@ -0,0 +1,40 @@
|
||||
// run
|
||||
|
||||
// Copyright 2025 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 "fmt"
|
||||
|
||||
// Y is the Y-combinator based on https://dreamsongs.com/Files/WhyOfY.pdf
|
||||
func Y[Endo ~func(RecFct) RecFct, RecFct ~func(T) R, T, R any](f Endo) RecFct {
|
||||
|
||||
type internal[RecFct ~func(T) R, T, R any] func(internal[RecFct, T, R]) RecFct
|
||||
|
||||
g := func(h internal[RecFct, T, R]) RecFct {
|
||||
return func(t T) R {
|
||||
return f(h(h))(t)
|
||||
}
|
||||
}
|
||||
return g(g)
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
fct := Y(func(r func(int) int) func(int) int {
|
||||
return func(n int) int {
|
||||
if n <= 0 {
|
||||
return 1
|
||||
}
|
||||
return n * r(n-1)
|
||||
}
|
||||
})
|
||||
|
||||
want := 3628800
|
||||
if got := fct(10); got != want {
|
||||
msg := fmt.Sprintf("unexpected result, got: %d, want: %d", got, want)
|
||||
panic(msg)
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user