mirror of
https://github.com/golang/go.git
synced 2026-02-04 09:55:06 +03:00
Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
324c3ace2d | ||
|
|
337dd75343 | ||
|
|
4a28cad666 | ||
|
|
090590fdcc | ||
|
|
25b4f40625 | ||
|
|
484535e67b | ||
|
|
813a811d33 | ||
|
|
ee42d468f5 | ||
|
|
446493f5b8 | ||
|
|
0684cecad5 | ||
|
|
ecf7e00db8 | ||
|
|
1dbbac7d79 | ||
|
|
99001c460e | ||
|
|
dcc9bdf380 | ||
|
|
5c7c20e262 | ||
|
|
7c47a6b157 | ||
|
|
20374d1d75 | ||
|
|
e7c4b07ecf | ||
|
|
bf8c7c575c | ||
|
|
ec18f62df5 | ||
|
|
ea6b5a64dd | ||
|
|
3991f6c41c | ||
|
|
9a164d1c41 | ||
|
|
8dce4ca8df | ||
|
|
94c02a3cc4 | ||
|
|
65fa8a6931 | ||
|
|
b52a6963bf | ||
|
|
3ff6dbdf5b | ||
|
|
fa42da156a | ||
|
|
5c7cc468a8 | ||
|
|
b852f39511 | ||
|
|
4df95d5145 | ||
|
|
aee9a19c55 | ||
|
|
26eeaec89c | ||
|
|
9629fa1874 | ||
|
|
3243f93747 | ||
|
|
d2d0ee2049 | ||
|
|
230765a11a | ||
|
|
bdd86bda09 | ||
|
|
aef8a8cd42 | ||
|
|
ef793801f8 | ||
|
|
aaace6dda7 | ||
|
|
0f4483cfdc | ||
|
|
1362737f50 | ||
|
|
602eeaab38 | ||
|
|
ac556f35a2 | ||
|
|
1acd39cc92 | ||
|
|
7b398b1ff7 | ||
|
|
2d01f3695b | ||
|
|
965e9ba0fb | ||
|
|
85ded85b78 | ||
|
|
828b05cc64 | ||
|
|
202a1a5706 | ||
|
|
8e02cffd8e | ||
|
|
5286ac4ed8 | ||
|
|
53b43607d9 | ||
|
|
bdf07c2e16 | ||
|
|
3a04b6e12e | ||
|
|
00f5d3001a | ||
|
|
7628627cb2 | ||
|
|
1fa2deb1b1 | ||
|
|
a943fd0ccc | ||
|
|
fbba58a0a4 | ||
|
|
9987cb6cf3 | ||
|
|
90b06002c4 | ||
|
|
487be3f90b | ||
|
|
7302f83d87 | ||
|
|
de4748c47c | ||
|
|
52bd3b186b | ||
|
|
be7e4fee4b | ||
|
|
b68d699aa7 | ||
|
|
10124c2631 | ||
|
|
5adb0ca8e9 | ||
|
|
8b34676710 | ||
|
|
d7c6da8bac | ||
|
|
9eed826bf9 | ||
|
|
670ce9b8a8 | ||
|
|
b3160e8bce | ||
|
|
9efc2e7f95 | ||
|
|
32593a9192 | ||
|
|
eb598248ba | ||
|
|
9f02342144 | ||
|
|
0480336414 |
@@ -1 +1,2 @@
|
||||
branch: master
|
||||
branch: release-branch.go1.20
|
||||
parent-branch: master
|
||||
|
||||
@@ -1200,9 +1200,8 @@ proxyHandler := &httputil.ReverseProxy{
|
||||
</p>
|
||||
|
||||
<p><!-- CL 444277 -->
|
||||
The <a href="/pkg/time/#Time.MarshalJSON"><code>Time.MarshalJSON</code></a> and
|
||||
<a href="/pkg/time/#Time.UnmarshalJSON"><code>Time.UnmarshalJSON</code></a> methods
|
||||
are now more strict about adherence to RFC 3339.
|
||||
The <a href="/pkg/time/#Time.MarshalJSON"><code>Time.MarshalJSON</code></a> method
|
||||
is now more strict about adherence to RFC 3339.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- time -->
|
||||
|
||||
@@ -1112,8 +1112,13 @@ func TestStd(t *testing.T) {
|
||||
t.Skip("skip in short mode")
|
||||
}
|
||||
t.Parallel()
|
||||
tmpDir := t.TempDir()
|
||||
// Use a temporary pkgdir to not interfere with other tests, and not write to GOROOT.
|
||||
// Cannot use goCmd as it runs with cloned GOROOT which is incomplete.
|
||||
runWithEnv(t, "building std", []string{"GOROOT=" + oldGOROOT},
|
||||
filepath.Join(oldGOROOT, "bin", "go"), "install", "-buildmode=shared", "-pkgdir="+t.TempDir(), "std")
|
||||
filepath.Join(oldGOROOT, "bin", "go"), "install", "-buildmode=shared", "-pkgdir="+tmpDir, "std")
|
||||
|
||||
// Issue #58966.
|
||||
runWithEnv(t, "testing issue #58966", []string{"GOROOT=" + oldGOROOT},
|
||||
filepath.Join(oldGOROOT, "bin", "go"), "run", "-linkshared", "-pkgdir="+tmpDir, "./issue58966/main.go")
|
||||
}
|
||||
|
||||
15
misc/cgo/testshared/testdata/issue58966/main.go
vendored
Normal file
15
misc/cgo/testshared/testdata/issue58966/main.go
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright 2023 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 "crypto/elliptic"
|
||||
|
||||
var curve elliptic.Curve
|
||||
|
||||
func main() {
|
||||
switch curve {
|
||||
case elliptic.P224():
|
||||
}
|
||||
}
|
||||
@@ -167,7 +167,7 @@ func ParseFlags() {
|
||||
|
||||
Debug.ConcurrentOk = true
|
||||
Debug.InlFuncsWithClosures = 1
|
||||
Debug.InlStaticInit = 1
|
||||
Debug.InlStaticInit = 0
|
||||
if buildcfg.Experiment.Unified {
|
||||
Debug.Unified = 1
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ func (e *escape) call(ks []hole, call ir.Node) {
|
||||
var init ir.Nodes
|
||||
e.callCommon(ks, call, &init, nil)
|
||||
if len(init) != 0 {
|
||||
call.(*ir.CallExpr).PtrInit().Append(init...)
|
||||
call.(ir.InitNode).PtrInit().Append(init...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,18 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
argumentFunc(nil, k, argp)
|
||||
}
|
||||
|
||||
argumentRType := func(rtypep *ir.Node) {
|
||||
rtype := *rtypep
|
||||
if rtype == nil {
|
||||
return
|
||||
}
|
||||
// common case: static rtype/itab argument, which can be evaluated within the wrapper instead.
|
||||
if addr, ok := rtype.(*ir.AddrExpr); ok && addr.Op() == ir.OADDR && addr.X.Op() == ir.OLINKSYMOFFSET {
|
||||
return
|
||||
}
|
||||
e.wrapExpr(rtype.Pos(), rtypep, init, call, wrapper)
|
||||
}
|
||||
|
||||
switch call.Op() {
|
||||
default:
|
||||
ir.Dump("esc", call)
|
||||
@@ -153,6 +165,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
argument(e.heapHole(), &args[i])
|
||||
}
|
||||
}
|
||||
argumentRType(&call.RType)
|
||||
|
||||
case ir.OCOPY:
|
||||
call := call.(*ir.BinaryExpr)
|
||||
@@ -163,6 +176,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
copiedK = e.heapHole().deref(call, "copied slice")
|
||||
}
|
||||
argument(copiedK, &call.Y)
|
||||
argumentRType(&call.RType)
|
||||
|
||||
case ir.OPANIC:
|
||||
call := call.(*ir.UnaryExpr)
|
||||
@@ -179,15 +193,21 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
for i := range call.Args {
|
||||
argument(e.discardHole(), &call.Args[i])
|
||||
}
|
||||
argumentRType(&call.RType)
|
||||
|
||||
case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
|
||||
case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
|
||||
call := call.(*ir.UnaryExpr)
|
||||
argument(e.discardHole(), &call.X)
|
||||
|
||||
case ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
|
||||
call := call.(*ir.UnaryExpr)
|
||||
argument(ks[0], &call.X)
|
||||
|
||||
case ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
|
||||
call := call.(*ir.BinaryExpr)
|
||||
argument(ks[0], &call.X)
|
||||
argument(e.discardHole(), &call.Y)
|
||||
argumentRType(&call.RType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,8 +39,9 @@ func lookupGorootExport(pkgDir string) (string, bool) {
|
||||
)
|
||||
f, _ = exportMap.LoadOrStore(pkgDir, func() (string, bool) {
|
||||
listOnce.Do(func() {
|
||||
cmd := exec.Command("go", "list", "-export", "-f", "{{.Export}}", pkgDir)
|
||||
cmd := exec.Command(filepath.Join(build.Default.GOROOT, "bin", "go"), "list", "-export", "-f", "{{.Export}}", pkgDir)
|
||||
cmd.Dir = build.Default.GOROOT
|
||||
cmd.Env = append(os.Environ(), "PWD="+cmd.Dir, "GOROOT="+build.Default.GOROOT)
|
||||
var output []byte
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
|
||||
@@ -959,6 +959,11 @@ func reassigned(name *Name) bool {
|
||||
if isName(OuterValue(n.X)) {
|
||||
return true
|
||||
}
|
||||
case ORANGE:
|
||||
n := n.(*RangeStmt)
|
||||
if isName(n.Key) || isName(n.Value) {
|
||||
return true
|
||||
}
|
||||
case OCLOSURE:
|
||||
n := n.(*ClosureExpr)
|
||||
if Any(n.Func, do) {
|
||||
|
||||
@@ -147,9 +147,10 @@ func NewFunc(pos src.XPos) *Func {
|
||||
|
||||
func (f *Func) isStmt() {}
|
||||
|
||||
func (n *Func) copy() Node { panic(n.no("copy")) }
|
||||
func (n *Func) doChildren(do func(Node) bool) bool { return doNodes(n.Body, do) }
|
||||
func (n *Func) editChildren(edit func(Node) Node) { editNodes(n.Body, edit) }
|
||||
func (n *Func) copy() Node { panic(n.no("copy")) }
|
||||
func (n *Func) doChildren(do func(Node) bool) bool { return doNodes(n.Body, do) }
|
||||
func (n *Func) editChildren(edit func(Node) Node) { editNodes(n.Body, edit) }
|
||||
func (n *Func) editChildrenWithHidden(edit func(Node) Node) { editNodes(n.Body, edit) }
|
||||
|
||||
func (f *Func) Type() *types.Type { return f.Nname.Type() }
|
||||
func (f *Func) Sym() *types.Sym { return f.Nname.Sym() }
|
||||
|
||||
@@ -256,18 +256,24 @@ func processType(t *ast.TypeSpec) {
|
||||
var copyBody strings.Builder
|
||||
var doChildrenBody strings.Builder
|
||||
var editChildrenBody strings.Builder
|
||||
var editChildrenWithHiddenBody strings.Builder
|
||||
for _, f := range fields {
|
||||
names := f.Names
|
||||
ft := f.Type
|
||||
hidden := false
|
||||
if f.Tag != nil {
|
||||
tag := f.Tag.Value[1 : len(f.Tag.Value)-1]
|
||||
if strings.HasPrefix(tag, "mknode:") {
|
||||
if tag[7:] == "\"-\"" {
|
||||
continue
|
||||
if !isNamedType(ft, "Node") {
|
||||
continue
|
||||
}
|
||||
hidden = true
|
||||
} else {
|
||||
panic(fmt.Sprintf("unexpected tag value: %s", tag))
|
||||
}
|
||||
panic(fmt.Sprintf("unexpected tag value: %s", tag))
|
||||
}
|
||||
}
|
||||
names := f.Names
|
||||
ft := f.Type
|
||||
if isNamedType(ft, "Nodes") {
|
||||
// Nodes == []Node
|
||||
ft = &ast.ArrayType{Elt: &ast.Ident{Name: "Node"}}
|
||||
@@ -286,6 +292,20 @@ func processType(t *ast.TypeSpec) {
|
||||
continue
|
||||
}
|
||||
for _, name := range names {
|
||||
ptr := ""
|
||||
if isPtr {
|
||||
ptr = "*"
|
||||
}
|
||||
if isSlice {
|
||||
fmt.Fprintf(&editChildrenWithHiddenBody,
|
||||
"edit%ss(n.%s, edit)\n", ft, name)
|
||||
} else {
|
||||
fmt.Fprintf(&editChildrenWithHiddenBody,
|
||||
"if n.%s != nil {\nn.%s = edit(n.%s).(%s%s)\n}\n", name, name, name, ptr, ft)
|
||||
}
|
||||
if hidden {
|
||||
continue
|
||||
}
|
||||
if isSlice {
|
||||
fmt.Fprintf(©Body, "c.%s = copy%ss(c.%s)\n", name, ft, name)
|
||||
fmt.Fprintf(&doChildrenBody,
|
||||
@@ -295,10 +315,6 @@ func processType(t *ast.TypeSpec) {
|
||||
} else {
|
||||
fmt.Fprintf(&doChildrenBody,
|
||||
"if n.%s != nil && do(n.%s) {\nreturn true\n}\n", name, name)
|
||||
ptr := ""
|
||||
if isPtr {
|
||||
ptr = "*"
|
||||
}
|
||||
fmt.Fprintf(&editChildrenBody,
|
||||
"if n.%s != nil {\nn.%s = edit(n.%s).(%s%s)\n}\n", name, name, name, ptr, ft)
|
||||
}
|
||||
@@ -313,6 +329,9 @@ func processType(t *ast.TypeSpec) {
|
||||
fmt.Fprintf(&buf, "func (n *%s) editChildren(edit func(Node) Node) {\n", name)
|
||||
buf.WriteString(editChildrenBody.String())
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
fmt.Fprintf(&buf, "func (n *%s) editChildrenWithHidden(edit func(Node) Node) {\n", name)
|
||||
buf.WriteString(editChildrenWithHiddenBody.String())
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
}
|
||||
|
||||
func generateHelpers() {
|
||||
|
||||
@@ -134,9 +134,10 @@ type Name struct {
|
||||
|
||||
func (n *Name) isExpr() {}
|
||||
|
||||
func (n *Name) copy() Node { panic(n.no("copy")) }
|
||||
func (n *Name) doChildren(do func(Node) bool) bool { return false }
|
||||
func (n *Name) editChildren(edit func(Node) Node) {}
|
||||
func (n *Name) copy() Node { panic(n.no("copy")) }
|
||||
func (n *Name) doChildren(do func(Node) bool) bool { return false }
|
||||
func (n *Name) editChildren(edit func(Node) Node) {}
|
||||
func (n *Name) editChildrenWithHidden(edit func(Node) Node) {}
|
||||
|
||||
// RecordFrameOffset records the frame offset for the name.
|
||||
// It is used by package types when laying out function arguments.
|
||||
|
||||
@@ -30,6 +30,7 @@ type Node interface {
|
||||
|
||||
doChildren(func(Node) bool) bool
|
||||
editChildren(func(Node) Node)
|
||||
editChildrenWithHidden(func(Node) Node)
|
||||
|
||||
// Abstract graph structure, for generic traversals.
|
||||
Op() Op
|
||||
@@ -290,7 +291,7 @@ const (
|
||||
OEFACE // itable and data words of an empty-interface value.
|
||||
OITAB // itable word of an interface value.
|
||||
OIDATA // data word of an interface value in X
|
||||
OSPTR // base pointer of a slice or string.
|
||||
OSPTR // base pointer of a slice or string. Bounded==1 means known non-nil.
|
||||
OCFUNC // reference to c function pointer (not go func value)
|
||||
OCHECKNIL // emit code to ensure pointer/interface not nil
|
||||
ORESULT // result of a function call; Xoffset is stack offset
|
||||
|
||||
@@ -30,6 +30,13 @@ func (n *AddStringExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *AddStringExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.List, edit)
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *AddrExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *AddrExpr) copy() Node {
|
||||
@@ -58,6 +65,15 @@ func (n *AddrExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *AddrExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *AssignListStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *AssignListStmt) copy() Node {
|
||||
@@ -84,6 +100,11 @@ func (n *AssignListStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.Lhs, edit)
|
||||
editNodes(n.Rhs, edit)
|
||||
}
|
||||
func (n *AssignListStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.Lhs, edit)
|
||||
editNodes(n.Rhs, edit)
|
||||
}
|
||||
|
||||
func (n *AssignOpStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *AssignOpStmt) copy() Node {
|
||||
@@ -112,6 +133,15 @@ func (n *AssignOpStmt) editChildren(edit func(Node) Node) {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
func (n *AssignOpStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Y != nil {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *AssignStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *AssignStmt) copy() Node {
|
||||
@@ -140,6 +170,15 @@ func (n *AssignStmt) editChildren(edit func(Node) Node) {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
func (n *AssignStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Y != nil {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *BasicLit) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *BasicLit) copy() Node {
|
||||
@@ -156,6 +195,9 @@ func (n *BasicLit) doChildren(do func(Node) bool) bool {
|
||||
func (n *BasicLit) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *BasicLit) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *BinaryExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *BinaryExpr) copy() Node {
|
||||
@@ -184,6 +226,18 @@ func (n *BinaryExpr) editChildren(edit func(Node) Node) {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
func (n *BinaryExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Y != nil {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *BlockStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *BlockStmt) copy() Node {
|
||||
@@ -205,6 +259,10 @@ func (n *BlockStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.List, edit)
|
||||
}
|
||||
func (n *BlockStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.List, edit)
|
||||
}
|
||||
|
||||
func (n *BranchStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *BranchStmt) copy() Node {
|
||||
@@ -221,6 +279,9 @@ func (n *BranchStmt) doChildren(do func(Node) bool) bool {
|
||||
func (n *BranchStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *BranchStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *CallExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *CallExpr) copy() Node {
|
||||
@@ -253,6 +314,17 @@ func (n *CallExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.Args, edit)
|
||||
editNames(n.KeepAlive, edit)
|
||||
}
|
||||
func (n *CallExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
editNodes(n.Args, edit)
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
editNames(n.KeepAlive, edit)
|
||||
}
|
||||
|
||||
func (n *CaseClause) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *CaseClause) copy() Node {
|
||||
@@ -290,6 +362,15 @@ func (n *CaseClause) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.RTypes, edit)
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
func (n *CaseClause) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Var != nil {
|
||||
n.Var = edit(n.Var).(*Name)
|
||||
}
|
||||
editNodes(n.List, edit)
|
||||
editNodes(n.RTypes, edit)
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
|
||||
func (n *ClosureExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ClosureExpr) copy() Node {
|
||||
@@ -312,6 +393,12 @@ func (n *ClosureExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *ClosureExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *CommClause) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *CommClause) copy() Node {
|
||||
@@ -339,6 +426,13 @@ func (n *CommClause) editChildren(edit func(Node) Node) {
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
func (n *CommClause) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Comm != nil {
|
||||
n.Comm = edit(n.Comm).(Node)
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
|
||||
func (n *CompLitExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *CompLitExpr) copy() Node {
|
||||
@@ -366,6 +460,16 @@ func (n *CompLitExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *CompLitExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.List, edit)
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *ConstExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ConstExpr) copy() Node {
|
||||
@@ -382,6 +486,9 @@ func (n *ConstExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *ConstExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *ConstExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *ConvExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ConvExpr) copy() Node {
|
||||
@@ -404,6 +511,24 @@ func (n *ConvExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *ConvExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.TypeWord != nil {
|
||||
n.TypeWord = edit(n.TypeWord).(Node)
|
||||
}
|
||||
if n.SrcRType != nil {
|
||||
n.SrcRType = edit(n.SrcRType).(Node)
|
||||
}
|
||||
if n.ElemRType != nil {
|
||||
n.ElemRType = edit(n.ElemRType).(Node)
|
||||
}
|
||||
if n.ElemElemRType != nil {
|
||||
n.ElemElemRType = edit(n.ElemElemRType).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Decl) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *Decl) copy() Node {
|
||||
@@ -421,6 +546,11 @@ func (n *Decl) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *Decl) editChildrenWithHidden(edit func(Node) Node) {
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *DynamicType) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *DynamicType) copy() Node {
|
||||
@@ -449,6 +579,15 @@ func (n *DynamicType) editChildren(edit func(Node) Node) {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
func (n *DynamicType) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.ITab != nil {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *DynamicTypeAssertExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *DynamicTypeAssertExpr) copy() Node {
|
||||
@@ -489,6 +628,21 @@ func (n *DynamicTypeAssertExpr) editChildren(edit func(Node) Node) {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
func (n *DynamicTypeAssertExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.SrcRType != nil {
|
||||
n.SrcRType = edit(n.SrcRType).(Node)
|
||||
}
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.ITab != nil {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *ForStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ForStmt) copy() Node {
|
||||
@@ -522,6 +676,16 @@ func (n *ForStmt) editChildren(edit func(Node) Node) {
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
func (n *ForStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Cond != nil {
|
||||
n.Cond = edit(n.Cond).(Node)
|
||||
}
|
||||
if n.Post != nil {
|
||||
n.Post = edit(n.Post).(Node)
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
}
|
||||
|
||||
func (n *Func) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
|
||||
@@ -546,6 +710,12 @@ func (n *GoDeferStmt) editChildren(edit func(Node) Node) {
|
||||
n.Call = edit(n.Call).(Node)
|
||||
}
|
||||
}
|
||||
func (n *GoDeferStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Call != nil {
|
||||
n.Call = edit(n.Call).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Ident) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *Ident) copy() Node {
|
||||
@@ -562,6 +732,9 @@ func (n *Ident) doChildren(do func(Node) bool) bool {
|
||||
func (n *Ident) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *Ident) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *IfStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *IfStmt) copy() Node {
|
||||
@@ -594,6 +767,14 @@ func (n *IfStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.Body, edit)
|
||||
editNodes(n.Else, edit)
|
||||
}
|
||||
func (n *IfStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Cond != nil {
|
||||
n.Cond = edit(n.Cond).(Node)
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
editNodes(n.Else, edit)
|
||||
}
|
||||
|
||||
func (n *IndexExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *IndexExpr) copy() Node {
|
||||
@@ -622,6 +803,18 @@ func (n *IndexExpr) editChildren(edit func(Node) Node) {
|
||||
n.Index = edit(n.Index).(Node)
|
||||
}
|
||||
}
|
||||
func (n *IndexExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Index != nil {
|
||||
n.Index = edit(n.Index).(Node)
|
||||
}
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *InlineMarkStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *InlineMarkStmt) copy() Node {
|
||||
@@ -638,6 +831,9 @@ func (n *InlineMarkStmt) doChildren(do func(Node) bool) bool {
|
||||
func (n *InlineMarkStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *InlineMarkStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *InlinedCallExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *InlinedCallExpr) copy() Node {
|
||||
@@ -664,6 +860,11 @@ func (n *InlinedCallExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.Body, edit)
|
||||
editNodes(n.ReturnVars, edit)
|
||||
}
|
||||
func (n *InlinedCallExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.Body, edit)
|
||||
editNodes(n.ReturnVars, edit)
|
||||
}
|
||||
|
||||
func (n *InstExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *InstExpr) copy() Node {
|
||||
@@ -691,6 +892,13 @@ func (n *InstExpr) editChildren(edit func(Node) Node) {
|
||||
}
|
||||
editNtypes(n.Targs, edit)
|
||||
}
|
||||
func (n *InstExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
editNtypes(n.Targs, edit)
|
||||
}
|
||||
|
||||
func (n *JumpTableStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *JumpTableStmt) copy() Node {
|
||||
@@ -713,6 +921,12 @@ func (n *JumpTableStmt) editChildren(edit func(Node) Node) {
|
||||
n.Idx = edit(n.Idx).(Node)
|
||||
}
|
||||
}
|
||||
func (n *JumpTableStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Idx != nil {
|
||||
n.Idx = edit(n.Idx).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *KeyExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *KeyExpr) copy() Node {
|
||||
@@ -741,6 +955,15 @@ func (n *KeyExpr) editChildren(edit func(Node) Node) {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
func (n *KeyExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Key != nil {
|
||||
n.Key = edit(n.Key).(Node)
|
||||
}
|
||||
if n.Value != nil {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *LabelStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *LabelStmt) copy() Node {
|
||||
@@ -757,6 +980,9 @@ func (n *LabelStmt) doChildren(do func(Node) bool) bool {
|
||||
func (n *LabelStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *LabelStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *LinksymOffsetExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *LinksymOffsetExpr) copy() Node {
|
||||
@@ -773,6 +999,9 @@ func (n *LinksymOffsetExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *LinksymOffsetExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *LinksymOffsetExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *LogicalExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *LogicalExpr) copy() Node {
|
||||
@@ -801,6 +1030,15 @@ func (n *LogicalExpr) editChildren(edit func(Node) Node) {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
func (n *LogicalExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Y != nil {
|
||||
n.Y = edit(n.Y).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *MakeExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *MakeExpr) copy() Node {
|
||||
@@ -829,6 +1067,18 @@ func (n *MakeExpr) editChildren(edit func(Node) Node) {
|
||||
n.Cap = edit(n.Cap).(Node)
|
||||
}
|
||||
}
|
||||
func (n *MakeExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.Len != nil {
|
||||
n.Len = edit(n.Len).(Node)
|
||||
}
|
||||
if n.Cap != nil {
|
||||
n.Cap = edit(n.Cap).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Name) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
|
||||
@@ -847,6 +1097,9 @@ func (n *NilExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *NilExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *NilExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *ParenExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ParenExpr) copy() Node {
|
||||
@@ -869,6 +1122,12 @@ func (n *ParenExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *ParenExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *RangeStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *RangeStmt) copy() Node {
|
||||
@@ -914,6 +1173,37 @@ func (n *RangeStmt) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *RangeStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.RType != nil {
|
||||
n.RType = edit(n.RType).(Node)
|
||||
}
|
||||
if n.Key != nil {
|
||||
n.Key = edit(n.Key).(Node)
|
||||
}
|
||||
if n.Value != nil {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
editNodes(n.Body, edit)
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
if n.KeyTypeWord != nil {
|
||||
n.KeyTypeWord = edit(n.KeyTypeWord).(Node)
|
||||
}
|
||||
if n.KeySrcRType != nil {
|
||||
n.KeySrcRType = edit(n.KeySrcRType).(Node)
|
||||
}
|
||||
if n.ValueTypeWord != nil {
|
||||
n.ValueTypeWord = edit(n.ValueTypeWord).(Node)
|
||||
}
|
||||
if n.ValueSrcRType != nil {
|
||||
n.ValueSrcRType = edit(n.ValueSrcRType).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *RawOrigExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *RawOrigExpr) copy() Node {
|
||||
@@ -930,6 +1220,9 @@ func (n *RawOrigExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *RawOrigExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *RawOrigExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *ResultExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ResultExpr) copy() Node {
|
||||
@@ -946,6 +1239,9 @@ func (n *ResultExpr) doChildren(do func(Node) bool) bool {
|
||||
func (n *ResultExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
func (n *ResultExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *ReturnStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *ReturnStmt) copy() Node {
|
||||
@@ -967,6 +1263,10 @@ func (n *ReturnStmt) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.Results, edit)
|
||||
}
|
||||
func (n *ReturnStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editNodes(n.Results, edit)
|
||||
}
|
||||
|
||||
func (n *SelectStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SelectStmt) copy() Node {
|
||||
@@ -993,6 +1293,11 @@ func (n *SelectStmt) editChildren(edit func(Node) Node) {
|
||||
editCommClauses(n.Cases, edit)
|
||||
editNodes(n.Compiled, edit)
|
||||
}
|
||||
func (n *SelectStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
editCommClauses(n.Cases, edit)
|
||||
editNodes(n.Compiled, edit)
|
||||
}
|
||||
|
||||
func (n *SelectorExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SelectorExpr) copy() Node {
|
||||
@@ -1021,6 +1326,15 @@ func (n *SelectorExpr) editChildren(edit func(Node) Node) {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
func (n *SelectorExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Prealloc != nil {
|
||||
n.Prealloc = edit(n.Prealloc).(*Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SendStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SendStmt) copy() Node {
|
||||
@@ -1049,6 +1363,15 @@ func (n *SendStmt) editChildren(edit func(Node) Node) {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
func (n *SendStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Chan != nil {
|
||||
n.Chan = edit(n.Chan).(Node)
|
||||
}
|
||||
if n.Value != nil {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SliceExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SliceExpr) copy() Node {
|
||||
@@ -1089,6 +1412,21 @@ func (n *SliceExpr) editChildren(edit func(Node) Node) {
|
||||
n.Max = edit(n.Max).(Node)
|
||||
}
|
||||
}
|
||||
func (n *SliceExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.Low != nil {
|
||||
n.Low = edit(n.Low).(Node)
|
||||
}
|
||||
if n.High != nil {
|
||||
n.High = edit(n.High).(Node)
|
||||
}
|
||||
if n.Max != nil {
|
||||
n.Max = edit(n.Max).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SliceHeaderExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SliceHeaderExpr) copy() Node {
|
||||
@@ -1123,6 +1461,18 @@ func (n *SliceHeaderExpr) editChildren(edit func(Node) Node) {
|
||||
n.Cap = edit(n.Cap).(Node)
|
||||
}
|
||||
}
|
||||
func (n *SliceHeaderExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Ptr != nil {
|
||||
n.Ptr = edit(n.Ptr).(Node)
|
||||
}
|
||||
if n.Len != nil {
|
||||
n.Len = edit(n.Len).(Node)
|
||||
}
|
||||
if n.Cap != nil {
|
||||
n.Cap = edit(n.Cap).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *StarExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *StarExpr) copy() Node {
|
||||
@@ -1145,6 +1495,12 @@ func (n *StarExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *StarExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *StringHeaderExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *StringHeaderExpr) copy() Node {
|
||||
@@ -1173,6 +1529,15 @@ func (n *StringHeaderExpr) editChildren(edit func(Node) Node) {
|
||||
n.Len = edit(n.Len).(Node)
|
||||
}
|
||||
}
|
||||
func (n *StringHeaderExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Ptr != nil {
|
||||
n.Ptr = edit(n.Ptr).(Node)
|
||||
}
|
||||
if n.Len != nil {
|
||||
n.Len = edit(n.Len).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *StructKeyExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *StructKeyExpr) copy() Node {
|
||||
@@ -1195,6 +1560,12 @@ func (n *StructKeyExpr) editChildren(edit func(Node) Node) {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
func (n *StructKeyExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Value != nil {
|
||||
n.Value = edit(n.Value).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SwitchStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *SwitchStmt) copy() Node {
|
||||
@@ -1227,6 +1598,14 @@ func (n *SwitchStmt) editChildren(edit func(Node) Node) {
|
||||
editCaseClauses(n.Cases, edit)
|
||||
editNodes(n.Compiled, edit)
|
||||
}
|
||||
func (n *SwitchStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Tag != nil {
|
||||
n.Tag = edit(n.Tag).(Node)
|
||||
}
|
||||
editCaseClauses(n.Cases, edit)
|
||||
editNodes(n.Compiled, edit)
|
||||
}
|
||||
|
||||
func (n *TailCallStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *TailCallStmt) copy() Node {
|
||||
@@ -1249,6 +1628,12 @@ func (n *TailCallStmt) editChildren(edit func(Node) Node) {
|
||||
n.Call = edit(n.Call).(*CallExpr)
|
||||
}
|
||||
}
|
||||
func (n *TailCallStmt) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Call != nil {
|
||||
n.Call = edit(n.Call).(*CallExpr)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *TypeAssertExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *TypeAssertExpr) copy() Node {
|
||||
@@ -1271,6 +1656,15 @@ func (n *TypeAssertExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *TypeAssertExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
if n.ITab != nil {
|
||||
n.ITab = edit(n.ITab).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *TypeSwitchGuard) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *TypeSwitchGuard) copy() Node {
|
||||
@@ -1294,6 +1688,14 @@ func (n *TypeSwitchGuard) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *TypeSwitchGuard) editChildrenWithHidden(edit func(Node) Node) {
|
||||
if n.Tag != nil {
|
||||
n.Tag = edit(n.Tag).(*Ident)
|
||||
}
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *UnaryExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *UnaryExpr) copy() Node {
|
||||
@@ -1316,6 +1718,12 @@ func (n *UnaryExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
func (n *UnaryExpr) editChildrenWithHidden(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.X != nil {
|
||||
n.X = edit(n.X).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *typeNode) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *typeNode) copy() Node {
|
||||
@@ -1327,6 +1735,8 @@ func (n *typeNode) doChildren(do func(Node) bool) bool {
|
||||
}
|
||||
func (n *typeNode) editChildren(edit func(Node) Node) {
|
||||
}
|
||||
func (n *typeNode) editChildrenWithHidden(edit func(Node) Node) {
|
||||
}
|
||||
|
||||
func copyCaseClauses(list []*CaseClause) []*CaseClause {
|
||||
if list == nil {
|
||||
|
||||
@@ -184,3 +184,15 @@ func EditChildren(n Node, edit func(Node) Node) {
|
||||
}
|
||||
n.editChildren(edit)
|
||||
}
|
||||
|
||||
// EditChildrenWithHidden is like EditChildren, but also edits
|
||||
// Node-typed fields tagged with `mknode:"-"`.
|
||||
//
|
||||
// TODO(mdempsky): Remove the `mknode:"-"` tags so this function can
|
||||
// go away.
|
||||
func EditChildrenWithHidden(n Node, edit func(Node) Node) {
|
||||
if n == nil {
|
||||
return
|
||||
}
|
||||
n.editChildrenWithHidden(edit)
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ func (l *linker) relocObj(pr *pkgReader, idx pkgbits.Index) pkgbits.Index {
|
||||
l.exportBody(obj, local)
|
||||
}
|
||||
|
||||
if obj.Op() == ir.OTYPE {
|
||||
if obj.Op() == ir.OTYPE && !obj.Alias() {
|
||||
if typ := obj.Type(); !typ.IsInterface() {
|
||||
for _, method := range typ.Methods().Slice() {
|
||||
l.exportBody(method.Nname.(*ir.Name), local)
|
||||
|
||||
@@ -231,6 +231,16 @@ func (r *reader) pos() src.XPos {
|
||||
return base.Ctxt.PosTable.XPos(r.pos0())
|
||||
}
|
||||
|
||||
// origPos reads a position from the bitstream, and returns both the
|
||||
// original raw position and an inlining-adjusted position.
|
||||
func (r *reader) origPos() (origPos, inlPos src.XPos) {
|
||||
r.suppressInlPos++
|
||||
origPos = r.pos()
|
||||
r.suppressInlPos--
|
||||
inlPos = r.inlPos(origPos)
|
||||
return
|
||||
}
|
||||
|
||||
func (r *reader) pos0() src.Pos {
|
||||
r.Sync(pkgbits.SyncPos)
|
||||
if !r.Bool() {
|
||||
@@ -517,13 +527,33 @@ func (r *reader) doTyp() *types.Type {
|
||||
}
|
||||
|
||||
func (r *reader) unionType() *types.Type {
|
||||
terms := make([]*types.Type, r.Len())
|
||||
tildes := make([]bool, len(terms))
|
||||
for i := range terms {
|
||||
tildes[i] = r.Bool()
|
||||
terms[i] = r.typ()
|
||||
// In the types1 universe, we only need to handle value types.
|
||||
// Impure interfaces (i.e., interfaces with non-trivial type sets
|
||||
// like "int | string") can only appear as type parameter bounds,
|
||||
// and this is enforced by the types2 type checker.
|
||||
//
|
||||
// However, type unions can still appear in pure interfaces if the
|
||||
// type union is equivalent to "any". E.g., typeparam/issue52124.go
|
||||
// declares variables with the type "interface { any | int }".
|
||||
//
|
||||
// To avoid needing to represent type unions in types1 (since we
|
||||
// don't have any uses for that today anyway), we simply fold them
|
||||
// to "any". As a consistency check, we still read the union terms
|
||||
// to make sure this substitution is safe.
|
||||
|
||||
pure := false
|
||||
for i, n := 0, r.Len(); i < n; i++ {
|
||||
_ = r.Bool() // tilde
|
||||
term := r.typ()
|
||||
if term.IsEmptyInterface() {
|
||||
pure = true
|
||||
}
|
||||
}
|
||||
return types.NewUnion(terms, tildes)
|
||||
if !pure {
|
||||
base.Fatalf("impure type set used in value type")
|
||||
}
|
||||
|
||||
return types.Types[types.TINTER]
|
||||
}
|
||||
|
||||
func (r *reader) interfaceType() *types.Type {
|
||||
@@ -2097,12 +2127,12 @@ func (r *reader) expr() (res ir.Node) {
|
||||
return typecheck.Callee(r.obj())
|
||||
|
||||
case exprFuncInst:
|
||||
pos := r.pos()
|
||||
origPos, pos := r.origPos()
|
||||
wrapperFn, baseFn, dictPtr := r.funcInst(pos)
|
||||
if wrapperFn != nil {
|
||||
return wrapperFn
|
||||
}
|
||||
return r.curry(pos, false, baseFn, dictPtr, nil)
|
||||
return r.curry(origPos, false, baseFn, dictPtr, nil)
|
||||
|
||||
case exprConst:
|
||||
pos := r.pos()
|
||||
@@ -2132,7 +2162,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
|
||||
case exprMethodVal:
|
||||
recv := r.expr()
|
||||
pos := r.pos()
|
||||
origPos, pos := r.origPos()
|
||||
wrapperFn, baseFn, dictPtr := r.methodExpr()
|
||||
|
||||
// For simple wrapperFn values, the existing machinery for creating
|
||||
@@ -2164,7 +2194,18 @@ func (r *reader) expr() (res ir.Node) {
|
||||
}
|
||||
|
||||
n := typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, recv, wrapperFn.Sel)).(*ir.SelectorExpr)
|
||||
assert(n.Selection == wrapperFn.Selection)
|
||||
|
||||
// As a consistency check here, we make sure "n" selected the
|
||||
// same method (represented by a types.Field) that wrapperFn
|
||||
// selected. However, for anonymous receiver types, there can be
|
||||
// multiple such types.Field instances (#58563). So we may need
|
||||
// to fallback to making sure Sym and Type (including the
|
||||
// receiver parameter's type) match.
|
||||
if n.Selection != wrapperFn.Selection {
|
||||
assert(n.Selection.Sym == wrapperFn.Selection.Sym)
|
||||
assert(types.Identical(n.Selection.Type, wrapperFn.Selection.Type))
|
||||
assert(types.Identical(n.Selection.Type.Recv().Type, wrapperFn.Selection.Type.Recv().Type))
|
||||
}
|
||||
|
||||
wrapper := methodValueWrapper{
|
||||
rcvr: n.X.Type(),
|
||||
@@ -2181,7 +2222,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
|
||||
// For more complicated method expressions, we construct a
|
||||
// function literal wrapper.
|
||||
return r.curry(pos, true, baseFn, recv, dictPtr)
|
||||
return r.curry(origPos, true, baseFn, recv, dictPtr)
|
||||
|
||||
case exprMethodExpr:
|
||||
recv := r.typ()
|
||||
@@ -2197,7 +2238,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
addr = true
|
||||
}
|
||||
|
||||
pos := r.pos()
|
||||
origPos, pos := r.origPos()
|
||||
wrapperFn, baseFn, dictPtr := r.methodExpr()
|
||||
|
||||
// If we already have a wrapper and don't need to do anything with
|
||||
@@ -2220,7 +2261,7 @@ func (r *reader) expr() (res ir.Node) {
|
||||
return typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, ir.TypeNode(recv), method.Sel)).(*ir.SelectorExpr)
|
||||
}
|
||||
|
||||
return r.methodExprWrap(pos, recv, implicits, deref, addr, baseFn, dictPtr)
|
||||
return r.methodExprWrap(origPos, recv, implicits, deref, addr, baseFn, dictPtr)
|
||||
|
||||
case exprIndex:
|
||||
x := r.expr()
|
||||
@@ -2550,7 +2591,7 @@ func (pr *pkgReader) objDictName(idx pkgbits.Index, implicits, explicits []*type
|
||||
// If nilCheck is true and arg0 is an interface value, then it's
|
||||
// checked to be non-nil as an initial step at the point of evaluating
|
||||
// the function literal itself.
|
||||
func (r *reader) curry(pos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir.Node) ir.Node {
|
||||
func (r *reader) curry(origPos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir.Node) ir.Node {
|
||||
var captured ir.Nodes
|
||||
captured.Append(fun, arg0)
|
||||
if arg1 != nil {
|
||||
@@ -2574,13 +2615,13 @@ func (r *reader) curry(pos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir.
|
||||
r.syntheticTailCall(pos, fun, args)
|
||||
}
|
||||
|
||||
return r.syntheticClosure(pos, typ, ifaceHack, captured, addBody)
|
||||
return r.syntheticClosure(origPos, typ, ifaceHack, captured, addBody)
|
||||
}
|
||||
|
||||
// methodExprWrap returns a function literal that changes method's
|
||||
// first parameter's type to recv, and uses implicits/deref/addr to
|
||||
// select the appropriate receiver parameter to pass to method.
|
||||
func (r *reader) methodExprWrap(pos src.XPos, recv *types.Type, implicits []int, deref, addr bool, method, dictPtr ir.Node) ir.Node {
|
||||
func (r *reader) methodExprWrap(origPos src.XPos, recv *types.Type, implicits []int, deref, addr bool, method, dictPtr ir.Node) ir.Node {
|
||||
var captured ir.Nodes
|
||||
captured.Append(method)
|
||||
|
||||
@@ -2631,12 +2672,13 @@ func (r *reader) methodExprWrap(pos src.XPos, recv *types.Type, implicits []int,
|
||||
r.syntheticTailCall(pos, fn, args)
|
||||
}
|
||||
|
||||
return r.syntheticClosure(pos, typ, false, captured, addBody)
|
||||
return r.syntheticClosure(origPos, typ, false, captured, addBody)
|
||||
}
|
||||
|
||||
// syntheticClosure constructs a synthetic function literal for
|
||||
// currying dictionary arguments. pos is the position used for the
|
||||
// closure. typ is the function literal's signature type.
|
||||
// currying dictionary arguments. origPos is the position used for the
|
||||
// closure, which must be a non-inlined position. typ is the function
|
||||
// literal's signature type.
|
||||
//
|
||||
// captures is a list of expressions that need to be evaluated at the
|
||||
// point of function literal evaluation and captured by the function
|
||||
@@ -2647,7 +2689,7 @@ func (r *reader) methodExprWrap(pos src.XPos, recv *types.Type, implicits []int,
|
||||
// list of captured values passed back has the captured variables for
|
||||
// use within the function literal, corresponding to the expressions
|
||||
// in captures.
|
||||
func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool, captures ir.Nodes, addBody func(pos src.XPos, r *reader, captured []ir.Node)) ir.Node {
|
||||
func (r *reader) syntheticClosure(origPos src.XPos, typ *types.Type, ifaceHack bool, captures ir.Nodes, addBody func(pos src.XPos, r *reader, captured []ir.Node)) ir.Node {
|
||||
// isSafe reports whether n is an expression that we can safely
|
||||
// defer to evaluating inside the closure instead, to avoid storing
|
||||
// them into the closure.
|
||||
@@ -2664,9 +2706,15 @@ func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool,
|
||||
return false
|
||||
}
|
||||
|
||||
fn := ir.NewClosureFunc(pos, r.curfn != nil)
|
||||
// The ODCLFUNC and its body need to use the original position, but
|
||||
// the OCLOSURE node and any Init statements should use the inlined
|
||||
// position instead. See also the explanation in reader.funcLit.
|
||||
inlPos := r.inlPos(origPos)
|
||||
|
||||
fn := ir.NewClosureFunc(origPos, r.curfn != nil)
|
||||
fn.SetWrapper(true)
|
||||
clo := fn.OClosure
|
||||
clo.SetPos(inlPos)
|
||||
ir.NameClosure(clo, r.curfn)
|
||||
|
||||
setType(fn.Nname, typ)
|
||||
@@ -2679,13 +2727,13 @@ func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool,
|
||||
continue // skip capture; can reference directly
|
||||
}
|
||||
|
||||
tmp := r.tempCopy(pos, n, &init)
|
||||
ir.NewClosureVar(pos, fn, tmp)
|
||||
tmp := r.tempCopy(inlPos, n, &init)
|
||||
ir.NewClosureVar(origPos, fn, tmp)
|
||||
|
||||
// We need to nil check interface receivers at the point of method
|
||||
// value evaluation, ugh.
|
||||
if ifaceHack && i == 1 && n.Type().IsInterface() {
|
||||
check := ir.NewUnaryExpr(pos, ir.OCHECKNIL, ir.NewUnaryExpr(pos, ir.OITAB, tmp))
|
||||
check := ir.NewUnaryExpr(inlPos, ir.OCHECKNIL, ir.NewUnaryExpr(inlPos, ir.OITAB, tmp))
|
||||
init.Append(typecheck.Stmt(check))
|
||||
}
|
||||
}
|
||||
@@ -2703,7 +2751,7 @@ func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool,
|
||||
}
|
||||
assert(next == len(r.closureVars))
|
||||
|
||||
addBody(pos, r, captured)
|
||||
addBody(origPos, r, captured)
|
||||
}}
|
||||
bodyReader[fn] = pri
|
||||
pri.funcBody(fn)
|
||||
|
||||
@@ -158,7 +158,11 @@ func readBodies(target *ir.Package, duringInlining bool) {
|
||||
// Instantiated generic function: add to Decls for typechecking
|
||||
// and compilation.
|
||||
if fn.OClosure == nil && len(pri.dict.targs) != 0 {
|
||||
if duringInlining {
|
||||
// cmd/link does not support a type symbol referencing a method symbol
|
||||
// across DSO boundary, so force re-compiling methods on a generic type
|
||||
// even it was seen from imported package in linkshared mode, see #58966.
|
||||
canSkipNonGenericMethod := !(base.Ctxt.Flag_linkshared && ir.IsMethod(fn))
|
||||
if duringInlining && canSkipNonGenericMethod {
|
||||
inlDecls = append(inlDecls, fn)
|
||||
} else {
|
||||
target.Decls = append(target.Decls, fn)
|
||||
|
||||
@@ -140,9 +140,30 @@ func New(profileFile string) *Profile {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(profile.Sample) == 0 {
|
||||
// We accept empty profiles, but there is nothing to do.
|
||||
return nil
|
||||
}
|
||||
|
||||
valueIndex := -1
|
||||
for i, s := range profile.SampleType {
|
||||
// Samples count is the raw data collected, and CPU nanoseconds is just
|
||||
// a scaled version of it, so either one we can find is fine.
|
||||
if (s.Type == "samples" && s.Unit == "count") ||
|
||||
(s.Type == "cpu" && s.Unit == "nanoseconds") {
|
||||
valueIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if valueIndex == -1 {
|
||||
log.Fatal("failed to find CPU samples count or CPU nanoseconds value-types in profile.")
|
||||
return nil
|
||||
}
|
||||
|
||||
g := newGraph(profile, &Options{
|
||||
CallTree: false,
|
||||
SampleValue: func(v []int64) int64 { return v[1] },
|
||||
SampleValue: func(v []int64) int64 { return v[valueIndex] },
|
||||
})
|
||||
|
||||
p := &Profile{
|
||||
|
||||
@@ -1757,13 +1757,13 @@
|
||||
x0:(MOVBstore [i-1] {s} p (SHRWconst [8] w) mem))
|
||||
&& x0.Uses == 1
|
||||
&& clobber(x0)
|
||||
=> (MOVWstore [i-1] {s} p (ROLWconst <w.Type> [8] w) mem)
|
||||
=> (MOVWstore [i-1] {s} p (ROLWconst <typ.UInt16> [8] w) mem)
|
||||
(MOVBstore [i] {s} p1 w
|
||||
x0:(MOVBstore [i] {s} p0 (SHRWconst [8] w) mem))
|
||||
&& x0.Uses == 1
|
||||
&& sequentialAddresses(p0, p1, 1)
|
||||
&& clobber(x0)
|
||||
=> (MOVWstore [i] {s} p0 (ROLWconst <w.Type> [8] w) mem)
|
||||
=> (MOVWstore [i] {s} p0 (ROLWconst <typ.UInt16> [8] w) mem)
|
||||
|
||||
// Combine stores + shifts into bswap and larger (unaligned) stores
|
||||
(MOVBstore [i] {s} p w
|
||||
@@ -1774,7 +1774,7 @@
|
||||
&& x1.Uses == 1
|
||||
&& x2.Uses == 1
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVLstore [i-3] {s} p (BSWAPL <w.Type> w) mem)
|
||||
=> (MOVLstore [i-3] {s} p (BSWAPL <typ.UInt32> w) mem)
|
||||
(MOVBstore [i] {s} p3 w
|
||||
x2:(MOVBstore [i] {s} p2 (SHRLconst [8] w)
|
||||
x1:(MOVBstore [i] {s} p1 (SHRLconst [16] w)
|
||||
@@ -1786,7 +1786,7 @@
|
||||
&& sequentialAddresses(p1, p2, 1)
|
||||
&& sequentialAddresses(p2, p3, 1)
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVLstore [i] {s} p0 (BSWAPL <w.Type> w) mem)
|
||||
=> (MOVLstore [i] {s} p0 (BSWAPL <typ.UInt32> w) mem)
|
||||
|
||||
(MOVBstore [i] {s} p w
|
||||
x6:(MOVBstore [i-1] {s} p (SHRQconst [8] w)
|
||||
@@ -1804,7 +1804,7 @@
|
||||
&& x5.Uses == 1
|
||||
&& x6.Uses == 1
|
||||
&& clobber(x0, x1, x2, x3, x4, x5, x6)
|
||||
=> (MOVQstore [i-7] {s} p (BSWAPQ <w.Type> w) mem)
|
||||
=> (MOVQstore [i-7] {s} p (BSWAPQ <typ.UInt64> w) mem)
|
||||
(MOVBstore [i] {s} p7 w
|
||||
x6:(MOVBstore [i] {s} p6 (SHRQconst [8] w)
|
||||
x5:(MOVBstore [i] {s} p5 (SHRQconst [16] w)
|
||||
@@ -1828,7 +1828,7 @@
|
||||
&& sequentialAddresses(p5, p6, 1)
|
||||
&& sequentialAddresses(p6, p7, 1)
|
||||
&& clobber(x0, x1, x2, x3, x4, x5, x6)
|
||||
=> (MOVQstore [i] {s} p0 (BSWAPQ <w.Type> w) mem)
|
||||
=> (MOVQstore [i] {s} p0 (BSWAPQ <typ.UInt64> w) mem)
|
||||
|
||||
// Combine constant stores into larger (unaligned) stores.
|
||||
(MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem))
|
||||
|
||||
@@ -2,14 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// split 3 operand LEA.
|
||||
// Note: Don't split pointer computations in order to avoid invalid pointers.
|
||||
(LEA(Q|L|W)1 <t> [c] {s} x y) && isPtr(x.Type) && c != 0 && s == nil => (ADD(Q|L|L) x (ADD(Q|L|L)const <y.Type> [c] y))
|
||||
(LEA(Q|L|W)1 <t> [c] {s} x y) && !isPtr(x.Type) && c != 0 && s == nil => (ADD(Q|L|L) y (ADD(Q|L|L)const <x.Type> [c] x))
|
||||
(LEA(Q|L|W)2 <t> [c] {s} x y) && !isPtr(t) && c != 0 && s == nil => (ADD(Q|L|L)const [c] (LEA(Q|L|W)2 <x.Type> x y))
|
||||
(LEA(Q|L|W)4 <t> [c] {s} x y) && !isPtr(t) && c != 0 && s == nil => (ADD(Q|L|L)const [c] (LEA(Q|L|W)4 <x.Type> x y))
|
||||
(LEA(Q|L|W)8 <t> [c] {s} x y) && !isPtr(t) && c != 0 && s == nil => (ADD(Q|L|L)const [c] (LEA(Q|L|W)8 <x.Type> x y))
|
||||
|
||||
// Prefer SARX/SHLX/SHRX instruction because it has less register restriction on the shift input.
|
||||
(SAR(Q|L) x y) && buildcfg.GOAMD64 >= 3 => (SARX(Q|L) x y)
|
||||
(SHL(Q|L) x y) && buildcfg.GOAMD64 >= 3 => (SHLX(Q|L) x y)
|
||||
|
||||
@@ -837,25 +837,35 @@
|
||||
(MOVDaddr [int32(off1)+off2] {sym} ptr)
|
||||
|
||||
// fold address into load/store
|
||||
(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBload [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBUload [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHload [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHUload [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWload [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWUload [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVDload [off1+int32(off2)] {sym} ptr mem)
|
||||
(LDP [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(LDP [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(LDP [off1+int32(off2)] {sym} ptr mem)
|
||||
(FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVSload [off1+int32(off2)] {sym} ptr mem)
|
||||
(FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVDload [off1+int32(off2)] {sym} ptr mem)
|
||||
|
||||
// register indexed load
|
||||
@@ -920,29 +930,41 @@
|
||||
(FMOVDloadidx8 ptr (MOVDconst [c]) mem) && is32Bit(c<<3) => (FMOVDload ptr [int32(c)<<3] mem)
|
||||
(FMOVSloadidx4 ptr (MOVDconst [c]) mem) && is32Bit(c<<2) => (FMOVSload ptr [int32(c)<<2] mem)
|
||||
|
||||
(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBstore [off1+int32(off2)] {sym} ptr val mem)
|
||||
(MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHstore [off1+int32(off2)] {sym} ptr val mem)
|
||||
(MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWstore [off1+int32(off2)] {sym} ptr val mem)
|
||||
(MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVDstore [off1+int32(off2)] {sym} ptr val mem)
|
||||
(STP [off1] {sym} (ADDconst [off2] ptr) val1 val2 mem) && is32Bit(int64(off1)+off2) =>
|
||||
(STP [off1] {sym} (ADDconst [off2] ptr) val1 val2 mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(STP [off1+int32(off2)] {sym} ptr val1 val2 mem)
|
||||
(FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) =>
|
||||
(FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVSstore [off1+int32(off2)] {sym} ptr val mem)
|
||||
(FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) =>
|
||||
(FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVDstore [off1+int32(off2)] {sym} ptr val mem)
|
||||
(MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBstorezero [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHstorezero [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWstorezero [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVDstorezero [off1+int32(off2)] {sym} ptr mem)
|
||||
(MOVQstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) =>
|
||||
(MOVQstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVQstorezero [off1+int32(off2)] {sym} ptr mem)
|
||||
|
||||
// register indexed store
|
||||
@@ -991,71 +1013,93 @@
|
||||
(FMOVSstoreidx4 ptr (MOVDconst [c]) val mem) && is32Bit(c<<2) => (FMOVSstore [int32(c)<<2] ptr val mem)
|
||||
|
||||
(MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(LDP [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(LDP [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
|
||||
(MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(STP [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val1 val2 mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(STP [off1+off2] {mergeSym(sym1,sym2)} ptr val1 val2 mem)
|
||||
(FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVQstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOVQstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
|
||||
// store zero
|
||||
@@ -2777,7 +2821,7 @@
|
||||
&& x5.Uses == 1
|
||||
&& x6.Uses == 1
|
||||
&& clobber(x0, x1, x2, x3, x4, x5, x6)
|
||||
=> (MOVDstore [i-7] {s} ptr (REV <w.Type> w) mem)
|
||||
=> (MOVDstore [i-7] {s} ptr (REV <typ.UInt64> w) mem)
|
||||
(MOVBstore [7] {s} p w
|
||||
x0:(MOVBstore [6] {s} p (SRLconst [8] w)
|
||||
x1:(MOVBstore [5] {s} p (SRLconst [16] w)
|
||||
@@ -2797,7 +2841,7 @@
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& isSamePtr(p1, p)
|
||||
&& clobber(x0, x1, x2, x3, x4, x5, x6)
|
||||
=> (MOVDstoreidx ptr0 idx0 (REV <w.Type> w) mem)
|
||||
=> (MOVDstoreidx ptr0 idx0 (REV <typ.UInt64> w) mem)
|
||||
(MOVBstore [i] {s} ptr w
|
||||
x0:(MOVBstore [i-1] {s} ptr (UBFX [armBFAuxInt(8, 24)] w)
|
||||
x1:(MOVBstore [i-2] {s} ptr (UBFX [armBFAuxInt(16, 16)] w)
|
||||
@@ -2806,7 +2850,7 @@
|
||||
&& x1.Uses == 1
|
||||
&& x2.Uses == 1
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstore [i-3] {s} ptr (REVW <w.Type> w) mem)
|
||||
=> (MOVWstore [i-3] {s} ptr (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstore [3] {s} p w
|
||||
x0:(MOVBstore [2] {s} p (UBFX [armBFAuxInt(8, 24)] w)
|
||||
x1:(MOVBstore [1] {s} p1:(ADD ptr1 idx1) (UBFX [armBFAuxInt(16, 16)] w)
|
||||
@@ -2818,7 +2862,7 @@
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& isSamePtr(p1, p)
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstoreidx ptr0 idx0 (REVW <w.Type> w) mem)
|
||||
=> (MOVWstoreidx ptr0 idx0 (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstoreidx ptr (ADDconst [3] idx) w
|
||||
x0:(MOVBstoreidx ptr (ADDconst [2] idx) (UBFX [armBFAuxInt(8, 24)] w)
|
||||
x1:(MOVBstoreidx ptr (ADDconst [1] idx) (UBFX [armBFAuxInt(16, 16)] w)
|
||||
@@ -2827,7 +2871,7 @@
|
||||
&& x1.Uses == 1
|
||||
&& x2.Uses == 1
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstoreidx ptr idx (REVW <w.Type> w) mem)
|
||||
=> (MOVWstoreidx ptr idx (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstoreidx ptr idx w
|
||||
x0:(MOVBstoreidx ptr (ADDconst [1] idx) (UBFX [armBFAuxInt(8, 24)] w)
|
||||
x1:(MOVBstoreidx ptr (ADDconst [2] idx) (UBFX [armBFAuxInt(16, 16)] w)
|
||||
@@ -2845,7 +2889,7 @@
|
||||
&& x1.Uses == 1
|
||||
&& x2.Uses == 1
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstore [i-3] {s} ptr (REVW <w.Type> w) mem)
|
||||
=> (MOVWstore [i-3] {s} ptr (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstore [3] {s} p w
|
||||
x0:(MOVBstore [2] {s} p (SRLconst [8] (MOVDreg w))
|
||||
x1:(MOVBstore [1] {s} p1:(ADD ptr1 idx1) (SRLconst [16] (MOVDreg w))
|
||||
@@ -2857,7 +2901,7 @@
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& isSamePtr(p1, p)
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstoreidx ptr0 idx0 (REVW <w.Type> w) mem)
|
||||
=> (MOVWstoreidx ptr0 idx0 (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstore [i] {s} ptr w
|
||||
x0:(MOVBstore [i-1] {s} ptr (SRLconst [8] w)
|
||||
x1:(MOVBstore [i-2] {s} ptr (SRLconst [16] w)
|
||||
@@ -2866,7 +2910,7 @@
|
||||
&& x1.Uses == 1
|
||||
&& x2.Uses == 1
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstore [i-3] {s} ptr (REVW <w.Type> w) mem)
|
||||
=> (MOVWstore [i-3] {s} ptr (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstore [3] {s} p w
|
||||
x0:(MOVBstore [2] {s} p (SRLconst [8] w)
|
||||
x1:(MOVBstore [1] {s} p1:(ADD ptr1 idx1) (SRLconst [16] w)
|
||||
@@ -2878,31 +2922,31 @@
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& isSamePtr(p1, p)
|
||||
&& clobber(x0, x1, x2)
|
||||
=> (MOVWstoreidx ptr0 idx0 (REVW <w.Type> w) mem)
|
||||
=> (MOVWstoreidx ptr0 idx0 (REVW <typ.UInt32> w) mem)
|
||||
(MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (SRLconst [8] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (SRLconst [8] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& s == nil
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& clobber(x)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (UBFX [armBFAuxInt(8, 8)] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (UBFX [armBFAuxInt(8, 8)] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& s == nil
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& clobber(x)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstoreidx ptr (ADDconst [1] idx) w x:(MOVBstoreidx ptr idx (UBFX [armBFAuxInt(8, 8)] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
=> (MOVHstoreidx ptr idx (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstoreidx ptr idx (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstoreidx ptr idx w x:(MOVBstoreidx ptr (ADDconst [1] idx) (UBFX [armBFAuxInt(8, 8)] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
@@ -2910,23 +2954,23 @@
|
||||
(MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (SRLconst [8] (MOVDreg w)) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (SRLconst [8] (MOVDreg w)) mem))
|
||||
&& x.Uses == 1
|
||||
&& s == nil
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& clobber(x)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (UBFX [armBFAuxInt(8, 24)] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstore [i-1] {s} ptr (REV16W <typ.UInt16> w) mem)
|
||||
(MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (UBFX [armBFAuxInt(8, 24)] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& s == nil
|
||||
&& (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1))
|
||||
&& clobber(x)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <w.Type> w) mem)
|
||||
=> (MOVHstoreidx ptr0 idx0 (REV16W <typ.UInt16> w) mem)
|
||||
|
||||
// FP simplification
|
||||
(FNEGS (FMULS x y)) => (FNMULS x y)
|
||||
|
||||
@@ -856,9 +856,6 @@ func prove(f *Func) {
|
||||
case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
|
||||
ft.update(b, v, v.Args[1], unsigned, lt|eq)
|
||||
ft.update(b, v, v.Args[0], unsigned, lt|eq)
|
||||
case OpOr64, OpOr32, OpOr16, OpOr8:
|
||||
ft.update(b, v, v.Args[1], unsigned, gt|eq)
|
||||
ft.update(b, v, v.Args[0], unsigned, gt|eq)
|
||||
case OpPhi:
|
||||
// Determine the min and max value of OpPhi composed entirely of integer constants.
|
||||
//
|
||||
|
||||
@@ -10244,7 +10244,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
}
|
||||
// match: (MOVBstore [i] {s} p w x0:(MOVBstore [i-1] {s} p (SHRWconst [8] w) mem))
|
||||
// cond: x0.Uses == 1 && clobber(x0)
|
||||
// result: (MOVWstore [i-1] {s} p (ROLWconst <w.Type> [8] w) mem)
|
||||
// result: (MOVWstore [i-1] {s} p (ROLWconst <typ.UInt16> [8] w) mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
@@ -10265,7 +10265,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
v.reset(OpAMD64MOVWstore)
|
||||
v.AuxInt = int32ToAuxInt(i - 1)
|
||||
v.Aux = symToAux(s)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, w.Type)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, typ.UInt16)
|
||||
v0.AuxInt = int8ToAuxInt(8)
|
||||
v0.AddArg(w)
|
||||
v.AddArg3(p, v0, mem)
|
||||
@@ -10273,7 +10273,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
}
|
||||
// match: (MOVBstore [i] {s} p1 w x0:(MOVBstore [i] {s} p0 (SHRWconst [8] w) mem))
|
||||
// cond: x0.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x0)
|
||||
// result: (MOVWstore [i] {s} p0 (ROLWconst <w.Type> [8] w) mem)
|
||||
// result: (MOVWstore [i] {s} p0 (ROLWconst <typ.UInt16> [8] w) mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
@@ -10292,7 +10292,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
v.reset(OpAMD64MOVWstore)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, w.Type)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, typ.UInt16)
|
||||
v0.AuxInt = int8ToAuxInt(8)
|
||||
v0.AddArg(w)
|
||||
v.AddArg3(p0, v0, mem)
|
||||
@@ -10300,7 +10300,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
}
|
||||
// match: (MOVBstore [i] {s} p w x2:(MOVBstore [i-1] {s} p (SHRLconst [8] w) x1:(MOVBstore [i-2] {s} p (SHRLconst [16] w) x0:(MOVBstore [i-3] {s} p (SHRLconst [24] w) mem))))
|
||||
// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2)
|
||||
// result: (MOVLstore [i-3] {s} p (BSWAPL <w.Type> w) mem)
|
||||
// result: (MOVLstore [i-3] {s} p (BSWAPL <typ.UInt32> w) mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
@@ -10345,14 +10345,14 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
v.reset(OpAMD64MOVLstore)
|
||||
v.AuxInt = int32ToAuxInt(i - 3)
|
||||
v.Aux = symToAux(s)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, w.Type)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, typ.UInt32)
|
||||
v0.AddArg(w)
|
||||
v.AddArg3(p, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBstore [i] {s} p3 w x2:(MOVBstore [i] {s} p2 (SHRLconst [8] w) x1:(MOVBstore [i] {s} p1 (SHRLconst [16] w) x0:(MOVBstore [i] {s} p0 (SHRLconst [24] w) mem))))
|
||||
// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && sequentialAddresses(p0, p1, 1) && sequentialAddresses(p1, p2, 1) && sequentialAddresses(p2, p3, 1) && clobber(x0, x1, x2)
|
||||
// result: (MOVLstore [i] {s} p0 (BSWAPL <w.Type> w) mem)
|
||||
// result: (MOVLstore [i] {s} p0 (BSWAPL <typ.UInt32> w) mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
@@ -10391,14 +10391,14 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
v.reset(OpAMD64MOVLstore)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, w.Type)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, typ.UInt32)
|
||||
v0.AddArg(w)
|
||||
v.AddArg3(p0, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBstore [i] {s} p w x6:(MOVBstore [i-1] {s} p (SHRQconst [8] w) x5:(MOVBstore [i-2] {s} p (SHRQconst [16] w) x4:(MOVBstore [i-3] {s} p (SHRQconst [24] w) x3:(MOVBstore [i-4] {s} p (SHRQconst [32] w) x2:(MOVBstore [i-5] {s} p (SHRQconst [40] w) x1:(MOVBstore [i-6] {s} p (SHRQconst [48] w) x0:(MOVBstore [i-7] {s} p (SHRQconst [56] w) mem))))))))
|
||||
// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && clobber(x0, x1, x2, x3, x4, x5, x6)
|
||||
// result: (MOVQstore [i-7] {s} p (BSWAPQ <w.Type> w) mem)
|
||||
// result: (MOVQstore [i-7] {s} p (BSWAPQ <typ.UInt64> w) mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
@@ -10491,14 +10491,14 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
v.reset(OpAMD64MOVQstore)
|
||||
v.AuxInt = int32ToAuxInt(i - 7)
|
||||
v.Aux = symToAux(s)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, w.Type)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, typ.UInt64)
|
||||
v0.AddArg(w)
|
||||
v.AddArg3(p, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBstore [i] {s} p7 w x6:(MOVBstore [i] {s} p6 (SHRQconst [8] w) x5:(MOVBstore [i] {s} p5 (SHRQconst [16] w) x4:(MOVBstore [i] {s} p4 (SHRQconst [24] w) x3:(MOVBstore [i] {s} p3 (SHRQconst [32] w) x2:(MOVBstore [i] {s} p2 (SHRQconst [40] w) x1:(MOVBstore [i] {s} p1 (SHRQconst [48] w) x0:(MOVBstore [i] {s} p0 (SHRQconst [56] w) mem))))))))
|
||||
// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && sequentialAddresses(p0, p1, 1) && sequentialAddresses(p1, p2, 1) && sequentialAddresses(p2, p3, 1) && sequentialAddresses(p3, p4, 1) && sequentialAddresses(p4, p5, 1) && sequentialAddresses(p5, p6, 1) && sequentialAddresses(p6, p7, 1) && clobber(x0, x1, x2, x3, x4, x5, x6)
|
||||
// result: (MOVQstore [i] {s} p0 (BSWAPQ <w.Type> w) mem)
|
||||
// result: (MOVQstore [i] {s} p0 (BSWAPQ <typ.UInt64> w) mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
@@ -10577,7 +10577,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
|
||||
v.reset(OpAMD64MOVQstore)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, w.Type)
|
||||
v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, typ.UInt64)
|
||||
v0.AddArg(w)
|
||||
v.AddArg3(p0, v0, mem)
|
||||
return true
|
||||
|
||||
@@ -7,30 +7,6 @@ import "internal/buildcfg"
|
||||
|
||||
func rewriteValueAMD64latelower(v *Value) bool {
|
||||
switch v.Op {
|
||||
case OpAMD64LEAL1:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAL1(v)
|
||||
case OpAMD64LEAL2:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAL2(v)
|
||||
case OpAMD64LEAL4:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAL4(v)
|
||||
case OpAMD64LEAL8:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAL8(v)
|
||||
case OpAMD64LEAQ1:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAQ1(v)
|
||||
case OpAMD64LEAQ2:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAQ2(v)
|
||||
case OpAMD64LEAQ4:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAQ4(v)
|
||||
case OpAMD64LEAQ8:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAQ8(v)
|
||||
case OpAMD64LEAW1:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAW1(v)
|
||||
case OpAMD64LEAW2:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAW2(v)
|
||||
case OpAMD64LEAW4:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAW4(v)
|
||||
case OpAMD64LEAW8:
|
||||
return rewriteValueAMD64latelower_OpAMD64LEAW8(v)
|
||||
case OpAMD64SARL:
|
||||
return rewriteValueAMD64latelower_OpAMD64SARL(v)
|
||||
case OpAMD64SARQ:
|
||||
@@ -46,375 +22,6 @@ func rewriteValueAMD64latelower(v *Value) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAL1(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAL1 <t> [c] {s} x y)
|
||||
// cond: isPtr(x.Type) && c != 0 && s == nil
|
||||
// result: (ADDL x (ADDLconst <y.Type> [c] y))
|
||||
for {
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(isPtr(x.Type) && c != 0 && s == nil) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ADDL)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDLconst, y.Type)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(y)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (LEAL1 <t> [c] {s} x y)
|
||||
// cond: !isPtr(x.Type) && c != 0 && s == nil
|
||||
// result: (ADDL y (ADDLconst <x.Type> [c] x))
|
||||
for {
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(x.Type) && c != 0 && s == nil) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ADDL)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDLconst, x.Type)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
v.AddArg2(y, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAL2(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAL2 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDLconst [c] (LEAL2 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDLconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAL2, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAL4(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAL4 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDLconst [c] (LEAL4 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDLconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAL4, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAL8(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAL8 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDLconst [c] (LEAL8 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDLconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAL8, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAQ1(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAQ1 <t> [c] {s} x y)
|
||||
// cond: isPtr(x.Type) && c != 0 && s == nil
|
||||
// result: (ADDQ x (ADDQconst <y.Type> [c] y))
|
||||
for {
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(isPtr(x.Type) && c != 0 && s == nil) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ADDQ)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDQconst, y.Type)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(y)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (LEAQ1 <t> [c] {s} x y)
|
||||
// cond: !isPtr(x.Type) && c != 0 && s == nil
|
||||
// result: (ADDQ y (ADDQconst <x.Type> [c] x))
|
||||
for {
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(x.Type) && c != 0 && s == nil) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ADDQ)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDQconst, x.Type)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
v.AddArg2(y, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAQ2(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAQ2 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDQconst [c] (LEAQ2 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDQconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAQ2, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAQ4(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAQ4 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDQconst [c] (LEAQ4 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDQconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAQ4, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAQ8(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAQ8 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDQconst [c] (LEAQ8 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDQconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAQ8, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAW1(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAW1 <t> [c] {s} x y)
|
||||
// cond: isPtr(x.Type) && c != 0 && s == nil
|
||||
// result: (ADDL x (ADDLconst <y.Type> [c] y))
|
||||
for {
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(isPtr(x.Type) && c != 0 && s == nil) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ADDL)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDLconst, y.Type)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(y)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (LEAW1 <t> [c] {s} x y)
|
||||
// cond: !isPtr(x.Type) && c != 0 && s == nil
|
||||
// result: (ADDL y (ADDLconst <x.Type> [c] x))
|
||||
for {
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(x.Type) && c != 0 && s == nil) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ADDL)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDLconst, x.Type)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
v.AddArg2(y, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAW2(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAW2 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDLconst [c] (LEAW2 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDLconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAW2, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAW4(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAW4 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDLconst [c] (LEAW4 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDLconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAW4, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64LEAW8(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (LEAW8 <t> [c] {s} x y)
|
||||
// cond: !isPtr(t) && c != 0 && s == nil
|
||||
// result: (ADDLconst [c] (LEAW8 <x.Type> x y))
|
||||
for {
|
||||
t := v.Type
|
||||
c := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if !(!isPtr(t) && c != 0 && s == nil) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDLconst)
|
||||
v.AuxInt = int32ToAuxInt(c)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAW8, x.Type)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64SARL(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3203,7 +3203,10 @@ func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value {
|
||||
n := n.(*ir.UnaryExpr)
|
||||
a := s.expr(n.X)
|
||||
if n.X.Type().IsSlice() {
|
||||
return s.newValue1(ssa.OpSlicePtr, n.Type(), a)
|
||||
if n.Bounded() {
|
||||
return s.newValue1(ssa.OpSlicePtr, n.Type(), a)
|
||||
}
|
||||
return s.newValue1(ssa.OpSlicePtrUnchecked, n.Type(), a)
|
||||
} else {
|
||||
return s.newValue1(ssa.OpStringPtr, n.Type(), a)
|
||||
}
|
||||
|
||||
@@ -615,6 +615,9 @@ func (s *Schedule) staticAssignInlinedCall(l *ir.Name, loff int64, call *ir.Inli
|
||||
// Build tree with args substituted for params and try it.
|
||||
args := make(map[*ir.Name]ir.Node)
|
||||
for i, v := range as2init.Lhs {
|
||||
if ir.IsBlank(v) {
|
||||
continue
|
||||
}
|
||||
args[v.(*ir.Name)] = as2init.Rhs[i]
|
||||
}
|
||||
r, ok := subst(as2body.Rhs[0], args)
|
||||
@@ -838,7 +841,7 @@ func subst(n ir.Node, m map[*ir.Name]ir.Node) (ir.Node, bool) {
|
||||
return x
|
||||
}
|
||||
x = ir.Copy(x)
|
||||
ir.EditChildren(x, edit)
|
||||
ir.EditChildrenWithHidden(x, edit)
|
||||
if x, ok := x.(*ir.ConvExpr); ok && x.X.Op() == ir.OLITERAL {
|
||||
// A conversion of variable or expression involving variables
|
||||
// may become a conversion of constant after inlining the parameters
|
||||
|
||||
@@ -7,6 +7,7 @@ package test
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"internal/profile"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"os"
|
||||
@@ -213,6 +214,73 @@ func TestPGOIntendedInliningShiftedLines(t *testing.T) {
|
||||
testPGOIntendedInlining(t, dir)
|
||||
}
|
||||
|
||||
// TestPGOSingleIndex tests that the sample index can not be 1 and compilation
|
||||
// will not fail. All it should care about is that the sample type is either
|
||||
// CPU nanoseconds or samples count, whichever it finds first.
|
||||
func TestPGOSingleIndex(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
originalIndex int
|
||||
}{{
|
||||
// The `testdata/pgo/inline/inline_hot.pprof` file is a standard CPU
|
||||
// profile as the runtime would generate. The 0 index contains the
|
||||
// value-type samples and value-unit count. The 1 index contains the
|
||||
// value-type cpu and value-unit nanoseconds. These tests ensure that
|
||||
// the compiler can work with profiles that only have a single index,
|
||||
// but are either samples count or CPU nanoseconds.
|
||||
originalIndex: 0,
|
||||
}, {
|
||||
originalIndex: 1,
|
||||
}} {
|
||||
t.Run(fmt.Sprintf("originalIndex=%d", tc.originalIndex), func(t *testing.T) {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("error getting wd: %v", err)
|
||||
}
|
||||
srcDir := filepath.Join(wd, "testdata/pgo/inline")
|
||||
|
||||
// Copy the module to a scratch location so we can add a go.mod.
|
||||
dir := t.TempDir()
|
||||
|
||||
originalPprofFile, err := os.Open(filepath.Join(srcDir, "inline_hot.pprof"))
|
||||
if err != nil {
|
||||
t.Fatalf("error opening inline_hot.pprof: %v", err)
|
||||
}
|
||||
defer originalPprofFile.Close()
|
||||
|
||||
p, err := profile.Parse(originalPprofFile)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing inline_hot.pprof: %v", err)
|
||||
}
|
||||
|
||||
// Move the samples count value-type to the 0 index.
|
||||
p.SampleType = []*profile.ValueType{p.SampleType[tc.originalIndex]}
|
||||
|
||||
// Ensure we only have a single set of sample values.
|
||||
for _, s := range p.Sample {
|
||||
s.Value = []int64{s.Value[tc.originalIndex]}
|
||||
}
|
||||
|
||||
modifiedPprofFile, err := os.Create(filepath.Join(dir, "inline_hot.pprof"))
|
||||
if err != nil {
|
||||
t.Fatalf("error creating inline_hot.pprof: %v", err)
|
||||
}
|
||||
defer modifiedPprofFile.Close()
|
||||
|
||||
if err := p.Write(modifiedPprofFile); err != nil {
|
||||
t.Fatalf("error writing inline_hot.pprof: %v", err)
|
||||
}
|
||||
|
||||
for _, file := range []string{"inline_hot.go", "inline_hot_test.go"} {
|
||||
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
|
||||
t.Fatalf("error copying %s: %v", file, err)
|
||||
}
|
||||
}
|
||||
|
||||
testPGOIntendedInlining(t, dir)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func copyFile(dst, src string) error {
|
||||
s, err := os.Open(src)
|
||||
if err != nil {
|
||||
|
||||
@@ -34,10 +34,7 @@ func roundFloat(v constant.Value, sz int64) constant.Value {
|
||||
// truncate float literal fv to 32-bit or 64-bit precision
|
||||
// according to type; return truncated value.
|
||||
func truncfltlit(v constant.Value, t *types.Type) constant.Value {
|
||||
if t.IsUntyped() || overflow(v, t) {
|
||||
// If there was overflow, simply continuing would set the
|
||||
// value to Inf which in turn would lead to spurious follow-on
|
||||
// errors. Avoid this by returning the existing value.
|
||||
if t.IsUntyped() {
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -48,10 +45,7 @@ func truncfltlit(v constant.Value, t *types.Type) constant.Value {
|
||||
// precision, according to type; return truncated value. In case of
|
||||
// overflow, calls Errorf but does not truncate the input value.
|
||||
func trunccmplxlit(v constant.Value, t *types.Type) constant.Value {
|
||||
if t.IsUntyped() || overflow(v, t) {
|
||||
// If there was overflow, simply continuing would set the
|
||||
// value to Inf which in turn would lead to spurious follow-on
|
||||
// errors. Avoid this by returning the existing value.
|
||||
if t.IsUntyped() {
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -251,7 +245,6 @@ func convertVal(v constant.Value, t *types.Type, explicit bool) constant.Value {
|
||||
switch {
|
||||
case t.IsInteger():
|
||||
v = toint(v)
|
||||
overflow(v, t)
|
||||
return v
|
||||
case t.IsFloat():
|
||||
v = toflt(v)
|
||||
@@ -273,9 +266,6 @@ func tocplx(v constant.Value) constant.Value {
|
||||
|
||||
func toflt(v constant.Value) constant.Value {
|
||||
if v.Kind() == constant.Complex {
|
||||
if constant.Sign(constant.Imag(v)) != 0 {
|
||||
base.Errorf("constant %v truncated to real", v)
|
||||
}
|
||||
v = constant.Real(v)
|
||||
}
|
||||
|
||||
@@ -284,9 +274,6 @@ func toflt(v constant.Value) constant.Value {
|
||||
|
||||
func toint(v constant.Value) constant.Value {
|
||||
if v.Kind() == constant.Complex {
|
||||
if constant.Sign(constant.Imag(v)) != 0 {
|
||||
base.Errorf("constant %v truncated to integer", v)
|
||||
}
|
||||
v = constant.Real(v)
|
||||
}
|
||||
|
||||
@@ -321,25 +308,6 @@ func toint(v constant.Value) constant.Value {
|
||||
return constant.MakeInt64(1)
|
||||
}
|
||||
|
||||
// overflow reports whether constant value v is too large
|
||||
// to represent with type t, and emits an error message if so.
|
||||
func overflow(v constant.Value, t *types.Type) bool {
|
||||
// v has already been converted
|
||||
// to appropriate form for t.
|
||||
if t.IsUntyped() {
|
||||
return false
|
||||
}
|
||||
if v.Kind() == constant.Int && constant.BitLen(v) > ir.ConstPrec {
|
||||
base.Errorf("integer too large")
|
||||
return true
|
||||
}
|
||||
if ir.ConstOverflow(v, t) {
|
||||
base.Errorf("constant %v overflows %v", types.FmtConst(v, false), t)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func tostr(v constant.Value) constant.Value {
|
||||
if v.Kind() == constant.Int {
|
||||
r := unicode.ReplacementChar
|
||||
|
||||
@@ -71,7 +71,7 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
|
||||
|
||||
do := func(nn ir.Node, t *types.Type) {
|
||||
if nn != nil {
|
||||
if ir.DeclaredBy(nn, n) {
|
||||
if ir.DeclaredBy(nn, n) && nn.Type() == nil {
|
||||
nn.SetType(t)
|
||||
} else if nn.Type() != nil {
|
||||
if op, why := Assignop(t, nn.Type()); op == ir.OXXX {
|
||||
|
||||
@@ -281,7 +281,9 @@ func walkStringToBytes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
|
||||
|
||||
// Copy from the static string data to the [n]byte.
|
||||
if len(sc) > 0 {
|
||||
as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, typecheck.ConvNop(ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), t.PtrTo())))
|
||||
sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
|
||||
sptr.SetBounded(true)
|
||||
as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, typecheck.ConvNop(sptr, t.PtrTo())))
|
||||
appendWalkStmt(init, as)
|
||||
}
|
||||
|
||||
|
||||
@@ -191,6 +191,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
|
||||
// Pointer to current iteration position. Start on entry to the loop
|
||||
// with the pointer in hu.
|
||||
ptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, hs)
|
||||
ptr.SetBounded(true)
|
||||
huVal := ir.NewConvExpr(base.Pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], ptr)
|
||||
huVal = ir.NewConvExpr(base.Pos, ir.OCONVNOP, types.Types[types.TUINTPTR], huVal)
|
||||
hu := typecheck.Temp(types.Types[types.TUINTPTR])
|
||||
|
||||
@@ -288,6 +288,7 @@ func (d *dstate) VisitFunc(pkgIdx uint32, fnIdx uint32, fd *coverage.FuncDesc) {
|
||||
}
|
||||
fmt.Printf("\nFunc: %s\n", fd.Funcname)
|
||||
fmt.Printf("Srcfile: %s\n", fd.Srcfile)
|
||||
fmt.Printf("Literal: %v\n", fd.Lit)
|
||||
}
|
||||
for i := 0; i < len(fd.Units); i++ {
|
||||
u := fd.Units[i]
|
||||
|
||||
@@ -9,7 +9,7 @@ require (
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/sys v0.3.0
|
||||
golang.org/x/term v0.2.0
|
||||
golang.org/x/tools v0.3.1-0.20221121233702-060c049c4674
|
||||
golang.org/x/tools v0.3.1-0.20230118190848-070db2996ebe
|
||||
)
|
||||
|
||||
require github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2 // indirect
|
||||
|
||||
@@ -12,5 +12,5 @@ golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/tools v0.3.1-0.20221121233702-060c049c4674 h1:Lv0Y+JVwLQF2YThz8ImE7rP2FSv/IzV9lS2k7bvua6U=
|
||||
golang.org/x/tools v0.3.1-0.20221121233702-060c049c4674/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||
golang.org/x/tools v0.3.1-0.20230118190848-070db2996ebe h1:1B2tjdkEp2f885xTfSsY+7mi5fNZHRxWciDl8Hz3EXg=
|
||||
golang.org/x/tools v0.3.1-0.20230118190848-070db2996ebe/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||
|
||||
@@ -69,14 +69,10 @@ var exeSuffix string = func() string {
|
||||
return ""
|
||||
}()
|
||||
|
||||
func tooSlow(t *testing.T) {
|
||||
func tooSlow(t *testing.T, reason string) {
|
||||
if testing.Short() {
|
||||
// In -short mode; skip test, except run it on the {darwin,linux,windows}/amd64 builders.
|
||||
if testenv.Builder() != "" && runtime.GOARCH == "amd64" && (runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows") {
|
||||
return
|
||||
}
|
||||
t.Helper()
|
||||
t.Skip("skipping test in -short mode")
|
||||
t.Skipf("skipping test in -short mode: %s", reason)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1085,7 +1081,7 @@ func TestPackageMainTestCompilerFlags(t *testing.T) {
|
||||
|
||||
// Issue 4104.
|
||||
func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links and runs a test")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1096,7 +1092,7 @@ func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGoListHasAConsistentOrder(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "walks all of GOROOT/src twice")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1109,7 +1105,7 @@ func TestGoListHasAConsistentOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "walks all of GOROOT/src")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1119,7 +1115,7 @@ func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
|
||||
|
||||
func TestGoListCmdOnlyShowsCommands(t *testing.T) {
|
||||
skipIfGccgo(t, "gccgo does not have GOROOT")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "walks all of GOROOT/src/cmd")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1202,7 +1198,8 @@ func TestGoListTest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGoListCompiledCgo(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles cgo files")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1423,7 +1420,7 @@ func TestDefaultGOPATHPrintedSearchList(t *testing.T) {
|
||||
|
||||
func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
|
||||
skipIfGccgo(t, "gccgo does not support -ldflags -X")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles and links a binary")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1440,7 +1437,7 @@ func TestLdFlagsLongArgumentsIssue42295(t *testing.T) {
|
||||
// Test the extremely long command line arguments that contain '\n' characters
|
||||
// get encoded and passed correctly.
|
||||
skipIfGccgo(t, "gccgo does not support -ldflags -X")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles and links a binary")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1462,7 +1459,7 @@ func TestLdFlagsLongArgumentsIssue42295(t *testing.T) {
|
||||
|
||||
func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
|
||||
skipIfGccgo(t, "gccgo has no standard packages")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles and links a test binary")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1473,7 +1470,7 @@ func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
|
||||
|
||||
func TestGoTestDashOWritesBinary(t *testing.T) {
|
||||
skipIfGccgo(t, "gccgo has no standard packages")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles and runs a test binary")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1484,7 +1481,7 @@ func TestGoTestDashOWritesBinary(t *testing.T) {
|
||||
|
||||
// Issue 4515.
|
||||
func TestInstallWithTags(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles and links binaries")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -1553,7 +1550,7 @@ func TestCgoShowsFullPathNames(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCgoHandlesWlORIGIN(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles cgo files")
|
||||
if !canCgo {
|
||||
t.Skip("skipping because cgo not enabled")
|
||||
}
|
||||
@@ -1571,7 +1568,7 @@ func TestCgoHandlesWlORIGIN(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCgoPkgConfig(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles cgo files")
|
||||
if !canCgo {
|
||||
t.Skip("skipping because cgo not enabled")
|
||||
}
|
||||
@@ -1656,7 +1653,7 @@ func TestListTemplateContextFunction(t *testing.T) {
|
||||
// accessed by a non-local import (found in a GOPATH/GOROOT).
|
||||
// See golang.org/issue/17475.
|
||||
func TestImportLocal(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "builds a lot of sequential packages")
|
||||
|
||||
tg := testgo(t)
|
||||
tg.parallel()
|
||||
@@ -1814,7 +1811,7 @@ func TestGoInstallPkgdir(t *testing.T) {
|
||||
// for the install.
|
||||
t.Skip("skipping because cgo not enabled")
|
||||
}
|
||||
tooSlow(t)
|
||||
tooSlow(t, "builds a package with cgo dependencies")
|
||||
|
||||
tg := testgo(t)
|
||||
tg.parallel()
|
||||
@@ -1829,7 +1826,7 @@ func TestGoInstallPkgdir(t *testing.T) {
|
||||
|
||||
// For issue 14337.
|
||||
func TestParallelTest(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links and runs test binaries")
|
||||
tg := testgo(t)
|
||||
tg.parallel()
|
||||
defer tg.cleanup()
|
||||
@@ -1849,7 +1846,7 @@ func TestParallelTest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBinaryOnlyPackages(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "compiles several packages sequentially")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
@@ -2051,7 +2048,7 @@ func TestFFLAGS(t *testing.T) {
|
||||
// This is really a cmd/link issue but this is a convenient place to test it.
|
||||
func TestDuplicateGlobalAsmSymbols(t *testing.T) {
|
||||
skipIfGccgo(t, "gccgo does not use cmd/asm")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links a binary with cgo dependencies")
|
||||
if runtime.GOARCH != "386" && runtime.GOARCH != "amd64" {
|
||||
t.Skipf("skipping test on %s", runtime.GOARCH)
|
||||
}
|
||||
@@ -2350,10 +2347,11 @@ func TestUpxCompression(t *testing.T) {
|
||||
var gocacheverify = godebug.New("gocacheverify")
|
||||
|
||||
func TestCacheListStale(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links a binary")
|
||||
if gocacheverify.Value() == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2372,8 +2370,7 @@ func TestCacheListStale(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCacheCoverage(t *testing.T) {
|
||||
tooSlow(t)
|
||||
|
||||
tooSlow(t, "links and runs a test binary with coverage enabled")
|
||||
if gocacheverify.Value() == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
@@ -2407,10 +2404,11 @@ func TestIssue22588(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIssue22531(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links binaries")
|
||||
if gocacheverify.Value() == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2436,10 +2434,11 @@ func TestIssue22531(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIssue22596(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links binaries")
|
||||
if gocacheverify.Value() == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2465,7 +2464,7 @@ func TestIssue22596(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTestCache(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links and runs test binaries")
|
||||
|
||||
if gocacheverify.Value() == "1" {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
@@ -2572,7 +2571,8 @@ func TestTestSkipVetAfterFailedBuild(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTestVetRebuild(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links and runs test binaries")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2612,7 +2612,8 @@ func TestTestVetRebuild(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInstallDeps(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links a binary")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2643,7 +2644,8 @@ func TestInstallDeps(t *testing.T) {
|
||||
|
||||
// Issue 22986.
|
||||
func TestImportPath(t *testing.T) {
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links and runs a test binary")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2744,7 +2746,8 @@ func TestTwoPkgConfigs(t *testing.T) {
|
||||
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
|
||||
t.Skipf("no shell scripts on %s", runtime.GOOS)
|
||||
}
|
||||
tooSlow(t)
|
||||
tooSlow(t, "builds a package with cgo dependencies")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -2775,7 +2778,7 @@ func TestCgoCache(t *testing.T) {
|
||||
if !canCgo {
|
||||
t.Skip("no cgo")
|
||||
}
|
||||
tooSlow(t)
|
||||
tooSlow(t, "builds a package with cgo dependencies")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
@@ -2828,7 +2831,7 @@ func TestLinkerTmpDirIsDeleted(t *testing.T) {
|
||||
if !canCgo {
|
||||
t.Skip("skipping because cgo not enabled")
|
||||
}
|
||||
tooSlow(t)
|
||||
tooSlow(t, "builds a package with cgo dependencies")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
@@ -2875,7 +2878,8 @@ func TestLinkerTmpDirIsDeleted(t *testing.T) {
|
||||
// Issue 25093.
|
||||
func TestCoverpkgTestOnly(t *testing.T) {
|
||||
skipIfGccgo(t, "gccgo has no cover tool")
|
||||
tooSlow(t)
|
||||
tooSlow(t, "links and runs a test binary with coverage enabled")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
|
||||
@@ -404,18 +404,6 @@ var codeRepoTests = []codeRepoTest{
|
||||
zipSum: "h1:YJYZRsM9BHFTlVr8YADjT0cJH8uFIDtoc5NLiVqZEx8=",
|
||||
zipFileHash: "c15e49d58b7a4c37966cbe5bc01a0330cd5f2927e990e1839bda1d407766d9c5",
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "gopkg.in/natefinch/lumberjack.v2",
|
||||
rev: "latest",
|
||||
version: "v2.0.0-20170531160350-a96e63847dc3",
|
||||
name: "a96e63847dc3c67d17befa69c303767e2f84e54f",
|
||||
short: "a96e63847dc3",
|
||||
time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC),
|
||||
gomod: "module gopkg.in/natefinch/lumberjack.v2\n",
|
||||
zipSum: "h1:AFxeG48hTWHhDTQDk/m2gorfVHUEa9vo3tp3D7TzwjI=",
|
||||
zipFileHash: "b5de0da7bbbec76709eef1ac71b6c9ff423b9fbf3bb97b56743450d4937b06d5",
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "gopkg.in/natefinch/lumberjack.v2",
|
||||
@@ -818,11 +806,6 @@ var codeRepoVersionsTests = []struct {
|
||||
path: "swtch.com/testmod",
|
||||
versions: []string{"v1.0.0", "v1.1.1"},
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "gopkg.in/natefinch/lumberjack.v2",
|
||||
versions: []string{"v2.0.0"},
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/odd-tags.git",
|
||||
|
||||
@@ -432,21 +432,37 @@ func Exec(cancel func(*exec.Cmd) error, waitDelay time.Duration) Cmd {
|
||||
}
|
||||
|
||||
func startCommand(s *State, name, path string, args []string, cancel func(*exec.Cmd) error, waitDelay time.Duration) (WaitFunc, error) {
|
||||
var stdoutBuf, stderrBuf strings.Builder
|
||||
cmd := exec.CommandContext(s.Context(), path, args...)
|
||||
if cancel == nil {
|
||||
cmd.Cancel = nil
|
||||
} else {
|
||||
cmd.Cancel = func() error { return cancel(cmd) }
|
||||
}
|
||||
cmd.WaitDelay = waitDelay
|
||||
cmd.Args[0] = name
|
||||
cmd.Dir = s.Getwd()
|
||||
cmd.Env = s.env
|
||||
cmd.Stdout = &stdoutBuf
|
||||
cmd.Stderr = &stderrBuf
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
var (
|
||||
cmd *exec.Cmd
|
||||
stdoutBuf, stderrBuf strings.Builder
|
||||
)
|
||||
for {
|
||||
cmd = exec.CommandContext(s.Context(), path, args...)
|
||||
if cancel == nil {
|
||||
cmd.Cancel = nil
|
||||
} else {
|
||||
cmd.Cancel = func() error { return cancel(cmd) }
|
||||
}
|
||||
cmd.WaitDelay = waitDelay
|
||||
cmd.Args[0] = name
|
||||
cmd.Dir = s.Getwd()
|
||||
cmd.Env = s.env
|
||||
cmd.Stdout = &stdoutBuf
|
||||
cmd.Stderr = &stderrBuf
|
||||
err := cmd.Start()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if isETXTBSY(err) {
|
||||
// If the script (or its host process) just wrote the executable we're
|
||||
// trying to run, a fork+exec in another thread may be holding open the FD
|
||||
// that we used to write the executable (see https://go.dev/issue/22315).
|
||||
// Since the descriptor should have CLOEXEC set, the problem should
|
||||
// resolve as soon as the forked child reaches its exec call.
|
||||
// Keep retrying until that happens.
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
wait := func(s *State) (stdout, stderr string, err error) {
|
||||
|
||||
11
src/cmd/go/internal/script/cmds_other.go
Normal file
11
src/cmd/go/internal/script/cmds_other.go
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2023 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 !(unix || windows)
|
||||
|
||||
package script
|
||||
|
||||
func isETXTBSY(err error) bool {
|
||||
return false
|
||||
}
|
||||
16
src/cmd/go/internal/script/cmds_posix.go
Normal file
16
src/cmd/go/internal/script/cmds_posix.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2023 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 unix || windows
|
||||
|
||||
package script
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func isETXTBSY(err error) bool {
|
||||
return errors.Is(err, syscall.ETXTBSY)
|
||||
}
|
||||
@@ -66,6 +66,7 @@ var passAnalyzersToVet = map[string]bool{
|
||||
"structtag": true,
|
||||
"testinggoroutine": true,
|
||||
"tests": true,
|
||||
"timeformat": true,
|
||||
"unmarshal": true,
|
||||
"unreachable": true,
|
||||
"unsafeptr": true,
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"cmd/go/internal/test/internal/genflags"
|
||||
"flag"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg.SetGOROOT(testenv.GOROOT(nil), false)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestPassFlagToTestIncludesAllTestFlags(t *testing.T) {
|
||||
@@ -48,6 +50,8 @@ func TestPassFlagToTestIncludesAllTestFlags(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestVetAnalyzersSetIsCorrect(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t) // runs 'go tool vet -flags'
|
||||
|
||||
vetAns, err := genflags.VetAnalyzers()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -75,7 +75,7 @@ func testFlags() []string {
|
||||
}
|
||||
|
||||
switch name {
|
||||
case "testlogfile", "paniconexit0", "fuzzcachedir", "fuzzworker":
|
||||
case "testlogfile", "paniconexit0", "fuzzcachedir", "fuzzworker", "gocoverdir":
|
||||
// These flags are only for use by cmd/go.
|
||||
default:
|
||||
names = append(names, name)
|
||||
|
||||
@@ -3027,6 +3027,36 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
|
||||
}
|
||||
}
|
||||
|
||||
// Scrutinize CFLAGS and related for flags that might cause
|
||||
// problems if we are using internal linking (for example, use of
|
||||
// plugins, LTO, etc) by calling a helper routine that builds on
|
||||
// the existing CGO flags allow-lists. If we see anything
|
||||
// suspicious, emit a special token file "preferlinkext" (known to
|
||||
// the linker) in the object file to signal the that it should not
|
||||
// try to link internally and should revert to external linking.
|
||||
// The token we pass is a suggestion, not a mandate; if a user is
|
||||
// explicitly asking for a specific linkmode via the "-linkmode"
|
||||
// flag, the token will be ignored. NB: in theory we could ditch
|
||||
// the token approach and just pass a flag to the linker when we
|
||||
// eventually invoke it, and the linker flag could then be
|
||||
// documented (although coming up with a simple explanation of the
|
||||
// flag might be challenging). For more context see issues #58619,
|
||||
// #58620, and #58848.
|
||||
flagSources := []string{"CGO_CFLAGS", "CGO_CXXFLAGS", "CGO_FFLAGS"}
|
||||
flagLists := [][]string{cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS}
|
||||
if flagsNotCompatibleWithInternalLinking(flagSources, flagLists) {
|
||||
tokenFile := objdir + "preferlinkext"
|
||||
if cfg.BuildN || cfg.BuildX {
|
||||
b.Showcmd("", "echo > %s", tokenFile)
|
||||
}
|
||||
if !cfg.BuildN {
|
||||
if err := os.WriteFile(tokenFile, nil, 0666); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
outObj = append(outObj, tokenFile)
|
||||
}
|
||||
|
||||
if cfg.BuildMSan {
|
||||
cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
|
||||
cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
|
||||
@@ -3276,6 +3306,24 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
|
||||
return outGo, outObj, nil
|
||||
}
|
||||
|
||||
// flagsNotCompatibleWithInternalLinking scans the list of cgo
|
||||
// compiler flags (C/C++/Fortran) looking for flags that might cause
|
||||
// problems if the build in question uses internal linking. The
|
||||
// primary culprits are use of plugins or use of LTO, but we err on
|
||||
// the side of caution, supporting only those flags that are on the
|
||||
// allow-list for safe flags from security perspective. Return is TRUE
|
||||
// if a sensitive flag is found, FALSE otherwise.
|
||||
func flagsNotCompatibleWithInternalLinking(sourceList []string, flagListList [][]string) bool {
|
||||
for i := range sourceList {
|
||||
sn := sourceList[i]
|
||||
fll := flagListList[i]
|
||||
if err := checkCompilerFlagsForInternalLink(sn, sn, fll); err != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// dynimport creates a Go source file named importGo containing
|
||||
// //go:cgo_import_dynamic directives for each symbol or library
|
||||
// dynamically imported by the object files outObj.
|
||||
|
||||
@@ -230,32 +230,55 @@ var validLinkerFlagsWithNextArg = []string{
|
||||
}
|
||||
|
||||
func checkCompilerFlags(name, source string, list []string) error {
|
||||
return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg)
|
||||
checkOverrides := true
|
||||
return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides)
|
||||
}
|
||||
|
||||
func checkLinkerFlags(name, source string, list []string) error {
|
||||
return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg)
|
||||
checkOverrides := true
|
||||
return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides)
|
||||
}
|
||||
|
||||
func checkFlags(name, source string, list []string, valid []*lazyregexp.Regexp, validNext []string) error {
|
||||
// checkCompilerFlagsForInternalLink returns an error if 'list'
|
||||
// contains a flag or flags that may not be fully supported by
|
||||
// internal linking (meaning that we should punt the link to the
|
||||
// external linker).
|
||||
func checkCompilerFlagsForInternalLink(name, source string, list []string) error {
|
||||
checkOverrides := false
|
||||
if err := checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides); err != nil {
|
||||
return err
|
||||
}
|
||||
// Currently the only flag on the allow list that causes problems
|
||||
// for the linker is "-flto"; check for it manually here.
|
||||
for _, fl := range list {
|
||||
if strings.HasPrefix(fl, "-flto") {
|
||||
return fmt.Errorf("flag %q triggers external linking", fl)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkFlags(name, source string, list []string, valid []*lazyregexp.Regexp, validNext []string, checkOverrides bool) error {
|
||||
// Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc.
|
||||
var (
|
||||
allow *regexp.Regexp
|
||||
disallow *regexp.Regexp
|
||||
)
|
||||
if env := cfg.Getenv("CGO_" + name + "_ALLOW"); env != "" {
|
||||
r, err := regexp.Compile(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err)
|
||||
if checkOverrides {
|
||||
if env := cfg.Getenv("CGO_" + name + "_ALLOW"); env != "" {
|
||||
r, err := regexp.Compile(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err)
|
||||
}
|
||||
allow = r
|
||||
}
|
||||
allow = r
|
||||
}
|
||||
if env := cfg.Getenv("CGO_" + name + "_DISALLOW"); env != "" {
|
||||
r, err := regexp.Compile(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err)
|
||||
if env := cfg.Getenv("CGO_" + name + "_DISALLOW"); env != "" {
|
||||
r, err := regexp.Compile(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err)
|
||||
}
|
||||
disallow = r
|
||||
}
|
||||
disallow = r
|
||||
}
|
||||
|
||||
Args:
|
||||
|
||||
@@ -6,6 +6,7 @@ package work
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -28,6 +29,7 @@ var goodCompilerFlags = [][]string{
|
||||
{"-Wp,-Ufoo"},
|
||||
{"-Wp,-Dfoo1"},
|
||||
{"-Wp,-Ufoo1"},
|
||||
{"-flto"},
|
||||
{"-fobjc-arc"},
|
||||
{"-fno-objc-arc"},
|
||||
{"-fomit-frame-pointer"},
|
||||
@@ -278,3 +280,34 @@ func TestCheckFlagAllowDisallow(t *testing.T) {
|
||||
t.Fatalf("missing error for -fplugin=lint.so: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckCompilerFlagsForInternalLink(t *testing.T) {
|
||||
// Any "bad" compiler flag should trigger external linking.
|
||||
for _, f := range badCompilerFlags {
|
||||
if err := checkCompilerFlagsForInternalLink("test", "test", f); err == nil {
|
||||
t.Errorf("missing error for %q", f)
|
||||
}
|
||||
}
|
||||
|
||||
// All "good" compiler flags should not trigger external linking,
|
||||
// except for anything that begins with "-flto".
|
||||
for _, f := range goodCompilerFlags {
|
||||
foundLTO := false
|
||||
for _, s := range f {
|
||||
if strings.Contains(s, "-flto") {
|
||||
foundLTO = true
|
||||
}
|
||||
}
|
||||
if err := checkCompilerFlagsForInternalLink("test", "test", f); err != nil {
|
||||
// expect error for -flto
|
||||
if !foundLTO {
|
||||
t.Errorf("unexpected error for %q: %v", f, err)
|
||||
}
|
||||
} else {
|
||||
// expect no error for everything else
|
||||
if foundLTO {
|
||||
t.Errorf("missing error for %q: %v", f, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ func scriptConditions() map[string]script.Cond {
|
||||
add("link", lazyBool("testenv.HasLink()", testenv.HasLink))
|
||||
add("mismatched-goroot", script.Condition("test's GOROOT_FINAL does not match the real GOROOT", isMismatchedGoroot))
|
||||
add("msan", sysCondition("-msan", platform.MSanSupported, true))
|
||||
add("cgolinkext", script.BoolCondition("platform requires external linking for cgo", platform.MustLinkExternalGo121(cfg.Goos, cfg.Goarch, true)))
|
||||
add("net", lazyBool("testenv.HasExternalNetwork()", testenv.HasExternalNetwork))
|
||||
add("race", sysCondition("-race", platform.RaceDetectorSupported, true))
|
||||
add("symlink", lazyBool("testenv.HasSymlink()", testenv.HasSymlink))
|
||||
|
||||
2
src/cmd/go/testdata/script/README
vendored
2
src/cmd/go/testdata/script/README
vendored
@@ -382,6 +382,8 @@ The available conditions are:
|
||||
$WORK filesystem is case-sensitive
|
||||
[cgo]
|
||||
host CGO_ENABLED
|
||||
[cgolinkext]
|
||||
platform requires external linking for cgo
|
||||
[compiler:*]
|
||||
runtime.Compiler == <suffix>
|
||||
[cross]
|
||||
|
||||
40
src/cmd/go/testdata/script/build_issue59571.txt
vendored
Normal file
40
src/cmd/go/testdata/script/build_issue59571.txt
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
# Regression test for https://go.dev/issue/59571
|
||||
# Build should be reproducible, even with aliased generic types.
|
||||
|
||||
go build -a -o 1.a
|
||||
go build -a -o 2.a
|
||||
cmp -q 1.a 2.a
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
||||
go 1.20
|
||||
-- m.go --
|
||||
package m
|
||||
|
||||
type (
|
||||
SliceFlag[T any] struct{}
|
||||
|
||||
Alias1 = SliceFlag[[1]int]
|
||||
Alias2 = SliceFlag[[2]int]
|
||||
Alias3 = SliceFlag[[3]int]
|
||||
Alias4 = SliceFlag[[4]int]
|
||||
Alias5 = SliceFlag[[5]int]
|
||||
Alias6 = SliceFlag[[6]int]
|
||||
Alias7 = SliceFlag[[7]int]
|
||||
Alias8 = SliceFlag[[8]int]
|
||||
Alias9 = SliceFlag[[9]int]
|
||||
Alias10 = SliceFlag[[10]int]
|
||||
Alias11 = SliceFlag[[11]int]
|
||||
Alias12 = SliceFlag[[12]int]
|
||||
Alias13 = SliceFlag[[13]int]
|
||||
Alias14 = SliceFlag[[14]int]
|
||||
Alias15 = SliceFlag[[15]int]
|
||||
Alias16 = SliceFlag[[16]int]
|
||||
Alias17 = SliceFlag[[17]int]
|
||||
Alias18 = SliceFlag[[18]int]
|
||||
Alias19 = SliceFlag[[19]int]
|
||||
Alias20 = SliceFlag[[20]int]
|
||||
)
|
||||
|
||||
func (x *SliceFlag[T]) String() string { return "zzz" }
|
||||
155
src/cmd/go/testdata/script/cgo_suspect_flag_force_external.txt
vendored
Normal file
155
src/cmd/go/testdata/script/cgo_suspect_flag_force_external.txt
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
# Test case to verify that when we have a package that uses CGO in
|
||||
# combination with selected "unusual" flags (involving plugins, LTO)
|
||||
# that we force external linking. See related
|
||||
# issues 58619, 58620, and 58848.
|
||||
|
||||
[compiler:gccgo] skip # only external linking for gccgo
|
||||
|
||||
# This test requires external linking, so use cgo as a proxy
|
||||
[!cgo] skip
|
||||
|
||||
# Here we build three program: one with explicit CGO use, one with no
|
||||
# CGO use, and one that uses a stdlib package ("runtime/cgo") that has
|
||||
# CGO in it. It used to be that only the explicit use of CGO would
|
||||
# trigger external linking, and that the program that only used
|
||||
# "runtime/cgo" would always be handled with internal linking. This caused
|
||||
# issues when users included odd/unusual flags (ex: -fplugin, -flto)
|
||||
# in CGO_CFLAGS, causing the Go linker to have to read and interpret
|
||||
# non-standard host objects.
|
||||
#
|
||||
# As of 1.21 we continue to use internal linking for programs whose
|
||||
# CGO use comes ony from stdlib packages in the absence of any flag
|
||||
# funny business, however if the Go command sees flags that may be suspicious,
|
||||
# it signals the Go linker to invoke the external linker.
|
||||
|
||||
# The next few tests run builds passing "-n" to the Go command, then
|
||||
# checking the output to see if the Go command is trying to pass a
|
||||
# "preferlinkext" token to the linker to request external linking.
|
||||
|
||||
#-----------------------
|
||||
|
||||
# Use a fresh GOCACHE for these next steps, so as to have the real
|
||||
# actions for the runtime/cgo package appear in the "-n -x" output.
|
||||
env GOCACHE=$WORK/gocache
|
||||
mkdir $GOCACHE
|
||||
|
||||
# First build: there is no CGO in use, so no token should be present regardless
|
||||
# of weird CGO flags.
|
||||
go build -x -n -o dummy.exe ./noUseOfCgo
|
||||
! stderr preferlinkext
|
||||
env CGO_CFLAGS=-flto
|
||||
go build -x -n -o dummy.exe ./noUseOfCgo
|
||||
! stderr preferlinkext
|
||||
env CGO_CFLAGS=
|
||||
|
||||
# Second build uses CGO, so we expect to see the token present in the
|
||||
# -n output only when strange flags are used.
|
||||
go build -x -n -o dummy.exe ./usesInternalCgo
|
||||
! stderr preferlinkext
|
||||
env CGO_CFLAGS=-flto
|
||||
go build -x -n -o dummy.exe ./usesInternalCgo
|
||||
stderr preferlinkext
|
||||
env CGO_CFLAGS=-fplugin
|
||||
go build -x -n -o dummy.exe ./usesInternalCgo
|
||||
stderr preferlinkext
|
||||
env CGO_CFLAGS=-fprofile-instr-generate
|
||||
go build -x -n -o dummy.exe ./usesInternalCgo
|
||||
stderr preferlinkext
|
||||
env CGO_CFLAGS=
|
||||
|
||||
[short] skip
|
||||
|
||||
# In the remaining tests below we do actual builds (without -n) to
|
||||
# verify that the Go linker is going the right thing in addition to the
|
||||
# Go command. Here the idea is to pass "-tmpdir" to the linker, then
|
||||
# check after the link is done for the presence of the file
|
||||
# <tmpdir>/go.o, which the Go linker creates prior to kicking off the
|
||||
# external linker.
|
||||
|
||||
mkdir tmp1
|
||||
mkdir tmp2
|
||||
mkdir tmp3
|
||||
mkdir tmp4
|
||||
mkdir tmp5
|
||||
|
||||
# First build: no external linking expected
|
||||
go build -ldflags=-tmpdir=tmp1 -o $devnull ./noUseOfCgo &
|
||||
|
||||
# Second build: using only "runtime/cgo", expect internal linking.
|
||||
go build -ldflags=-tmpdir=tmp2 -o $devnull ./usesInternalCgo &
|
||||
|
||||
# Third build: program uses only "runtime/cgo", so we would normally
|
||||
# expect internal linking, except that cflags contain suspicious entries
|
||||
# (in this case, a flag that does not appear on the allow list).
|
||||
env CGO_CFLAGS=-fmerge-all-constants
|
||||
env CGO_LDFLAGS=-fmerge-all-constants
|
||||
go build -ldflags=-tmpdir=tmp3 -o $devnull ./usesInternalCgo &
|
||||
env CGO_CFLAGS=
|
||||
env CGO_LDFLAGS=
|
||||
|
||||
# Fourth build: explicit CGO, expect external linking.
|
||||
go build -ldflags=-tmpdir=tmp4 -o $devnull ./usesExplicitCgo &
|
||||
|
||||
# Fifth build: explicit CGO, but we specifically asked for internal linking
|
||||
# via a flag, so using internal linking it is.
|
||||
[cgolinkext] go list ./usesInternalCgo
|
||||
[!cgolinkext] go build '-ldflags=-tmpdir=tmp5 -linkmode=internal' -o $devnull ./usesInternalCgo &
|
||||
|
||||
wait
|
||||
|
||||
# Check first build: no external linking expected
|
||||
! exists tmp1/go.o
|
||||
|
||||
# Check second build: using only "runtime/cgo", expect internal linking.
|
||||
[!cgolinkext] ! exists tmp2/go.o
|
||||
[cgolinkext] exists tmp2/go.o
|
||||
|
||||
# Check third build: has suspicious flag.
|
||||
exists tmp3/go.o
|
||||
|
||||
# Fourth build: explicit CGO, expect external linking.
|
||||
exists tmp4/go.o
|
||||
|
||||
# Fifth build: explicit CGO, -linkmode=internal.
|
||||
! exists tmp5/go.o
|
||||
|
||||
-- go.mod --
|
||||
|
||||
module cgo.example
|
||||
|
||||
go 1.20
|
||||
|
||||
-- noUseOfCgo/main.go --
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
println("clean as a whistle")
|
||||
}
|
||||
|
||||
-- usesInternalCgo/main.go --
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"runtime/cgo"
|
||||
)
|
||||
|
||||
func main() {
|
||||
q := "hello"
|
||||
h := cgo.NewHandle(q)
|
||||
h.Delete()
|
||||
}
|
||||
|
||||
-- usesExplicitCgo/main.go --
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
int meaningOfLife() { return 42; }
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
println(C.meaningOfLife())
|
||||
}
|
||||
24
src/cmd/go/testdata/script/version_gc_sections.txt
vendored
Normal file
24
src/cmd/go/testdata/script/version_gc_sections.txt
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# This test checks that external linking with --gc-sections does not strip version information.
|
||||
|
||||
[short] skip
|
||||
[!cgo] skip
|
||||
[GOOS:aix] skip # no --gc-sections
|
||||
[GOOS:darwin] skip # no --gc-sections
|
||||
|
||||
go build -ldflags='-linkmode=external -extldflags=-Wl,--gc-sections'
|
||||
go version hello$GOEXE
|
||||
! stdout 'not a Go executable'
|
||||
! stderr 'not a Go executable'
|
||||
|
||||
-- go.mod --
|
||||
module hello
|
||||
-- hello.go --
|
||||
package main
|
||||
|
||||
/*
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
println("hello")
|
||||
}
|
||||
@@ -51,7 +51,7 @@ func (r *MReader) Read(p []byte) (int, error) {
|
||||
r.off += int64(amt)
|
||||
return amt, nil
|
||||
}
|
||||
return r.rdr.Read(p)
|
||||
return io.ReadFull(r.rdr, p)
|
||||
}
|
||||
|
||||
func (r *MReader) ReadByte() (byte, error) {
|
||||
|
||||
98
src/cmd/internal/cov/read_test.go
Normal file
98
src/cmd/internal/cov/read_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2022 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 cov_test
|
||||
|
||||
import (
|
||||
"cmd/internal/cov"
|
||||
"fmt"
|
||||
"internal/coverage"
|
||||
"internal/coverage/decodecounter"
|
||||
"internal/coverage/decodemeta"
|
||||
"internal/coverage/pods"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// visitor implements the CovDataVisitor interface in a very stripped
|
||||
// down way, just keeps track of interesting events.
|
||||
type visitor struct {
|
||||
metaFileCount int
|
||||
counterFileCount int
|
||||
funcCounterData int
|
||||
metaFuncCount int
|
||||
}
|
||||
|
||||
func (v *visitor) BeginPod(p pods.Pod) {}
|
||||
func (v *visitor) EndPod(p pods.Pod) {}
|
||||
func (v *visitor) VisitMetaDataFile(mdf string, mfr *decodemeta.CoverageMetaFileReader) {
|
||||
v.metaFileCount++
|
||||
}
|
||||
func (v *visitor) BeginCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) {
|
||||
v.counterFileCount++
|
||||
}
|
||||
func (v *visitor) EndCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) {}
|
||||
func (v *visitor) VisitFuncCounterData(payload decodecounter.FuncPayload) { v.funcCounterData++ }
|
||||
func (v *visitor) EndCounters() {}
|
||||
func (v *visitor) BeginPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) {}
|
||||
func (v *visitor) EndPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) {}
|
||||
func (v *visitor) VisitFunc(pkgIdx uint32, fnIdx uint32, fd *coverage.FuncDesc) { v.metaFuncCount++ }
|
||||
func (v *visitor) Finish() {}
|
||||
|
||||
func TestIssue58411(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
// Build a tiny test program with -cover. Smallness is important;
|
||||
// it is one of the factors that triggers issue 58411.
|
||||
d := t.TempDir()
|
||||
exepath := filepath.Join(d, "small.exe")
|
||||
path := filepath.Join("testdata", "small.go")
|
||||
cmd := testenv.Command(t, testenv.GoToolPath(t), "build",
|
||||
"-o", exepath, "-cover", path)
|
||||
b, err := cmd.CombinedOutput()
|
||||
if len(b) != 0 {
|
||||
t.Logf("## build output:\n%s", b)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("build error: %v", err)
|
||||
}
|
||||
|
||||
// Run to produce coverage data. Note the large argument; we need a large
|
||||
// argument (more than 4k) to trigger the bug, but the overall file
|
||||
// has to remain small (since large files will be read with mmap).
|
||||
covdir := filepath.Join(d, "covdata")
|
||||
if err = os.Mkdir(covdir, 0777); err != nil {
|
||||
t.Fatalf("creating covdir: %v", err)
|
||||
}
|
||||
large := fmt.Sprintf("%07999d", 0)
|
||||
cmd = testenv.Command(t, exepath, "1", "2", "3", large)
|
||||
cmd.Dir = covdir
|
||||
cmd.Env = append(os.Environ(), "GOCOVERDIR="+covdir)
|
||||
b, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Logf("## run output:\n%s", b)
|
||||
t.Fatalf("build error: %v", err)
|
||||
}
|
||||
|
||||
vis := &visitor{}
|
||||
|
||||
// Read resulting coverage data. Without the fix, this would
|
||||
// yield a "short read" error.
|
||||
const verbosityLevel = 0
|
||||
const flags = 0
|
||||
cdr := cov.MakeCovDataReader(vis, []string{covdir}, verbosityLevel, flags, nil)
|
||||
err = cdr.Visit()
|
||||
if err != nil {
|
||||
t.Fatalf("visit failed: %v", err)
|
||||
}
|
||||
|
||||
// make sure we saw a few things just for grins
|
||||
const want = "{metaFileCount:1 counterFileCount:1 funcCounterData:1 metaFuncCount:1}"
|
||||
got := fmt.Sprintf("%+v", *vis)
|
||||
if want != got {
|
||||
t.Errorf("visitor contents: want %v got %v\n", want, got)
|
||||
}
|
||||
}
|
||||
@@ -186,6 +186,7 @@ func (r *CovDataReader) visitPod(p pods.Pod) error {
|
||||
if err != nil {
|
||||
return r.fatal("unable to open meta-file %s", p.MetaFile)
|
||||
}
|
||||
defer f.Close()
|
||||
br := bio.NewReader(f)
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
@@ -209,6 +210,9 @@ func (r *CovDataReader) visitPod(p pods.Pod) error {
|
||||
if err != nil {
|
||||
return r.fatal("opening counter data file %s: %s", cdf, err)
|
||||
}
|
||||
defer func(f *os.File) {
|
||||
f.Close()
|
||||
}(cf)
|
||||
var mr *MReader
|
||||
mr, err = NewMreader(cf)
|
||||
if err != nil {
|
||||
|
||||
7
src/cmd/internal/cov/testdata/small.go
vendored
Normal file
7
src/cmd/internal/cov/testdata/small.go
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
import "os"
|
||||
|
||||
func main() {
|
||||
println(len(os.Args))
|
||||
}
|
||||
@@ -3132,8 +3132,13 @@ func asmout(c *ctxt9, p *obj.Prog, o *Optab, out *[5]uint32) {
|
||||
if r == 0 {
|
||||
r = c.getimpliedreg(&p.From, p)
|
||||
}
|
||||
o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v)))
|
||||
o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v))
|
||||
if o.a6 == C_REG {
|
||||
o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v)))
|
||||
o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v))
|
||||
} else {
|
||||
o1 = AOP_IRR(OP_ADDIS, uint32(REGTMP), uint32(r), uint32(high16adjusted(v)))
|
||||
o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(REGTMP), uint32(v))
|
||||
}
|
||||
|
||||
// Sign extend MOVB if needed
|
||||
o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
|
||||
@@ -3519,8 +3524,8 @@ func asmout(c *ctxt9, p *obj.Prog, o *Optab, out *[5]uint32) {
|
||||
rel.Type = objabi.R_ADDRPOWER_TOCREL_DS
|
||||
}
|
||||
default:
|
||||
reuseBaseReg := p.As != AFMOVD && p.As != AFMOVS
|
||||
// Reuse To.Reg as base register if not FP move.
|
||||
reuseBaseReg := o.a6 == C_REG
|
||||
// Reuse To.Reg as base register if it is a GPR.
|
||||
o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst, reuseBaseReg)
|
||||
}
|
||||
|
||||
|
||||
@@ -396,11 +396,28 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
|
||||
// laid out. Conservatively use a trampoline. This should be rare, as we lay out packages
|
||||
// in dependency order.
|
||||
if ldr.SymValue(rs) != 0 {
|
||||
// r.Add is the instruction
|
||||
// low 24-bit encodes the target address
|
||||
t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4
|
||||
// Workaround for issue #58425: it appears that the
|
||||
// external linker doesn't always take into account the
|
||||
// relocation addend when doing reachability checks. This
|
||||
// means that if you have a call from function XYZ at
|
||||
// offset 8 to runtime.duffzero with addend 800 (for
|
||||
// example), where the distance between the start of XYZ
|
||||
// and the start of runtime.duffzero is just over the
|
||||
// limit (by 100 bytes, say), you can get "relocation
|
||||
// doesn't fit" errors from the external linker. To deal
|
||||
// with this, ignore the addend when performing the
|
||||
// distance calculation (this assumes that we're only
|
||||
// handling backward jumps; ideally we might want to check
|
||||
// both with and without the addend).
|
||||
if ctxt.IsExternal() {
|
||||
t = (ldr.SymValue(rs) - (ldr.SymValue(s) + int64(r.Off()))) / 4
|
||||
} else {
|
||||
// r.Add is the instruction
|
||||
// low 24-bit encodes the target address
|
||||
t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4
|
||||
}
|
||||
}
|
||||
if t > 0x7fffff || t < -0x800000 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
|
||||
if t > 0x7fffff || t <= -0x800000 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
|
||||
// direct call too far, need to insert trampoline.
|
||||
// look up existing trampolines first. if we found one within the range
|
||||
// of direct call, we can reuse it. otherwise create a new one.
|
||||
|
||||
@@ -537,6 +537,13 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy
|
||||
ldr.Errorf(s, "internal error: relocation addend overflow: %s+0x%x", ldr.SymName(rs), xadd)
|
||||
}
|
||||
}
|
||||
if rt == objabi.R_CALLARM64 && xadd != 0 {
|
||||
label := ldr.Lookup(offsetLabelName(ldr, rs, xadd), ldr.SymVersion(rs))
|
||||
if label != 0 {
|
||||
xadd = ldr.SymValue(rs) + xadd - ldr.SymValue(label) // should always be 0 (checked below)
|
||||
rs = label
|
||||
}
|
||||
}
|
||||
|
||||
if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 ||
|
||||
rt == objabi.R_ARM64_PCREL_LDST8 || rt == objabi.R_ARM64_PCREL_LDST16 ||
|
||||
@@ -564,10 +571,9 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy
|
||||
v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28
|
||||
case objabi.R_CALLARM64:
|
||||
if xadd != 0 {
|
||||
out.Write32(uint32(sectoff))
|
||||
out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
|
||||
// Addend should be handled above via label symbols.
|
||||
ldr.Errorf(s, "unexpected non-zero addend: %s+%d", ldr.SymName(rs), xadd)
|
||||
}
|
||||
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
|
||||
case objabi.R_ADDRARM64,
|
||||
@@ -788,9 +794,6 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
|
||||
|
||||
case objabi.R_CALLARM64:
|
||||
nExtReloc = 1
|
||||
if target.IsDarwin() && r.Add() != 0 {
|
||||
nExtReloc = 2 // need another relocation for addend
|
||||
}
|
||||
return val, nExtReloc, isOk
|
||||
|
||||
case objabi.R_ARM64_TLS_LE:
|
||||
@@ -1184,6 +1187,9 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
|
||||
// addend. For large symbols, we generate "label" symbols in the middle, so
|
||||
// that relocations can target them with smaller addends.
|
||||
// On Windows, we only get 21 bits, again (presumably) signed.
|
||||
// Also, on Windows (always) and Darwin (for very large binaries), the external
|
||||
// linker does't support CALL relocations with addend, so we generate "label"
|
||||
// symbols for functions of which we can target the middle (Duff's devices).
|
||||
if !ctxt.IsDarwin() && !ctxt.IsWindows() || !ctxt.IsExternal() {
|
||||
return
|
||||
}
|
||||
@@ -1193,19 +1199,6 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
|
||||
limit = peRelocLimit
|
||||
}
|
||||
|
||||
if ctxt.IsDarwin() {
|
||||
big := false
|
||||
for _, seg := range ld.Segments {
|
||||
if seg.Length >= machoRelocLimit {
|
||||
big = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !big {
|
||||
return // skip work if nothing big
|
||||
}
|
||||
}
|
||||
|
||||
// addLabelSyms adds "label" symbols at s+limit, s+2*limit, etc.
|
||||
addLabelSyms := func(s loader.Sym, limit, sz int64) {
|
||||
v := ldr.SymValue(s)
|
||||
@@ -1225,23 +1218,36 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
|
||||
}
|
||||
}
|
||||
|
||||
// Generate symbol names for every offset we need in duffcopy/duffzero (only 64 each).
|
||||
if s := ldr.Lookup("runtime.duffcopy", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) {
|
||||
addLabelSyms(s, 8, 8*64)
|
||||
}
|
||||
if s := ldr.Lookup("runtime.duffzero", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) {
|
||||
addLabelSyms(s, 4, 4*64)
|
||||
}
|
||||
|
||||
if ctxt.IsDarwin() {
|
||||
big := false
|
||||
for _, seg := range ld.Segments {
|
||||
if seg.Length >= machoRelocLimit {
|
||||
big = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !big {
|
||||
return // skip work if nothing big
|
||||
}
|
||||
}
|
||||
|
||||
for s, n := loader.Sym(1), loader.Sym(ldr.NSym()); s < n; s++ {
|
||||
if !ldr.AttrReachable(s) {
|
||||
continue
|
||||
}
|
||||
t := ldr.SymType(s)
|
||||
if t == sym.STEXT {
|
||||
if ctxt.IsDarwin() || ctxt.IsWindows() {
|
||||
// Cannot relocate into middle of function.
|
||||
// Generate symbol names for every offset we need in duffcopy/duffzero (only 64 each).
|
||||
switch ldr.SymName(s) {
|
||||
case "runtime.duffcopy":
|
||||
addLabelSyms(s, 8, 8*64)
|
||||
case "runtime.duffzero":
|
||||
addLabelSyms(s, 4, 4*64)
|
||||
}
|
||||
}
|
||||
continue // we don't target the middle of other functions
|
||||
// Except for Duff's devices (handled above), we don't
|
||||
// target the middle of a function.
|
||||
continue
|
||||
}
|
||||
if t >= sym.SDWARFSECT {
|
||||
continue // no need to add label for DWARF symbols
|
||||
|
||||
@@ -281,7 +281,11 @@ func determineLinkMode(ctxt *Link) {
|
||||
ctxt.LinkMode = LinkExternal
|
||||
via = "via GO_EXTLINK_ENABLED "
|
||||
default:
|
||||
if extNeeded || (iscgo && externalobj) {
|
||||
preferExternal := len(preferlinkext) != 0
|
||||
if preferExternal && ctxt.Debugvlog > 0 {
|
||||
ctxt.Logf("external linking prefer list is %v\n", preferlinkext)
|
||||
}
|
||||
if extNeeded || (iscgo && (externalobj || preferExternal)) {
|
||||
ctxt.LinkMode = LinkExternal
|
||||
} else {
|
||||
ctxt.LinkMode = LinkInternal
|
||||
|
||||
@@ -1669,6 +1669,9 @@ func (ctxt *Link) dodata(symGroupType []sym.SymKind) {
|
||||
func (state *dodataState) allocateDataSectionForSym(seg *sym.Segment, s loader.Sym, rwx int) *sym.Section {
|
||||
ldr := state.ctxt.loader
|
||||
sname := ldr.SymName(s)
|
||||
if strings.HasPrefix(sname, "go:") {
|
||||
sname = ".go." + sname[len("go:"):]
|
||||
}
|
||||
sect := addsection(ldr, state.ctxt.Arch, seg, sname, rwx)
|
||||
sect.Align = symalign(ldr, s)
|
||||
state.datsize = Rnd(state.datsize, int64(sect.Align))
|
||||
@@ -2254,7 +2257,7 @@ func (ctxt *Link) buildinfo() {
|
||||
// Write the buildinfo symbol, which go version looks for.
|
||||
// The code reading this data is in package debug/buildinfo.
|
||||
ldr := ctxt.loader
|
||||
s := ldr.CreateSymForUpdate(".go.buildinfo", 0)
|
||||
s := ldr.CreateSymForUpdate("go:buildinfo", 0)
|
||||
s.SetType(sym.SBUILDINFO)
|
||||
s.SetAlign(16)
|
||||
// The \xff is invalid UTF-8, meant to make it less likely
|
||||
@@ -2276,6 +2279,14 @@ func (ctxt *Link) buildinfo() {
|
||||
}
|
||||
s.SetData(data)
|
||||
s.SetSize(int64(len(data)))
|
||||
|
||||
// Add reference to go:buildinfo from the rodata section,
|
||||
// so that external linking with -Wl,--gc-sections does not
|
||||
// delete the build info.
|
||||
sr := ldr.CreateSymForUpdate("go:buildinfo.ref", 0)
|
||||
sr.SetType(sym.SRODATA)
|
||||
sr.SetAlign(int32(ctxt.Arch.PtrSize))
|
||||
sr.AddAddr(ctxt.Arch, s.Sym())
|
||||
}
|
||||
|
||||
// appendString appends s to data, prefixed by its varint-encoded length.
|
||||
|
||||
@@ -350,6 +350,12 @@ var (
|
||||
// any of these objects, we must link externally. Issue 52863.
|
||||
dynimportfail []string
|
||||
|
||||
// preferlinkext is a list of packages for which the Go command
|
||||
// noticed use of peculiar C flags. If we see any of these,
|
||||
// default to linking externally unless overridden by the
|
||||
// user. See issues #58619, #58620, and #58848.
|
||||
preferlinkext []string
|
||||
|
||||
// unknownObjFormat is set to true if we see an object whose
|
||||
// format we don't recognize.
|
||||
unknownObjFormat = false
|
||||
@@ -1072,6 +1078,13 @@ func loadobjfile(ctxt *Link, lib *sym.Library) {
|
||||
if arhdr.name == "dynimportfail" {
|
||||
dynimportfail = append(dynimportfail, lib.Pkg)
|
||||
}
|
||||
if arhdr.name == "preferlinkext" {
|
||||
// Ignore this directive if -linkmode has been
|
||||
// set explicitly.
|
||||
if ctxt.LinkMode == LinkAuto {
|
||||
preferlinkext = append(preferlinkext, lib.Pkg)
|
||||
}
|
||||
}
|
||||
|
||||
// Skip other special (non-object-file) sections that
|
||||
// build tools may have added. Such sections must have
|
||||
|
||||
5
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
generated
vendored
5
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
generated
vendored
@@ -303,6 +303,11 @@ func parallelSubtest(info *types.Info, call *ast.CallExpr) []ast.Stmt {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(call.Args) != 2 {
|
||||
// Ignore calls such as t.Run(fn()).
|
||||
return nil
|
||||
}
|
||||
|
||||
lit, _ := call.Args[1].(*ast.FuncLit)
|
||||
if lit == nil {
|
||||
return nil
|
||||
|
||||
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
generated
vendored
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
generated
vendored
@@ -910,7 +910,7 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o
|
||||
if reason != "" {
|
||||
details = " (" + reason + ")"
|
||||
}
|
||||
pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s%s, see also https://pkg.go.dev/fmt#hdr-Printing", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString, details)
|
||||
pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s%s", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString, details)
|
||||
return false
|
||||
}
|
||||
if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) {
|
||||
|
||||
2
src/cmd/vendor/modules.txt
vendored
2
src/cmd/vendor/modules.txt
vendored
@@ -46,7 +46,7 @@ golang.org/x/sys/windows
|
||||
# golang.org/x/term v0.2.0
|
||||
## explicit; go 1.17
|
||||
golang.org/x/term
|
||||
# golang.org/x/tools v0.3.1-0.20221121233702-060c049c4674
|
||||
# golang.org/x/tools v0.3.1-0.20230118190848-070db2996ebe
|
||||
## explicit; go 1.18
|
||||
golang.org/x/tools/cover
|
||||
golang.org/x/tools/go/analysis
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"crypto"
|
||||
"crypto/internal/boring"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
@@ -109,7 +110,8 @@ type PrivateKey struct {
|
||||
publicKeyOnce sync.Once
|
||||
}
|
||||
|
||||
// ECDH performs a ECDH exchange and returns the shared secret.
|
||||
// ECDH performs a ECDH exchange and returns the shared secret. The PrivateKey
|
||||
// and PublicKey must use the same curve.
|
||||
//
|
||||
// For NIST curves, this performs ECDH as specified in SEC 1, Version 2.0,
|
||||
// Section 3.3.1, and returns the x-coordinate encoded according to SEC 1,
|
||||
@@ -118,6 +120,9 @@ type PrivateKey struct {
|
||||
// For X25519, this performs ECDH as specified in RFC 7748, Section 6.1. If
|
||||
// the result is the all-zero value, ECDH returns an error.
|
||||
func (k *PrivateKey) ECDH(remote *PublicKey) ([]byte, error) {
|
||||
if k.curve != remote.curve {
|
||||
return nil, errors.New("crypto/ecdh: private key and public key curves do not match")
|
||||
}
|
||||
return k.curve.ecdh(k, remote)
|
||||
}
|
||||
|
||||
|
||||
@@ -487,3 +487,39 @@ func TestLinker(t *testing.T) {
|
||||
t.Error("no P384 symbols found in program using ecdh.P384, test is broken")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMismatchedCurves(t *testing.T) {
|
||||
curves := []struct {
|
||||
name string
|
||||
curve ecdh.Curve
|
||||
}{
|
||||
{"P256", ecdh.P256()},
|
||||
{"P384", ecdh.P384()},
|
||||
{"P521", ecdh.P521()},
|
||||
{"X25519", ecdh.X25519()},
|
||||
}
|
||||
|
||||
for _, privCurve := range curves {
|
||||
priv, err := privCurve.curve.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to generate test key: %s", err)
|
||||
}
|
||||
|
||||
for _, pubCurve := range curves {
|
||||
if privCurve == pubCurve {
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("%s/%s", privCurve.name, pubCurve.name), func(t *testing.T) {
|
||||
pub, err := pubCurve.curve.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to generate test key: %s", err)
|
||||
}
|
||||
expected := "crypto/ecdh: private key and public key curves do not match"
|
||||
_, err = priv.ECDH(pub.PublicKey())
|
||||
if err.Error() != expected {
|
||||
t.Fatalf("unexpected error: want %q, got %q", expected, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ func main() {
|
||||
ConstraintExpr("amd64,gc,!purego")
|
||||
|
||||
Implement("montgomeryLoop")
|
||||
Pragma("noescape")
|
||||
|
||||
size := Load(Param("d").Len(), GP64())
|
||||
d := Mem{Base: Load(Param("d").Base(), GP64())}
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
|
||||
package bigmod
|
||||
|
||||
//go:noescape
|
||||
func montgomeryLoop(d []uint, a []uint, b []uint, m []uint, m0inv uint) uint
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/elliptic"
|
||||
"crypto/internal/nistec"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
@@ -165,6 +166,86 @@ func testEquivalents[P nistPoint[P]](t *testing.T, newPoint func() P, c elliptic
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarMult(t *testing.T) {
|
||||
t.Run("P224", func(t *testing.T) {
|
||||
testScalarMult(t, nistec.NewP224Point, elliptic.P224())
|
||||
})
|
||||
t.Run("P256", func(t *testing.T) {
|
||||
testScalarMult(t, nistec.NewP256Point, elliptic.P256())
|
||||
})
|
||||
t.Run("P384", func(t *testing.T) {
|
||||
testScalarMult(t, nistec.NewP384Point, elliptic.P384())
|
||||
})
|
||||
t.Run("P521", func(t *testing.T) {
|
||||
testScalarMult(t, nistec.NewP521Point, elliptic.P521())
|
||||
})
|
||||
}
|
||||
|
||||
func testScalarMult[P nistPoint[P]](t *testing.T, newPoint func() P, c elliptic.Curve) {
|
||||
G := newPoint().SetGenerator()
|
||||
checkScalar := func(t *testing.T, scalar []byte) {
|
||||
p1, err := newPoint().ScalarBaseMult(scalar)
|
||||
fatalIfErr(t, err)
|
||||
p2, err := newPoint().ScalarMult(G, scalar)
|
||||
fatalIfErr(t, err)
|
||||
if !bytes.Equal(p1.Bytes(), p2.Bytes()) {
|
||||
t.Error("[k]G != ScalarBaseMult(k)")
|
||||
}
|
||||
|
||||
d := new(big.Int).SetBytes(scalar)
|
||||
d.Sub(c.Params().N, d)
|
||||
d.Mod(d, c.Params().N)
|
||||
g1, err := newPoint().ScalarBaseMult(d.FillBytes(make([]byte, len(scalar))))
|
||||
fatalIfErr(t, err)
|
||||
g1.Add(g1, p1)
|
||||
if !bytes.Equal(g1.Bytes(), newPoint().Bytes()) {
|
||||
t.Error("[N - k]G + [k]G != ∞")
|
||||
}
|
||||
}
|
||||
|
||||
byteLen := len(c.Params().N.Bytes())
|
||||
bitLen := c.Params().N.BitLen()
|
||||
t.Run("0", func(t *testing.T) { checkScalar(t, make([]byte, byteLen)) })
|
||||
t.Run("1", func(t *testing.T) {
|
||||
checkScalar(t, big.NewInt(1).FillBytes(make([]byte, byteLen)))
|
||||
})
|
||||
t.Run("N-1", func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Sub(c.Params().N, big.NewInt(1)).Bytes())
|
||||
})
|
||||
t.Run("N", func(t *testing.T) { checkScalar(t, c.Params().N.Bytes()) })
|
||||
t.Run("N+1", func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Add(c.Params().N, big.NewInt(1)).Bytes())
|
||||
})
|
||||
t.Run("all1s", func(t *testing.T) {
|
||||
s := new(big.Int).Lsh(big.NewInt(1), uint(bitLen))
|
||||
s.Sub(s, big.NewInt(1))
|
||||
checkScalar(t, s.Bytes())
|
||||
})
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
for i := 0; i < bitLen; i++ {
|
||||
t.Run(fmt.Sprintf("1<<%d", i), func(t *testing.T) {
|
||||
s := new(big.Int).Lsh(big.NewInt(1), uint(i))
|
||||
checkScalar(t, s.FillBytes(make([]byte, byteLen)))
|
||||
})
|
||||
}
|
||||
// Test N+1...N+32 since they risk overlapping with precomputed table values
|
||||
// in the final additions.
|
||||
for i := int64(2); i <= 32; i++ {
|
||||
t.Run(fmt.Sprintf("N+%d", i), func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Add(c.Params().N, big.NewInt(i)).Bytes())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func fatalIfErr(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkScalarMult(b *testing.B) {
|
||||
b.Run("P224", func(b *testing.B) {
|
||||
benchmarkScalarMult(b, nistec.NewP224Point().SetGenerator(), 28)
|
||||
|
||||
@@ -364,6 +364,21 @@ func p256PointDoubleAsm(res, in *P256Point)
|
||||
// Montgomery domain (with R 2²⁵⁶) as four uint64 limbs in little-endian order.
|
||||
type p256OrdElement [4]uint64
|
||||
|
||||
// p256OrdReduce ensures s is in the range [0, ord(G)-1].
|
||||
func p256OrdReduce(s *p256OrdElement) {
|
||||
// Since 2 * ord(G) > 2²⁵⁶, we can just conditionally subtract ord(G),
|
||||
// keeping the result if it doesn't underflow.
|
||||
t0, b := bits.Sub64(s[0], 0xf3b9cac2fc632551, 0)
|
||||
t1, b := bits.Sub64(s[1], 0xbce6faada7179e84, b)
|
||||
t2, b := bits.Sub64(s[2], 0xffffffffffffffff, b)
|
||||
t3, b := bits.Sub64(s[3], 0xffffffff00000000, b)
|
||||
tMask := b - 1 // zero if subtraction underflowed
|
||||
s[0] ^= (t0 ^ s[0]) & tMask
|
||||
s[1] ^= (t1 ^ s[1]) & tMask
|
||||
s[2] ^= (t2 ^ s[2]) & tMask
|
||||
s[3] ^= (t3 ^ s[3]) & tMask
|
||||
}
|
||||
|
||||
// Add sets q = p1 + p2, and returns q. The points may overlap.
|
||||
func (q *P256Point) Add(r1, r2 *P256Point) *P256Point {
|
||||
var sum, double P256Point
|
||||
@@ -393,6 +408,7 @@ func (r *P256Point) ScalarBaseMult(scalar []byte) (*P256Point, error) {
|
||||
}
|
||||
scalarReversed := new(p256OrdElement)
|
||||
p256OrdBigToLittle(scalarReversed, (*[32]byte)(scalar))
|
||||
p256OrdReduce(scalarReversed)
|
||||
|
||||
r.p256BaseMult(scalarReversed)
|
||||
return r, nil
|
||||
@@ -407,6 +423,7 @@ func (r *P256Point) ScalarMult(q *P256Point, scalar []byte) (*P256Point, error)
|
||||
}
|
||||
scalarReversed := new(p256OrdElement)
|
||||
p256OrdBigToLittle(scalarReversed, (*[32]byte)(scalar))
|
||||
p256OrdReduce(scalarReversed)
|
||||
|
||||
r.Set(q).p256ScalarMult(scalarReversed)
|
||||
return r, nil
|
||||
|
||||
@@ -25,6 +25,7 @@ func P256OrdInverse(k []byte) ([]byte, error) {
|
||||
|
||||
x := new(p256OrdElement)
|
||||
p256OrdBigToLittle(x, (*[32]byte)(k))
|
||||
p256OrdReduce(x)
|
||||
|
||||
// Inversion is implemented as exponentiation by n - 2, per Fermat's little theorem.
|
||||
//
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/internal/boring"
|
||||
"crypto/rand"
|
||||
. "crypto/rsa"
|
||||
"crypto/sha1"
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
"encoding/pem"
|
||||
"flag"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -129,6 +131,31 @@ func testKeyBasics(t *testing.T, priv *PrivateKey) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocations(t *testing.T) {
|
||||
if boring.Enabled {
|
||||
t.Skip("skipping allocations test with BoringCrypto")
|
||||
}
|
||||
testenv.SkipIfOptimizationOff(t)
|
||||
|
||||
m := []byte("Hello Gophers")
|
||||
c, err := EncryptPKCS1v15(rand.Reader, &test2048Key.PublicKey, m)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if allocs := testing.AllocsPerRun(100, func() {
|
||||
p, err := DecryptPKCS1v15(nil, test2048Key, c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(p, m) {
|
||||
t.Fatalf("unexpected output: %q", p)
|
||||
}
|
||||
}); allocs > 10 {
|
||||
t.Errorf("expected less than 10 allocations, got %0.1f", allocs)
|
||||
}
|
||||
}
|
||||
|
||||
var allFlag = flag.Bool("all", false, "test all key sizes up to 2048")
|
||||
|
||||
func TestEverything(t *testing.T) {
|
||||
|
||||
@@ -46,7 +46,13 @@ func aligned(dst, x, y *byte) bool {
|
||||
// words returns a []uintptr pointing at the same data as x,
|
||||
// with any trailing partial word removed.
|
||||
func words(x []byte) []uintptr {
|
||||
return unsafe.Slice((*uintptr)(unsafe.Pointer(&x[0])), uintptr(len(x))/wordSize)
|
||||
n := uintptr(len(x)) / wordSize
|
||||
if n == 0 {
|
||||
// Avoid creating a *uintptr that refers to data smaller than a uintptr;
|
||||
// see issue 59334.
|
||||
return nil
|
||||
}
|
||||
return unsafe.Slice((*uintptr)(unsafe.Pointer(&x[0])), n)
|
||||
}
|
||||
|
||||
func xorLoop[T byte | uintptr](dst, x, y []T) {
|
||||
|
||||
@@ -269,7 +269,7 @@ func TestBoringClientHello(t *testing.T) {
|
||||
|
||||
go Client(c, clientConfig).Handshake()
|
||||
srv := Server(s, testConfig)
|
||||
msg, err := srv.readHandshake()
|
||||
msg, err := srv.readHandshake(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1394,7 +1394,7 @@ func (c *Certificate) leaf() (*x509.Certificate, error) {
|
||||
}
|
||||
|
||||
type handshakeMessage interface {
|
||||
marshal() []byte
|
||||
marshal() ([]byte, error)
|
||||
unmarshal([]byte) bool
|
||||
}
|
||||
|
||||
|
||||
@@ -1004,18 +1004,37 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// writeRecord writes a TLS record with the given type and payload to the
|
||||
// connection and updates the record layer state.
|
||||
func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
|
||||
// writeHandshakeRecord writes a handshake message to the connection and updates
|
||||
// the record layer state. If transcript is non-nil the marshalled message is
|
||||
// written to it.
|
||||
func (c *Conn) writeHandshakeRecord(msg handshakeMessage, transcript transcriptHash) (int, error) {
|
||||
c.out.Lock()
|
||||
defer c.out.Unlock()
|
||||
|
||||
return c.writeRecordLocked(typ, data)
|
||||
data, err := msg.marshal()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if transcript != nil {
|
||||
transcript.Write(data)
|
||||
}
|
||||
|
||||
return c.writeRecordLocked(recordTypeHandshake, data)
|
||||
}
|
||||
|
||||
// writeChangeCipherRecord writes a ChangeCipherSpec message to the connection and
|
||||
// updates the record layer state.
|
||||
func (c *Conn) writeChangeCipherRecord() error {
|
||||
c.out.Lock()
|
||||
defer c.out.Unlock()
|
||||
_, err := c.writeRecordLocked(recordTypeChangeCipherSpec, []byte{1})
|
||||
return err
|
||||
}
|
||||
|
||||
// readHandshake reads the next handshake message from
|
||||
// the record layer.
|
||||
func (c *Conn) readHandshake() (any, error) {
|
||||
// the record layer. If transcript is non-nil, the message
|
||||
// is written to the passed transcriptHash.
|
||||
func (c *Conn) readHandshake(transcript transcriptHash) (any, error) {
|
||||
for c.hand.Len() < 4 {
|
||||
if err := c.readRecord(); err != nil {
|
||||
return nil, err
|
||||
@@ -1094,6 +1113,11 @@ func (c *Conn) readHandshake() (any, error) {
|
||||
if !m.unmarshal(data) {
|
||||
return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
|
||||
}
|
||||
|
||||
if transcript != nil {
|
||||
transcript.Write(data)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
@@ -1169,7 +1193,7 @@ func (c *Conn) handleRenegotiation() error {
|
||||
return errors.New("tls: internal error: unexpected renegotiation")
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1215,7 +1239,7 @@ func (c *Conn) handlePostHandshakeMessage() error {
|
||||
return c.handleRenegotiation()
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1251,7 +1275,11 @@ func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
|
||||
defer c.out.Unlock()
|
||||
|
||||
msg := &keyUpdateMsg{}
|
||||
_, err := c.writeRecordLocked(recordTypeHandshake, msg.marshal())
|
||||
msgBytes, err := msg.marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.writeRecordLocked(recordTypeHandshake, msgBytes)
|
||||
if err != nil {
|
||||
// Surface the error at the next write.
|
||||
c.out.setErrorLocked(err)
|
||||
|
||||
@@ -162,7 +162,10 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
}
|
||||
c.serverName = hello.serverName
|
||||
|
||||
cacheKey, session, earlySecret, binderKey := c.loadSession(hello)
|
||||
cacheKey, session, earlySecret, binderKey, err := c.loadSession(hello)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cacheKey != "" && session != nil {
|
||||
defer func() {
|
||||
// If we got a handshake failure when resuming a session, throw away
|
||||
@@ -177,11 +180,12 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
}()
|
||||
}
|
||||
|
||||
if _, err := c.writeRecord(recordTypeHandshake, hello.marshal()); err != nil {
|
||||
if _, err := c.writeHandshakeRecord(hello, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
// serverHelloMsg is not included in the transcript
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -246,9 +250,9 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
session *ClientSessionState, earlySecret, binderKey []byte) {
|
||||
session *ClientSessionState, earlySecret, binderKey []byte, err error) {
|
||||
if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
|
||||
return "", nil, nil, nil
|
||||
return "", nil, nil, nil, nil
|
||||
}
|
||||
|
||||
hello.ticketSupported = true
|
||||
@@ -263,14 +267,14 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
// renegotiation is primarily used to allow a client to send a client
|
||||
// certificate, which would be skipped if session resumption occurred.
|
||||
if c.handshakes != 0 {
|
||||
return "", nil, nil, nil
|
||||
return "", nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// Try to resume a previously negotiated TLS session, if available.
|
||||
cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
|
||||
session, ok := c.config.ClientSessionCache.Get(cacheKey)
|
||||
if !ok || session == nil {
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// Check that version used for the previous session is still valid.
|
||||
@@ -282,7 +286,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
}
|
||||
}
|
||||
if !versOk {
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// Check that the cached server certificate is not expired, and that it's
|
||||
@@ -291,16 +295,16 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
if !c.config.InsecureSkipVerify {
|
||||
if len(session.verifiedChains) == 0 {
|
||||
// The original connection had InsecureSkipVerify, while this doesn't.
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
serverCert := session.serverCertificates[0]
|
||||
if c.config.time().After(serverCert.NotAfter) {
|
||||
// Expired certificate, delete the entry.
|
||||
c.config.ClientSessionCache.Put(cacheKey, nil)
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
if err := serverCert.VerifyHostname(c.config.ServerName); err != nil {
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +312,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
// In TLS 1.2 the cipher suite must match the resumed session. Ensure we
|
||||
// are still offering it.
|
||||
if mutualCipherSuite(hello.cipherSuites, session.cipherSuite) == nil {
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
hello.sessionTicket = session.sessionTicket
|
||||
@@ -318,14 +322,14 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
// Check that the session ticket is not expired.
|
||||
if c.config.time().After(session.useBy) {
|
||||
c.config.ClientSessionCache.Put(cacheKey, nil)
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// In TLS 1.3 the KDF hash must match the resumed session. Ensure we
|
||||
// offer at least one cipher suite with that hash.
|
||||
cipherSuite := cipherSuiteTLS13ByID(session.cipherSuite)
|
||||
if cipherSuite == nil {
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
cipherSuiteOk := false
|
||||
for _, offeredID := range hello.cipherSuites {
|
||||
@@ -336,7 +340,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
}
|
||||
}
|
||||
if !cipherSuiteOk {
|
||||
return cacheKey, nil, nil, nil
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1.
|
||||
@@ -354,9 +358,15 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
earlySecret = cipherSuite.extract(psk, nil)
|
||||
binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil)
|
||||
transcript := cipherSuite.hash.New()
|
||||
transcript.Write(hello.marshalWithoutBinders())
|
||||
helloBytes, err := hello.marshalWithoutBinders()
|
||||
if err != nil {
|
||||
return "", nil, nil, nil, err
|
||||
}
|
||||
transcript.Write(helloBytes)
|
||||
pskBinders := [][]byte{cipherSuite.finishedHash(binderKey, transcript)}
|
||||
hello.updateBinders(pskBinders)
|
||||
if err := hello.updateBinders(pskBinders); err != nil {
|
||||
return "", nil, nil, nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -401,8 +411,12 @@ func (hs *clientHandshakeState) handshake() error {
|
||||
hs.finishedHash.discardHandshakeBuffer()
|
||||
}
|
||||
|
||||
hs.finishedHash.Write(hs.hello.marshal())
|
||||
hs.finishedHash.Write(hs.serverHello.marshal())
|
||||
if err := transcriptMsg(hs.hello, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := transcriptMsg(hs.serverHello, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.buffering = true
|
||||
c.didResume = isResume
|
||||
@@ -473,7 +487,7 @@ func (hs *clientHandshakeState) pickCipherSuite() error {
|
||||
func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
c := hs.c
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
msg, err := c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -482,9 +496,8 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certMsg, msg)
|
||||
}
|
||||
hs.finishedHash.Write(certMsg.marshal())
|
||||
|
||||
msg, err = c.readHandshake()
|
||||
msg, err = c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -502,11 +515,10 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return errors.New("tls: received unexpected CertificateStatus message")
|
||||
}
|
||||
hs.finishedHash.Write(cs.marshal())
|
||||
|
||||
c.ocspResponse = cs.response
|
||||
|
||||
msg, err = c.readHandshake()
|
||||
msg, err = c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -535,14 +547,13 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
|
||||
skx, ok := msg.(*serverKeyExchangeMsg)
|
||||
if ok {
|
||||
hs.finishedHash.Write(skx.marshal())
|
||||
err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx)
|
||||
if err != nil {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err = c.readHandshake()
|
||||
msg, err = c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -553,7 +564,6 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
certReq, ok := msg.(*certificateRequestMsg)
|
||||
if ok {
|
||||
certRequested = true
|
||||
hs.finishedHash.Write(certReq.marshal())
|
||||
|
||||
cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq)
|
||||
if chainToSend, err = c.getClientCertificate(cri); err != nil {
|
||||
@@ -561,7 +571,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err = c.readHandshake()
|
||||
msg, err = c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -572,7 +582,6 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(shd, msg)
|
||||
}
|
||||
hs.finishedHash.Write(shd.marshal())
|
||||
|
||||
// If the server requested a certificate then we have to send a
|
||||
// Certificate message, even if it's empty because we don't have a
|
||||
@@ -580,8 +589,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
if certRequested {
|
||||
certMsg = new(certificateMsg)
|
||||
certMsg.certificates = chainToSend.Certificate
|
||||
hs.finishedHash.Write(certMsg.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -592,8 +600,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
return err
|
||||
}
|
||||
if ckx != nil {
|
||||
hs.finishedHash.Write(ckx.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, ckx.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(ckx, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -640,8 +647,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
return err
|
||||
}
|
||||
|
||||
hs.finishedHash.Write(certVerify.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, certVerify.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(certVerify, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -776,7 +782,10 @@ func (hs *clientHandshakeState) readFinished(out []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
// finishedMsg is included in the transcript, but not until after we
|
||||
// check the client version, since the state before this message was
|
||||
// sent is used during verification.
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -792,7 +801,11 @@ func (hs *clientHandshakeState) readFinished(out []byte) error {
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return errors.New("tls: server's Finished message was incorrect")
|
||||
}
|
||||
hs.finishedHash.Write(serverFinished.marshal())
|
||||
|
||||
if err := transcriptMsg(serverFinished, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
copy(out, verify)
|
||||
return nil
|
||||
}
|
||||
@@ -803,7 +816,7 @@ func (hs *clientHandshakeState) readSessionTicket() error {
|
||||
}
|
||||
|
||||
c := hs.c
|
||||
msg, err := c.readHandshake()
|
||||
msg, err := c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -812,7 +825,6 @@ func (hs *clientHandshakeState) readSessionTicket() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(sessionTicketMsg, msg)
|
||||
}
|
||||
hs.finishedHash.Write(sessionTicketMsg.marshal())
|
||||
|
||||
hs.session = &ClientSessionState{
|
||||
sessionTicket: sessionTicketMsg.ticket,
|
||||
@@ -832,14 +844,13 @@ func (hs *clientHandshakeState) readSessionTicket() error {
|
||||
func (hs *clientHandshakeState) sendFinished(out []byte) error {
|
||||
c := hs.c
|
||||
|
||||
if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
|
||||
if err := c.writeChangeCipherRecord(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
finished := new(finishedMsg)
|
||||
finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
|
||||
hs.finishedHash.Write(finished.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
copy(out, finished.verifyData)
|
||||
|
||||
@@ -1028,6 +1028,27 @@ func testResumption(t *testing.T, version uint16) {
|
||||
deleteTicket()
|
||||
testResumeState("WithoutSessionTicket", false)
|
||||
|
||||
// In TLS 1.3, HelloRetryRequest is sent after incorrect key share.
|
||||
// See https://www.rfc-editor.org/rfc/rfc8446#page-14.
|
||||
if version == VersionTLS13 {
|
||||
deleteTicket()
|
||||
serverConfig = &Config{
|
||||
// Use a different curve than the client to force a HelloRetryRequest.
|
||||
CurvePreferences: []CurveID{CurveP521, CurveP384, CurveP256},
|
||||
MaxVersion: version,
|
||||
Certificates: testConfig.Certificates,
|
||||
}
|
||||
testResumeState("InitialHandshake", false)
|
||||
testResumeState("WithHelloRetryRequest", true)
|
||||
|
||||
// Reset serverConfig back.
|
||||
serverConfig = &Config{
|
||||
MaxVersion: version,
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
|
||||
Certificates: testConfig.Certificates,
|
||||
}
|
||||
}
|
||||
|
||||
// Session resumption should work when using client certificates
|
||||
deleteTicket()
|
||||
serverConfig.ClientCAs = rootCAs
|
||||
@@ -1257,7 +1278,7 @@ func TestServerSelectingUnconfiguredApplicationProtocol(t *testing.T) {
|
||||
cipherSuite: TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
alpnProtocol: "how-about-this",
|
||||
}
|
||||
serverHelloBytes := serverHello.marshal()
|
||||
serverHelloBytes := mustMarshal(t, serverHello)
|
||||
|
||||
s.Write([]byte{
|
||||
byte(recordTypeHandshake),
|
||||
@@ -1500,7 +1521,7 @@ func TestServerSelectingUnconfiguredCipherSuite(t *testing.T) {
|
||||
random: make([]byte, 32),
|
||||
cipherSuite: TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
}
|
||||
serverHelloBytes := serverHello.marshal()
|
||||
serverHelloBytes := mustMarshal(t, serverHello)
|
||||
|
||||
s.Write([]byte{
|
||||
byte(recordTypeHandshake),
|
||||
|
||||
@@ -62,7 +62,10 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
|
||||
}
|
||||
|
||||
hs.transcript = hs.suite.hash.New()
|
||||
hs.transcript.Write(hs.hello.marshal())
|
||||
|
||||
if err := transcriptMsg(hs.hello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
|
||||
if err := hs.sendDummyChangeCipherSpec(); err != nil {
|
||||
@@ -73,7 +76,9 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
|
||||
}
|
||||
}
|
||||
|
||||
hs.transcript.Write(hs.serverHello.marshal())
|
||||
if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.buffering = true
|
||||
if err := hs.processServerHello(); err != nil {
|
||||
@@ -172,8 +177,7 @@ func (hs *clientHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
|
||||
}
|
||||
hs.sentDummyCCS = true
|
||||
|
||||
_, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
|
||||
return err
|
||||
return hs.c.writeChangeCipherRecord()
|
||||
}
|
||||
|
||||
// processHelloRetryRequest handles the HRR in hs.serverHello, modifies and
|
||||
@@ -188,7 +192,9 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
|
||||
hs.transcript.Reset()
|
||||
hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
|
||||
hs.transcript.Write(chHash)
|
||||
hs.transcript.Write(hs.serverHello.marshal())
|
||||
if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The only HelloRetryRequest extensions we support are key_share and
|
||||
// cookie, and clients must abort the handshake if the HRR would not result
|
||||
@@ -253,10 +259,18 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
|
||||
transcript := hs.suite.hash.New()
|
||||
transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
|
||||
transcript.Write(chHash)
|
||||
transcript.Write(hs.serverHello.marshal())
|
||||
transcript.Write(hs.hello.marshalWithoutBinders())
|
||||
if err := transcriptMsg(hs.serverHello, transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
helloBytes, err := hs.hello.marshalWithoutBinders()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
transcript.Write(helloBytes)
|
||||
pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)}
|
||||
hs.hello.updateBinders(pskBinders)
|
||||
if err := hs.hello.updateBinders(pskBinders); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Server selected a cipher suite incompatible with the PSK.
|
||||
hs.hello.pskIdentities = nil
|
||||
@@ -264,12 +278,12 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
|
||||
}
|
||||
}
|
||||
|
||||
hs.transcript.Write(hs.hello.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
// serverHelloMsg is not included in the transcript
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -363,6 +377,7 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
|
||||
if !hs.usingPSK {
|
||||
earlySecret = hs.suite.extract(nil, nil)
|
||||
}
|
||||
|
||||
handshakeSecret := hs.suite.extract(sharedKey,
|
||||
hs.suite.deriveSecret(earlySecret, "derived", nil))
|
||||
|
||||
@@ -393,7 +408,7 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
|
||||
func (hs *clientHandshakeStateTLS13) readServerParameters() error {
|
||||
c := hs.c
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
msg, err := c.readHandshake(hs.transcript)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -403,7 +418,6 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(encryptedExtensions, msg)
|
||||
}
|
||||
hs.transcript.Write(encryptedExtensions.marshal())
|
||||
|
||||
if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol); err != nil {
|
||||
c.sendAlert(alertUnsupportedExtension)
|
||||
@@ -432,18 +446,16 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
msg, err := c.readHandshake(hs.transcript)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certReq, ok := msg.(*certificateRequestMsgTLS13)
|
||||
if ok {
|
||||
hs.transcript.Write(certReq.marshal())
|
||||
|
||||
hs.certReq = certReq
|
||||
|
||||
msg, err = c.readHandshake()
|
||||
msg, err = c.readHandshake(hs.transcript)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -458,7 +470,6 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
|
||||
c.sendAlert(alertDecodeError)
|
||||
return errors.New("tls: received empty certificates message")
|
||||
}
|
||||
hs.transcript.Write(certMsg.marshal())
|
||||
|
||||
c.scts = certMsg.certificate.SignedCertificateTimestamps
|
||||
c.ocspResponse = certMsg.certificate.OCSPStaple
|
||||
@@ -467,7 +478,10 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err = c.readHandshake()
|
||||
// certificateVerifyMsg is included in the transcript, but not until
|
||||
// after we verify the handshake signature, since the state before
|
||||
// this message was sent is used.
|
||||
msg, err = c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -498,7 +512,9 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
|
||||
return errors.New("tls: invalid signature by the server certificate: " + err.Error())
|
||||
}
|
||||
|
||||
hs.transcript.Write(certVerify.marshal())
|
||||
if err := transcriptMsg(certVerify, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -506,7 +522,10 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
|
||||
func (hs *clientHandshakeStateTLS13) readServerFinished() error {
|
||||
c := hs.c
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
// finishedMsg is included in the transcript, but not until after we
|
||||
// check the client version, since the state before this message was
|
||||
// sent is used during verification.
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -523,7 +542,9 @@ func (hs *clientHandshakeStateTLS13) readServerFinished() error {
|
||||
return errors.New("tls: invalid server finished hash")
|
||||
}
|
||||
|
||||
hs.transcript.Write(finished.marshal())
|
||||
if err := transcriptMsg(finished, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Derive secrets that take context through the server Finished.
|
||||
|
||||
@@ -572,8 +593,7 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
|
||||
certMsg.scts = hs.certReq.scts && len(cert.SignedCertificateTimestamps) > 0
|
||||
certMsg.ocspStapling = hs.certReq.ocspStapling && len(cert.OCSPStaple) > 0
|
||||
|
||||
hs.transcript.Write(certMsg.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -610,8 +630,7 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
|
||||
}
|
||||
certVerifyMsg.signature = sig
|
||||
|
||||
hs.transcript.Write(certVerifyMsg.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, certVerifyMsg.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -625,8 +644,7 @@ func (hs *clientHandshakeStateTLS13) sendClientFinished() error {
|
||||
verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
|
||||
}
|
||||
|
||||
hs.transcript.Write(finished.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package tls
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@@ -94,9 +95,181 @@ type clientHelloMsg struct {
|
||||
pskBinders [][]byte
|
||||
}
|
||||
|
||||
func (m *clientHelloMsg) marshal() []byte {
|
||||
func (m *clientHelloMsg) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
var exts cryptobyte.Builder
|
||||
if len(m.serverName) > 0 {
|
||||
// RFC 6066, Section 3
|
||||
exts.AddUint16(extensionServerName)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint8(0) // name_type = host_name
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes([]byte(m.serverName))
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.ocspStapling {
|
||||
// RFC 4366, Section 3.6
|
||||
exts.AddUint16(extensionStatusRequest)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint8(1) // status_type = ocsp
|
||||
exts.AddUint16(0) // empty responder_id_list
|
||||
exts.AddUint16(0) // empty request_extensions
|
||||
})
|
||||
}
|
||||
if len(m.supportedCurves) > 0 {
|
||||
// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
|
||||
exts.AddUint16(extensionSupportedCurves)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
for _, curve := range m.supportedCurves {
|
||||
exts.AddUint16(uint16(curve))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.supportedPoints) > 0 {
|
||||
// RFC 4492, Section 5.1.2
|
||||
exts.AddUint16(extensionSupportedPoints)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(m.supportedPoints)
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.ticketSupported {
|
||||
// RFC 5077, Section 3.2
|
||||
exts.AddUint16(extensionSessionTicket)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(m.sessionTicket)
|
||||
})
|
||||
}
|
||||
if len(m.supportedSignatureAlgorithms) > 0 {
|
||||
// RFC 5246, Section 7.4.1.4.1
|
||||
exts.AddUint16(extensionSignatureAlgorithms)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
for _, sigAlgo := range m.supportedSignatureAlgorithms {
|
||||
exts.AddUint16(uint16(sigAlgo))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.supportedSignatureAlgorithmsCert) > 0 {
|
||||
// RFC 8446, Section 4.2.3
|
||||
exts.AddUint16(extensionSignatureAlgorithmsCert)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
for _, sigAlgo := range m.supportedSignatureAlgorithmsCert {
|
||||
exts.AddUint16(uint16(sigAlgo))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.secureRenegotiationSupported {
|
||||
// RFC 5746, Section 3.2
|
||||
exts.AddUint16(extensionRenegotiationInfo)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(m.secureRenegotiation)
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.alpnProtocols) > 0 {
|
||||
// RFC 7301, Section 3.1
|
||||
exts.AddUint16(extensionALPN)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
for _, proto := range m.alpnProtocols {
|
||||
exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes([]byte(proto))
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.scts {
|
||||
// RFC 6962, Section 3.3.1
|
||||
exts.AddUint16(extensionSCT)
|
||||
exts.AddUint16(0) // empty extension_data
|
||||
}
|
||||
if len(m.supportedVersions) > 0 {
|
||||
// RFC 8446, Section 4.2.1
|
||||
exts.AddUint16(extensionSupportedVersions)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
for _, vers := range m.supportedVersions {
|
||||
exts.AddUint16(vers)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.cookie) > 0 {
|
||||
// RFC 8446, Section 4.2.2
|
||||
exts.AddUint16(extensionCookie)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(m.cookie)
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.keyShares) > 0 {
|
||||
// RFC 8446, Section 4.2.8
|
||||
exts.AddUint16(extensionKeyShare)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
for _, ks := range m.keyShares {
|
||||
exts.AddUint16(uint16(ks.group))
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(ks.data)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.earlyData {
|
||||
// RFC 8446, Section 4.2.10
|
||||
exts.AddUint16(extensionEarlyData)
|
||||
exts.AddUint16(0) // empty extension_data
|
||||
}
|
||||
if len(m.pskModes) > 0 {
|
||||
// RFC 8446, Section 4.2.9
|
||||
exts.AddUint16(extensionPSKModes)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(m.pskModes)
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension
|
||||
// RFC 8446, Section 4.2.11
|
||||
exts.AddUint16(extensionPreSharedKey)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
for _, psk := range m.pskIdentities {
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(psk.label)
|
||||
})
|
||||
exts.AddUint32(psk.obfuscatedTicketAge)
|
||||
}
|
||||
})
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
for _, binder := range m.pskBinders {
|
||||
exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(binder)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
extBytes, err := exts.Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var b cryptobyte.Builder
|
||||
@@ -116,219 +289,53 @@ func (m *clientHelloMsg) marshal() []byte {
|
||||
b.AddBytes(m.compressionMethods)
|
||||
})
|
||||
|
||||
// If extensions aren't present, omit them.
|
||||
var extensionsPresent bool
|
||||
bWithoutExtensions := *b
|
||||
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
if len(m.serverName) > 0 {
|
||||
// RFC 6066, Section 3
|
||||
b.AddUint16(extensionServerName)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8(0) // name_type = host_name
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes([]byte(m.serverName))
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.ocspStapling {
|
||||
// RFC 4366, Section 3.6
|
||||
b.AddUint16(extensionStatusRequest)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8(1) // status_type = ocsp
|
||||
b.AddUint16(0) // empty responder_id_list
|
||||
b.AddUint16(0) // empty request_extensions
|
||||
})
|
||||
}
|
||||
if len(m.supportedCurves) > 0 {
|
||||
// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
|
||||
b.AddUint16(extensionSupportedCurves)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, curve := range m.supportedCurves {
|
||||
b.AddUint16(uint16(curve))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.supportedPoints) > 0 {
|
||||
// RFC 4492, Section 5.1.2
|
||||
b.AddUint16(extensionSupportedPoints)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.supportedPoints)
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.ticketSupported {
|
||||
// RFC 5077, Section 3.2
|
||||
b.AddUint16(extensionSessionTicket)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.sessionTicket)
|
||||
})
|
||||
}
|
||||
if len(m.supportedSignatureAlgorithms) > 0 {
|
||||
// RFC 5246, Section 7.4.1.4.1
|
||||
b.AddUint16(extensionSignatureAlgorithms)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, sigAlgo := range m.supportedSignatureAlgorithms {
|
||||
b.AddUint16(uint16(sigAlgo))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.supportedSignatureAlgorithmsCert) > 0 {
|
||||
// RFC 8446, Section 4.2.3
|
||||
b.AddUint16(extensionSignatureAlgorithmsCert)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, sigAlgo := range m.supportedSignatureAlgorithmsCert {
|
||||
b.AddUint16(uint16(sigAlgo))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.secureRenegotiationSupported {
|
||||
// RFC 5746, Section 3.2
|
||||
b.AddUint16(extensionRenegotiationInfo)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.secureRenegotiation)
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.alpnProtocols) > 0 {
|
||||
// RFC 7301, Section 3.1
|
||||
b.AddUint16(extensionALPN)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, proto := range m.alpnProtocols {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes([]byte(proto))
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.scts {
|
||||
// RFC 6962, Section 3.3.1
|
||||
b.AddUint16(extensionSCT)
|
||||
b.AddUint16(0) // empty extension_data
|
||||
}
|
||||
if len(m.supportedVersions) > 0 {
|
||||
// RFC 8446, Section 4.2.1
|
||||
b.AddUint16(extensionSupportedVersions)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, vers := range m.supportedVersions {
|
||||
b.AddUint16(vers)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.cookie) > 0 {
|
||||
// RFC 8446, Section 4.2.2
|
||||
b.AddUint16(extensionCookie)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.cookie)
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.keyShares) > 0 {
|
||||
// RFC 8446, Section 4.2.8
|
||||
b.AddUint16(extensionKeyShare)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, ks := range m.keyShares {
|
||||
b.AddUint16(uint16(ks.group))
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(ks.data)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.earlyData {
|
||||
// RFC 8446, Section 4.2.10
|
||||
b.AddUint16(extensionEarlyData)
|
||||
b.AddUint16(0) // empty extension_data
|
||||
}
|
||||
if len(m.pskModes) > 0 {
|
||||
// RFC 8446, Section 4.2.9
|
||||
b.AddUint16(extensionPSKModes)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.pskModes)
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension
|
||||
// RFC 8446, Section 4.2.11
|
||||
b.AddUint16(extensionPreSharedKey)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, psk := range m.pskIdentities {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(psk.label)
|
||||
})
|
||||
b.AddUint32(psk.obfuscatedTicketAge)
|
||||
}
|
||||
})
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, binder := range m.pskBinders {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(binder)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
extensionsPresent = len(b.BytesOrPanic()) > 2
|
||||
})
|
||||
|
||||
if !extensionsPresent {
|
||||
*b = bWithoutExtensions
|
||||
if len(extBytes) > 0 {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(extBytes)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
// marshalWithoutBinders returns the ClientHello through the
|
||||
// PreSharedKeyExtension.identities field, according to RFC 8446, Section
|
||||
// 4.2.11.2. Note that m.pskBinders must be set to slices of the correct length.
|
||||
func (m *clientHelloMsg) marshalWithoutBinders() []byte {
|
||||
func (m *clientHelloMsg) marshalWithoutBinders() ([]byte, error) {
|
||||
bindersLen := 2 // uint16 length prefix
|
||||
for _, binder := range m.pskBinders {
|
||||
bindersLen += 1 // uint8 length prefix
|
||||
bindersLen += len(binder)
|
||||
}
|
||||
|
||||
fullMessage := m.marshal()
|
||||
return fullMessage[:len(fullMessage)-bindersLen]
|
||||
fullMessage, err := m.marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fullMessage[:len(fullMessage)-bindersLen], nil
|
||||
}
|
||||
|
||||
// updateBinders updates the m.pskBinders field, if necessary updating the
|
||||
// cached marshaled representation. The supplied binders must have the same
|
||||
// length as the current m.pskBinders.
|
||||
func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) {
|
||||
func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) error {
|
||||
if len(pskBinders) != len(m.pskBinders) {
|
||||
panic("tls: internal error: pskBinders length mismatch")
|
||||
return errors.New("tls: internal error: pskBinders length mismatch")
|
||||
}
|
||||
for i := range m.pskBinders {
|
||||
if len(pskBinders[i]) != len(m.pskBinders[i]) {
|
||||
panic("tls: internal error: pskBinders length mismatch")
|
||||
return errors.New("tls: internal error: pskBinders length mismatch")
|
||||
}
|
||||
}
|
||||
m.pskBinders = pskBinders
|
||||
if m.raw != nil {
|
||||
lenWithoutBinders := len(m.marshalWithoutBinders())
|
||||
helloBytes, err := m.marshalWithoutBinders()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lenWithoutBinders := len(helloBytes)
|
||||
b := cryptobyte.NewFixedBuilder(m.raw[:lenWithoutBinders])
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, binder := range m.pskBinders {
|
||||
@@ -338,9 +345,11 @@ func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) {
|
||||
}
|
||||
})
|
||||
if out, err := b.Bytes(); err != nil || len(out) != len(m.raw) {
|
||||
panic("tls: internal error: failed to update binders")
|
||||
return errors.New("tls: internal error: failed to update binders")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *clientHelloMsg) unmarshal(data []byte) bool {
|
||||
@@ -618,9 +627,98 @@ type serverHelloMsg struct {
|
||||
selectedGroup CurveID
|
||||
}
|
||||
|
||||
func (m *serverHelloMsg) marshal() []byte {
|
||||
func (m *serverHelloMsg) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
var exts cryptobyte.Builder
|
||||
if m.ocspStapling {
|
||||
exts.AddUint16(extensionStatusRequest)
|
||||
exts.AddUint16(0) // empty extension_data
|
||||
}
|
||||
if m.ticketSupported {
|
||||
exts.AddUint16(extensionSessionTicket)
|
||||
exts.AddUint16(0) // empty extension_data
|
||||
}
|
||||
if m.secureRenegotiationSupported {
|
||||
exts.AddUint16(extensionRenegotiationInfo)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(m.secureRenegotiation)
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.alpnProtocol) > 0 {
|
||||
exts.AddUint16(extensionALPN)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes([]byte(m.alpnProtocol))
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.scts) > 0 {
|
||||
exts.AddUint16(extensionSCT)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
for _, sct := range m.scts {
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(sct)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.supportedVersion != 0 {
|
||||
exts.AddUint16(extensionSupportedVersions)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16(m.supportedVersion)
|
||||
})
|
||||
}
|
||||
if m.serverShare.group != 0 {
|
||||
exts.AddUint16(extensionKeyShare)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16(uint16(m.serverShare.group))
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(m.serverShare.data)
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.selectedIdentityPresent {
|
||||
exts.AddUint16(extensionPreSharedKey)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16(m.selectedIdentity)
|
||||
})
|
||||
}
|
||||
|
||||
if len(m.cookie) > 0 {
|
||||
exts.AddUint16(extensionCookie)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(m.cookie)
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.selectedGroup != 0 {
|
||||
exts.AddUint16(extensionKeyShare)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint16(uint16(m.selectedGroup))
|
||||
})
|
||||
}
|
||||
if len(m.supportedPoints) > 0 {
|
||||
exts.AddUint16(extensionSupportedPoints)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(m.supportedPoints)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
extBytes, err := exts.Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var b cryptobyte.Builder
|
||||
@@ -634,104 +732,15 @@ func (m *serverHelloMsg) marshal() []byte {
|
||||
b.AddUint16(m.cipherSuite)
|
||||
b.AddUint8(m.compressionMethod)
|
||||
|
||||
// If extensions aren't present, omit them.
|
||||
var extensionsPresent bool
|
||||
bWithoutExtensions := *b
|
||||
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
if m.ocspStapling {
|
||||
b.AddUint16(extensionStatusRequest)
|
||||
b.AddUint16(0) // empty extension_data
|
||||
}
|
||||
if m.ticketSupported {
|
||||
b.AddUint16(extensionSessionTicket)
|
||||
b.AddUint16(0) // empty extension_data
|
||||
}
|
||||
if m.secureRenegotiationSupported {
|
||||
b.AddUint16(extensionRenegotiationInfo)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.secureRenegotiation)
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.alpnProtocol) > 0 {
|
||||
b.AddUint16(extensionALPN)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes([]byte(m.alpnProtocol))
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(m.scts) > 0 {
|
||||
b.AddUint16(extensionSCT)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, sct := range m.scts {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(sct)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.supportedVersion != 0 {
|
||||
b.AddUint16(extensionSupportedVersions)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16(m.supportedVersion)
|
||||
})
|
||||
}
|
||||
if m.serverShare.group != 0 {
|
||||
b.AddUint16(extensionKeyShare)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16(uint16(m.serverShare.group))
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.serverShare.data)
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.selectedIdentityPresent {
|
||||
b.AddUint16(extensionPreSharedKey)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16(m.selectedIdentity)
|
||||
})
|
||||
}
|
||||
|
||||
if len(m.cookie) > 0 {
|
||||
b.AddUint16(extensionCookie)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.cookie)
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.selectedGroup != 0 {
|
||||
b.AddUint16(extensionKeyShare)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint16(uint16(m.selectedGroup))
|
||||
})
|
||||
}
|
||||
if len(m.supportedPoints) > 0 {
|
||||
b.AddUint16(extensionSupportedPoints)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.supportedPoints)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
extensionsPresent = len(b.BytesOrPanic()) > 2
|
||||
})
|
||||
|
||||
if !extensionsPresent {
|
||||
*b = bWithoutExtensions
|
||||
if len(extBytes) > 0 {
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(extBytes)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *serverHelloMsg) unmarshal(data []byte) bool {
|
||||
@@ -855,9 +864,9 @@ type encryptedExtensionsMsg struct {
|
||||
alpnProtocol string
|
||||
}
|
||||
|
||||
func (m *encryptedExtensionsMsg) marshal() []byte {
|
||||
func (m *encryptedExtensionsMsg) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
var b cryptobyte.Builder
|
||||
@@ -877,8 +886,9 @@ func (m *encryptedExtensionsMsg) marshal() []byte {
|
||||
})
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
|
||||
@@ -926,10 +936,10 @@ func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
|
||||
|
||||
type endOfEarlyDataMsg struct{}
|
||||
|
||||
func (m *endOfEarlyDataMsg) marshal() []byte {
|
||||
func (m *endOfEarlyDataMsg) marshal() ([]byte, error) {
|
||||
x := make([]byte, 4)
|
||||
x[0] = typeEndOfEarlyData
|
||||
return x
|
||||
return x, nil
|
||||
}
|
||||
|
||||
func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool {
|
||||
@@ -941,9 +951,9 @@ type keyUpdateMsg struct {
|
||||
updateRequested bool
|
||||
}
|
||||
|
||||
func (m *keyUpdateMsg) marshal() []byte {
|
||||
func (m *keyUpdateMsg) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
var b cryptobyte.Builder
|
||||
@@ -956,8 +966,9 @@ func (m *keyUpdateMsg) marshal() []byte {
|
||||
}
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *keyUpdateMsg) unmarshal(data []byte) bool {
|
||||
@@ -989,9 +1000,9 @@ type newSessionTicketMsgTLS13 struct {
|
||||
maxEarlyData uint32
|
||||
}
|
||||
|
||||
func (m *newSessionTicketMsgTLS13) marshal() []byte {
|
||||
func (m *newSessionTicketMsgTLS13) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
var b cryptobyte.Builder
|
||||
@@ -1016,8 +1027,9 @@ func (m *newSessionTicketMsgTLS13) marshal() []byte {
|
||||
})
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool {
|
||||
@@ -1070,9 +1082,9 @@ type certificateRequestMsgTLS13 struct {
|
||||
certificateAuthorities [][]byte
|
||||
}
|
||||
|
||||
func (m *certificateRequestMsgTLS13) marshal() []byte {
|
||||
func (m *certificateRequestMsgTLS13) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
var b cryptobyte.Builder
|
||||
@@ -1131,8 +1143,9 @@ func (m *certificateRequestMsgTLS13) marshal() []byte {
|
||||
})
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool {
|
||||
@@ -1216,9 +1229,9 @@ type certificateMsg struct {
|
||||
certificates [][]byte
|
||||
}
|
||||
|
||||
func (m *certificateMsg) marshal() (x []byte) {
|
||||
func (m *certificateMsg) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
var i int
|
||||
@@ -1227,7 +1240,7 @@ func (m *certificateMsg) marshal() (x []byte) {
|
||||
}
|
||||
|
||||
length := 3 + 3*len(m.certificates) + i
|
||||
x = make([]byte, 4+length)
|
||||
x := make([]byte, 4+length)
|
||||
x[0] = typeCertificate
|
||||
x[1] = uint8(length >> 16)
|
||||
x[2] = uint8(length >> 8)
|
||||
@@ -1248,7 +1261,7 @@ func (m *certificateMsg) marshal() (x []byte) {
|
||||
}
|
||||
|
||||
m.raw = x
|
||||
return
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
func (m *certificateMsg) unmarshal(data []byte) bool {
|
||||
@@ -1295,9 +1308,9 @@ type certificateMsgTLS13 struct {
|
||||
scts bool
|
||||
}
|
||||
|
||||
func (m *certificateMsgTLS13) marshal() []byte {
|
||||
func (m *certificateMsgTLS13) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
var b cryptobyte.Builder
|
||||
@@ -1315,8 +1328,9 @@ func (m *certificateMsgTLS13) marshal() []byte {
|
||||
marshalCertificate(b, certificate)
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) {
|
||||
@@ -1439,9 +1453,9 @@ type serverKeyExchangeMsg struct {
|
||||
key []byte
|
||||
}
|
||||
|
||||
func (m *serverKeyExchangeMsg) marshal() []byte {
|
||||
func (m *serverKeyExchangeMsg) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
length := len(m.key)
|
||||
x := make([]byte, length+4)
|
||||
@@ -1452,7 +1466,7 @@ func (m *serverKeyExchangeMsg) marshal() []byte {
|
||||
copy(x[4:], m.key)
|
||||
|
||||
m.raw = x
|
||||
return x
|
||||
return x, nil
|
||||
}
|
||||
|
||||
func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool {
|
||||
@@ -1469,9 +1483,9 @@ type certificateStatusMsg struct {
|
||||
response []byte
|
||||
}
|
||||
|
||||
func (m *certificateStatusMsg) marshal() []byte {
|
||||
func (m *certificateStatusMsg) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
var b cryptobyte.Builder
|
||||
@@ -1483,8 +1497,9 @@ func (m *certificateStatusMsg) marshal() []byte {
|
||||
})
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *certificateStatusMsg) unmarshal(data []byte) bool {
|
||||
@@ -1503,10 +1518,10 @@ func (m *certificateStatusMsg) unmarshal(data []byte) bool {
|
||||
|
||||
type serverHelloDoneMsg struct{}
|
||||
|
||||
func (m *serverHelloDoneMsg) marshal() []byte {
|
||||
func (m *serverHelloDoneMsg) marshal() ([]byte, error) {
|
||||
x := make([]byte, 4)
|
||||
x[0] = typeServerHelloDone
|
||||
return x
|
||||
return x, nil
|
||||
}
|
||||
|
||||
func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
|
||||
@@ -1518,9 +1533,9 @@ type clientKeyExchangeMsg struct {
|
||||
ciphertext []byte
|
||||
}
|
||||
|
||||
func (m *clientKeyExchangeMsg) marshal() []byte {
|
||||
func (m *clientKeyExchangeMsg) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
length := len(m.ciphertext)
|
||||
x := make([]byte, length+4)
|
||||
@@ -1531,7 +1546,7 @@ func (m *clientKeyExchangeMsg) marshal() []byte {
|
||||
copy(x[4:], m.ciphertext)
|
||||
|
||||
m.raw = x
|
||||
return x
|
||||
return x, nil
|
||||
}
|
||||
|
||||
func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
|
||||
@@ -1552,9 +1567,9 @@ type finishedMsg struct {
|
||||
verifyData []byte
|
||||
}
|
||||
|
||||
func (m *finishedMsg) marshal() []byte {
|
||||
func (m *finishedMsg) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
var b cryptobyte.Builder
|
||||
@@ -1563,8 +1578,9 @@ func (m *finishedMsg) marshal() []byte {
|
||||
b.AddBytes(m.verifyData)
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *finishedMsg) unmarshal(data []byte) bool {
|
||||
@@ -1586,9 +1602,9 @@ type certificateRequestMsg struct {
|
||||
certificateAuthorities [][]byte
|
||||
}
|
||||
|
||||
func (m *certificateRequestMsg) marshal() (x []byte) {
|
||||
func (m *certificateRequestMsg) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
// See RFC 4346, Section 7.4.4.
|
||||
@@ -1603,7 +1619,7 @@ func (m *certificateRequestMsg) marshal() (x []byte) {
|
||||
length += 2 + 2*len(m.supportedSignatureAlgorithms)
|
||||
}
|
||||
|
||||
x = make([]byte, 4+length)
|
||||
x := make([]byte, 4+length)
|
||||
x[0] = typeCertificateRequest
|
||||
x[1] = uint8(length >> 16)
|
||||
x[2] = uint8(length >> 8)
|
||||
@@ -1638,7 +1654,7 @@ func (m *certificateRequestMsg) marshal() (x []byte) {
|
||||
}
|
||||
|
||||
m.raw = x
|
||||
return
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
func (m *certificateRequestMsg) unmarshal(data []byte) bool {
|
||||
@@ -1724,9 +1740,9 @@ type certificateVerifyMsg struct {
|
||||
signature []byte
|
||||
}
|
||||
|
||||
func (m *certificateVerifyMsg) marshal() (x []byte) {
|
||||
func (m *certificateVerifyMsg) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
var b cryptobyte.Builder
|
||||
@@ -1740,8 +1756,9 @@ func (m *certificateVerifyMsg) marshal() (x []byte) {
|
||||
})
|
||||
})
|
||||
|
||||
m.raw = b.BytesOrPanic()
|
||||
return m.raw
|
||||
var err error
|
||||
m.raw, err = b.Bytes()
|
||||
return m.raw, err
|
||||
}
|
||||
|
||||
func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
|
||||
@@ -1764,15 +1781,15 @@ type newSessionTicketMsg struct {
|
||||
ticket []byte
|
||||
}
|
||||
|
||||
func (m *newSessionTicketMsg) marshal() (x []byte) {
|
||||
func (m *newSessionTicketMsg) marshal() ([]byte, error) {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
// See RFC 5077, Section 3.3.
|
||||
ticketLen := len(m.ticket)
|
||||
length := 2 + 4 + ticketLen
|
||||
x = make([]byte, 4+length)
|
||||
x := make([]byte, 4+length)
|
||||
x[0] = typeNewSessionTicket
|
||||
x[1] = uint8(length >> 16)
|
||||
x[2] = uint8(length >> 8)
|
||||
@@ -1783,7 +1800,7 @@ func (m *newSessionTicketMsg) marshal() (x []byte) {
|
||||
|
||||
m.raw = x
|
||||
|
||||
return
|
||||
return m.raw, nil
|
||||
}
|
||||
|
||||
func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
|
||||
@@ -1811,10 +1828,25 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
|
||||
type helloRequestMsg struct {
|
||||
}
|
||||
|
||||
func (*helloRequestMsg) marshal() []byte {
|
||||
return []byte{typeHelloRequest, 0, 0, 0}
|
||||
func (*helloRequestMsg) marshal() ([]byte, error) {
|
||||
return []byte{typeHelloRequest, 0, 0, 0}, nil
|
||||
}
|
||||
|
||||
func (*helloRequestMsg) unmarshal(data []byte) bool {
|
||||
return len(data) == 4
|
||||
}
|
||||
|
||||
type transcriptHash interface {
|
||||
Write([]byte) (int, error)
|
||||
}
|
||||
|
||||
// transcriptMsg is a helper used to marshal and hash messages which typically
|
||||
// are not written to the wire, and as such aren't hashed during Conn.writeRecord.
|
||||
func transcriptMsg(msg handshakeMessage, h transcriptHash) error {
|
||||
data, err := msg.marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.Write(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -38,6 +38,15 @@ var tests = []any{
|
||||
&certificateMsgTLS13{},
|
||||
}
|
||||
|
||||
func mustMarshal(t *testing.T, msg handshakeMessage) []byte {
|
||||
t.Helper()
|
||||
b, err := msg.marshal()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshal(t *testing.T) {
|
||||
rand := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
@@ -56,7 +65,7 @@ func TestMarshalUnmarshal(t *testing.T) {
|
||||
}
|
||||
|
||||
m1 := v.Interface().(handshakeMessage)
|
||||
marshaled := m1.marshal()
|
||||
marshaled := mustMarshal(t, m1)
|
||||
m2 := iface.(handshakeMessage)
|
||||
if !m2.unmarshal(marshaled) {
|
||||
t.Errorf("#%d failed to unmarshal %#v %x", i, m1, marshaled)
|
||||
@@ -409,12 +418,12 @@ func TestRejectEmptySCTList(t *testing.T) {
|
||||
|
||||
var random [32]byte
|
||||
sct := []byte{0x42, 0x42, 0x42, 0x42}
|
||||
serverHello := serverHelloMsg{
|
||||
serverHello := &serverHelloMsg{
|
||||
vers: VersionTLS12,
|
||||
random: random[:],
|
||||
scts: [][]byte{sct},
|
||||
}
|
||||
serverHelloBytes := serverHello.marshal()
|
||||
serverHelloBytes := mustMarshal(t, serverHello)
|
||||
|
||||
var serverHelloCopy serverHelloMsg
|
||||
if !serverHelloCopy.unmarshal(serverHelloBytes) {
|
||||
@@ -452,12 +461,12 @@ func TestRejectEmptySCT(t *testing.T) {
|
||||
// not be zero length.
|
||||
|
||||
var random [32]byte
|
||||
serverHello := serverHelloMsg{
|
||||
serverHello := &serverHelloMsg{
|
||||
vers: VersionTLS12,
|
||||
random: random[:],
|
||||
scts: [][]byte{nil},
|
||||
}
|
||||
serverHelloBytes := serverHello.marshal()
|
||||
serverHelloBytes := mustMarshal(t, serverHello)
|
||||
|
||||
var serverHelloCopy serverHelloMsg
|
||||
if serverHelloCopy.unmarshal(serverHelloBytes) {
|
||||
|
||||
@@ -128,7 +128,9 @@ func (hs *serverHandshakeState) handshake() error {
|
||||
|
||||
// readClientHello reads a ClientHello message and selects the protocol version.
|
||||
func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) {
|
||||
msg, err := c.readHandshake()
|
||||
// clientHelloMsg is included in the transcript, but we haven't initialized
|
||||
// it yet. The respective handshake functions will record it themselves.
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -462,9 +464,10 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
|
||||
hs.hello.ticketSupported = hs.sessionState.usedOldKey
|
||||
hs.finishedHash = newFinishedHash(c.vers, hs.suite)
|
||||
hs.finishedHash.discardHandshakeBuffer()
|
||||
hs.finishedHash.Write(hs.clientHello.marshal())
|
||||
hs.finishedHash.Write(hs.hello.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
|
||||
if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -502,24 +505,23 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
// certificates won't be used.
|
||||
hs.finishedHash.discardHandshakeBuffer()
|
||||
}
|
||||
hs.finishedHash.Write(hs.clientHello.marshal())
|
||||
hs.finishedHash.Write(hs.hello.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
|
||||
if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certMsg := new(certificateMsg)
|
||||
certMsg.certificates = hs.cert.Certificate
|
||||
hs.finishedHash.Write(certMsg.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if hs.hello.ocspStapling {
|
||||
certStatus := new(certificateStatusMsg)
|
||||
certStatus.response = hs.cert.OCSPStaple
|
||||
hs.finishedHash.Write(certStatus.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, certStatus.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(certStatus, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -531,8 +533,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
return err
|
||||
}
|
||||
if skx != nil {
|
||||
hs.finishedHash.Write(skx.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, skx.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(skx, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -558,15 +559,13 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
if c.config.ClientCAs != nil {
|
||||
certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
|
||||
}
|
||||
hs.finishedHash.Write(certReq.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(certReq, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
helloDone := new(serverHelloDoneMsg)
|
||||
hs.finishedHash.Write(helloDone.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, helloDone.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(helloDone, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -576,7 +575,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
|
||||
var pub crypto.PublicKey // public key for client auth, if any
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
msg, err := c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -589,7 +588,6 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certMsg, msg)
|
||||
}
|
||||
hs.finishedHash.Write(certMsg.marshal())
|
||||
|
||||
if err := c.processCertsFromClient(Certificate{
|
||||
Certificate: certMsg.certificates,
|
||||
@@ -600,7 +598,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
pub = c.peerCertificates[0].PublicKey
|
||||
}
|
||||
|
||||
msg, err = c.readHandshake()
|
||||
msg, err = c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -618,7 +616,6 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(ckx, msg)
|
||||
}
|
||||
hs.finishedHash.Write(ckx.marshal())
|
||||
|
||||
preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers)
|
||||
if err != nil {
|
||||
@@ -638,7 +635,10 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
// to the client's certificate. This allows us to verify that the client is in
|
||||
// possession of the private key of the certificate.
|
||||
if len(c.peerCertificates) > 0 {
|
||||
msg, err = c.readHandshake()
|
||||
// certificateVerifyMsg is included in the transcript, but not until
|
||||
// after we verify the handshake signature, since the state before
|
||||
// this message was sent is used.
|
||||
msg, err = c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -673,7 +673,9 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
return errors.New("tls: invalid signature by the client certificate: " + err.Error())
|
||||
}
|
||||
|
||||
hs.finishedHash.Write(certVerify.marshal())
|
||||
if err := transcriptMsg(certVerify, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
hs.finishedHash.discardHandshakeBuffer()
|
||||
@@ -713,7 +715,10 @@ func (hs *serverHandshakeState) readFinished(out []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
// finishedMsg is included in the transcript, but not until after we
|
||||
// check the client version, since the state before this message was
|
||||
// sent is used during verification.
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -730,7 +735,10 @@ func (hs *serverHandshakeState) readFinished(out []byte) error {
|
||||
return errors.New("tls: client's Finished message is incorrect")
|
||||
}
|
||||
|
||||
hs.finishedHash.Write(clientFinished.marshal())
|
||||
if err := transcriptMsg(clientFinished, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
copy(out, verify)
|
||||
return nil
|
||||
}
|
||||
@@ -764,14 +772,16 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
|
||||
masterSecret: hs.masterSecret,
|
||||
certificates: certsFromClient,
|
||||
}
|
||||
var err error
|
||||
m.ticket, err = c.encryptTicket(state.marshal())
|
||||
stateBytes, err := state.marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.ticket, err = c.encryptTicket(stateBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hs.finishedHash.Write(m.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(m, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -781,14 +791,13 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
|
||||
func (hs *serverHandshakeState) sendFinished(out []byte) error {
|
||||
c := hs.c
|
||||
|
||||
if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
|
||||
if err := c.writeChangeCipherRecord(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
finished := new(finishedMsg)
|
||||
finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
|
||||
hs.finishedHash.Write(finished.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,13 @@ func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
|
||||
testClientHelloFailure(t, serverConfig, m, "")
|
||||
}
|
||||
|
||||
// testFatal is a hack to prevent the compiler from complaining that there is a
|
||||
// call to t.Fatal from a non-test goroutine
|
||||
func testFatal(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessage, expectedSubStr string) {
|
||||
c, s := localPipe(t)
|
||||
go func() {
|
||||
@@ -37,7 +44,9 @@ func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessa
|
||||
if ch, ok := m.(*clientHelloMsg); ok {
|
||||
cli.vers = ch.vers
|
||||
}
|
||||
cli.writeRecord(recordTypeHandshake, m.marshal())
|
||||
if _, err := cli.writeHandshakeRecord(m, nil); err != nil {
|
||||
testFatal(t, err)
|
||||
}
|
||||
c.Close()
|
||||
}()
|
||||
ctx := context.Background()
|
||||
@@ -194,7 +203,9 @@ func TestRenegotiationExtension(t *testing.T) {
|
||||
go func() {
|
||||
cli := Client(c, testConfig)
|
||||
cli.vers = clientHello.vers
|
||||
cli.writeRecord(recordTypeHandshake, clientHello.marshal())
|
||||
if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil {
|
||||
testFatal(t, err)
|
||||
}
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
n, err := c.Read(buf)
|
||||
@@ -253,8 +264,10 @@ func TestTLS12OnlyCipherSuites(t *testing.T) {
|
||||
go func() {
|
||||
cli := Client(c, testConfig)
|
||||
cli.vers = clientHello.vers
|
||||
cli.writeRecord(recordTypeHandshake, clientHello.marshal())
|
||||
reply, err := cli.readHandshake()
|
||||
if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil {
|
||||
testFatal(t, err)
|
||||
}
|
||||
reply, err := cli.readHandshake(nil)
|
||||
c.Close()
|
||||
if err != nil {
|
||||
replyChan <- err
|
||||
@@ -311,8 +324,10 @@ func TestTLSPointFormats(t *testing.T) {
|
||||
go func() {
|
||||
cli := Client(c, testConfig)
|
||||
cli.vers = clientHello.vers
|
||||
cli.writeRecord(recordTypeHandshake, clientHello.marshal())
|
||||
reply, err := cli.readHandshake()
|
||||
if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil {
|
||||
testFatal(t, err)
|
||||
}
|
||||
reply, err := cli.readHandshake(nil)
|
||||
c.Close()
|
||||
if err != nil {
|
||||
replyChan <- err
|
||||
@@ -1426,7 +1441,9 @@ func TestSNIGivenOnFailure(t *testing.T) {
|
||||
go func() {
|
||||
cli := Client(c, testConfig)
|
||||
cli.vers = clientHello.vers
|
||||
cli.writeRecord(recordTypeHandshake, clientHello.marshal())
|
||||
if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil {
|
||||
testFatal(t, err)
|
||||
}
|
||||
c.Close()
|
||||
}()
|
||||
conn := Server(s, serverConfig)
|
||||
|
||||
@@ -306,7 +306,12 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
|
||||
c.sendAlert(alertInternalError)
|
||||
return errors.New("tls: internal error: failed to clone hash")
|
||||
}
|
||||
transcript.Write(hs.clientHello.marshalWithoutBinders())
|
||||
clientHelloBytes, err := hs.clientHello.marshalWithoutBinders()
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
transcript.Write(clientHelloBytes)
|
||||
pskBinder := hs.suite.finishedHash(binderKey, transcript)
|
||||
if !hmac.Equal(hs.clientHello.pskBinders[i], pskBinder) {
|
||||
c.sendAlert(alertDecryptError)
|
||||
@@ -397,8 +402,7 @@ func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
|
||||
}
|
||||
hs.sentDummyCCS = true
|
||||
|
||||
_, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
|
||||
return err
|
||||
return hs.c.writeChangeCipherRecord()
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error {
|
||||
@@ -406,7 +410,9 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID)
|
||||
|
||||
// The first ClientHello gets double-hashed into the transcript upon a
|
||||
// HelloRetryRequest. See RFC 8446, Section 4.4.1.
|
||||
hs.transcript.Write(hs.clientHello.marshal())
|
||||
if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
chHash := hs.transcript.Sum(nil)
|
||||
hs.transcript.Reset()
|
||||
hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
|
||||
@@ -422,8 +428,7 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID)
|
||||
selectedGroup: selectedGroup,
|
||||
}
|
||||
|
||||
hs.transcript.Write(helloRetryRequest.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(helloRetryRequest, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -431,7 +436,8 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID)
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
// clientHelloMsg is not included in the transcript.
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -522,9 +528,10 @@ func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool {
|
||||
func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
|
||||
c := hs.c
|
||||
|
||||
hs.transcript.Write(hs.clientHello.marshal())
|
||||
hs.transcript.Write(hs.hello.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
|
||||
if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -567,8 +574,7 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
|
||||
encryptedExtensions.alpnProtocol = selectedProto
|
||||
c.clientProtocol = selectedProto
|
||||
|
||||
hs.transcript.Write(encryptedExtensions.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(encryptedExtensions, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -597,8 +603,7 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
|
||||
certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
|
||||
}
|
||||
|
||||
hs.transcript.Write(certReq.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(certReq, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -609,8 +614,7 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
|
||||
certMsg.scts = hs.clientHello.scts && len(hs.cert.SignedCertificateTimestamps) > 0
|
||||
certMsg.ocspStapling = hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0
|
||||
|
||||
hs.transcript.Write(certMsg.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -641,8 +645,7 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
|
||||
}
|
||||
certVerifyMsg.signature = sig
|
||||
|
||||
hs.transcript.Write(certVerifyMsg.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, certVerifyMsg.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -656,8 +659,7 @@ func (hs *serverHandshakeStateTLS13) sendServerFinished() error {
|
||||
verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
|
||||
}
|
||||
|
||||
hs.transcript.Write(finished.marshal())
|
||||
if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -718,7 +720,9 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
|
||||
finishedMsg := &finishedMsg{
|
||||
verifyData: hs.clientFinished,
|
||||
}
|
||||
hs.transcript.Write(finishedMsg.marshal())
|
||||
if err := transcriptMsg(finishedMsg, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !hs.shouldSendSessionTickets() {
|
||||
return nil
|
||||
@@ -743,8 +747,12 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
|
||||
SignedCertificateTimestamps: c.scts,
|
||||
},
|
||||
}
|
||||
var err error
|
||||
m.label, err = c.encryptTicket(state.marshal())
|
||||
stateBytes, err := state.marshal()
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
m.label, err = c.encryptTicket(stateBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -763,7 +771,7 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
|
||||
// ticket_nonce, which must be unique per connection, is always left at
|
||||
// zero because we only ever send one ticket per connection.
|
||||
|
||||
if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
|
||||
if _, err := c.writeHandshakeRecord(m, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -788,7 +796,7 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
|
||||
// If we requested a client certificate, then the client must send a
|
||||
// certificate message. If it's empty, no CertificateVerify is sent.
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
msg, err := c.readHandshake(hs.transcript)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -798,7 +806,6 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certMsg, msg)
|
||||
}
|
||||
hs.transcript.Write(certMsg.marshal())
|
||||
|
||||
if err := c.processCertsFromClient(certMsg.certificate); err != nil {
|
||||
return err
|
||||
@@ -812,7 +819,10 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
|
||||
}
|
||||
|
||||
if len(certMsg.certificate.Certificate) != 0 {
|
||||
msg, err = c.readHandshake()
|
||||
// certificateVerifyMsg is included in the transcript, but not until
|
||||
// after we verify the handshake signature, since the state before
|
||||
// this message was sent is used.
|
||||
msg, err = c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -843,7 +853,9 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
|
||||
return errors.New("tls: invalid signature by the client certificate: " + err.Error())
|
||||
}
|
||||
|
||||
hs.transcript.Write(certVerify.marshal())
|
||||
if err := transcriptMsg(certVerify, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If we waited until the client certificates to send session tickets, we
|
||||
@@ -858,7 +870,8 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
|
||||
func (hs *serverHandshakeStateTLS13) readClientFinished() error {
|
||||
c := hs.c
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
// finishedMsg is not included in the transcript.
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"crypto/ecdh"
|
||||
"crypto/hmac"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
|
||||
@@ -40,8 +41,24 @@ func (c *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []by
|
||||
hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(context)
|
||||
})
|
||||
hkdfLabelBytes, err := hkdfLabel.Bytes()
|
||||
if err != nil {
|
||||
// Rather than calling BytesOrPanic, we explicitly handle this error, in
|
||||
// order to provide a reasonable error message. It should be basically
|
||||
// impossible for this to panic, and routing errors back through the
|
||||
// tree rooted in this function is quite painful. The labels are fixed
|
||||
// size, and the context is either a fixed-length computed hash, or
|
||||
// parsed from a field which has the same length limitation. As such, an
|
||||
// error here is likely to only be caused during development.
|
||||
//
|
||||
// NOTE: another reasonable approach here might be to return a
|
||||
// randomized slice if we encounter an error, which would break the
|
||||
// connection, but avoid panicking. This would perhaps be safer but
|
||||
// significantly more confusing to users.
|
||||
panic(fmt.Errorf("failed to construct HKDF label: %s", err))
|
||||
}
|
||||
out := make([]byte, length)
|
||||
n, err := hkdf.Expand(c.hash.New, secret, hkdfLabel.BytesOrPanic()).Read(out)
|
||||
n, err := hkdf.Expand(c.hash.New, secret, hkdfLabelBytes).Read(out)
|
||||
if err != nil || n != length {
|
||||
panic("tls: HKDF-Expand-Label invocation failed unexpectedly")
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ type sessionState struct {
|
||||
usedOldKey bool
|
||||
}
|
||||
|
||||
func (m *sessionState) marshal() []byte {
|
||||
func (m *sessionState) marshal() ([]byte, error) {
|
||||
var b cryptobyte.Builder
|
||||
b.AddUint16(m.vers)
|
||||
b.AddUint16(m.cipherSuite)
|
||||
@@ -47,7 +47,7 @@ func (m *sessionState) marshal() []byte {
|
||||
})
|
||||
}
|
||||
})
|
||||
return b.BytesOrPanic()
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (m *sessionState) unmarshal(data []byte) bool {
|
||||
@@ -86,7 +86,7 @@ type sessionStateTLS13 struct {
|
||||
certificate Certificate // CertificateEntry certificate_list<0..2^24-1>;
|
||||
}
|
||||
|
||||
func (m *sessionStateTLS13) marshal() []byte {
|
||||
func (m *sessionStateTLS13) marshal() ([]byte, error) {
|
||||
var b cryptobyte.Builder
|
||||
b.AddUint16(VersionTLS13)
|
||||
b.AddUint8(0) // revision
|
||||
@@ -96,7 +96,7 @@ func (m *sessionStateTLS13) marshal() []byte {
|
||||
b.AddBytes(m.resumptionSecret)
|
||||
})
|
||||
marshalCertificate(&b, m.certificate)
|
||||
return b.BytesOrPanic()
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (m *sessionStateTLS13) unmarshal(data []byte) bool {
|
||||
|
||||
@@ -28,7 +28,7 @@ type pkcs8 struct {
|
||||
// ParsePKCS8PrivateKey parses an unencrypted private key in PKCS #8, ASN.1 DER form.
|
||||
//
|
||||
// It returns a *rsa.PrivateKey, a *ecdsa.PrivateKey, a ed25519.PrivateKey (not
|
||||
// a pointer), or a *ecdh.PublicKey (for X25519). More types might be supported
|
||||
// a pointer), or a *ecdh.PrivateKey (for X25519). More types might be supported
|
||||
// in the future.
|
||||
//
|
||||
// This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY".
|
||||
|
||||
@@ -25,9 +25,10 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
|
||||
return nil, err
|
||||
}
|
||||
sc, err := macOS.SecCertificateCreateWithData(c.Raw)
|
||||
if err == nil {
|
||||
macOS.CFArrayAppendValue(certs, sc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
macOS.CFArrayAppendValue(certs, sc)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ func TestLoadSystemCertsLoadColonSeparatedDirs(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
rootPEMs := []string{
|
||||
geoTrustRoot,
|
||||
gtsRoot,
|
||||
googleLeaf,
|
||||
startComRoot,
|
||||
}
|
||||
|
||||
@@ -43,33 +43,33 @@ var verifyTests = []verifyTest{
|
||||
{
|
||||
name: "Valid",
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
intermediates: []string{gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "www.google.com",
|
||||
|
||||
expectedChains: [][]string{
|
||||
{"Google", "Google Internet Authority", "GeoTrust"},
|
||||
{"www.google.com", "GTS CA 1C3", "GTS Root R1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MixedCase",
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
intermediates: []string{gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "WwW.GooGLE.coM",
|
||||
|
||||
expectedChains: [][]string{
|
||||
{"Google", "Google Internet Authority", "GeoTrust"},
|
||||
{"www.google.com", "GTS CA 1C3", "GTS Root R1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "HostnameMismatch",
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
intermediates: []string{gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "www.example.com",
|
||||
|
||||
errorCallback: expectHostnameError("certificate is valid for"),
|
||||
@@ -77,9 +77,9 @@ var verifyTests = []verifyTest{
|
||||
{
|
||||
name: "IPMissing",
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
intermediates: []string{gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "1.2.3.4",
|
||||
|
||||
errorCallback: expectHostnameError("doesn't contain any IP SANs"),
|
||||
@@ -87,8 +87,8 @@ var verifyTests = []verifyTest{
|
||||
{
|
||||
name: "Expired",
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
intermediates: []string{gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1,
|
||||
dnsName: "www.example.com",
|
||||
|
||||
@@ -97,8 +97,8 @@ var verifyTests = []verifyTest{
|
||||
{
|
||||
name: "MissingIntermediate",
|
||||
leaf: googleLeaf,
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "www.google.com",
|
||||
|
||||
// Skip when using systemVerify, since Windows
|
||||
@@ -109,13 +109,13 @@ var verifyTests = []verifyTest{
|
||||
{
|
||||
name: "RootInIntermediates",
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{geoTrustRoot, giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
intermediates: []string{gtsRoot, gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "www.google.com",
|
||||
|
||||
expectedChains: [][]string{
|
||||
{"Google", "Google Internet Authority", "GeoTrust"},
|
||||
{"www.google.com", "GTS CA 1C3", "GTS Root R1"},
|
||||
},
|
||||
// CAPI doesn't build the chain with the duplicated GeoTrust
|
||||
// entry so the results don't match.
|
||||
@@ -163,9 +163,9 @@ var verifyTests = []verifyTest{
|
||||
{
|
||||
name: "InvalidHash",
|
||||
leaf: googleLeafWithInvalidHash,
|
||||
intermediates: []string{giag2Intermediate},
|
||||
roots: []string{geoTrustRoot},
|
||||
currentTime: 1395785200,
|
||||
intermediates: []string{gtsIntermediate},
|
||||
roots: []string{gtsRoot},
|
||||
currentTime: 1677615892,
|
||||
dnsName: "www.google.com",
|
||||
|
||||
// The specific error message may not occur when using system
|
||||
@@ -230,21 +230,20 @@ var verifyTests = []verifyTest{
|
||||
// Check that SHA-384 intermediates (which are popping up)
|
||||
// work.
|
||||
name: "SHA-384",
|
||||
leaf: moipLeafCert,
|
||||
intermediates: []string{comodoIntermediateSHA384, comodoRSAAuthority},
|
||||
roots: []string{addTrustRoot},
|
||||
currentTime: 1397502195,
|
||||
dnsName: "api.moip.com.br",
|
||||
leaf: trustAsiaLeaf,
|
||||
intermediates: []string{trustAsiaSHA384Intermediate},
|
||||
roots: []string{digicertRoot},
|
||||
currentTime: 1558051200,
|
||||
dnsName: "tm.cn",
|
||||
|
||||
// CryptoAPI can find alternative validation paths.
|
||||
systemLax: true,
|
||||
|
||||
expectedChains: [][]string{
|
||||
{
|
||||
"api.moip.com.br",
|
||||
"COMODO RSA Extended Validation Secure Server CA",
|
||||
"COMODO RSA Certification Authority",
|
||||
"AddTrust External CA Root",
|
||||
"tm.cn",
|
||||
"TrustAsia ECC OV TLS Pro CA",
|
||||
"DigiCert Global Root CA",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -582,106 +581,135 @@ func nameToKey(name *pkix.Name) string {
|
||||
return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
|
||||
}
|
||||
|
||||
const geoTrustRoot = `-----BEGIN CERTIFICATE-----
|
||||
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
|
||||
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
|
||||
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
|
||||
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
|
||||
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
|
||||
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
|
||||
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
|
||||
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
|
||||
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
|
||||
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
|
||||
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
|
||||
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
|
||||
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
|
||||
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
|
||||
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
|
||||
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
|
||||
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
|
||||
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
|
||||
const gtsIntermediate = `-----BEGIN CERTIFICATE-----
|
||||
MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw
|
||||
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
|
||||
MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw
|
||||
MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
|
||||
Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp
|
||||
kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX
|
||||
lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm
|
||||
BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA
|
||||
gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL
|
||||
tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud
|
||||
DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T
|
||||
AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD
|
||||
VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG
|
||||
CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw
|
||||
AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt
|
||||
MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG
|
||||
A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br
|
||||
aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN
|
||||
AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ
|
||||
cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL
|
||||
RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U
|
||||
+o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr
|
||||
PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER
|
||||
lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs
|
||||
Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO
|
||||
z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG
|
||||
AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw
|
||||
juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl
|
||||
1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const giag2Intermediate = `-----BEGIN CERTIFICATE-----
|
||||
MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
|
||||
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
|
||||
YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
|
||||
EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
|
||||
bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
|
||||
VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
|
||||
h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
|
||||
ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
|
||||
EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
|
||||
DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
|
||||
qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
|
||||
VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
|
||||
K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
|
||||
KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
|
||||
ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
|
||||
BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
|
||||
/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
|
||||
zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
|
||||
HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
|
||||
WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
|
||||
yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
|
||||
const gtsRoot = `-----BEGIN CERTIFICATE-----
|
||||
MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw
|
||||
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
|
||||
MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
|
||||
MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
|
||||
Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA
|
||||
A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo
|
||||
27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w
|
||||
Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw
|
||||
TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl
|
||||
qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH
|
||||
szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8
|
||||
Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk
|
||||
MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
|
||||
wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p
|
||||
aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN
|
||||
VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID
|
||||
AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
|
||||
FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb
|
||||
C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe
|
||||
QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy
|
||||
h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4
|
||||
7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J
|
||||
ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef
|
||||
MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/
|
||||
Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT
|
||||
6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ
|
||||
0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm
|
||||
2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb
|
||||
bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const googleLeaf = `-----BEGIN CERTIFICATE-----
|
||||
MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
|
||||
BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
|
||||
cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw
|
||||
WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
|
||||
TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
|
||||
Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe
|
||||
m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6
|
||||
jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q
|
||||
fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4
|
||||
NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ
|
||||
0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI
|
||||
dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
|
||||
KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
|
||||
XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
|
||||
MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
|
||||
A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud
|
||||
IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW
|
||||
eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB
|
||||
RzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj
|
||||
5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf
|
||||
tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+
|
||||
orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi
|
||||
8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA
|
||||
Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX
|
||||
MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQsFADBG
|
||||
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
|
||||
QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw
|
||||
ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a
|
||||
wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o
|
||||
55kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr
|
||||
N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs
|
||||
KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q
|
||||
WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw
|
||||
DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC
|
||||
MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0
|
||||
f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb
|
||||
aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v
|
||||
cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n
|
||||
b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD
|
||||
VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow
|
||||
TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4
|
||||
4FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S
|
||||
3T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx
|
||||
1+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB
|
||||
hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC
|
||||
IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p
|
||||
MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd
|
||||
VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga
|
||||
zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI
|
||||
c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP
|
||||
i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
// googleLeafWithInvalidHash is the same as googleLeaf, but the signature
|
||||
// algorithm in the certificate contains a nonsense OID.
|
||||
const googleLeafWithInvalidHash = `-----BEGIN CERTIFICATE-----
|
||||
MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAWAFBQAwSTELMAkGA1UE
|
||||
BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
|
||||
cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw
|
||||
WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
|
||||
TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
|
||||
Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe
|
||||
m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6
|
||||
jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q
|
||||
fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4
|
||||
NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ
|
||||
0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI
|
||||
dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
|
||||
KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
|
||||
XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
|
||||
MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
|
||||
A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud
|
||||
IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW
|
||||
eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB
|
||||
RzIuY3JsMA0GCSqGSIb3DQFgBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj
|
||||
5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf
|
||||
tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+
|
||||
orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi
|
||||
8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA
|
||||
Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX
|
||||
MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQ4FADBG
|
||||
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
|
||||
QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw
|
||||
ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a
|
||||
wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o
|
||||
55kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr
|
||||
N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs
|
||||
KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q
|
||||
WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw
|
||||
DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC
|
||||
MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0
|
||||
f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb
|
||||
aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v
|
||||
cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n
|
||||
b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD
|
||||
VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow
|
||||
TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4
|
||||
4FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S
|
||||
3T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx
|
||||
1+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB
|
||||
hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC
|
||||
IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQ4F
|
||||
AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p
|
||||
MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd
|
||||
VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga
|
||||
zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI
|
||||
c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP
|
||||
i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const dnssecExpLeaf = `-----BEGIN CERTIFICATE-----
|
||||
@@ -1095,136 +1123,81 @@ DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
|
||||
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
var moipLeafCert = `-----BEGIN CERTIFICATE-----
|
||||
MIIGQDCCBSigAwIBAgIRAPe/cwh7CUWizo8mYSDavLIwDQYJKoZIhvcNAQELBQAw
|
||||
gZIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
|
||||
BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTgwNgYD
|
||||
VQQDEy9DT01PRE8gUlNBIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZl
|
||||
ciBDQTAeFw0xMzA4MTUwMDAwMDBaFw0xNDA4MTUyMzU5NTlaMIIBQjEXMBUGA1UE
|
||||
BRMOMDg3MTg0MzEwMDAxMDgxEzARBgsrBgEEAYI3PAIBAxMCQlIxGjAYBgsrBgEE
|
||||
AYI3PAIBAhMJU2FvIFBhdWxvMR0wGwYDVQQPExRQcml2YXRlIE9yZ2FuaXphdGlv
|
||||
bjELMAkGA1UEBhMCQlIxETAPBgNVBBETCDAxNDUyMDAwMRIwEAYDVQQIEwlTYW8g
|
||||
UGF1bG8xEjAQBgNVBAcTCVNhbyBQYXVsbzEtMCsGA1UECRMkQXZlbmlkYSBCcmln
|
||||
YWRlaXJvIEZhcmlhIExpbWEgLCAyOTI3MR0wGwYDVQQKExRNb2lwIFBhZ2FtZW50
|
||||
b3MgUy5BLjENMAsGA1UECxMETU9JUDEYMBYGA1UECxMPU1NMIEJsaW5kYWRvIEVW
|
||||
MRgwFgYDVQQDEw9hcGkubW9pcC5jb20uYnIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
||||
DwAwggEKAoIBAQDN0b9x6TrXXA9hPCF8/NjqGJ++2D4LO4ZiMFTjs0VwpXy2Y1Oe
|
||||
s74/HuiLGnAHxTmAtV7IpZMibiOcTxcnDYp9oEWkf+gR+hZvwFZwyOBC7wyb3SR3
|
||||
UvV0N1ZbEVRYpN9kuX/3vjDghjDmzzBwu8a/T+y5JTym5uiJlngVAWyh/RjtIvYi
|
||||
+NVkQMbyVlPGkoCe6c30pH8DKYuUCZU6DHjUsPTX3jAskqbhDSAnclX9iX0p2bmw
|
||||
KVBc+5Vh/2geyzDuquF0w+mNIYdU5h7uXvlmJnf3d2Cext5dxdL8/jezD3U0dAqI
|
||||
pYSKERbyxSkJWxdvRlhdpM9YXMJcpc88xNp1AgMBAAGjggHcMIIB2DAfBgNVHSME
|
||||
GDAWgBQ52v/KKBSKqHQTCLnkDqnS+n6daTAdBgNVHQ4EFgQU/lXuOa7DMExzZjRj
|
||||
LQWcMWGZY7swDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYw
|
||||
FAYIKwYBBQUHAwEGCCsGAQUFBwMCMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQUB
|
||||
MCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5jb20vQ1BTMFYG
|
||||
A1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JT
|
||||
QUV4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNybDCBhwYIKwYBBQUH
|
||||
AQEEezB5MFEGCCsGAQUFBzAChkVodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01P
|
||||
RE9SU0FFeHRlbmRlZFZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcnQwJAYIKwYB
|
||||
BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAvBgNVHREEKDAmgg9hcGku
|
||||
bW9pcC5jb20uYnKCE3d3dy5hcGkubW9pcC5jb20uYnIwDQYJKoZIhvcNAQELBQAD
|
||||
ggEBAFoTmPlaDcf+nudhjXHwud8g7/LRyA8ucb+3/vfmgbn7FUc1eprF5sJS1mA+
|
||||
pbiTyXw4IxcJq2KUj0Nw3IPOe9k84mzh+XMmdCKH+QK3NWkE9Udz+VpBOBc0dlqC
|
||||
1RH5umStYDmuZg/8/r652eeQ5kUDcJyADfpKWBgDPYaGtwzKVT4h3Aok9SLXRHx6
|
||||
z/gOaMjEDMarMCMw4VUIG1pvNraZrG5oTaALPaIXXpd8VqbQYPudYJ6fR5eY3FeW
|
||||
H/ofbYFdRcuD26MfBFWE9VGGral9Fgo8sEHffho+UWhgApuQV4/l5fMzxB5YBXyQ
|
||||
jhuy8PqqZS9OuLilTeLu4a8z2JI=
|
||||
const digicertRoot = `-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
var comodoIntermediateSHA384 = `-----BEGIN CERTIFICATE-----
|
||||
MIIGDjCCA/agAwIBAgIQBqdDgNTr/tQ1taP34Wq92DANBgkqhkiG9w0BAQwFADCB
|
||||
hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
|
||||
BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTIwMjEy
|
||||
MDAwMDAwWhcNMjcwMjExMjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
|
||||
EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
|
||||
Q09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBSU0EgRXh0ZW5kZWQg
|
||||
VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEAlVbeVLTf1QJJe9FbXKKyHo+cK2JMK40SKPMalaPGEP0p3uGf
|
||||
CzhAk9HvbpUQ/OGQF3cs7nU+e2PsYZJuTzurgElr3wDqAwB/L3XVKC/sVmePgIOj
|
||||
vdwDmZOLlJFWW6G4ajo/Br0OksxgnP214J9mMF/b5pTwlWqvyIqvgNnmiDkBfBzA
|
||||
xSr3e5Wg8narbZtyOTDr0VdVAZ1YEZ18bYSPSeidCfw8/QpKdhQhXBZzQCMZdMO6
|
||||
WAqmli7eNuWf0MLw4eDBYuPCGEUZUaoXHugjddTI0JYT/8ck0YwLJ66eetw6YWNg
|
||||
iJctXQUL5Tvrrs46R3N2qPos3cCHF+msMJn4HwIDAQABo4IBaTCCAWUwHwYDVR0j
|
||||
BBgwFoAUu69+Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYEFDna/8ooFIqodBMI
|
||||
ueQOqdL6fp1pMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMD4G
|
||||
A1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5j
|
||||
b21vZG8uY29tL0NQUzBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9k
|
||||
b2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggr
|
||||
BgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29t
|
||||
L0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
|
||||
cC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAERCnUFRK0iIXZebeV4R
|
||||
AUpSGXtBLMeJPNBy3IX6WK/VJeQT+FhlZ58N/1eLqYVeyqZLsKeyLeCMIs37/3mk
|
||||
jCuN/gI9JN6pXV/kD0fQ22YlPodHDK4ixVAihNftSlka9pOlk7DgG4HyVsTIEFPk
|
||||
1Hax0VtpS3ey4E/EhOfUoFDuPPpE/NBXueEoU/1Tzdy5H3pAvTA/2GzS8+cHnx8i
|
||||
teoiccsq8FZ8/qyo0QYPFBRSTP5kKwxpKrgNUG4+BAe/eiCL+O5lCeHHSQgyPQ0o
|
||||
fkkdt0rvAucNgBfIXOBhYsvss2B5JdoaZXOcOBCgJjqwyBZ9kzEi7nQLiMBciUEA
|
||||
KKlHMd99SUWa9eanRRrSjhMQ34Ovmw2tfn6dNVA0BM7pINae253UqNpktNEvWS5e
|
||||
ojZh1CSggjMziqHRbO9haKPl0latxf1eYusVqHQSTC8xjOnB3xBLAer2VBvNfzu9
|
||||
XJ/B288ByvK6YBIhMe2pZLiySVgXbVrXzYxtvp5/4gJYp9vDLVj2dAZqmvZh+fYA
|
||||
tmnYOosxWd2R5nwnI4fdAw+PKowegwFOAWEMUnNt/AiiuSpm5HZNMaBWm9lTjaK2
|
||||
jwLI5jqmBNFI+8NKAnb9L9K8E7bobTQk+p0pisehKxTxlgBzuRPpwLk6R1YCcYAn
|
||||
pLwltum95OmYdBbxN4SBB7SC
|
||||
const trustAsiaSHA384Intermediate = `-----BEGIN CERTIFICATE-----
|
||||
MIID9zCCAt+gAwIBAgIQC965p4OR4AKrGlsyW0XrDzANBgkqhkiG9w0BAQwFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0xODA0MjcxMjQyNTlaFw0yODA0MjcxMjQyNTlaMFoxCzAJBgNVBAYTAkNO
|
||||
MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQD
|
||||
ExtUcnVzdEFzaWEgRUNDIE9WIFRMUyBQcm8gQ0EwdjAQBgcqhkjOPQIBBgUrgQQA
|
||||
IgNiAAQPIUn75M5BCQLKoPsSU2KTr3mDMh13usnAQ38XfKOzjXiyQ+W0inA7meYR
|
||||
xS+XMQgvnbCigEsKj3ErPIzO68uC9V/KdqMaXWBJp85Ws9A4KL92NB4Okbn5dp6v
|
||||
Qzy08PajggFeMIIBWjAdBgNVHQ4EFgQULdRyBx6HyIH/+LOvuexyH5p/3PwwHwYD
|
||||
VR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0G
|
||||
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEA
|
||||
MDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AuZGlnaWNl
|
||||
cnQtY24uY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwuZGlnaWNlcnQt
|
||||
Y24uY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDBWBgNVHSAETzBNMDcGCWCG
|
||||
SAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v
|
||||
Q1BTMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQEMBQADggEBACVRufYd
|
||||
j81xUqngFCO+Pk8EYXie0pxHKsBZnOPygAyXKx+awUasKBAnHjmhoFPXaDGAP2oV
|
||||
OeZTWgwnURVr6wUCuTkz2/8Tgl1egC7OrVcHSa0fIIhaVo9/zRA/hr31xMG7LFBk
|
||||
GNd7jd06Up4f/UOGbcJsqJexc5QRcUeSwe1MiUDcTNiyCjZk74QCPdcfdFYM4xsa
|
||||
SlUpboB5vyT7jFePZ2v95CKjcr0EhiQ0gwxpdgoipZdfYTiMFGxCLsk6v8pUv7Tq
|
||||
PT/qadOGyC+PfLuZh1PtLp20mF06K+MzheCiv+w1NT5ofhmcObvukc68wvbvRFL6
|
||||
rRzZxAYN36q1SX8=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const comodoRSAAuthority = `-----BEGIN CERTIFICATE-----
|
||||
MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv
|
||||
MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
|
||||
ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
|
||||
eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow
|
||||
gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
|
||||
BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD
|
||||
VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw
|
||||
AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6
|
||||
2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr
|
||||
ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt
|
||||
4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq
|
||||
m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/
|
||||
vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT
|
||||
8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE
|
||||
IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO
|
||||
KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO
|
||||
GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/
|
||||
s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g
|
||||
JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD
|
||||
AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9
|
||||
MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy
|
||||
bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6
|
||||
Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ
|
||||
zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj
|
||||
Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY
|
||||
Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5
|
||||
B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx
|
||||
PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR
|
||||
pu/xO28QOG8=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const addTrustRoot = `-----BEGIN CERTIFICATE-----
|
||||
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
|
||||
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
|
||||
IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
|
||||
MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
|
||||
FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
|
||||
bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
|
||||
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
|
||||
H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
|
||||
uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
|
||||
mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
|
||||
a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
|
||||
E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
|
||||
WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
|
||||
VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
|
||||
Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
|
||||
cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
|
||||
IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
|
||||
AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
|
||||
YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
|
||||
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
|
||||
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
|
||||
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
|
||||
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
|
||||
const trustAsiaLeaf = `-----BEGIN CERTIFICATE-----
|
||||
MIIEwTCCBEegAwIBAgIQBOjomZfHfhgz2bVYZVuf2DAKBggqhkjOPQQDAzBaMQsw
|
||||
CQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5j
|
||||
LjEkMCIGA1UEAxMbVHJ1c3RBc2lhIEVDQyBPViBUTFMgUHJvIENBMB4XDTE5MDUx
|
||||
NzAwMDAwMFoXDTIwMDcyODEyMDAwMFowgY0xCzAJBgNVBAYTAkNOMRIwEAYDVQQI
|
||||
DAnnpo/lu7rnnIExEjAQBgNVBAcMCeWOpumXqOW4gjEqMCgGA1UECgwh5Y6m6Zeo
|
||||
5Y+B546W5Y+B56eR5oqA5pyJ6ZmQ5YWs5Y+4MRgwFgYDVQQLDA/nn6Xor4bkuqfm
|
||||
nYPpg6gxEDAOBgNVBAMMByoudG0uY24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
|
||||
AARx/MDQ0oGnCLagQIzjIz57iqFYFmz4/W6gaU6N+GHBkzyvQU8aX02QkdlTTNYL
|
||||
TCoGFJxHB0XlZVSxrqoIPlNKo4ICuTCCArUwHwYDVR0jBBgwFoAULdRyBx6HyIH/
|
||||
+LOvuexyH5p/3PwwHQYDVR0OBBYEFGTyf5adc5smW8NvDZyummJwZRLEMBkGA1Ud
|
||||
EQQSMBCCByoudG0uY26CBXRtLmNuMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAU
|
||||
BggrBgEFBQcDAQYIKwYBBQUHAwIwRgYDVR0fBD8wPTA7oDmgN4Y1aHR0cDovL2Ny
|
||||
bC5kaWdpY2VydC1jbi5jb20vVHJ1c3RBc2lhRUNDT1ZUTFNQcm9DQS5jcmwwTAYD
|
||||
VR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cu
|
||||
ZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfgYIKwYBBQUHAQEEcjBwMCcGCCsG
|
||||
AQUFBzABhhtodHRwOi8vb2NzcC5kaWdpY2VydC1jbi5jb20wRQYIKwYBBQUHMAKG
|
||||
OWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LWNuLmNvbS9UcnVzdEFzaWFFQ0NPVlRM
|
||||
U1Byb0NBLmNydDAMBgNVHRMBAf8EAjAAMIIBAwYKKwYBBAHWeQIEAgSB9ASB8QDv
|
||||
AHUA7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/csAAAFqxGMTnwAABAMA
|
||||
RjBEAiAz13zKEoyqd4e/96SK/fxfjl7uR+xhfoDZeyA1BvtfOwIgTY+8nJMGekv8
|
||||
leIVdW6AGh7oqH31CIGTAbNJJWzaSFYAdgCHdb/nWXz4jEOZX73zbv9WjUdWNv9K
|
||||
tWDBtOr/XqCDDwAAAWrEYxTCAAAEAwBHMEUCIQDlWm7+limbRiurcqUwXav3NSmx
|
||||
x/aMnolLbh6+f+b1XAIgQfinHwLw6pDr4R9UkndUsX8QFF4GXS3/IwRR8HCp+pIw
|
||||
CgYIKoZIzj0EAwMDaAAwZQIwHg8JmjRtcq+OgV0vVmdVBPqehi1sQJ9PZ+51CG+Z
|
||||
0GOu+2HwS/fyLRViwSc/MZoVAjEA7NgbgpPN4OIsZn2XjMGxemtVxGFS6ZR+1364
|
||||
EEeHB9vhZAEjQSePAfjR9aAGhXRa
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const selfSigned = `-----BEGIN CERTIFICATE-----
|
||||
@@ -1508,33 +1481,36 @@ ePBQCV1F9sE2q4ZrnsT9TZoNrSe/bMDjzA==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
var unknownAuthorityErrorTests = []struct {
|
||||
name string
|
||||
cert string
|
||||
expected string
|
||||
}{
|
||||
{selfSignedWithCommonName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"test\")"},
|
||||
{selfSignedNoCommonNameWithOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"ca\")"},
|
||||
{selfSignedNoCommonNameNoOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"serial:0\")"},
|
||||
{"self-signed, cn", selfSignedWithCommonName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"test\")"},
|
||||
{"self-signed, no cn, org", selfSignedNoCommonNameWithOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"ca\")"},
|
||||
{"self-signed, no cn, no org", selfSignedNoCommonNameNoOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"serial:0\")"},
|
||||
}
|
||||
|
||||
func TestUnknownAuthorityError(t *testing.T) {
|
||||
for i, tt := range unknownAuthorityErrorTests {
|
||||
der, _ := pem.Decode([]byte(tt.cert))
|
||||
if der == nil {
|
||||
t.Errorf("#%d: Unable to decode PEM block", i)
|
||||
}
|
||||
c, err := ParseCertificate(der.Bytes)
|
||||
if err != nil {
|
||||
t.Errorf("#%d: Unable to parse certificate -> %v", i, err)
|
||||
}
|
||||
uae := &UnknownAuthorityError{
|
||||
Cert: c,
|
||||
hintErr: fmt.Errorf("empty"),
|
||||
hintCert: c,
|
||||
}
|
||||
actual := uae.Error()
|
||||
if actual != tt.expected {
|
||||
t.Errorf("#%d: UnknownAuthorityError.Error() response invalid actual: %s expected: %s", i, actual, tt.expected)
|
||||
}
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
der, _ := pem.Decode([]byte(tt.cert))
|
||||
if der == nil {
|
||||
t.Fatalf("#%d: Unable to decode PEM block", i)
|
||||
}
|
||||
c, err := ParseCertificate(der.Bytes)
|
||||
if err != nil {
|
||||
t.Fatalf("#%d: Unable to parse certificate -> %v", i, err)
|
||||
}
|
||||
uae := &UnknownAuthorityError{
|
||||
Cert: c,
|
||||
hintErr: fmt.Errorf("empty"),
|
||||
hintCert: c,
|
||||
}
|
||||
actual := uae.Error()
|
||||
if actual != tt.expected {
|
||||
t.Errorf("#%d: UnknownAuthorityError.Error() response invalid actual: %s expected: %s", i, actual, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1852,10 +1828,10 @@ func TestSystemRootsError(t *testing.T) {
|
||||
opts := VerifyOptions{
|
||||
Intermediates: NewCertPool(),
|
||||
DNSName: "www.google.com",
|
||||
CurrentTime: time.Unix(1395785200, 0),
|
||||
CurrentTime: time.Unix(1677615892, 0),
|
||||
}
|
||||
|
||||
if ok := opts.Intermediates.AppendCertsFromPEM([]byte(giag2Intermediate)); !ok {
|
||||
if ok := opts.Intermediates.AppendCertsFromPEM([]byte(gtsIntermediate)); !ok {
|
||||
t.Fatalf("failed to parse intermediate")
|
||||
}
|
||||
|
||||
@@ -1881,6 +1857,16 @@ func TestSystemRootsErrorUnwrap(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIssue51759(t *testing.T) {
|
||||
if runtime.GOOS != "darwin" {
|
||||
t.Skip("only affects darwin")
|
||||
}
|
||||
builder := testenv.Builder()
|
||||
if builder == "" {
|
||||
t.Skip("only run this test on the builders, as we have no reasonable way to gate tests on macOS versions elsewhere")
|
||||
}
|
||||
if builder == "darwin-amd64-10_14" || builder == "darwin-amd64-10_15" {
|
||||
t.Skip("behavior only enforced in macOS 11 and after")
|
||||
}
|
||||
// badCertData contains a cert that we parse as valid
|
||||
// but that macOS SecCertificateCreateWithData rejects.
|
||||
const badCertData = "0\x82\x01U0\x82\x01\a\xa0\x03\x02\x01\x02\x02\x01\x020\x05\x06\x03+ep0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260\x1e\x17\r220112235755Z\x17\r220313235755Z0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260*0\x05\x06\x03+ep\x03!\x00bA\xd8e\xadW\xcb\xefZ\x89\xb5\"\x1eR\x9d\xba\x0e:\x1042Q@\u007f\xbd\xfb{ks\x04\xd1£\x020\x000\x05\x06\x03+ep\x03A\x00[\xa7\x06y\x86(\x94\x97\x9eLwA\x00\x01x\xaa\xbc\xbd Ê]\n(΅!ف0\xf5\x9a%I\x19<\xffo\xf1\xeaaf@\xb1\xa7\xaf\xfd\xe9R\xc7\x0f\x8d&\xd5\xfc\x0f;Ϙ\x82\x84a\xbc\r"
|
||||
@@ -1891,9 +1877,10 @@ func TestIssue51759(t *testing.T) {
|
||||
|
||||
t.Run("leaf", func(t *testing.T) {
|
||||
opts := VerifyOptions{}
|
||||
expectedErr := "invalid leaf certificate"
|
||||
_, err = badCert.Verify(opts)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
if err == nil || err.Error() != expectedErr {
|
||||
t.Fatalf("unexpected error: want %q, got %q", expectedErr, err)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1907,9 +1894,10 @@ func TestIssue51759(t *testing.T) {
|
||||
Intermediates: NewCertPool(),
|
||||
}
|
||||
opts.Intermediates.AddCert(badCert)
|
||||
expectedErr := "SecCertificateCreateWithData: invalid certificate"
|
||||
_, err = goodCert.Verify(opts)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
if err == nil || err.Error() != expectedErr {
|
||||
t.Fatalf("unexpected error: want %q, got %q", expectedErr, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ go 1.20
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a
|
||||
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10
|
||||
golang.org/x/net v0.4.1-0.20230214201333-88ed8ca3307d
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a h1:diz9pEYuTIuLMJLs3rGDkeaTsNyRs6duYdFyPAxzE/U=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 h1:Frnccbp+ok2GkUS2tC84yAq/U9Vg+0sIO7aRL3T4Xnc=
|
||||
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.4.1-0.20230214201333-88ed8ca3307d h1:KHU/KRz6+/yWyRHEC24m7T5gou5VSh62duch955ktBY=
|
||||
golang.org/x/net v0.4.1-0.20230214201333-88ed8ca3307d/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
|
||||
@@ -42,8 +42,9 @@ func lookupGorootExport(pkgDir string) (string, bool) {
|
||||
)
|
||||
f, _ = exportMap.LoadOrStore(pkgDir, func() (string, bool) {
|
||||
listOnce.Do(func() {
|
||||
cmd := exec.Command("go", "list", "-export", "-f", "{{.Export}}", pkgDir)
|
||||
cmd := exec.Command(filepath.Join(build.Default.GOROOT, "bin", "go"), "list", "-export", "-f", "{{.Export}}", pkgDir)
|
||||
cmd.Dir = build.Default.GOROOT
|
||||
cmd.Env = append(cmd.Environ(), "GOROOT="+build.Default.GOROOT)
|
||||
var output []byte
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
|
||||
@@ -764,3 +764,19 @@ func TestRangePos(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestIssue59180 tests that line number overflow doesn't cause an infinite loop.
|
||||
func TestIssue59180(t *testing.T) {
|
||||
testcases := []string{
|
||||
"package p\n//line :9223372036854775806\n\n//",
|
||||
"package p\n//line :1:9223372036854775806\n\n//",
|
||||
"package p\n//line file:9223372036854775806\n\n//",
|
||||
}
|
||||
|
||||
for _, src := range testcases {
|
||||
_, err := ParseFile(token.NewFileSet(), "", src, ParseComments)
|
||||
if err == nil {
|
||||
t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,13 +253,16 @@ func (s *Scanner) updateLineInfo(next, offs int, text []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
// Put a cap on the maximum size of line and column numbers.
|
||||
// 30 bits allows for some additional space before wrapping an int32.
|
||||
const maxLineCol = 1<<30 - 1
|
||||
var line, col int
|
||||
i2, n2, ok2 := trailingDigits(text[:i-1])
|
||||
if ok2 {
|
||||
//line filename:line:col
|
||||
i, i2 = i2, i
|
||||
line, col = n2, n
|
||||
if col == 0 {
|
||||
if col == 0 || col > maxLineCol {
|
||||
s.error(offs+i2, "invalid column number: "+string(text[i2:]))
|
||||
return
|
||||
}
|
||||
@@ -269,7 +272,7 @@ func (s *Scanner) updateLineInfo(next, offs int, text []byte) {
|
||||
line = n
|
||||
}
|
||||
|
||||
if line == 0 {
|
||||
if line == 0 || line > maxLineCol {
|
||||
s.error(offs+i, "invalid line number: "+string(text[i:]))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -120,6 +120,8 @@ const (
|
||||
stateJSDqStr
|
||||
// stateJSSqStr occurs inside a JavaScript single quoted string.
|
||||
stateJSSqStr
|
||||
// stateJSBqStr occurs inside a JavaScript back quoted string.
|
||||
stateJSBqStr
|
||||
// stateJSRegexp occurs inside a JavaScript regexp literal.
|
||||
stateJSRegexp
|
||||
// stateJSBlockCmt occurs inside a JavaScript /* block comment */.
|
||||
|
||||
@@ -238,7 +238,7 @@ func cssValueFilter(args ...any) string {
|
||||
// inside a string that might embed JavaScript source.
|
||||
for i, c := range b {
|
||||
switch c {
|
||||
case 0, '"', '\'', '(', ')', '/', ';', '@', '[', '\\', ']', '`', '{', '}':
|
||||
case 0, '"', '\'', '(', ')', '/', ';', '@', '[', '\\', ']', '`', '{', '}', '<', '>':
|
||||
return filterFailsafe
|
||||
case '-':
|
||||
// Disallow <!-- or -->.
|
||||
|
||||
@@ -231,6 +231,8 @@ func TestCSSValueFilter(t *testing.T) {
|
||||
{`-exp\000052 ession(alert(1337))`, "ZgotmplZ"},
|
||||
{`-expre\0000073sion`, "-expre\x073sion"},
|
||||
{`@import url evil.css`, "ZgotmplZ"},
|
||||
{"<", "ZgotmplZ"},
|
||||
{">", "ZgotmplZ"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
got := cssValueFilter(test.css)
|
||||
|
||||
@@ -231,5 +231,12 @@ Least Surprise Property:
|
||||
"A developer (or code reviewer) familiar with HTML, CSS, and JavaScript, who
|
||||
knows that contextual autoescaping happens should be able to look at a {{.}}
|
||||
and correctly infer what sanitization happens."
|
||||
|
||||
As a consequence of the Least Surprise Property, template actions within an
|
||||
ECMAScript 6 template literal are disabled by default.
|
||||
Handling string interpolation within these literals is rather complex resulting
|
||||
in no clear safe way to support it.
|
||||
To re-enable template actions within ECMAScript 6 template literals, use the
|
||||
GODEBUG=jstmpllitinterp=1 environment variable.
|
||||
*/
|
||||
package template
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user