From 048033641474a8a87b0f8ed66c6098148023bfd6 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Wed, 7 Dec 2022 12:38:55 -0500 Subject: [PATCH 001/165] [release-branch.go1.20] update codereview.cfg for release-branch.go1.20 Following go.dev/cl/334376. Change-Id: I96be6379566b5bcc31e41bdd5f30946b06001153 Reviewed-on: https://go-review.googlesource.com/c/go/+/455896 TryBot-Result: Gopher Robot Run-TryBot: Michael Pratt Reviewed-by: Heschi Kreinick --- codereview.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/codereview.cfg b/codereview.cfg index 77a74f108eae36..6e621c3f9374d3 100644 --- a/codereview.cfg +++ b/codereview.cfg @@ -1 +1,2 @@ -branch: master +branch: release-branch.go1.20 +parent-branch: master From 9f0234214473dfb785a5ad84a8fc62a6a395cbc3 Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Wed, 7 Dec 2022 21:37:53 +0000 Subject: [PATCH 002/165] [release-branch.go1.20] go1.20rc1 Change-Id: I26470f8bcd902f9e1c7877763e360cb3c6255f3a Reviewed-on: https://go-review.googlesource.com/c/go/+/456096 Reviewed-by: Heschi Kreinick Run-TryBot: Gopher Robot Reviewed-by: Michael Pratt TryBot-Bypass: Michael Pratt Auto-Submit: Gopher Robot --- VERSION | 1 + 1 file changed, 1 insertion(+) create mode 100644 VERSION diff --git a/VERSION b/VERSION new file mode 100644 index 00000000000000..867a89f8be429d --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +go1.20rc1 \ No newline at end of file From 32593a91927dbb891e00a5a94abb04105f6a8aa8 Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Wed, 4 Jan 2023 15:42:49 +0000 Subject: [PATCH 003/165] [release-branch.go1.20] go1.20rc2 Change-Id: Ieb30cc96008bd705677e44983c68d4581706cc05 Reviewed-on: https://go-review.googlesource.com/c/go/+/460498 Auto-Submit: Gopher Robot Run-TryBot: Gopher Robot TryBot-Result: Gopher Robot Reviewed-by: Heschi Kreinick Reviewed-by: Dmitri Shuralyov --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 867a89f8be429d..e0e176f21ad0d4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -go1.20rc1 \ No newline at end of file +go1.20rc2 \ No newline at end of file From b3160e8bcedb25c5266e047ada01b6f462521401 Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Thu, 12 Jan 2023 16:47:17 +0000 Subject: [PATCH 004/165] [release-branch.go1.20] go1.20rc3 Change-Id: I87007947c075e8b90dd74bdf164b59e81487f6de Reviewed-on: https://go-review.googlesource.com/c/go/+/461836 Reviewed-by: Heschi Kreinick Auto-Submit: Gopher Robot TryBot-Result: Gopher Robot Reviewed-by: Carlos Amedee Run-TryBot: Gopher Robot --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e0e176f21ad0d4..3faae45cd8798b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -go1.20rc2 \ No newline at end of file +go1.20rc3 \ No newline at end of file From 9eed826bf92818fd9473460af32af70dc0ec59ed Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 17 Jan 2023 10:59:25 -0800 Subject: [PATCH 005/165] [release-branch.go1.20] cmd/compile: fix static init inlining for hidden node fields Unified IR added several new IR fields for holding *runtime._type expressions. To avoid throwing off any frontend semantics (particularly inlining cost heuristics), they were marked as `mknode:"-"` so that code wouldn't visit them. Unfortunately, this has a bad interaction with the static init inlining optimization, because the latter relies on ir.EditChildren to substitute all parameters. This potentially includes dictionary parameters, which can appear within the new RType fields. This CL adds a new ir.EditChildrenWithHidden function that also edits these fields, and switches staticinit to use it. Longer term, we should unhide the RType fields so that ir.EditChildren visits them normally, but that's scarier so late in the release cycle. Updates #57778. Updates #57854. Change-Id: I98c1e8cf366156dc0c81a0cb79029cc5e59c476f Reviewed-on: https://go-review.googlesource.com/c/go/+/461686 Run-TryBot: Matthew Dempsky TryBot-Result: Gopher Robot Reviewed-by: Keith Randall Reviewed-by: Keith Randall (cherry picked from commit 9f2fbedf010d59c3ecaa8c25b07a5f68fcb2e3d5) Reviewed-on: https://go-review.googlesource.com/c/go/+/462535 Auto-Submit: Matthew Dempsky Reviewed-by: Cherry Mui --- src/cmd/compile/internal/ir/func.go | 7 +- src/cmd/compile/internal/ir/mknode.go | 35 +- src/cmd/compile/internal/ir/name.go | 7 +- src/cmd/compile/internal/ir/node.go | 1 + src/cmd/compile/internal/ir/node_gen.go | 410 +++++++++++++++++++ src/cmd/compile/internal/ir/visit.go | 12 + src/cmd/compile/internal/staticinit/sched.go | 2 +- test/fixedbugs/issue57778.go | 19 + 8 files changed, 478 insertions(+), 15 deletions(-) create mode 100644 test/fixedbugs/issue57778.go diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go index 31c11f8297ec19..b0b8da5d18a8f3 100644 --- a/src/cmd/compile/internal/ir/func.go +++ b/src/cmd/compile/internal/ir/func.go @@ -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() } diff --git a/src/cmd/compile/internal/ir/mknode.go b/src/cmd/compile/internal/ir/mknode.go index caf4ba01358cd8..716e84389ff999 100644 --- a/src/cmd/compile/internal/ir/mknode.go +++ b/src/cmd/compile/internal/ir/mknode.go @@ -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() { diff --git a/src/cmd/compile/internal/ir/name.go b/src/cmd/compile/internal/ir/name.go index f537ba49818f6d..43aa582e3d18eb 100644 --- a/src/cmd/compile/internal/ir/name.go +++ b/src/cmd/compile/internal/ir/name.go @@ -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. diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index bda3957af95611..b42f914aadd820 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -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 diff --git a/src/cmd/compile/internal/ir/node_gen.go b/src/cmd/compile/internal/ir/node_gen.go index f5d362eef543d1..2dda76b1e3f498 100644 --- a/src/cmd/compile/internal/ir/node_gen.go +++ b/src/cmd/compile/internal/ir/node_gen.go @@ -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 { diff --git a/src/cmd/compile/internal/ir/visit.go b/src/cmd/compile/internal/ir/visit.go index e4aeae352209a7..016467081e5d9e 100644 --- a/src/cmd/compile/internal/ir/visit.go +++ b/src/cmd/compile/internal/ir/visit.go @@ -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) +} diff --git a/src/cmd/compile/internal/staticinit/sched.go b/src/cmd/compile/internal/staticinit/sched.go index fde128ec86d4bc..bd1bf4114d334c 100644 --- a/src/cmd/compile/internal/staticinit/sched.go +++ b/src/cmd/compile/internal/staticinit/sched.go @@ -838,7 +838,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 diff --git a/test/fixedbugs/issue57778.go b/test/fixedbugs/issue57778.go new file mode 100644 index 00000000000000..597eb80fbd92ef --- /dev/null +++ b/test/fixedbugs/issue57778.go @@ -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) From d7c6da8bacf11f845a837a9c93ce43c607dba8a1 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 17 Jan 2023 01:29:02 +0700 Subject: [PATCH 006/165] [release-branch.go1.20] cmd/compile: fix unsafe.{SliceData,StringData} escape analysis memory corruption Updates #57823 Updates #57854 Change-Id: I54654d3ecb20b75afa9052c5c9db2072a86188d4 Reviewed-on: https://go-review.googlesource.com/c/go/+/461759 Reviewed-by: Cherry Mui Auto-Submit: Cuong Manh Le Reviewed-by: Keith Randall TryBot-Result: Gopher Robot Run-TryBot: Cuong Manh Le Reviewed-by: Keith Randall Reviewed-by: Matthew Dempsky Reviewed-on: https://go-review.googlesource.com/c/go/+/461760 --- src/cmd/compile/internal/escape/call.go | 6 +- test/fixedbugs/issue57823.go | 76 +++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue57823.go diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go index 4f602ca15fe779..e2235520e5cd73 100644 --- a/src/cmd/compile/internal/escape/call.go +++ b/src/cmd/compile/internal/escape/call.go @@ -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) diff --git a/test/fixedbugs/issue57823.go b/test/fixedbugs/issue57823.go new file mode 100644 index 00000000000000..d6708f6de8d422 --- /dev/null +++ b/test/fixedbugs/issue57823.go @@ -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") + } +} From 8b34676710eebe9b6fb7ea6d4fde6ae9a18d7ac9 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 18 Jan 2023 10:37:04 -0500 Subject: [PATCH 007/165] [release-branch.go1.20] cmd: update x/tools to latest internal Go 1.20 branch Import x/tools as of CL 462596 (070db2996ebe, Jan 18 2022), to bring in two vet analysis fixes (printf and loopclosure). For #57911. Fixes #57903. Fixes #57904. Change-Id: I82fe4e9bd56fb8e64394ee8618c155316942a517 Reviewed-on: https://go-review.googlesource.com/c/go/+/462555 Reviewed-by: Bryan Mills Run-TryBot: Bryan Mills Auto-Submit: Russ Cox TryBot-Result: Gopher Robot Reviewed-on: https://go-review.googlesource.com/c/go/+/462695 Run-TryBot: Russ Cox Reviewed-by: Ian Lance Taylor Reviewed-by: Cherry Mui --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 4 ++-- .../x/tools/go/analysis/passes/loopclosure/loopclosure.go | 5 +++++ .../golang.org/x/tools/go/analysis/passes/printf/printf.go | 2 +- src/cmd/vendor/modules.txt | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/cmd/go.mod b/src/cmd/go.mod index c1f0e0eac1a8aa..d2e3949deaf9b5 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -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 diff --git a/src/cmd/go.sum b/src/cmd/go.sum index bb72137ecfd851..da5f720a72e311 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -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= diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go index 5291d1b2cd058a..ae5b4151dbe7e1 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go @@ -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 diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go index 3ac4fcaa28e1c4..daaf709a44927f 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go @@ -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{'#'}) { diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 414d8eb743d5ff..6961b9b6c8f62f 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -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 From 5adb0ca8e93d24d47fc3a9fbf03296cbe22fcc35 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Wed, 18 Jan 2023 13:22:54 -0500 Subject: [PATCH 008/165] [release-branch.go1.20] time: revert strict parsing of RFC 3339 CL 444277 fixed Time.UnmarshalText and Time.UnmarshalJSON to properly unmarshal timestamps according to RFC 3339 instead of according to Go's bespoke time syntax that is a superset of RFC 3339. However, this change seems to have broken an AWS S3 unit test that relies on parsing timestamps with single digit hours. It is unclear whether S3 emits these timestamps in production or whether this is simply a testing artifact that has been cargo culted across many code bases. Either way, disable strict parsing for now and re-enable later with better GODEBUG support. Updates #54580 Change-Id: Icced2c7f9a6b2fc06bbd9c7e90f90edce24c2306 Reviewed-on: https://go-review.googlesource.com/c/go/+/462286 Reviewed-by: Bryan Mills Run-TryBot: Joseph Tsai TryBot-Result: Gopher Robot Auto-Submit: Russ Cox Reviewed-by: Russ Cox Reviewed-by: Ian Lance Taylor Reviewed-on: https://go-review.googlesource.com/c/go/+/462675 Reviewed-by: Joseph Tsai Run-TryBot: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Run-TryBot: Russ Cox Reviewed-by: Ian Lance Taylor --- doc/go1.20.html | 5 ++--- src/time/format_rfc3339.go | 7 ++++++- src/time/time_test.go | 12 ++++++------ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/doc/go1.20.html b/doc/go1.20.html index 324d59ed6e283f..1fef45204ed568 100644 --- a/doc/go1.20.html +++ b/doc/go1.20.html @@ -1200,9 +1200,8 @@

Minor changes to the library

- The Time.MarshalJSON and - Time.UnmarshalJSON methods - are now more strict about adherence to RFC 3339. + The Time.MarshalJSON method + is now more strict about adherence to RFC 3339.

diff --git a/src/time/format_rfc3339.go b/src/time/format_rfc3339.go index a9c295df97e5bb..1151666c3e42f3 100644 --- a/src/time/format_rfc3339.go +++ b/src/time/format_rfc3339.go @@ -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 diff --git a/src/time/time_test.go b/src/time/time_test.go index ddf77cccb4359e..4221efec8872b7 100644 --- a/src/time/time_test.go +++ b/src/time/time_test.go @@ -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"`, ``}, + {`"2000-01-01T00:00:00,000Z"`, ``}, + {`"2000-01-01T00:00:00+24:00"`, ``}, + {`"2000-01-01T00:00:00+00:60"`, ``}, {`"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) } } From 10124c2631893fc944a98880796eadd7df048c37 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 24 Jan 2023 16:11:06 +0000 Subject: [PATCH 009/165] [release-branch.go1.20] Revert "cmd/compile: teach prove about bitwise OR operation" This reverts commit 3680b5e9c4f42fcf9155aa42b3b344d1fbe19571. Reason for revert: causes long compile times on certain functions. See issue #57959 Change-Id: Ie9e881ca8abbc79a46de2bfeaed0b9d6c416ed42 Reviewed-on: https://go-review.googlesource.com/c/go/+/463295 Run-TryBot: Keith Randall Reviewed-by: David Chase Reviewed-by: Cherry Mui TryBot-Result: Gopher Robot Reviewed-by: Cuong Manh Le (cherry picked from commit a6ddb15f8f5955d93eeb2f674ec564ffd4530c18) Reviewed-on: https://go-review.googlesource.com/c/go/+/463415 Run-TryBot: Matthew Dempsky Reviewed-by: Keith Randall Auto-Submit: Matthew Dempsky Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/prove.go | 3 --- test/prove.go | 5 ----- 2 files changed, 8 deletions(-) diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go index 908fb5af465e9b..9ecd335b6a06c2 100644 --- a/src/cmd/compile/internal/ssa/prove.go +++ b/src/cmd/compile/internal/ssa/prove.go @@ -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. // diff --git a/test/prove.go b/test/prove.go index 7792b432f964aa..c91fb26c04c1b3 100644 --- a/test/prove.go +++ b/test/prove.go @@ -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) { } From b68d699aa73291d3ab8c7547047308efcd582072 Mon Sep 17 00:00:00 2001 From: Changkun Ou Date: Wed, 28 Dec 2022 15:04:58 +0100 Subject: [PATCH 010/165] [release-branch.go1.20] sync: document memory model for Swap/CompareAnd{Swap,Delete} in Map CL 381316 documented the memory model of Map's APIs. However, the newly introduced Swap, CompareAndSwap, and CompareAndDelete are missing from this documentation as CL 399094 did not add this info. This CL specifies the defined read/write operations of the new Map APIs. For #51972 Change-Id: I519a04040a0b429a3f978823a183cd62e42c90ae Reviewed-on: https://go-review.googlesource.com/c/go/+/459715 TryBot-Result: Gopher Robot Reviewed-by: Dmitri Shuralyov Run-TryBot: Changkun Ou Auto-Submit: Bryan Mills Reviewed-by: Bryan Mills (cherry picked from commit f07910bd577f73b81e4f7117c7cfdf9cf7579028) Reviewed-on: https://go-review.googlesource.com/c/go/+/463416 Run-TryBot: Matthew Dempsky Auto-Submit: Matthew Dempsky Reviewed-by: Changkun Ou --- src/sync/map.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sync/map.go b/src/sync/map.go index 658cef65cfcbcb..e8ccf58b56b34b 100644 --- a/src/sync/map.go +++ b/src/sync/map.go @@ -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 From be7e4fee4b6a96074d003d7211047c23ae9e6c18 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Thu, 19 Jan 2023 10:16:07 -0500 Subject: [PATCH 011/165] [release-branch.go1.20] runtime/coverage: avoid non-test coverage profiles in test report helper When walking through the set of coverage data files generated from a "go test -cover" run, it's possible to encounter pods (clumps of data files) that were generated by a run from an instrumented Go tool (for example, cmd/compile). Add a guard to the test reporting code to ensure that it only processes files created by the currently running test. Fixes #57924. Change-Id: I1bb7dce88305e1088162e3cb1df628486ecee1c1 Reviewed-on: https://go-review.googlesource.com/c/go/+/462756 Reviewed-by: David Chase TryBot-Result: Gopher Robot Reviewed-by: Cherry Mui Run-TryBot: Than McIntosh (cherry picked from commit cf70d37967b8447af8305e02ef534c4c5f42d49c) Reviewed-on: https://go-review.googlesource.com/c/go/+/463417 Run-TryBot: Matthew Dempsky Auto-Submit: Matthew Dempsky Reviewed-by: Than McIntosh --- src/runtime/coverage/testsupport.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/runtime/coverage/testsupport.go b/src/runtime/coverage/testsupport.go index 1d90ebd7a299bf..a481bbbd9ddaa3 100644 --- a/src/runtime/coverage/testsupport.go +++ b/src/runtime/coverage/testsupport.go @@ -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 } From 52bd3b186bd18a1104bd74780fbcb20d35a1114d Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Fri, 20 Jan 2023 14:03:43 -0500 Subject: [PATCH 012/165] [release-branch.go1.20] internal/coverage/decodemeta: fix coding error in func literal handling Fix a coding error in coverage meta-data decoding in the method decodemeta.CoverageMetaDataDecoder.ReadFunc. The code was not unconditionally assigning the "function literal" field of the coverage.FuncDesc object passed in, resulting in bad values depending on what the state of the field happened to be in the object. Fixes #57942. Change-Id: I6dfd7d7f7af6004f05c622f9a7116e9f6018cf4f Reviewed-on: https://go-review.googlesource.com/c/go/+/462955 Run-TryBot: Than McIntosh TryBot-Result: Gopher Robot Reviewed-by: Cherry Mui (cherry picked from commit 620399ef0d1390a8f7e7061a45d5304ed087889a) Reviewed-on: https://go-review.googlesource.com/c/go/+/463418 Reviewed-by: Than McIntosh Run-TryBot: Matthew Dempsky Auto-Submit: Matthew Dempsky --- src/cmd/covdata/dump.go | 1 + src/internal/coverage/decodemeta/decode.go | 4 +- src/internal/coverage/test/roundtrip_test.go | 55 ++++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/cmd/covdata/dump.go b/src/cmd/covdata/dump.go index 59fdc80d03d6df..62267170ce1d12 100644 --- a/src/cmd/covdata/dump.go +++ b/src/cmd/covdata/dump.go @@ -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] diff --git a/src/internal/coverage/decodemeta/decode.go b/src/internal/coverage/decodemeta/decode.go index 4e80c07f0c5684..71f1c567ab0d09 100644 --- a/src/internal/coverage/decodemeta/decode.go +++ b/src/internal/coverage/decodemeta/decode.go @@ -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 } diff --git a/src/internal/coverage/test/roundtrip_test.go b/src/internal/coverage/test/roundtrip_test.go index b26993ffd5825d..614f56e6329a35 100644 --- a/src/internal/coverage/test/roundtrip_test.go +++ b/src/internal/coverage/test/roundtrip_test.go @@ -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) + } + } +} From de4748c47c67392a57f250714509f590f68ad395 Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Wed, 1 Feb 2023 18:43:23 +0000 Subject: [PATCH 013/165] [release-branch.go1.20] go1.20 Change-Id: I156873d216ccb7d91e716b4348069df246b527b3 Reviewed-on: https://go-review.googlesource.com/c/go/+/464496 Run-TryBot: Gopher Robot Auto-Submit: Gopher Robot Reviewed-by: Matthew Dempsky TryBot-Result: Gopher Robot Reviewed-by: Michael Knyszek --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3faae45cd8798b..83534e24796a8c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -go1.20rc3 \ No newline at end of file +go1.20 \ No newline at end of file From 7302f83d8733203aa23f056690d20a4adb949424 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sat, 4 Feb 2023 12:00:20 +0700 Subject: [PATCH 014/165] [release-branch.go1.20] cmd/compile: remove constant arithmetic overflows during typecheck Since go1.19, these errors are already reported by types2 for any user's Go code. Compiler generated code, which looks like constant expression should be evaluated as non-constant semantic, which allows overflows. Fixes #58319 Change-Id: I6f0049a69bdb0a8d0d7a0db49c7badaa92598ea2 Reviewed-on: https://go-review.googlesource.com/c/go/+/466676 Reviewed-by: Keith Randall TryBot-Result: Gopher Robot Run-TryBot: Cuong Manh Le Reviewed-by: Keith Randall Reviewed-by: Tobias Klauser --- src/cmd/compile/internal/typecheck/const.go | 36 ++------------------- test/fixedbugs/issue58293.go | 13 ++++++++ 2 files changed, 15 insertions(+), 34 deletions(-) create mode 100644 test/fixedbugs/issue58293.go diff --git a/src/cmd/compile/internal/typecheck/const.go b/src/cmd/compile/internal/typecheck/const.go index edc399ffd74c77..6855f05b7b3460 100644 --- a/src/cmd/compile/internal/typecheck/const.go +++ b/src/cmd/compile/internal/typecheck/const.go @@ -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 diff --git a/test/fixedbugs/issue58293.go b/test/fixedbugs/issue58293.go new file mode 100644 index 00000000000000..58d550025341a6 --- /dev/null +++ b/test/fixedbugs/issue58293.go @@ -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 +} From 487be3f90bf65c06eb5f1f30aec30cd0e5b24f92 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sun, 5 Feb 2023 14:33:32 +0700 Subject: [PATCH 015/165] [release-branch.go1.20] cmd/compile: fix inline static init arguments substitued tree Blank node must be ignored when building arguments substitued tree. Otherwise, it could be used to replace other blank node in left hand side of an assignment, causing an invalid IR node. Consider the following code: 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() After staticAssignInlinedCall, the assignment becomes: var _ = S1{s2: S2{}.Make()} and the arg substitued tree is "map[*ir.Name]ir.Node{_: S1{}}". Now, when doing static assignment, if there is any assignment to blank node, for example: _ := S2{} That blank node will be replaced with "S1{}": S1{} := S2{} So constructing an invalid IR which causes the ICE. Fixes #58335 Change-Id: I21b48357f669a7e02a7eb4325246aadc31f78fb9 Reviewed-on: https://go-review.googlesource.com/c/go/+/465098 Run-TryBot: Cuong Manh Le Auto-Submit: Cuong Manh Le TryBot-Result: Gopher Robot Reviewed-by: Keith Randall Reviewed-by: Keith Randall Reviewed-by: David Chase Reviewed-on: https://go-review.googlesource.com/c/go/+/466275 Reviewed-by: Than McIntosh --- src/cmd/compile/internal/staticinit/sched.go | 3 +++ test/fixedbugs/issue58325.go | 23 ++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 test/fixedbugs/issue58325.go diff --git a/src/cmd/compile/internal/staticinit/sched.go b/src/cmd/compile/internal/staticinit/sched.go index bd1bf4114d334c..2bfb5d79b22761 100644 --- a/src/cmd/compile/internal/staticinit/sched.go +++ b/src/cmd/compile/internal/staticinit/sched.go @@ -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) diff --git a/test/fixedbugs/issue58325.go b/test/fixedbugs/issue58325.go new file mode 100644 index 00000000000000..d37089c800f710 --- /dev/null +++ b/test/fixedbugs/issue58325.go @@ -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() From 90b06002c44e7fb8fd4b9227efd2d1423e21176b Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 1 Dec 2022 17:24:23 -0800 Subject: [PATCH 016/165] [release-branch.go1.20] cmd/compile/internal/noder: stop creating TUNION types In the types1 universe under the unified frontend, we never need to worry about type parameter constraints, so we only see pure interfaces. However, we might still see interfaces that contain union types, because of interfaces like "interface{ any | int }" (equivalent to just "any"). We can handle these without needing to actually represent type unions within types1 by simply mapping any union to "any". Fixes #58413. Change-Id: I5e4efcf0339edbb01f4035c54fb6fb1f9ddc0c65 Reviewed-on: https://go-review.googlesource.com/c/go/+/458619 Run-TryBot: Matthew Dempsky Reviewed-by: Keith Randall TryBot-Result: Gopher Robot Reviewed-by: Keith Randall (cherry picked from commit a7de684e1b6f460aae7d4dbf2568cb21130ec520) Reviewed-on: https://go-review.googlesource.com/c/go/+/466435 Reviewed-by: Than McIntosh Run-TryBot: David Chase --- src/cmd/compile/internal/noder/reader.go | 32 +++++++++++++++++++----- test/typeparam/issue52124.go | 4 ++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index d03da27a4603a7..189531959e555d 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -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 + } + } + if !pure { + base.Fatalf("impure type set used in value type") } - return types.NewUnion(terms, tildes) + + return types.Types[types.TINTER] } func (r *reader) interfaceType() *types.Type { diff --git a/test/typeparam/issue52124.go b/test/typeparam/issue52124.go index a113fc74441f11..07cba479821ee2 100644 --- a/test/typeparam/issue52124.go +++ b/test/typeparam/issue52124.go @@ -6,7 +6,9 @@ package p -type I interface{ any | int } +type Any any + +type I interface{ Any | int } var ( X I = 42 From 9987cb6cf34cc893887ad2ecc9d832ee3c69c255 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Fri, 27 Jan 2023 19:12:43 +0100 Subject: [PATCH 017/165] [release-branch.go1.20] time: update windows zoneinfo_abbrs zoneinfo_abbrs hasn't been updated since go 1.14, it's time to regenerate it. Fixes #58117. Change-Id: Ic156ae607c46f1f5a9408b1fc0b56de6c14a4ed4 Reviewed-on: https://go-review.googlesource.com/c/go/+/463838 Reviewed-by: Alex Brainman Run-TryBot: Quim Muntal TryBot-Result: Gopher Robot Reviewed-by: Bryan Mills Reviewed-by: Dmitri Shuralyov (cherry picked from commit 007d8f4db1f890f0d34018bb418bdc90ad4a8c35) Reviewed-on: https://go-review.googlesource.com/c/go/+/466436 Reviewed-by: Than McIntosh Reviewed-by: Quim Muntal Run-TryBot: David Chase --- src/time/zoneinfo_abbrs_windows.go | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/time/zoneinfo_abbrs_windows.go b/src/time/zoneinfo_abbrs_windows.go index 3294d0d78689bc..139bda1accea95 100644 --- a/src/time/zoneinfo_abbrs_windows.go +++ b/src/time/zoneinfo_abbrs_windows.go @@ -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 } From fbba58a0a4f5ff4f3aa4cfa0d494b6d2fefd068a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 1 Feb 2023 12:15:08 -0500 Subject: [PATCH 018/165] [release-branch.go1.20] cmd/link: keep go.buildinfo even with --gc-sections If you use an external linker with --gc-sections, nothing refers to .go.buildinfo, so the section is deleted, which in turns makes 'go version' fail on the binary. It is important for vulnerability scanning and the like to be able to run 'go version' on any binary. Fix this by inserting a reference to .go.buildinfo from the rodata section, which will not be GC'ed. Fixes #58222. Fixes #58224. Change-Id: I1e13e9464acaf2f5cc5e0b70476fa52b43651123 Reviewed-on: https://go-review.googlesource.com/c/go/+/464435 Run-TryBot: Russ Cox Reviewed-by: Cherry Mui Reviewed-by: Than McIntosh Auto-Submit: Russ Cox TryBot-Result: Gopher Robot Reviewed-on: https://go-review.googlesource.com/c/go/+/464796 --- .../testdata/script/version_gc_sections.txt | 24 +++++++++++++++++++ src/cmd/link/internal/ld/data.go | 13 +++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/testdata/script/version_gc_sections.txt diff --git a/src/cmd/go/testdata/script/version_gc_sections.txt b/src/cmd/go/testdata/script/version_gc_sections.txt new file mode 100644 index 00000000000000..4bda23ba953605 --- /dev/null +++ b/src/cmd/go/testdata/script/version_gc_sections.txt @@ -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") +} diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 94f8fc32d6e2d6..925e554b1d9db1 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -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. From a943fd0cccc6043e6a3397659f3f262544e615b2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 8 Feb 2023 14:02:55 -0500 Subject: [PATCH 019/165] [release-branch.go1.20] runtime: skip darwin osinit_hack on ios Darwin needs the osinit_hack call to fix some bugs in the Apple libc that surface when Go programs call exec. On iOS, the functions that osinit_hack uses are not available, so signing fails. But on iOS exec is also unavailable, so the hack is not needed. Disable it there, which makes signing work again. Fixes #58323. Fixes #58419. Change-Id: I3f1472f852bb36c06854fe1f14aa27ad450c5945 Reviewed-on: https://go-review.googlesource.com/c/go/+/466516 Run-TryBot: Russ Cox Reviewed-by: Dave Anderson Reviewed-by: Michael Knyszek TryBot-Result: Gopher Robot Auto-Submit: Russ Cox Reviewed-by: Bryan Mills Reviewed-by: Than McIntosh Reviewed-on: https://go-review.googlesource.com/c/go/+/467316 --- src/runtime/sys_darwin.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go index 8bff695f5729d8..5ba697e3047f46 100644 --- a/src/runtime/sys_darwin.go +++ b/src/runtime/sys_darwin.go @@ -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() From 1fa2deb1b1a620511a3c45fcbae895e78d4f5d40 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 9 Feb 2023 16:37:51 -0500 Subject: [PATCH 020/165] [release-branch.go1.20] cmd/go: remove tests that assume lack of new versions of external modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In general it seems ok to assume that an open-source module that did exist will continue to do so — after all, users of open-source modules already do that all the time. However, we should not assume that those modules do not publish new versions — that's really up to their maintainers to decide. Two existing tests did make that assumption for the module gopkg.in/natefinch/lumberjack.v2. Let's remove those two tests. If we need to replace them at some point, we can replace them with hermetic test-only modules (#54503) or perhaps modules owned by the Go project. Updates #58445. Fixes #58450. Change-Id: Ica8fe587d86fc41f3d8445a4cd2b8820455ae45f Reviewed-on: https://go-review.googlesource.com/c/go/+/466861 TryBot-Result: Gopher Robot Run-TryBot: Bryan Mills Reviewed-by: David Chase --- src/cmd/go/internal/modfetch/coderepo_test.go | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/cmd/go/internal/modfetch/coderepo_test.go b/src/cmd/go/internal/modfetch/coderepo_test.go index 553946ba369e77..8ccd9b2dca691c 100644 --- a/src/cmd/go/internal/modfetch/coderepo_test.go +++ b/src/cmd/go/internal/modfetch/coderepo_test.go @@ -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", From 7628627cb236662002b53686ff0618834a9aa077 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Wed, 8 Feb 2023 14:36:47 -0500 Subject: [PATCH 021/165] [release-branch.go1.20] cmd/go/internal/test: refresh flagdefs.go and fix test The tests for cmd/go/internal/test were not running at all due to a missed call to m.Run in TestMain. That masked a missing vet analyzer ("timeformat") and a missed update to the generator script in CL 355452. Fixes #58421. Updates #58415. Change-Id: I7b0315952967ca07a866cdaa5903478b2873eb7a Reviewed-on: https://go-review.googlesource.com/c/go/+/466635 TryBot-Result: Gopher Robot Reviewed-by: Ian Lance Taylor Auto-Submit: Bryan Mills Run-TryBot: Bryan Mills (cherry picked from commit 910f041ff0cdf90dbcd3bd22a272b9b7205a5add) Reviewed-on: https://go-review.googlesource.com/c/go/+/466855 --- src/cmd/go/internal/test/flagdefs.go | 1 + src/cmd/go/internal/test/flagdefs_test.go | 4 ++++ src/cmd/go/internal/test/genflags.go | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cmd/go/internal/test/flagdefs.go b/src/cmd/go/internal/test/flagdefs.go index b91204ee93758d..3f3709fe7e28b5 100644 --- a/src/cmd/go/internal/test/flagdefs.go +++ b/src/cmd/go/internal/test/flagdefs.go @@ -66,6 +66,7 @@ var passAnalyzersToVet = map[string]bool{ "structtag": true, "testinggoroutine": true, "tests": true, + "timeformat": true, "unmarshal": true, "unreachable": true, "unsafeptr": true, diff --git a/src/cmd/go/internal/test/flagdefs_test.go b/src/cmd/go/internal/test/flagdefs_test.go index 337f136d06177a..d5facb7161ab18 100644 --- a/src/cmd/go/internal/test/flagdefs_test.go +++ b/src/cmd/go/internal/test/flagdefs_test.go @@ -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) diff --git a/src/cmd/go/internal/test/genflags.go b/src/cmd/go/internal/test/genflags.go index 8c7554919a5c8c..625f94133a1479 100644 --- a/src/cmd/go/internal/test/genflags.go +++ b/src/cmd/go/internal/test/genflags.go @@ -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) From 00f5d3001a7e684263307ab39c64eba3c79f279c Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Tue, 31 Jan 2023 17:21:14 -0500 Subject: [PATCH 022/165] [release-branch.go1.20] cmd/go/internal/script: retry ETXTBSY errors in scripts Fixes #58431. Updates #58019. Change-Id: Ib25d668bfede6e87a3786f44bdc0db1027e3ebec Reviewed-on: https://go-review.googlesource.com/c/go/+/463748 TryBot-Result: Gopher Robot Auto-Submit: Bryan Mills Run-TryBot: Bryan Mills Reviewed-by: Ian Lance Taylor (cherry picked from commit 23c0121e4eb259cc1087d0f79a0803cbc71f500b) Reviewed-on: https://go-review.googlesource.com/c/go/+/466856 Reviewed-by: David Chase --- src/cmd/go/internal/script/cmds.go | 46 ++++++++++++++++-------- src/cmd/go/internal/script/cmds_other.go | 11 ++++++ src/cmd/go/internal/script/cmds_posix.go | 16 +++++++++ 3 files changed, 58 insertions(+), 15 deletions(-) create mode 100644 src/cmd/go/internal/script/cmds_other.go create mode 100644 src/cmd/go/internal/script/cmds_posix.go diff --git a/src/cmd/go/internal/script/cmds.go b/src/cmd/go/internal/script/cmds.go index e0eaad4c43d19c..666d2d62d30f54 100644 --- a/src/cmd/go/internal/script/cmds.go +++ b/src/cmd/go/internal/script/cmds.go @@ -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) { diff --git a/src/cmd/go/internal/script/cmds_other.go b/src/cmd/go/internal/script/cmds_other.go new file mode 100644 index 00000000000000..847b225ae64989 --- /dev/null +++ b/src/cmd/go/internal/script/cmds_other.go @@ -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 +} diff --git a/src/cmd/go/internal/script/cmds_posix.go b/src/cmd/go/internal/script/cmds_posix.go new file mode 100644 index 00000000000000..2525f6e7529d8c --- /dev/null +++ b/src/cmd/go/internal/script/cmds_posix.go @@ -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) +} From 3a04b6e12ef0e5a0c608f82051943408bd6f28bd Mon Sep 17 00:00:00 2001 From: Frederic Branczyk Date: Wed, 8 Feb 2023 17:59:27 +0000 Subject: [PATCH 023/165] [release-branch.go1.20] cmd/compile/internal/pgo: fix hard-coded PGO sample data position This patch detects at which index position profiling samples that have the value-type samples count are, instead of the previously hard-coded position of index 1. Runtime generated profiles always generate CPU profiling data with the 0 index being CPU nanoseconds, and samples count at index 1, which is why this previously hasn't come up. This is a redo of CL 465135, now allowing empty profiles. Note that preprocessProfileGraph will already cause pgo.New to return nil for empty profiles. For #58292 For #58309 Change-Id: Ia6c94f0793f6ca9b0882b5e2c4d34f38e600c1e3 Reviewed-on: https://go-review.googlesource.com/c/go/+/467375 Run-TryBot: Michael Pratt TryBot-Result: Gopher Robot Reviewed-by: Austin Clements --- src/cmd/compile/internal/pgo/irgraph.go | 23 ++++++- src/cmd/compile/internal/test/pgo_inl_test.go | 68 +++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/pgo/irgraph.go b/src/cmd/compile/internal/pgo/irgraph.go index bf11e365f1042a..bb5df50e3ad32c 100644 --- a/src/cmd/compile/internal/pgo/irgraph.go +++ b/src/cmd/compile/internal/pgo/irgraph.go @@ -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{ diff --git a/src/cmd/compile/internal/test/pgo_inl_test.go b/src/cmd/compile/internal/test/pgo_inl_test.go index 2f6391fded265d..4d6b5a134a0e28 100644 --- a/src/cmd/compile/internal/test/pgo_inl_test.go +++ b/src/cmd/compile/internal/test/pgo_inl_test.go @@ -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 { From bdf07c2e168baf736e4c057279ca12a4d674f18c Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Mon, 12 Dec 2022 16:43:37 -0800 Subject: [PATCH 024/165] [release-branch.go1.20] path/filepath: do not Clean("a/../c:/b") into c:\b on Windows Do not permit Clean to convert a relative path into one starting with a drive reference. This change causes Clean to insert a . path element at the start of a path when the original path does not start with a volume name, and the first path element would contain a colon. This may introduce a spurious but harmless . path element under some circumstances. For example, Clean("a/../b:/../c") becomes `.\c`. This reverts CL 401595, since the change here supersedes the one in that CL. Thanks to RyotaK (https://twitter.com/ryotkak) for reporting this issue. Updates #57274 Fixes #57276 Fixes CVE-2022-41722 Change-Id: I837446285a03aa74c79d7642720e01f354c2ca17 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1675249 Reviewed-by: Roland Shoemaker Run-TryBot: Damien Neil Reviewed-by: Julie Qiu TryBot-Result: Security TryBots (cherry picked from commit 8ca37f4813ef2f64600c92b83f17c9f3ca6c03a5) Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1728944 Run-TryBot: Roland Shoemaker Reviewed-by: Tatiana Bradley Reviewed-by: Damien Neil Reviewed-on: https://go-review.googlesource.com/c/go/+/468119 Reviewed-by: Than McIntosh Run-TryBot: Michael Pratt TryBot-Result: Gopher Robot Auto-Submit: Michael Pratt --- src/path/filepath/path.go | 27 +++++++++++++------------- src/path/filepath/path_test.go | 8 ++++++++ src/path/filepath/path_windows_test.go | 2 +- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go index a6578cbb728b95..32dd887998650b 100644 --- a/src/path/filepath/path.go +++ b/src/path/filepath/path.go @@ -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]) diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go index 66474448526675..697bcc672d73c3 100644 --- a/src/path/filepath/path_test.go +++ b/src/path/filepath/path_test.go @@ -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}, diff --git a/src/path/filepath/path_windows_test.go b/src/path/filepath/path_windows_test.go index e37dddceadbdf1..c8c7eefcc0bb4b 100644 --- a/src/path/filepath/path_windows_test.go +++ b/src/path/filepath/path_windows_test.go @@ -542,7 +542,7 @@ func TestIssue52476(t *testing.T) { }{ {`..\.`, `C:`, `..\C:`}, {`..`, `C:`, `..\C:`}, - {`.`, `:`, `:`}, + {`.`, `:`, `.\:`}, {`.`, `C:`, `.\C:`}, {`.`, `C:/a/b/../c`, `.\C:\a\c`}, {`.`, `\C:`, `.\C:`}, From 53b43607d92e9738067c93829bd799441eda8034 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 25 Jan 2023 09:27:01 -0800 Subject: [PATCH 025/165] [release-branch.go1.20] mime/multipart: limit memory/inode consumption of ReadForm Reader.ReadForm is documented as storing "up to maxMemory bytes + 10MB" in memory. Parsed forms can consume substantially more memory than this limit, since ReadForm does not account for map entry overhead and MIME headers. In addition, while the amount of disk memory consumed by ReadForm can be constrained by limiting the size of the parsed input, ReadForm will create one temporary file per form part stored on disk, potentially consuming a large number of inodes. Update ReadForm's memory accounting to include part names, MIME headers, and map entry overhead. Update ReadForm to store all on-disk file parts in a single temporary file. Files returned by FileHeader.Open are documented as having a concrete type of *os.File when a file is stored on disk. The change to use a single temporary file for all parts means that this is no longer the case when a form contains more than a single file part stored on disk. The previous behavior of storing each file part in a separate disk file may be reenabled with GODEBUG=multipartfiles=distinct. Update Reader.NextPart and Reader.NextRawPart to set a 10MiB cap on the size of MIME headers. Thanks to Jakob Ackermann (@das7pad) for reporting this issue. Updates #58006 Fixes #58363 Fixes CVE-2022-41725 Change-Id: Ibd780a6c4c83ac8bcfd3cbe344f042e9940f2eab Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1714276 Reviewed-by: Julie Qiu TryBot-Result: Security TryBots Reviewed-by: Roland Shoemaker Run-TryBot: Damien Neil (cherry picked from commit 7d0da0029bfbe3228cc5216ced8c7b3184eb517d) Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1728950 Reviewed-by: Damien Neil Run-TryBot: Roland Shoemaker Reviewed-by: Tatiana Bradley Reviewed-on: https://go-review.googlesource.com/c/go/+/468120 Auto-Submit: Michael Pratt Run-TryBot: Michael Pratt Reviewed-by: Than McIntosh TryBot-Result: Gopher Robot --- src/mime/multipart/formdata.go | 133 ++++++++++++++++++++----- src/mime/multipart/formdata_test.go | 141 ++++++++++++++++++++++++++- src/mime/multipart/multipart.go | 25 +++-- src/mime/multipart/readmimeheader.go | 14 +++ src/net/http/request_test.go | 2 +- src/net/textproto/reader.go | 20 +++- 6 files changed, 297 insertions(+), 38 deletions(-) create mode 100644 src/mime/multipart/readmimeheader.go diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go index fca5f9e15fb21f..41bc886d1679d5 100644 --- a/src/mime/multipart/formdata.go +++ b/src/mime/multipart/formdata.go @@ -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 } diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go index 8a4eabcee038a2..8a862be717415e 100644 --- a/src/mime/multipart/formdata_test.go +++ b/src/mime/multipart/formdata_test.go @@ -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)) + } +} diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go index b3a904f0aff340..86ea926346eb5f 100644 --- a/src/mime/multipart/multipart.go +++ b/src/mime/multipart/multipart.go @@ -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 } diff --git a/src/mime/multipart/readmimeheader.go b/src/mime/multipart/readmimeheader.go new file mode 100644 index 00000000000000..6836928c9e8b48 --- /dev/null +++ b/src/mime/multipart/readmimeheader.go @@ -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) diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go index 686a8699fb08db..23e49d6b8e3549 100644 --- a/src/net/http/request_test.go +++ b/src/net/http/request_test.go @@ -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) diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go index 4e4999b3c9534d..8e800088c1fe79 100644 --- a/src/net/textproto/reader.go +++ b/src/net/textproto/reader.go @@ -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. From 5286ac4ed85a3771cc8a982041fe36dc53d7dc3b Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Wed, 14 Dec 2022 09:43:16 -0800 Subject: [PATCH 026/165] [release-branch.go1.20] crypto/tls: replace all usages of BytesOrPanic Message marshalling makes use of BytesOrPanic a lot, under the assumption that it will never panic. This assumption was incorrect, and specifically crafted handshakes could trigger panics. Rather than just surgically replacing the usages of BytesOrPanic in paths that could panic, replace all usages of it with proper error returns in case there are other ways of triggering panics which we didn't find. In one specific case, the tree routed by expandLabel, we replace the usage of BytesOrPanic, but retain a panic. This function already explicitly panicked elsewhere, and returning an error from it becomes rather painful because it requires changing a large number of APIs. The marshalling is unlikely to ever panic, as the inputs are all either fixed length, or already limited to the sizes required. If it were to panic, it'd likely only be during development. A close inspection shows no paths for a user to cause a panic currently. This patches ends up being rather large, since it requires routing errors back through functions which previously had no error returns. Where possible I've tried to use helpers that reduce the verbosity of frequently repeated stanzas, and to make the diffs as minimal as possible. Thanks to Marten Seemann for reporting this issue. Updates #58001 Fixes #58359 Fixes CVE-2022-41724 Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436 Reviewed-by: Julie Qiu TryBot-Result: Security TryBots Run-TryBot: Roland Shoemaker Reviewed-by: Damien Neil (cherry picked from commit 1d4e6ca9454f6cf81d30c5361146fb5988f1b5f6) Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1728205 Reviewed-by: Tatiana Bradley Reviewed-on: https://go-review.googlesource.com/c/go/+/468121 Reviewed-by: Than McIntosh Auto-Submit: Michael Pratt TryBot-Bypass: Michael Pratt Run-TryBot: Michael Pratt --- src/crypto/tls/boring_test.go | 2 +- src/crypto/tls/common.go | 2 +- src/crypto/tls/conn.go | 46 +- src/crypto/tls/handshake_client.go | 95 +-- src/crypto/tls/handshake_client_test.go | 4 +- src/crypto/tls/handshake_client_tls13.go | 74 ++- src/crypto/tls/handshake_messages.go | 716 +++++++++++----------- src/crypto/tls/handshake_messages_test.go | 19 +- src/crypto/tls/handshake_server.go | 73 ++- src/crypto/tls/handshake_server_test.go | 31 +- src/crypto/tls/handshake_server_tls13.go | 71 ++- src/crypto/tls/key_schedule.go | 19 +- src/crypto/tls/ticket.go | 8 +- 13 files changed, 657 insertions(+), 503 deletions(-) diff --git a/src/crypto/tls/boring_test.go b/src/crypto/tls/boring_test.go index 59d4d2b2724ea3..ba68f355eb037c 100644 --- a/src/crypto/tls/boring_test.go +++ b/src/crypto/tls/boring_test.go @@ -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) } diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go index 007f0f47b233c6..5394d64ac6c810 100644 --- a/src/crypto/tls/common.go +++ b/src/crypto/tls/common.go @@ -1394,7 +1394,7 @@ func (c *Certificate) leaf() (*x509.Certificate, error) { } type handshakeMessage interface { - marshal() []byte + marshal() ([]byte, error) unmarshal([]byte) bool } diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go index 03c72633be1fd8..1eefb17206f120 100644 --- a/src/crypto/tls/conn.go +++ b/src/crypto/tls/conn.go @@ -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) diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go index 7cf906c91d8ee1..63d86b9f3a7ef1 100644 --- a/src/crypto/tls/handshake_client.go +++ b/src/crypto/tls/handshake_client.go @@ -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) diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go index 380de9f6fb50eb..749c9fc95452ad 100644 --- a/src/crypto/tls/handshake_client_test.go +++ b/src/crypto/tls/handshake_client_test.go @@ -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), diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go index 3bdd9373d668ef..fefba01a0611ac 100644 --- a/src/crypto/tls/handshake_client_tls13.go +++ b/src/crypto/tls/handshake_client_tls13.go @@ -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 } diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go index 7ab0f100b8bcee..695aacf126a15d 100644 --- a/src/crypto/tls/handshake_messages.go +++ b/src/crypto/tls/handshake_messages.go @@ -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 +} diff --git a/src/crypto/tls/handshake_messages_test.go b/src/crypto/tls/handshake_messages_test.go index c6fc8f2bf3783d..206e2fb024febc 100644 --- a/src/crypto/tls/handshake_messages_test.go +++ b/src/crypto/tls/handshake_messages_test.go @@ -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) { diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go index 682cfc20619f68..e22f284cfb428a 100644 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@ -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 } diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go index 78889f4ad2746c..04abdcca89040d 100644 --- a/src/crypto/tls/handshake_server_test.go +++ b/src/crypto/tls/handshake_server_test.go @@ -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) diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go index 80d4dce3c5d6ed..b7b568cd84ac80 100644 --- a/src/crypto/tls/handshake_server_tls13.go +++ b/src/crypto/tls/handshake_server_tls13.go @@ -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 } diff --git a/src/crypto/tls/key_schedule.go b/src/crypto/tls/key_schedule.go index 8150d804a40430..ae8f80a7cfcc5c 100644 --- a/src/crypto/tls/key_schedule.go +++ b/src/crypto/tls/key_schedule.go @@ -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") } diff --git a/src/crypto/tls/ticket.go b/src/crypto/tls/ticket.go index 6c1d20da206daa..b82ccd141e7910 100644 --- a/src/crypto/tls/ticket.go +++ b/src/crypto/tls/ticket.go @@ -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 { From 8e02cffd8e8a1d5d7b25bd46f675fc8ff9e841d0 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Mon, 6 Feb 2023 10:09:00 -0800 Subject: [PATCH 027/165] [release-branch.go1.20] net/http: update bundled golang.org/x/net/http2 Disable cmd/internal/moddeps test, since this update includes PRIVATE track fixes. Fixes CVE-2022-41723 Fixes #58356 Updates #57855 Change-Id: I603886b5b76c16303dab1420d4ec8b7c7cdcf330 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1728940 Reviewed-by: Damien Neil Reviewed-by: Julie Qiu TryBot-Result: Security TryBots Reviewed-by: Tatiana Bradley Run-TryBot: Roland Shoemaker Reviewed-on: https://go-review.googlesource.com/c/go/+/468122 Auto-Submit: Michael Pratt TryBot-Result: Gopher Robot Run-TryBot: Michael Pratt Reviewed-by: Than McIntosh --- src/cmd/internal/moddeps/moddeps_test.go | 2 + .../golang.org/x/net/http2/hpack/hpack.go | 79 ++++++++++++------- 2 files changed, 51 insertions(+), 30 deletions(-) diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go index 41220645c6ed18..25125face050e2 100644 --- a/src/cmd/internal/moddeps/moddeps_test.go +++ b/src/cmd/internal/moddeps/moddeps_test.go @@ -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 diff --git a/src/vendor/golang.org/x/net/http2/hpack/hpack.go b/src/vendor/golang.org/x/net/http2/hpack/hpack.go index ebdfbee964ae38..fe52df95e8cda3 100644 --- a/src/vendor/golang.org/x/net/http2/hpack/hpack.go +++ b/src/vendor/golang.org/x/net/http2/hpack/hpack.go @@ -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 - } - if !isHuff { - if wantStr { - s = string(p[:strLen]) - } - return s, p[strLen:], nil + return u, p, errNeedMore } + u.isHuff = isHuff + u.b = p[:strLen] + return u, 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 - } +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 } - return s, p[strLen:], nil + buf.Reset() // be nice to GC + bufPool.Put(buf) + return s, err } From 202a1a57064127c3f19d96df57b9f9586145e21c Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Tue, 14 Feb 2023 17:53:38 +0000 Subject: [PATCH 028/165] [release-branch.go1.20] go1.20.1 Change-Id: I6a40cdd44d7bc7e4bf95a5169ecad16757eb41d3 Reviewed-on: https://go-review.googlesource.com/c/go/+/468238 Auto-Submit: Gopher Robot Reviewed-by: Michael Pratt Run-TryBot: Gopher Robot Reviewed-by: Than McIntosh TryBot-Result: Gopher Robot --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 83534e24796a8c..866106008f2eba 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -go1.20 \ No newline at end of file +go1.20.1 \ No newline at end of file From 828b05cc647e9777c7e8c67fdd9d5bef2b842d31 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Tue, 14 Feb 2023 15:15:23 -0500 Subject: [PATCH 029/165] [release-branch.go1.20] all: update vendored golang.org/x/net Update golang.org/x/net to the tip of internal-branch.go1.20-vendor to include CL 468336. The contents of that CL were already merged into this branch in CL 468122, so this CL just brings go.mod back in line to matching the actual vendored content. For #58356 For #57855 Change-Id: I6ee9483077630c11c725927f38f6b69a784106db Reviewed-on: https://go-review.googlesource.com/c/go/+/468302 Run-TryBot: Michael Pratt TryBot-Result: Gopher Robot Reviewed-by: Than McIntosh Auto-Submit: Michael Pratt --- src/cmd/internal/moddeps/moddeps_test.go | 2 -- src/go.mod | 2 +- src/go.sum | 4 ++-- src/vendor/modules.txt | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go index 25125face050e2..41220645c6ed18 100644 --- a/src/cmd/internal/moddeps/moddeps_test.go +++ b/src/cmd/internal/moddeps/moddeps_test.go @@ -31,8 +31,6 @@ 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 diff --git a/src/go.mod b/src/go.mod index 2a1261f925a844..4697da201c0b4e 100644 --- a/src/go.mod +++ b/src/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a - golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 + golang.org/x/net v0.4.1-0.20230214201333-88ed8ca3307d ) require ( diff --git a/src/go.sum b/src/go.sum index ef6748d5968c24..625f2070b34874 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,7 +1,7 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a h1:diz9pEYuTIuLMJLs3rGDkeaTsNyRs6duYdFyPAxzE/U= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 h1:Frnccbp+ok2GkUS2tC84yAq/U9Vg+0sIO7aRL3T4Xnc= -golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.4.1-0.20230214201333-88ed8ca3307d h1:KHU/KRz6+/yWyRHEC24m7T5gou5VSh62duch955ktBY= +golang.org/x/net v0.4.1-0.20230214201333-88ed8ca3307d/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt index 3e4bb5b90bc672..89a7c86c41dbd7 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -7,7 +7,7 @@ golang.org/x/crypto/cryptobyte/asn1 golang.org/x/crypto/hkdf golang.org/x/crypto/internal/alias golang.org/x/crypto/internal/poly1305 -# golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 +# golang.org/x/net v0.4.1-0.20230214201333-88ed8ca3307d ## explicit; go 1.17 golang.org/x/net/dns/dnsmessage golang.org/x/net/http/httpguts From 85ded85b78e881d826ed5a2e0cc1dcff8af71142 Mon Sep 17 00:00:00 2001 From: Adin Scannell Date: Wed, 8 Feb 2023 19:15:23 +0000 Subject: [PATCH 030/165] [release-branch.go1.20] runtime: fix signature for linked functions These functions are linked using go:linkname, but do not match the original declarations. This change brings these in sync. For #58442. Change-Id: I16651304c3dba2f9897c2c42e30555d2f7805c2a Reviewed-on: https://go-review.googlesource.com/c/go/+/466615 Reviewed-by: Michael Pratt Run-TryBot: Michael Pratt TryBot-Result: Gopher Robot Auto-Submit: Michael Pratt (cherry picked from commit 8fb9565832e6dbacaaa057ffabc251a9341f8d23) Reviewed-on: https://go-review.googlesource.com/c/go/+/466859 Reviewed-by: Ian Lance Taylor Reviewed-by: Austin Clements --- src/internal/poll/fd_poll_runtime.go | 2 +- src/sync/atomic/value.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal/poll/fd_poll_runtime.go b/src/internal/poll/fd_poll_runtime.go index 4d3cc784059611..0a2e76d73f2241 100644 --- a/src/internal/poll/fd_poll_runtime.go +++ b/src/internal/poll/fd_poll_runtime.go @@ -23,7 +23,7 @@ func runtime_pollServerInit() func runtime_pollOpen(fd uintptr) (uintptr, int) func runtime_pollClose(ctx uintptr) func runtime_pollWait(ctx uintptr, mode int) int -func runtime_pollWaitCanceled(ctx uintptr, mode int) int +func runtime_pollWaitCanceled(ctx uintptr, mode int) func runtime_pollReset(ctx uintptr, mode int) int func runtime_pollSetDeadline(ctx uintptr, d int64, mode int) func runtime_pollUnblock(ctx uintptr) diff --git a/src/sync/atomic/value.go b/src/sync/atomic/value.go index 8c491b4616267f..a57b08a6b877e6 100644 --- a/src/sync/atomic/value.go +++ b/src/sync/atomic/value.go @@ -190,5 +190,5 @@ func (v *Value) CompareAndSwap(old, new any) (swapped bool) { } // Disable/enable preemption, implemented in runtime. -func runtime_procPin() +func runtime_procPin() int func runtime_procUnpin() From 965e9ba0fb6ed8b511860beaefa7a3ac97a81c36 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Fri, 10 Feb 2023 02:13:05 +0700 Subject: [PATCH 031/165] [release-branch.go1.20] cmd/compile: disable inline static init optimization There are a plenty of regression in 1.20 with this optimization. This CL disable inline static init, so it's safer to backport to 1.20 branch. The optimization will be enabled again during 1.21 cycle. Fixes #58444 Change-Id: If5916008597b46146b4dc7108c6b389d53f35e95 Reviewed-on: https://go-review.googlesource.com/c/go/+/467015 Reviewed-by: Keith Randall Reviewed-by: Keith Randall Run-TryBot: Cuong Manh Le TryBot-Result: Gopher Robot Reviewed-by: Matthew Dempsky Auto-Submit: Cuong Manh Le Reviewed-on: https://go-review.googlesource.com/c/go/+/467035 Run-TryBot: Matthew Dempsky --- src/cmd/compile/internal/base/flag.go | 2 +- test/fixedbugs/issue56778.go | 2 +- test/inline.go | 2 +- test/noinit.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/base/flag.go b/src/cmd/compile/internal/base/flag.go index 25f8458e5cf028..be555c3d060cb3 100644 --- a/src/cmd/compile/internal/base/flag.go +++ b/src/cmd/compile/internal/base/flag.go @@ -167,7 +167,7 @@ func ParseFlags() { Debug.ConcurrentOk = true Debug.InlFuncsWithClosures = 1 - Debug.InlStaticInit = 1 + Debug.InlStaticInit = 0 if buildcfg.Experiment.Unified { Debug.Unified = 1 } diff --git a/test/fixedbugs/issue56778.go b/test/fixedbugs/issue56778.go index 8bb5c3e21398f4..3c27501fd27d87 100644 --- a/test/fixedbugs/issue56778.go +++ b/test/fixedbugs/issue56778.go @@ -1,4 +1,4 @@ -// compiledir +// compiledir -d=inlstaticinit=1 // Copyright 2022 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/inline.go b/test/inline.go index cf2cd8cd60326e..1aa8fccbbdc625 100644 --- a/test/inline.go +++ b/test/inline.go @@ -1,4 +1,4 @@ -// errorcheckwithauto -0 -m -d=inlfuncswithclosures=1 +// errorcheckwithauto -0 -m -d=inlfuncswithclosures=1 -d=inlstaticinit=1 // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/noinit.go b/test/noinit.go index ed8e572e511121..505467cf8f3326 100644 --- a/test/noinit.go +++ b/test/noinit.go @@ -1,4 +1,4 @@ -// run +// run -gcflags=-d=inlstaticinit=1 //go:build !gcflags_noopt // Copyright 2010 The Go Authors. All rights reserved. From 2d01f3695becd725959a723b512cf46e88ae60fe Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 7 Feb 2023 19:28:15 +0700 Subject: [PATCH 032/165] [release-branch.go1.20] cmd/compile: fix wrong escape analysis for go/defer generic calls For go/defer calls like "defer f(x, y)", the compiler rewrites it to: x1, y1 := x, y defer func() { f(x1, y1) }() However, if "f" needs runtime type information, the "RType" field will refer to the outer ".dict" param, causing wrong liveness analysis. To fix this, if "f" refers to outer ".dict", the dict param will be copied to an autotmp, and "f" will refer to this autotmp instead. Fixes #58467 Change-Id: I238b6e75441442b5540d39bc818205398e80c94d Reviewed-on: https://go-review.googlesource.com/c/go/+/466035 Reviewed-by: David Chase Auto-Submit: Cuong Manh Le Reviewed-by: Matthew Dempsky Run-TryBot: Cuong Manh Le TryBot-Result: Gopher Robot Reviewed-on: https://go-review.googlesource.com/c/go/+/467935 Reviewed-by: Michael Pratt --- src/cmd/compile/internal/escape/call.go | 18 ++++++++++++++- test/fixedbugs/issue58341.go | 30 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue58341.go diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go index e2235520e5cd73..448702e3f07c62 100644 --- a/src/cmd/compile/internal/escape/call.go +++ b/src/cmd/compile/internal/escape/call.go @@ -19,7 +19,7 @@ func (e *escape) call(ks []hole, call ir.Node) { var init ir.Nodes e.callCommon(ks, call, &init, nil) if len(init) != 0 { - call.(*ir.CallExpr).PtrInit().Append(init...) + call.(ir.InitNode).PtrInit().Append(init...) } } @@ -38,6 +38,18 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir argumentFunc(nil, k, argp) } + argumentRType := func(rtypep *ir.Node) { + rtype := *rtypep + if rtype == nil { + return + } + // common case: static rtype/itab argument, which can be evaluated within the wrapper instead. + if addr, ok := rtype.(*ir.AddrExpr); ok && addr.Op() == ir.OADDR && addr.X.Op() == ir.OLINKSYMOFFSET { + return + } + e.wrapExpr(rtype.Pos(), rtypep, init, call, wrapper) + } + switch call.Op() { default: ir.Dump("esc", call) @@ -153,6 +165,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir argument(e.heapHole(), &args[i]) } } + argumentRType(&call.RType) case ir.OCOPY: call := call.(*ir.BinaryExpr) @@ -163,6 +176,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir copiedK = e.heapHole().deref(call, "copied slice") } argument(copiedK, &call.Y) + argumentRType(&call.RType) case ir.OPANIC: call := call.(*ir.UnaryExpr) @@ -179,6 +193,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir for i := range call.Args { argument(e.discardHole(), &call.Args[i]) } + argumentRType(&call.RType) case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE: call := call.(*ir.UnaryExpr) @@ -192,6 +207,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir call := call.(*ir.BinaryExpr) argument(ks[0], &call.X) argument(e.discardHole(), &call.Y) + argumentRType(&call.RType) } } diff --git a/test/fixedbugs/issue58341.go b/test/fixedbugs/issue58341.go new file mode 100644 index 00000000000000..c7b09bee9fb785 --- /dev/null +++ b/test/fixedbugs/issue58341.go @@ -0,0 +1,30 @@ +// 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 S[T comparable] struct { + m map[T]T +} + +func (s S[T]) M1(node T) { + defer delete(s.m, node) +} + +func (s S[T]) M2(node T) { + defer func() { + delete(s.m, node) + }() +} + +func (s S[T]) M3(node T) { + defer f(s.m, node) +} + +//go:noinline +func f[T comparable](map[T]T, T) {} + +var _ = S[int]{} From 7b398b1ff7d751032ea1e4ffed6f02675fc51c3b Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 4 Jan 2023 05:20:58 +0000 Subject: [PATCH 033/165] [release-branch.go1.20] runtime: check for overflow in sweep assist The sweep assist computation is intentionally racy for performance, since the specifics of sweep assist aren't super sensitive to error. However, if overflow occurs when computing the live heap delta, we can end up with a massive sweep target that causes the sweep assist to sweep until sweep termination, causing severe latency issues. In fact, because heapLive doesn't always increase monotonically then anything that flushes mcaches will cause _all_ allocating goroutines to inevitably get stuck in sweeping. Consider the following scenario: 1. SetGCPercent is called, updating sweepHeapLiveBasis to heapLive. 2. Very shortly after, ReadMemStats is called, flushing mcaches and decreasing heapLive below the value sweepHeapLiveBasis was set to. 3. Every allocating goroutine goes to refill its mcache, calls into deductSweepCredit for sweep assist, and gets stuck sweeping until the sweep phase ends. Fix this by just checking for overflow in the delta live heap calculation and if it would overflow, pick a small delta live heap. This probably means that no sweeping will happen at all, but that's OK. This is a transient state and the runtime will recover as soon as heapLive increases again. Note that deductSweepCredit doesn't check overflow on other operations but that's OK: those operations are signed and extremely unlikely to overflow. The subtraction targeted by this CL is only a problem because it's unsigned. An alternative fix would be to make the operation signed, but being explicit about the overflow situation seems worthwhile. For #57523. Fixes #58536. Change-Id: Ib18f71f53468e913548aac6e5358830c72ef0215 Reviewed-on: https://go-review.googlesource.com/c/go/+/468375 Reviewed-by: Michael Pratt Run-TryBot: Michael Knyszek TryBot-Result: Gopher Robot --- src/runtime/mgcsweep.go | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go index c21ecc60d8cf3a..6ccf090ac5b3cd 100644 --- a/src/runtime/mgcsweep.go +++ b/src/runtime/mgcsweep.go @@ -873,11 +873,30 @@ func deductSweepCredit(spanBytes uintptr, callerSweepPages uintptr) { traceGCSweepStart() } + // Fix debt if necessary. retry: sweptBasis := mheap_.pagesSweptBasis.Load() - - // Fix debt if necessary. - newHeapLive := uintptr(gcController.heapLive.Load()-mheap_.sweepHeapLiveBasis) + spanBytes + live := gcController.heapLive.Load() + liveBasis := mheap_.sweepHeapLiveBasis + newHeapLive := spanBytes + if liveBasis < live { + // Only do this subtraction when we don't overflow. Otherwise, pagesTarget + // might be computed as something really huge, causing us to get stuck + // sweeping here until the next mark phase. + // + // Overflow can happen here if gcPaceSweeper is called concurrently with + // sweeping (i.e. not during a STW, like it usually is) because this code + // is intentionally racy. A concurrent call to gcPaceSweeper can happen + // if a GC tuning parameter is modified and we read an older value of + // heapLive than what was used to set the basis. + // + // This state should be transient, so it's fine to just let newHeapLive + // be a relatively small number. We'll probably just skip this attempt to + // sweep. + // + // See issue #57523. + newHeapLive += uintptr(live - liveBasis) + } pagesTarget := int64(mheap_.sweepPagesPerByte*float64(newHeapLive)) - int64(callerSweepPages) for pagesTarget > int64(mheap_.pagesSwept.Load()-sweptBasis) { if sweepone() == ^uintptr(0) { From 1acd39cc92cea4937fe9530c7d9bbce4711fc41c Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 21 Feb 2023 23:00:01 +0000 Subject: [PATCH 034/165] [release-branch.go1.20] Revert "internal/poll: drop redundant ENOSYS in CopyFileRange" This reverts CL 428555. Reason for revert: It appears that even a newer kernel can get ENOSYS from copy_file_range. For #58592 Fixes #58627 Change-Id: Ib8dd1be61544f54bf652a99dc0b449109f8f50ed Reviewed-on: https://go-review.googlesource.com/c/go/+/470316 Run-TryBot: Ian Lance Taylor Reviewed-by: Than McIntosh Reviewed-by: Michael Pratt TryBot-Result: Gopher Robot --- src/internal/poll/copy_file_range_linux.go | 24 +++++++++++++--------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/internal/poll/copy_file_range_linux.go b/src/internal/poll/copy_file_range_linux.go index 66408e459040b5..ba33f5145d4896 100644 --- a/src/internal/poll/copy_file_range_linux.go +++ b/src/internal/poll/copy_file_range_linux.go @@ -41,18 +41,22 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err } n, err := copyFileRange(dst, src, int(max)) switch err { + case syscall.ENOSYS: + // copy_file_range(2) was introduced in Linux 4.5. + // Go supports Linux >= 2.6.33, so the system call + // may not be present. + // + // If we see ENOSYS, we have certainly not transferred + // any data, so we can tell the caller that we + // couldn't handle the transfer and let them fall + // back to more generic code. + return 0, false, nil case syscall.EXDEV, syscall.EINVAL, syscall.EIO, syscall.EOPNOTSUPP, syscall.EPERM: // Prior to Linux 5.3, it was not possible to - // copy_file_range across file systems. An attempt - // to do this will result in a EXDEV error. - // - // Even though we have checked the kernel version and blocked - // the attempts to copy_file_range(2) when the kernel version - // is older than 5.3, but until now the latest kernel (5.19.x) - // may still return EXDEV error in certain cases. - // - // If we see EXDEV, we have not transferred any data, - // and we can let the caller fall back to generic code. + // copy_file_range across file systems. Similarly to + // the ENOSYS case above, if we see EXDEV, we have + // not transferred any data, and we can let the caller + // fall back to generic code. // // As for EINVAL, that is what we see if, for example, // dst or src refer to a pipe rather than a regular From ac556f35a27dbd73372af4088b89df4d61ab74e8 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Wed, 8 Feb 2023 15:06:08 -0500 Subject: [PATCH 035/165] [release-branch.go1.20] cmd/internal/cov: fix misuse of bufio.Reader.Read in read helper Fix a misuse of bufio.Reader.Read in the helper class cmd/internal/cov.MReader; the MReader method in question should have been using io.ReadFull (passing the bufio.Reader) instead of directly calling Read. Using the Read method instead of io.ReadFull will result in a "short" read when processing a specific subset of counter data files, e.g. those that are short enough to not trigger the mmap-based scheme we use for larger files, but also with a large args section (something large enough to exceed the default 4k buffer size used by bufio.Reader). Along the way, add some additional defered Close() calls for files opened by the CovDataReader.visitPod, to enure we don't leave any open file descriptor following a call to CovDataReader.Visit. Fixes #58427. Updates #58411. Change-Id: Iea48dc25c0081be1ade29f3a633df02a681fd941 Reviewed-on: https://go-review.googlesource.com/c/go/+/466677 Run-TryBot: Than McIntosh TryBot-Result: Gopher Robot Reviewed-by: David Chase (cherry picked from commit a7fe9ada10c02a7ea61b2909ef7db151d290073f) Reviewed-on: https://go-review.googlesource.com/c/go/+/468536 Reviewed-by: Cherry Mui --- src/cmd/internal/cov/mreader.go | 2 +- src/cmd/internal/cov/read_test.go | 98 ++++++++++++++++++++++++++ src/cmd/internal/cov/readcovdata.go | 4 ++ src/cmd/internal/cov/testdata/small.go | 7 ++ 4 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 src/cmd/internal/cov/read_test.go create mode 100644 src/cmd/internal/cov/testdata/small.go diff --git a/src/cmd/internal/cov/mreader.go b/src/cmd/internal/cov/mreader.go index 17dcfff05ba0b9..30f53d6ec1a47a 100644 --- a/src/cmd/internal/cov/mreader.go +++ b/src/cmd/internal/cov/mreader.go @@ -51,7 +51,7 @@ func (r *MReader) Read(p []byte) (int, error) { r.off += int64(amt) return amt, nil } - return r.rdr.Read(p) + return io.ReadFull(r.rdr, p) } func (r *MReader) ReadByte() (byte, error) { diff --git a/src/cmd/internal/cov/read_test.go b/src/cmd/internal/cov/read_test.go new file mode 100644 index 00000000000000..cef03fa323e6e8 --- /dev/null +++ b/src/cmd/internal/cov/read_test.go @@ -0,0 +1,98 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cov_test + +import ( + "cmd/internal/cov" + "fmt" + "internal/coverage" + "internal/coverage/decodecounter" + "internal/coverage/decodemeta" + "internal/coverage/pods" + "internal/testenv" + "os" + "path/filepath" + "testing" +) + +// visitor implements the CovDataVisitor interface in a very stripped +// down way, just keeps track of interesting events. +type visitor struct { + metaFileCount int + counterFileCount int + funcCounterData int + metaFuncCount int +} + +func (v *visitor) BeginPod(p pods.Pod) {} +func (v *visitor) EndPod(p pods.Pod) {} +func (v *visitor) VisitMetaDataFile(mdf string, mfr *decodemeta.CoverageMetaFileReader) { + v.metaFileCount++ +} +func (v *visitor) BeginCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) { + v.counterFileCount++ +} +func (v *visitor) EndCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) {} +func (v *visitor) VisitFuncCounterData(payload decodecounter.FuncPayload) { v.funcCounterData++ } +func (v *visitor) EndCounters() {} +func (v *visitor) BeginPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) {} +func (v *visitor) EndPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) {} +func (v *visitor) VisitFunc(pkgIdx uint32, fnIdx uint32, fd *coverage.FuncDesc) { v.metaFuncCount++ } +func (v *visitor) Finish() {} + +func TestIssue58411(t *testing.T) { + testenv.MustHaveGoBuild(t) + + // Build a tiny test program with -cover. Smallness is important; + // it is one of the factors that triggers issue 58411. + d := t.TempDir() + exepath := filepath.Join(d, "small.exe") + path := filepath.Join("testdata", "small.go") + cmd := testenv.Command(t, testenv.GoToolPath(t), "build", + "-o", exepath, "-cover", path) + b, err := cmd.CombinedOutput() + if len(b) != 0 { + t.Logf("## build output:\n%s", b) + } + if err != nil { + t.Fatalf("build error: %v", err) + } + + // Run to produce coverage data. Note the large argument; we need a large + // argument (more than 4k) to trigger the bug, but the overall file + // has to remain small (since large files will be read with mmap). + covdir := filepath.Join(d, "covdata") + if err = os.Mkdir(covdir, 0777); err != nil { + t.Fatalf("creating covdir: %v", err) + } + large := fmt.Sprintf("%07999d", 0) + cmd = testenv.Command(t, exepath, "1", "2", "3", large) + cmd.Dir = covdir + cmd.Env = append(os.Environ(), "GOCOVERDIR="+covdir) + b, err = cmd.CombinedOutput() + if err != nil { + t.Logf("## run output:\n%s", b) + t.Fatalf("build error: %v", err) + } + + vis := &visitor{} + + // Read resulting coverage data. Without the fix, this would + // yield a "short read" error. + const verbosityLevel = 0 + const flags = 0 + cdr := cov.MakeCovDataReader(vis, []string{covdir}, verbosityLevel, flags, nil) + err = cdr.Visit() + if err != nil { + t.Fatalf("visit failed: %v", err) + } + + // make sure we saw a few things just for grins + const want = "{metaFileCount:1 counterFileCount:1 funcCounterData:1 metaFuncCount:1}" + got := fmt.Sprintf("%+v", *vis) + if want != got { + t.Errorf("visitor contents: want %v got %v\n", want, got) + } +} diff --git a/src/cmd/internal/cov/readcovdata.go b/src/cmd/internal/cov/readcovdata.go index 263148b993a84f..7e90e9e8089271 100644 --- a/src/cmd/internal/cov/readcovdata.go +++ b/src/cmd/internal/cov/readcovdata.go @@ -186,6 +186,7 @@ func (r *CovDataReader) visitPod(p pods.Pod) error { if err != nil { return r.fatal("unable to open meta-file %s", p.MetaFile) } + defer f.Close() br := bio.NewReader(f) fi, err := f.Stat() if err != nil { @@ -209,6 +210,9 @@ func (r *CovDataReader) visitPod(p pods.Pod) error { if err != nil { return r.fatal("opening counter data file %s: %s", cdf, err) } + defer func(f *os.File) { + f.Close() + }(cf) var mr *MReader mr, err = NewMreader(cf) if err != nil { diff --git a/src/cmd/internal/cov/testdata/small.go b/src/cmd/internal/cov/testdata/small.go new file mode 100644 index 00000000000000..d81cb70624c699 --- /dev/null +++ b/src/cmd/internal/cov/testdata/small.go @@ -0,0 +1,7 @@ +package main + +import "os" + +func main() { + println(len(os.Args)) +} From 602eeaab387f24a4b28c5eccbb50fa934f3bc3c4 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 13 Feb 2023 15:16:27 +0100 Subject: [PATCH 036/165] [release-branch.go1.20] crypto/internal/nistec: reduce P-256 scalar Unlike the rest of nistec, the P-256 assembly doesn't use complete addition formulas, meaning that p256PointAdd[Affine]Asm won't return the correct value if the two inputs are equal. This was (undocumentedly) ignored in the scalar multiplication loops because as long as the input point is not the identity and the scalar is lower than the order of the group, the addition inputs can't be the same. As part of the math/big rewrite, we went however from always reducing the scalar to only checking its length, under the incorrect assumption that the scalar multiplication loop didn't require reduction. Added a reduction, and while at it added it in P256OrdInverse, too, to enforce a universal reduction invariant on p256OrdElement values. Note that if the input point is the infinity, the code currently still relies on undefined behavior, but that's easily tested to behave acceptably, and will be addressed in a future CL. Updates #58647 Fixes #58720 Fixes CVE-2023-24532 (Filed with the "safe APIs like complete addition formulas are good" dept.) Change-Id: I7b2c75238440e6852be2710fad66ff1fdc4e2b24 Reviewed-on: https://go-review.googlesource.com/c/go/+/471255 TryBot-Result: Gopher Robot Reviewed-by: Roland Shoemaker Run-TryBot: Filippo Valsorda Auto-Submit: Filippo Valsorda Reviewed-by: Damien Neil (cherry picked from commit 203e59ad41bd288e1d92b6f617c2f55e70d3c8e3) Reviewed-on: https://go-review.googlesource.com/c/go/+/471695 Reviewed-by: Dmitri Shuralyov Auto-Submit: Dmitri Shuralyov Reviewed-by: Filippo Valsorda Run-TryBot: Roland Shoemaker --- src/crypto/internal/nistec/nistec_test.go | 81 +++++++++++++++++++++++ src/crypto/internal/nistec/p256_asm.go | 17 +++++ src/crypto/internal/nistec/p256_ordinv.go | 1 + 3 files changed, 99 insertions(+) diff --git a/src/crypto/internal/nistec/nistec_test.go b/src/crypto/internal/nistec/nistec_test.go index 309f68be16a9fc..9103608c18a0f9 100644 --- a/src/crypto/internal/nistec/nistec_test.go +++ b/src/crypto/internal/nistec/nistec_test.go @@ -8,6 +8,7 @@ import ( "bytes" "crypto/elliptic" "crypto/internal/nistec" + "fmt" "internal/testenv" "math/big" "math/rand" @@ -165,6 +166,86 @@ func testEquivalents[P nistPoint[P]](t *testing.T, newPoint func() P, c elliptic } } +func TestScalarMult(t *testing.T) { + t.Run("P224", func(t *testing.T) { + testScalarMult(t, nistec.NewP224Point, elliptic.P224()) + }) + t.Run("P256", func(t *testing.T) { + testScalarMult(t, nistec.NewP256Point, elliptic.P256()) + }) + t.Run("P384", func(t *testing.T) { + testScalarMult(t, nistec.NewP384Point, elliptic.P384()) + }) + t.Run("P521", func(t *testing.T) { + testScalarMult(t, nistec.NewP521Point, elliptic.P521()) + }) +} + +func testScalarMult[P nistPoint[P]](t *testing.T, newPoint func() P, c elliptic.Curve) { + G := newPoint().SetGenerator() + checkScalar := func(t *testing.T, scalar []byte) { + p1, err := newPoint().ScalarBaseMult(scalar) + fatalIfErr(t, err) + p2, err := newPoint().ScalarMult(G, scalar) + fatalIfErr(t, err) + if !bytes.Equal(p1.Bytes(), p2.Bytes()) { + t.Error("[k]G != ScalarBaseMult(k)") + } + + d := new(big.Int).SetBytes(scalar) + d.Sub(c.Params().N, d) + d.Mod(d, c.Params().N) + g1, err := newPoint().ScalarBaseMult(d.FillBytes(make([]byte, len(scalar)))) + fatalIfErr(t, err) + g1.Add(g1, p1) + if !bytes.Equal(g1.Bytes(), newPoint().Bytes()) { + t.Error("[N - k]G + [k]G != ∞") + } + } + + byteLen := len(c.Params().N.Bytes()) + bitLen := c.Params().N.BitLen() + t.Run("0", func(t *testing.T) { checkScalar(t, make([]byte, byteLen)) }) + t.Run("1", func(t *testing.T) { + checkScalar(t, big.NewInt(1).FillBytes(make([]byte, byteLen))) + }) + t.Run("N-1", func(t *testing.T) { + checkScalar(t, new(big.Int).Sub(c.Params().N, big.NewInt(1)).Bytes()) + }) + t.Run("N", func(t *testing.T) { checkScalar(t, c.Params().N.Bytes()) }) + t.Run("N+1", func(t *testing.T) { + checkScalar(t, new(big.Int).Add(c.Params().N, big.NewInt(1)).Bytes()) + }) + t.Run("all1s", func(t *testing.T) { + s := new(big.Int).Lsh(big.NewInt(1), uint(bitLen)) + s.Sub(s, big.NewInt(1)) + checkScalar(t, s.Bytes()) + }) + if testing.Short() { + return + } + for i := 0; i < bitLen; i++ { + t.Run(fmt.Sprintf("1<<%d", i), func(t *testing.T) { + s := new(big.Int).Lsh(big.NewInt(1), uint(i)) + checkScalar(t, s.FillBytes(make([]byte, byteLen))) + }) + } + // Test N+1...N+32 since they risk overlapping with precomputed table values + // in the final additions. + for i := int64(2); i <= 32; i++ { + t.Run(fmt.Sprintf("N+%d", i), func(t *testing.T) { + checkScalar(t, new(big.Int).Add(c.Params().N, big.NewInt(i)).Bytes()) + }) + } +} + +func fatalIfErr(t *testing.T, err error) { + t.Helper() + if err != nil { + t.Fatal(err) + } +} + func BenchmarkScalarMult(b *testing.B) { b.Run("P224", func(b *testing.B) { benchmarkScalarMult(b, nistec.NewP224Point().SetGenerator(), 28) diff --git a/src/crypto/internal/nistec/p256_asm.go b/src/crypto/internal/nistec/p256_asm.go index 6ea161eb499532..99a22b833f028c 100644 --- a/src/crypto/internal/nistec/p256_asm.go +++ b/src/crypto/internal/nistec/p256_asm.go @@ -364,6 +364,21 @@ func p256PointDoubleAsm(res, in *P256Point) // Montgomery domain (with R 2²⁵⁶) as four uint64 limbs in little-endian order. type p256OrdElement [4]uint64 +// p256OrdReduce ensures s is in the range [0, ord(G)-1]. +func p256OrdReduce(s *p256OrdElement) { + // Since 2 * ord(G) > 2²⁵⁶, we can just conditionally subtract ord(G), + // keeping the result if it doesn't underflow. + t0, b := bits.Sub64(s[0], 0xf3b9cac2fc632551, 0) + t1, b := bits.Sub64(s[1], 0xbce6faada7179e84, b) + t2, b := bits.Sub64(s[2], 0xffffffffffffffff, b) + t3, b := bits.Sub64(s[3], 0xffffffff00000000, b) + tMask := b - 1 // zero if subtraction underflowed + s[0] ^= (t0 ^ s[0]) & tMask + s[1] ^= (t1 ^ s[1]) & tMask + s[2] ^= (t2 ^ s[2]) & tMask + s[3] ^= (t3 ^ s[3]) & tMask +} + // Add sets q = p1 + p2, and returns q. The points may overlap. func (q *P256Point) Add(r1, r2 *P256Point) *P256Point { var sum, double P256Point @@ -393,6 +408,7 @@ func (r *P256Point) ScalarBaseMult(scalar []byte) (*P256Point, error) { } scalarReversed := new(p256OrdElement) p256OrdBigToLittle(scalarReversed, (*[32]byte)(scalar)) + p256OrdReduce(scalarReversed) r.p256BaseMult(scalarReversed) return r, nil @@ -407,6 +423,7 @@ func (r *P256Point) ScalarMult(q *P256Point, scalar []byte) (*P256Point, error) } scalarReversed := new(p256OrdElement) p256OrdBigToLittle(scalarReversed, (*[32]byte)(scalar)) + p256OrdReduce(scalarReversed) r.Set(q).p256ScalarMult(scalarReversed) return r, nil diff --git a/src/crypto/internal/nistec/p256_ordinv.go b/src/crypto/internal/nistec/p256_ordinv.go index 86a7a230bdce8e..1274fb7fd3f5cc 100644 --- a/src/crypto/internal/nistec/p256_ordinv.go +++ b/src/crypto/internal/nistec/p256_ordinv.go @@ -25,6 +25,7 @@ func P256OrdInverse(k []byte) ([]byte, error) { x := new(p256OrdElement) p256OrdBigToLittle(x, (*[32]byte)(k)) + p256OrdReduce(x) // Inversion is implemented as exponentiation by n - 2, per Fermat's little theorem. // From 1362737f50ad2cb827eb1b8bc93d8d78e45a1371 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Fri, 17 Feb 2023 14:51:05 -0500 Subject: [PATCH 037/165] [release-branch.go1.20] cmd/link: better fix for arm32 trampgen problem with duff routines This patch provides a fix for a problem linking large arm32 binaries with external linking, specifically R_CALLARM relocations against runtime.duff* routines being flagged by the external linker as not reaching. What appears to be happening in the bug in question is that the Go linker and the external linker are using slightly different recipes to decide whether a given R_CALLARM relocation will "fit" (e.g. will not require a trampoline). The Go linker is taking into account the addend on the call reloc (which for calls to runtime.duffcopy or runtime.duffzero is nonzero), whereas the external linker appears to be ignoring the addend. Example to illustrate: Addr Size Func ----- ----- ----- ... XYZ 1024 runtime.duffcopy ... ABC ... mypackge.MyFunc + R0: R_CALLARM o=8 a=848 tgt=runtime.duffcopy<0> Let's say that the distance between ABC (start address of runtime.duffcopy) and XYZ (start of MyFunc) is just over the architected 24-bit maximum displacement for an R_CALLARM (let's say that ABC-XYZ is just over the architected limit by some small value, say 36). Because we're calling into runtime.duffcopy at offset 848, however, the relocation does in fact fit, but if the external linker isn't taking into account the addend (assuming that all calls target the first instruction of the called routine), then we'll get a "doesn't fit" error from the linker. To work around this problem, revise the ARM trampoline generation code in the Go linker that computes the trampoline threshold to ignore the addend on R_CALLARM relocations, so as to harmonize the two linkers. Fixes #58503. Updates #58428. Updates #58425. Change-Id: I56e580c05b7b47bbe8edf5532a1770bbd700fbe5 Reviewed-on: https://go-review.googlesource.com/c/go/+/469275 TryBot-Result: Gopher Robot Reviewed-by: Cherry Mui Run-TryBot: Than McIntosh (cherry picked from commit 0b5affb193ed559f2cb646e0324827f261e2e767) Reviewed-on: https://go-review.googlesource.com/c/go/+/471597 --- src/cmd/link/internal/arm/asm.go | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index 9eaa7b9eea7f37..1e4b36df48f48d 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -396,9 +396,26 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) { // laid out. Conservatively use a trampoline. This should be rare, as we lay out packages // in dependency order. if ldr.SymValue(rs) != 0 { - // r.Add is the instruction - // low 24-bit encodes the target address - t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4 + // Workaround for issue #58425: it appears that the + // external linker doesn't always take into account the + // relocation addend when doing reachability checks. This + // means that if you have a call from function XYZ at + // offset 8 to runtime.duffzero with addend 800 (for + // example), where the distance between the start of XYZ + // and the start of runtime.duffzero is just over the + // limit (by 100 bytes, say), you can get "relocation + // doesn't fit" errors from the external linker. To deal + // with this, ignore the addend when performing the + // distance calculation (this assumes that we're only + // handling backward jumps; ideally we might want to check + // both with and without the addend). + if ctxt.IsExternal() { + t = (ldr.SymValue(rs) - (ldr.SymValue(s) + int64(r.Off()))) / 4 + } else { + // r.Add is the instruction + // low 24-bit encodes the target address + t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4 + } } if t > 0x7fffff || t < -0x800000 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) { // direct call too far, need to insert trampoline. From 0f4483cfdcf303ac5cbe4f4536e23750423137d9 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 14 Feb 2023 15:13:50 -0800 Subject: [PATCH 038/165] [release-branch.go1.20] cmd/compile/internal/noder: correct positions for synthetic closures When inlining functions that contain function literals, we need to be careful about position information. The OCLOSURE node should use the inline-adjusted position, but the ODCLFUNC and its body should use the original positions. However, the same problem can arise with certain generic constructs, which require the compiler to synthesize function literals to insert dictionary arguments. go.dev/cl/425395 fixed the issue with user-written function literals in a somewhat kludgy way; this CL extends the same solution to synthetic function literals. This is all quite subtle and the solutions aren't terribly robust, so longer term it's probably desirable to revisit how we track inlining context for positions. But for now, this seems to be the least bad solution, esp. for backporting to 1.20. Updates #54625. Fixes #58531. Change-Id: Icc43a70dbb11a0e665cbc9e6a64ef274ad8253d1 Reviewed-on: https://go-review.googlesource.com/c/go/+/468415 TryBot-Result: Gopher Robot Reviewed-by: Cuong Manh Le Reviewed-by: Than McIntosh Run-TryBot: Matthew Dempsky (cherry picked from commit 873c14cec730ee278848f7cc58d2b4d89ab52288) Reviewed-on: https://go-review.googlesource.com/c/go/+/471677 Auto-Submit: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov --- src/cmd/compile/internal/noder/reader.go | 53 ++++++++++++++------- test/typeparam/issue58513.go | 60 ++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 18 deletions(-) create mode 100644 test/typeparam/issue58513.go diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 189531959e555d..591d09ba783efb 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -231,6 +231,16 @@ func (r *reader) pos() src.XPos { return base.Ctxt.PosTable.XPos(r.pos0()) } +// origPos reads a position from the bitstream, and returns both the +// original raw position and an inlining-adjusted position. +func (r *reader) origPos() (origPos, inlPos src.XPos) { + r.suppressInlPos++ + origPos = r.pos() + r.suppressInlPos-- + inlPos = r.inlPos(origPos) + return +} + func (r *reader) pos0() src.Pos { r.Sync(pkgbits.SyncPos) if !r.Bool() { @@ -2117,12 +2127,12 @@ func (r *reader) expr() (res ir.Node) { return typecheck.Callee(r.obj()) case exprFuncInst: - pos := r.pos() + origPos, pos := r.origPos() wrapperFn, baseFn, dictPtr := r.funcInst(pos) if wrapperFn != nil { return wrapperFn } - return r.curry(pos, false, baseFn, dictPtr, nil) + return r.curry(origPos, false, baseFn, dictPtr, nil) case exprConst: pos := r.pos() @@ -2152,7 +2162,7 @@ func (r *reader) expr() (res ir.Node) { case exprMethodVal: recv := r.expr() - pos := r.pos() + origPos, pos := r.origPos() wrapperFn, baseFn, dictPtr := r.methodExpr() // For simple wrapperFn values, the existing machinery for creating @@ -2201,7 +2211,7 @@ func (r *reader) expr() (res ir.Node) { // For more complicated method expressions, we construct a // function literal wrapper. - return r.curry(pos, true, baseFn, recv, dictPtr) + return r.curry(origPos, true, baseFn, recv, dictPtr) case exprMethodExpr: recv := r.typ() @@ -2217,7 +2227,7 @@ func (r *reader) expr() (res ir.Node) { addr = true } - pos := r.pos() + origPos, pos := r.origPos() wrapperFn, baseFn, dictPtr := r.methodExpr() // If we already have a wrapper and don't need to do anything with @@ -2240,7 +2250,7 @@ func (r *reader) expr() (res ir.Node) { return typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, ir.TypeNode(recv), method.Sel)).(*ir.SelectorExpr) } - return r.methodExprWrap(pos, recv, implicits, deref, addr, baseFn, dictPtr) + return r.methodExprWrap(origPos, recv, implicits, deref, addr, baseFn, dictPtr) case exprIndex: x := r.expr() @@ -2570,7 +2580,7 @@ func (pr *pkgReader) objDictName(idx pkgbits.Index, implicits, explicits []*type // If nilCheck is true and arg0 is an interface value, then it's // checked to be non-nil as an initial step at the point of evaluating // the function literal itself. -func (r *reader) curry(pos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir.Node) ir.Node { +func (r *reader) curry(origPos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir.Node) ir.Node { var captured ir.Nodes captured.Append(fun, arg0) if arg1 != nil { @@ -2594,13 +2604,13 @@ func (r *reader) curry(pos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir. r.syntheticTailCall(pos, fun, args) } - return r.syntheticClosure(pos, typ, ifaceHack, captured, addBody) + return r.syntheticClosure(origPos, typ, ifaceHack, captured, addBody) } // methodExprWrap returns a function literal that changes method's // first parameter's type to recv, and uses implicits/deref/addr to // select the appropriate receiver parameter to pass to method. -func (r *reader) methodExprWrap(pos src.XPos, recv *types.Type, implicits []int, deref, addr bool, method, dictPtr ir.Node) ir.Node { +func (r *reader) methodExprWrap(origPos src.XPos, recv *types.Type, implicits []int, deref, addr bool, method, dictPtr ir.Node) ir.Node { var captured ir.Nodes captured.Append(method) @@ -2651,12 +2661,13 @@ func (r *reader) methodExprWrap(pos src.XPos, recv *types.Type, implicits []int, r.syntheticTailCall(pos, fn, args) } - return r.syntheticClosure(pos, typ, false, captured, addBody) + return r.syntheticClosure(origPos, typ, false, captured, addBody) } // syntheticClosure constructs a synthetic function literal for -// currying dictionary arguments. pos is the position used for the -// closure. typ is the function literal's signature type. +// currying dictionary arguments. origPos is the position used for the +// closure, which must be a non-inlined position. typ is the function +// literal's signature type. // // captures is a list of expressions that need to be evaluated at the // point of function literal evaluation and captured by the function @@ -2667,7 +2678,7 @@ func (r *reader) methodExprWrap(pos src.XPos, recv *types.Type, implicits []int, // list of captured values passed back has the captured variables for // use within the function literal, corresponding to the expressions // in captures. -func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool, captures ir.Nodes, addBody func(pos src.XPos, r *reader, captured []ir.Node)) ir.Node { +func (r *reader) syntheticClosure(origPos src.XPos, typ *types.Type, ifaceHack bool, captures ir.Nodes, addBody func(pos src.XPos, r *reader, captured []ir.Node)) ir.Node { // isSafe reports whether n is an expression that we can safely // defer to evaluating inside the closure instead, to avoid storing // them into the closure. @@ -2684,9 +2695,15 @@ func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool, return false } - fn := ir.NewClosureFunc(pos, r.curfn != nil) + // The ODCLFUNC and its body need to use the original position, but + // the OCLOSURE node and any Init statements should use the inlined + // position instead. See also the explanation in reader.funcLit. + inlPos := r.inlPos(origPos) + + fn := ir.NewClosureFunc(origPos, r.curfn != nil) fn.SetWrapper(true) clo := fn.OClosure + clo.SetPos(inlPos) ir.NameClosure(clo, r.curfn) setType(fn.Nname, typ) @@ -2699,13 +2716,13 @@ func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool, continue // skip capture; can reference directly } - tmp := r.tempCopy(pos, n, &init) - ir.NewClosureVar(pos, fn, tmp) + tmp := r.tempCopy(inlPos, n, &init) + ir.NewClosureVar(origPos, fn, tmp) // We need to nil check interface receivers at the point of method // value evaluation, ugh. if ifaceHack && i == 1 && n.Type().IsInterface() { - check := ir.NewUnaryExpr(pos, ir.OCHECKNIL, ir.NewUnaryExpr(pos, ir.OITAB, tmp)) + check := ir.NewUnaryExpr(inlPos, ir.OCHECKNIL, ir.NewUnaryExpr(inlPos, ir.OITAB, tmp)) init.Append(typecheck.Stmt(check)) } } @@ -2723,7 +2740,7 @@ func (r *reader) syntheticClosure(pos src.XPos, typ *types.Type, ifaceHack bool, } assert(next == len(r.closureVars)) - addBody(pos, r, captured) + addBody(origPos, r, captured) }} bodyReader[fn] = pri pri.funcBody(fn) diff --git a/test/typeparam/issue58513.go b/test/typeparam/issue58513.go new file mode 100644 index 00000000000000..37cb5725ca14c0 --- /dev/null +++ b/test/typeparam/issue58513.go @@ -0,0 +1,60 @@ +// 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. + +// Some derived-type expressions require the compiler to synthesize +// function literals to plumb sub-dictionaries appropriately. +// However, when these expressions are inlined, we were constructing +// the function literal bodies with the inline-adjusted positions +// instead of the original (inline-free) positions, which could lead +// to infinite loops when unwinding the stack. + +package main + +import "runtime" + +func assert[_ any]() { + panic(0) +} + +func Assert[To any]() func() { + return assert[To] +} + +type asserter[_ any] struct{} + +func (asserter[_]) assert() { + panic(0) +} + +func AssertMV[To any]() func() { + return asserter[To]{}.assert +} + +func AssertME[To any]() func(asserter[To]) { + return asserter[To].assert +} + +var me = AssertME[string]() + +var tests = []func(){ + Assert[int](), + AssertMV[int](), + func() { me(asserter[string]{}) }, +} + +func main() { + for _, test := range tests { + func() { + defer func() { + recover() + + // Check that we can unwind the stack without infinite looping. + runtime.Caller(1000) + }() + test() + }() + } +} From aaace6dda7cde2bebf13c64fb0d75536adb2b08b Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Tue, 31 Jan 2023 09:14:16 -0800 Subject: [PATCH 039/165] [release-branch.go1.20] crypto/ecdh: explicitly reject mismatched curves in ECDH Return an explicit error when PrivateKey.ECDH is called with a PublicKey which uses a different Curve. Also document this requirement, even though it is perhaps obvious. Updates #58131. Fixes #58498. Change-Id: I739181a3f1283bed14fb5ee7eb78658b854d28d8 Reviewed-on: https://go-review.googlesource.com/c/go/+/464335 Reviewed-by: Filippo Valsorda TryBot-Result: Gopher Robot Reviewed-by: Tatiana Bradley Auto-Submit: Roland Shoemaker Run-TryBot: Roland Shoemaker (cherry picked from commit 67d8916d551d22f5376e0be71d3922c9d63eaa6a) Reviewed-on: https://go-review.googlesource.com/c/go/+/471602 Reviewed-by: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov Auto-Submit: Dmitri Shuralyov Reviewed-by: Roland Shoemaker --- src/crypto/ecdh/ecdh.go | 7 ++++++- src/crypto/ecdh/ecdh_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/crypto/ecdh/ecdh.go b/src/crypto/ecdh/ecdh.go index d78b4d44324c24..74420559b5892f 100644 --- a/src/crypto/ecdh/ecdh.go +++ b/src/crypto/ecdh/ecdh.go @@ -10,6 +10,7 @@ import ( "crypto" "crypto/internal/boring" "crypto/subtle" + "errors" "io" "sync" ) @@ -109,7 +110,8 @@ type PrivateKey struct { publicKeyOnce sync.Once } -// ECDH performs a ECDH exchange and returns the shared secret. +// ECDH performs a ECDH exchange and returns the shared secret. The PrivateKey +// and PublicKey must use the same curve. // // For NIST curves, this performs ECDH as specified in SEC 1, Version 2.0, // Section 3.3.1, and returns the x-coordinate encoded according to SEC 1, @@ -118,6 +120,9 @@ type PrivateKey struct { // For X25519, this performs ECDH as specified in RFC 7748, Section 6.1. If // the result is the all-zero value, ECDH returns an error. func (k *PrivateKey) ECDH(remote *PublicKey) ([]byte, error) { + if k.curve != remote.curve { + return nil, errors.New("crypto/ecdh: private key and public key curves do not match") + } return k.curve.ecdh(k, remote) } diff --git a/src/crypto/ecdh/ecdh_test.go b/src/crypto/ecdh/ecdh_test.go index 426850a146101e..10da95afbb4ed9 100644 --- a/src/crypto/ecdh/ecdh_test.go +++ b/src/crypto/ecdh/ecdh_test.go @@ -487,3 +487,39 @@ func TestLinker(t *testing.T) { t.Error("no P384 symbols found in program using ecdh.P384, test is broken") } } + +func TestMismatchedCurves(t *testing.T) { + curves := []struct { + name string + curve ecdh.Curve + }{ + {"P256", ecdh.P256()}, + {"P384", ecdh.P384()}, + {"P521", ecdh.P521()}, + {"X25519", ecdh.X25519()}, + } + + for _, privCurve := range curves { + priv, err := privCurve.curve.GenerateKey(rand.Reader) + if err != nil { + t.Fatalf("failed to generate test key: %s", err) + } + + for _, pubCurve := range curves { + if privCurve == pubCurve { + continue + } + t.Run(fmt.Sprintf("%s/%s", privCurve.name, pubCurve.name), func(t *testing.T) { + pub, err := pubCurve.curve.GenerateKey(rand.Reader) + if err != nil { + t.Fatalf("failed to generate test key: %s", err) + } + expected := "crypto/ecdh: private key and public key curves do not match" + _, err = priv.ECDH(pub.PublicKey()) + if err.Error() != expected { + t.Fatalf("unexpected error: want %q, got %q", expected, err) + } + }) + } + } +} From ef793801f8b54398c5013caa8ffea092129de1a5 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sun, 8 Jan 2023 17:39:02 +0100 Subject: [PATCH 040/165] [release-branch.go1.20] crypto/internal/bigmod: flag amd64 assembly as noescape MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I had forgotten, which caused amd64 allocations to go back up significantly. Added an allocations test. name old time/op new time/op delta DecryptPKCS1v15/2048-8 1.50ms ± 0% 1.48ms ± 0% -0.95% (p=0.000 n=9+10) DecryptPKCS1v15/3072-8 4.64ms ± 1% 4.60ms ± 0% -0.82% (p=0.000 n=8+10) DecryptPKCS1v15/4096-8 10.7ms ± 0% 10.6ms ± 1% -0.99% (p=0.000 n=10+10) EncryptPKCS1v15/2048-8 158µs ± 0% 157µs ± 0% -0.63% (p=0.000 n=10+10) DecryptOAEP/2048-8 1.50ms ± 0% 1.48ms ± 0% -1.09% (p=0.000 n=9+10) EncryptOAEP/2048-8 161µs ± 0% 160µs ± 0% -0.34% (p=0.000 n=9+10) SignPKCS1v15/2048-8 1.55ms ± 0% 1.53ms ± 1% -1.32% (p=0.000 n=10+10) VerifyPKCS1v15/2048-8 157µs ± 0% 157µs ± 0% -0.33% (p=0.004 n=9+10) SignPSS/2048-8 1.55ms ± 0% 1.54ms ± 0% -1.14% (p=0.000 n=10+10) VerifyPSS/2048-8 160µs ± 0% 160µs ± 0% -0.32% (p=0.000 n=10+10) name old alloc/op new alloc/op delta DecryptPKCS1v15/2048-8 15.0kB ± 0% 0.6kB ± 0% -95.74% (p=0.000 n=10+10) DecryptPKCS1v15/3072-8 17.9kB ± 0% 3.5kB ± 0% -80.65% (p=0.000 n=10+10) DecryptPKCS1v15/4096-8 19.1kB ± 0% 4.7kB ± 0% -75.25% (p=0.000 n=10+10) EncryptPKCS1v15/2048-8 7.51kB ± 0% 1.17kB ± 0% -84.39% (p=0.000 n=10+10) DecryptOAEP/2048-8 15.3kB ± 0% 0.9kB ± 0% -94.29% (p=0.000 n=10+10) EncryptOAEP/2048-8 7.74kB ± 0% 1.40kB ± 0% -81.86% (p=0.000 n=10+10) SignPKCS1v15/2048-8 21.6kB ± 0% 0.9kB ± 0% -95.86% (p=0.000 n=10+10) VerifyPKCS1v15/2048-8 7.25kB ± 0% 0.91kB ± 0% -87.42% (p=0.000 n=10+10) SignPSS/2048-8 22.0kB ± 0% 1.3kB ± 0% -94.12% (p=0.000 n=10+10) VerifyPSS/2048-8 7.46kB ± 0% 1.12kB ± 0% -84.98% (p=0.000 n=10+10) name old allocs/op new allocs/op delta DecryptPKCS1v15/2048-8 54.0 ± 0% 4.0 ± 0% -92.59% (p=0.000 n=10+10) DecryptPKCS1v15/3072-8 60.0 ± 0% 10.0 ± 0% -83.33% (p=0.000 n=10+10) DecryptPKCS1v15/4096-8 60.0 ± 0% 10.0 ± 0% -83.33% (p=0.000 n=10+10) EncryptPKCS1v15/2048-8 29.0 ± 0% 7.0 ± 0% -75.86% (p=0.000 n=10+10) DecryptOAEP/2048-8 60.0 ± 0% 10.0 ± 0% -83.33% (p=0.000 n=10+10) EncryptOAEP/2048-8 35.0 ± 0% 13.0 ± 0% -62.86% (p=0.000 n=10+10) SignPKCS1v15/2048-8 77.0 ± 0% 5.0 ± 0% -93.51% (p=0.000 n=10+10) VerifyPKCS1v15/2048-8 28.0 ± 0% 6.0 ± 0% -78.57% (p=0.000 n=10+10) SignPSS/2048-8 82.0 ± 0% 10.0 ± 0% -87.80% (p=0.000 n=10+10) VerifyPSS/2048-8 33.0 ± 0% 11.0 ± 0% -66.67% (p=0.000 n=10+10) Updates #58501. Fixes #58505. Change-Id: I418c5152833787b80220b556336ec284674c2493 Reviewed-on: https://go-review.googlesource.com/c/go/+/460542 Run-TryBot: Filippo Valsorda TryBot-Result: Gopher Robot Reviewed-by: Roland Shoemaker Reviewed-by: Michael Pratt Auto-Submit: Filippo Valsorda (cherry picked from commit ed370d8720750ad670564079b1e0bcf74f75dd3a) Reviewed-on: https://go-review.googlesource.com/c/go/+/471855 Auto-Submit: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov --- .../internal/bigmod/_asm/nat_amd64_asm.go | 1 + src/crypto/internal/bigmod/nat_amd64.go | 1 + src/crypto/rsa/rsa_test.go | 27 +++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go b/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go index cea9365dcca988..5690f04d1ee268 100644 --- a/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go +++ b/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go @@ -17,6 +17,7 @@ func main() { ConstraintExpr("amd64,gc,!purego") Implement("montgomeryLoop") + Pragma("noescape") size := Load(Param("d").Len(), GP64()) d := Mem{Base: Load(Param("d").Base(), GP64())} diff --git a/src/crypto/internal/bigmod/nat_amd64.go b/src/crypto/internal/bigmod/nat_amd64.go index eaed2280c4550e..e94778245df27f 100644 --- a/src/crypto/internal/bigmod/nat_amd64.go +++ b/src/crypto/internal/bigmod/nat_amd64.go @@ -4,4 +4,5 @@ package bigmod +//go:noescape func montgomeryLoop(d []uint, a []uint, b []uint, m []uint, m0inv uint) uint diff --git a/src/crypto/rsa/rsa_test.go b/src/crypto/rsa/rsa_test.go index 16101f043a770f..3278a7ff305766 100644 --- a/src/crypto/rsa/rsa_test.go +++ b/src/crypto/rsa/rsa_test.go @@ -8,6 +8,7 @@ import ( "bufio" "bytes" "crypto" + "crypto/internal/boring" "crypto/rand" . "crypto/rsa" "crypto/sha1" @@ -16,6 +17,7 @@ import ( "encoding/pem" "flag" "fmt" + "internal/testenv" "math/big" "strings" "testing" @@ -129,6 +131,31 @@ func testKeyBasics(t *testing.T, priv *PrivateKey) { } } +func TestAllocations(t *testing.T) { + if boring.Enabled { + t.Skip("skipping allocations test with BoringCrypto") + } + testenv.SkipIfOptimizationOff(t) + + m := []byte("Hello Gophers") + c, err := EncryptPKCS1v15(rand.Reader, &test2048Key.PublicKey, m) + if err != nil { + t.Fatal(err) + } + + if allocs := testing.AllocsPerRun(100, func() { + p, err := DecryptPKCS1v15(nil, test2048Key, c) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(p, m) { + t.Fatalf("unexpected output: %q", p) + } + }); allocs > 10 { + t.Errorf("expected less than 10 allocations, got %0.1f", allocs) + } +} + var allFlag = flag.Bool("all", false, "test all key sizes up to 2048") func TestEverything(t *testing.T) { From aef8a8cd42726d4a86481d0eaee4b3a44b180afe Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 15 Feb 2023 16:47:40 -0800 Subject: [PATCH 041/165] [release-branch.go1.20] syscall: Faccessat: check for CAP_DAC_OVERRIDE on Linux CL 416115 added using faccessat2(2) from syscall.Faccessat on Linux (which is the only true way to implement AT_EACCESS flag handing), if available. If not available, it uses some heuristics to mimic the kernel behavior, mostly taken from glibc (see CL 126415). Next, CL 414824 added using the above call (via unix.Eaccess) to exec.LookPath in order to check if the binary can really be executed. As a result, in a very specific scenario, described below, syscall.Faccessat (and thus exec.LookPath) mistakenly tells that the binary can not be executed, while in reality it can be. This makes this bug a regression in Go 1.20. This scenario involves all these conditions: - no faccessat2 support available (i.e. either Linux kernel < 5.8, or a seccomp set up to disable faccessat2); - the current user is not root (i.e. geteuid() != 0); - CAP_DAC_OVERRIDE capability is set for the current process; - the file to be executed does not have executable permission bit set for either the current EUID or EGID; - the file to be executed have at least one executable bit set. Unfortunately, this set of conditions was observed in the wild -- a container run as a non-root user with the binary file owned by root with executable permission set for a user only [1]. Essentially it means it is not as rare as it may seem. Now, CAP_DAC_OVERRIDE essentially makes the kernel bypass most of the checks, so execve(2) and friends work the same was as for root user, i.e. if at least one executable bit it set, the permission to execute is granted (see generic_permission() function in the Linux kernel). Modify the code to check for CAP_DAC_OVERRIDE and mimic the kernel behavior for permission checks. [1] https://github.com/opencontainers/runc/issues/3715 For #58552. Fixes #58624. Change-Id: I82a7e757ab3fd3d0193690a65c3b48fee46ff067 Reviewed-on: https://go-review.googlesource.com/c/go/+/468735 Reviewed-by: Damien Neil TryBot-Result: Gopher Robot Run-TryBot: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor (cherry picked from commit 031401a7905a38498fc399fc10cd0c1e885f7fc9) Reviewed-on: https://go-review.googlesource.com/c/go/+/469956 Auto-Submit: Dmitri Shuralyov Run-TryBot: Than McIntosh Reviewed-by: Than McIntosh Reviewed-by: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov --- src/syscall/syscall_linux.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go index d4cc34bdee0b2f..f337388a749e37 100644 --- a/src/syscall/syscall_linux.go +++ b/src/syscall/syscall_linux.go @@ -138,6 +138,16 @@ func isGroupMember(gid int) bool { return false } +func isCapDacOverrideSet() bool { + const _CAP_DAC_OVERRIDE = 1 + var c caps + c.hdr.version = _LINUX_CAPABILITY_VERSION_3 + + _, _, err := RawSyscall(SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(&c.data[0])), 0) + + return err == 0 && c.data[0].effective&capToMask(_CAP_DAC_OVERRIDE) != 0 +} + //sys faccessat(dirfd int, path string, mode uint32) (err error) //sys faccessat2(dirfd int, path string, mode uint32, flags int) (err error) = _SYS_faccessat2 @@ -179,9 +189,16 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { return nil } + // Fallback to checking permission bits. var uid int if flags&_AT_EACCESS != 0 { uid = Geteuid() + if uid != 0 && isCapDacOverrideSet() { + // If CAP_DAC_OVERRIDE is set, file access check is + // done by the kernel in the same way as for root + // (see generic_permission() in the Linux sources). + uid = 0 + } } else { uid = Getuid() } From bdd86bda09050bdeaf4e812eef69ba13ff57dfee Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Tue, 28 Feb 2023 10:11:51 -0800 Subject: [PATCH 042/165] [release-branch.go1.20] crypto/x509: fix ParsePKCS8PrivateKey comment Updates #58789. Fixes #58793. Change-Id: I91cdd20c6d4f05baaacd6a38717aa7bed6682573 Reviewed-on: https://go-review.googlesource.com/c/go/+/472155 TryBot-Result: Gopher Robot Run-TryBot: Roland Shoemaker Auto-Submit: Roland Shoemaker Reviewed-by: Damien Neil (cherry picked from commit ec26277aecfba112089b1bb54b522bf062059e22) Reviewed-on: https://go-review.googlesource.com/c/go/+/472415 Reviewed-by: Filippo Valsorda Auto-Submit: Dmitri Shuralyov TryBot-Bypass: Dmitri Shuralyov Reviewed-by: Roland Shoemaker Reviewed-by: Dmitri Shuralyov --- src/crypto/x509/pkcs8.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/x509/pkcs8.go b/src/crypto/x509/pkcs8.go index 63bfa9987df3f9..2d085e0a966992 100644 --- a/src/crypto/x509/pkcs8.go +++ b/src/crypto/x509/pkcs8.go @@ -28,7 +28,7 @@ type pkcs8 struct { // ParsePKCS8PrivateKey parses an unencrypted private key in PKCS #8, ASN.1 DER form. // // It returns a *rsa.PrivateKey, a *ecdsa.PrivateKey, a ed25519.PrivateKey (not -// a pointer), or a *ecdh.PublicKey (for X25519). More types might be supported +// a pointer), or a *ecdh.PrivateKey (for X25519). More types might be supported // in the future. // // This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY". From 230765a11a9be0aa72a6dc1a8a02bad246514535 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 5 Jan 2023 14:00:25 -0500 Subject: [PATCH 043/165] [release-branch.go1.20] net: delete TestTCPSelfConnect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test is flaky, apparently due to a typo'd operator in CL 21447 that causes it to compare “same port OR IP” instead of “same port AND IP”. If we merely fixed the comparison, the test would hopefully stop being flaky itself, but we would still be left with another problem: repeatedly dialing a port that we believe to be unused can interfere with other tests, which may open the previously-unused port and then attempt a single Dial and expect it to succeed. Arbitrary other Dial calls for that port may cause the wrong connection to be accepted, leading to spurious test failures. Moreover, the test can be extremely expensive for the amount of data we hope to get from it, depending on the system's port-reuse algorithms and dial implementations. It is already scaled back by up to 1000x on a huge number of platforms due to latency, and may even be ineffective on those platforms because of the arbitrary 1ms Dial timeout. And the incremental value from it is quite low, too: it tests the workaround for what is arguably a bug in the Linux kernel, which ought to be fixed (and tested) upstream instead of worked around in every open-source project that dials local ports. Instead of trying to deflake this test, let's just get rid of it. Updates #18290. Fixes #58717. Change-Id: I8a58b93d67916a33741c9ab29ef99c49c46b32c4 Reviewed-on: https://go-review.googlesource.com/c/go/+/460657 TryBot-Result: Gopher Robot Auto-Submit: Bryan Mills Reviewed-by: Ian Lance Taylor Run-TryBot: Bryan Mills (cherry picked from commit e08642cae18460778ba3f7808c91cbf6d9ee9f67) Reviewed-on: https://go-review.googlesource.com/c/go/+/471155 Reviewed-by: Ian Lance Taylor Reviewed-by: Damien Neil Auto-Submit: Dmitri Shuralyov --- src/net/tcpsock_test.go | 44 ----------------------------------------- 1 file changed, 44 deletions(-) diff --git a/src/net/tcpsock_test.go b/src/net/tcpsock_test.go index 990d34706fdf83..35a93d1f385ced 100644 --- a/src/net/tcpsock_test.go +++ b/src/net/tcpsock_test.go @@ -617,50 +617,6 @@ func TestTCPStress(t *testing.T) { <-done } -func TestTCPSelfConnect(t *testing.T) { - if runtime.GOOS == "windows" { - // TODO(brainman): do not know why it hangs. - t.Skip("known-broken test on windows") - } - - ln := newLocalListener(t, "tcp") - var d Dialer - c, err := d.Dial(ln.Addr().Network(), ln.Addr().String()) - if err != nil { - ln.Close() - t.Fatal(err) - } - network := c.LocalAddr().Network() - laddr := *c.LocalAddr().(*TCPAddr) - c.Close() - ln.Close() - - // Try to connect to that address repeatedly. - n := 100000 - if testing.Short() { - n = 1000 - } - switch runtime.GOOS { - case "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "illumos", "solaris", "windows": - // Non-Linux systems take a long time to figure - // out that there is nothing listening on localhost. - n = 100 - } - for i := 0; i < n; i++ { - d.Timeout = time.Millisecond - c, err := d.Dial(network, laddr.String()) - if err == nil { - addr := c.LocalAddr().(*TCPAddr) - if addr.Port == laddr.Port || addr.IP.Equal(laddr.IP) { - t.Errorf("Dial %v should fail", addr) - } else { - t.Logf("Dial %v succeeded - possibly racing with other listener", addr) - } - c.Close() - } - } -} - // Test that >32-bit reads work on 64-bit systems. // On 32-bit systems this tests that maxint reads work. func TestTCPBig(t *testing.T) { From d2d0ee2049e78d8c57025e0861425808825c759e Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sat, 25 Feb 2023 16:32:15 +0700 Subject: [PATCH 044/165] [release-branch.go1.20] syscall: fix invalid unsafe.Pointer conversion on Windows Updates #58714 Fixes #58774 Change-Id: Ifa5c059ed5e358ed98aee7e83b95dd1806b535f7 Reviewed-on: https://go-review.googlesource.com/c/go/+/471335 Reviewed-by: Than McIntosh TryBot-Result: Gopher Robot Reviewed-by: Ian Lance Taylor Run-TryBot: Cuong Manh Le Reviewed-by: Bryan Mills (cherry picked from commit de8c999159bb72e8a43f9b38b6369fc43eca572e) Reviewed-on: https://go-review.googlesource.com/c/go/+/471599 Reviewed-by: Cuong Manh Le Auto-Submit: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov Run-TryBot: Bryan Mills --- src/syscall/env_windows.go | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/syscall/env_windows.go b/src/syscall/env_windows.go index cd085a9e44732c..94364f930c6fe4 100644 --- a/src/syscall/env_windows.go +++ b/src/syscall/env_windows.go @@ -74,21 +74,24 @@ func Clearenv() { } func Environ() []string { - s, e := GetEnvironmentStrings() + envp, e := GetEnvironmentStrings() if e != nil { return nil } - defer FreeEnvironmentStrings(s) + defer FreeEnvironmentStrings(envp) + r := make([]string, 0, 50) // Empty with room to grow. - for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ { - if p[i] == 0 { - // empty string marks the end - if i <= from { - break - } - r = append(r, string(utf16.Decode(p[from:i]))) - from = i + 1 + const size = unsafe.Sizeof(*envp) + for *envp != 0 { // environment block ends with empty string + // find NUL terminator + end := unsafe.Pointer(envp) + for *(*uint16)(end) != 0 { + end = unsafe.Add(end, size) } + + entry := unsafe.Slice(envp, (uintptr(end)-uintptr(unsafe.Pointer(envp)))/size) + r = append(r, string(utf16.Decode(entry))) + envp = (*uint16)(unsafe.Add(end, size)) } return r } From 3243f93747227816795bca8f04452fbdc2237e5f Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Tue, 28 Feb 2023 13:23:43 -0800 Subject: [PATCH 045/165] [release-branch.go1.20] crypto/x509: fix system root tests + darwin intermediate handling On Windows, replace tests which rely on a root that expired last year. On Darwin fix an test which wasn't testing the expected behavior, and fix the behavior which was broken. Updates #58791 Fixes #58811 Change-Id: I771175b9e123b8bb0e4efdf58cc2bb93aa94fbae Reviewed-on: https://go-review.googlesource.com/c/go/+/472295 TryBot-Result: Gopher Robot Reviewed-by: Bryan Mills Run-TryBot: Roland Shoemaker (cherry picked from commit bb8f9a6ae66d742cb67b4ad444179905a537de00) Reviewed-on: https://go-review.googlesource.com/c/go/+/472616 Auto-Submit: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov --- src/crypto/x509/root_darwin.go | 5 +- src/crypto/x509/root_unix_test.go | 2 +- src/crypto/x509/verify_test.go | 490 ++++++++++++++---------------- 3 files changed, 238 insertions(+), 259 deletions(-) diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go index de2ff894a92aa2..469e907a8e154e 100644 --- a/src/crypto/x509/root_darwin.go +++ b/src/crypto/x509/root_darwin.go @@ -25,9 +25,10 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate return nil, err } sc, err := macOS.SecCertificateCreateWithData(c.Raw) - if err == nil { - macOS.CFArrayAppendValue(certs, sc) + if err != nil { + return nil, err } + macOS.CFArrayAppendValue(certs, sc) } } diff --git a/src/crypto/x509/root_unix_test.go b/src/crypto/x509/root_unix_test.go index 7197a0de3b185c..d5215b9ff2afd8 100644 --- a/src/crypto/x509/root_unix_test.go +++ b/src/crypto/x509/root_unix_test.go @@ -149,7 +149,7 @@ func TestLoadSystemCertsLoadColonSeparatedDirs(t *testing.T) { tmpDir := t.TempDir() rootPEMs := []string{ - geoTrustRoot, + gtsRoot, googleLeaf, startComRoot, } diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go index 4c21e78ccc925f..cd9f6a8788efa2 100644 --- a/src/crypto/x509/verify_test.go +++ b/src/crypto/x509/verify_test.go @@ -43,33 +43,33 @@ var verifyTests = []verifyTest{ { name: "Valid", leaf: googleLeaf, - intermediates: []string{giag2Intermediate}, - roots: []string{geoTrustRoot}, - currentTime: 1395785200, + intermediates: []string{gtsIntermediate}, + roots: []string{gtsRoot}, + currentTime: 1677615892, dnsName: "www.google.com", expectedChains: [][]string{ - {"Google", "Google Internet Authority", "GeoTrust"}, + {"www.google.com", "GTS CA 1C3", "GTS Root R1"}, }, }, { name: "MixedCase", leaf: googleLeaf, - intermediates: []string{giag2Intermediate}, - roots: []string{geoTrustRoot}, - currentTime: 1395785200, + intermediates: []string{gtsIntermediate}, + roots: []string{gtsRoot}, + currentTime: 1677615892, dnsName: "WwW.GooGLE.coM", expectedChains: [][]string{ - {"Google", "Google Internet Authority", "GeoTrust"}, + {"www.google.com", "GTS CA 1C3", "GTS Root R1"}, }, }, { name: "HostnameMismatch", leaf: googleLeaf, - intermediates: []string{giag2Intermediate}, - roots: []string{geoTrustRoot}, - currentTime: 1395785200, + intermediates: []string{gtsIntermediate}, + roots: []string{gtsRoot}, + currentTime: 1677615892, dnsName: "www.example.com", errorCallback: expectHostnameError("certificate is valid for"), @@ -77,9 +77,9 @@ var verifyTests = []verifyTest{ { name: "IPMissing", leaf: googleLeaf, - intermediates: []string{giag2Intermediate}, - roots: []string{geoTrustRoot}, - currentTime: 1395785200, + intermediates: []string{gtsIntermediate}, + roots: []string{gtsRoot}, + currentTime: 1677615892, dnsName: "1.2.3.4", errorCallback: expectHostnameError("doesn't contain any IP SANs"), @@ -87,8 +87,8 @@ var verifyTests = []verifyTest{ { name: "Expired", leaf: googleLeaf, - intermediates: []string{giag2Intermediate}, - roots: []string{geoTrustRoot}, + intermediates: []string{gtsIntermediate}, + roots: []string{gtsRoot}, currentTime: 1, dnsName: "www.example.com", @@ -97,8 +97,8 @@ var verifyTests = []verifyTest{ { name: "MissingIntermediate", leaf: googleLeaf, - roots: []string{geoTrustRoot}, - currentTime: 1395785200, + roots: []string{gtsRoot}, + currentTime: 1677615892, dnsName: "www.google.com", // Skip when using systemVerify, since Windows @@ -109,13 +109,13 @@ var verifyTests = []verifyTest{ { name: "RootInIntermediates", leaf: googleLeaf, - intermediates: []string{geoTrustRoot, giag2Intermediate}, - roots: []string{geoTrustRoot}, - currentTime: 1395785200, + intermediates: []string{gtsRoot, gtsIntermediate}, + roots: []string{gtsRoot}, + currentTime: 1677615892, dnsName: "www.google.com", expectedChains: [][]string{ - {"Google", "Google Internet Authority", "GeoTrust"}, + {"www.google.com", "GTS CA 1C3", "GTS Root R1"}, }, // CAPI doesn't build the chain with the duplicated GeoTrust // entry so the results don't match. @@ -163,9 +163,9 @@ var verifyTests = []verifyTest{ { name: "InvalidHash", leaf: googleLeafWithInvalidHash, - intermediates: []string{giag2Intermediate}, - roots: []string{geoTrustRoot}, - currentTime: 1395785200, + intermediates: []string{gtsIntermediate}, + roots: []string{gtsRoot}, + currentTime: 1677615892, dnsName: "www.google.com", // The specific error message may not occur when using system @@ -230,21 +230,20 @@ var verifyTests = []verifyTest{ // Check that SHA-384 intermediates (which are popping up) // work. name: "SHA-384", - leaf: moipLeafCert, - intermediates: []string{comodoIntermediateSHA384, comodoRSAAuthority}, - roots: []string{addTrustRoot}, - currentTime: 1397502195, - dnsName: "api.moip.com.br", + leaf: trustAsiaLeaf, + intermediates: []string{trustAsiaSHA384Intermediate}, + roots: []string{digicertRoot}, + currentTime: 1558051200, + dnsName: "tm.cn", // CryptoAPI can find alternative validation paths. systemLax: true, expectedChains: [][]string{ { - "api.moip.com.br", - "COMODO RSA Extended Validation Secure Server CA", - "COMODO RSA Certification Authority", - "AddTrust External CA Root", + "tm.cn", + "TrustAsia ECC OV TLS Pro CA", + "DigiCert Global Root CA", }, }, }, @@ -582,106 +581,135 @@ func nameToKey(name *pkix.Name) string { return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName } -const geoTrustRoot = `-----BEGIN CERTIFICATE----- -MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i -YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg -R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 -9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq -fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv -iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU -1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ -bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW -MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA -ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l -uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn -Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS -tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF -PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un -hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV -5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +const gtsIntermediate = `-----BEGIN CERTIFICATE----- +MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw +MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp +kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX +lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm +BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA +gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL +tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud +DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T +AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD +VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG +CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw +AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt +MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG +A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br +aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN +AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ +cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL +RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U ++o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr +PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER +lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs +Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO +z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG +AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw +juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl +1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd -----END CERTIFICATE-----` -const giag2Intermediate = `-----BEGIN CERTIFICATE----- -MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i -YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG -EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy -bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP -VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv -h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE -ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ -EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC -DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7 -qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD -VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g -K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI -KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n -ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB -BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY -/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/ -zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza -HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto -WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6 -yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx +const gtsRoot = `-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo +27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w +Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw +TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl +qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH +szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 +Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk +MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p +aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN +VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb +C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy +h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 +7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J +ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef +MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ +Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT +6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ +0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm +2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb +bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c -----END CERTIFICATE-----` const googleLeaf = `-----BEGIN CERTIFICATE----- -MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE -BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl -cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw -WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN -TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3 -Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe -m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6 -jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q -fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4 -NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ -0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI -dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI -KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE -XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0 -MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G -A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud -IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW -eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB -RzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj -5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf -tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+ -orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi -8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA -Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX +MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQsFADBG +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw +ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a +wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o +55kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr +N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs +KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q +WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw +DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC +MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0 +f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb +aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v +cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n +b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD +VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow +TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4 +4FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S +3T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx +1+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB +hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC +IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQsF +AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p +MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd +VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga +zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI +c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP +i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg== -----END CERTIFICATE-----` // googleLeafWithInvalidHash is the same as googleLeaf, but the signature // algorithm in the certificate contains a nonsense OID. const googleLeafWithInvalidHash = `-----BEGIN CERTIFICATE----- -MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAWAFBQAwSTELMAkGA1UE -BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl -cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw -WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN -TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3 -Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe -m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6 -jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q -fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4 -NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ -0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI -dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI -KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE -XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0 -MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G -A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud -IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW -eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB -RzIuY3JsMA0GCSqGSIb3DQFgBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj -5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf -tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+ -orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi -8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA -Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX +MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQ4FADBG +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw +ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a +wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o +55kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr +N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs +KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q +WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw +DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC +MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0 +f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb +aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v +cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n +b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD +VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow +TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4 +4FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S +3T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx +1+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB +hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC +IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQ4F +AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p +MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd +VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga +zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI +c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP +i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg== -----END CERTIFICATE-----` const dnssecExpLeaf = `-----BEGIN CERTIFICATE----- @@ -1095,136 +1123,81 @@ DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE-----` -var moipLeafCert = `-----BEGIN CERTIFICATE----- -MIIGQDCCBSigAwIBAgIRAPe/cwh7CUWizo8mYSDavLIwDQYJKoZIhvcNAQELBQAw -gZIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO -BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTgwNgYD -VQQDEy9DT01PRE8gUlNBIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZl -ciBDQTAeFw0xMzA4MTUwMDAwMDBaFw0xNDA4MTUyMzU5NTlaMIIBQjEXMBUGA1UE -BRMOMDg3MTg0MzEwMDAxMDgxEzARBgsrBgEEAYI3PAIBAxMCQlIxGjAYBgsrBgEE -AYI3PAIBAhMJU2FvIFBhdWxvMR0wGwYDVQQPExRQcml2YXRlIE9yZ2FuaXphdGlv -bjELMAkGA1UEBhMCQlIxETAPBgNVBBETCDAxNDUyMDAwMRIwEAYDVQQIEwlTYW8g -UGF1bG8xEjAQBgNVBAcTCVNhbyBQYXVsbzEtMCsGA1UECRMkQXZlbmlkYSBCcmln -YWRlaXJvIEZhcmlhIExpbWEgLCAyOTI3MR0wGwYDVQQKExRNb2lwIFBhZ2FtZW50 -b3MgUy5BLjENMAsGA1UECxMETU9JUDEYMBYGA1UECxMPU1NMIEJsaW5kYWRvIEVW -MRgwFgYDVQQDEw9hcGkubW9pcC5jb20uYnIwggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQDN0b9x6TrXXA9hPCF8/NjqGJ++2D4LO4ZiMFTjs0VwpXy2Y1Oe -s74/HuiLGnAHxTmAtV7IpZMibiOcTxcnDYp9oEWkf+gR+hZvwFZwyOBC7wyb3SR3 -UvV0N1ZbEVRYpN9kuX/3vjDghjDmzzBwu8a/T+y5JTym5uiJlngVAWyh/RjtIvYi -+NVkQMbyVlPGkoCe6c30pH8DKYuUCZU6DHjUsPTX3jAskqbhDSAnclX9iX0p2bmw -KVBc+5Vh/2geyzDuquF0w+mNIYdU5h7uXvlmJnf3d2Cext5dxdL8/jezD3U0dAqI -pYSKERbyxSkJWxdvRlhdpM9YXMJcpc88xNp1AgMBAAGjggHcMIIB2DAfBgNVHSME -GDAWgBQ52v/KKBSKqHQTCLnkDqnS+n6daTAdBgNVHQ4EFgQU/lXuOa7DMExzZjRj -LQWcMWGZY7swDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYw -FAYIKwYBBQUHAwEGCCsGAQUFBwMCMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQUB -MCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5jb20vQ1BTMFYG -A1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JT -QUV4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNybDCBhwYIKwYBBQUH -AQEEezB5MFEGCCsGAQUFBzAChkVodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01P -RE9SU0FFeHRlbmRlZFZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcnQwJAYIKwYB -BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAvBgNVHREEKDAmgg9hcGku -bW9pcC5jb20uYnKCE3d3dy5hcGkubW9pcC5jb20uYnIwDQYJKoZIhvcNAQELBQAD -ggEBAFoTmPlaDcf+nudhjXHwud8g7/LRyA8ucb+3/vfmgbn7FUc1eprF5sJS1mA+ -pbiTyXw4IxcJq2KUj0Nw3IPOe9k84mzh+XMmdCKH+QK3NWkE9Udz+VpBOBc0dlqC -1RH5umStYDmuZg/8/r652eeQ5kUDcJyADfpKWBgDPYaGtwzKVT4h3Aok9SLXRHx6 -z/gOaMjEDMarMCMw4VUIG1pvNraZrG5oTaALPaIXXpd8VqbQYPudYJ6fR5eY3FeW -H/ofbYFdRcuD26MfBFWE9VGGral9Fgo8sEHffho+UWhgApuQV4/l5fMzxB5YBXyQ -jhuy8PqqZS9OuLilTeLu4a8z2JI= +const digicertRoot = `-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE-----` -var comodoIntermediateSHA384 = `-----BEGIN CERTIFICATE----- -MIIGDjCCA/agAwIBAgIQBqdDgNTr/tQ1taP34Wq92DANBgkqhkiG9w0BAQwFADCB -hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV -BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTIwMjEy -MDAwMDAwWhcNMjcwMjExMjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgT -EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR -Q09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBSU0EgRXh0ZW5kZWQg -VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAlVbeVLTf1QJJe9FbXKKyHo+cK2JMK40SKPMalaPGEP0p3uGf -CzhAk9HvbpUQ/OGQF3cs7nU+e2PsYZJuTzurgElr3wDqAwB/L3XVKC/sVmePgIOj -vdwDmZOLlJFWW6G4ajo/Br0OksxgnP214J9mMF/b5pTwlWqvyIqvgNnmiDkBfBzA -xSr3e5Wg8narbZtyOTDr0VdVAZ1YEZ18bYSPSeidCfw8/QpKdhQhXBZzQCMZdMO6 -WAqmli7eNuWf0MLw4eDBYuPCGEUZUaoXHugjddTI0JYT/8ck0YwLJ66eetw6YWNg -iJctXQUL5Tvrrs46R3N2qPos3cCHF+msMJn4HwIDAQABo4IBaTCCAWUwHwYDVR0j -BBgwFoAUu69+Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYEFDna/8ooFIqodBMI -ueQOqdL6fp1pMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMD4G -A1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5j -b21vZG8uY29tL0NQUzBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9k -b2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggr -BgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29t -L0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz -cC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAERCnUFRK0iIXZebeV4R -AUpSGXtBLMeJPNBy3IX6WK/VJeQT+FhlZ58N/1eLqYVeyqZLsKeyLeCMIs37/3mk -jCuN/gI9JN6pXV/kD0fQ22YlPodHDK4ixVAihNftSlka9pOlk7DgG4HyVsTIEFPk -1Hax0VtpS3ey4E/EhOfUoFDuPPpE/NBXueEoU/1Tzdy5H3pAvTA/2GzS8+cHnx8i -teoiccsq8FZ8/qyo0QYPFBRSTP5kKwxpKrgNUG4+BAe/eiCL+O5lCeHHSQgyPQ0o -fkkdt0rvAucNgBfIXOBhYsvss2B5JdoaZXOcOBCgJjqwyBZ9kzEi7nQLiMBciUEA -KKlHMd99SUWa9eanRRrSjhMQ34Ovmw2tfn6dNVA0BM7pINae253UqNpktNEvWS5e -ojZh1CSggjMziqHRbO9haKPl0latxf1eYusVqHQSTC8xjOnB3xBLAer2VBvNfzu9 -XJ/B288ByvK6YBIhMe2pZLiySVgXbVrXzYxtvp5/4gJYp9vDLVj2dAZqmvZh+fYA -tmnYOosxWd2R5nwnI4fdAw+PKowegwFOAWEMUnNt/AiiuSpm5HZNMaBWm9lTjaK2 -jwLI5jqmBNFI+8NKAnb9L9K8E7bobTQk+p0pisehKxTxlgBzuRPpwLk6R1YCcYAn -pLwltum95OmYdBbxN4SBB7SC +const trustAsiaSHA384Intermediate = `-----BEGIN CERTIFICATE----- +MIID9zCCAt+gAwIBAgIQC965p4OR4AKrGlsyW0XrDzANBgkqhkiG9w0BAQwFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0xODA0MjcxMjQyNTlaFw0yODA0MjcxMjQyNTlaMFoxCzAJBgNVBAYTAkNO +MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQD +ExtUcnVzdEFzaWEgRUNDIE9WIFRMUyBQcm8gQ0EwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQPIUn75M5BCQLKoPsSU2KTr3mDMh13usnAQ38XfKOzjXiyQ+W0inA7meYR +xS+XMQgvnbCigEsKj3ErPIzO68uC9V/KdqMaXWBJp85Ws9A4KL92NB4Okbn5dp6v +Qzy08PajggFeMIIBWjAdBgNVHQ4EFgQULdRyBx6HyIH/+LOvuexyH5p/3PwwHwYD +VR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0G +A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEA +MDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AuZGlnaWNl +cnQtY24uY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwuZGlnaWNlcnQt +Y24uY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDBWBgNVHSAETzBNMDcGCWCG +SAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v +Q1BTMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQEMBQADggEBACVRufYd +j81xUqngFCO+Pk8EYXie0pxHKsBZnOPygAyXKx+awUasKBAnHjmhoFPXaDGAP2oV +OeZTWgwnURVr6wUCuTkz2/8Tgl1egC7OrVcHSa0fIIhaVo9/zRA/hr31xMG7LFBk +GNd7jd06Up4f/UOGbcJsqJexc5QRcUeSwe1MiUDcTNiyCjZk74QCPdcfdFYM4xsa +SlUpboB5vyT7jFePZ2v95CKjcr0EhiQ0gwxpdgoipZdfYTiMFGxCLsk6v8pUv7Tq +PT/qadOGyC+PfLuZh1PtLp20mF06K+MzheCiv+w1NT5ofhmcObvukc68wvbvRFL6 +rRzZxAYN36q1SX8= -----END CERTIFICATE-----` -const comodoRSAAuthority = `-----BEGIN CERTIFICATE----- -MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv -MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk -ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF -eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow -gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO -BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD -VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq -hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw -AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6 -2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr -ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt -4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq -m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/ -vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT -8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE -IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO -KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO -GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/ -s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g -JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD -AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9 -MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy -bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6 -Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ -zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj -Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY -Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5 -B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx -PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR -pu/xO28QOG8= ------END CERTIFICATE-----` - -const addTrustRoot = `-----BEGIN CERTIFICATE----- -MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs -IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 -MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux -FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h -bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v -dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt -H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 -uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX -mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX -a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN -E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 -WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD -VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 -Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU -cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx -IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN -AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH -YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 -6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC -Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX -c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a -mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +const trustAsiaLeaf = `-----BEGIN CERTIFICATE----- +MIIEwTCCBEegAwIBAgIQBOjomZfHfhgz2bVYZVuf2DAKBggqhkjOPQQDAzBaMQsw +CQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5j +LjEkMCIGA1UEAxMbVHJ1c3RBc2lhIEVDQyBPViBUTFMgUHJvIENBMB4XDTE5MDUx +NzAwMDAwMFoXDTIwMDcyODEyMDAwMFowgY0xCzAJBgNVBAYTAkNOMRIwEAYDVQQI +DAnnpo/lu7rnnIExEjAQBgNVBAcMCeWOpumXqOW4gjEqMCgGA1UECgwh5Y6m6Zeo +5Y+B546W5Y+B56eR5oqA5pyJ6ZmQ5YWs5Y+4MRgwFgYDVQQLDA/nn6Xor4bkuqfm +nYPpg6gxEDAOBgNVBAMMByoudG0uY24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC +AARx/MDQ0oGnCLagQIzjIz57iqFYFmz4/W6gaU6N+GHBkzyvQU8aX02QkdlTTNYL +TCoGFJxHB0XlZVSxrqoIPlNKo4ICuTCCArUwHwYDVR0jBBgwFoAULdRyBx6HyIH/ ++LOvuexyH5p/3PwwHQYDVR0OBBYEFGTyf5adc5smW8NvDZyummJwZRLEMBkGA1Ud +EQQSMBCCByoudG0uY26CBXRtLmNuMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAU +BggrBgEFBQcDAQYIKwYBBQUHAwIwRgYDVR0fBD8wPTA7oDmgN4Y1aHR0cDovL2Ny +bC5kaWdpY2VydC1jbi5jb20vVHJ1c3RBc2lhRUNDT1ZUTFNQcm9DQS5jcmwwTAYD +VR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cu +ZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfgYIKwYBBQUHAQEEcjBwMCcGCCsG +AQUFBzABhhtodHRwOi8vb2NzcC5kaWdpY2VydC1jbi5jb20wRQYIKwYBBQUHMAKG +OWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LWNuLmNvbS9UcnVzdEFzaWFFQ0NPVlRM +U1Byb0NBLmNydDAMBgNVHRMBAf8EAjAAMIIBAwYKKwYBBAHWeQIEAgSB9ASB8QDv +AHUA7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/csAAAFqxGMTnwAABAMA +RjBEAiAz13zKEoyqd4e/96SK/fxfjl7uR+xhfoDZeyA1BvtfOwIgTY+8nJMGekv8 +leIVdW6AGh7oqH31CIGTAbNJJWzaSFYAdgCHdb/nWXz4jEOZX73zbv9WjUdWNv9K +tWDBtOr/XqCDDwAAAWrEYxTCAAAEAwBHMEUCIQDlWm7+limbRiurcqUwXav3NSmx +x/aMnolLbh6+f+b1XAIgQfinHwLw6pDr4R9UkndUsX8QFF4GXS3/IwRR8HCp+pIw +CgYIKoZIzj0EAwMDaAAwZQIwHg8JmjRtcq+OgV0vVmdVBPqehi1sQJ9PZ+51CG+Z +0GOu+2HwS/fyLRViwSc/MZoVAjEA7NgbgpPN4OIsZn2XjMGxemtVxGFS6ZR+1364 +EEeHB9vhZAEjQSePAfjR9aAGhXRa -----END CERTIFICATE-----` const selfSigned = `-----BEGIN CERTIFICATE----- @@ -1852,10 +1825,10 @@ func TestSystemRootsError(t *testing.T) { opts := VerifyOptions{ Intermediates: NewCertPool(), DNSName: "www.google.com", - CurrentTime: time.Unix(1395785200, 0), + CurrentTime: time.Unix(1677615892, 0), } - if ok := opts.Intermediates.AppendCertsFromPEM([]byte(giag2Intermediate)); !ok { + if ok := opts.Intermediates.AppendCertsFromPEM([]byte(gtsIntermediate)); !ok { t.Fatalf("failed to parse intermediate") } @@ -1881,6 +1854,9 @@ func TestSystemRootsErrorUnwrap(t *testing.T) { } func TestIssue51759(t *testing.T) { + if runtime.GOOS != "darwin" { + t.Skip("only affects darwin") + } // badCertData contains a cert that we parse as valid // but that macOS SecCertificateCreateWithData rejects. const badCertData = "0\x82\x01U0\x82\x01\a\xa0\x03\x02\x01\x02\x02\x01\x020\x05\x06\x03+ep0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260\x1e\x17\r220112235755Z\x17\r220313235755Z0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260*0\x05\x06\x03+ep\x03!\x00bA\xd8e\xadW\xcb\xefZ\x89\xb5\"\x1eR\x9d\xba\x0e:\x1042Q@\u007f\xbd\xfb{ks\x04\xd1£\x020\x000\x05\x06\x03+ep\x03A\x00[\xa7\x06y\x86(\x94\x97\x9eLwA\x00\x01x\xaa\xbc\xbd Ê]\n(΅!ف0\xf5\x9a%I\x19<\xffo\xf1\xeaaf@\xb1\xa7\xaf\xfd\xe9R\xc7\x0f\x8d&\xd5\xfc\x0f;Ϙ\x82\x84a\xbc\r" @@ -1891,9 +1867,10 @@ func TestIssue51759(t *testing.T) { t.Run("leaf", func(t *testing.T) { opts := VerifyOptions{} + expectedErr := errors.New("invalid leaf certificate") _, err = badCert.Verify(opts) - if err == nil { - t.Fatal("expected error") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: want %q, got %q", expectedErr, err) } }) @@ -1907,9 +1884,10 @@ func TestIssue51759(t *testing.T) { Intermediates: NewCertPool(), } opts.Intermediates.AddCert(badCert) + expectedErr := errors.New("SecCertificateCreateWithData: invalid certificate") _, err = goodCert.Verify(opts) - if err == nil { - t.Fatal("expected error") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: want %q, got %q", expectedErr, err) } }) } From 9629fa1874f269cdc488081912afb45a7b34da86 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Wed, 1 Mar 2023 08:39:04 -0800 Subject: [PATCH 046/165] [release-branch.go1.20] crypto/x509: fix broken tests Convert TestUnknownAuthorityError to use subtests, avoiding continuing the test after an unrecoverable failure. Skip TestIssue51759 on pre-macOS 11 builders, which don't enforce the behavior we were testing for. Also only enable the test on builders. Updates #58791 Updates #58812 Fixes #58811 Change-Id: I4e3e5bc371aa139d38052184c8232f8cb564138f Reviewed-on: https://go-review.googlesource.com/c/go/+/472496 TryBot-Result: Gopher Robot Run-TryBot: Roland Shoemaker Reviewed-by: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov (cherry picked from commit cf3d0655f8ca2de555549f6e8a91bf8654da7e6c) Reviewed-on: https://go-review.googlesource.com/c/go/+/472618 Auto-Submit: Dmitri Shuralyov --- src/crypto/x509/verify_test.go | 58 ++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go index cd9f6a8788efa2..164c47fd6d5512 100644 --- a/src/crypto/x509/verify_test.go +++ b/src/crypto/x509/verify_test.go @@ -1481,33 +1481,36 @@ ePBQCV1F9sE2q4ZrnsT9TZoNrSe/bMDjzA== -----END CERTIFICATE-----` var unknownAuthorityErrorTests = []struct { + name string cert string expected string }{ - {selfSignedWithCommonName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"test\")"}, - {selfSignedNoCommonNameWithOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"ca\")"}, - {selfSignedNoCommonNameNoOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"serial:0\")"}, + {"self-signed, cn", selfSignedWithCommonName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"test\")"}, + {"self-signed, no cn, org", selfSignedNoCommonNameWithOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"ca\")"}, + {"self-signed, no cn, no org", selfSignedNoCommonNameNoOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"serial:0\")"}, } func TestUnknownAuthorityError(t *testing.T) { for i, tt := range unknownAuthorityErrorTests { - der, _ := pem.Decode([]byte(tt.cert)) - if der == nil { - t.Errorf("#%d: Unable to decode PEM block", i) - } - c, err := ParseCertificate(der.Bytes) - if err != nil { - t.Errorf("#%d: Unable to parse certificate -> %v", i, err) - } - uae := &UnknownAuthorityError{ - Cert: c, - hintErr: fmt.Errorf("empty"), - hintCert: c, - } - actual := uae.Error() - if actual != tt.expected { - t.Errorf("#%d: UnknownAuthorityError.Error() response invalid actual: %s expected: %s", i, actual, tt.expected) - } + t.Run(tt.name, func(t *testing.T) { + der, _ := pem.Decode([]byte(tt.cert)) + if der == nil { + t.Fatalf("#%d: Unable to decode PEM block", i) + } + c, err := ParseCertificate(der.Bytes) + if err != nil { + t.Fatalf("#%d: Unable to parse certificate -> %v", i, err) + } + uae := &UnknownAuthorityError{ + Cert: c, + hintErr: fmt.Errorf("empty"), + hintCert: c, + } + actual := uae.Error() + if actual != tt.expected { + t.Errorf("#%d: UnknownAuthorityError.Error() response invalid actual: %s expected: %s", i, actual, tt.expected) + } + }) } } @@ -1857,6 +1860,13 @@ func TestIssue51759(t *testing.T) { if runtime.GOOS != "darwin" { t.Skip("only affects darwin") } + builder := testenv.Builder() + if builder == "" { + t.Skip("only run this test on the builders, as we have no reasonable way to gate tests on macOS versions elsewhere") + } + if builder == "darwin-amd64-10_14" || builder == "darwin-amd64-10_15" { + t.Skip("behavior only enforced in macOS 11 and after") + } // badCertData contains a cert that we parse as valid // but that macOS SecCertificateCreateWithData rejects. const badCertData = "0\x82\x01U0\x82\x01\a\xa0\x03\x02\x01\x02\x02\x01\x020\x05\x06\x03+ep0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260\x1e\x17\r220112235755Z\x17\r220313235755Z0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260*0\x05\x06\x03+ep\x03!\x00bA\xd8e\xadW\xcb\xefZ\x89\xb5\"\x1eR\x9d\xba\x0e:\x1042Q@\u007f\xbd\xfb{ks\x04\xd1£\x020\x000\x05\x06\x03+ep\x03A\x00[\xa7\x06y\x86(\x94\x97\x9eLwA\x00\x01x\xaa\xbc\xbd Ê]\n(΅!ف0\xf5\x9a%I\x19<\xffo\xf1\xeaaf@\xb1\xa7\xaf\xfd\xe9R\xc7\x0f\x8d&\xd5\xfc\x0f;Ϙ\x82\x84a\xbc\r" @@ -1867,9 +1877,9 @@ func TestIssue51759(t *testing.T) { t.Run("leaf", func(t *testing.T) { opts := VerifyOptions{} - expectedErr := errors.New("invalid leaf certificate") + expectedErr := "invalid leaf certificate" _, err = badCert.Verify(opts) - if err.Error() != expectedErr.Error() { + if err == nil || err.Error() != expectedErr { t.Fatalf("unexpected error: want %q, got %q", expectedErr, err) } }) @@ -1884,9 +1894,9 @@ func TestIssue51759(t *testing.T) { Intermediates: NewCertPool(), } opts.Intermediates.AddCert(badCert) - expectedErr := errors.New("SecCertificateCreateWithData: invalid certificate") + expectedErr := "SecCertificateCreateWithData: invalid certificate" _, err = goodCert.Verify(opts) - if err.Error() != expectedErr.Error() { + if err == nil || err.Error() != expectedErr { t.Fatalf("unexpected error: want %q, got %q", expectedErr, err) } }) From 26eeaec89c1e78696bfa8ad000d4c8275e3bdb75 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 21 Feb 2023 13:16:22 -0800 Subject: [PATCH 047/165] [release-branch.go1.20] cmd/compile: relax overly strict assertion The assertion here was to make sure the newly constructed and typechecked expression selected the same receiver-qualified method, but in the case of anonymous receiver types we can actually end up with separate types.Field instances corresponding to each types.Type instance. In that case, the assertion spuriously failed. The fix here is to relax and assertion and just compare the method's name and type (including receiver type). Fixes #58776. Change-Id: I67d51ddb020e6ed52671473c93fc08f283a40886 Reviewed-on: https://go-review.googlesource.com/c/go/+/471676 Auto-Submit: Matthew Dempsky Run-TryBot: Matthew Dempsky Reviewed-by: Dmitri Shuralyov Reviewed-by: Cuong Manh Le TryBot-Result: Gopher Robot (cherry picked from commit 37a2004b431df6cdd3260cbfe2ddb7673e94b9ef) Reviewed-on: https://go-review.googlesource.com/c/go/+/472620 Auto-Submit: Dmitri Shuralyov TryBot-Bypass: Dmitri Shuralyov --- src/cmd/compile/internal/noder/reader.go | 13 ++++++++++++- test/fixedbugs/issue58563.dir/a.go | 13 +++++++++++++ test/fixedbugs/issue58563.dir/main.go | 16 ++++++++++++++++ test/fixedbugs/issue58563.go | 7 +++++++ 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue58563.dir/a.go create mode 100644 test/fixedbugs/issue58563.dir/main.go create mode 100644 test/fixedbugs/issue58563.go diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 591d09ba783efb..bc2151e178c580 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -2194,7 +2194,18 @@ func (r *reader) expr() (res ir.Node) { } n := typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, recv, wrapperFn.Sel)).(*ir.SelectorExpr) - assert(n.Selection == wrapperFn.Selection) + + // As a consistency check here, we make sure "n" selected the + // same method (represented by a types.Field) that wrapperFn + // selected. However, for anonymous receiver types, there can be + // multiple such types.Field instances (#58563). So we may need + // to fallback to making sure Sym and Type (including the + // receiver parameter's type) match. + if n.Selection != wrapperFn.Selection { + assert(n.Selection.Sym == wrapperFn.Selection.Sym) + assert(types.Identical(n.Selection.Type, wrapperFn.Selection.Type)) + assert(types.Identical(n.Selection.Type.Recv().Type, wrapperFn.Selection.Type.Recv().Type)) + } wrapper := methodValueWrapper{ rcvr: n.X.Type(), diff --git a/test/fixedbugs/issue58563.dir/a.go b/test/fixedbugs/issue58563.dir/a.go new file mode 100644 index 00000000000000..2b716c1b334a05 --- /dev/null +++ b/test/fixedbugs/issue58563.dir/a.go @@ -0,0 +1,13 @@ +// 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 a + +func Start() interface{ Stop() } { + return new(Stopper) +} + +type Stopper struct{} + +func (s *Stopper) Stop() {} diff --git a/test/fixedbugs/issue58563.dir/main.go b/test/fixedbugs/issue58563.dir/main.go new file mode 100644 index 00000000000000..18a90fcf056c0f --- /dev/null +++ b/test/fixedbugs/issue58563.dir/main.go @@ -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. + +package main + +import "test/a" + +func main() { + stop := start() + defer stop() +} + +func start() func() { + return a.Start().Stop +} diff --git a/test/fixedbugs/issue58563.go b/test/fixedbugs/issue58563.go new file mode 100644 index 00000000000000..5c4c5c0a8fb907 --- /dev/null +++ b/test/fixedbugs/issue58563.go @@ -0,0 +1,7 @@ +// compiledir + +// 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 ignored From aee9a19c559da6fd258a8609556d89f6fad2a6d8 Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Tue, 7 Mar 2023 16:26:27 +0000 Subject: [PATCH 048/165] [release-branch.go1.20] go1.20.2 Change-Id: Ib993bfea994a3e885a6068860d2e1f6705f8cf40 Reviewed-on: https://go-review.googlesource.com/c/go/+/474037 Auto-Submit: Gopher Robot Run-TryBot: Gopher Robot Reviewed-by: Carlos Amedee Reviewed-by: Heschi Kreinick TryBot-Result: Gopher Robot --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 866106008f2eba..3acbb8feaf843b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -go1.20.1 \ No newline at end of file +go1.20.2 \ No newline at end of file From 4df95d5145ffea7a7aa6a8e785038f41185ee166 Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Wed, 25 Jan 2023 12:48:54 -0500 Subject: [PATCH 049/165] [release-branch.go1.20] internal/testpty: fix error handling When calling a c library function, you discover that an error has occurred, typically by looking at the return value of the function. Only after that can you use errno to figure out the cause of the error. Nothing about cgo changes that story -- you still have to look at the result before checking the error that represents errno. If not you can get false errors if the function happens to leak a non-zero errno. Fix testpty to check errors correctly. Fixes #58942. Change-Id: Idb95f8dd6a8ed63f653190c2e722e742cf50542b Reviewed-on: https://go-review.googlesource.com/c/go/+/463397 Run-TryBot: Heschi Kreinick Reviewed-by: Michael Pratt Auto-Submit: Heschi Kreinick TryBot-Result: Gopher Robot (cherry picked from commit f85c282a18bbe7197ba645fff58ba5e0065962ca) Reviewed-on: https://go-review.googlesource.com/c/go/+/474616 Reviewed-by: Carlos Amedee --- src/internal/testpty/pty_cgo.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/internal/testpty/pty_cgo.go b/src/internal/testpty/pty_cgo.go index 1db6a925afdc4b..442fbcf6184a43 100644 --- a/src/internal/testpty/pty_cgo.go +++ b/src/internal/testpty/pty_cgo.go @@ -18,14 +18,14 @@ import "os" func open() (pty *os.File, processTTY string, err error) { m, err := C.posix_openpt(C.O_RDWR) - if err != nil { + if m < 0 { return nil, "", ptyError("posix_openpt", err) } - if _, err := C.grantpt(m); err != nil { + if res, err := C.grantpt(m); res < 0 { C.close(m) return nil, "", ptyError("grantpt", err) } - if _, err := C.unlockpt(m); err != nil { + if res, err := C.unlockpt(m); res < 0 { C.close(m) return nil, "", ptyError("unlockpt", err) } From b852f39511db4c8f74a243fa3ce251b0dc8872b3 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Tue, 7 Mar 2023 15:12:29 -0500 Subject: [PATCH 050/165] [release-branch.go1.20] cmd/go: avoid running slow tests on non-longtest builders Also annotate calls to tooSlow with specific reasons. This will somewhat reduce test coverage on the 'darwin' builders until we have darwin 'longtest' builders (#35678,#49055), but still seems worthwhile to avoid alert fatigue from tests that really shouldn't be running in the short configurations. Updates #58918. Updates #58919. Fixes #58938. Change-Id: I0000f0084b262beeec3eca3e9b8a45d61fab4313 Reviewed-on: https://go-review.googlesource.com/c/go/+/474137 Reviewed-by: Ian Lance Taylor Auto-Submit: Bryan Mills Run-TryBot: Bryan Mills TryBot-Result: Gopher Robot (cherry picked from commit 9f532dd0de78af91694a2d7e5e3c45b2978d1062) Reviewed-on: https://go-review.googlesource.com/c/go/+/474580 --- src/cmd/go/go_test.go | 76 +++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index ef22499b87add3..6b6620feeb0947 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -69,14 +69,10 @@ var exeSuffix string = func() string { return "" }() -func tooSlow(t *testing.T) { +func tooSlow(t *testing.T, reason string) { if testing.Short() { - // In -short mode; skip test, except run it on the {darwin,linux,windows}/amd64 builders. - if testenv.Builder() != "" && runtime.GOARCH == "amd64" && (runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows") { - return - } t.Helper() - t.Skip("skipping test in -short mode") + t.Skipf("skipping test in -short mode: %s", reason) } } @@ -1085,7 +1081,7 @@ func TestPackageMainTestCompilerFlags(t *testing.T) { // Issue 4104. func TestGoTestWithPackageListedMultipleTimes(t *testing.T) { - tooSlow(t) + tooSlow(t, "links and runs a test") tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -1096,7 +1092,7 @@ func TestGoTestWithPackageListedMultipleTimes(t *testing.T) { } func TestGoListHasAConsistentOrder(t *testing.T) { - tooSlow(t) + tooSlow(t, "walks all of GOROOT/src twice") tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -1109,7 +1105,7 @@ func TestGoListHasAConsistentOrder(t *testing.T) { } func TestGoListStdDoesNotIncludeCommands(t *testing.T) { - tooSlow(t) + tooSlow(t, "walks all of GOROOT/src") tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -1119,7 +1115,7 @@ func TestGoListStdDoesNotIncludeCommands(t *testing.T) { func TestGoListCmdOnlyShowsCommands(t *testing.T) { skipIfGccgo(t, "gccgo does not have GOROOT") - tooSlow(t) + tooSlow(t, "walks all of GOROOT/src/cmd") tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -1202,7 +1198,8 @@ func TestGoListTest(t *testing.T) { } func TestGoListCompiledCgo(t *testing.T) { - tooSlow(t) + tooSlow(t, "compiles cgo files") + tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -1423,7 +1420,7 @@ func TestDefaultGOPATHPrintedSearchList(t *testing.T) { func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) { skipIfGccgo(t, "gccgo does not support -ldflags -X") - tooSlow(t) + tooSlow(t, "compiles and links a binary") tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -1440,7 +1437,7 @@ func TestLdFlagsLongArgumentsIssue42295(t *testing.T) { // Test the extremely long command line arguments that contain '\n' characters // get encoded and passed correctly. skipIfGccgo(t, "gccgo does not support -ldflags -X") - tooSlow(t) + tooSlow(t, "compiles and links a binary") tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -1462,7 +1459,7 @@ func TestLdFlagsLongArgumentsIssue42295(t *testing.T) { func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) { skipIfGccgo(t, "gccgo has no standard packages") - tooSlow(t) + tooSlow(t, "compiles and links a test binary") tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -1473,7 +1470,7 @@ func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) { func TestGoTestDashOWritesBinary(t *testing.T) { skipIfGccgo(t, "gccgo has no standard packages") - tooSlow(t) + tooSlow(t, "compiles and runs a test binary") tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -1484,7 +1481,7 @@ func TestGoTestDashOWritesBinary(t *testing.T) { // Issue 4515. func TestInstallWithTags(t *testing.T) { - tooSlow(t) + tooSlow(t, "compiles and links binaries") tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -1553,7 +1550,7 @@ func TestCgoShowsFullPathNames(t *testing.T) { } func TestCgoHandlesWlORIGIN(t *testing.T) { - tooSlow(t) + tooSlow(t, "compiles cgo files") if !canCgo { t.Skip("skipping because cgo not enabled") } @@ -1571,7 +1568,7 @@ func TestCgoHandlesWlORIGIN(t *testing.T) { } func TestCgoPkgConfig(t *testing.T) { - tooSlow(t) + tooSlow(t, "compiles cgo files") if !canCgo { t.Skip("skipping because cgo not enabled") } @@ -1656,7 +1653,7 @@ func TestListTemplateContextFunction(t *testing.T) { // accessed by a non-local import (found in a GOPATH/GOROOT). // See golang.org/issue/17475. func TestImportLocal(t *testing.T) { - tooSlow(t) + tooSlow(t, "builds a lot of sequential packages") tg := testgo(t) tg.parallel() @@ -1814,7 +1811,7 @@ func TestGoInstallPkgdir(t *testing.T) { // for the install. t.Skip("skipping because cgo not enabled") } - tooSlow(t) + tooSlow(t, "builds a package with cgo dependencies") tg := testgo(t) tg.parallel() @@ -1829,7 +1826,7 @@ func TestGoInstallPkgdir(t *testing.T) { // For issue 14337. func TestParallelTest(t *testing.T) { - tooSlow(t) + tooSlow(t, "links and runs test binaries") tg := testgo(t) tg.parallel() defer tg.cleanup() @@ -1849,7 +1846,7 @@ func TestParallelTest(t *testing.T) { } func TestBinaryOnlyPackages(t *testing.T) { - tooSlow(t) + tooSlow(t, "compiles several packages sequentially") tg := testgo(t) defer tg.cleanup() @@ -2051,7 +2048,7 @@ func TestFFLAGS(t *testing.T) { // This is really a cmd/link issue but this is a convenient place to test it. func TestDuplicateGlobalAsmSymbols(t *testing.T) { skipIfGccgo(t, "gccgo does not use cmd/asm") - tooSlow(t) + tooSlow(t, "links a binary with cgo dependencies") if runtime.GOARCH != "386" && runtime.GOARCH != "amd64" { t.Skipf("skipping test on %s", runtime.GOARCH) } @@ -2350,10 +2347,11 @@ func TestUpxCompression(t *testing.T) { var gocacheverify = godebug.New("gocacheverify") func TestCacheListStale(t *testing.T) { - tooSlow(t) + tooSlow(t, "links a binary") if gocacheverify.Value() == "1" { t.Skip("GODEBUG gocacheverify") } + tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -2372,8 +2370,7 @@ func TestCacheListStale(t *testing.T) { } func TestCacheCoverage(t *testing.T) { - tooSlow(t) - + tooSlow(t, "links and runs a test binary with coverage enabled") if gocacheverify.Value() == "1" { t.Skip("GODEBUG gocacheverify") } @@ -2407,10 +2404,11 @@ func TestIssue22588(t *testing.T) { } func TestIssue22531(t *testing.T) { - tooSlow(t) + tooSlow(t, "links binaries") if gocacheverify.Value() == "1" { t.Skip("GODEBUG gocacheverify") } + tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -2436,10 +2434,11 @@ func TestIssue22531(t *testing.T) { } func TestIssue22596(t *testing.T) { - tooSlow(t) + tooSlow(t, "links binaries") if gocacheverify.Value() == "1" { t.Skip("GODEBUG gocacheverify") } + tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -2465,7 +2464,7 @@ func TestIssue22596(t *testing.T) { } func TestTestCache(t *testing.T) { - tooSlow(t) + tooSlow(t, "links and runs test binaries") if gocacheverify.Value() == "1" { t.Skip("GODEBUG gocacheverify") @@ -2572,7 +2571,8 @@ func TestTestSkipVetAfterFailedBuild(t *testing.T) { } func TestTestVetRebuild(t *testing.T) { - tooSlow(t) + tooSlow(t, "links and runs test binaries") + tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -2612,7 +2612,8 @@ func TestTestVetRebuild(t *testing.T) { } func TestInstallDeps(t *testing.T) { - tooSlow(t) + tooSlow(t, "links a binary") + tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -2643,7 +2644,8 @@ func TestInstallDeps(t *testing.T) { // Issue 22986. func TestImportPath(t *testing.T) { - tooSlow(t) + tooSlow(t, "links and runs a test binary") + tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -2744,7 +2746,8 @@ func TestTwoPkgConfigs(t *testing.T) { if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { t.Skipf("no shell scripts on %s", runtime.GOOS) } - tooSlow(t) + tooSlow(t, "builds a package with cgo dependencies") + tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -2775,7 +2778,7 @@ func TestCgoCache(t *testing.T) { if !canCgo { t.Skip("no cgo") } - tooSlow(t) + tooSlow(t, "builds a package with cgo dependencies") tg := testgo(t) defer tg.cleanup() @@ -2828,7 +2831,7 @@ func TestLinkerTmpDirIsDeleted(t *testing.T) { if !canCgo { t.Skip("skipping because cgo not enabled") } - tooSlow(t) + tooSlow(t, "builds a package with cgo dependencies") tg := testgo(t) defer tg.cleanup() @@ -2875,7 +2878,8 @@ func TestLinkerTmpDirIsDeleted(t *testing.T) { // Issue 25093. func TestCoverpkgTestOnly(t *testing.T) { skipIfGccgo(t, "gccgo has no cover tool") - tooSlow(t) + tooSlow(t, "links and runs a test binary with coverage enabled") + tg := testgo(t) defer tg.cleanup() tg.parallel() From 5c7cc468a8dacc032c4eddea6d5e7fc089d2f517 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 7 Mar 2023 18:23:40 +0000 Subject: [PATCH 051/165] [release-branch.go1.20] Revert "cmd/compile: enable address folding for global symbols of shared library" This reverts CL 445535. Reason for revert: see issue #58826. It doesn't handle large offset well. Updates #58826. Fixes #58920. Change-Id: Ic4a33f4c510c88628ea7e16207a60977a04cf798 Reviewed-on: https://go-review.googlesource.com/c/go/+/474175 Reviewed-by: Heschi Kreinick TryBot-Result: Gopher Robot Run-TryBot: Cherry Mui Reviewed-by: Keith Randall (cherry picked from commit a4cf4fde466035e6a485c29bd12450d51bc7d4e1) Reviewed-on: https://go-review.googlesource.com/c/go/+/474235 Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/_gen/ARM64.rules | 132 +++++++---- src/cmd/compile/internal/ssa/rewriteARM64.go | 209 ++++++++++-------- 2 files changed, 209 insertions(+), 132 deletions(-) diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64.rules b/src/cmd/compile/internal/ssa/_gen/ARM64.rules index 0c5a2e66a8ca75..8405248fe55a2c 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/_gen/ARM64.rules @@ -837,25 +837,35 @@ (MOVDaddr [int32(off1)+off2] {sym} ptr) // fold address into load/store -(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVBload [off1+int32(off2)] {sym} ptr mem) -(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVBUload [off1+int32(off2)] {sym} ptr mem) -(MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVHload [off1+int32(off2)] {sym} ptr mem) -(MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVHUload [off1+int32(off2)] {sym} ptr mem) -(MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVWload [off1+int32(off2)] {sym} ptr mem) -(MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVWUload [off1+int32(off2)] {sym} ptr mem) -(MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVDload [off1+int32(off2)] {sym} ptr mem) -(LDP [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(LDP [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (LDP [off1+int32(off2)] {sym} ptr mem) -(FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (FMOVSload [off1+int32(off2)] {sym} ptr mem) -(FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (FMOVDload [off1+int32(off2)] {sym} ptr mem) // register indexed load @@ -920,29 +930,41 @@ (FMOVDloadidx8 ptr (MOVDconst [c]) mem) && is32Bit(c<<3) => (FMOVDload ptr [int32(c)<<3] mem) (FMOVSloadidx4 ptr (MOVDconst [c]) mem) && is32Bit(c<<2) => (FMOVSload ptr [int32(c)<<2] mem) -(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) => +(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVBstore [off1+int32(off2)] {sym} ptr val mem) -(MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) => +(MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVHstore [off1+int32(off2)] {sym} ptr val mem) -(MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) => +(MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVWstore [off1+int32(off2)] {sym} ptr val mem) -(MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) => +(MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVDstore [off1+int32(off2)] {sym} ptr val mem) -(STP [off1] {sym} (ADDconst [off2] ptr) val1 val2 mem) && is32Bit(int64(off1)+off2) => +(STP [off1] {sym} (ADDconst [off2] ptr) val1 val2 mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (STP [off1+int32(off2)] {sym} ptr val1 val2 mem) -(FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) => +(FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (FMOVSstore [off1+int32(off2)] {sym} ptr val mem) -(FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) => +(FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (FMOVDstore [off1+int32(off2)] {sym} ptr val mem) -(MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVBstorezero [off1+int32(off2)] {sym} ptr mem) -(MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVHstorezero [off1+int32(off2)] {sym} ptr mem) -(MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVWstorezero [off1+int32(off2)] {sym} ptr mem) -(MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVDstorezero [off1+int32(off2)] {sym} ptr mem) -(MOVQstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) => +(MOVQstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(int64(off1)+off2) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVQstorezero [off1+int32(off2)] {sym} ptr mem) // register indexed store @@ -991,71 +1013,93 @@ (FMOVSstoreidx4 ptr (MOVDconst [c]) val mem) && is32Bit(c<<2) => (FMOVSstore [int32(c)<<2] ptr val mem) (MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (LDP [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (LDP [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (STP [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val1 val2 mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (STP [off1+off2] {mergeSym(sym1,sym2)} ptr val1 val2 mem) (FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVQstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => + && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVQstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) // store zero diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index e82a49c33193e7..12b3bbd572f170 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -4533,6 +4533,8 @@ func rewriteValueARM64_OpARM64FMOVDgpfp(v *Value) bool { func rewriteValueARM64_OpARM64FMOVDload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (FMOVDload [off] {sym} ptr (MOVDstore [off] {sym} ptr val _)) // result: (FMOVDgpfp val) for { @@ -4551,7 +4553,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value) bool { return true } // match: (FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVDload [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -4562,7 +4564,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64FMOVDload) @@ -4610,7 +4612,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value) bool { return true } // match: (FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -4622,7 +4624,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64FMOVDload) @@ -4729,6 +4731,8 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (FMOVDstore [off] {sym} ptr (FMOVDgpfp val) mem) // result: (MOVDstore [off] {sym} ptr val mem) for { @@ -4747,7 +4751,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value) bool { return true } // match: (FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVDstore [off1+int32(off2)] {sym} ptr val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -4759,7 +4763,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value) bool { ptr := v_0.Args[0] val := v_1 mem := v_2 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64FMOVDstore) @@ -4809,7 +4813,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value) bool { return true } // match: (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -4822,7 +4826,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value) bool { ptr := v_0.Args[0] val := v_1 mem := v_2 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64FMOVDstore) @@ -4935,6 +4939,8 @@ func rewriteValueARM64_OpARM64FMOVDstoreidx8(v *Value) bool { func rewriteValueARM64_OpARM64FMOVSload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (FMOVSload [off] {sym} ptr (MOVWstore [off] {sym} ptr val _)) // result: (FMOVSgpfp val) for { @@ -4953,7 +4959,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value) bool { return true } // match: (FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVSload [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -4964,7 +4970,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64FMOVSload) @@ -5012,7 +5018,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value) bool { return true } // match: (FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -5024,7 +5030,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64FMOVSload) @@ -5131,6 +5137,8 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (FMOVSstore [off] {sym} ptr (FMOVSgpfp val) mem) // result: (MOVWstore [off] {sym} ptr val mem) for { @@ -5149,7 +5157,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value) bool { return true } // match: (FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVSstore [off1+int32(off2)] {sym} ptr val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -5161,7 +5169,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value) bool { ptr := v_0.Args[0] val := v_1 mem := v_2 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64FMOVSstore) @@ -5211,7 +5219,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value) bool { return true } // match: (FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -5224,7 +5232,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value) bool { ptr := v_0.Args[0] val := v_1 mem := v_2 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64FMOVSstore) @@ -5935,8 +5943,10 @@ func rewriteValueARM64_OpARM64GreaterThanU(v *Value) bool { func rewriteValueARM64_OpARM64LDP(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (LDP [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (LDP [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -5947,7 +5957,7 @@ func rewriteValueARM64_OpARM64LDP(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64LDP) @@ -5957,7 +5967,7 @@ func rewriteValueARM64_OpARM64LDP(v *Value) bool { return true } // match: (LDP [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (LDP [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -5969,7 +5979,7 @@ func rewriteValueARM64_OpARM64LDP(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64LDP) @@ -7636,8 +7646,10 @@ func rewriteValueARM64_OpARM64MODW(v *Value) bool { func rewriteValueARM64_OpARM64MOVBUload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVBUload [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -7648,7 +7660,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVBUload) @@ -7677,7 +7689,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value) bool { return true } // match: (MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -7689,7 +7701,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVBUload) @@ -8077,8 +8089,10 @@ func rewriteValueARM64_OpARM64MOVBUreg(v *Value) bool { func rewriteValueARM64_OpARM64MOVBload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVBload [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -8089,7 +8103,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVBload) @@ -8118,7 +8132,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value) bool { return true } // match: (MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -8130,7 +8144,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVBload) @@ -8308,8 +8322,9 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] b := v.Block + config := b.Func.Config // match: (MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVBstore [off1+int32(off2)] {sym} ptr val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -8321,7 +8336,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { ptr := v_0.Args[0] val := v_1 mem := v_2 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVBstore) @@ -8351,7 +8366,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { return true } // match: (MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -8364,7 +8379,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { ptr := v_0.Args[0] val := v_1 mem := v_2 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVBstore) @@ -10159,8 +10174,10 @@ func rewriteValueARM64_OpARM64MOVBstoreidx(v *Value) bool { func rewriteValueARM64_OpARM64MOVBstorezero(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVBstorezero [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -10171,7 +10188,7 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVBstorezero) @@ -10181,7 +10198,7 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value) bool { return true } // match: (MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -10193,7 +10210,7 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVBstorezero) @@ -10368,7 +10385,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value) bool { return true } // match: (MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVDload [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -10379,7 +10396,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVDload) @@ -10427,7 +10444,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value) bool { return true } // match: (MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -10439,7 +10456,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVDload) @@ -10657,6 +10674,8 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVDstore [off] {sym} ptr (FMOVDfpgp val) mem) // result: (FMOVDstore [off] {sym} ptr val mem) for { @@ -10675,7 +10694,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value) bool { return true } // match: (MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVDstore [off1+int32(off2)] {sym} ptr val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -10687,7 +10706,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value) bool { ptr := v_0.Args[0] val := v_1 mem := v_2 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVDstore) @@ -10737,7 +10756,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value) bool { return true } // match: (MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -10750,7 +10769,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value) bool { ptr := v_0.Args[0] val := v_1 mem := v_2 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVDstore) @@ -10905,8 +10924,10 @@ func rewriteValueARM64_OpARM64MOVDstoreidx8(v *Value) bool { func rewriteValueARM64_OpARM64MOVDstorezero(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVDstorezero [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -10917,7 +10938,7 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVDstorezero) @@ -10927,7 +10948,7 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value) bool { return true } // match: (MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -10939,7 +10960,7 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVDstorezero) @@ -11178,7 +11199,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value) bool { b := v.Block config := b.Func.Config // match: (MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVHUload [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -11189,7 +11210,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVHUload) @@ -11237,7 +11258,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value) bool { return true } // match: (MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -11249,7 +11270,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVHUload) @@ -11614,8 +11635,10 @@ func rewriteValueARM64_OpARM64MOVHUreg(v *Value) bool { func rewriteValueARM64_OpARM64MOVHload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVHload [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -11626,7 +11649,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVHload) @@ -11674,7 +11697,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value) bool { return true } // match: (MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -11686,7 +11709,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVHload) @@ -12028,8 +12051,9 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] b := v.Block + config := b.Func.Config // match: (MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVHstore [off1+int32(off2)] {sym} ptr val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -12041,7 +12065,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value) bool { ptr := v_0.Args[0] val := v_1 mem := v_2 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVHstore) @@ -12091,7 +12115,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value) bool { return true } // match: (MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -12104,7 +12128,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value) bool { ptr := v_0.Args[0] val := v_1 mem := v_2 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVHstore) @@ -12905,8 +12929,9 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] b := v.Block + config := b.Func.Config // match: (MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVHstorezero [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -12917,7 +12942,7 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVHstorezero) @@ -12927,7 +12952,7 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value) bool { return true } // match: (MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -12939,7 +12964,7 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVHstorezero) @@ -13225,8 +13250,10 @@ func rewriteValueARM64_OpARM64MOVHstorezeroidx2(v *Value) bool { func rewriteValueARM64_OpARM64MOVQstorezero(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVQstorezero [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVQstorezero [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -13237,7 +13264,7 @@ func rewriteValueARM64_OpARM64MOVQstorezero(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVQstorezero) @@ -13247,7 +13274,7 @@ func rewriteValueARM64_OpARM64MOVQstorezero(v *Value) bool { return true } // match: (MOVQstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVQstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -13259,7 +13286,7 @@ func rewriteValueARM64_OpARM64MOVQstorezero(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVQstorezero) @@ -13293,7 +13320,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value) bool { return true } // match: (MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVWUload [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -13304,7 +13331,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVWUload) @@ -13352,7 +13379,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value) bool { return true } // match: (MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -13364,7 +13391,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVWUload) @@ -13754,8 +13781,10 @@ func rewriteValueARM64_OpARM64MOVWUreg(v *Value) bool { func rewriteValueARM64_OpARM64MOVWload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVWload [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -13766,7 +13795,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVWload) @@ -13814,7 +13843,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value) bool { return true } // match: (MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -13826,7 +13855,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVWload) @@ -14226,6 +14255,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] b := v.Block + config := b.Func.Config // match: (MOVWstore [off] {sym} ptr (FMOVSfpgp val) mem) // result: (FMOVSstore [off] {sym} ptr val mem) for { @@ -14244,7 +14274,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value) bool { return true } // match: (MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVWstore [off1+int32(off2)] {sym} ptr val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -14256,7 +14286,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value) bool { ptr := v_0.Args[0] val := v_1 mem := v_2 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVWstore) @@ -14306,7 +14336,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value) bool { return true } // match: (MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -14319,7 +14349,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value) bool { ptr := v_0.Args[0] val := v_1 mem := v_2 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVWstore) @@ -14790,8 +14820,9 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] b := v.Block + config := b.Func.Config // match: (MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVWstorezero [off1+int32(off2)] {sym} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -14802,7 +14833,7 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVWstorezero) @@ -14812,7 +14843,7 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value) bool { return true } // match: (MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -14824,7 +14855,7 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value) bool { sym2 := auxToSym(v_0.Aux) ptr := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64MOVWstorezero) @@ -21686,8 +21717,10 @@ func rewriteValueARM64_OpARM64STP(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (STP [off1] {sym} (ADDconst [off2] ptr) val1 val2 mem) - // cond: is32Bit(int64(off1)+off2) + // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (STP [off1+int32(off2)] {sym} ptr val1 val2 mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -21700,7 +21733,7 @@ func rewriteValueARM64_OpARM64STP(v *Value) bool { val1 := v_1 val2 := v_2 mem := v_3 - if !(is32Bit(int64(off1) + off2)) { + if !(is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64STP) @@ -21710,7 +21743,7 @@ func rewriteValueARM64_OpARM64STP(v *Value) bool { return true } // match: (STP [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val1 val2 mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (STP [off1+off2] {mergeSym(sym1,sym2)} ptr val1 val2 mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -21724,7 +21757,7 @@ func rewriteValueARM64_OpARM64STP(v *Value) bool { val1 := v_1 val2 := v_2 mem := v_3 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) { break } v.reset(OpARM64STP) From fa42da156a166ecf81ab7d72f53619ad9e6f134a Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 8 Mar 2023 16:38:32 -0500 Subject: [PATCH 052/165] [release-branch.go1.20] cmd/link: use label symbols for Duff's devices on darwin/arm64 On darwin, the external linker generally supports CALL relocations with addend. One exception is that for a very large binary when it decides to insert a trampoline, instead of applying the addend to the call target (in the trampoline), it applies the addend to the CALL instruction in the caller, i.e. generating a call to trampoline+addend, which is not the correct address and usually points to unreloated functions. To work around this, we use label symbols so the CALL is targeting a label symbol without addend. To make things simple we always use label symbols for CALLs with addend (in external linking mode on darwin/arm64), even for small binaries. Updates #58935. Fixes #58954. Change-Id: I38aed6b62a0496c277c589b5accbbef6aace8dd5 Reviewed-on: https://go-review.googlesource.com/c/go/+/474620 TryBot-Result: Gopher Robot Run-TryBot: Cherry Mui Reviewed-by: Than McIntosh (cherry picked from commit 7dbd6de7d45da622e532e149de616e159286e1d4) Reviewed-on: https://go-review.googlesource.com/c/go/+/475175 --- src/cmd/link/internal/arm64/asm.go | 66 ++++++++++++++++-------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index fc0ad3fb4e4d24..7109d84fa32b81 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -537,6 +537,13 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy ldr.Errorf(s, "internal error: relocation addend overflow: %s+0x%x", ldr.SymName(rs), xadd) } } + if rt == objabi.R_CALLARM64 && xadd != 0 { + label := ldr.Lookup(offsetLabelName(ldr, rs, xadd), ldr.SymVersion(rs)) + if label != 0 { + xadd = ldr.SymValue(rs) + xadd - ldr.SymValue(label) // should always be 0 (checked below) + rs = label + } + } if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 || rt == objabi.R_ARM64_PCREL_LDST8 || rt == objabi.R_ARM64_PCREL_LDST16 || @@ -564,10 +571,9 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28 case objabi.R_CALLARM64: if xadd != 0 { - out.Write32(uint32(sectoff)) - out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff)) + // Addend should be handled above via label symbols. + ldr.Errorf(s, "unexpected non-zero addend: %s+%d", ldr.SymName(rs), xadd) } - v |= 1 << 24 // pc-relative bit v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28 case objabi.R_ADDRARM64, @@ -788,9 +794,6 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade case objabi.R_CALLARM64: nExtReloc = 1 - if target.IsDarwin() && r.Add() != 0 { - nExtReloc = 2 // need another relocation for addend - } return val, nExtReloc, isOk case objabi.R_ARM64_TLS_LE: @@ -1184,6 +1187,9 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) { // addend. For large symbols, we generate "label" symbols in the middle, so // that relocations can target them with smaller addends. // On Windows, we only get 21 bits, again (presumably) signed. + // Also, on Windows (always) and Darwin (for very large binaries), the external + // linker does't support CALL relocations with addend, so we generate "label" + // symbols for functions of which we can target the middle (Duff's devices). if !ctxt.IsDarwin() && !ctxt.IsWindows() || !ctxt.IsExternal() { return } @@ -1193,19 +1199,6 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) { limit = peRelocLimit } - if ctxt.IsDarwin() { - big := false - for _, seg := range ld.Segments { - if seg.Length >= machoRelocLimit { - big = true - break - } - } - if !big { - return // skip work if nothing big - } - } - // addLabelSyms adds "label" symbols at s+limit, s+2*limit, etc. addLabelSyms := func(s loader.Sym, limit, sz int64) { v := ldr.SymValue(s) @@ -1225,23 +1218,36 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) { } } + // Generate symbol names for every offset we need in duffcopy/duffzero (only 64 each). + if s := ldr.Lookup("runtime.duffcopy", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) { + addLabelSyms(s, 8, 8*64) + } + if s := ldr.Lookup("runtime.duffzero", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) { + addLabelSyms(s, 4, 4*64) + } + + if ctxt.IsDarwin() { + big := false + for _, seg := range ld.Segments { + if seg.Length >= machoRelocLimit { + big = true + break + } + } + if !big { + return // skip work if nothing big + } + } + for s, n := loader.Sym(1), loader.Sym(ldr.NSym()); s < n; s++ { if !ldr.AttrReachable(s) { continue } t := ldr.SymType(s) if t == sym.STEXT { - if ctxt.IsDarwin() || ctxt.IsWindows() { - // Cannot relocate into middle of function. - // Generate symbol names for every offset we need in duffcopy/duffzero (only 64 each). - switch ldr.SymName(s) { - case "runtime.duffcopy": - addLabelSyms(s, 8, 8*64) - case "runtime.duffzero": - addLabelSyms(s, 4, 4*64) - } - } - continue // we don't target the middle of other functions + // Except for Duff's devices (handled above), we don't + // target the middle of a function. + continue } if t >= sym.SDWARFSECT { continue // no need to add label for DWARF symbols From 3ff6dbdf5b65e4c9da1a2020e45a56a7ae48cc91 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Fri, 10 Mar 2023 10:29:38 -0500 Subject: [PATCH 053/165] [release-branch.go1.20] cmd/go,cmd/link: prefer external linking when strange cgo flags seen This patch changes the Go command to examine the set of compiler flags feeding into the C compiler when packages that use cgo are built. If any of a specific set of strange/dangerous flags are in use, then the Go command generates a token file ("preferlinkext") and embeds it into the compiled package's archive. When the Go linker reads the archives of the packages feeding into the link and detects a "preferlinkext" token, it will then use external linking for the program by default (although this default can be overridden with an explicit "-linkmode" flag). The intent here is to avoid having to teach the Go linker's host object reader to grok/understand the various odd symbols/sections/types that can result from boutique flag use, but rather to just boot the objects in question over to the C linker instead. Fixes #59051. Updates #58619. Updates #58620. Updates #58848. Change-Id: I56382dd305de8dac3841a7a7e664277826061eaa Reviewed-on: https://go-review.googlesource.com/c/go/+/475375 Reviewed-by: Cherry Mui Reviewed-by: Bryan Mills Run-TryBot: Than McIntosh TryBot-Result: Gopher Robot (cherry picked from commit 035db07d7c5f1b90ebc9bae03cab694685acebb8) Reviewed-on: https://go-review.googlesource.com/c/go/+/476577 --- src/cmd/go/internal/work/exec.go | 48 ++++++ src/cmd/go/internal/work/security.go | 51 ++++-- src/cmd/go/internal/work/security_test.go | 33 ++++ src/cmd/go/scriptconds_test.go | 1 + src/cmd/go/testdata/script/README | 2 + .../cgo_suspect_flag_force_external.txt | 155 ++++++++++++++++++ src/cmd/link/internal/ld/config.go | 6 +- src/cmd/link/internal/ld/lib.go | 13 ++ src/internal/platform/supported.go | 37 +++++ 9 files changed, 331 insertions(+), 15 deletions(-) create mode 100644 src/cmd/go/testdata/script/cgo_suspect_flag_force_external.txt diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index d6fa847be043a8..02a59e48e9a77a 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -3027,6 +3027,36 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo } } + // Scrutinize CFLAGS and related for flags that might cause + // problems if we are using internal linking (for example, use of + // plugins, LTO, etc) by calling a helper routine that builds on + // the existing CGO flags allow-lists. If we see anything + // suspicious, emit a special token file "preferlinkext" (known to + // the linker) in the object file to signal the that it should not + // try to link internally and should revert to external linking. + // The token we pass is a suggestion, not a mandate; if a user is + // explicitly asking for a specific linkmode via the "-linkmode" + // flag, the token will be ignored. NB: in theory we could ditch + // the token approach and just pass a flag to the linker when we + // eventually invoke it, and the linker flag could then be + // documented (although coming up with a simple explanation of the + // flag might be challenging). For more context see issues #58619, + // #58620, and #58848. + flagSources := []string{"CGO_CFLAGS", "CGO_CXXFLAGS", "CGO_FFLAGS"} + flagLists := [][]string{cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS} + if flagsNotCompatibleWithInternalLinking(flagSources, flagLists) { + tokenFile := objdir + "preferlinkext" + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "echo > %s", tokenFile) + } + if !cfg.BuildN { + if err := os.WriteFile(tokenFile, nil, 0666); err != nil { + return nil, nil, err + } + } + outObj = append(outObj, tokenFile) + } + if cfg.BuildMSan { cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...) cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...) @@ -3276,6 +3306,24 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo return outGo, outObj, nil } +// flagsNotCompatibleWithInternalLinking scans the list of cgo +// compiler flags (C/C++/Fortran) looking for flags that might cause +// problems if the build in question uses internal linking. The +// primary culprits are use of plugins or use of LTO, but we err on +// the side of caution, supporting only those flags that are on the +// allow-list for safe flags from security perspective. Return is TRUE +// if a sensitive flag is found, FALSE otherwise. +func flagsNotCompatibleWithInternalLinking(sourceList []string, flagListList [][]string) bool { + for i := range sourceList { + sn := sourceList[i] + fll := flagListList[i] + if err := checkCompilerFlagsForInternalLink(sn, sn, fll); err != nil { + return true + } + } + return false +} + // dynimport creates a Go source file named importGo containing // //go:cgo_import_dynamic directives for each symbol or library // dynamically imported by the object files outObj. diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go index 0bf8763543b14e..f4f1880c846aec 100644 --- a/src/cmd/go/internal/work/security.go +++ b/src/cmd/go/internal/work/security.go @@ -230,32 +230,55 @@ var validLinkerFlagsWithNextArg = []string{ } func checkCompilerFlags(name, source string, list []string) error { - return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg) + checkOverrides := true + return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides) } func checkLinkerFlags(name, source string, list []string) error { - return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg) + checkOverrides := true + return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides) } -func checkFlags(name, source string, list []string, valid []*lazyregexp.Regexp, validNext []string) error { +// checkCompilerFlagsForInternalLink returns an error if 'list' +// contains a flag or flags that may not be fully supported by +// internal linking (meaning that we should punt the link to the +// external linker). +func checkCompilerFlagsForInternalLink(name, source string, list []string) error { + checkOverrides := false + if err := checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides); err != nil { + return err + } + // Currently the only flag on the allow list that causes problems + // for the linker is "-flto"; check for it manually here. + for _, fl := range list { + if strings.HasPrefix(fl, "-flto") { + return fmt.Errorf("flag %q triggers external linking", fl) + } + } + return nil +} + +func checkFlags(name, source string, list []string, valid []*lazyregexp.Regexp, validNext []string, checkOverrides bool) error { // Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc. var ( allow *regexp.Regexp disallow *regexp.Regexp ) - if env := cfg.Getenv("CGO_" + name + "_ALLOW"); env != "" { - r, err := regexp.Compile(env) - if err != nil { - return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err) + if checkOverrides { + if env := cfg.Getenv("CGO_" + name + "_ALLOW"); env != "" { + r, err := regexp.Compile(env) + if err != nil { + return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err) + } + allow = r } - allow = r - } - if env := cfg.Getenv("CGO_" + name + "_DISALLOW"); env != "" { - r, err := regexp.Compile(env) - if err != nil { - return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err) + if env := cfg.Getenv("CGO_" + name + "_DISALLOW"); env != "" { + r, err := regexp.Compile(env) + if err != nil { + return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err) + } + disallow = r } - disallow = r } Args: diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go index d2aeb54e0cea14..8cecc74eae3cce 100644 --- a/src/cmd/go/internal/work/security_test.go +++ b/src/cmd/go/internal/work/security_test.go @@ -6,6 +6,7 @@ package work import ( "os" + "strings" "testing" ) @@ -28,6 +29,7 @@ var goodCompilerFlags = [][]string{ {"-Wp,-Ufoo"}, {"-Wp,-Dfoo1"}, {"-Wp,-Ufoo1"}, + {"-flto"}, {"-fobjc-arc"}, {"-fno-objc-arc"}, {"-fomit-frame-pointer"}, @@ -278,3 +280,34 @@ func TestCheckFlagAllowDisallow(t *testing.T) { t.Fatalf("missing error for -fplugin=lint.so: %v", err) } } + +func TestCheckCompilerFlagsForInternalLink(t *testing.T) { + // Any "bad" compiler flag should trigger external linking. + for _, f := range badCompilerFlags { + if err := checkCompilerFlagsForInternalLink("test", "test", f); err == nil { + t.Errorf("missing error for %q", f) + } + } + + // All "good" compiler flags should not trigger external linking, + // except for anything that begins with "-flto". + for _, f := range goodCompilerFlags { + foundLTO := false + for _, s := range f { + if strings.Contains(s, "-flto") { + foundLTO = true + } + } + if err := checkCompilerFlagsForInternalLink("test", "test", f); err != nil { + // expect error for -flto + if !foundLTO { + t.Errorf("unexpected error for %q: %v", f, err) + } + } else { + // expect no error for everything else + if foundLTO { + t.Errorf("missing error for %q: %v", f, err) + } + } + } +} diff --git a/src/cmd/go/scriptconds_test.go b/src/cmd/go/scriptconds_test.go index 516375021a28fd..e7bd9433c125d3 100644 --- a/src/cmd/go/scriptconds_test.go +++ b/src/cmd/go/scriptconds_test.go @@ -49,6 +49,7 @@ func scriptConditions() map[string]script.Cond { add("link", lazyBool("testenv.HasLink()", testenv.HasLink)) add("mismatched-goroot", script.Condition("test's GOROOT_FINAL does not match the real GOROOT", isMismatchedGoroot)) add("msan", sysCondition("-msan", platform.MSanSupported, true)) + add("cgolinkext", script.BoolCondition("platform requires external linking for cgo", platform.MustLinkExternalGo121(cfg.Goos, cfg.Goarch, true))) add("net", lazyBool("testenv.HasExternalNetwork()", testenv.HasExternalNetwork)) add("race", sysCondition("-race", platform.RaceDetectorSupported, true)) add("symlink", lazyBool("testenv.HasSymlink()", testenv.HasSymlink)) diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README index 7b747994c62ade..349ba972fb692d 100644 --- a/src/cmd/go/testdata/script/README +++ b/src/cmd/go/testdata/script/README @@ -382,6 +382,8 @@ The available conditions are: $WORK filesystem is case-sensitive [cgo] host CGO_ENABLED +[cgolinkext] + platform requires external linking for cgo [compiler:*] runtime.Compiler == [cross] diff --git a/src/cmd/go/testdata/script/cgo_suspect_flag_force_external.txt b/src/cmd/go/testdata/script/cgo_suspect_flag_force_external.txt new file mode 100644 index 00000000000000..fbe8236f9da4e9 --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_suspect_flag_force_external.txt @@ -0,0 +1,155 @@ +# Test case to verify that when we have a package that uses CGO in +# combination with selected "unusual" flags (involving plugins, LTO) +# that we force external linking. See related +# issues 58619, 58620, and 58848. + +[compiler:gccgo] skip # only external linking for gccgo + +# This test requires external linking, so use cgo as a proxy +[!cgo] skip + +# Here we build three program: one with explicit CGO use, one with no +# CGO use, and one that uses a stdlib package ("runtime/cgo") that has +# CGO in it. It used to be that only the explicit use of CGO would +# trigger external linking, and that the program that only used +# "runtime/cgo" would always be handled with internal linking. This caused +# issues when users included odd/unusual flags (ex: -fplugin, -flto) +# in CGO_CFLAGS, causing the Go linker to have to read and interpret +# non-standard host objects. +# +# As of 1.21 we continue to use internal linking for programs whose +# CGO use comes ony from stdlib packages in the absence of any flag +# funny business, however if the Go command sees flags that may be suspicious, +# it signals the Go linker to invoke the external linker. + +# The next few tests run builds passing "-n" to the Go command, then +# checking the output to see if the Go command is trying to pass a +# "preferlinkext" token to the linker to request external linking. + +#----------------------- + +# Use a fresh GOCACHE for these next steps, so as to have the real +# actions for the runtime/cgo package appear in the "-n -x" output. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# First build: there is no CGO in use, so no token should be present regardless +# of weird CGO flags. +go build -x -n -o dummy.exe ./noUseOfCgo +! stderr preferlinkext +env CGO_CFLAGS=-flto +go build -x -n -o dummy.exe ./noUseOfCgo +! stderr preferlinkext +env CGO_CFLAGS= + +# Second build uses CGO, so we expect to see the token present in the +# -n output only when strange flags are used. +go build -x -n -o dummy.exe ./usesInternalCgo +! stderr preferlinkext +env CGO_CFLAGS=-flto +go build -x -n -o dummy.exe ./usesInternalCgo +stderr preferlinkext +env CGO_CFLAGS=-fplugin +go build -x -n -o dummy.exe ./usesInternalCgo +stderr preferlinkext +env CGO_CFLAGS=-fprofile-instr-generate +go build -x -n -o dummy.exe ./usesInternalCgo +stderr preferlinkext +env CGO_CFLAGS= + +[short] skip + +# In the remaining tests below we do actual builds (without -n) to +# verify that the Go linker is going the right thing in addition to the +# Go command. Here the idea is to pass "-tmpdir" to the linker, then +# check after the link is done for the presence of the file +# /go.o, which the Go linker creates prior to kicking off the +# external linker. + +mkdir tmp1 +mkdir tmp2 +mkdir tmp3 +mkdir tmp4 +mkdir tmp5 + +# First build: no external linking expected +go build -ldflags=-tmpdir=tmp1 -o $devnull ./noUseOfCgo & + +# Second build: using only "runtime/cgo", expect internal linking. +go build -ldflags=-tmpdir=tmp2 -o $devnull ./usesInternalCgo & + +# Third build: program uses only "runtime/cgo", so we would normally +# expect internal linking, except that cflags contain suspicious entries +# (in this case, a flag that does not appear on the allow list). +env CGO_CFLAGS=-fmerge-all-constants +env CGO_LDFLAGS=-fmerge-all-constants +go build -ldflags=-tmpdir=tmp3 -o $devnull ./usesInternalCgo & +env CGO_CFLAGS= +env CGO_LDFLAGS= + +# Fourth build: explicit CGO, expect external linking. +go build -ldflags=-tmpdir=tmp4 -o $devnull ./usesExplicitCgo & + +# Fifth build: explicit CGO, but we specifically asked for internal linking +# via a flag, so using internal linking it is. +[cgolinkext] go list ./usesInternalCgo +[!cgolinkext] go build '-ldflags=-tmpdir=tmp5 -linkmode=internal' -o $devnull ./usesInternalCgo & + +wait + +# Check first build: no external linking expected +! exists tmp1/go.o + +# Check second build: using only "runtime/cgo", expect internal linking. +[!cgolinkext] ! exists tmp2/go.o +[cgolinkext] exists tmp2/go.o + +# Check third build: has suspicious flag. +exists tmp3/go.o + +# Fourth build: explicit CGO, expect external linking. +exists tmp4/go.o + +# Fifth build: explicit CGO, -linkmode=internal. +! exists tmp5/go.o + +-- go.mod -- + +module cgo.example + +go 1.20 + +-- noUseOfCgo/main.go -- + +package main + +func main() { + println("clean as a whistle") +} + +-- usesInternalCgo/main.go -- + +package main + +import ( + "runtime/cgo" +) + +func main() { + q := "hello" + h := cgo.NewHandle(q) + h.Delete() +} + +-- usesExplicitCgo/main.go -- + +package main + +/* +int meaningOfLife() { return 42; } +*/ +import "C" + +func main() { + println(C.meaningOfLife()) +} diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index 336cb33e3ba399..ba74b6fc96c3dc 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -281,7 +281,11 @@ func determineLinkMode(ctxt *Link) { ctxt.LinkMode = LinkExternal via = "via GO_EXTLINK_ENABLED " default: - if extNeeded || (iscgo && externalobj) { + preferExternal := len(preferlinkext) != 0 + if preferExternal && ctxt.Debugvlog > 0 { + ctxt.Logf("external linking prefer list is %v\n", preferlinkext) + } + if extNeeded || (iscgo && (externalobj || preferExternal)) { ctxt.LinkMode = LinkExternal } else { ctxt.LinkMode = LinkInternal diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index c0730179db4acc..03b9f11608d3de 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -350,6 +350,12 @@ var ( // any of these objects, we must link externally. Issue 52863. dynimportfail []string + // preferlinkext is a list of packages for which the Go command + // noticed use of peculiar C flags. If we see any of these, + // default to linking externally unless overridden by the + // user. See issues #58619, #58620, and #58848. + preferlinkext []string + // unknownObjFormat is set to true if we see an object whose // format we don't recognize. unknownObjFormat = false @@ -1072,6 +1078,13 @@ func loadobjfile(ctxt *Link, lib *sym.Library) { if arhdr.name == "dynimportfail" { dynimportfail = append(dynimportfail, lib.Pkg) } + if arhdr.name == "preferlinkext" { + // Ignore this directive if -linkmode has been + // set explicitly. + if ctxt.LinkMode == LinkAuto { + preferlinkext = append(preferlinkext, lib.Pkg) + } + } // Skip other special (non-object-file) sections that // build tools may have added. Such sections must have diff --git a/src/internal/platform/supported.go b/src/internal/platform/supported.go index 86c9f07adedcd6..046352f34c1d30 100644 --- a/src/internal/platform/supported.go +++ b/src/internal/platform/supported.go @@ -73,6 +73,43 @@ func FuzzInstrumented(goos, goarch string) bool { // MustLinkExternal reports whether goos/goarch requires external linking. func MustLinkExternal(goos, goarch string) bool { + return MustLinkExternalGo121(goos, goarch, false) +} + +// MustLinkExternalGo121 reports whether goos/goarch requires external linking, +// with or without cgo dependencies. [This version back-ported from +// Go 1.21 as part of a test]. +func MustLinkExternalGo121(goos, goarch string, withCgo bool) bool { + if withCgo { + switch goarch { + case "loong64", + "mips", "mipsle", "mips64", "mips64le", + "riscv64": + // Internally linking cgo is incomplete on some architectures. + // https://go.dev/issue/14449 + return true + case "arm64": + if goos == "windows" { + // windows/arm64 internal linking is not implemented. + return true + } + case "ppc64": + // Big Endian PPC64 cgo internal linking is not implemented for aix or linux. + // https://go.dev/issue/8912 + return true + } + + switch goos { + case "android": + return true + case "dragonfly": + // It seems that on Dragonfly thread local storage is + // set up by the dynamic linker, so internal cgo linking + // doesn't work. Test case is "go test runtime/cgo". + return true + } + } + switch goos { case "android": if goarch != "arm64" { From b52a6963bf6dfdddb8f8e7e85d52012ac305476f Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Mon, 13 Mar 2023 12:02:36 -0400 Subject: [PATCH 054/165] [release-branch.go1.20] cmd/link/internal/arm: fix off-by-1 in trampoline reachability computation Tweak the code in trampoline generation that determines if a given call branch will reach, changing the lower limit guard from "x < -0x800000" to "x <= -0x800000". This is to resolve linking failures when the computed displacement is exactly -0x800000, which results in errors of the form .../ld.gold: internal error in arm_branch_common, at ../../gold/arm.cc:4079 when using the Gold linker, and ...:(.text+0x...): relocation truncated to fit: R_ARM_CALL against `runtime.morestack_noctxt' when using the bfd linker. Fixes #59059. Updates #59034. Updates #58425. Change-Id: I8a76986b38727df1b961654824c2af23f06b9fcf Reviewed-on: https://go-review.googlesource.com/c/go/+/475957 Run-TryBot: Than McIntosh TryBot-Result: Gopher Robot Reviewed-by: Cherry Mui (cherry picked from commit f26bf203ac67fd917f2eb992baa1cb2d01edf3c8) Reviewed-on: https://go-review.googlesource.com/c/go/+/476936 --- src/cmd/link/internal/arm/asm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index 1e4b36df48f48d..4574f2d5f9f9bb 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -417,7 +417,7 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) { t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4 } } - if t > 0x7fffff || t < -0x800000 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) { + if t > 0x7fffff || t <= -0x800000 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) { // direct call too far, need to insert trampoline. // look up existing trampolines first. if we found one within the range // of direct call, we can reuse it. otherwise create a new one. From 65fa8a69312dd64e09e32e4138ccc7278d0693e5 Mon Sep 17 00:00:00 2001 From: Geon Kim Date: Sat, 11 Mar 2023 00:57:57 +0000 Subject: [PATCH 055/165] [release-branch.go1.20] time: fix timezone lookup logic for non-DST zones This change fixes time.LoadLocationFromTZData and time.Location.lookup logic if the given time is after the last transition and the extend string doesn't have the DST rule. For #58682 Fixes #59075 Change-Id: Ie34a6d658d14c2b33098b29ab83c041ef0d34266 GitHub-Last-Rev: f6681eb44c0ea0772004e56eb68fcbd9023d971e GitHub-Pull-Request: golang/go#58684 Reviewed-on: https://go-review.googlesource.com/c/go/+/471020 Reviewed-by: Ian Lance Taylor TryBot-Result: Gopher Robot Auto-Submit: Ian Lance Taylor Reviewed-by: Cherry Mui Run-TryBot: Ian Lance Taylor Run-TryBot: Ian Lance Taylor (cherry picked from commit 90dde5dec1126ddf2236730ec57511ced56a512d) Reviewed-on: https://go-review.googlesource.com/c/go/+/478658 Reviewed-by: Dmitri Shuralyov Reviewed-by: Heschi Kreinick Auto-Submit: Heschi Kreinick --- src/time/time_test.go | 26 ++++++++++++++++++-------- src/time/zoneinfo.go | 8 ++++---- src/time/zoneinfo_read.go | 2 +- src/time/zoneinfo_test.go | 1 + 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/time/time_test.go b/src/time/time_test.go index 4221efec8872b7..3b30f802efe776 100644 --- a/src/time/time_test.go +++ b/src/time/time_test.go @@ -1860,16 +1860,26 @@ func TestZoneBounds(t *testing.T) { 5: {Date(1991, September, 14, 17, 0, 0, 0, loc), boundTwo, boundThree}, 6: {Date(1991, September, 15, 0, 50, 0, 0, loc), boundTwo, boundThree}, + // The ZoneBounds of a "Asia/Shanghai" after the last transition (Standard Time) + 7: {boundThree, boundThree, Time{}}, + 8: {Date(1991, December, 15, 1, 50, 0, 0, loc), boundThree, Time{}}, + 9: {Date(1992, April, 13, 17, 50, 0, 0, loc), boundThree, Time{}}, + 10: {Date(1992, April, 13, 18, 0, 0, 0, loc), boundThree, Time{}}, + 11: {Date(1992, April, 14, 1, 50, 0, 0, loc), boundThree, Time{}}, + 12: {Date(1992, September, 14, 16, 50, 0, 0, loc), boundThree, Time{}}, + 13: {Date(1992, September, 14, 17, 0, 0, 0, loc), boundThree, Time{}}, + 14: {Date(1992, September, 15, 0, 50, 0, 0, loc), boundThree, Time{}}, + // The ZoneBounds of a local time would return two local Time. // Note: We preloaded "America/Los_Angeles" as time.Local for testing - 7: {makeLocalTime(0), makeLocalTime(-5756400), makeLocalTime(9972000)}, - 8: {makeLocalTime(1221681866), makeLocalTime(1205056800), makeLocalTime(1225616400)}, - 9: {makeLocalTime(2152173599), makeLocalTime(2145916800), makeLocalTime(2152173600)}, - 10: {makeLocalTime(2152173600), makeLocalTime(2152173600), makeLocalTime(2172733200)}, - 11: {makeLocalTime(2152173601), makeLocalTime(2152173600), makeLocalTime(2172733200)}, - 12: {makeLocalTime(2159200800), makeLocalTime(2152173600), makeLocalTime(2172733200)}, - 13: {makeLocalTime(2172733199), makeLocalTime(2152173600), makeLocalTime(2172733200)}, - 14: {makeLocalTime(2172733200), makeLocalTime(2172733200), makeLocalTime(2177452800)}, + 15: {makeLocalTime(0), makeLocalTime(-5756400), makeLocalTime(9972000)}, + 16: {makeLocalTime(1221681866), makeLocalTime(1205056800), makeLocalTime(1225616400)}, + 17: {makeLocalTime(2152173599), makeLocalTime(2145916800), makeLocalTime(2152173600)}, + 18: {makeLocalTime(2152173600), makeLocalTime(2152173600), makeLocalTime(2172733200)}, + 19: {makeLocalTime(2152173601), makeLocalTime(2152173600), makeLocalTime(2172733200)}, + 20: {makeLocalTime(2159200800), makeLocalTime(2152173600), makeLocalTime(2172733200)}, + 21: {makeLocalTime(2172733199), makeLocalTime(2152173600), makeLocalTime(2172733200)}, + 22: {makeLocalTime(2172733200), makeLocalTime(2172733200), makeLocalTime(2177452800)}, } for i, tt := range realTests { start, end := tt.giveTime.ZoneBounds() diff --git a/src/time/zoneinfo.go b/src/time/zoneinfo.go index dd3b4edd01d0b8..4edcf3d98f1296 100644 --- a/src/time/zoneinfo.go +++ b/src/time/zoneinfo.go @@ -203,7 +203,7 @@ func (l *Location) lookup(sec int64) (name string, offset int, start, end int64, // If we're at the end of the known zone transitions, // try the extend string. if lo == len(tx)-1 && l.extend != "" { - if ename, eoffset, estart, eend, eisDST, ok := tzset(l.extend, end, sec); ok { + if ename, eoffset, estart, eend, eisDST, ok := tzset(l.extend, start, sec); ok { return ename, eoffset, estart, eend, eisDST } } @@ -264,12 +264,12 @@ func (l *Location) firstZoneUsed() bool { } // tzset takes a timezone string like the one found in the TZ environment -// variable, the end of the last time zone transition expressed as seconds +// variable, the time of the last time zone transition expressed as seconds // since January 1, 1970 00:00:00 UTC, and a time expressed the same way. // We call this a tzset string since in C the function tzset reads TZ. // The return values are as for lookup, plus ok which reports whether the // parse succeeded. -func tzset(s string, initEnd, sec int64) (name string, offset int, start, end int64, isDST, ok bool) { +func tzset(s string, lastTxSec, sec int64) (name string, offset int, start, end int64, isDST, ok bool) { var ( stdName, dstName string stdOffset, dstOffset int @@ -290,7 +290,7 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in if len(s) == 0 || s[0] == ',' { // No daylight savings time. - return stdName, stdOffset, initEnd, omega, false, true + return stdName, stdOffset, lastTxSec, omega, false, true } dstName, s, ok = tzsetName(s) diff --git a/src/time/zoneinfo_read.go b/src/time/zoneinfo_read.go index 90814ad36a1ad4..1c155dc59d5d8c 100644 --- a/src/time/zoneinfo_read.go +++ b/src/time/zoneinfo_read.go @@ -329,7 +329,7 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) { } else if l.extend != "" { // If we're at the end of the known zone transitions, // try the extend string. - if name, offset, estart, eend, isDST, ok := tzset(l.extend, l.cacheEnd, sec); ok { + if name, offset, estart, eend, isDST, ok := tzset(l.extend, l.cacheStart, sec); ok { l.cacheStart = estart l.cacheEnd = eend // Find the zone that is returned by tzset to avoid allocation if possible. diff --git a/src/time/zoneinfo_test.go b/src/time/zoneinfo_test.go index 243ff8ebdee775..8cd37b5e27fe24 100644 --- a/src/time/zoneinfo_test.go +++ b/src/time/zoneinfo_test.go @@ -271,6 +271,7 @@ func TestTzset(t *testing.T) { {"PST8PDT,M3.2.0,M11.1.0", 0, 2172733199, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true, true}, {"PST8PDT,M3.2.0,M11.1.0", 0, 2172733200, "PST", -8 * 60 * 60, 2172733200, 2177452800, false, true}, {"PST8PDT,M3.2.0,M11.1.0", 0, 2172733201, "PST", -8 * 60 * 60, 2172733200, 2177452800, false, true}, + {"KST-9", 592333200, 1677246697, "KST", 9 * 60 * 60, 592333200, 1<<63 - 1, false, true}, } { name, off, start, end, isDST, ok := time.Tzset(test.inStr, test.inEnd, test.inSec) if name != test.name || off != test.off || start != test.start || end != test.end || isDST != test.isDST || ok != test.ok { From 94c02a3cc481e4b73ce275ba6e50c286d4c492ff Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sat, 18 Mar 2023 00:53:07 +0700 Subject: [PATCH 056/165] [release-branch.go1.20] cmd/compile: re-compile instantiated generic methods in linkshared mode For G[T] that was seen and compiled in imported package, it is not added to typecheck.Target.Decls, prevent wasting compile time re-creating DUPOKS symbols. However, the linker do not support a type symbol referencing a method symbol across DSO boundary. That causes unreachable sym error when building under -linkshared mode. To fix it, always re-compile generic methods in linkshared mode. Fixes #59236 Change-Id: I894b417cfe8234ae1fe809cc975889345df22cef Reviewed-on: https://go-review.googlesource.com/c/go/+/477375 Run-TryBot: Cuong Manh Le Reviewed-by: Cherry Mui Reviewed-by: Matthew Dempsky TryBot-Result: Gopher Robot Reviewed-on: https://go-review.googlesource.com/c/go/+/479355 --- misc/cgo/testshared/shared_test.go | 7 ++++++- misc/cgo/testshared/testdata/issue58966/main.go | 15 +++++++++++++++ src/cmd/compile/internal/noder/unified.go | 6 +++++- 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 misc/cgo/testshared/testdata/issue58966/main.go diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go index b14fb1cb3a7b79..03da8f9435704f 100644 --- a/misc/cgo/testshared/shared_test.go +++ b/misc/cgo/testshared/shared_test.go @@ -1112,8 +1112,13 @@ func TestStd(t *testing.T) { t.Skip("skip in short mode") } t.Parallel() + tmpDir := t.TempDir() // Use a temporary pkgdir to not interfere with other tests, and not write to GOROOT. // Cannot use goCmd as it runs with cloned GOROOT which is incomplete. runWithEnv(t, "building std", []string{"GOROOT=" + oldGOROOT}, - filepath.Join(oldGOROOT, "bin", "go"), "install", "-buildmode=shared", "-pkgdir="+t.TempDir(), "std") + filepath.Join(oldGOROOT, "bin", "go"), "install", "-buildmode=shared", "-pkgdir="+tmpDir, "std") + + // Issue #58966. + runWithEnv(t, "testing issue #58966", []string{"GOROOT=" + oldGOROOT}, + filepath.Join(oldGOROOT, "bin", "go"), "run", "-linkshared", "-pkgdir="+tmpDir, "./issue58966/main.go") } diff --git a/misc/cgo/testshared/testdata/issue58966/main.go b/misc/cgo/testshared/testdata/issue58966/main.go new file mode 100644 index 00000000000000..2d923c36076d5f --- /dev/null +++ b/misc/cgo/testshared/testdata/issue58966/main.go @@ -0,0 +1,15 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "crypto/elliptic" + +var curve elliptic.Curve + +func main() { + switch curve { + case elliptic.P224(): + } +} diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go index ed97a09302e899..25136e6aad190b 100644 --- a/src/cmd/compile/internal/noder/unified.go +++ b/src/cmd/compile/internal/noder/unified.go @@ -158,7 +158,11 @@ func readBodies(target *ir.Package, duringInlining bool) { // Instantiated generic function: add to Decls for typechecking // and compilation. if fn.OClosure == nil && len(pri.dict.targs) != 0 { - if duringInlining { + // cmd/link does not support a type symbol referencing a method symbol + // across DSO boundary, so force re-compiling methods on a generic type + // even it was seen from imported package in linkshared mode, see #58966. + canSkipNonGenericMethod := !(base.Ctxt.Flag_linkshared && ir.IsMethod(fn)) + if duringInlining && canSkipNonGenericMethod { inlDecls = append(inlDecls, fn) } else { target.Decls = append(target.Decls, fn) From 8dce4ca8dfd4892e2f5bdf0a1224b9efe0dca89f Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 28 Mar 2023 10:19:21 -0700 Subject: [PATCH 057/165] [release-branch.go1.20] cmd/compile: don't assume pointer of a slice is non-nil unsafe.SliceData can return pointers which are nil. That function gets lowered to the SSA OpSlicePtr, which the compiler assumes is non-nil. This used to be the case as OpSlicePtr was only used in situations where the bounds check already passed. But with unsafe.SliceData that is no longer the case. There are situations where we know it is nil. Use Bounded() to indicate that. I looked through all the uses of OSPTR and added SetBounded where it made sense. Most OSPTR results are passed directly to runtime calls (e.g. memmove), so even if we know they are non-nil that info isn't helpful. Fixes #59296 Change-Id: I437a15330db48e0082acfb1f89caf8c56723fc51 Reviewed-on: https://go-review.googlesource.com/c/go/+/479896 Reviewed-by: Matthew Dempsky Reviewed-by: Keith Randall TryBot-Result: Gopher Robot Run-TryBot: Keith Randall (cherry picked from commit b899641ecea7d07c997282e985beb295c31d1097) Reviewed-on: https://go-review.googlesource.com/c/go/+/479899 Run-TryBot: Keith Randall Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/ir/node.go | 2 +- src/cmd/compile/internal/ssagen/ssa.go | 5 ++++- src/cmd/compile/internal/walk/convert.go | 4 +++- src/cmd/compile/internal/walk/range.go | 1 + test/fixedbugs/issue59293.go | 28 ++++++++++++++++++++++++ 5 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 test/fixedbugs/issue59293.go diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index b42f914aadd820..547dd48a147446 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -291,7 +291,7 @@ const ( OEFACE // itable and data words of an empty-interface value. OITAB // itable word of an interface value. OIDATA // data word of an interface value in X - OSPTR // base pointer of a slice or string. + OSPTR // base pointer of a slice or string. Bounded==1 means known non-nil. OCFUNC // reference to c function pointer (not go func value) OCHECKNIL // emit code to ensure pointer/interface not nil ORESULT // result of a function call; Xoffset is stack offset diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 52f94030df7e20..526332294c5809 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -3203,7 +3203,10 @@ func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value { n := n.(*ir.UnaryExpr) a := s.expr(n.X) if n.X.Type().IsSlice() { - return s.newValue1(ssa.OpSlicePtr, n.Type(), a) + if n.Bounded() { + return s.newValue1(ssa.OpSlicePtr, n.Type(), a) + } + return s.newValue1(ssa.OpSlicePtrUnchecked, n.Type(), a) } else { return s.newValue1(ssa.OpStringPtr, n.Type(), a) } diff --git a/src/cmd/compile/internal/walk/convert.go b/src/cmd/compile/internal/walk/convert.go index bf06ed6f4679b7..ca0c806a1e1a52 100644 --- a/src/cmd/compile/internal/walk/convert.go +++ b/src/cmd/compile/internal/walk/convert.go @@ -281,7 +281,9 @@ func walkStringToBytes(n *ir.ConvExpr, init *ir.Nodes) ir.Node { // Copy from the static string data to the [n]byte. if len(sc) > 0 { - as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, typecheck.ConvNop(ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), t.PtrTo()))) + sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, s) + sptr.SetBounded(true) + as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, typecheck.ConvNop(sptr, t.PtrTo()))) appendWalkStmt(init, as) } diff --git a/src/cmd/compile/internal/walk/range.go b/src/cmd/compile/internal/walk/range.go index 64af26bf29c587..82e7d22cfa8397 100644 --- a/src/cmd/compile/internal/walk/range.go +++ b/src/cmd/compile/internal/walk/range.go @@ -191,6 +191,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node { // Pointer to current iteration position. Start on entry to the loop // with the pointer in hu. ptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, hs) + ptr.SetBounded(true) huVal := ir.NewConvExpr(base.Pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], ptr) huVal = ir.NewConvExpr(base.Pos, ir.OCONVNOP, types.Types[types.TUINTPTR], huVal) hu := typecheck.Temp(types.Types[types.TUINTPTR]) diff --git a/test/fixedbugs/issue59293.go b/test/fixedbugs/issue59293.go new file mode 100644 index 00000000000000..1f05fe9a7ac1aa --- /dev/null +++ b/test/fixedbugs/issue59293.go @@ -0,0 +1,28 @@ +// 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 "unsafe" + +//go:noinline +func f(x []byte) bool { + return unsafe.SliceData(x) != nil +} + +//go:noinline +func g(x string) bool { + return unsafe.StringData(x) != nil +} + +func main() { + if f(nil) { + panic("bad f") + } + if g("") { + panic("bad g") + } +} From 9a164d1c41a5c85cc3c6fa93c29677e8bc36714f Mon Sep 17 00:00:00 2001 From: Lynn Boger Date: Mon, 27 Mar 2023 08:26:59 -0500 Subject: [PATCH 058/165] [release-branch.go1.20] cmd/internal/obj/ppc64: fix incorrect base reg causing segv This fixes a segv that was reported due to building minio. The problem occurred because of an incorrect selection of the base register, which was introduced by CL 306369. Fixes #59220 Change-Id: Ieb77b2afa8fb4e6f3943df5ce138679f6750d376 Reviewed-on: https://go-review.googlesource.com/c/go/+/479475 Reviewed-by: Archana Ravindar TryBot-Result: Gopher Robot Reviewed-by: Matthew Dempsky Run-TryBot: Lynn Boger Reviewed-by: Cherry Mui --- src/cmd/internal/obj/ppc64/asm9.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go index 9469edaf4c8052..c346043f3e06e8 100644 --- a/src/cmd/internal/obj/ppc64/asm9.go +++ b/src/cmd/internal/obj/ppc64/asm9.go @@ -3132,8 +3132,13 @@ func asmout(c *ctxt9, p *obj.Prog, o *Optab, out *[5]uint32) { if r == 0 { r = c.getimpliedreg(&p.From, p) } - o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v))) - o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v)) + if o.a6 == C_REG { + o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v))) + o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v)) + } else { + o1 = AOP_IRR(OP_ADDIS, uint32(REGTMP), uint32(r), uint32(high16adjusted(v))) + o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(REGTMP), uint32(v)) + } // Sign extend MOVB if needed o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0) @@ -3519,8 +3524,8 @@ func asmout(c *ctxt9, p *obj.Prog, o *Optab, out *[5]uint32) { rel.Type = objabi.R_ADDRPOWER_TOCREL_DS } default: - reuseBaseReg := p.As != AFMOVD && p.As != AFMOVS - // Reuse To.Reg as base register if not FP move. + reuseBaseReg := o.a6 == C_REG + // Reuse To.Reg as base register if it is a GPR. o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst, reuseBaseReg) } From 3991f6c41c7dfd167e889234c0cf1d840475e93c Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Fri, 10 Mar 2023 14:21:05 -0800 Subject: [PATCH 059/165] [release-branch.go1.20] net/textproto: avoid overpredicting the number of MIME header keys A parsed MIME header is a map[string][]string. In the common case, a header contains many one-element []string slices. To avoid allocating a separate slice for each key, ReadMIMEHeader looks ahead in the input to predict the number of keys that will be parsed, and allocates a single []string of that length. The individual slices are then allocated out of the larger one. The prediction of the number of header keys was done by counting newlines in the input buffer, which does not take into account header continuation lines (where a header key/value spans multiple lines) or the end of the header block and the start of the body. This could lead to a substantial amount of overallocation, for example when the body consists of nothing but a large block of newlines. Fix header key count prediction to take into account the end of the headers (indicated by a blank line) and continuation lines (starting with whitespace). Thanks to Jakob Ackermann (@das7pad) for reporting this issue. Fixes CVE-2023-24534 For #58975 Fixes #59268 Change-Id: I0591593e67b6fdba22a32dcc3334fad797727f5c Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802452 Run-TryBot: Damien Neil Reviewed-by: Roland Shoemaker Reviewed-by: Julie Qiu Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802397 Run-TryBot: Roland Shoemaker TryBot-Result: Security TryBots Reviewed-on: https://go-review.googlesource.com/c/go/+/481988 Run-TryBot: Michael Knyszek TryBot-Bypass: Michael Knyszek Auto-Submit: Michael Knyszek Reviewed-by: Matthew Dempsky --- src/net/textproto/reader.go | 24 ++++++++++--- src/net/textproto/reader_test.go | 59 ++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 4 deletions(-) diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go index 8e800088c1fe79..48ae2946a6b0e8 100644 --- a/src/net/textproto/reader.go +++ b/src/net/textproto/reader.go @@ -489,8 +489,11 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { // large one ahead of time which we'll cut up into smaller // slices. If this isn't big enough later, we allocate small ones. var strs []string - hint := r.upcomingHeaderNewlines() + hint := r.upcomingHeaderKeys() if hint > 0 { + if hint > 1000 { + hint = 1000 // set a cap to avoid overallocation + } strs = make([]string, hint) } @@ -581,9 +584,9 @@ func mustHaveFieldNameColon(line []byte) error { var nl = []byte("\n") -// upcomingHeaderNewlines returns an approximation of the number of newlines +// upcomingHeaderKeys returns an approximation of the number of keys // that will be in this header. If it gets confused, it returns 0. -func (r *Reader) upcomingHeaderNewlines() (n int) { +func (r *Reader) upcomingHeaderKeys() (n int) { // Try to determine the 'hint' size. r.R.Peek(1) // force a buffer load if empty s := r.R.Buffered() @@ -591,7 +594,20 @@ func (r *Reader) upcomingHeaderNewlines() (n int) { return } peek, _ := r.R.Peek(s) - return bytes.Count(peek, nl) + for len(peek) > 0 && n < 1000 { + var line []byte + line, peek, _ = bytes.Cut(peek, nl) + if len(line) == 0 || (len(line) == 1 && line[0] == '\r') { + // Blank line separating headers from the body. + break + } + if line[0] == ' ' || line[0] == '\t' { + // Folded continuation of the previous line. + continue + } + n++ + } + return n } // CanonicalMIMEHeaderKey returns the canonical format of the diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go index 9618b874e6f853..696ae406f3860f 100644 --- a/src/net/textproto/reader_test.go +++ b/src/net/textproto/reader_test.go @@ -10,6 +10,7 @@ import ( "io" "net" "reflect" + "runtime" "strings" "sync" "testing" @@ -129,6 +130,42 @@ func TestReadMIMEHeaderSingle(t *testing.T) { } } +// TestReaderUpcomingHeaderKeys is testing an internal function, but it's very +// difficult to test well via the external API. +func TestReaderUpcomingHeaderKeys(t *testing.T) { + for _, test := range []struct { + input string + want int + }{{ + input: "", + want: 0, + }, { + input: "A: v", + want: 1, + }, { + input: "A: v\r\nB: v\r\n", + want: 2, + }, { + input: "A: v\nB: v\n", + want: 2, + }, { + input: "A: v\r\n continued\r\n still continued\r\nB: v\r\n\r\n", + want: 2, + }, { + input: "A: v\r\n\r\nB: v\r\nC: v\r\n", + want: 1, + }, { + input: "A: v" + strings.Repeat("\n", 1000), + want: 1, + }} { + r := reader(test.input) + got := r.upcomingHeaderKeys() + if test.want != got { + t.Fatalf("upcomingHeaderKeys(%q): %v; want %v", test.input, got, test.want) + } + } +} + func TestReadMIMEHeaderNoKey(t *testing.T) { r := reader(": bar\ntest-1: 1\n\n") m, err := r.ReadMIMEHeader() @@ -271,6 +308,28 @@ func TestReadMIMEHeaderTrimContinued(t *testing.T) { } } +// Test that reading a header doesn't overallocate. Issue 58975. +func TestReadMIMEHeaderAllocations(t *testing.T) { + var totalAlloc uint64 + const count = 200 + for i := 0; i < count; i++ { + r := reader("A: b\r\n\r\n" + strings.Repeat("\n", 4096)) + var m1, m2 runtime.MemStats + runtime.ReadMemStats(&m1) + _, err := r.ReadMIMEHeader() + if err != nil { + t.Fatalf("ReadMIMEHeader: %v", err) + } + runtime.ReadMemStats(&m2) + totalAlloc += m2.TotalAlloc - m1.TotalAlloc + } + // 32k is large and we actually allocate substantially less, + // but prior to the fix for #58975 we allocated ~400k in this case. + if got, want := totalAlloc/count, uint64(32768); got > want { + t.Fatalf("ReadMIMEHeader allocated %v bytes, want < %v", got, want) + } +} + type readResponseTest struct { in string inCode int From ea6b5a64dd5bf68b33286436ffbe06f68a1fdbfd Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Thu, 16 Mar 2023 14:18:04 -0700 Subject: [PATCH 060/165] [release-branch.go1.20] mime/multipart: avoid excessive copy buffer allocations in ReadForm When copying form data to disk with io.Copy, allocate only one copy buffer and reuse it rather than creating two buffers per file (one from io.multiReader.WriteTo, and a second one from os.File.ReadFrom). Thanks to Jakob Ackermann (@das7pad) for reporting this issue. For CVE-2023-24536 For #59153 For #59270 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802453 Run-TryBot: Damien Neil Reviewed-by: Julie Qiu Reviewed-by: Roland Shoemaker Change-Id: I44ef17c4b4964cdac2858317275594194801fee3 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802398 Run-TryBot: Roland Shoemaker Reviewed-on: https://go-review.googlesource.com/c/go/+/481989 Auto-Submit: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Gopher Robot Reviewed-by: Matthew Dempsky --- src/mime/multipart/formdata.go | 15 +++++++-- src/mime/multipart/formdata_test.go | 49 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go index 41bc886d1679d5..69b8b0399da57f 100644 --- a/src/mime/multipart/formdata.go +++ b/src/mime/multipart/formdata.go @@ -85,6 +85,7 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { maxMemoryBytes = math.MaxInt64 } } + var copyBuf []byte for { p, err := r.nextPart(false, maxMemoryBytes) if err == io.EOF { @@ -148,14 +149,22 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { } } numDiskFiles++ - size, err := io.Copy(file, io.MultiReader(&b, p)) + if _, err := file.Write(b.Bytes()); err != nil { + return nil, err + } + if copyBuf == nil { + copyBuf = make([]byte, 32*1024) // same buffer size as io.Copy uses + } + // os.File.ReadFrom will allocate its own copy buffer if we let io.Copy use it. + type writerOnly struct{ io.Writer } + remainingSize, err := io.CopyBuffer(writerOnly{file}, p, copyBuf) if err != nil { return nil, err } fh.tmpfile = file.Name() - fh.Size = size + fh.Size = int64(b.Len()) + remainingSize fh.tmpoff = fileOff - fileOff += size + fileOff += fh.Size if !combineFiles { if err := file.Close(); err != nil { return nil, err diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go index 8a862be717415e..60f55b4a27fa02 100644 --- a/src/mime/multipart/formdata_test.go +++ b/src/mime/multipart/formdata_test.go @@ -368,3 +368,52 @@ func testReadFormManyFiles(t *testing.T, distinct bool) { t.Fatalf("temp dir contains %v files; want 0", len(names)) } } + +func BenchmarkReadForm(b *testing.B) { + for _, test := range []struct { + name string + form func(fw *Writer, count int) + }{{ + name: "fields", + form: func(fw *Writer, count int) { + for i := 0; i < count; i++ { + w, _ := fw.CreateFormField(fmt.Sprintf("field%v", i)) + fmt.Fprintf(w, "value %v", i) + } + }, + }, { + name: "files", + form: func(fw *Writer, count int) { + for i := 0; i < count; i++ { + w, _ := fw.CreateFormFile(fmt.Sprintf("field%v", i), fmt.Sprintf("file%v", i)) + fmt.Fprintf(w, "value %v", i) + } + }, + }} { + b.Run(test.name, func(b *testing.B) { + for _, maxMemory := range []int64{ + 0, + 1 << 20, + } { + var buf bytes.Buffer + fw := NewWriter(&buf) + test.form(fw, 10) + if err := fw.Close(); err != nil { + b.Fatal(err) + } + b.Run(fmt.Sprintf("maxMemory=%v", maxMemory), func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + fr := NewReader(bytes.NewReader(buf.Bytes()), fw.Boundary()) + form, err := fr.ReadForm(maxMemory) + if err != nil { + b.Fatal(err) + } + form.RemoveAll() + } + + }) + } + }) + } +} From ec18f62df59d8f857e63ed3d7480754c49b072c3 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Thu, 16 Mar 2023 16:56:12 -0700 Subject: [PATCH 061/165] [release-branch.go1.20] net/textproto, mime/multipart: improve accounting of non-file data For requests containing large numbers of small parts, memory consumption of a parsed form could be about 250% over the estimated size. When considering the size of parsed forms, account for the size of FileHeader structs and increase the estimate of memory consumed by map entries. Thanks to Jakob Ackermann (@das7pad) for reporting this issue. For CVE-2023-24536 For #59153 For #59270 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802454 Run-TryBot: Damien Neil Reviewed-by: Roland Shoemaker Reviewed-by: Julie Qiu Change-Id: I9753aa1f8a1b1479c160f870def3b7081b6847ac Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802399 TryBot-Result: Security TryBots Run-TryBot: Roland Shoemaker Reviewed-on: https://go-review.googlesource.com/c/go/+/481990 TryBot-Bypass: Michael Knyszek Reviewed-by: Matthew Dempsky Run-TryBot: Michael Knyszek Auto-Submit: Michael Knyszek --- src/mime/multipart/formdata.go | 9 +++-- src/mime/multipart/formdata_test.go | 55 ++++++++++++----------------- src/net/textproto/reader.go | 8 ++++- 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go index 69b8b0399da57f..e757ae370b5c31 100644 --- a/src/mime/multipart/formdata.go +++ b/src/mime/multipart/formdata.go @@ -104,8 +104,9 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { // 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. + const mapEntryOverhead = 200 maxMemoryBytes -= int64(len(name)) - maxMemoryBytes -= 100 // map overhead + maxMemoryBytes -= mapEntryOverhead 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. @@ -129,7 +130,10 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { } // file, store in memory or on disk + const fileHeaderSize = 100 maxMemoryBytes -= mimeHeaderSize(p.Header) + maxMemoryBytes -= mapEntryOverhead + maxMemoryBytes -= fileHeaderSize if maxMemoryBytes < 0 { return nil, ErrMessageTooLarge } @@ -184,9 +188,10 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { } func mimeHeaderSize(h textproto.MIMEHeader) (size int64) { + size = 400 for k, vs := range h { size += int64(len(k)) - size += 100 // map entry overhead + size += 200 // map entry overhead for _, v := range vs { size += int64(len(v)) } diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go index 60f55b4a27fa02..9e2806df36ced4 100644 --- a/src/mime/multipart/formdata_test.go +++ b/src/mime/multipart/formdata_test.go @@ -192,10 +192,10 @@ func (r *failOnReadAfterErrorReader) Read(p []byte) (n int, err error) { // TestReadForm_NonFileMaxMemory asserts that the ReadForm maxMemory limit is applied // while processing non-file form data as well as file form data. func TestReadForm_NonFileMaxMemory(t *testing.T) { - n := 10<<20 + 25 if testing.Short() { - n = 10<<10 + 25 + t.Skip("skipping in -short mode") } + n := 10 << 20 largeTextValue := strings.Repeat("1", n) message := `--MyBoundary Content-Disposition: form-data; name="largetext" @@ -203,38 +203,29 @@ Content-Disposition: form-data; name="largetext" ` + largeTextValue + ` --MyBoundary-- ` - testBody := strings.ReplaceAll(message, "\n", "\r\n") - testCases := []struct { - name string - maxMemory int64 - err error - }{ - {"smaller", 50 + int64(len("largetext")) + 100, nil}, - {"exact-fit", 25 + int64(len("largetext")) + 100, nil}, - {"too-large", 0, ErrMessageTooLarge}, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - if tc.maxMemory == 0 && testing.Short() { - t.Skip("skipping in -short mode") - } - b := strings.NewReader(testBody) - r := NewReader(b, boundary) - f, err := r.ReadForm(tc.maxMemory) - if err == nil { - defer f.RemoveAll() - } - if 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 { - t.Errorf("largetext mismatch: got size: %v, expected size: %v", len(g), len(largeTextValue)) - } - } - }) + // Try parsing the form with increasing maxMemory values. + // Changes in how we account for non-file form data may cause the exact point + // where we change from rejecting the form as too large to accepting it to vary, + // but we should see both successes and failures. + const failWhenMaxMemoryLessThan = 128 + for maxMemory := int64(0); maxMemory < failWhenMaxMemoryLessThan*2; maxMemory += 16 { + b := strings.NewReader(testBody) + r := NewReader(b, boundary) + f, err := r.ReadForm(maxMemory) + if err != nil { + continue + } + if g := f.Value["largetext"][0]; g != largeTextValue { + t.Errorf("largetext mismatch: got size: %v, expected size: %v", len(g), len(largeTextValue)) + } + f.RemoveAll() + if maxMemory < failWhenMaxMemoryLessThan { + t.Errorf("ReadForm(%v): no error, expect to hit memory limit when maxMemory < %v", maxMemory, failWhenMaxMemoryLessThan) + } + return } + t.Errorf("ReadForm(x) failed for x < 1024, expect success") } // TestReadForm_MetadataTooLarge verifies that we account for the size of field names, diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go index 48ae2946a6b0e8..af82b4b9ab153a 100644 --- a/src/net/textproto/reader.go +++ b/src/net/textproto/reader.go @@ -499,6 +499,12 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { m := make(MIMEHeader, hint) + // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry. + // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large + // MIMEHeaders average about 200 bytes per entry. + lim -= 400 + const mapEntryOverhead = 200 + // The first line cannot start with a leading space. if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') { line, err := r.readLineSlice() @@ -542,7 +548,7 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { vv := m[key] if vv == nil { lim -= int64(len(key)) - lim -= 100 // map entry overhead + lim -= mapEntryOverhead } lim -= int64(len(value)) if lim < 0 { From bf8c7c575c8a552d9d79deb29e80854dc88528d0 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Mon, 20 Mar 2023 10:43:19 -0700 Subject: [PATCH 062/165] [release-branch.go1.20] mime/multipart: limit parsed mime message sizes The parsed forms of MIME headers and multipart forms can consume substantially more memory than the size of the input data. A malicious input containing a very large number of headers or form parts can cause excessively large memory allocations. Set limits on the size of MIME data: Reader.NextPart and Reader.NextRawPart limit the the number of headers in a part to 10000. Reader.ReadForm limits the total number of headers in all FileHeaders to 10000. Both of these limits may be set with with GODEBUG=multipartmaxheaders=. Reader.ReadForm limits the number of parts in a form to 1000. This limit may be set with GODEBUG=multipartmaxparts=. Thanks for Jakob Ackermann (@das7pad) for reporting this issue. For CVE-2023-24536 For #59153 For #59270 Change-Id: I36ddceead7f8292c327286fd8694e6113d3b4977 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802455 Run-TryBot: Damien Neil Reviewed-by: Roland Shoemaker Reviewed-by: Julie Qiu Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802608 Run-TryBot: Roland Shoemaker Reviewed-on: https://go-review.googlesource.com/c/go/+/481991 Run-TryBot: Michael Knyszek Reviewed-by: Matthew Dempsky Auto-Submit: Michael Knyszek TryBot-Bypass: Michael Knyszek --- src/mime/multipart/formdata.go | 28 +++++++++++-- src/mime/multipart/formdata_test.go | 61 ++++++++++++++++++++++++++++ src/mime/multipart/multipart.go | 32 +++++++++++---- src/mime/multipart/readmimeheader.go | 2 +- src/net/textproto/reader.go | 19 +++++---- 5 files changed, 123 insertions(+), 19 deletions(-) diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go index e757ae370b5c31..267cfe84cae696 100644 --- a/src/mime/multipart/formdata.go +++ b/src/mime/multipart/formdata.go @@ -12,6 +12,7 @@ import ( "math" "net/textproto" "os" + "strconv" ) // ErrMessageTooLarge is returned by ReadForm if the message form @@ -32,7 +33,10 @@ func (r *Reader) ReadForm(maxMemory int64) (*Form, error) { return r.readForm(maxMemory) } -var multipartFiles = godebug.New("multipartfiles") +var ( + multipartFiles = godebug.New("multipartfiles") + multipartMaxParts = godebug.New("multipartmaxparts") +) func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { form := &Form{make(map[string][]string), make(map[string][]*FileHeader)} @@ -41,7 +45,18 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { fileOff int64 ) numDiskFiles := 0 - combineFiles := multipartFiles.Value() != "distinct" + combineFiles := true + if multipartFiles.Value() == "distinct" { + combineFiles = false + } + maxParts := 1000 + if s := multipartMaxParts.Value(); s != "" { + if v, err := strconv.Atoi(s); err == nil && v >= 0 { + maxParts = v + } + } + maxHeaders := maxMIMEHeaders() + defer func() { if file != nil { if cerr := file.Close(); err == nil { @@ -87,13 +102,17 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { } var copyBuf []byte for { - p, err := r.nextPart(false, maxMemoryBytes) + p, err := r.nextPart(false, maxMemoryBytes, maxHeaders) if err == io.EOF { break } if err != nil { return nil, err } + if maxParts <= 0 { + return nil, ErrMessageTooLarge + } + maxParts-- name := p.FormName() if name == "" { @@ -137,6 +156,9 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { if maxMemoryBytes < 0 { return nil, ErrMessageTooLarge } + for _, v := range p.Header { + maxHeaders -= int64(len(v)) + } fh := &FileHeader{ Filename: filename, Header: p.Header, diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go index 9e2806df36ced4..a618a64beb24b6 100644 --- a/src/mime/multipart/formdata_test.go +++ b/src/mime/multipart/formdata_test.go @@ -360,6 +360,67 @@ func testReadFormManyFiles(t *testing.T, distinct bool) { } } +func TestReadFormLimits(t *testing.T) { + for _, test := range []struct { + values int + files int + extraKeysPerFile int + wantErr error + godebug string + }{ + {values: 1000}, + {values: 1001, wantErr: ErrMessageTooLarge}, + {values: 500, files: 500}, + {values: 501, files: 500, wantErr: ErrMessageTooLarge}, + {files: 1000}, + {files: 1001, wantErr: ErrMessageTooLarge}, + {files: 1, extraKeysPerFile: 9998}, // plus Content-Disposition and Content-Type + {files: 1, extraKeysPerFile: 10000, wantErr: ErrMessageTooLarge}, + {godebug: "multipartmaxparts=100", values: 100}, + {godebug: "multipartmaxparts=100", values: 101, wantErr: ErrMessageTooLarge}, + {godebug: "multipartmaxheaders=100", files: 2, extraKeysPerFile: 48}, + {godebug: "multipartmaxheaders=100", files: 2, extraKeysPerFile: 50, wantErr: ErrMessageTooLarge}, + } { + name := fmt.Sprintf("values=%v/files=%v/extraKeysPerFile=%v", test.values, test.files, test.extraKeysPerFile) + if test.godebug != "" { + name += fmt.Sprintf("/godebug=%v", test.godebug) + } + t.Run(name, func(t *testing.T) { + if test.godebug != "" { + t.Setenv("GODEBUG", test.godebug) + } + var buf bytes.Buffer + fw := NewWriter(&buf) + for i := 0; i < test.values; i++ { + w, _ := fw.CreateFormField(fmt.Sprintf("field%v", i)) + fmt.Fprintf(w, "value %v", i) + } + for i := 0; i < test.files; i++ { + h := make(textproto.MIMEHeader) + h.Set("Content-Disposition", + fmt.Sprintf(`form-data; name="file%v"; filename="file%v"`, i, i)) + h.Set("Content-Type", "application/octet-stream") + for j := 0; j < test.extraKeysPerFile; j++ { + h.Set(fmt.Sprintf("k%v", j), "v") + } + w, _ := fw.CreatePart(h) + fmt.Fprintf(w, "value %v", i) + } + if err := fw.Close(); err != nil { + t.Fatal(err) + } + fr := NewReader(bytes.NewReader(buf.Bytes()), fw.Boundary()) + form, err := fr.ReadForm(1 << 10) + if err == nil { + defer form.RemoveAll() + } + if err != test.wantErr { + t.Errorf("ReadForm = %v, want %v", err, test.wantErr) + } + }) + } +} + func BenchmarkReadForm(b *testing.B) { for _, test := range []struct { name string diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go index 86ea926346eb5f..7b25db9ceca604 100644 --- a/src/mime/multipart/multipart.go +++ b/src/mime/multipart/multipart.go @@ -16,11 +16,13 @@ import ( "bufio" "bytes" "fmt" + "internal/godebug" "io" "mime" "mime/quotedprintable" "net/textproto" "path/filepath" + "strconv" "strings" ) @@ -128,12 +130,12 @@ func (r *stickyErrorReader) Read(p []byte) (n int, _ error) { return n, r.err } -func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { +func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize, maxMIMEHeaders int64) (*Part, error) { bp := &Part{ Header: make(map[string][]string), mr: mr, } - if err := bp.populateHeaders(maxMIMEHeaderSize); err != nil { + if err := bp.populateHeaders(maxMIMEHeaderSize, maxMIMEHeaders); err != nil { return nil, err } bp.r = partReader{bp} @@ -149,9 +151,9 @@ func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { return bp, nil } -func (p *Part) populateHeaders(maxMIMEHeaderSize int64) error { +func (p *Part) populateHeaders(maxMIMEHeaderSize, maxMIMEHeaders int64) error { r := textproto.NewReader(p.mr.bufReader) - header, err := readMIMEHeader(r, maxMIMEHeaderSize) + header, err := readMIMEHeader(r, maxMIMEHeaderSize, maxMIMEHeaders) if err == nil { p.Header = header } @@ -330,6 +332,20 @@ type Reader struct { // including header keys, values, and map overhead. const maxMIMEHeaderSize = 10 << 20 +// multipartMaxHeaders is the maximum number of header entries NextPart will return, +// as well as the maximum combined total of header entries Reader.ReadForm will return +// in FileHeaders. +var multipartMaxHeaders = godebug.New("multipartmaxheaders") + +func maxMIMEHeaders() int64 { + if s := multipartMaxHeaders.Value(); s != "" { + if v, err := strconv.ParseInt(s, 10, 64); err == nil && v >= 0 { + return v + } + } + return 10000 +} + // NextPart returns the next part in the multipart or an error. // When there are no more parts, the error io.EOF is returned. // @@ -337,7 +353,7 @@ const maxMIMEHeaderSize = 10 << 20 // 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, maxMIMEHeaderSize) + return r.nextPart(false, maxMIMEHeaderSize, maxMIMEHeaders()) } // NextRawPart returns the next part in the multipart or an error. @@ -346,10 +362,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, maxMIMEHeaderSize) + return r.nextPart(true, maxMIMEHeaderSize, maxMIMEHeaders()) } -func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { +func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize, maxMIMEHeaders int64) (*Part, error) { if r.currentPart != nil { r.currentPart.Close() } @@ -374,7 +390,7 @@ func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) if r.isBoundaryDelimiterLine(line) { r.partsRead++ - bp, err := newPart(r, rawPart, maxMIMEHeaderSize) + bp, err := newPart(r, rawPart, maxMIMEHeaderSize, maxMIMEHeaders) if err != nil { return nil, err } diff --git a/src/mime/multipart/readmimeheader.go b/src/mime/multipart/readmimeheader.go index 6836928c9e8b48..25aa6e2092861b 100644 --- a/src/mime/multipart/readmimeheader.go +++ b/src/mime/multipart/readmimeheader.go @@ -11,4 +11,4 @@ import ( // readMIMEHeader is defined in package net/textproto. // //go:linkname readMIMEHeader net/textproto.readMIMEHeader -func readMIMEHeader(r *textproto.Reader, lim int64) (textproto.MIMEHeader, error) +func readMIMEHeader(r *textproto.Reader, maxMemory, maxHeaders int64) (textproto.MIMEHeader, error) diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go index af82b4b9ab153a..fc2590b1cdc244 100644 --- a/src/net/textproto/reader.go +++ b/src/net/textproto/reader.go @@ -479,12 +479,12 @@ var colon = []byte(":") // "Long-Key": {"Even Longer Value"}, // } func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { - return readMIMEHeader(r, math.MaxInt64) + return readMIMEHeader(r, math.MaxInt64, 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) { +func readMIMEHeader(r *Reader, maxMemory, maxHeaders 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. @@ -502,7 +502,7 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry. // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large // MIMEHeaders average about 200 bytes per entry. - lim -= 400 + maxMemory -= 400 const mapEntryOverhead = 200 // The first line cannot start with a leading space. @@ -542,16 +542,21 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { continue } + maxHeaders-- + if maxHeaders < 0 { + return nil, errors.New("message too large") + } + // Skip initial spaces in value. value := string(bytes.TrimLeft(v, " \t")) vv := m[key] if vv == nil { - lim -= int64(len(key)) - lim -= mapEntryOverhead + maxMemory -= int64(len(key)) + maxMemory -= mapEntryOverhead } - lim -= int64(len(value)) - if lim < 0 { + maxMemory -= int64(len(value)) + if maxMemory < 0 { // TODO: This should be a distinguishable error (ErrMessageTooLarge) // to allow mime/multipart to detect it. return m, errors.New("message too large") From e7c4b07ecf6b367f1afc9cc48cde963829dd0aab Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 22 Mar 2023 09:33:22 -0700 Subject: [PATCH 063/165] [release-branch.go1.20] go/scanner: reject large line and column numbers in //line directives Setting a large line or column number using a //line directive can cause integer overflow even in small source files. Limit line and column numbers in //line directives to 2^30-1, which is small enough to avoid int32 overflow on all reasonbly-sized files. Fixes CVE-2023-24537 For #59180 Fixes #59274 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802456 Reviewed-by: Julie Qiu Reviewed-by: Roland Shoemaker Run-TryBot: Damien Neil Change-Id: Ib9c5cb38428ed34ab129d451b00a2998e72c861c Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802401 TryBot-Result: Security TryBots Run-TryBot: Roland Shoemaker Reviewed-on: https://go-review.googlesource.com/c/go/+/481992 Reviewed-by: Matthew Dempsky Auto-Submit: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Bypass: Michael Knyszek --- src/go/parser/parser_test.go | 16 ++++++++++++++++ src/go/scanner/scanner.go | 7 +++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go index 153562df75068d..22b11a0cc45354 100644 --- a/src/go/parser/parser_test.go +++ b/src/go/parser/parser_test.go @@ -764,3 +764,19 @@ func TestRangePos(t *testing.T) { }) } } + +// TestIssue59180 tests that line number overflow doesn't cause an infinite loop. +func TestIssue59180(t *testing.T) { + testcases := []string{ + "package p\n//line :9223372036854775806\n\n//", + "package p\n//line :1:9223372036854775806\n\n//", + "package p\n//line file:9223372036854775806\n\n//", + } + + for _, src := range testcases { + _, err := ParseFile(token.NewFileSet(), "", src, ParseComments) + if err == nil { + t.Errorf("ParseFile(%s) succeeded unexpectedly", src) + } + } +} diff --git a/src/go/scanner/scanner.go b/src/go/scanner/scanner.go index 16958d22ce2997..0cd9f5901d0bba 100644 --- a/src/go/scanner/scanner.go +++ b/src/go/scanner/scanner.go @@ -253,13 +253,16 @@ func (s *Scanner) updateLineInfo(next, offs int, text []byte) { return } + // Put a cap on the maximum size of line and column numbers. + // 30 bits allows for some additional space before wrapping an int32. + const maxLineCol = 1<<30 - 1 var line, col int i2, n2, ok2 := trailingDigits(text[:i-1]) if ok2 { //line filename:line:col i, i2 = i2, i line, col = n2, n - if col == 0 { + if col == 0 || col > maxLineCol { s.error(offs+i2, "invalid column number: "+string(text[i2:])) return } @@ -269,7 +272,7 @@ func (s *Scanner) updateLineInfo(next, offs int, text []byte) { line = n } - if line == 0 { + if line == 0 || line > maxLineCol { s.error(offs+i, "invalid line number: "+string(text[i:])) return } From 20374d1d759bc4e17486bde1cb9dca5be37d9e52 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Mon, 20 Mar 2023 11:01:13 -0700 Subject: [PATCH 064/165] [release-branch.go1.20] html/template: disallow actions in JS template literals ECMAScript 6 introduced template literals[0][1] which are delimited with backticks. These need to be escaped in a similar fashion to the delimiters for other string literals. Additionally template literals can contain special syntax for string interpolation. There is no clear way to allow safe insertion of actions within JS template literals, as handling (JS) string interpolation inside of these literals is rather complex. As such we've chosen to simply disallow template actions within these template literals. A new error code is added for this parsing failure case, errJsTmplLit, but it is unexported as it is not backwards compatible with other minor release versions to introduce an API change in a minor release. We will export this code in the next major release. The previous behavior (with the cavet that backticks are now escaped properly) can be re-enabled with GODEBUG=jstmpllitinterp=1. This change subsumes CL471455. Thanks to Sohom Datta, Manipal Institute of Technology, for reporting this issue. Fixes CVE-2023-24538 For #59234 Fixes #59272 [0] https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-template-literals [1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals Change-Id: Idff74ec386e9b73d6e9a3c9f71990eabc0ce7506 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802457 Reviewed-by: Damien Neil Run-TryBot: Damien Neil Reviewed-by: Julie Qiu Reviewed-by: Roland Shoemaker Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802688 Run-TryBot: Roland Shoemaker Reviewed-on: https://go-review.googlesource.com/c/go/+/481993 Run-TryBot: Michael Knyszek Auto-Submit: Michael Knyszek TryBot-Bypass: Michael Knyszek Reviewed-by: Matthew Dempsky --- src/html/template/context.go | 2 + src/html/template/error.go | 13 ++++++ src/html/template/escape.go | 12 ++++++ src/html/template/escape_test.go | 66 +++++++++++++++++-------------- src/html/template/js.go | 2 + src/html/template/js_test.go | 2 +- src/html/template/jsctx_string.go | 9 +++++ src/html/template/state_string.go | 37 ++++++++++++++++- src/html/template/transition.go | 7 +++- 9 files changed, 117 insertions(+), 33 deletions(-) diff --git a/src/html/template/context.go b/src/html/template/context.go index a97c8be56f958e..c28fb0c5ea8ef3 100644 --- a/src/html/template/context.go +++ b/src/html/template/context.go @@ -120,6 +120,8 @@ const ( stateJSDqStr // stateJSSqStr occurs inside a JavaScript single quoted string. stateJSSqStr + // stateJSBqStr occurs inside a JavaScript back quoted string. + stateJSBqStr // stateJSRegexp occurs inside a JavaScript regexp literal. stateJSRegexp // stateJSBlockCmt occurs inside a JavaScript /* block comment */. diff --git a/src/html/template/error.go b/src/html/template/error.go index 5c51f772cbde36..d7d6f5b3ab589e 100644 --- a/src/html/template/error.go +++ b/src/html/template/error.go @@ -214,6 +214,19 @@ const ( // pipeline occurs in an unquoted attribute value context, "html" is // disallowed. Avoid using "html" and "urlquery" entirely in new templates. ErrPredefinedEscaper + + // errJSTmplLit: "... appears in a JS template literal" + // Example: + // + // Discussion: + // Package html/template does not support actions inside of JS template + // literals. + // + // TODO(rolandshoemaker): we cannot add this as an exported error in a minor + // release, since it is backwards incompatible with the other minor + // releases. As such we need to leave it unexported, and then we'll add it + // in the next major release. + errJSTmplLit ) func (e *Error) Error() string { diff --git a/src/html/template/escape.go b/src/html/template/escape.go index 54fbcdca333549..23ece7a72fbacc 100644 --- a/src/html/template/escape.go +++ b/src/html/template/escape.go @@ -8,6 +8,7 @@ import ( "bytes" "fmt" "html" + "internal/godebug" "io" "text/template" "text/template/parse" @@ -160,6 +161,8 @@ func (e *escaper) escape(c context, n parse.Node) context { panic("escaping " + n.String() + " is unimplemented") } +var debugAllowActionJSTmpl = godebug.New("jstmpllitinterp") + // escapeAction escapes an action template node. func (e *escaper) escapeAction(c context, n *parse.ActionNode) context { if len(n.Pipe.Decl) != 0 { @@ -223,6 +226,15 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context { c.jsCtx = jsCtxDivOp case stateJSDqStr, stateJSSqStr: s = append(s, "_html_template_jsstrescaper") + case stateJSBqStr: + if debugAllowActionJSTmpl.Value() == "1" { + s = append(s, "_html_template_jsstrescaper") + } else { + return context{ + state: stateError, + err: errorf(errJSTmplLit, n, n.Line, "%s appears in a JS template literal", n), + } + } case stateJSRegexp: s = append(s, "_html_template_jsregexpescaper") case stateCSS: diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go index 12add077c3c38d..3dd212bac94061 100644 --- a/src/html/template/escape_test.go +++ b/src/html/template/escape_test.go @@ -681,35 +681,31 @@ func TestEscape(t *testing.T) { } for _, test := range tests { - tmpl := New(test.name) - tmpl = Must(tmpl.Parse(test.input)) - // Check for bug 6459: Tree field was not set in Parse. - if tmpl.Tree != tmpl.text.Tree { - t.Errorf("%s: tree not set properly", test.name) - continue - } - b := new(strings.Builder) - if err := tmpl.Execute(b, data); err != nil { - t.Errorf("%s: template execution failed: %s", test.name, err) - continue - } - if w, g := test.output, b.String(); w != g { - t.Errorf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g) - continue - } - b.Reset() - if err := tmpl.Execute(b, pdata); err != nil { - t.Errorf("%s: template execution failed for pointer: %s", test.name, err) - continue - } - if w, g := test.output, b.String(); w != g { - t.Errorf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g) - continue - } - if tmpl.Tree != tmpl.text.Tree { - t.Errorf("%s: tree mismatch", test.name) - continue - } + t.Run(test.name, func(t *testing.T) { + tmpl := New(test.name) + tmpl = Must(tmpl.Parse(test.input)) + // Check for bug 6459: Tree field was not set in Parse. + if tmpl.Tree != tmpl.text.Tree { + t.Fatalf("%s: tree not set properly", test.name) + } + b := new(strings.Builder) + if err := tmpl.Execute(b, data); err != nil { + t.Fatalf("%s: template execution failed: %s", test.name, err) + } + if w, g := test.output, b.String(); w != g { + t.Fatalf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g) + } + b.Reset() + if err := tmpl.Execute(b, pdata); err != nil { + t.Fatalf("%s: template execution failed for pointer: %s", test.name, err) + } + if w, g := test.output, b.String(); w != g { + t.Fatalf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g) + } + if tmpl.Tree != tmpl.text.Tree { + t.Fatalf("%s: tree mismatch", test.name) + } + }) } } @@ -936,6 +932,10 @@ func TestErrors(t *testing.T) { "{{range .Items}}{{if .X}}{{break}}{{end}}{{end}}", "", }, + { + "`", + "", + }, // Error cases. { "{{if .Cond}}var tmpl = `asd {{.}}`;", + `{{.}} appears in a JS template literal`, + }, } for _, test := range tests { buf := new(bytes.Buffer) @@ -1303,6 +1307,10 @@ func TestEscapeText(t *testing.T) { `= state(len(_state_index)-1) { diff --git a/src/html/template/transition.go b/src/html/template/transition.go index 06df679330db2c..92eb3519063c9e 100644 --- a/src/html/template/transition.go +++ b/src/html/template/transition.go @@ -27,6 +27,7 @@ var transitionFunc = [...]func(context, []byte) (context, int){ stateJS: tJS, stateJSDqStr: tJSDelimited, stateJSSqStr: tJSDelimited, + stateJSBqStr: tJSDelimited, stateJSRegexp: tJSDelimited, stateJSBlockCmt: tBlockCmt, stateJSLineCmt: tLineCmt, @@ -262,7 +263,7 @@ func tURL(c context, s []byte) (context, int) { // tJS is the context transition function for the JS state. func tJS(c context, s []byte) (context, int) { - i := bytes.IndexAny(s, `"'/`) + i := bytes.IndexAny(s, "\"`'/") if i == -1 { // Entire input is non string, comment, regexp tokens. c.jsCtx = nextJSCtx(s, c.jsCtx) @@ -274,6 +275,8 @@ func tJS(c context, s []byte) (context, int) { c.state, c.jsCtx = stateJSDqStr, jsCtxRegexp case '\'': c.state, c.jsCtx = stateJSSqStr, jsCtxRegexp + case '`': + c.state, c.jsCtx = stateJSBqStr, jsCtxRegexp case '/': switch { case i+1 < len(s) && s[i+1] == '/': @@ -303,6 +306,8 @@ func tJSDelimited(c context, s []byte) (context, int) { switch c.state { case stateJSSqStr: specials = `\'` + case stateJSBqStr: + specials = "`\\" case stateJSRegexp: specials = `\/[]` } From 7c47a6b15782b13ecb76fd3c6c18e5f1edc34733 Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Tue, 4 Apr 2023 17:05:20 +0000 Subject: [PATCH 065/165] [release-branch.go1.20] go1.20.3 Change-Id: I1ca3074262203c6f250c902ca087d244edf9eb96 Reviewed-on: https://go-review.googlesource.com/c/go/+/482097 TryBot-Bypass: Michael Knyszek Reviewed-by: Michael Knyszek Run-TryBot: Gopher Robot Auto-Submit: Gopher Robot Reviewed-by: Matthew Dempsky --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3acbb8feaf843b..95a9a4cba6de90 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -go1.20.2 \ No newline at end of file +go1.20.3 \ No newline at end of file From 5c7c20e262bdef14c23bd07950bde94ba335ee63 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Tue, 4 Apr 2023 22:07:09 +0000 Subject: [PATCH 066/165] [release-branch.go1.20] html/template,mime/multipart: document new GODEBUG settings This change documents the new GODEBUG settings introduced for html/template and mime/multipart, released with Go 1.19.8 and Go 1.20.3 as part of a security fix. Updates #59153. For #59270. Updates #59234. For #59272. Change-Id: I25f4d8245da3301dccccfb44da8ff1a5985392a4 Reviewed-on: https://go-review.googlesource.com/c/go/+/482555 TryBot-Result: Gopher Robot Auto-Submit: Michael Knyszek Reviewed-by: Damien Neil Run-TryBot: Michael Knyszek --- src/html/template/doc.go | 7 +++++++ src/mime/multipart/multipart.go | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/html/template/doc.go b/src/html/template/doc.go index 5d1631b266361e..ce7b094d9a1fb7 100644 --- a/src/html/template/doc.go +++ b/src/html/template/doc.go @@ -231,5 +231,12 @@ Least Surprise Property: "A developer (or code reviewer) familiar with HTML, CSS, and JavaScript, who knows that contextual autoescaping happens should be able to look at a {{.}} and correctly infer what sanitization happens." + +As a consequence of the Least Surprise Property, template actions within an +ECMAScript 6 template literal are disabled by default. +Handling string interpolation within these literals is rather complex resulting +in no clear safe way to support it. +To re-enable template actions within ECMAScript 6 template literals, use the +GODEBUG=jstmpllitinterp=1 environment variable. */ package template diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go index 7b25db9ceca604..066aa70286efc4 100644 --- a/src/mime/multipart/multipart.go +++ b/src/mime/multipart/multipart.go @@ -9,6 +9,21 @@ Package multipart implements MIME multipart parsing, as defined in RFC The implementation is sufficient for HTTP (RFC 2388) and the multipart bodies generated by popular browsers. + +# Limits + +To protect against malicious inputs, this package sets limits on the size +of the MIME data it processes. + +Reader.NextPart and Reader.NextRawPart limit the number of headers in a +part to 10000 and Reader.ReadForm limits the total number of headers in all +FileHeaders to 10000. +These limits may be adjusted with the GODEBUG=multipartmaxheaders= +setting. + +Reader.ReadForm further limits the number of parts in a form to 1000. +This limit may be adjusted with the GODEBUG=multipartmaxparts= +setting. */ package multipart From dcc9bdf38037af6197f3f50968badb1f0db82e10 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 30 Mar 2023 09:52:39 -0700 Subject: [PATCH 067/165] [release-branch.go1.20] crypto/subtle: don't cast to *uintptr when word size is 0 Casting to a *uintptr is not ok if there isn't at least 8 bytes of data backing that pointer (on 64-bit archs). So although we end up making a slice of 0 length with that pointer, the cast itself doesn't know that. Instead, bail early if the result is going to be 0 length. Fixes #59336 Change-Id: Id3c0e09d341d838835c0382cccfb0f71dc3dc7e6 Reviewed-on: https://go-review.googlesource.com/c/go/+/480575 Run-TryBot: Keith Randall Reviewed-by: Cherry Mui Reviewed-by: Matthew Dempsky Reviewed-by: Emmanuel Odeke TryBot-Result: Gopher Robot Reviewed-by: Bryan Mills (cherry picked from commit 297cf6dd31bd99fc4ccda320aa3d4faf290ab278) Reviewed-on: https://go-review.googlesource.com/c/go/+/481238 Reviewed-by: Keith Randall Auto-Submit: Michael Knyszek Run-TryBot: Michael Knyszek --- src/crypto/subtle/xor_generic.go | 8 +++++++- test/fixedbugs/issue59334.go | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue59334.go diff --git a/src/crypto/subtle/xor_generic.go b/src/crypto/subtle/xor_generic.go index 482fcf9b4bffcb..7dc89e315be4a4 100644 --- a/src/crypto/subtle/xor_generic.go +++ b/src/crypto/subtle/xor_generic.go @@ -46,7 +46,13 @@ func aligned(dst, x, y *byte) bool { // words returns a []uintptr pointing at the same data as x, // with any trailing partial word removed. func words(x []byte) []uintptr { - return unsafe.Slice((*uintptr)(unsafe.Pointer(&x[0])), uintptr(len(x))/wordSize) + n := uintptr(len(x)) / wordSize + if n == 0 { + // Avoid creating a *uintptr that refers to data smaller than a uintptr; + // see issue 59334. + return nil + } + return unsafe.Slice((*uintptr)(unsafe.Pointer(&x[0])), n) } func xorLoop[T byte | uintptr](dst, x, y []T) { diff --git a/test/fixedbugs/issue59334.go b/test/fixedbugs/issue59334.go new file mode 100644 index 00000000000000..06c12cf92ffe6f --- /dev/null +++ b/test/fixedbugs/issue59334.go @@ -0,0 +1,18 @@ +// run -tags=purego -gcflags=all=-d=checkptr + +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "crypto/subtle" + +func main() { + dst := make([]byte, 5) + src := make([]byte, 5) + for _, n := range []int{1024, 2048} { // just to make the size non-constant + b := make([]byte, n) + subtle.XORBytes(dst, src, b[n-5:]) + } +} From 99001c460e9c552c9ccc8a65c428bbe4d6128085 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Mon, 3 Apr 2023 11:18:45 +0700 Subject: [PATCH 068/165] [release-branch.go1.20] cmd/compile: don't set range expr key/value type if already set Unified IR already records the correct type for them. Fixes #59450 Change-Id: I275c45b48f67bde55c8e2079d60b5868d0acde7f Reviewed-on: https://go-review.googlesource.com/c/go/+/481555 Reviewed-by: Michael Knyszek Auto-Submit: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Gopher Robot Reviewed-by: Matthew Dempsky Reviewed-on: https://go-review.googlesource.com/c/go/+/482655 Auto-Submit: Michael Knyszek --- src/cmd/compile/internal/typecheck/stmt.go | 2 +- test/fixedbugs/issue59378.go | 26 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue59378.go diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go index 9d57edb39fc36a..fca06deaa10d51 100644 --- a/src/cmd/compile/internal/typecheck/stmt.go +++ b/src/cmd/compile/internal/typecheck/stmt.go @@ -71,7 +71,7 @@ func typecheckrangeExpr(n *ir.RangeStmt) { do := func(nn ir.Node, t *types.Type) { if nn != nil { - if ir.DeclaredBy(nn, n) { + if ir.DeclaredBy(nn, n) && nn.Type() == nil { nn.SetType(t) } else if nn.Type() != nil { if op, why := Assignop(t, nn.Type()); op == ir.OXXX { diff --git a/test/fixedbugs/issue59378.go b/test/fixedbugs/issue59378.go new file mode 100644 index 00000000000000..8ff198eaa7bec3 --- /dev/null +++ b/test/fixedbugs/issue59378.go @@ -0,0 +1,26 @@ +// 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 + +func f() { + F([]int{}, func(*int) bool { return true }) +} + +func F[S []E, E any](a S, fn func(*E) bool) { + for _, v := range a { + G(a, func(e E) bool { return fn(&v) }) + } +} + +func G[E any](s []E, f func(E) bool) int { + for i, v := range s { + if f(v) { + return i + } + } + return -1 +} From 1dbbac7d796041eac4791fc0caa9315bd50ea964 Mon Sep 17 00:00:00 2001 From: Junwei Zuo Date: Wed, 12 Apr 2023 18:53:51 +0800 Subject: [PATCH 069/165] [release-branch.go1.20] cmd/compile: fix ir.StaticValue for ORANGE Range statement will mutate the key and value, so we should treat them as reassigned. Fixes #59580 Change-Id: I9c6b67d938760a0c6a1d9739f2737c67af4a3a10 Reviewed-on: https://go-review.googlesource.com/c/go/+/483855 Run-TryBot: Wayne Zuo TryBot-Result: Gopher Robot Reviewed-by: Matthew Dempsky Auto-Submit: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Keith Randall (cherry picked from commit 89567a35c11c343cf765d6fb1270e1250e50d83f) Reviewed-on: https://go-review.googlesource.com/c/go/+/484136 Run-TryBot: Matthew Dempsky --- src/cmd/compile/internal/ir/expr.go | 5 +++++ test/fixedbugs/issue59572.go | 30 +++++++++++++++++++++++++++++ test/fixedbugs/issue59572.out | 3 +++ 3 files changed, 38 insertions(+) create mode 100644 test/fixedbugs/issue59572.go create mode 100644 test/fixedbugs/issue59572.out diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index a481b14f8b94c0..e549c08d0c1447 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -959,6 +959,11 @@ func reassigned(name *Name) bool { if isName(OuterValue(n.X)) { return true } + case ORANGE: + n := n.(*RangeStmt) + if isName(n.Key) || isName(n.Value) { + return true + } case OCLOSURE: n := n.(*ClosureExpr) if Any(n.Func, do) { diff --git a/test/fixedbugs/issue59572.go b/test/fixedbugs/issue59572.go new file mode 100644 index 00000000000000..a16817aec0a2a7 --- /dev/null +++ b/test/fixedbugs/issue59572.go @@ -0,0 +1,30 @@ +// 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 + +func foo() { + println("foo") +} + +func main() { + fn := foo + for _, fn = range list { + fn() + } +} + +var list = []func(){ + func() { + println("1") + }, + func() { + println("2") + }, + func() { + println("3") + }, +} diff --git a/test/fixedbugs/issue59572.out b/test/fixedbugs/issue59572.out new file mode 100644 index 00000000000000..01e79c32a8c99c --- /dev/null +++ b/test/fixedbugs/issue59572.out @@ -0,0 +1,3 @@ +1 +2 +3 From ecf7e00db8b8f5fff622f232bd8c515814c2ecc6 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 22 Mar 2023 13:17:58 -0700 Subject: [PATCH 070/165] [release-branch.go1.20] syscall: restore original NOFILE rlimit in child process If we increased the NOFILE rlimit when starting the program, restore the original rlimit when forking a child process. In CL 393354 the os package was changed to raise the open file rlimit at program start. That code is not inherently tied to the os package. This CL moves it into the syscall package. This is a backport of CLs 476096 and 476097 from trunk. For #46279 Fixes #59064 Change-Id: Ib813de896de0a5d28fa2b29afdf414a89fbe7b2a Reviewed-on: https://go-review.googlesource.com/c/go/+/478659 Run-TryBot: Ian Lance Taylor TryBot-Result: Gopher Robot Reviewed-by: David Chase Reviewed-by: Michael Knyszek Reviewed-by: Tobias Klauser --- src/runtime/syscall2_solaris.go | 2 ++ src/runtime/syscall_aix.go | 10 ++++++ src/runtime/syscall_solaris.go | 14 +++++++++ src/syscall/asm_solaris_amd64.s | 3 ++ src/syscall/exec_bsd.go | 7 +++++ src/syscall/exec_freebsd.go | 7 +++++ src/syscall/exec_libc.go | 8 +++++ src/syscall/exec_libc2.go | 7 +++++ src/syscall/exec_linux.go | 7 +++++ src/syscall/exec_unix.go | 5 +++ src/syscall/exec_unix_test.go | 42 +++++++++++++++++++++++++ src/syscall/export_rlimit_test.go | 14 +++++++++ src/{os => syscall}/rlimit.go | 28 ++++++++++++++--- src/{os => syscall}/rlimit_darwin.go | 8 ++--- src/{os => syscall}/rlimit_stub.go | 6 ++-- src/{os => syscall}/rlimit_test.go | 8 ++--- src/syscall/syscall_aix.go | 2 +- src/syscall/syscall_darwin.go | 2 +- src/syscall/syscall_dragonfly.go | 2 +- src/syscall/syscall_freebsd.go | 2 +- src/syscall/syscall_linux.go | 13 +++++++- src/syscall/syscall_linux_386.go | 33 +++++++++++++++++-- src/syscall/syscall_linux_amd64.go | 12 ++++++- src/syscall/syscall_linux_arm.go | 33 +++++++++++++++++-- src/syscall/syscall_linux_arm64.go | 18 ++++++++--- src/syscall/syscall_linux_loong64.go | 10 ++++-- src/syscall/syscall_linux_mips64x.go | 12 ++++++- src/syscall/syscall_linux_mipsx.go | 33 +++++++++++++++++-- src/syscall/syscall_linux_ppc64x.go | 12 ++++++- src/syscall/syscall_linux_riscv64.go | 8 ++++- src/syscall/syscall_linux_s390x.go | 8 ++++- src/syscall/syscall_netbsd.go | 2 +- src/syscall/syscall_openbsd.go | 2 +- src/syscall/syscall_solaris.go | 2 +- src/syscall/zsyscall_aix_ppc64.go | 2 +- src/syscall/zsyscall_darwin_amd64.go | 2 +- src/syscall/zsyscall_darwin_arm64.go | 2 +- src/syscall/zsyscall_dragonfly_amd64.go | 2 +- src/syscall/zsyscall_freebsd_386.go | 2 +- src/syscall/zsyscall_freebsd_amd64.go | 2 +- src/syscall/zsyscall_freebsd_arm.go | 2 +- src/syscall/zsyscall_freebsd_arm64.go | 2 +- src/syscall/zsyscall_freebsd_riscv64.go | 2 +- src/syscall/zsyscall_linux_386.go | 4 +-- src/syscall/zsyscall_linux_amd64.go | 4 +-- src/syscall/zsyscall_linux_arm.go | 4 +-- src/syscall/zsyscall_linux_arm64.go | 4 +-- src/syscall/zsyscall_linux_loong64.go | 2 +- src/syscall/zsyscall_linux_mips.go | 4 +-- src/syscall/zsyscall_linux_mips64.go | 4 +-- src/syscall/zsyscall_linux_mips64le.go | 4 +-- src/syscall/zsyscall_linux_mipsle.go | 4 +-- src/syscall/zsyscall_linux_ppc64.go | 4 +-- src/syscall/zsyscall_linux_ppc64le.go | 4 +-- src/syscall/zsyscall_linux_riscv64.go | 4 +-- src/syscall/zsyscall_linux_s390x.go | 4 +-- src/syscall/zsyscall_netbsd_386.go | 2 +- src/syscall/zsyscall_netbsd_amd64.go | 2 +- src/syscall/zsyscall_netbsd_arm.go | 2 +- src/syscall/zsyscall_netbsd_arm64.go | 2 +- src/syscall/zsyscall_openbsd_386.go | 2 +- src/syscall/zsyscall_openbsd_amd64.go | 2 +- src/syscall/zsyscall_openbsd_arm.go | 2 +- src/syscall/zsyscall_openbsd_arm64.go | 2 +- src/syscall/zsyscall_openbsd_mips64.go | 2 +- src/syscall/zsyscall_solaris_amd64.go | 2 +- 66 files changed, 380 insertions(+), 90 deletions(-) create mode 100644 src/syscall/export_rlimit_test.go rename src/{os => syscall}/rlimit.go (58%) rename src/{os => syscall}/rlimit_darwin.go (79%) rename src/{os => syscall}/rlimit_stub.go (82%) rename src/{os => syscall}/rlimit_test.go (91%) diff --git a/src/runtime/syscall2_solaris.go b/src/runtime/syscall2_solaris.go index 33104892021223..d464f284bcb2f4 100644 --- a/src/runtime/syscall2_solaris.go +++ b/src/runtime/syscall2_solaris.go @@ -17,6 +17,7 @@ import _ "unsafe" // for go:linkname //go:cgo_import_dynamic libc_ioctl ioctl "libc.so" //go:cgo_import_dynamic libc_setgid setgid "libc.so" //go:cgo_import_dynamic libc_setgroups setgroups "libc.so" +//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.so" //go:cgo_import_dynamic libc_setsid setsid "libc.so" //go:cgo_import_dynamic libc_setuid setuid "libc.so" //go:cgo_import_dynamic libc_setpgid setpgid "libc.so" @@ -34,6 +35,7 @@ import _ "unsafe" // for go:linkname //go:linkname libc_ioctl libc_ioctl //go:linkname libc_setgid libc_setgid //go:linkname libc_setgroups libc_setgroups +//go:linkname libc_setrlimit libc_setrlimit //go:linkname libc_setsid libc_setsid //go:linkname libc_setuid libc_setuid //go:linkname libc_setpgid libc_setpgid diff --git a/src/runtime/syscall_aix.go b/src/runtime/syscall_aix.go index cc9e912613dcac..e87d4d6d7acced 100644 --- a/src/runtime/syscall_aix.go +++ b/src/runtime/syscall_aix.go @@ -18,6 +18,7 @@ import "unsafe" //go:cgo_import_dynamic libc_ioctl ioctl "libc.a/shr_64.o" //go:cgo_import_dynamic libc_setgid setgid "libc.a/shr_64.o" //go:cgo_import_dynamic libc_setgroups setgroups "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.a/shr_64.o" //go:cgo_import_dynamic libc_setsid setsid "libc.a/shr_64.o" //go:cgo_import_dynamic libc_setuid setuid "libc.a/shr_64.o" //go:cgo_import_dynamic libc_setpgid setpgid "libc.a/shr_64.o" @@ -31,6 +32,7 @@ import "unsafe" //go:linkname libc_ioctl libc_ioctl //go:linkname libc_setgid libc_setgid //go:linkname libc_setgroups libc_setgroups +//go:linkname libc_setrlimit libc_setrlimit //go:linkname libc_setsid libc_setsid //go:linkname libc_setuid libc_setuid //go:linkname libc_setpgid libc_setpgid @@ -45,6 +47,7 @@ var ( libc_ioctl, libc_setgid, libc_setgroups, + libc_setrlimit, libc_setsid, libc_setuid, libc_setpgid libFunc @@ -199,6 +202,13 @@ func syscall_setgroups1(ngid, gid uintptr) (err uintptr) { return } +//go:linkname syscall_setrlimit1 syscall.setrlimit1 +//go:nosplit +func syscall_setrlimit1(which uintptr, lim unsafe.Pointer) (err uintptr) { + _, err = syscall2(&libc_setrlimit, which, uintptr(lim)) + return +} + //go:linkname syscall_setsid syscall.setsid //go:nosplit func syscall_setsid() (pid, err uintptr) { diff --git a/src/runtime/syscall_solaris.go b/src/runtime/syscall_solaris.go index e7bab3b23fb54f..9faee9ec468952 100644 --- a/src/runtime/syscall_solaris.go +++ b/src/runtime/syscall_solaris.go @@ -18,6 +18,7 @@ var ( libc_ioctl, libc_setgid, libc_setgroups, + libc_setrlimit, libc_setsid, libc_setuid, libc_setpgid, @@ -234,6 +235,19 @@ func syscall_setgroups(ngid, gid uintptr) (err uintptr) { return call.err } +//go:nosplit +//go:linkname syscall_setrlimit +//go:cgo_unsafe_args +func syscall_setrlimit(which uintptr, lim unsafe.Pointer) (err uintptr) { + call := libcall{ + fn: uintptr(unsafe.Pointer(&libc_setrlimit)), + n: 2, + args: uintptr(unsafe.Pointer(&which)), + } + asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&call)) + return call.err +} + //go:nosplit //go:linkname syscall_setsid func syscall_setsid() (pid, err uintptr) { diff --git a/src/syscall/asm_solaris_amd64.s b/src/syscall/asm_solaris_amd64.s index 6891e9c8f96d5e..6dee29a9c71819 100644 --- a/src/syscall/asm_solaris_amd64.s +++ b/src/syscall/asm_solaris_amd64.s @@ -60,6 +60,9 @@ TEXT ·setgid(SB),NOSPLIT,$0 TEXT ·setgroups1(SB),NOSPLIT,$0 JMP runtime·syscall_setgroups(SB) +TEXT ·setrlimit1(SB),NOSPLIT,$0 + JMP runtime·syscall_setrlimit(SB) + TEXT ·setsid(SB),NOSPLIT,$0 JMP runtime·syscall_setsid(SB) diff --git a/src/syscall/exec_bsd.go b/src/syscall/exec_bsd.go index 32c3ebdd9b9fe9..db96b481448ff3 100644 --- a/src/syscall/exec_bsd.go +++ b/src/syscall/exec_bsd.go @@ -61,6 +61,8 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr i int ) + rlim, rlimOK := origRlimitNofile.Load().(Rlimit) + // guard against side effects of shuffling fds below. // Make sure that nextfd is beyond any currently open files so // that we can't run the risk of overwriting any of them. @@ -270,6 +272,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } } + // Restore original rlimit. + if rlimOK && rlim.Cur != 0 { + RawSyscall(SYS_SETRLIMIT, uintptr(RLIMIT_NOFILE), uintptr(unsafe.Pointer(&rlim)), 0) + } + // Time to exec. _, _, err1 = RawSyscall(SYS_EXECVE, uintptr(unsafe.Pointer(argv0)), diff --git a/src/syscall/exec_freebsd.go b/src/syscall/exec_freebsd.go index af5a4158f04fec..91d7eaa3f12ab4 100644 --- a/src/syscall/exec_freebsd.go +++ b/src/syscall/exec_freebsd.go @@ -66,6 +66,8 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr i int ) + rlim, rlimOK := origRlimitNofile.Load().(Rlimit) + // Record parent PID so child can test if it has died. ppid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) @@ -283,6 +285,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } } + // Restore original rlimit. + if rlimOK && rlim.Cur != 0 { + RawSyscall(SYS_SETRLIMIT, uintptr(RLIMIT_NOFILE), uintptr(unsafe.Pointer(&rlim)), 0) + } + // Time to exec. _, _, err1 = RawSyscall(SYS_EXECVE, uintptr(unsafe.Pointer(argv0)), diff --git a/src/syscall/exec_libc.go b/src/syscall/exec_libc.go index ef0c87e03c461f..c83f261cf7ec44 100644 --- a/src/syscall/exec_libc.go +++ b/src/syscall/exec_libc.go @@ -53,6 +53,7 @@ func getpid() (pid uintptr, err Errno) func ioctl(fd uintptr, req uintptr, arg uintptr) (err Errno) func setgid(gid uintptr) (err Errno) func setgroups1(ngid uintptr, gid uintptr) (err Errno) +func setrlimit1(which uintptr, lim unsafe.Pointer) (err Errno) func setsid() (pid uintptr, err Errno) func setuid(uid uintptr) (err Errno) func setpgid(pid uintptr, pgid uintptr) (err Errno) @@ -87,6 +88,8 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr i int ) + rlim, rlimOK := origRlimitNofile.Load().(Rlimit) + // guard against side effects of shuffling fds below. // Make sure that nextfd is beyond any currently open files so // that we can't run the risk of overwriting any of them. @@ -289,6 +292,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } } + // Restore original rlimit. + if rlimOK && rlim.Cur != 0 { + setrlimit1(RLIMIT_NOFILE, unsafe.Pointer(&rlim)) + } + // Time to exec. err1 = execve( uintptr(unsafe.Pointer(argv0)), diff --git a/src/syscall/exec_libc2.go b/src/syscall/exec_libc2.go index 41bc79a721e7d4..88d3b60b4d9cab 100644 --- a/src/syscall/exec_libc2.go +++ b/src/syscall/exec_libc2.go @@ -62,6 +62,8 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr i int ) + rlim, rlimOK := origRlimitNofile.Load().(Rlimit) + // guard against side effects of shuffling fds below. // Make sure that nextfd is beyond any currently open files so // that we can't run the risk of overwriting any of them. @@ -266,6 +268,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } } + // Restore original rlimit. + if rlimOK && rlim.Cur != 0 { + rawSyscall(abi.FuncPCABI0(libc_setrlimit_trampoline), uintptr(RLIMIT_NOFILE), uintptr(unsafe.Pointer(&rlim)), 0) + } + // Time to exec. _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_execve_trampoline), uintptr(unsafe.Pointer(argv0)), diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index 7e0c3d250bcb98..dcb3d51b5f7298 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -228,6 +228,8 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att clone3 *cloneArgs ) + rlim, rlimOK := origRlimitNofile.Load().(Rlimit) + if sys.UidMappings != nil { puid = []byte("/proc/self/uid_map\000") uidmap = formatIDMappings(sys.UidMappings) @@ -592,6 +594,11 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att } } + // Restore original rlimit. + if rlimOK && rlim.Cur != 0 { + rawSetrlimit(RLIMIT_NOFILE, &rlim) + } + // Enable tracing if requested. // Do this right before exec so that we don't unnecessarily trace the runtime // setting up after the fork. See issue #21428. diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go index 286be454d88f02..40e9b9feda5493 100644 --- a/src/syscall/exec_unix.go +++ b/src/syscall/exec_unix.go @@ -282,6 +282,11 @@ func Exec(argv0 string, argv []string, envv []string) (err error) { } runtime_BeforeExec() + rlim, rlimOK := origRlimitNofile.Load().(Rlimit) + if rlimOK && rlim.Cur != 0 { + Setrlimit(RLIMIT_NOFILE, &rlim) + } + var err1 error if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" || runtime.GOOS == "aix" { // RawSyscall should never be used on Solaris, illumos, or AIX. diff --git a/src/syscall/exec_unix_test.go b/src/syscall/exec_unix_test.go index 4253cda5cb6c7d..f8f09df749bc09 100644 --- a/src/syscall/exec_unix_test.go +++ b/src/syscall/exec_unix_test.go @@ -7,12 +7,15 @@ package syscall_test import ( + "bytes" + "fmt" "internal/testenv" "io" "math/rand" "os" "os/exec" "os/signal" + "strconv" "syscall" "testing" "time" @@ -345,3 +348,42 @@ func TestExecHelper(t *testing.T) { t.Error("syscall.Exec returned") } + +// Test that rlimit values are restored by exec. +func TestRlimitRestored(t *testing.T) { + if os.Getenv("GO_WANT_HELPER_PROCESS") != "" { + fmt.Println(syscall.OrigRlimitNofile().Cur) + os.Exit(0) + } + + orig := syscall.OrigRlimitNofile() + if orig.Cur == 0 { + t.Skip("skipping test because rlimit not adjusted at startup") + } + + executable, err := os.Executable() + if err != nil { + executable = os.Args[0] + } + + cmd := testenv.Command(t, executable, "-test.run=TestRlimitRestored") + cmd = testenv.CleanCmdEnv(cmd) + cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1") + + out, err := cmd.CombinedOutput() + if len(out) > 0 { + t.Logf("%s", out) + } + if err != nil { + t.Fatalf("subprocess failed: %v", err) + } + s := string(bytes.TrimSpace(out)) + v, err := strconv.ParseUint(s, 10, 64) + if err != nil { + t.Fatalf("could not parse %q as number: %v", s, v) + } + + if v != uint64(orig.Cur) { + t.Errorf("exec rlimit = %d, want %d", v, orig) + } +} diff --git a/src/syscall/export_rlimit_test.go b/src/syscall/export_rlimit_test.go new file mode 100644 index 00000000000000..320e331c5882ea --- /dev/null +++ b/src/syscall/export_rlimit_test.go @@ -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. + +//go:build unix + +package syscall + +func OrigRlimitNofile() Rlimit { + if rlim, ok := origRlimitNofile.Load().(Rlimit); ok { + return rlim + } + return Rlimit{0, 0} +} diff --git a/src/os/rlimit.go b/src/syscall/rlimit.go similarity index 58% rename from src/os/rlimit.go rename to src/syscall/rlimit.go index e0d0ef9b621d23..cc7935d37be12a 100644 --- a/src/os/rlimit.go +++ b/src/syscall/rlimit.go @@ -4,9 +4,16 @@ //go:build unix -package os +package syscall -import "syscall" +import ( + "sync/atomic" +) + +// origRlimitNofile, if not {0, 0}, is the original soft RLIMIT_NOFILE. +// When we can assume that we are bootstrapping with Go 1.19, +// this can be atomic.Pointer[Rlimit]. +var origRlimitNofile atomic.Value // of Rlimit // Some systems set an artificially low soft limit on open file count, for compatibility // with code that uses select and its hard-coded maximum file descriptor @@ -23,10 +30,21 @@ import "syscall" // Code that really wants Go to leave the limit alone can set the hard limit, // which Go of course has no choice but to respect. func init() { - var lim syscall.Rlimit - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim); err == nil && lim.Cur != lim.Max { + var lim Rlimit + if err := Getrlimit(RLIMIT_NOFILE, &lim); err == nil && lim.Cur != lim.Max { + origRlimitNofile.Store(lim) lim.Cur = lim.Max adjustFileLimit(&lim) - syscall.Setrlimit(syscall.RLIMIT_NOFILE, &lim) + setrlimit(RLIMIT_NOFILE, &lim) + } +} + +func Setrlimit(resource int, rlim *Rlimit) error { + err := setrlimit(resource, rlim) + if err == nil && resource == RLIMIT_NOFILE { + // Store zeroes in origRlimitNofile to tell StartProcess + // to not adjust the rlimit in the child process. + origRlimitNofile.Store(Rlimit{0, 0}) } + return err } diff --git a/src/os/rlimit_darwin.go b/src/syscall/rlimit_darwin.go similarity index 79% rename from src/os/rlimit_darwin.go rename to src/syscall/rlimit_darwin.go index b28982a83a193d..73e49646b30896 100644 --- a/src/os/rlimit_darwin.go +++ b/src/syscall/rlimit_darwin.go @@ -4,15 +4,13 @@ //go:build darwin -package os - -import "syscall" +package syscall // adjustFileLimit adds per-OS limitations on the Rlimit used for RLIMIT_NOFILE. See rlimit.go. -func adjustFileLimit(lim *syscall.Rlimit) { +func adjustFileLimit(lim *Rlimit) { // On older macOS, setrlimit(RLIMIT_NOFILE, lim) with lim.Cur = infinity fails. // Set to the value of kern.maxfilesperproc instead. - n, err := syscall.SysctlUint32("kern.maxfilesperproc") + n, err := SysctlUint32("kern.maxfilesperproc") if err != nil { return } diff --git a/src/os/rlimit_stub.go b/src/syscall/rlimit_stub.go similarity index 82% rename from src/os/rlimit_stub.go rename to src/syscall/rlimit_stub.go index cbe28400c5b47d..e8f839dd991a38 100644 --- a/src/os/rlimit_stub.go +++ b/src/syscall/rlimit_stub.go @@ -4,9 +4,7 @@ //go:build aix || dragonfly || freebsd || linux || netbsd || openbsd || solaris -package os - -import "syscall" +package syscall // adjustFileLimit adds per-OS limitations on the Rlimit used for RLIMIT_NOFILE. See rlimit.go. -func adjustFileLimit(lim *syscall.Rlimit) {} +func adjustFileLimit(lim *Rlimit) {} diff --git a/src/os/rlimit_test.go b/src/syscall/rlimit_test.go similarity index 91% rename from src/os/rlimit_test.go rename to src/syscall/rlimit_test.go index c02e36f3f76a68..e48f45e3aacb75 100644 --- a/src/os/rlimit_test.go +++ b/src/syscall/rlimit_test.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package os_test +package syscall_test import ( - . "os" + "os" "runtime" "testing" ) @@ -24,9 +24,9 @@ func TestOpenFileLimit(t *testing.T) { fileCount = 768 } - var files []*File + var files []*os.File for i := 0; i < fileCount; i++ { - f, err := Open("rlimit.go") + f, err := os.Open("rlimit.go") if err != nil { t.Error(err) break diff --git a/src/syscall/syscall_aix.go b/src/syscall/syscall_aix.go index 807990f3c0c5f6..a072080f094c25 100644 --- a/src/syscall/syscall_aix.go +++ b/src/syscall/syscall_aix.go @@ -633,7 +633,7 @@ func PtraceDetach(pid int) (err error) { return ptrace64(PT_DETACH, int64(pid), //sys Setpriority(which int, who int, prio int) (err error) //sysnb Setregid(rgid int, egid int) (err error) //sysnb Setreuid(ruid int, euid int) (err error) -//sysnb Setrlimit(which int, lim *Rlimit) (err error) +//sysnb setrlimit(which int, lim *Rlimit) (err error) //sys Stat(path string, stat *Stat_t) (err error) //sys Statfs(path string, buf *Statfs_t) (err error) //sys Symlink(path string, link string) (err error) diff --git a/src/syscall/syscall_darwin.go b/src/syscall/syscall_darwin.go index a39e99dc633a86..a9639e3913ac5d 100644 --- a/src/syscall/syscall_darwin.go +++ b/src/syscall/syscall_darwin.go @@ -195,7 +195,7 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1) //sys Setprivexec(flag int) (err error) //sysnb Setregid(rgid int, egid int) (err error) //sysnb Setreuid(ruid int, euid int) (err error) -//sysnb Setrlimit(which int, lim *Rlimit) (err error) +//sysnb setrlimit(which int, lim *Rlimit) (err error) //sysnb Setsid() (pid int, err error) //sysnb Settimeofday(tp *Timeval) (err error) //sysnb Setuid(uid int) (err error) diff --git a/src/syscall/syscall_dragonfly.go b/src/syscall/syscall_dragonfly.go index 1a1f1f69425647..6cb506b3009d5d 100644 --- a/src/syscall/syscall_dragonfly.go +++ b/src/syscall/syscall_dragonfly.go @@ -240,7 +240,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { //sys Setpriority(which int, who int, prio int) (err error) //sysnb Setregid(rgid int, egid int) (err error) //sysnb Setreuid(ruid int, euid int) (err error) -//sysnb Setrlimit(which int, lim *Rlimit) (err error) +//sysnb setrlimit(which int, lim *Rlimit) (err error) //sysnb Setsid() (pid int, err error) //sysnb Settimeofday(tp *Timeval) (err error) //sysnb Setuid(uid int) (err error) diff --git a/src/syscall/syscall_freebsd.go b/src/syscall/syscall_freebsd.go index 0f3912644b86d0..a0faa817eaf2de 100644 --- a/src/syscall/syscall_freebsd.go +++ b/src/syscall/syscall_freebsd.go @@ -234,7 +234,7 @@ func Mknod(path string, mode uint32, dev uint64) (err error) { //sys Setpriority(which int, who int, prio int) (err error) //sysnb Setregid(rgid int, egid int) (err error) //sysnb Setreuid(ruid int, euid int) (err error) -//sysnb Setrlimit(which int, lim *Rlimit) (err error) +//sysnb setrlimit(which int, lim *Rlimit) (err error) //sysnb Setsid() (pid int, err error) //sysnb Settimeofday(tp *Timeval) (err error) //sysnb Setuid(uid int) (err error) diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go index f337388a749e37..d1c981a9b3f560 100644 --- a/src/syscall/syscall_linux.go +++ b/src/syscall/syscall_linux.go @@ -1058,7 +1058,7 @@ func Getpgrp() (pid int) { //sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error) //sys Nanosleep(time *Timespec, leftover *Timespec) (err error) //sys PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT -//sysnb prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT64 +//sysnb prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT64 //sys read(fd int, p []byte) (n int, err error) //sys Removexattr(path string, attr string) (err error) //sys Setdomainname(p []byte) (err error) @@ -1261,3 +1261,14 @@ func Munmap(b []byte) (err error) { //sys Munlock(b []byte) (err error) //sys Mlockall(flags int) (err error) //sys Munlockall() (err error) + +// prlimit changes a resource limit. We use a single definition so that +// we can tell StartProcess to not restore the original NOFILE limit. +// This is unexported but can be called from x/sys/unix. +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + err = prlimit1(pid, resource, newlimit, old) + if err == nil && newlimit != nil && resource == RLIMIT_NOFILE { + origRlimitNofile.Store(Rlimit{0, 0}) + } + return err +} diff --git a/src/syscall/syscall_linux_386.go b/src/syscall/syscall_linux_386.go index 0c9c6aa7551db5..9cbd9ac9f03113 100644 --- a/src/syscall/syscall_linux_386.go +++ b/src/syscall/syscall_linux_386.go @@ -107,9 +107,9 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { return } -//sysnb setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT +//sysnb setrlimit1(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT -func Setrlimit(resource int, rlim *Rlimit) (err error) { +func setrlimit(resource int, rlim *Rlimit) (err error) { err = prlimit(0, resource, rlim, nil) if err != ENOSYS { return err @@ -131,7 +131,34 @@ func Setrlimit(resource int, rlim *Rlimit) (err error) { return EINVAL } - return setrlimit(resource, &rl) + return setrlimit1(resource, &rl) +} + +//go:nosplit +func rawSetrlimit(resource int, rlim *Rlimit) Errno { + _, _, errno := RawSyscall6(SYS_PRLIMIT64, 0, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0, 0, 0) + if errno != ENOSYS { + return errno + } + + rl := rlimit32{} + if rlim.Cur == rlimInf64 { + rl.Cur = rlimInf32 + } else if rlim.Cur < uint64(rlimInf32) { + rl.Cur = uint32(rlim.Cur) + } else { + return EINVAL + } + if rlim.Max == rlimInf64 { + rl.Max = rlimInf32 + } else if rlim.Max < uint64(rlimInf32) { + rl.Max = uint32(rlim.Max) + } else { + return EINVAL + } + + _, _, errno = RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + return errno } // Underlying system call writes to newoffset via pointer. diff --git a/src/syscall/syscall_linux_amd64.go b/src/syscall/syscall_linux_amd64.go index 77e1393de1dd24..aa85a523b20b99 100644 --- a/src/syscall/syscall_linux_amd64.go +++ b/src/syscall/syscall_linux_amd64.go @@ -4,6 +4,10 @@ package syscall +import ( + "unsafe" +) + const ( _SYS_setgroups = SYS_SETGROUPS _SYS_clone3 = 435 @@ -33,7 +37,7 @@ const ( //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) //sys Setfsgid(gid int) (err error) //sys Setfsuid(uid int) (err error) -//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) +//sysnb setrlimit(resource int, rlim *Rlimit) (err error) = SYS_SETRLIMIT //sys Shutdown(fd int, how int) (err error) //sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) //sys Statfs(path string, buf *Statfs_t) (err error) @@ -98,6 +102,12 @@ func Time(t *Time_t) (tt Time_t, err error) { //sys Utime(path string, buf *Utimbuf) (err error) //sys utimes(path string, times *[2]Timeval) (err error) +//go:nosplit +func rawSetrlimit(resource int, rlim *Rlimit) Errno { + _, _, errno := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + return errno +} + func setTimespec(sec, nsec int64) Timespec { return Timespec{Sec: sec, Nsec: nsec} } diff --git a/src/syscall/syscall_linux_arm.go b/src/syscall/syscall_linux_arm.go index f4740af5863dec..600ec3552db520 100644 --- a/src/syscall/syscall_linux_arm.go +++ b/src/syscall/syscall_linux_arm.go @@ -159,9 +159,9 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { return } -//sysnb setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT +//sysnb setrlimit1(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT -func Setrlimit(resource int, rlim *Rlimit) (err error) { +func setrlimit(resource int, rlim *Rlimit) (err error) { err = prlimit(0, resource, rlim, nil) if err != ENOSYS { return err @@ -183,7 +183,34 @@ func Setrlimit(resource int, rlim *Rlimit) (err error) { return EINVAL } - return setrlimit(resource, &rl) + return setrlimit1(resource, &rl) +} + +//go:nosplit +func rawSetrlimit(resource int, rlim *Rlimit) Errno { + _, _, errno := RawSyscall6(SYS_PRLIMIT64, 0, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0, 0, 0) + if errno != ENOSYS { + return errno + } + + rl := rlimit32{} + if rlim.Cur == rlimInf64 { + rl.Cur = rlimInf32 + } else if rlim.Cur < uint64(rlimInf32) { + rl.Cur = uint32(rlim.Cur) + } else { + return EINVAL + } + if rlim.Max == rlimInf64 { + rl.Max = rlimInf32 + } else if rlim.Max < uint64(rlimInf32) { + rl.Max = uint32(rlim.Max) + } else { + return EINVAL + } + + _, _, errno = RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + return errno } func (r *PtraceRegs) PC() uint64 { return uint64(r.Uregs[15]) } diff --git a/src/syscall/syscall_linux_arm64.go b/src/syscall/syscall_linux_arm64.go index f42686262ac930..42984ba2eddaa4 100644 --- a/src/syscall/syscall_linux_arm64.go +++ b/src/syscall/syscall_linux_arm64.go @@ -36,7 +36,7 @@ func Fstatat(fd int, path string, stat *Stat_t, flags int) error { //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) //sys Setfsgid(gid int) (err error) //sys Setfsuid(uid int) (err error) -//sysnb setrlimit(resource int, rlim *Rlimit) (err error) +//sysnb setrlimit1(resource int, rlim *Rlimit) (err error) //sys Shutdown(fd int, how int) (err error) //sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) @@ -148,13 +148,23 @@ func Getrlimit(resource int, rlim *Rlimit) error { return getrlimit(resource, rlim) } -// Setrlimit prefers the prlimit64 system call. See issue 38604. -func Setrlimit(resource int, rlim *Rlimit) error { +// setrlimit prefers the prlimit64 system call. See issue 38604. +func setrlimit(resource int, rlim *Rlimit) error { err := prlimit(0, resource, rlim, nil) if err != ENOSYS { return err } - return setrlimit(resource, rlim) + return setrlimit1(resource, rlim) +} + +//go:nosplit +func rawSetrlimit(resource int, rlim *Rlimit) Errno { + _, _, errno := RawSyscall6(SYS_PRLIMIT64, 0, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0, 0, 0) + if errno != ENOSYS { + return errno + } + _, _, errno = RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + return errno } func (r *PtraceRegs) PC() uint64 { return r.Pc } diff --git a/src/syscall/syscall_linux_loong64.go b/src/syscall/syscall_linux_loong64.go index 5a0fa0834d0704..f8f01c2d225e50 100644 --- a/src/syscall/syscall_linux_loong64.go +++ b/src/syscall/syscall_linux_loong64.go @@ -187,11 +187,17 @@ func Getrlimit(resource int, rlim *Rlimit) error { return prlimit(0, resource, nil, rlim) } -// Setrlimit prefers the prlimit64 system call. -func Setrlimit(resource int, rlim *Rlimit) error { +// setrlimit prefers the prlimit64 system call. +func setrlimit(resource int, rlim *Rlimit) error { return prlimit(0, resource, rlim, nil) } +//go:nosplit +func rawSetrlimit(resource int, rlim *Rlimit) Errno { + _, _, errno := RawSyscall6(SYS_PRLIMIT64, 0, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0, 0, 0) + return errno +} + func (r *PtraceRegs) GetEra() uint64 { return r.Era } func (r *PtraceRegs) SetEra(era uint64) { r.Era = era } diff --git a/src/syscall/syscall_linux_mips64x.go b/src/syscall/syscall_linux_mips64x.go index 8a0aa5c91e1695..47410d42601c69 100644 --- a/src/syscall/syscall_linux_mips64x.go +++ b/src/syscall/syscall_linux_mips64x.go @@ -6,6 +6,10 @@ package syscall +import ( + "unsafe" +) + const ( _SYS_setgroups = SYS_SETGROUPS _SYS_clone3 = 5435 @@ -33,7 +37,7 @@ const ( //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) //sys Setfsgid(gid int) (err error) //sys Setfsuid(uid int) (err error) -//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) +//sysnb setrlimit(resource int, rlim *Rlimit) (err error) = SYS_SETRLIMIT //sys Shutdown(fd int, how int) (err error) //sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) //sys Statfs(path string, buf *Statfs_t) (err error) @@ -89,6 +93,12 @@ func Time(t *Time_t) (tt Time_t, err error) { //sys Utime(path string, buf *Utimbuf) (err error) //sys utimes(path string, times *[2]Timeval) (err error) +//go:nosplit +func rawSetrlimit(resource int, rlim *Rlimit) Errno { + _, _, errno := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + return errno +} + func setTimespec(sec, nsec int64) Timespec { return Timespec{Sec: sec, Nsec: nsec} } diff --git a/src/syscall/syscall_linux_mipsx.go b/src/syscall/syscall_linux_mipsx.go index c8468fb5b596f6..d8d5044b81aa63 100644 --- a/src/syscall/syscall_linux_mipsx.go +++ b/src/syscall/syscall_linux_mipsx.go @@ -152,9 +152,9 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { return } -//sysnb setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT +//sysnb setrlimit1(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT -func Setrlimit(resource int, rlim *Rlimit) (err error) { +func setrlimit(resource int, rlim *Rlimit) (err error) { err = prlimit(0, resource, rlim, nil) if err != ENOSYS { return err @@ -176,7 +176,34 @@ func Setrlimit(resource int, rlim *Rlimit) (err error) { return EINVAL } - return setrlimit(resource, &rl) + return setrlimit1(resource, &rl) +} + +//go:nosplit +func rawSetrlimit(resource int, rlim *Rlimit) Errno { + _, _, errno := RawSyscall6(SYS_PRLIMIT64, 0, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0, 0, 0) + if errno != ENOSYS { + return errno + } + + rl := rlimit32{} + if rlim.Cur == rlimInf64 { + rl.Cur = rlimInf32 + } else if rlim.Cur < uint64(rlimInf32) { + rl.Cur = uint32(rlim.Cur) + } else { + return EINVAL + } + if rlim.Max == rlimInf64 { + rl.Max = rlimInf32 + } else if rlim.Max < uint64(rlimInf32) { + rl.Max = uint32(rlim.Max) + } else { + return EINVAL + } + + _, _, errno = RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + return errno } func (r *PtraceRegs) PC() uint64 { return uint64(r.Regs[64]) } diff --git a/src/syscall/syscall_linux_ppc64x.go b/src/syscall/syscall_linux_ppc64x.go index 5c076d8beae356..36f7711dfa3118 100644 --- a/src/syscall/syscall_linux_ppc64x.go +++ b/src/syscall/syscall_linux_ppc64x.go @@ -6,6 +6,10 @@ package syscall +import ( + "unsafe" +) + const ( _SYS_setgroups = SYS_SETGROUPS _SYS_clone3 = 435 @@ -39,7 +43,7 @@ const ( //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) //sys Setfsgid(gid int) (err error) //sys Setfsuid(uid int) (err error) -//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) +//sysnb setrlimit(resource int, rlim *Rlimit) (err error) = SYS_SETRLIMIT //sys Shutdown(fd int, how int) (err error) //sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) //sys Stat(path string, stat *Stat_t) (err error) @@ -68,6 +72,12 @@ const ( //sys Utime(path string, buf *Utimbuf) (err error) //sys utimes(path string, times *[2]Timeval) (err error) +//go:nosplit +func rawSetrlimit(resource int, rlim *Rlimit) Errno { + _, _, errno := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + return errno +} + func setTimespec(sec, nsec int64) Timespec { return Timespec{Sec: sec, Nsec: nsec} } diff --git a/src/syscall/syscall_linux_riscv64.go b/src/syscall/syscall_linux_riscv64.go index 3bb54600a83a24..44ff1d733e910b 100644 --- a/src/syscall/syscall_linux_riscv64.go +++ b/src/syscall/syscall_linux_riscv64.go @@ -36,7 +36,7 @@ func Fstatat(fd int, path string, stat *Stat_t, flags int) error { //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) //sys Setfsgid(gid int) (err error) //sys Setfsuid(uid int) (err error) -//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) +//sysnb setrlimit(resource int, rlim *Rlimit) (err error) = SYS_SETRLIMIT //sys Shutdown(fd int, how int) (err error) //sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) @@ -143,6 +143,12 @@ func utimes(path string, tv *[2]Timeval) (err error) { return utimensat(_AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0) } +//go:nosplit +func rawSetrlimit(resource int, rlim *Rlimit) Errno { + _, _, errno := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + return errno +} + func (r *PtraceRegs) PC() uint64 { return r.Pc } func (r *PtraceRegs) SetPC(pc uint64) { r.Pc = pc } diff --git a/src/syscall/syscall_linux_s390x.go b/src/syscall/syscall_linux_s390x.go index cb83697be4c10a..44990f2b1bf99d 100644 --- a/src/syscall/syscall_linux_s390x.go +++ b/src/syscall/syscall_linux_s390x.go @@ -36,7 +36,7 @@ const ( //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) //sys Setfsgid(gid int) (err error) //sys Setfsuid(uid int) (err error) -//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) +//sysnb setrlimit(resource int, rlim *Rlimit) (err error) = SYS_SETRLIMIT //sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) //sys Stat(path string, stat *Stat_t) (err error) //sys Statfs(path string, buf *Statfs_t) (err error) @@ -243,6 +243,12 @@ func Shutdown(s, how int) (err error) { return } +//go:nosplit +func rawSetrlimit(resource int, rlim *Rlimit) Errno { + _, _, errno := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + return errno +} + func (r *PtraceRegs) PC() uint64 { return r.Psw.Addr } func (r *PtraceRegs) SetPC(pc uint64) { r.Psw.Addr = pc } diff --git a/src/syscall/syscall_netbsd.go b/src/syscall/syscall_netbsd.go index 7f7c5b1c6bf410..333dd3ade67343 100644 --- a/src/syscall/syscall_netbsd.go +++ b/src/syscall/syscall_netbsd.go @@ -224,7 +224,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e //sys Setpriority(which int, who int, prio int) (err error) //sysnb Setregid(rgid int, egid int) (err error) //sysnb Setreuid(ruid int, euid int) (err error) -//sysnb Setrlimit(which int, lim *Rlimit) (err error) +//sysnb setrlimit(which int, lim *Rlimit) (err error) //sysnb Setsid() (pid int, err error) //sysnb Settimeofday(tp *Timeval) (err error) //sysnb Setuid(uid int) (err error) diff --git a/src/syscall/syscall_openbsd.go b/src/syscall/syscall_openbsd.go index ba67ab1a57a27f..5784d5c583d718 100644 --- a/src/syscall/syscall_openbsd.go +++ b/src/syscall/syscall_openbsd.go @@ -196,7 +196,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { //sys Setpriority(which int, who int, prio int) (err error) //sysnb Setregid(rgid int, egid int) (err error) //sysnb Setreuid(ruid int, euid int) (err error) -//sysnb Setrlimit(which int, lim *Rlimit) (err error) +//sysnb setrlimit(which int, lim *Rlimit) (err error) //sysnb Setsid() (pid int, err error) //sysnb Settimeofday(tp *Timeval) (err error) //sysnb Setuid(uid int) (err error) diff --git a/src/syscall/syscall_solaris.go b/src/syscall/syscall_solaris.go index 2d042acdc9811c..97eefcf4cc5415 100644 --- a/src/syscall/syscall_solaris.go +++ b/src/syscall/syscall_solaris.go @@ -474,7 +474,7 @@ func sendmsgN(fd int, p, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags i //sys Setpriority(which int, who int, prio int) (err error) //sysnb Setregid(rgid int, egid int) (err error) //sysnb Setreuid(ruid int, euid int) (err error) -//sysnb Setrlimit(which int, lim *Rlimit) (err error) +//sysnb setrlimit(which int, lim *Rlimit) (err error) //sysnb Setsid() (pid int, err error) //sysnb Setuid(uid int) (err error) //sys Shutdown(s int, how int) (err error) = libsocket.shutdown diff --git a/src/syscall/zsyscall_aix_ppc64.go b/src/syscall/zsyscall_aix_ppc64.go index c9e2edea242b15..854bbc15eee8a5 100644 --- a/src/syscall/zsyscall_aix_ppc64.go +++ b/src/syscall/zsyscall_aix_ppc64.go @@ -1261,7 +1261,7 @@ func Setreuid(ruid int, euid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go index 6b3fff3f3726a2..161bb4443a1409 100644 --- a/src/syscall/zsyscall_darwin_amd64.go +++ b/src/syscall/zsyscall_darwin_amd64.go @@ -1480,7 +1480,7 @@ func libc_setreuid_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_darwin_arm64.go b/src/syscall/zsyscall_darwin_arm64.go index 61601449a04043..630737138896d2 100644 --- a/src/syscall/zsyscall_darwin_arm64.go +++ b/src/syscall/zsyscall_darwin_arm64.go @@ -1480,7 +1480,7 @@ func libc_setreuid_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_dragonfly_amd64.go b/src/syscall/zsyscall_dragonfly_amd64.go index 5d5576d76ff646..a591682b7dc6d7 100644 --- a/src/syscall/zsyscall_dragonfly_amd64.go +++ b/src/syscall/zsyscall_dragonfly_amd64.go @@ -1066,7 +1066,7 @@ func Setreuid(ruid int, euid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_freebsd_386.go b/src/syscall/zsyscall_freebsd_386.go index 3839dd707451a2..e729adcc68aec1 100644 --- a/src/syscall/zsyscall_freebsd_386.go +++ b/src/syscall/zsyscall_freebsd_386.go @@ -1052,7 +1052,7 @@ func Setreuid(ruid int, euid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_freebsd_amd64.go b/src/syscall/zsyscall_freebsd_amd64.go index 109230216ccd85..df0b817b229108 100644 --- a/src/syscall/zsyscall_freebsd_amd64.go +++ b/src/syscall/zsyscall_freebsd_amd64.go @@ -1052,7 +1052,7 @@ func Setreuid(ruid int, euid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_freebsd_arm.go b/src/syscall/zsyscall_freebsd_arm.go index 53e48d5666c98b..abd4bf1639977b 100644 --- a/src/syscall/zsyscall_freebsd_arm.go +++ b/src/syscall/zsyscall_freebsd_arm.go @@ -1052,7 +1052,7 @@ func Setreuid(ruid int, euid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_freebsd_arm64.go b/src/syscall/zsyscall_freebsd_arm64.go index 320ce1f76eed50..b86cfb5d85c5a9 100644 --- a/src/syscall/zsyscall_freebsd_arm64.go +++ b/src/syscall/zsyscall_freebsd_arm64.go @@ -1052,7 +1052,7 @@ func Setreuid(ruid int, euid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_freebsd_riscv64.go b/src/syscall/zsyscall_freebsd_riscv64.go index a63eafb4b457c0..ad195e8cae7d15 100644 --- a/src/syscall/zsyscall_freebsd_riscv64.go +++ b/src/syscall/zsyscall_freebsd_riscv64.go @@ -1052,7 +1052,7 @@ func Setreuid(ruid int, euid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_linux_386.go b/src/syscall/zsyscall_linux_386.go index 6a646fba4f5fc0..0e657edf1ded05 100644 --- a/src/syscall/zsyscall_linux_386.go +++ b/src/syscall/zsyscall_linux_386.go @@ -691,7 +691,7 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { +func prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) @@ -1391,7 +1391,7 @@ func getrlimit(resource int, rlim *rlimit32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func setrlimit(resource int, rlim *rlimit32) (err error) { +func setrlimit1(resource int, rlim *rlimit32) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go index d5b0099a9a70e2..f2faef44331d0a 100644 --- a/src/syscall/zsyscall_linux_amd64.go +++ b/src/syscall/zsyscall_linux_amd64.go @@ -691,7 +691,7 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { +func prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) @@ -1322,7 +1322,7 @@ func Setfsuid(uid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(resource int, rlim *Rlimit) (err error) { +func setrlimit(resource int, rlim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go index 69f811a0ec7c31..765ae0febd24e7 100644 --- a/src/syscall/zsyscall_linux_arm.go +++ b/src/syscall/zsyscall_linux_arm.go @@ -691,7 +691,7 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { +func prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) @@ -1594,7 +1594,7 @@ func getrlimit(resource int, rlim *rlimit32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func setrlimit(resource int, rlim *rlimit32) (err error) { +func setrlimit1(resource int, rlim *rlimit32) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_linux_arm64.go b/src/syscall/zsyscall_linux_arm64.go index 7655ccbb3d7935..48eef852336f58 100644 --- a/src/syscall/zsyscall_linux_arm64.go +++ b/src/syscall/zsyscall_linux_arm64.go @@ -691,7 +691,7 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { +func prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) @@ -1292,7 +1292,7 @@ func Setfsuid(uid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func setrlimit(resource int, rlim *Rlimit) (err error) { +func setrlimit1(resource int, rlim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_linux_loong64.go b/src/syscall/zsyscall_linux_loong64.go index abbc19be6046bf..a89940e51837ae 100644 --- a/src/syscall/zsyscall_linux_loong64.go +++ b/src/syscall/zsyscall_linux_loong64.go @@ -691,7 +691,7 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { +func prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_linux_mips.go b/src/syscall/zsyscall_linux_mips.go index 792668c1d5c375..295f6736403ee8 100644 --- a/src/syscall/zsyscall_linux_mips.go +++ b/src/syscall/zsyscall_linux_mips.go @@ -691,7 +691,7 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { +func prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) @@ -1669,7 +1669,7 @@ func getrlimit(resource int, rlim *rlimit32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func setrlimit(resource int, rlim *rlimit32) (err error) { +func setrlimit1(resource int, rlim *rlimit32) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_linux_mips64.go b/src/syscall/zsyscall_linux_mips64.go index 27dbcb8a2d24a9..8ef441b8817514 100644 --- a/src/syscall/zsyscall_linux_mips64.go +++ b/src/syscall/zsyscall_linux_mips64.go @@ -691,7 +691,7 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { +func prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) @@ -1311,7 +1311,7 @@ func Setfsuid(uid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(resource int, rlim *Rlimit) (err error) { +func setrlimit(resource int, rlim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_linux_mips64le.go b/src/syscall/zsyscall_linux_mips64le.go index 0362303c5f4ce4..7ea91f2a1b359b 100644 --- a/src/syscall/zsyscall_linux_mips64le.go +++ b/src/syscall/zsyscall_linux_mips64le.go @@ -691,7 +691,7 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { +func prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) @@ -1311,7 +1311,7 @@ func Setfsuid(uid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(resource int, rlim *Rlimit) (err error) { +func setrlimit(resource int, rlim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_linux_mipsle.go b/src/syscall/zsyscall_linux_mipsle.go index 5320dfa65a7f53..a6d52b3da999bc 100644 --- a/src/syscall/zsyscall_linux_mipsle.go +++ b/src/syscall/zsyscall_linux_mipsle.go @@ -691,7 +691,7 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { +func prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) @@ -1669,7 +1669,7 @@ func getrlimit(resource int, rlim *rlimit32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func setrlimit(resource int, rlim *rlimit32) (err error) { +func setrlimit1(resource int, rlim *rlimit32) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_linux_ppc64.go b/src/syscall/zsyscall_linux_ppc64.go index 61f3063352c871..7f23a5e33847bf 100644 --- a/src/syscall/zsyscall_linux_ppc64.go +++ b/src/syscall/zsyscall_linux_ppc64.go @@ -691,7 +691,7 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { +func prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) @@ -1384,7 +1384,7 @@ func Setfsuid(uid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(resource int, rlim *Rlimit) (err error) { +func setrlimit(resource int, rlim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_linux_ppc64le.go b/src/syscall/zsyscall_linux_ppc64le.go index 3e14ab37a1dfe1..bc69150325482a 100644 --- a/src/syscall/zsyscall_linux_ppc64le.go +++ b/src/syscall/zsyscall_linux_ppc64le.go @@ -691,7 +691,7 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { +func prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) @@ -1384,7 +1384,7 @@ func Setfsuid(uid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(resource int, rlim *Rlimit) (err error) { +func setrlimit(resource int, rlim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_linux_riscv64.go b/src/syscall/zsyscall_linux_riscv64.go index 4a3fa5dbd86b91..9cf748e52fe11a 100644 --- a/src/syscall/zsyscall_linux_riscv64.go +++ b/src/syscall/zsyscall_linux_riscv64.go @@ -691,7 +691,7 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { +func prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) @@ -1292,7 +1292,7 @@ func Setfsuid(uid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(resource int, rlim *Rlimit) (err error) { +func setrlimit(resource int, rlim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_linux_s390x.go b/src/syscall/zsyscall_linux_s390x.go index 1fca71e3044511..a0dd0be6154801 100644 --- a/src/syscall/zsyscall_linux_s390x.go +++ b/src/syscall/zsyscall_linux_s390x.go @@ -691,7 +691,7 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { +func prlimit1(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) @@ -1354,7 +1354,7 @@ func Setfsuid(uid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(resource int, rlim *Rlimit) (err error) { +func setrlimit(resource int, rlim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_netbsd_386.go b/src/syscall/zsyscall_netbsd_386.go index 9b9285920601a8..e401d02d0201f9 100644 --- a/src/syscall/zsyscall_netbsd_386.go +++ b/src/syscall/zsyscall_netbsd_386.go @@ -1030,7 +1030,7 @@ func Setreuid(ruid int, euid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_netbsd_amd64.go b/src/syscall/zsyscall_netbsd_amd64.go index ac34c00b5a2935..a4f217b948fbda 100644 --- a/src/syscall/zsyscall_netbsd_amd64.go +++ b/src/syscall/zsyscall_netbsd_amd64.go @@ -1030,7 +1030,7 @@ func Setreuid(ruid int, euid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_netbsd_arm.go b/src/syscall/zsyscall_netbsd_arm.go index 2be5e7baa4d32e..1f55614f64088a 100644 --- a/src/syscall/zsyscall_netbsd_arm.go +++ b/src/syscall/zsyscall_netbsd_arm.go @@ -1030,7 +1030,7 @@ func Setreuid(ruid int, euid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_netbsd_arm64.go b/src/syscall/zsyscall_netbsd_arm64.go index 02a652bbbb2463..be33fcd4128e78 100644 --- a/src/syscall/zsyscall_netbsd_arm64.go +++ b/src/syscall/zsyscall_netbsd_arm64.go @@ -1030,7 +1030,7 @@ func Setreuid(ruid int, euid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_openbsd_386.go b/src/syscall/zsyscall_openbsd_386.go index b60af1743d891d..b3a4b731243f03 100644 --- a/src/syscall/zsyscall_openbsd_386.go +++ b/src/syscall/zsyscall_openbsd_386.go @@ -1387,7 +1387,7 @@ func libc_setreuid_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_openbsd_amd64.go b/src/syscall/zsyscall_openbsd_amd64.go index 8b3e81e6bd36f2..15cd8cce2786bb 100644 --- a/src/syscall/zsyscall_openbsd_amd64.go +++ b/src/syscall/zsyscall_openbsd_amd64.go @@ -1387,7 +1387,7 @@ func libc_setreuid_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_openbsd_arm.go b/src/syscall/zsyscall_openbsd_arm.go index 42d57812b25d30..90b493f1ec7d68 100644 --- a/src/syscall/zsyscall_openbsd_arm.go +++ b/src/syscall/zsyscall_openbsd_arm.go @@ -1387,7 +1387,7 @@ func libc_setreuid_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_openbsd_arm64.go b/src/syscall/zsyscall_openbsd_arm64.go index 7a5a2c0c819e42..6615336043d89a 100644 --- a/src/syscall/zsyscall_openbsd_arm64.go +++ b/src/syscall/zsyscall_openbsd_arm64.go @@ -1387,7 +1387,7 @@ func libc_setreuid_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := rawSyscall(abi.FuncPCABI0(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_openbsd_mips64.go b/src/syscall/zsyscall_openbsd_mips64.go index 2cf84653191b57..2a91c368313693 100644 --- a/src/syscall/zsyscall_openbsd_mips64.go +++ b/src/syscall/zsyscall_openbsd_mips64.go @@ -1039,7 +1039,7 @@ func Setreuid(ruid int, euid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) diff --git a/src/syscall/zsyscall_solaris_amd64.go b/src/syscall/zsyscall_solaris_amd64.go index 19e5ec1fcd3643..e25db63eba926e 100644 --- a/src/syscall/zsyscall_solaris_amd64.go +++ b/src/syscall/zsyscall_solaris_amd64.go @@ -962,7 +962,7 @@ func Setreuid(ruid int, euid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Setrlimit(which int, lim *Rlimit) (err error) { +func setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0) if e1 != 0 { err = errnoErr(e1) From 0684cecad5b9c22e7a5a44fbe93c35e56144946c Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sat, 1 Apr 2023 10:33:26 -0700 Subject: [PATCH 071/165] [release-branch.go1.20] cmd/compile: use correct type for byteswaps on multi-byte stores Use the type of the store for the byteswap, not the type of the store's value argument. Normally when we're storing a 16-bit value, the value being stored is also typed as 16 bits. But sometimes it is typed as something smaller, usually because it is the result of an upcast from a smaller value, and that upcast needs no instructions. If the type of the store's arg is thinner than the type being stored, and the byteswap'd value uses that thinner type, and the byteswap'd value needs to be spilled & restored, that spill/restore happens using the thinner type, which causes us to lose some of the top bits of the value. Fixes #59374 Change-Id: If6ce1e8a76f18bf8e9d79871b6caa438bc3cce4d Reviewed-on: https://go-review.googlesource.com/c/go/+/481395 Reviewed-by: David Chase Reviewed-by: Cherry Mui Run-TryBot: Keith Randall TryBot-Result: Gopher Robot (cherry picked from commit b3bc8620f89153fddc1a30ee17c1d93654ed4314) Reviewed-on: https://go-review.googlesource.com/c/go/+/483176 Auto-Submit: Dmitri Shuralyov --- src/cmd/compile/internal/ssa/_gen/AMD64.rules | 12 +-- src/cmd/compile/internal/ssa/_gen/ARM64.rules | 36 ++++----- src/cmd/compile/internal/ssa/rewriteAMD64.go | 24 +++--- src/cmd/compile/internal/ssa/rewriteARM64.go | 74 ++++++++--------- test/fixedbugs/issue59367.go | 80 +++++++++++++++++++ 5 files changed, 154 insertions(+), 72 deletions(-) create mode 100644 test/fixedbugs/issue59367.go diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64.rules b/src/cmd/compile/internal/ssa/_gen/AMD64.rules index ccb52956224bf8..aa156f61b99250 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/_gen/AMD64.rules @@ -1757,13 +1757,13 @@ x0:(MOVBstore [i-1] {s} p (SHRWconst [8] w) mem)) && x0.Uses == 1 && clobber(x0) - => (MOVWstore [i-1] {s} p (ROLWconst [8] w) mem) + => (MOVWstore [i-1] {s} p (ROLWconst [8] w) mem) (MOVBstore [i] {s} p1 w x0:(MOVBstore [i] {s} p0 (SHRWconst [8] w) mem)) && x0.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x0) - => (MOVWstore [i] {s} p0 (ROLWconst [8] w) mem) + => (MOVWstore [i] {s} p0 (ROLWconst [8] w) mem) // Combine stores + shifts into bswap and larger (unaligned) stores (MOVBstore [i] {s} p w @@ -1774,7 +1774,7 @@ && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2) - => (MOVLstore [i-3] {s} p (BSWAPL w) mem) + => (MOVLstore [i-3] {s} p (BSWAPL w) mem) (MOVBstore [i] {s} p3 w x2:(MOVBstore [i] {s} p2 (SHRLconst [8] w) x1:(MOVBstore [i] {s} p1 (SHRLconst [16] w) @@ -1786,7 +1786,7 @@ && sequentialAddresses(p1, p2, 1) && sequentialAddresses(p2, p3, 1) && clobber(x0, x1, x2) - => (MOVLstore [i] {s} p0 (BSWAPL w) mem) + => (MOVLstore [i] {s} p0 (BSWAPL w) mem) (MOVBstore [i] {s} p w x6:(MOVBstore [i-1] {s} p (SHRQconst [8] w) @@ -1804,7 +1804,7 @@ && x5.Uses == 1 && x6.Uses == 1 && clobber(x0, x1, x2, x3, x4, x5, x6) - => (MOVQstore [i-7] {s} p (BSWAPQ w) mem) + => (MOVQstore [i-7] {s} p (BSWAPQ w) mem) (MOVBstore [i] {s} p7 w x6:(MOVBstore [i] {s} p6 (SHRQconst [8] w) x5:(MOVBstore [i] {s} p5 (SHRQconst [16] w) @@ -1828,7 +1828,7 @@ && sequentialAddresses(p5, p6, 1) && sequentialAddresses(p6, p7, 1) && clobber(x0, x1, x2, x3, x4, x5, x6) - => (MOVQstore [i] {s} p0 (BSWAPQ w) mem) + => (MOVQstore [i] {s} p0 (BSWAPQ w) mem) // Combine constant stores into larger (unaligned) stores. (MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem)) diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64.rules b/src/cmd/compile/internal/ssa/_gen/ARM64.rules index 8405248fe55a2c..78a8492aa3a83d 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/_gen/ARM64.rules @@ -2821,7 +2821,7 @@ && x5.Uses == 1 && x6.Uses == 1 && clobber(x0, x1, x2, x3, x4, x5, x6) - => (MOVDstore [i-7] {s} ptr (REV w) mem) + => (MOVDstore [i-7] {s} ptr (REV w) mem) (MOVBstore [7] {s} p w x0:(MOVBstore [6] {s} p (SRLconst [8] w) x1:(MOVBstore [5] {s} p (SRLconst [16] w) @@ -2841,7 +2841,7 @@ && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && isSamePtr(p1, p) && clobber(x0, x1, x2, x3, x4, x5, x6) - => (MOVDstoreidx ptr0 idx0 (REV w) mem) + => (MOVDstoreidx ptr0 idx0 (REV w) mem) (MOVBstore [i] {s} ptr w x0:(MOVBstore [i-1] {s} ptr (UBFX [armBFAuxInt(8, 24)] w) x1:(MOVBstore [i-2] {s} ptr (UBFX [armBFAuxInt(16, 16)] w) @@ -2850,7 +2850,7 @@ && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2) - => (MOVWstore [i-3] {s} ptr (REVW w) mem) + => (MOVWstore [i-3] {s} ptr (REVW w) mem) (MOVBstore [3] {s} p w x0:(MOVBstore [2] {s} p (UBFX [armBFAuxInt(8, 24)] w) x1:(MOVBstore [1] {s} p1:(ADD ptr1 idx1) (UBFX [armBFAuxInt(16, 16)] w) @@ -2862,7 +2862,7 @@ && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && isSamePtr(p1, p) && clobber(x0, x1, x2) - => (MOVWstoreidx ptr0 idx0 (REVW w) mem) + => (MOVWstoreidx ptr0 idx0 (REVW w) mem) (MOVBstoreidx ptr (ADDconst [3] idx) w x0:(MOVBstoreidx ptr (ADDconst [2] idx) (UBFX [armBFAuxInt(8, 24)] w) x1:(MOVBstoreidx ptr (ADDconst [1] idx) (UBFX [armBFAuxInt(16, 16)] w) @@ -2871,7 +2871,7 @@ && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2) - => (MOVWstoreidx ptr idx (REVW w) mem) + => (MOVWstoreidx ptr idx (REVW w) mem) (MOVBstoreidx ptr idx w x0:(MOVBstoreidx ptr (ADDconst [1] idx) (UBFX [armBFAuxInt(8, 24)] w) x1:(MOVBstoreidx ptr (ADDconst [2] idx) (UBFX [armBFAuxInt(16, 16)] w) @@ -2889,7 +2889,7 @@ && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2) - => (MOVWstore [i-3] {s} ptr (REVW w) mem) + => (MOVWstore [i-3] {s} ptr (REVW w) mem) (MOVBstore [3] {s} p w x0:(MOVBstore [2] {s} p (SRLconst [8] (MOVDreg w)) x1:(MOVBstore [1] {s} p1:(ADD ptr1 idx1) (SRLconst [16] (MOVDreg w)) @@ -2901,7 +2901,7 @@ && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && isSamePtr(p1, p) && clobber(x0, x1, x2) - => (MOVWstoreidx ptr0 idx0 (REVW w) mem) + => (MOVWstoreidx ptr0 idx0 (REVW w) mem) (MOVBstore [i] {s} ptr w x0:(MOVBstore [i-1] {s} ptr (SRLconst [8] w) x1:(MOVBstore [i-2] {s} ptr (SRLconst [16] w) @@ -2910,7 +2910,7 @@ && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2) - => (MOVWstore [i-3] {s} ptr (REVW w) mem) + => (MOVWstore [i-3] {s} ptr (REVW w) mem) (MOVBstore [3] {s} p w x0:(MOVBstore [2] {s} p (SRLconst [8] w) x1:(MOVBstore [1] {s} p1:(ADD ptr1 idx1) (SRLconst [16] w) @@ -2922,31 +2922,31 @@ && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && isSamePtr(p1, p) && clobber(x0, x1, x2) - => (MOVWstoreidx ptr0 idx0 (REVW w) mem) + => (MOVWstoreidx ptr0 idx0 (REVW w) mem) (MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (SRLconst [8] w) mem)) && x.Uses == 1 && clobber(x) - => (MOVHstore [i-1] {s} ptr (REV16W w) mem) + => (MOVHstore [i-1] {s} ptr (REV16W w) mem) (MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (SRLconst [8] w) mem)) && x.Uses == 1 && s == nil && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && clobber(x) - => (MOVHstoreidx ptr0 idx0 (REV16W w) mem) + => (MOVHstoreidx ptr0 idx0 (REV16W w) mem) (MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (UBFX [armBFAuxInt(8, 8)] w) mem)) && x.Uses == 1 && clobber(x) - => (MOVHstore [i-1] {s} ptr (REV16W w) mem) + => (MOVHstore [i-1] {s} ptr (REV16W w) mem) (MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (UBFX [armBFAuxInt(8, 8)] w) mem)) && x.Uses == 1 && s == nil && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && clobber(x) - => (MOVHstoreidx ptr0 idx0 (REV16W w) mem) + => (MOVHstoreidx ptr0 idx0 (REV16W w) mem) (MOVBstoreidx ptr (ADDconst [1] idx) w x:(MOVBstoreidx ptr idx (UBFX [armBFAuxInt(8, 8)] w) mem)) && x.Uses == 1 && clobber(x) - => (MOVHstoreidx ptr idx (REV16W w) mem) + => (MOVHstoreidx ptr idx (REV16W w) mem) (MOVBstoreidx ptr idx w x:(MOVBstoreidx ptr (ADDconst [1] idx) (UBFX [armBFAuxInt(8, 8)] w) mem)) && x.Uses == 1 && clobber(x) @@ -2954,23 +2954,23 @@ (MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (SRLconst [8] (MOVDreg w)) mem)) && x.Uses == 1 && clobber(x) - => (MOVHstore [i-1] {s} ptr (REV16W w) mem) + => (MOVHstore [i-1] {s} ptr (REV16W w) mem) (MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (SRLconst [8] (MOVDreg w)) mem)) && x.Uses == 1 && s == nil && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && clobber(x) - => (MOVHstoreidx ptr0 idx0 (REV16W w) mem) + => (MOVHstoreidx ptr0 idx0 (REV16W w) mem) (MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (UBFX [armBFAuxInt(8, 24)] w) mem)) && x.Uses == 1 && clobber(x) - => (MOVHstore [i-1] {s} ptr (REV16W w) mem) + => (MOVHstore [i-1] {s} ptr (REV16W w) mem) (MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (UBFX [armBFAuxInt(8, 24)] w) mem)) && x.Uses == 1 && s == nil && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && clobber(x) - => (MOVHstoreidx ptr0 idx0 (REV16W w) mem) + => (MOVHstoreidx ptr0 idx0 (REV16W w) mem) // FP simplification (FNEGS (FMULS x y)) => (FNMULS x y) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index cad37d40391e99..7ece8c04ce3f63 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -10244,7 +10244,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { } // match: (MOVBstore [i] {s} p w x0:(MOVBstore [i-1] {s} p (SHRWconst [8] w) mem)) // cond: x0.Uses == 1 && clobber(x0) - // result: (MOVWstore [i-1] {s} p (ROLWconst [8] w) mem) + // result: (MOVWstore [i-1] {s} p (ROLWconst [8] w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -10265,7 +10265,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.reset(OpAMD64MOVWstore) v.AuxInt = int32ToAuxInt(i - 1) v.Aux = symToAux(s) - v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, w.Type) + v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, typ.UInt16) v0.AuxInt = int8ToAuxInt(8) v0.AddArg(w) v.AddArg3(p, v0, mem) @@ -10273,7 +10273,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { } // match: (MOVBstore [i] {s} p1 w x0:(MOVBstore [i] {s} p0 (SHRWconst [8] w) mem)) // cond: x0.Uses == 1 && sequentialAddresses(p0, p1, 1) && clobber(x0) - // result: (MOVWstore [i] {s} p0 (ROLWconst [8] w) mem) + // result: (MOVWstore [i] {s} p0 (ROLWconst [8] w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -10292,7 +10292,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.reset(OpAMD64MOVWstore) v.AuxInt = int32ToAuxInt(i) v.Aux = symToAux(s) - v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, w.Type) + v0 := b.NewValue0(x0.Pos, OpAMD64ROLWconst, typ.UInt16) v0.AuxInt = int8ToAuxInt(8) v0.AddArg(w) v.AddArg3(p0, v0, mem) @@ -10300,7 +10300,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { } // match: (MOVBstore [i] {s} p w x2:(MOVBstore [i-1] {s} p (SHRLconst [8] w) x1:(MOVBstore [i-2] {s} p (SHRLconst [16] w) x0:(MOVBstore [i-3] {s} p (SHRLconst [24] w) mem)))) // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2) - // result: (MOVLstore [i-3] {s} p (BSWAPL w) mem) + // result: (MOVLstore [i-3] {s} p (BSWAPL w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -10345,14 +10345,14 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.reset(OpAMD64MOVLstore) v.AuxInt = int32ToAuxInt(i - 3) v.Aux = symToAux(s) - v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, w.Type) + v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, typ.UInt32) v0.AddArg(w) v.AddArg3(p, v0, mem) return true } // match: (MOVBstore [i] {s} p3 w x2:(MOVBstore [i] {s} p2 (SHRLconst [8] w) x1:(MOVBstore [i] {s} p1 (SHRLconst [16] w) x0:(MOVBstore [i] {s} p0 (SHRLconst [24] w) mem)))) // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && sequentialAddresses(p0, p1, 1) && sequentialAddresses(p1, p2, 1) && sequentialAddresses(p2, p3, 1) && clobber(x0, x1, x2) - // result: (MOVLstore [i] {s} p0 (BSWAPL w) mem) + // result: (MOVLstore [i] {s} p0 (BSWAPL w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -10391,14 +10391,14 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.reset(OpAMD64MOVLstore) v.AuxInt = int32ToAuxInt(i) v.Aux = symToAux(s) - v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, w.Type) + v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPL, typ.UInt32) v0.AddArg(w) v.AddArg3(p0, v0, mem) return true } // match: (MOVBstore [i] {s} p w x6:(MOVBstore [i-1] {s} p (SHRQconst [8] w) x5:(MOVBstore [i-2] {s} p (SHRQconst [16] w) x4:(MOVBstore [i-3] {s} p (SHRQconst [24] w) x3:(MOVBstore [i-4] {s} p (SHRQconst [32] w) x2:(MOVBstore [i-5] {s} p (SHRQconst [40] w) x1:(MOVBstore [i-6] {s} p (SHRQconst [48] w) x0:(MOVBstore [i-7] {s} p (SHRQconst [56] w) mem)))))))) // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && clobber(x0, x1, x2, x3, x4, x5, x6) - // result: (MOVQstore [i-7] {s} p (BSWAPQ w) mem) + // result: (MOVQstore [i-7] {s} p (BSWAPQ w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -10491,14 +10491,14 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.reset(OpAMD64MOVQstore) v.AuxInt = int32ToAuxInt(i - 7) v.Aux = symToAux(s) - v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, w.Type) + v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, typ.UInt64) v0.AddArg(w) v.AddArg3(p, v0, mem) return true } // match: (MOVBstore [i] {s} p7 w x6:(MOVBstore [i] {s} p6 (SHRQconst [8] w) x5:(MOVBstore [i] {s} p5 (SHRQconst [16] w) x4:(MOVBstore [i] {s} p4 (SHRQconst [24] w) x3:(MOVBstore [i] {s} p3 (SHRQconst [32] w) x2:(MOVBstore [i] {s} p2 (SHRQconst [40] w) x1:(MOVBstore [i] {s} p1 (SHRQconst [48] w) x0:(MOVBstore [i] {s} p0 (SHRQconst [56] w) mem)))))))) // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && sequentialAddresses(p0, p1, 1) && sequentialAddresses(p1, p2, 1) && sequentialAddresses(p2, p3, 1) && sequentialAddresses(p3, p4, 1) && sequentialAddresses(p4, p5, 1) && sequentialAddresses(p5, p6, 1) && sequentialAddresses(p6, p7, 1) && clobber(x0, x1, x2, x3, x4, x5, x6) - // result: (MOVQstore [i] {s} p0 (BSWAPQ w) mem) + // result: (MOVQstore [i] {s} p0 (BSWAPQ w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -10577,7 +10577,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.reset(OpAMD64MOVQstore) v.AuxInt = int32ToAuxInt(i) v.Aux = symToAux(s) - v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, w.Type) + v0 := b.NewValue0(x0.Pos, OpAMD64BSWAPQ, typ.UInt64) v0.AddArg(w) v.AddArg3(p0, v0, mem) return true diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index 12b3bbd572f170..645b9b07750619 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -8323,6 +8323,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { v_0 := v.Args[0] b := v.Block config := b.Func.Config + typ := &b.Func.Config.Types // match: (MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (MOVBstore [off1+int32(off2)] {sym} ptr val mem) @@ -8993,7 +8994,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { } // match: (MOVBstore [i] {s} ptr w x0:(MOVBstore [i-1] {s} ptr (SRLconst [8] w) x1:(MOVBstore [i-2] {s} ptr (SRLconst [16] w) x2:(MOVBstore [i-3] {s} ptr (SRLconst [24] w) x3:(MOVBstore [i-4] {s} ptr (SRLconst [32] w) x4:(MOVBstore [i-5] {s} ptr (SRLconst [40] w) x5:(MOVBstore [i-6] {s} ptr (SRLconst [48] w) x6:(MOVBstore [i-7] {s} ptr (SRLconst [56] w) mem)))))))) // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && clobber(x0, x1, x2, x3, x4, x5, x6) - // result: (MOVDstore [i-7] {s} ptr (REV w) mem) + // result: (MOVDstore [i-7] {s} ptr (REV w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -9086,14 +9087,14 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { v.reset(OpARM64MOVDstore) v.AuxInt = int32ToAuxInt(i - 7) v.Aux = symToAux(s) - v0 := b.NewValue0(x6.Pos, OpARM64REV, w.Type) + v0 := b.NewValue0(x6.Pos, OpARM64REV, typ.UInt64) v0.AddArg(w) v.AddArg3(ptr, v0, mem) return true } // match: (MOVBstore [7] {s} p w x0:(MOVBstore [6] {s} p (SRLconst [8] w) x1:(MOVBstore [5] {s} p (SRLconst [16] w) x2:(MOVBstore [4] {s} p (SRLconst [24] w) x3:(MOVBstore [3] {s} p (SRLconst [32] w) x4:(MOVBstore [2] {s} p (SRLconst [40] w) x5:(MOVBstore [1] {s} p1:(ADD ptr1 idx1) (SRLconst [48] w) x6:(MOVBstoreidx ptr0 idx0 (SRLconst [56] w) mem)))))))) // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && s == nil && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && isSamePtr(p1, p) && clobber(x0, x1, x2, x3, x4, x5, x6) - // result: (MOVDstoreidx ptr0 idx0 (REV w) mem) + // result: (MOVDstoreidx ptr0 idx0 (REV w) mem) for { if auxIntToInt32(v.AuxInt) != 7 { break @@ -9192,7 +9193,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { continue } v.reset(OpARM64MOVDstoreidx) - v0 := b.NewValue0(x5.Pos, OpARM64REV, w.Type) + v0 := b.NewValue0(x5.Pos, OpARM64REV, typ.UInt64) v0.AddArg(w) v.AddArg4(ptr0, idx0, v0, mem) return true @@ -9201,7 +9202,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { } // match: (MOVBstore [i] {s} ptr w x0:(MOVBstore [i-1] {s} ptr (UBFX [armBFAuxInt(8, 24)] w) x1:(MOVBstore [i-2] {s} ptr (UBFX [armBFAuxInt(16, 16)] w) x2:(MOVBstore [i-3] {s} ptr (UBFX [armBFAuxInt(24, 8)] w) mem)))) // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2) - // result: (MOVWstore [i-3] {s} ptr (REVW w) mem) + // result: (MOVWstore [i-3] {s} ptr (REVW w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -9246,14 +9247,14 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { v.reset(OpARM64MOVWstore) v.AuxInt = int32ToAuxInt(i - 3) v.Aux = symToAux(s) - v0 := b.NewValue0(x2.Pos, OpARM64REVW, w.Type) + v0 := b.NewValue0(x2.Pos, OpARM64REVW, typ.UInt32) v0.AddArg(w) v.AddArg3(ptr, v0, mem) return true } // match: (MOVBstore [3] {s} p w x0:(MOVBstore [2] {s} p (UBFX [armBFAuxInt(8, 24)] w) x1:(MOVBstore [1] {s} p1:(ADD ptr1 idx1) (UBFX [armBFAuxInt(16, 16)] w) x2:(MOVBstoreidx ptr0 idx0 (UBFX [armBFAuxInt(24, 8)] w) mem)))) // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s == nil && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && isSamePtr(p1, p) && clobber(x0, x1, x2) - // result: (MOVWstoreidx ptr0 idx0 (REVW w) mem) + // result: (MOVWstoreidx ptr0 idx0 (REVW w) mem) for { if auxIntToInt32(v.AuxInt) != 3 { break @@ -9304,7 +9305,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { continue } v.reset(OpARM64MOVWstoreidx) - v0 := b.NewValue0(x1.Pos, OpARM64REVW, w.Type) + v0 := b.NewValue0(x1.Pos, OpARM64REVW, typ.UInt32) v0.AddArg(w) v.AddArg4(ptr0, idx0, v0, mem) return true @@ -9313,7 +9314,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { } // match: (MOVBstore [i] {s} ptr w x0:(MOVBstore [i-1] {s} ptr (SRLconst [8] (MOVDreg w)) x1:(MOVBstore [i-2] {s} ptr (SRLconst [16] (MOVDreg w)) x2:(MOVBstore [i-3] {s} ptr (SRLconst [24] (MOVDreg w)) mem)))) // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2) - // result: (MOVWstore [i-3] {s} ptr (REVW w) mem) + // result: (MOVWstore [i-3] {s} ptr (REVW w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -9370,14 +9371,14 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { v.reset(OpARM64MOVWstore) v.AuxInt = int32ToAuxInt(i - 3) v.Aux = symToAux(s) - v0 := b.NewValue0(x2.Pos, OpARM64REVW, w.Type) + v0 := b.NewValue0(x2.Pos, OpARM64REVW, typ.UInt32) v0.AddArg(w) v.AddArg3(ptr, v0, mem) return true } // match: (MOVBstore [3] {s} p w x0:(MOVBstore [2] {s} p (SRLconst [8] (MOVDreg w)) x1:(MOVBstore [1] {s} p1:(ADD ptr1 idx1) (SRLconst [16] (MOVDreg w)) x2:(MOVBstoreidx ptr0 idx0 (SRLconst [24] (MOVDreg w)) mem)))) // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s == nil && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && isSamePtr(p1, p) && clobber(x0, x1, x2) - // result: (MOVWstoreidx ptr0 idx0 (REVW w) mem) + // result: (MOVWstoreidx ptr0 idx0 (REVW w) mem) for { if auxIntToInt32(v.AuxInt) != 3 { break @@ -9440,7 +9441,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { continue } v.reset(OpARM64MOVWstoreidx) - v0 := b.NewValue0(x1.Pos, OpARM64REVW, w.Type) + v0 := b.NewValue0(x1.Pos, OpARM64REVW, typ.UInt32) v0.AddArg(w) v.AddArg4(ptr0, idx0, v0, mem) return true @@ -9449,7 +9450,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { } // match: (MOVBstore [i] {s} ptr w x0:(MOVBstore [i-1] {s} ptr (SRLconst [8] w) x1:(MOVBstore [i-2] {s} ptr (SRLconst [16] w) x2:(MOVBstore [i-3] {s} ptr (SRLconst [24] w) mem)))) // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2) - // result: (MOVWstore [i-3] {s} ptr (REVW w) mem) + // result: (MOVWstore [i-3] {s} ptr (REVW w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -9494,14 +9495,14 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { v.reset(OpARM64MOVWstore) v.AuxInt = int32ToAuxInt(i - 3) v.Aux = symToAux(s) - v0 := b.NewValue0(x2.Pos, OpARM64REVW, w.Type) + v0 := b.NewValue0(x2.Pos, OpARM64REVW, typ.UInt32) v0.AddArg(w) v.AddArg3(ptr, v0, mem) return true } // match: (MOVBstore [3] {s} p w x0:(MOVBstore [2] {s} p (SRLconst [8] w) x1:(MOVBstore [1] {s} p1:(ADD ptr1 idx1) (SRLconst [16] w) x2:(MOVBstoreidx ptr0 idx0 (SRLconst [24] w) mem)))) // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s == nil && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && isSamePtr(p1, p) && clobber(x0, x1, x2) - // result: (MOVWstoreidx ptr0 idx0 (REVW w) mem) + // result: (MOVWstoreidx ptr0 idx0 (REVW w) mem) for { if auxIntToInt32(v.AuxInt) != 3 { break @@ -9552,7 +9553,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { continue } v.reset(OpARM64MOVWstoreidx) - v0 := b.NewValue0(x1.Pos, OpARM64REVW, w.Type) + v0 := b.NewValue0(x1.Pos, OpARM64REVW, typ.UInt32) v0.AddArg(w) v.AddArg4(ptr0, idx0, v0, mem) return true @@ -9561,7 +9562,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { } // match: (MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (SRLconst [8] w) mem)) // cond: x.Uses == 1 && clobber(x) - // result: (MOVHstore [i-1] {s} ptr (REV16W w) mem) + // result: (MOVHstore [i-1] {s} ptr (REV16W w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -9582,14 +9583,14 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { v.reset(OpARM64MOVHstore) v.AuxInt = int32ToAuxInt(i - 1) v.Aux = symToAux(s) - v0 := b.NewValue0(x.Pos, OpARM64REV16W, w.Type) + v0 := b.NewValue0(x.Pos, OpARM64REV16W, typ.UInt16) v0.AddArg(w) v.AddArg3(ptr, v0, mem) return true } // match: (MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (SRLconst [8] w) mem)) // cond: x.Uses == 1 && s == nil && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && clobber(x) - // result: (MOVHstoreidx ptr0 idx0 (REV16W w) mem) + // result: (MOVHstoreidx ptr0 idx0 (REV16W w) mem) for { if auxIntToInt32(v.AuxInt) != 1 { break @@ -9617,7 +9618,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { continue } v.reset(OpARM64MOVHstoreidx) - v0 := b.NewValue0(v.Pos, OpARM64REV16W, w.Type) + v0 := b.NewValue0(v.Pos, OpARM64REV16W, typ.UInt16) v0.AddArg(w) v.AddArg4(ptr0, idx0, v0, mem) return true @@ -9626,7 +9627,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { } // match: (MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (UBFX [armBFAuxInt(8, 8)] w) mem)) // cond: x.Uses == 1 && clobber(x) - // result: (MOVHstore [i-1] {s} ptr (REV16W w) mem) + // result: (MOVHstore [i-1] {s} ptr (REV16W w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -9647,14 +9648,14 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { v.reset(OpARM64MOVHstore) v.AuxInt = int32ToAuxInt(i - 1) v.Aux = symToAux(s) - v0 := b.NewValue0(x.Pos, OpARM64REV16W, w.Type) + v0 := b.NewValue0(x.Pos, OpARM64REV16W, typ.UInt16) v0.AddArg(w) v.AddArg3(ptr, v0, mem) return true } // match: (MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (UBFX [armBFAuxInt(8, 8)] w) mem)) // cond: x.Uses == 1 && s == nil && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && clobber(x) - // result: (MOVHstoreidx ptr0 idx0 (REV16W w) mem) + // result: (MOVHstoreidx ptr0 idx0 (REV16W w) mem) for { if auxIntToInt32(v.AuxInt) != 1 { break @@ -9682,7 +9683,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { continue } v.reset(OpARM64MOVHstoreidx) - v0 := b.NewValue0(v.Pos, OpARM64REV16W, w.Type) + v0 := b.NewValue0(v.Pos, OpARM64REV16W, typ.UInt16) v0.AddArg(w) v.AddArg4(ptr0, idx0, v0, mem) return true @@ -9691,7 +9692,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { } // match: (MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (SRLconst [8] (MOVDreg w)) mem)) // cond: x.Uses == 1 && clobber(x) - // result: (MOVHstore [i-1] {s} ptr (REV16W w) mem) + // result: (MOVHstore [i-1] {s} ptr (REV16W w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -9716,14 +9717,14 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { v.reset(OpARM64MOVHstore) v.AuxInt = int32ToAuxInt(i - 1) v.Aux = symToAux(s) - v0 := b.NewValue0(x.Pos, OpARM64REV16W, w.Type) + v0 := b.NewValue0(x.Pos, OpARM64REV16W, typ.UInt16) v0.AddArg(w) v.AddArg3(ptr, v0, mem) return true } // match: (MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (SRLconst [8] (MOVDreg w)) mem)) // cond: x.Uses == 1 && s == nil && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && clobber(x) - // result: (MOVHstoreidx ptr0 idx0 (REV16W w) mem) + // result: (MOVHstoreidx ptr0 idx0 (REV16W w) mem) for { if auxIntToInt32(v.AuxInt) != 1 { break @@ -9755,7 +9756,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { continue } v.reset(OpARM64MOVHstoreidx) - v0 := b.NewValue0(v.Pos, OpARM64REV16W, w.Type) + v0 := b.NewValue0(v.Pos, OpARM64REV16W, typ.UInt16) v0.AddArg(w) v.AddArg4(ptr0, idx0, v0, mem) return true @@ -9764,7 +9765,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { } // match: (MOVBstore [i] {s} ptr w x:(MOVBstore [i-1] {s} ptr (UBFX [armBFAuxInt(8, 24)] w) mem)) // cond: x.Uses == 1 && clobber(x) - // result: (MOVHstore [i-1] {s} ptr (REV16W w) mem) + // result: (MOVHstore [i-1] {s} ptr (REV16W w) mem) for { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) @@ -9785,14 +9786,14 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { v.reset(OpARM64MOVHstore) v.AuxInt = int32ToAuxInt(i - 1) v.Aux = symToAux(s) - v0 := b.NewValue0(x.Pos, OpARM64REV16W, w.Type) + v0 := b.NewValue0(x.Pos, OpARM64REV16W, typ.UInt16) v0.AddArg(w) v.AddArg3(ptr, v0, mem) return true } // match: (MOVBstore [1] {s} (ADD ptr1 idx1) w x:(MOVBstoreidx ptr0 idx0 (UBFX [armBFAuxInt(8, 24)] w) mem)) // cond: x.Uses == 1 && s == nil && (isSamePtr(ptr0, ptr1) && isSamePtr(idx0, idx1) || isSamePtr(ptr0, idx1) && isSamePtr(idx0, ptr1)) && clobber(x) - // result: (MOVHstoreidx ptr0 idx0 (REV16W w) mem) + // result: (MOVHstoreidx ptr0 idx0 (REV16W w) mem) for { if auxIntToInt32(v.AuxInt) != 1 { break @@ -9820,7 +9821,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool { continue } v.reset(OpARM64MOVHstoreidx) - v0 := b.NewValue0(v.Pos, OpARM64REV16W, w.Type) + v0 := b.NewValue0(v.Pos, OpARM64REV16W, typ.UInt16) v0.AddArg(w) v.AddArg4(ptr0, idx0, v0, mem) return true @@ -9835,6 +9836,7 @@ func rewriteValueARM64_OpARM64MOVBstoreidx(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] b := v.Block + typ := &b.Func.Config.Types // match: (MOVBstoreidx ptr (MOVDconst [c]) val mem) // cond: is32Bit(c) // result: (MOVBstore [int32(c)] ptr val mem) @@ -9997,7 +9999,7 @@ func rewriteValueARM64_OpARM64MOVBstoreidx(v *Value) bool { } // match: (MOVBstoreidx ptr (ADDconst [3] idx) w x0:(MOVBstoreidx ptr (ADDconst [2] idx) (UBFX [armBFAuxInt(8, 24)] w) x1:(MOVBstoreidx ptr (ADDconst [1] idx) (UBFX [armBFAuxInt(16, 16)] w) x2:(MOVBstoreidx ptr idx (UBFX [armBFAuxInt(24, 8)] w) mem)))) // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && clobber(x0, x1, x2) - // result: (MOVWstoreidx ptr idx (REVW w) mem) + // result: (MOVWstoreidx ptr idx (REVW w) mem) for { ptr := v_0 if v_1.Op != OpARM64ADDconst || auxIntToInt64(v_1.AuxInt) != 3 { @@ -10050,7 +10052,7 @@ func rewriteValueARM64_OpARM64MOVBstoreidx(v *Value) bool { break } v.reset(OpARM64MOVWstoreidx) - v0 := b.NewValue0(v.Pos, OpARM64REVW, w.Type) + v0 := b.NewValue0(v.Pos, OpARM64REVW, typ.UInt32) v0.AddArg(w) v.AddArg4(ptr, idx, v0, mem) return true @@ -10116,7 +10118,7 @@ func rewriteValueARM64_OpARM64MOVBstoreidx(v *Value) bool { } // match: (MOVBstoreidx ptr (ADDconst [1] idx) w x:(MOVBstoreidx ptr idx (UBFX [armBFAuxInt(8, 8)] w) mem)) // cond: x.Uses == 1 && clobber(x) - // result: (MOVHstoreidx ptr idx (REV16W w) mem) + // result: (MOVHstoreidx ptr idx (REV16W w) mem) for { ptr := v_0 if v_1.Op != OpARM64ADDconst || auxIntToInt64(v_1.AuxInt) != 1 { @@ -10137,7 +10139,7 @@ func rewriteValueARM64_OpARM64MOVBstoreidx(v *Value) bool { break } v.reset(OpARM64MOVHstoreidx) - v0 := b.NewValue0(v.Pos, OpARM64REV16W, w.Type) + v0 := b.NewValue0(v.Pos, OpARM64REV16W, typ.UInt16) v0.AddArg(w) v.AddArg4(ptr, idx, v0, mem) return true diff --git a/test/fixedbugs/issue59367.go b/test/fixedbugs/issue59367.go new file mode 100644 index 00000000000000..32a79e120841cc --- /dev/null +++ b/test/fixedbugs/issue59367.go @@ -0,0 +1,80 @@ +// 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 + +func main() { + var b [8]byte + one := uint8(1) + f16(&one, b[:2]) + if b[1] != 1 { + println("2-byte value lost") + } + f32(&one, b[:4]) + if b[3] != 1 { + println("4-byte value lost") + } + f64(&one, b[:8]) + if b[7] != 1 { + println("8-byte value lost") + } +} + +//go:noinline +func f16(p *uint8, b []byte) { + _ = b[1] // bounds check + x := *p // load a byte + y := uint16(x) // zero extend to 16 bits + b[0] = byte(y >> 8) // compute ROLW + b[1] = byte(y) + nop() // spill/restore ROLW + b[0] = byte(y >> 8) // use ROLW + b[1] = byte(y) +} + +//go:noinline +func f32(p *uint8, b []byte) { + _ = b[3] // bounds check + x := *p // load a byte + y := uint32(x) // zero extend to 32 bits + b[0] = byte(y >> 24) // compute ROLL + b[1] = byte(y >> 16) + b[2] = byte(y >> 8) + b[3] = byte(y) + nop() // spill/restore ROLL + b[0] = byte(y >> 24) // use ROLL + b[1] = byte(y >> 16) + b[2] = byte(y >> 8) + b[3] = byte(y) +} + +//go:noinline +func f64(p *uint8, b []byte) { + _ = b[7] // bounds check + x := *p // load a byte + y := uint64(x) // zero extend to 64 bits + b[0] = byte(y >> 56) // compute ROLQ + b[1] = byte(y >> 48) + b[2] = byte(y >> 40) + b[3] = byte(y >> 32) + b[4] = byte(y >> 24) + b[5] = byte(y >> 16) + b[6] = byte(y >> 8) + b[7] = byte(y) + nop() // spill/restore ROLQ + b[0] = byte(y >> 56) // use ROLQ + b[1] = byte(y >> 48) + b[2] = byte(y >> 40) + b[3] = byte(y >> 32) + b[4] = byte(y >> 24) + b[5] = byte(y >> 16) + b[6] = byte(y >> 8) + b[7] = byte(y) +} + +//go:noinline +func nop() { +} From 446493f5b8dc1c1425862153bf39643a99b10bec Mon Sep 17 00:00:00 2001 From: David Chase Date: Thu, 6 Apr 2023 14:42:53 -0400 Subject: [PATCH 072/165] [release-branch.go1.20] cmd/compile: remove broken LEA "optimization" CL 440035 added rewrite rules to simplify "costly" LEA instructions, but the types in the rewrites were wrong and the code would go bad if the wrong-typed register was spilled. CL 482536 attempted to fix this by correcting the type in the rewrite, but that "fix" broke something on windows-amd64-race. Instead / for-now, remove the offending rewrite rules. Updates #21735. Updates #59432. Fixes #59468. Change-Id: I0497c42db414f2055e1378e0a53e2bceee9cd5d9 Reviewed-on: https://go-review.googlesource.com/c/go/+/482820 Run-TryBot: David Chase Reviewed-by: Cherry Mui TryBot-Result: Gopher Robot (cherry picked from commit 6a97a60b4b80dfa9db91200c054d734e18dda115) Reviewed-on: https://go-review.googlesource.com/c/go/+/482164 Auto-Submit: Dmitri Shuralyov Reviewed-by: Keith Randall Reviewed-by: Keith Randall --- .../internal/ssa/_gen/AMD64latelower.rules | 8 - .../internal/ssa/rewriteAMD64latelower.go | 393 ------------------ 2 files changed, 401 deletions(-) diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64latelower.rules b/src/cmd/compile/internal/ssa/_gen/AMD64latelower.rules index bcf453128aadf5..a1e63d6249ac8a 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64latelower.rules +++ b/src/cmd/compile/internal/ssa/_gen/AMD64latelower.rules @@ -2,14 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// split 3 operand LEA. -// Note: Don't split pointer computations in order to avoid invalid pointers. -(LEA(Q|L|W)1 [c] {s} x y) && isPtr(x.Type) && c != 0 && s == nil => (ADD(Q|L|L) x (ADD(Q|L|L)const [c] y)) -(LEA(Q|L|W)1 [c] {s} x y) && !isPtr(x.Type) && c != 0 && s == nil => (ADD(Q|L|L) y (ADD(Q|L|L)const [c] x)) -(LEA(Q|L|W)2 [c] {s} x y) && !isPtr(t) && c != 0 && s == nil => (ADD(Q|L|L)const [c] (LEA(Q|L|W)2 x y)) -(LEA(Q|L|W)4 [c] {s} x y) && !isPtr(t) && c != 0 && s == nil => (ADD(Q|L|L)const [c] (LEA(Q|L|W)4 x y)) -(LEA(Q|L|W)8 [c] {s} x y) && !isPtr(t) && c != 0 && s == nil => (ADD(Q|L|L)const [c] (LEA(Q|L|W)8 x y)) - // Prefer SARX/SHLX/SHRX instruction because it has less register restriction on the shift input. (SAR(Q|L) x y) && buildcfg.GOAMD64 >= 3 => (SARX(Q|L) x y) (SHL(Q|L) x y) && buildcfg.GOAMD64 >= 3 => (SHLX(Q|L) x y) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64latelower.go b/src/cmd/compile/internal/ssa/rewriteAMD64latelower.go index 792cddd09e355c..907225716834e6 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64latelower.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64latelower.go @@ -7,30 +7,6 @@ import "internal/buildcfg" func rewriteValueAMD64latelower(v *Value) bool { switch v.Op { - case OpAMD64LEAL1: - return rewriteValueAMD64latelower_OpAMD64LEAL1(v) - case OpAMD64LEAL2: - return rewriteValueAMD64latelower_OpAMD64LEAL2(v) - case OpAMD64LEAL4: - return rewriteValueAMD64latelower_OpAMD64LEAL4(v) - case OpAMD64LEAL8: - return rewriteValueAMD64latelower_OpAMD64LEAL8(v) - case OpAMD64LEAQ1: - return rewriteValueAMD64latelower_OpAMD64LEAQ1(v) - case OpAMD64LEAQ2: - return rewriteValueAMD64latelower_OpAMD64LEAQ2(v) - case OpAMD64LEAQ4: - return rewriteValueAMD64latelower_OpAMD64LEAQ4(v) - case OpAMD64LEAQ8: - return rewriteValueAMD64latelower_OpAMD64LEAQ8(v) - case OpAMD64LEAW1: - return rewriteValueAMD64latelower_OpAMD64LEAW1(v) - case OpAMD64LEAW2: - return rewriteValueAMD64latelower_OpAMD64LEAW2(v) - case OpAMD64LEAW4: - return rewriteValueAMD64latelower_OpAMD64LEAW4(v) - case OpAMD64LEAW8: - return rewriteValueAMD64latelower_OpAMD64LEAW8(v) case OpAMD64SARL: return rewriteValueAMD64latelower_OpAMD64SARL(v) case OpAMD64SARQ: @@ -46,375 +22,6 @@ func rewriteValueAMD64latelower(v *Value) bool { } return false } -func rewriteValueAMD64latelower_OpAMD64LEAL1(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (LEAL1 [c] {s} x y) - // cond: isPtr(x.Type) && c != 0 && s == nil - // result: (ADDL x (ADDLconst [c] y)) - for { - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - y := v_1 - if !(isPtr(x.Type) && c != 0 && s == nil) { - continue - } - v.reset(OpAMD64ADDL) - v0 := b.NewValue0(v.Pos, OpAMD64ADDLconst, y.Type) - v0.AuxInt = int32ToAuxInt(c) - v0.AddArg(y) - v.AddArg2(x, v0) - return true - } - break - } - // match: (LEAL1 [c] {s} x y) - // cond: !isPtr(x.Type) && c != 0 && s == nil - // result: (ADDL y (ADDLconst [c] x)) - for { - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - y := v_1 - if !(!isPtr(x.Type) && c != 0 && s == nil) { - continue - } - v.reset(OpAMD64ADDL) - v0 := b.NewValue0(v.Pos, OpAMD64ADDLconst, x.Type) - v0.AuxInt = int32ToAuxInt(c) - v0.AddArg(x) - v.AddArg2(y, v0) - return true - } - break - } - return false -} -func rewriteValueAMD64latelower_OpAMD64LEAL2(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (LEAL2 [c] {s} x y) - // cond: !isPtr(t) && c != 0 && s == nil - // result: (ADDLconst [c] (LEAL2 x y)) - for { - t := v.Type - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - x := v_0 - y := v_1 - if !(!isPtr(t) && c != 0 && s == nil) { - break - } - v.reset(OpAMD64ADDLconst) - v.AuxInt = int32ToAuxInt(c) - v0 := b.NewValue0(v.Pos, OpAMD64LEAL2, x.Type) - v0.AddArg2(x, y) - v.AddArg(v0) - return true - } - return false -} -func rewriteValueAMD64latelower_OpAMD64LEAL4(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (LEAL4 [c] {s} x y) - // cond: !isPtr(t) && c != 0 && s == nil - // result: (ADDLconst [c] (LEAL4 x y)) - for { - t := v.Type - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - x := v_0 - y := v_1 - if !(!isPtr(t) && c != 0 && s == nil) { - break - } - v.reset(OpAMD64ADDLconst) - v.AuxInt = int32ToAuxInt(c) - v0 := b.NewValue0(v.Pos, OpAMD64LEAL4, x.Type) - v0.AddArg2(x, y) - v.AddArg(v0) - return true - } - return false -} -func rewriteValueAMD64latelower_OpAMD64LEAL8(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (LEAL8 [c] {s} x y) - // cond: !isPtr(t) && c != 0 && s == nil - // result: (ADDLconst [c] (LEAL8 x y)) - for { - t := v.Type - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - x := v_0 - y := v_1 - if !(!isPtr(t) && c != 0 && s == nil) { - break - } - v.reset(OpAMD64ADDLconst) - v.AuxInt = int32ToAuxInt(c) - v0 := b.NewValue0(v.Pos, OpAMD64LEAL8, x.Type) - v0.AddArg2(x, y) - v.AddArg(v0) - return true - } - return false -} -func rewriteValueAMD64latelower_OpAMD64LEAQ1(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (LEAQ1 [c] {s} x y) - // cond: isPtr(x.Type) && c != 0 && s == nil - // result: (ADDQ x (ADDQconst [c] y)) - for { - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - y := v_1 - if !(isPtr(x.Type) && c != 0 && s == nil) { - continue - } - v.reset(OpAMD64ADDQ) - v0 := b.NewValue0(v.Pos, OpAMD64ADDQconst, y.Type) - v0.AuxInt = int32ToAuxInt(c) - v0.AddArg(y) - v.AddArg2(x, v0) - return true - } - break - } - // match: (LEAQ1 [c] {s} x y) - // cond: !isPtr(x.Type) && c != 0 && s == nil - // result: (ADDQ y (ADDQconst [c] x)) - for { - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - y := v_1 - if !(!isPtr(x.Type) && c != 0 && s == nil) { - continue - } - v.reset(OpAMD64ADDQ) - v0 := b.NewValue0(v.Pos, OpAMD64ADDQconst, x.Type) - v0.AuxInt = int32ToAuxInt(c) - v0.AddArg(x) - v.AddArg2(y, v0) - return true - } - break - } - return false -} -func rewriteValueAMD64latelower_OpAMD64LEAQ2(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (LEAQ2 [c] {s} x y) - // cond: !isPtr(t) && c != 0 && s == nil - // result: (ADDQconst [c] (LEAQ2 x y)) - for { - t := v.Type - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - x := v_0 - y := v_1 - if !(!isPtr(t) && c != 0 && s == nil) { - break - } - v.reset(OpAMD64ADDQconst) - v.AuxInt = int32ToAuxInt(c) - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ2, x.Type) - v0.AddArg2(x, y) - v.AddArg(v0) - return true - } - return false -} -func rewriteValueAMD64latelower_OpAMD64LEAQ4(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (LEAQ4 [c] {s} x y) - // cond: !isPtr(t) && c != 0 && s == nil - // result: (ADDQconst [c] (LEAQ4 x y)) - for { - t := v.Type - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - x := v_0 - y := v_1 - if !(!isPtr(t) && c != 0 && s == nil) { - break - } - v.reset(OpAMD64ADDQconst) - v.AuxInt = int32ToAuxInt(c) - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ4, x.Type) - v0.AddArg2(x, y) - v.AddArg(v0) - return true - } - return false -} -func rewriteValueAMD64latelower_OpAMD64LEAQ8(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (LEAQ8 [c] {s} x y) - // cond: !isPtr(t) && c != 0 && s == nil - // result: (ADDQconst [c] (LEAQ8 x y)) - for { - t := v.Type - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - x := v_0 - y := v_1 - if !(!isPtr(t) && c != 0 && s == nil) { - break - } - v.reset(OpAMD64ADDQconst) - v.AuxInt = int32ToAuxInt(c) - v0 := b.NewValue0(v.Pos, OpAMD64LEAQ8, x.Type) - v0.AddArg2(x, y) - v.AddArg(v0) - return true - } - return false -} -func rewriteValueAMD64latelower_OpAMD64LEAW1(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (LEAW1 [c] {s} x y) - // cond: isPtr(x.Type) && c != 0 && s == nil - // result: (ADDL x (ADDLconst [c] y)) - for { - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - y := v_1 - if !(isPtr(x.Type) && c != 0 && s == nil) { - continue - } - v.reset(OpAMD64ADDL) - v0 := b.NewValue0(v.Pos, OpAMD64ADDLconst, y.Type) - v0.AuxInt = int32ToAuxInt(c) - v0.AddArg(y) - v.AddArg2(x, v0) - return true - } - break - } - // match: (LEAW1 [c] {s} x y) - // cond: !isPtr(x.Type) && c != 0 && s == nil - // result: (ADDL y (ADDLconst [c] x)) - for { - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - y := v_1 - if !(!isPtr(x.Type) && c != 0 && s == nil) { - continue - } - v.reset(OpAMD64ADDL) - v0 := b.NewValue0(v.Pos, OpAMD64ADDLconst, x.Type) - v0.AuxInt = int32ToAuxInt(c) - v0.AddArg(x) - v.AddArg2(y, v0) - return true - } - break - } - return false -} -func rewriteValueAMD64latelower_OpAMD64LEAW2(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (LEAW2 [c] {s} x y) - // cond: !isPtr(t) && c != 0 && s == nil - // result: (ADDLconst [c] (LEAW2 x y)) - for { - t := v.Type - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - x := v_0 - y := v_1 - if !(!isPtr(t) && c != 0 && s == nil) { - break - } - v.reset(OpAMD64ADDLconst) - v.AuxInt = int32ToAuxInt(c) - v0 := b.NewValue0(v.Pos, OpAMD64LEAW2, x.Type) - v0.AddArg2(x, y) - v.AddArg(v0) - return true - } - return false -} -func rewriteValueAMD64latelower_OpAMD64LEAW4(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (LEAW4 [c] {s} x y) - // cond: !isPtr(t) && c != 0 && s == nil - // result: (ADDLconst [c] (LEAW4 x y)) - for { - t := v.Type - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - x := v_0 - y := v_1 - if !(!isPtr(t) && c != 0 && s == nil) { - break - } - v.reset(OpAMD64ADDLconst) - v.AuxInt = int32ToAuxInt(c) - v0 := b.NewValue0(v.Pos, OpAMD64LEAW4, x.Type) - v0.AddArg2(x, y) - v.AddArg(v0) - return true - } - return false -} -func rewriteValueAMD64latelower_OpAMD64LEAW8(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block - // match: (LEAW8 [c] {s} x y) - // cond: !isPtr(t) && c != 0 && s == nil - // result: (ADDLconst [c] (LEAW8 x y)) - for { - t := v.Type - c := auxIntToInt32(v.AuxInt) - s := auxToSym(v.Aux) - x := v_0 - y := v_1 - if !(!isPtr(t) && c != 0 && s == nil) { - break - } - v.reset(OpAMD64ADDLconst) - v.AuxInt = int32ToAuxInt(c) - v0 := b.NewValue0(v.Pos, OpAMD64LEAW8, x.Type) - v0.AddArg2(x, y) - v.AddArg(v0) - return true - } - return false -} func rewriteValueAMD64latelower_OpAMD64SARL(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] From ee42d468f50e863f240a8b11e521feaf7f9114c9 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 12 Apr 2023 12:41:45 -0700 Subject: [PATCH 073/165] [release-branch.go1.20] cmd/compile: fix reproducible build of aliased generic types Due to a missing "&& !alias" check, the unified linker was treating type aliases the same as defined types for the purpose of exporting method bodies. The methods will get exported anyway alongside the aliased type, so this mistake is normally harmless. However, if multiple type aliases instantiated the same generic type but with different type arguments, this could result in the same (generic) method body being exported multiple times under different symbol names. Further, because bodies aren't expected to be exported multiple times, we were sorting them simply based on index. And consequently, the sort wasn't total and is sensitive to the map iteration order used while ranging over linker.bodies. The fix is simply to add the missing "&& !alias" check, so that we don't end up with duplicate bodies in the first place. Thanks rsc@ for providing a minimal repro case. Fixes #59585. Change-Id: Iaa55968cc7110b601e2f0f9b620901c2d55f7014 Reviewed-on: https://go-review.googlesource.com/c/go/+/484155 Reviewed-by: Keith Randall Auto-Submit: Matthew Dempsky TryBot-Result: Gopher Robot Run-TryBot: Matthew Dempsky Reviewed-by: Keith Randall Reviewed-by: Russ Cox (cherry picked from commit f58c6cccc44752146aabcd50a30865e34817a4b4) Reviewed-on: https://go-review.googlesource.com/c/go/+/484160 Reviewed-by: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov Auto-Submit: Dmitri Shuralyov --- src/cmd/compile/internal/noder/linker.go | 2 +- .../go/testdata/script/build_issue59571.txt | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/testdata/script/build_issue59571.txt diff --git a/src/cmd/compile/internal/noder/linker.go b/src/cmd/compile/internal/noder/linker.go index 0f39fdec051f5f..5d0459d4129f1d 100644 --- a/src/cmd/compile/internal/noder/linker.go +++ b/src/cmd/compile/internal/noder/linker.go @@ -198,7 +198,7 @@ func (l *linker) relocObj(pr *pkgReader, idx pkgbits.Index) pkgbits.Index { l.exportBody(obj, local) } - if obj.Op() == ir.OTYPE { + if obj.Op() == ir.OTYPE && !obj.Alias() { if typ := obj.Type(); !typ.IsInterface() { for _, method := range typ.Methods().Slice() { l.exportBody(method.Nname.(*ir.Name), local) diff --git a/src/cmd/go/testdata/script/build_issue59571.txt b/src/cmd/go/testdata/script/build_issue59571.txt new file mode 100644 index 00000000000000..2cf32594bf4033 --- /dev/null +++ b/src/cmd/go/testdata/script/build_issue59571.txt @@ -0,0 +1,40 @@ +# Regression test for https://go.dev/issue/59571 +# Build should be reproducible, even with aliased generic types. + +go build -a -o 1.a +go build -a -o 2.a +cmp -q 1.a 2.a + +-- go.mod -- +module m + +go 1.20 +-- m.go -- +package m + +type ( + SliceFlag[T any] struct{} + + Alias1 = SliceFlag[[1]int] + Alias2 = SliceFlag[[2]int] + Alias3 = SliceFlag[[3]int] + Alias4 = SliceFlag[[4]int] + Alias5 = SliceFlag[[5]int] + Alias6 = SliceFlag[[6]int] + Alias7 = SliceFlag[[7]int] + Alias8 = SliceFlag[[8]int] + Alias9 = SliceFlag[[9]int] + Alias10 = SliceFlag[[10]int] + Alias11 = SliceFlag[[11]int] + Alias12 = SliceFlag[[12]int] + Alias13 = SliceFlag[[13]int] + Alias14 = SliceFlag[[14]int] + Alias15 = SliceFlag[[15]int] + Alias16 = SliceFlag[[16]int] + Alias17 = SliceFlag[[17]int] + Alias18 = SliceFlag[[18]int] + Alias19 = SliceFlag[[19]int] + Alias20 = SliceFlag[[20]int] +) + +func (x *SliceFlag[T]) String() string { return "zzz" } From 813a811d3308c82cfc5b739321a5eb973612a990 Mon Sep 17 00:00:00 2001 From: Tero Saarni Date: Wed, 12 Apr 2023 10:07:07 +0000 Subject: [PATCH 074/165] [release-branch.go1.20] crypto/tls: fix PSK binder calculation When server and client have mismatch in curve preference, the server will send HelloRetryRequest during TLSv1.3 PSK resumption. There was a bug introduced by Go1.19.6 or later and Go1.20.1 or later, that makes the client calculate the PSK binder hash incorrectly. Server will reject the TLS handshake by sending alert: invalid PSK binder. For #59424. Fixes #59540. Change-Id: I2ca8948474275740a36d991c057b62a13392dbb9 GitHub-Last-Rev: 1aad9bcf27f563449c1a7ed6d0dd1d247cc65713 GitHub-Pull-Request: golang/go#59425 Reviewed-on: https://go-review.googlesource.com/c/go/+/481955 Reviewed-by: Roland Shoemaker Reviewed-by: Dmitri Shuralyov Run-TryBot: Roland Shoemaker TryBot-Result: Gopher Robot Auto-Submit: Roland Shoemaker (cherry picked from commit 2c70690451f1484607a9172a4c24f78ae832dcb0) Reviewed-on: https://go-review.googlesource.com/c/go/+/488055 Auto-Submit: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov --- src/crypto/tls/handshake_client_test.go | 21 +++++++++++++++++++++ src/crypto/tls/handshake_client_tls13.go | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go index 749c9fc95452ad..22be38faff4687 100644 --- a/src/crypto/tls/handshake_client_test.go +++ b/src/crypto/tls/handshake_client_test.go @@ -1028,6 +1028,27 @@ func testResumption(t *testing.T, version uint16) { deleteTicket() testResumeState("WithoutSessionTicket", false) + // In TLS 1.3, HelloRetryRequest is sent after incorrect key share. + // See https://www.rfc-editor.org/rfc/rfc8446#page-14. + if version == VersionTLS13 { + deleteTicket() + serverConfig = &Config{ + // Use a different curve than the client to force a HelloRetryRequest. + CurvePreferences: []CurveID{CurveP521, CurveP384, CurveP256}, + MaxVersion: version, + Certificates: testConfig.Certificates, + } + testResumeState("InitialHandshake", false) + testResumeState("WithHelloRetryRequest", true) + + // Reset serverConfig back. + serverConfig = &Config{ + MaxVersion: version, + CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA}, + Certificates: testConfig.Certificates, + } + } + // Session resumption should work when using client certificates deleteTicket() serverConfig.ClientCAs = rootCAs diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go index fefba01a0611ac..4a8661085ebf57 100644 --- a/src/crypto/tls/handshake_client_tls13.go +++ b/src/crypto/tls/handshake_client_tls13.go @@ -259,7 +259,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { transcript := hs.suite.hash.New() transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) transcript.Write(chHash) - if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil { + if err := transcriptMsg(hs.serverHello, transcript); err != nil { return err } helloBytes, err := hs.hello.marshalWithoutBinders() From 484535e67b03ff8c757b66806032aee54a2a3bde Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 14 Apr 2023 16:48:26 +0000 Subject: [PATCH 075/165] cmd/compile/internal/importer,go/internal/gcimporter: use the 'go' command from build.Default.GOROOT in lookupGorootExport Also set GOROOT explicitly in case it is set to something else in the caller's environment. Updates #59598. Fixes #59637. Change-Id: I5599ed1183b23187fc3b976786f3c320d42ef4f3 Reviewed-on: https://go-review.googlesource.com/c/go/+/484756 Run-TryBot: Bryan Mills TryBot-Result: Gopher Robot Auto-Submit: Bryan Mills Reviewed-by: Michael Matloob (cherry picked from commit 750e91152bbd1cb2869660ddb80f2b3adcfd1f9b) Reviewed-on: https://go-review.googlesource.com/c/go/+/484758 Auto-Submit: Dmitri Shuralyov --- src/cmd/compile/internal/importer/gcimporter.go | 3 ++- src/go/internal/gcimporter/gcimporter.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/importer/gcimporter.go b/src/cmd/compile/internal/importer/gcimporter.go index 5d948f03c8a33f..490cdf94dfad5c 100644 --- a/src/cmd/compile/internal/importer/gcimporter.go +++ b/src/cmd/compile/internal/importer/gcimporter.go @@ -39,8 +39,9 @@ func lookupGorootExport(pkgDir string) (string, bool) { ) f, _ = exportMap.LoadOrStore(pkgDir, func() (string, bool) { listOnce.Do(func() { - cmd := exec.Command("go", "list", "-export", "-f", "{{.Export}}", pkgDir) + cmd := exec.Command(filepath.Join(build.Default.GOROOT, "bin", "go"), "list", "-export", "-f", "{{.Export}}", pkgDir) cmd.Dir = build.Default.GOROOT + cmd.Env = append(os.Environ(), "PWD="+cmd.Dir, "GOROOT="+build.Default.GOROOT) var output []byte output, err := cmd.Output() if err != nil { diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go index 2140a9f98c2c4a..284389aae73f4d 100644 --- a/src/go/internal/gcimporter/gcimporter.go +++ b/src/go/internal/gcimporter/gcimporter.go @@ -42,8 +42,9 @@ func lookupGorootExport(pkgDir string) (string, bool) { ) f, _ = exportMap.LoadOrStore(pkgDir, func() (string, bool) { listOnce.Do(func() { - cmd := exec.Command("go", "list", "-export", "-f", "{{.Export}}", pkgDir) + cmd := exec.Command(filepath.Join(build.Default.GOROOT, "bin", "go"), "list", "-export", "-f", "{{.Export}}", pkgDir) cmd.Dir = build.Default.GOROOT + cmd.Env = append(cmd.Environ(), "GOROOT="+build.Default.GOROOT) var output []byte output, err := cmd.Output() if err != nil { From 25b4f4062589a349117aaf52edf8db8ffa68773b Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 5 Apr 2023 10:19:44 -0700 Subject: [PATCH 076/165] [release-branch.go1.20] Revert "net/http: FileServer method check + minimal OPTIONS implementation" This reverts https://go.dev/cl/413554 Reason for revert: Backwards-incompatible change in behavior. For #53501 For #59375 Fixes #59469 Change-Id: Ic3f63b378f9c819599b32e5e6e410f6163849317 Reviewed-on: https://go-review.googlesource.com/c/go/+/482635 Reviewed-by: Tatiana Bradley Run-TryBot: Damien Neil TryBot-Result: Gopher Robot (cherry picked from commit c02fa75086dbc6db0d90f477e7b4c839140fdeb2) Reviewed-on: https://go-review.googlesource.com/c/go/+/488635 Reviewed-by: Dmitri Shuralyov Auto-Submit: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov --- src/net/http/fs.go | 20 +++++--------------- src/net/http/fs_test.go | 41 ----------------------------------------- 2 files changed, 5 insertions(+), 56 deletions(-) diff --git a/src/net/http/fs.go b/src/net/http/fs.go index 83459046bf76ea..41e0b43ac819bf 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -858,22 +858,12 @@ func FileServer(root FileSystem) Handler { } func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) { - const options = MethodOptions + ", " + MethodGet + ", " + MethodHead - - switch r.Method { - case MethodGet, MethodHead: - if !strings.HasPrefix(r.URL.Path, "/") { - r.URL.Path = "/" + r.URL.Path - } - serveFile(w, r, f.root, path.Clean(r.URL.Path), true) - - case MethodOptions: - w.Header().Set("Allow", options) - - default: - w.Header().Set("Allow", options) - Error(w, "read-only", StatusMethodNotAllowed) + upath := r.URL.Path + if !strings.HasPrefix(upath, "/") { + upath = "/" + upath + r.URL.Path = upath } + serveFile(w, r, f.root, path.Clean(upath), true) } // httpRange specifies the byte range to be sent to the client. diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go index 74f7a80e279e53..e25a580b1fada4 100644 --- a/src/net/http/fs_test.go +++ b/src/net/http/fs_test.go @@ -24,7 +24,6 @@ import ( "reflect" "regexp" "runtime" - "sort" "strings" "testing" "time" @@ -420,46 +419,6 @@ func testFileServerImplicitLeadingSlash(t *testing.T, mode testMode) { } } -func TestFileServerMethodOptions(t *testing.T) { run(t, testFileServerMethodOptions) } -func testFileServerMethodOptions(t *testing.T, mode testMode) { - const want = "GET, HEAD, OPTIONS" - ts := newClientServerTest(t, mode, FileServer(Dir("."))).ts - - tests := []struct { - method string - wantStatus int - }{ - {MethodOptions, StatusOK}, - - {MethodDelete, StatusMethodNotAllowed}, - {MethodPut, StatusMethodNotAllowed}, - {MethodPost, StatusMethodNotAllowed}, - } - - for _, test := range tests { - req, err := NewRequest(test.method, ts.URL, nil) - if err != nil { - t.Fatal(err) - } - res, err := ts.Client().Do(req) - if err != nil { - t.Fatal(err) - } - defer res.Body.Close() - - if res.StatusCode != test.wantStatus { - t.Errorf("%s got status %q, want code %d", test.method, res.Status, test.wantStatus) - } - - a := strings.Split(res.Header.Get("Allow"), ", ") - sort.Strings(a) - got := strings.Join(a, ", ") - if got != want { - t.Errorf("%s got Allow header %q, want %q", test.method, got, want) - } - } -} - func TestDirJoin(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("skipping test on windows") From 090590fdccc8442728aa31601927da1bf2ef1288 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Thu, 13 Apr 2023 15:40:44 -0700 Subject: [PATCH 077/165] [release-branch.go1.20] html/template: disallow angle brackets in CSS values Angle brackets should not appear in CSS contexts, as they may affect token boundaries (such as closing a