mirror of
https://github.com/golang/go.git
synced 2026-01-30 15:42:04 +03:00
Compare commits
31 Commits
dev.corety
...
go1.20.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 -->
|
||||
|
||||
@@ -180,10 +180,14 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
argument(e.discardHole(), &call.Args[i])
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -517,13 +517,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 {
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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.
|
||||
//
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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)
|
||||
|
||||
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")
|
||||
}
|
||||
@@ -31,6 +31,8 @@ import (
|
||||
// See issues 36852, 41409, and 43687.
|
||||
// (Also see golang.org/issue/27348.)
|
||||
func TestAllDependencies(t *testing.T) {
|
||||
t.Skip("TODO(#58356): 1.19.4 contains unreleased changes from vendored modules")
|
||||
|
||||
goBin := testenv.GoToolPath(t)
|
||||
|
||||
// Ensure that all packages imported within GOROOT
|
||||
|
||||
@@ -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.
|
||||
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1257,7 +1257,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 +1500,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, hs.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 {
|
||||
|
||||
@@ -123,8 +123,6 @@ func (d *CoverageMetaDataDecoder) ReadFunc(fidx uint32, f *coverage.FuncDesc) er
|
||||
})
|
||||
}
|
||||
lit := d.r.ReadULEB128()
|
||||
if lit != 0 {
|
||||
f.Lit = true
|
||||
}
|
||||
f.Lit = lit != 0
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -274,3 +274,58 @@ func TestMetaDataWriterReader(t *testing.T) {
|
||||
inf.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetaDataDecodeLitFlagIssue57942(t *testing.T) {
|
||||
|
||||
// Encode a package with a few functions. The funcs alternate
|
||||
// between regular functions and function literals.
|
||||
pp := "foo/bar/pkg"
|
||||
pn := "pkg"
|
||||
mp := "barmod"
|
||||
b, err := encodemeta.NewCoverageMetaDataBuilder(pp, pn, mp)
|
||||
if err != nil {
|
||||
t.Fatalf("making builder: %v", err)
|
||||
}
|
||||
const NF = 6
|
||||
const NCU = 1
|
||||
ln := uint32(10)
|
||||
wantfds := []coverage.FuncDesc{}
|
||||
for fi := uint32(0); fi < NF; fi++ {
|
||||
fis := fmt.Sprintf("%d", fi)
|
||||
fd := coverage.FuncDesc{
|
||||
Funcname: "func" + fis,
|
||||
Srcfile: "foo" + fis + ".go",
|
||||
Units: []coverage.CoverableUnit{
|
||||
coverage.CoverableUnit{StLine: ln + 1, StCol: 2, EnLine: ln + 3, EnCol: 4, NxStmts: fi + 2},
|
||||
},
|
||||
Lit: (fi % 2) == 0,
|
||||
}
|
||||
wantfds = append(wantfds, fd)
|
||||
b.AddFunc(fd)
|
||||
}
|
||||
|
||||
// Emit into a writer.
|
||||
drws := &slicewriter.WriteSeeker{}
|
||||
b.Emit(drws)
|
||||
|
||||
// Decode the result.
|
||||
drws.Seek(0, io.SeekStart)
|
||||
dec, err := decodemeta.NewCoverageMetaDataDecoder(drws.BytesWritten(), false)
|
||||
if err != nil {
|
||||
t.Fatalf("making decoder: %v", err)
|
||||
}
|
||||
nf := dec.NumFuncs()
|
||||
if nf != NF {
|
||||
t.Fatalf("decoder number of functions: got %d want %d", nf, NF)
|
||||
}
|
||||
var fn coverage.FuncDesc
|
||||
for i := uint32(0); i < uint32(NF); i++ {
|
||||
if err := dec.ReadFunc(i, &fn); err != nil {
|
||||
t.Fatalf("err reading function %d: %v", i, err)
|
||||
}
|
||||
res := cmpFuncDesc(wantfds[i], fn)
|
||||
if res != "" {
|
||||
t.Errorf("ReadFunc(%d): %s", i, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package multipart
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"internal/godebug"
|
||||
"io"
|
||||
"math"
|
||||
"net/textproto"
|
||||
@@ -31,25 +32,61 @@ func (r *Reader) ReadForm(maxMemory int64) (*Form, error) {
|
||||
return r.readForm(maxMemory)
|
||||
}
|
||||
|
||||
var multipartFiles = godebug.New("multipartfiles")
|
||||
|
||||
func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
|
||||
form := &Form{make(map[string][]string), make(map[string][]*FileHeader)}
|
||||
var (
|
||||
file *os.File
|
||||
fileOff int64
|
||||
)
|
||||
numDiskFiles := 0
|
||||
combineFiles := multipartFiles.Value() != "distinct"
|
||||
defer func() {
|
||||
if file != nil {
|
||||
if cerr := file.Close(); err == nil {
|
||||
err = cerr
|
||||
}
|
||||
}
|
||||
if combineFiles && numDiskFiles > 1 {
|
||||
for _, fhs := range form.File {
|
||||
for _, fh := range fhs {
|
||||
fh.tmpshared = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
form.RemoveAll()
|
||||
if file != nil {
|
||||
os.Remove(file.Name())
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Reserve an additional 10 MB for non-file parts.
|
||||
maxValueBytes := maxMemory + int64(10<<20)
|
||||
if maxValueBytes <= 0 {
|
||||
// maxFileMemoryBytes is the maximum bytes of file data we will store in memory.
|
||||
// Data past this limit is written to disk.
|
||||
// This limit strictly applies to content, not metadata (filenames, MIME headers, etc.),
|
||||
// since metadata is always stored in memory, not disk.
|
||||
//
|
||||
// maxMemoryBytes is the maximum bytes we will store in memory, including file content,
|
||||
// non-file part values, metdata, and map entry overhead.
|
||||
//
|
||||
// We reserve an additional 10 MB in maxMemoryBytes for non-file data.
|
||||
//
|
||||
// The relationship between these parameters, as well as the overly-large and
|
||||
// unconfigurable 10 MB added on to maxMemory, is unfortunate but difficult to change
|
||||
// within the constraints of the API as documented.
|
||||
maxFileMemoryBytes := maxMemory
|
||||
maxMemoryBytes := maxMemory + int64(10<<20)
|
||||
if maxMemoryBytes <= 0 {
|
||||
if maxMemory < 0 {
|
||||
maxValueBytes = 0
|
||||
maxMemoryBytes = 0
|
||||
} else {
|
||||
maxValueBytes = math.MaxInt64
|
||||
maxMemoryBytes = math.MaxInt64
|
||||
}
|
||||
}
|
||||
for {
|
||||
p, err := r.NextPart()
|
||||
p, err := r.nextPart(false, maxMemoryBytes)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
@@ -63,16 +100,27 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
|
||||
}
|
||||
filename := p.FileName()
|
||||
|
||||
// Multiple values for the same key (one map entry, longer slice) are cheaper
|
||||
// than the same number of values for different keys (many map entries), but
|
||||
// using a consistent per-value cost for overhead is simpler.
|
||||
maxMemoryBytes -= int64(len(name))
|
||||
maxMemoryBytes -= 100 // map overhead
|
||||
if maxMemoryBytes < 0 {
|
||||
// We can't actually take this path, since nextPart would already have
|
||||
// rejected the MIME headers for being too large. Check anyway.
|
||||
return nil, ErrMessageTooLarge
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
|
||||
if filename == "" {
|
||||
// value, store as string in memory
|
||||
n, err := io.CopyN(&b, p, maxValueBytes+1)
|
||||
n, err := io.CopyN(&b, p, maxMemoryBytes+1)
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
maxValueBytes -= n
|
||||
if maxValueBytes < 0 {
|
||||
maxMemoryBytes -= n
|
||||
if maxMemoryBytes < 0 {
|
||||
return nil, ErrMessageTooLarge
|
||||
}
|
||||
form.Value[name] = append(form.Value[name], b.String())
|
||||
@@ -80,35 +128,45 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
|
||||
}
|
||||
|
||||
// file, store in memory or on disk
|
||||
maxMemoryBytes -= mimeHeaderSize(p.Header)
|
||||
if maxMemoryBytes < 0 {
|
||||
return nil, ErrMessageTooLarge
|
||||
}
|
||||
fh := &FileHeader{
|
||||
Filename: filename,
|
||||
Header: p.Header,
|
||||
}
|
||||
n, err := io.CopyN(&b, p, maxMemory+1)
|
||||
n, err := io.CopyN(&b, p, maxFileMemoryBytes+1)
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
if n > maxMemory {
|
||||
// too big, write to disk and flush buffer
|
||||
file, err := os.CreateTemp("", "multipart-")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if n > maxFileMemoryBytes {
|
||||
if file == nil {
|
||||
file, err = os.CreateTemp(r.tempDir, "multipart-")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
numDiskFiles++
|
||||
size, err := io.Copy(file, io.MultiReader(&b, p))
|
||||
if cerr := file.Close(); err == nil {
|
||||
err = cerr
|
||||
}
|
||||
if err != nil {
|
||||
os.Remove(file.Name())
|
||||
return nil, err
|
||||
}
|
||||
fh.tmpfile = file.Name()
|
||||
fh.Size = size
|
||||
fh.tmpoff = fileOff
|
||||
fileOff += size
|
||||
if !combineFiles {
|
||||
if err := file.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
file = nil
|
||||
}
|
||||
} else {
|
||||
fh.content = b.Bytes()
|
||||
fh.Size = int64(len(fh.content))
|
||||
maxMemory -= n
|
||||
maxValueBytes -= n
|
||||
maxFileMemoryBytes -= n
|
||||
maxMemoryBytes -= n
|
||||
}
|
||||
form.File[name] = append(form.File[name], fh)
|
||||
}
|
||||
@@ -116,6 +174,17 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
|
||||
return form, nil
|
||||
}
|
||||
|
||||
func mimeHeaderSize(h textproto.MIMEHeader) (size int64) {
|
||||
for k, vs := range h {
|
||||
size += int64(len(k))
|
||||
size += 100 // map entry overhead
|
||||
for _, v := range vs {
|
||||
size += int64(len(v))
|
||||
}
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// Form is a parsed multipart form.
|
||||
// Its File parts are stored either in memory or on disk,
|
||||
// and are accessible via the *FileHeader's Open method.
|
||||
@@ -133,7 +202,7 @@ func (f *Form) RemoveAll() error {
|
||||
for _, fh := range fhs {
|
||||
if fh.tmpfile != "" {
|
||||
e := os.Remove(fh.tmpfile)
|
||||
if e != nil && err == nil {
|
||||
if e != nil && !errors.Is(e, os.ErrNotExist) && err == nil {
|
||||
err = e
|
||||
}
|
||||
}
|
||||
@@ -148,15 +217,25 @@ type FileHeader struct {
|
||||
Header textproto.MIMEHeader
|
||||
Size int64
|
||||
|
||||
content []byte
|
||||
tmpfile string
|
||||
content []byte
|
||||
tmpfile string
|
||||
tmpoff int64
|
||||
tmpshared bool
|
||||
}
|
||||
|
||||
// Open opens and returns the FileHeader's associated File.
|
||||
func (fh *FileHeader) Open() (File, error) {
|
||||
if b := fh.content; b != nil {
|
||||
r := io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b)))
|
||||
return sectionReadCloser{r}, nil
|
||||
return sectionReadCloser{r, nil}, nil
|
||||
}
|
||||
if fh.tmpshared {
|
||||
f, err := os.Open(fh.tmpfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r := io.NewSectionReader(f, fh.tmpoff, fh.Size)
|
||||
return sectionReadCloser{r, f}, nil
|
||||
}
|
||||
return os.Open(fh.tmpfile)
|
||||
}
|
||||
@@ -175,8 +254,12 @@ type File interface {
|
||||
|
||||
type sectionReadCloser struct {
|
||||
*io.SectionReader
|
||||
io.Closer
|
||||
}
|
||||
|
||||
func (rc sectionReadCloser) Close() error {
|
||||
if rc.Closer != nil {
|
||||
return rc.Closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,8 +5,11 @@
|
||||
package multipart
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -207,8 +210,8 @@ Content-Disposition: form-data; name="largetext"
|
||||
maxMemory int64
|
||||
err error
|
||||
}{
|
||||
{"smaller", 50, nil},
|
||||
{"exact-fit", 25, nil},
|
||||
{"smaller", 50 + int64(len("largetext")) + 100, nil},
|
||||
{"exact-fit", 25 + int64(len("largetext")) + 100, nil},
|
||||
{"too-large", 0, ErrMessageTooLarge},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
@@ -223,7 +226,7 @@ Content-Disposition: form-data; name="largetext"
|
||||
defer f.RemoveAll()
|
||||
}
|
||||
if tc.err != err {
|
||||
t.Fatalf("ReadForm error - got: %v; expected: %v", tc.err, err)
|
||||
t.Fatalf("ReadForm error - got: %v; expected: %v", err, tc.err)
|
||||
}
|
||||
if err == nil {
|
||||
if g := f.Value["largetext"][0]; g != largeTextValue {
|
||||
@@ -233,3 +236,135 @@ Content-Disposition: form-data; name="largetext"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestReadForm_MetadataTooLarge verifies that we account for the size of field names,
|
||||
// MIME headers, and map entry overhead while limiting the memory consumption of parsed forms.
|
||||
func TestReadForm_MetadataTooLarge(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
f func(*Writer)
|
||||
}{{
|
||||
name: "large name",
|
||||
f: func(fw *Writer) {
|
||||
name := strings.Repeat("a", 10<<20)
|
||||
w, _ := fw.CreateFormField(name)
|
||||
w.Write([]byte("value"))
|
||||
},
|
||||
}, {
|
||||
name: "large MIME header",
|
||||
f: func(fw *Writer) {
|
||||
h := make(textproto.MIMEHeader)
|
||||
h.Set("Content-Disposition", `form-data; name="a"`)
|
||||
h.Set("X-Foo", strings.Repeat("a", 10<<20))
|
||||
w, _ := fw.CreatePart(h)
|
||||
w.Write([]byte("value"))
|
||||
},
|
||||
}, {
|
||||
name: "many parts",
|
||||
f: func(fw *Writer) {
|
||||
for i := 0; i < 110000; i++ {
|
||||
w, _ := fw.CreateFormField("f")
|
||||
w.Write([]byte("v"))
|
||||
}
|
||||
},
|
||||
}} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
fw := NewWriter(&buf)
|
||||
test.f(fw)
|
||||
if err := fw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fr := NewReader(&buf, fw.Boundary())
|
||||
_, err := fr.ReadForm(0)
|
||||
if err != ErrMessageTooLarge {
|
||||
t.Errorf("fr.ReadForm() = %v, want ErrMessageTooLarge", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestReadForm_ManyFiles_Combined tests that a multipart form containing many files only
|
||||
// results in a single on-disk file.
|
||||
func TestReadForm_ManyFiles_Combined(t *testing.T) {
|
||||
const distinct = false
|
||||
testReadFormManyFiles(t, distinct)
|
||||
}
|
||||
|
||||
// TestReadForm_ManyFiles_Distinct tests that setting GODEBUG=multipartfiles=distinct
|
||||
// results in every file in a multipart form being placed in a distinct on-disk file.
|
||||
func TestReadForm_ManyFiles_Distinct(t *testing.T) {
|
||||
t.Setenv("GODEBUG", "multipartfiles=distinct")
|
||||
const distinct = true
|
||||
testReadFormManyFiles(t, distinct)
|
||||
}
|
||||
|
||||
func testReadFormManyFiles(t *testing.T, distinct bool) {
|
||||
var buf bytes.Buffer
|
||||
fw := NewWriter(&buf)
|
||||
const numFiles = 10
|
||||
for i := 0; i < numFiles; i++ {
|
||||
name := fmt.Sprint(i)
|
||||
w, err := fw.CreateFormFile(name, name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w.Write([]byte(name))
|
||||
}
|
||||
if err := fw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fr := NewReader(&buf, fw.Boundary())
|
||||
fr.tempDir = t.TempDir()
|
||||
form, err := fr.ReadForm(0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := 0; i < numFiles; i++ {
|
||||
name := fmt.Sprint(i)
|
||||
if got := len(form.File[name]); got != 1 {
|
||||
t.Fatalf("form.File[%q] has %v entries, want 1", name, got)
|
||||
}
|
||||
fh := form.File[name][0]
|
||||
file, err := fh.Open()
|
||||
if err != nil {
|
||||
t.Fatalf("form.File[%q].Open() = %v", name, err)
|
||||
}
|
||||
if distinct {
|
||||
if _, ok := file.(*os.File); !ok {
|
||||
t.Fatalf("form.File[%q].Open: %T, want *os.File", name, file)
|
||||
}
|
||||
}
|
||||
got, err := io.ReadAll(file)
|
||||
file.Close()
|
||||
if string(got) != name || err != nil {
|
||||
t.Fatalf("read form.File[%q]: %q, %v; want %q, nil", name, string(got), err, name)
|
||||
}
|
||||
}
|
||||
dir, err := os.Open(fr.tempDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer dir.Close()
|
||||
names, err := dir.Readdirnames(0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantNames := 1
|
||||
if distinct {
|
||||
wantNames = numFiles
|
||||
}
|
||||
if len(names) != wantNames {
|
||||
t.Fatalf("temp dir contains %v files; want 1", len(names))
|
||||
}
|
||||
if err := form.RemoveAll(); err != nil {
|
||||
t.Fatalf("form.RemoveAll() = %v", err)
|
||||
}
|
||||
names, err = dir.Readdirnames(0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(names) != 0 {
|
||||
t.Fatalf("temp dir contains %v files; want 0", len(names))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,12 +128,12 @@ func (r *stickyErrorReader) Read(p []byte) (n int, _ error) {
|
||||
return n, r.err
|
||||
}
|
||||
|
||||
func newPart(mr *Reader, rawPart bool) (*Part, error) {
|
||||
func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) {
|
||||
bp := &Part{
|
||||
Header: make(map[string][]string),
|
||||
mr: mr,
|
||||
}
|
||||
if err := bp.populateHeaders(); err != nil {
|
||||
if err := bp.populateHeaders(maxMIMEHeaderSize); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bp.r = partReader{bp}
|
||||
@@ -149,12 +149,16 @@ func newPart(mr *Reader, rawPart bool) (*Part, error) {
|
||||
return bp, nil
|
||||
}
|
||||
|
||||
func (p *Part) populateHeaders() error {
|
||||
func (p *Part) populateHeaders(maxMIMEHeaderSize int64) error {
|
||||
r := textproto.NewReader(p.mr.bufReader)
|
||||
header, err := r.ReadMIMEHeader()
|
||||
header, err := readMIMEHeader(r, maxMIMEHeaderSize)
|
||||
if err == nil {
|
||||
p.Header = header
|
||||
}
|
||||
// TODO: Add a distinguishable error to net/textproto.
|
||||
if err != nil && err.Error() == "message too large" {
|
||||
err = ErrMessageTooLarge
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -311,6 +315,7 @@ func (p *Part) Close() error {
|
||||
// isn't supported.
|
||||
type Reader struct {
|
||||
bufReader *bufio.Reader
|
||||
tempDir string // used in tests
|
||||
|
||||
currentPart *Part
|
||||
partsRead int
|
||||
@@ -321,6 +326,10 @@ type Reader struct {
|
||||
dashBoundary []byte // "--boundary"
|
||||
}
|
||||
|
||||
// maxMIMEHeaderSize is the maximum size of a MIME header we will parse,
|
||||
// including header keys, values, and map overhead.
|
||||
const maxMIMEHeaderSize = 10 << 20
|
||||
|
||||
// NextPart returns the next part in the multipart or an error.
|
||||
// When there are no more parts, the error io.EOF is returned.
|
||||
//
|
||||
@@ -328,7 +337,7 @@ type Reader struct {
|
||||
// has a value of "quoted-printable", that header is instead
|
||||
// hidden and the body is transparently decoded during Read calls.
|
||||
func (r *Reader) NextPart() (*Part, error) {
|
||||
return r.nextPart(false)
|
||||
return r.nextPart(false, maxMIMEHeaderSize)
|
||||
}
|
||||
|
||||
// NextRawPart returns the next part in the multipart or an error.
|
||||
@@ -337,10 +346,10 @@ func (r *Reader) NextPart() (*Part, error) {
|
||||
// Unlike NextPart, it does not have special handling for
|
||||
// "Content-Transfer-Encoding: quoted-printable".
|
||||
func (r *Reader) NextRawPart() (*Part, error) {
|
||||
return r.nextPart(true)
|
||||
return r.nextPart(true, maxMIMEHeaderSize)
|
||||
}
|
||||
|
||||
func (r *Reader) nextPart(rawPart bool) (*Part, error) {
|
||||
func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) {
|
||||
if r.currentPart != nil {
|
||||
r.currentPart.Close()
|
||||
}
|
||||
@@ -365,7 +374,7 @@ func (r *Reader) nextPart(rawPart bool) (*Part, error) {
|
||||
|
||||
if r.isBoundaryDelimiterLine(line) {
|
||||
r.partsRead++
|
||||
bp, err := newPart(r, rawPart)
|
||||
bp, err := newPart(r, rawPart, maxMIMEHeaderSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
14
src/mime/multipart/readmimeheader.go
Normal file
14
src/mime/multipart/readmimeheader.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// 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 multipart
|
||||
|
||||
import (
|
||||
"net/textproto"
|
||||
_ "unsafe" // for go:linkname
|
||||
)
|
||||
|
||||
// readMIMEHeader is defined in package net/textproto.
|
||||
//
|
||||
//go:linkname readMIMEHeader net/textproto.readMIMEHeader
|
||||
func readMIMEHeader(r *textproto.Reader, lim int64) (textproto.MIMEHeader, error)
|
||||
@@ -1097,7 +1097,7 @@ func testMissingFile(t *testing.T, req *Request) {
|
||||
t.Errorf("FormFile file = %v, want nil", f)
|
||||
}
|
||||
if fh != nil {
|
||||
t.Errorf("FormFile file header = %q, want nil", fh)
|
||||
t.Errorf("FormFile file header = %v, want nil", fh)
|
||||
}
|
||||
if err != ErrMissingFile {
|
||||
t.Errorf("FormFile err = %q, want ErrMissingFile", err)
|
||||
|
||||
@@ -7,8 +7,10 @@ package textproto
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -477,6 +479,12 @@ var colon = []byte(":")
|
||||
// "Long-Key": {"Even Longer Value"},
|
||||
// }
|
||||
func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
|
||||
return readMIMEHeader(r, math.MaxInt64)
|
||||
}
|
||||
|
||||
// readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size.
|
||||
// It is called by the mime/multipart package.
|
||||
func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) {
|
||||
// Avoid lots of small slice allocations later by allocating one
|
||||
// large one ahead of time which we'll cut up into smaller
|
||||
// slices. If this isn't big enough later, we allocate small ones.
|
||||
@@ -526,9 +534,19 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
|
||||
}
|
||||
|
||||
// Skip initial spaces in value.
|
||||
value := strings.TrimLeft(string(v), " \t")
|
||||
value := string(bytes.TrimLeft(v, " \t"))
|
||||
|
||||
vv := m[key]
|
||||
if vv == nil {
|
||||
lim -= int64(len(key))
|
||||
lim -= 100 // map entry overhead
|
||||
}
|
||||
lim -= int64(len(value))
|
||||
if lim < 0 {
|
||||
// TODO: This should be a distinguishable error (ErrMessageTooLarge)
|
||||
// to allow mime/multipart to detect it.
|
||||
return m, errors.New("message too large")
|
||||
}
|
||||
if vv == nil && len(strs) > 0 {
|
||||
// More than likely this will be a single-element key.
|
||||
// Most headers aren't multi-valued.
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
@@ -117,21 +118,9 @@ func Clean(path string) string {
|
||||
case os.IsPathSeparator(path[r]):
|
||||
// empty path element
|
||||
r++
|
||||
case path[r] == '.' && r+1 == n:
|
||||
case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])):
|
||||
// . element
|
||||
r++
|
||||
case path[r] == '.' && os.IsPathSeparator(path[r+1]):
|
||||
// ./ element
|
||||
r++
|
||||
|
||||
for r < len(path) && os.IsPathSeparator(path[r]) {
|
||||
r++
|
||||
}
|
||||
if out.w == 0 && volumeNameLen(path[r:]) > 0 {
|
||||
// When joining prefix "." and an absolute path on Windows,
|
||||
// the prefix should not be removed.
|
||||
out.append('.')
|
||||
}
|
||||
case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
|
||||
// .. element: remove to last separator
|
||||
r += 2
|
||||
@@ -157,6 +146,18 @@ func Clean(path string) string {
|
||||
if rooted && out.w != 1 || !rooted && out.w != 0 {
|
||||
out.append(Separator)
|
||||
}
|
||||
// If a ':' appears in the path element at the start of a Windows path,
|
||||
// insert a .\ at the beginning to avoid converting relative paths
|
||||
// like a/../c: into c:.
|
||||
if runtime.GOOS == "windows" && out.w == 0 && out.volLen == 0 && r != 0 {
|
||||
for i := r; i < n && !os.IsPathSeparator(path[i]); i++ {
|
||||
if path[i] == ':' {
|
||||
out.append('.')
|
||||
out.append(Separator)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// copy element
|
||||
for ; r < n && !os.IsPathSeparator(path[r]); r++ {
|
||||
out.append(path[r])
|
||||
|
||||
@@ -106,6 +106,13 @@ var wincleantests = []PathTest{
|
||||
{`//abc`, `\\abc`},
|
||||
{`///abc`, `\\\abc`},
|
||||
{`//abc//`, `\\abc\\`},
|
||||
|
||||
// Don't allow cleaning to move an element with a colon to the start of the path.
|
||||
{`a/../c:`, `.\c:`},
|
||||
{`a\..\c:`, `.\c:`},
|
||||
{`a/../c:/a`, `.\c:\a`},
|
||||
{`a/../../c:`, `..\c:`},
|
||||
{`foo:bar`, `foo:bar`},
|
||||
}
|
||||
|
||||
func TestClean(t *testing.T) {
|
||||
@@ -174,6 +181,7 @@ var winislocaltests = []IsLocalTest{
|
||||
{`C:`, false},
|
||||
{`C:\a`, false},
|
||||
{`..\a`, false},
|
||||
{`a/../c:`, false},
|
||||
{`CONIN$`, false},
|
||||
{`conin$`, false},
|
||||
{`CONOUT$`, false},
|
||||
|
||||
@@ -542,7 +542,7 @@ func TestIssue52476(t *testing.T) {
|
||||
}{
|
||||
{`..\.`, `C:`, `..\C:`},
|
||||
{`..`, `C:`, `..\C:`},
|
||||
{`.`, `:`, `:`},
|
||||
{`.`, `:`, `.\:`},
|
||||
{`.`, `C:`, `.\C:`},
|
||||
{`.`, `C:/a/b/../c`, `.\C:\a\c`},
|
||||
{`.`, `\C:`, `.\C:`},
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"internal/coverage/pods"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// processCoverTestDir is called (via a linknamed reference) from
|
||||
@@ -80,7 +81,15 @@ func processCoverTestDirInternal(dir string, cfile string, cm string, cpkg strin
|
||||
cf: cformat.NewFormatter(cmode),
|
||||
cmode: cmode,
|
||||
}
|
||||
// Generate the expected hash string based on the final meta-data
|
||||
// hash for this test, then look only for pods that refer to that
|
||||
// hash (just in case there are multiple instrumented executables
|
||||
// in play). See issue #57924 for more on this.
|
||||
hashstring := fmt.Sprintf("%x", finalHash)
|
||||
for _, p := range podlist {
|
||||
if !strings.Contains(p.MetaFile, hashstring) {
|
||||
continue
|
||||
}
|
||||
if err := ts.processPod(p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -213,7 +213,9 @@ func pthread_kill_trampoline()
|
||||
//
|
||||
//go:nosplit
|
||||
func osinit_hack() {
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(osinit_hack_trampoline)), nil)
|
||||
if GOOS == "darwin" { // not ios
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(osinit_hack_trampoline)), nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
func osinit_hack_trampoline()
|
||||
|
||||
@@ -27,9 +27,11 @@ import (
|
||||
// In the terminology of the Go memory model, Map arranges that a write operation
|
||||
// “synchronizes before” any read operation that observes the effect of the write, where
|
||||
// read and write operations are defined as follows.
|
||||
// Load, LoadAndDelete, LoadOrStore are read operations;
|
||||
// Delete, LoadAndDelete, and Store are write operations;
|
||||
// and LoadOrStore is a write operation when it returns loaded set to false.
|
||||
// Load, LoadAndDelete, LoadOrStore, Swap, CompareAndSwap, and CompareAndDelete
|
||||
// are read operations; Delete, LoadAndDelete, Store, and Swap are write operations;
|
||||
// LoadOrStore is a write operation when it returns loaded set to false;
|
||||
// CompareAndSwap is a write operation when it returns swapped set to true;
|
||||
// and CompareAndDelete is a write operation when it returns deleted set to true.
|
||||
type Map struct {
|
||||
mu Mutex
|
||||
|
||||
|
||||
@@ -155,7 +155,8 @@ func parseRFC3339[bytes []byte | string](s bytes, local *Location) (Time, bool)
|
||||
func parseStrictRFC3339(b []byte) (Time, error) {
|
||||
t, ok := parseRFC3339(b, Local)
|
||||
if !ok {
|
||||
if _, err := Parse(RFC3339, string(b)); err != nil {
|
||||
t, err := Parse(RFC3339, string(b))
|
||||
if err != nil {
|
||||
return Time{}, err
|
||||
}
|
||||
|
||||
@@ -164,6 +165,10 @@ func parseStrictRFC3339(b []byte) (Time, error) {
|
||||
// See https://go.dev/issue/54580.
|
||||
num2 := func(b []byte) byte { return 10*(b[0]-'0') + (b[1] - '0') }
|
||||
switch {
|
||||
// TODO(https://go.dev/issue/54580): Strict parsing is disabled for now.
|
||||
// Enable this again with a GODEBUG opt-out.
|
||||
case true:
|
||||
return t, nil
|
||||
case b[len("2006-01-02T")+1] == ':': // hour must be two digits
|
||||
return Time{}, &ParseError{RFC3339, string(b), "15", string(b[len("2006-01-02T"):][:1]), ""}
|
||||
case b[len("2006-01-02T15:04:05")] == ',': // sub-second separator must be a period
|
||||
|
||||
@@ -830,10 +830,10 @@ func TestUnmarshalInvalidTimes(t *testing.T) {
|
||||
}{
|
||||
{`{}`, "Time.UnmarshalJSON: input is not a JSON string"},
|
||||
{`[]`, "Time.UnmarshalJSON: input is not a JSON string"},
|
||||
{`"2000-01-01T1:12:34Z"`, `parsing time "2000-01-01T1:12:34Z" as "2006-01-02T15:04:05Z07:00": cannot parse "1" as "15"`},
|
||||
{`"2000-01-01T00:00:00,000Z"`, `parsing time "2000-01-01T00:00:00,000Z" as "2006-01-02T15:04:05Z07:00": cannot parse "," as "."`},
|
||||
{`"2000-01-01T00:00:00+24:00"`, `parsing time "2000-01-01T00:00:00+24:00": timezone hour out of range`},
|
||||
{`"2000-01-01T00:00:00+00:60"`, `parsing time "2000-01-01T00:00:00+00:60": timezone minute out of range`},
|
||||
{`"2000-01-01T1:12:34Z"`, `<nil>`},
|
||||
{`"2000-01-01T00:00:00,000Z"`, `<nil>`},
|
||||
{`"2000-01-01T00:00:00+24:00"`, `<nil>`},
|
||||
{`"2000-01-01T00:00:00+00:60"`, `<nil>`},
|
||||
{`"2000-01-01T00:00:00+123:45"`, `parsing time "2000-01-01T00:00:00+123:45" as "2006-01-02T15:04:05Z07:00": cannot parse "+123:45" as "Z07:00"`},
|
||||
}
|
||||
|
||||
@@ -842,13 +842,13 @@ func TestUnmarshalInvalidTimes(t *testing.T) {
|
||||
|
||||
want := tt.want
|
||||
err := json.Unmarshal([]byte(tt.in), &ts)
|
||||
if err == nil || err.Error() != want {
|
||||
if fmt.Sprint(err) != want {
|
||||
t.Errorf("Time.UnmarshalJSON(%s) = %v, want %v", tt.in, err, want)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(tt.in, `"`) && strings.HasSuffix(tt.in, `"`) {
|
||||
err = ts.UnmarshalText([]byte(strings.Trim(tt.in, `"`)))
|
||||
if err == nil || err.Error() != want {
|
||||
if fmt.Sprint(err) != want {
|
||||
t.Errorf("Time.UnmarshalText(%s) = %v, want %v", tt.in, err, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@ var abbrs = map[string]abbr{
|
||||
"Egypt Standard Time": {"EET", "EET"}, // Africa/Cairo
|
||||
"Morocco Standard Time": {"+00", "+01"}, // Africa/Casablanca
|
||||
"South Africa Standard Time": {"SAST", "SAST"}, // Africa/Johannesburg
|
||||
"South Sudan Standard Time": {"CAT", "CAT"}, // Africa/Juba
|
||||
"Sudan Standard Time": {"CAT", "CAT"}, // Africa/Khartoum
|
||||
"W. Central Africa Standard Time": {"WAT", "WAT"}, // Africa/Lagos
|
||||
"E. Africa Standard Time": {"EAT", "EAT"}, // Africa/Nairobi
|
||||
"Sao Tome Standard Time": {"GMT", "WAT"}, // Africa/Sao_Tome
|
||||
"Sao Tome Standard Time": {"GMT", "GMT"}, // Africa/Sao_Tome
|
||||
"Libya Standard Time": {"EET", "EET"}, // Africa/Tripoli
|
||||
"Namibia Standard Time": {"CAT", "CAT"}, // Africa/Windhoek
|
||||
"Aleutian Standard Time": {"HST", "HDT"}, // America/Adak
|
||||
@@ -33,8 +34,8 @@ var abbrs = map[string]abbr{
|
||||
"Venezuela Standard Time": {"-04", "-04"}, // America/Caracas
|
||||
"SA Eastern Standard Time": {"-03", "-03"}, // America/Cayenne
|
||||
"Central Standard Time": {"CST", "CDT"}, // America/Chicago
|
||||
"Mountain Standard Time (Mexico)": {"MST", "MDT"}, // America/Chihuahua
|
||||
"Central Brazilian Standard Time": {"-04", "-03"}, // America/Cuiaba
|
||||
"Mountain Standard Time (Mexico)": {"CST", "CST"}, // America/Chihuahua
|
||||
"Central Brazilian Standard Time": {"-04", "-04"}, // America/Cuiaba
|
||||
"Mountain Standard Time": {"MST", "MDT"}, // America/Denver
|
||||
"Greenland Standard Time": {"-03", "-02"}, // America/Godthab
|
||||
"Turks And Caicos Standard Time": {"EST", "EDT"}, // America/Grand_Turk
|
||||
@@ -44,7 +45,7 @@ var abbrs = map[string]abbr{
|
||||
"US Eastern Standard Time": {"EST", "EDT"}, // America/Indianapolis
|
||||
"SA Western Standard Time": {"-04", "-04"}, // America/La_Paz
|
||||
"Pacific Standard Time": {"PST", "PDT"}, // America/Los_Angeles
|
||||
"Central Standard Time (Mexico)": {"CST", "CDT"}, // America/Mexico_City
|
||||
"Central Standard Time (Mexico)": {"CST", "CST"}, // America/Mexico_City
|
||||
"Saint Pierre Standard Time": {"-03", "-02"}, // America/Miquelon
|
||||
"Montevideo Standard Time": {"-03", "-03"}, // America/Montevideo
|
||||
"Eastern Standard Time": {"EST", "EDT"}, // America/New_York
|
||||
@@ -53,11 +54,12 @@ var abbrs = map[string]abbr{
|
||||
"Magallanes Standard Time": {"-03", "-03"}, // America/Punta_Arenas
|
||||
"Canada Central Standard Time": {"CST", "CST"}, // America/Regina
|
||||
"Pacific SA Standard Time": {"-04", "-03"}, // America/Santiago
|
||||
"E. South America Standard Time": {"-03", "-02"}, // America/Sao_Paulo
|
||||
"E. South America Standard Time": {"-03", "-03"}, // America/Sao_Paulo
|
||||
"Newfoundland Standard Time": {"NST", "NDT"}, // America/St_Johns
|
||||
"Pacific Standard Time (Mexico)": {"PST", "PDT"}, // America/Tijuana
|
||||
"Yukon Standard Time": {"MST", "MST"}, // America/Whitehorse
|
||||
"Central Asia Standard Time": {"+06", "+06"}, // Asia/Almaty
|
||||
"Jordan Standard Time": {"EET", "EEST"}, // Asia/Amman
|
||||
"Jordan Standard Time": {"+03", "+03"}, // Asia/Amman
|
||||
"Arabic Standard Time": {"+03", "+03"}, // Asia/Baghdad
|
||||
"Azerbaijan Standard Time": {"+04", "+04"}, // Asia/Baku
|
||||
"SE Asia Standard Time": {"+07", "+07"}, // Asia/Bangkok
|
||||
@@ -66,7 +68,7 @@ var abbrs = map[string]abbr{
|
||||
"India Standard Time": {"IST", "IST"}, // Asia/Calcutta
|
||||
"Transbaikal Standard Time": {"+09", "+09"}, // Asia/Chita
|
||||
"Sri Lanka Standard Time": {"+0530", "+0530"}, // Asia/Colombo
|
||||
"Syria Standard Time": {"EET", "EEST"}, // Asia/Damascus
|
||||
"Syria Standard Time": {"+03", "+03"}, // Asia/Damascus
|
||||
"Bangladesh Standard Time": {"+06", "+06"}, // Asia/Dhaka
|
||||
"Arabian Standard Time": {"+04", "+04"}, // Asia/Dubai
|
||||
"West Bank Standard Time": {"EET", "EEST"}, // Asia/Hebron
|
||||
@@ -82,7 +84,7 @@ var abbrs = map[string]abbr{
|
||||
"N. Central Asia Standard Time": {"+07", "+07"}, // Asia/Novosibirsk
|
||||
"Omsk Standard Time": {"+06", "+06"}, // Asia/Omsk
|
||||
"North Korea Standard Time": {"KST", "KST"}, // Asia/Pyongyang
|
||||
"Qyzylorda Standard Time": {"+05", "+06"}, // Asia/Qyzylorda
|
||||
"Qyzylorda Standard Time": {"+05", "+05"}, // Asia/Qyzylorda
|
||||
"Myanmar Standard Time": {"+0630", "+0630"}, // Asia/Rangoon
|
||||
"Arab Standard Time": {"+03", "+03"}, // Asia/Riyadh
|
||||
"Sakhalin Standard Time": {"+11", "+11"}, // Asia/Sakhalin
|
||||
@@ -93,7 +95,7 @@ var abbrs = map[string]abbr{
|
||||
"Taipei Standard Time": {"CST", "CST"}, // Asia/Taipei
|
||||
"West Asia Standard Time": {"+05", "+05"}, // Asia/Tashkent
|
||||
"Georgian Standard Time": {"+04", "+04"}, // Asia/Tbilisi
|
||||
"Iran Standard Time": {"+0330", "+0430"}, // Asia/Tehran
|
||||
"Iran Standard Time": {"+0330", "+0330"}, // Asia/Tehran
|
||||
"Tokyo Standard Time": {"JST", "JST"}, // Asia/Tokyo
|
||||
"Tomsk Standard Time": {"+07", "+07"}, // Asia/Tomsk
|
||||
"Ulaanbaatar Standard Time": {"+08", "+08"}, // Asia/Ulaanbaatar
|
||||
@@ -112,7 +114,6 @@ var abbrs = map[string]abbr{
|
||||
"Lord Howe Standard Time": {"+1030", "+11"}, // Australia/Lord_Howe
|
||||
"W. Australia Standard Time": {"AWST", "AWST"}, // Australia/Perth
|
||||
"AUS Eastern Standard Time": {"AEST", "AEDT"}, // Australia/Sydney
|
||||
"UTC": {"GMT", "GMT"}, // Etc/GMT
|
||||
"UTC-11": {"-11", "-11"}, // Etc/GMT+11
|
||||
"Dateline Standard Time": {"-12", "-12"}, // Etc/GMT+12
|
||||
"UTC-02": {"-02", "-02"}, // Etc/GMT+2
|
||||
@@ -120,6 +121,7 @@ var abbrs = map[string]abbr{
|
||||
"UTC-09": {"-09", "-09"}, // Etc/GMT+9
|
||||
"UTC+12": {"+12", "+12"}, // Etc/GMT-12
|
||||
"UTC+13": {"+13", "+13"}, // Etc/GMT-13
|
||||
"UTC": {"UTC", "UTC"}, // Etc/UTC
|
||||
"Astrakhan Standard Time": {"+04", "+04"}, // Europe/Astrakhan
|
||||
"W. Europe Standard Time": {"CET", "CEST"}, // Europe/Berlin
|
||||
"GTB Standard Time": {"EET", "EEST"}, // Europe/Bucharest
|
||||
@@ -134,20 +136,20 @@ var abbrs = map[string]abbr{
|
||||
"Romance Standard Time": {"CET", "CEST"}, // Europe/Paris
|
||||
"Russia Time Zone 3": {"+04", "+04"}, // Europe/Samara
|
||||
"Saratov Standard Time": {"+04", "+04"}, // Europe/Saratov
|
||||
"Volgograd Standard Time": {"+04", "+04"}, // Europe/Volgograd
|
||||
"Volgograd Standard Time": {"+03", "+03"}, // Europe/Volgograd
|
||||
"Central European Standard Time": {"CET", "CEST"}, // Europe/Warsaw
|
||||
"Mauritius Standard Time": {"+04", "+04"}, // Indian/Mauritius
|
||||
"Samoa Standard Time": {"+13", "+14"}, // Pacific/Apia
|
||||
"Samoa Standard Time": {"+13", "+13"}, // Pacific/Apia
|
||||
"New Zealand Standard Time": {"NZST", "NZDT"}, // Pacific/Auckland
|
||||
"Bougainville Standard Time": {"+11", "+11"}, // Pacific/Bougainville
|
||||
"Chatham Islands Standard Time": {"+1245", "+1345"}, // Pacific/Chatham
|
||||
"Easter Island Standard Time": {"-06", "-05"}, // Pacific/Easter
|
||||
"Fiji Standard Time": {"+12", "+13"}, // Pacific/Fiji
|
||||
"Fiji Standard Time": {"+12", "+12"}, // Pacific/Fiji
|
||||
"Central Pacific Standard Time": {"+11", "+11"}, // Pacific/Guadalcanal
|
||||
"Hawaiian Standard Time": {"HST", "HST"}, // Pacific/Honolulu
|
||||
"Line Islands Standard Time": {"+14", "+14"}, // Pacific/Kiritimati
|
||||
"Marquesas Standard Time": {"-0930", "-0930"}, // Pacific/Marquesas
|
||||
"Norfolk Standard Time": {"+11", "+11"}, // Pacific/Norfolk
|
||||
"Norfolk Standard Time": {"+11", "+12"}, // Pacific/Norfolk
|
||||
"West Pacific Standard Time": {"+10", "+10"}, // Pacific/Port_Moresby
|
||||
"Tonga Standard Time": {"+13", "+13"}, // Pacific/Tongatapu
|
||||
}
|
||||
|
||||
85
src/vendor/golang.org/x/net/http2/hpack/hpack.go
generated
vendored
85
src/vendor/golang.org/x/net/http2/hpack/hpack.go
generated
vendored
@@ -359,6 +359,7 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
|
||||
|
||||
var hf HeaderField
|
||||
wantStr := d.emitEnabled || it.indexed()
|
||||
var undecodedName undecodedString
|
||||
if nameIdx > 0 {
|
||||
ihf, ok := d.at(nameIdx)
|
||||
if !ok {
|
||||
@@ -366,15 +367,27 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
|
||||
}
|
||||
hf.Name = ihf.Name
|
||||
} else {
|
||||
hf.Name, buf, err = d.readString(buf, wantStr)
|
||||
undecodedName, buf, err = d.readString(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
hf.Value, buf, err = d.readString(buf, wantStr)
|
||||
undecodedValue, buf, err := d.readString(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if wantStr {
|
||||
if nameIdx <= 0 {
|
||||
hf.Name, err = d.decodeString(undecodedName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
hf.Value, err = d.decodeString(undecodedValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
d.buf = buf
|
||||
if it.indexed() {
|
||||
d.dynTab.add(hf)
|
||||
@@ -459,46 +472,52 @@ func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
|
||||
return 0, origP, errNeedMore
|
||||
}
|
||||
|
||||
// readString decodes an hpack string from p.
|
||||
// readString reads an hpack string from p.
|
||||
//
|
||||
// wantStr is whether s will be used. If false, decompression and
|
||||
// []byte->string garbage are skipped if s will be ignored
|
||||
// anyway. This does mean that huffman decoding errors for non-indexed
|
||||
// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server
|
||||
// is returning an error anyway, and because they're not indexed, the error
|
||||
// won't affect the decoding state.
|
||||
func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) {
|
||||
// It returns a reference to the encoded string data to permit deferring decode costs
|
||||
// until after the caller verifies all data is present.
|
||||
func (d *Decoder) readString(p []byte) (u undecodedString, remain []byte, err error) {
|
||||
if len(p) == 0 {
|
||||
return "", p, errNeedMore
|
||||
return u, p, errNeedMore
|
||||
}
|
||||
isHuff := p[0]&128 != 0
|
||||
strLen, p, err := readVarInt(7, p)
|
||||
if err != nil {
|
||||
return "", p, err
|
||||
return u, p, err
|
||||
}
|
||||
if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) {
|
||||
return "", nil, ErrStringLength
|
||||
// Returning an error here means Huffman decoding errors
|
||||
// for non-indexed strings past the maximum string length
|
||||
// are ignored, but the server is returning an error anyway
|
||||
// and because the string is not indexed the error will not
|
||||
// affect the decoding state.
|
||||
return u, nil, ErrStringLength
|
||||
}
|
||||
if uint64(len(p)) < strLen {
|
||||
return "", p, errNeedMore
|
||||
return u, p, errNeedMore
|
||||
}
|
||||
if !isHuff {
|
||||
if wantStr {
|
||||
s = string(p[:strLen])
|
||||
}
|
||||
return s, p[strLen:], nil
|
||||
}
|
||||
|
||||
if wantStr {
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
buf.Reset() // don't trust others
|
||||
defer bufPool.Put(buf)
|
||||
if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
|
||||
buf.Reset()
|
||||
return "", nil, err
|
||||
}
|
||||
s = buf.String()
|
||||
buf.Reset() // be nice to GC
|
||||
}
|
||||
return s, p[strLen:], nil
|
||||
u.isHuff = isHuff
|
||||
u.b = p[:strLen]
|
||||
return u, p[strLen:], nil
|
||||
}
|
||||
|
||||
type undecodedString struct {
|
||||
isHuff bool
|
||||
b []byte
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeString(u undecodedString) (string, error) {
|
||||
if !u.isHuff {
|
||||
return string(u.b), nil
|
||||
}
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
buf.Reset() // don't trust others
|
||||
var s string
|
||||
err := huffmanDecode(buf, d.maxStrLen, u.b)
|
||||
if err == nil {
|
||||
s = buf.String()
|
||||
}
|
||||
buf.Reset() // be nice to GC
|
||||
bufPool.Put(buf)
|
||||
return s, err
|
||||
}
|
||||
|
||||
19
test/fixedbugs/issue57778.go
Normal file
19
test/fixedbugs/issue57778.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// compile
|
||||
|
||||
// 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 p
|
||||
|
||||
type FreeListG[T any] struct {
|
||||
freelist []*node[T]
|
||||
}
|
||||
|
||||
type node[T any] struct{}
|
||||
|
||||
func NewFreeListG[T any](size int) *FreeListG[T] {
|
||||
return &FreeListG[T]{freelist: make([]*node[T], 0, size)}
|
||||
}
|
||||
|
||||
var bf = NewFreeListG[*int](1024)
|
||||
76
test/fixedbugs/issue57823.go
Normal file
76
test/fixedbugs/issue57823.go
Normal file
@@ -0,0 +1,76 @@
|
||||
// run
|
||||
|
||||
// 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 (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:noinline
|
||||
func g(x *byte) *byte { return x }
|
||||
|
||||
func main() {
|
||||
slice()
|
||||
str("AAAAAAAA", "BBBBBBBBB")
|
||||
}
|
||||
|
||||
func wait(done <-chan struct{}) bool {
|
||||
for i := 0; i < 10; i++ {
|
||||
runtime.GC()
|
||||
select {
|
||||
case <-done:
|
||||
return true
|
||||
default:
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func slice() {
|
||||
s := make([]byte, 100)
|
||||
s[0] = 1
|
||||
one := unsafe.SliceData(s)
|
||||
|
||||
done := make(chan struct{})
|
||||
runtime.SetFinalizer(one, func(*byte) { close(done) })
|
||||
|
||||
h := g(one)
|
||||
|
||||
if wait(done) {
|
||||
panic("GC'd early")
|
||||
}
|
||||
|
||||
if *h != 1 {
|
||||
panic("lost one")
|
||||
}
|
||||
|
||||
if !wait(done) {
|
||||
panic("never GC'd")
|
||||
}
|
||||
}
|
||||
|
||||
var strDone = make(chan struct{})
|
||||
|
||||
//go:noinline
|
||||
func str(x, y string) {
|
||||
s := x + y // put in temporary on stack
|
||||
p := unsafe.StringData(s)
|
||||
runtime.SetFinalizer(p, func(*byte) { close(strDone) })
|
||||
|
||||
if wait(strDone) {
|
||||
panic("GC'd early")
|
||||
}
|
||||
|
||||
if *p != 'A' {
|
||||
panic("lost p")
|
||||
}
|
||||
|
||||
if !wait(strDone) {
|
||||
panic("never GC'd")
|
||||
}
|
||||
}
|
||||
13
test/fixedbugs/issue58293.go
Normal file
13
test/fixedbugs/issue58293.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// compile
|
||||
|
||||
// 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 p
|
||||
|
||||
var bar = f(13579)
|
||||
|
||||
func f(x uint16) uint16 {
|
||||
return x>>8 | x<<8
|
||||
}
|
||||
23
test/fixedbugs/issue58325.go
Normal file
23
test/fixedbugs/issue58325.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// compile
|
||||
|
||||
// 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 p
|
||||
|
||||
type S1 struct {
|
||||
s2 S2
|
||||
}
|
||||
|
||||
type S2 struct{}
|
||||
|
||||
func (S2) Make() S2 {
|
||||
return S2{}
|
||||
}
|
||||
|
||||
func (S1) Make() S1 {
|
||||
return S1{s2: S2{}.Make()}
|
||||
}
|
||||
|
||||
var _ = S1{}.Make()
|
||||
@@ -1053,11 +1053,6 @@ func issue51622(b []byte) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func issue45928(x int) {
|
||||
combinedFrac := (x) / (x | (1 << 31)) // ERROR "Proved Neq64$"
|
||||
useInt(combinedFrac)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func useInt(a int) {
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
|
||||
package p
|
||||
|
||||
type I interface{ any | int }
|
||||
type Any any
|
||||
|
||||
type I interface{ Any | int }
|
||||
|
||||
var (
|
||||
X I = 42
|
||||
|
||||
Reference in New Issue
Block a user