Catch range and elided-literal writes to protected fields

Range clauses can assign a protected field directly, and an elided
literal inside a []*T or map[K]*T composite initializes a fresh header
just like &T{...} does. Both bypassed the write check.
This commit is contained in:
Jake Bailey committed 2026-10-14 10:19:57 -07:00
1 parent 424618b8aa
commit f4d9da17e9
3 files changed
+48 -1

No files matched your search

+14 -1
View File
@@ -38,6 +38,7 @@ func (p *protectedFieldPass) run() (any, error) {
for c := range in.Root().Preorder(
(*ast.AssignStmt)(nil),
(*ast.IncDecStmt)(nil),
(*ast.RangeStmt)(nil),
(*ast.UnaryExpr)(nil),
(*ast.CompositeLit)(nil),
(*ast.FuncType)(nil),
@@ -50,6 +51,13 @@ func (p *protectedFieldPass) run() (any, error) {
}
case *ast.IncDecStmt:
p.checkWrite(node.X, "write to")
case *ast.RangeStmt:
if node.Key != nil {
p.checkWrite(node.Key, "write to")
}
if node.Value != nil {
p.checkWrite(node.Value, "write to")
}
case *ast.UnaryExpr:
if node.Op == token.AND {
p.checkWrite(node.X, "address of")
@@ -107,7 +115,12 @@ func (p *protectedFieldPass) checkWrite(expr ast.Expr, what string) {
}
func (p *protectedFieldPass) checkLiteral(lit *ast.CompositeLit) {
st, ok := p.pass.TypesInfo.TypeOf(lit).Underlying().(*types.Struct)
typ := p.pass.TypesInfo.TypeOf(lit)
// Elided literals in []*T or map[K]*T composites have type *T.
if ptr, ok := typ.Underlying().(*types.Pointer); ok {
typ = ptr.Elem()
}
st, ok := typ.Underlying().(*types.Struct)
if !ok {
return
}
@@ -17,6 +17,14 @@ func writes(h *record.Header, s *record.Small, d *record.Defined) {
h.Flags = 1
_ = &h.Flags
_ = h.Kind
for _, h.Kind = range []record.Kind{record.KindLarge} {
}
for h.Kind = range record.Kind(2) {
}
var kinds []record.Kind
for _, kind := range kinds {
_ = kind
}
}
func literals() {
@@ -25,6 +33,10 @@ func literals() {
_ = &record.Header{Flags: 1}
_ = &record.Small{}
_ = &record.Alias{Kind: record.KindSmall}
_ = []*record.Header{{Kind: record.KindLarge}}
_ = []*record.Header{{record.KindLarge, 1}}
_ = map[int]*record.Header{0: {Kind: record.KindLarge}}
_ = []*record.Header{{Flags: 1}}
}
func copies(h *record.Header, s *record.Small, hs []record.Header) {
@@ -29,6 +29,18 @@
h.Flags = 1
_ = &h.Flags
_ = h.Kind
for _, h.Kind = range []record.Kind{record.KindLarge} {
~
!!! protectedfield: write to protected field Kind
}
for h.Kind = range record.Kind(2) {
~
!!! protectedfield: write to protected field Kind
}
var kinds []record.Kind
for _, kind := range kinds {
_ = kind
}
}
func literals() {
@@ -43,6 +55,16 @@
_ = &record.Alias{Kind: record.KindSmall}
~
!!! protectedfield: write to protected field Kind
_ = []*record.Header{{Kind: record.KindLarge}}
~
!!! protectedfield: write to protected field Kind
_ = []*record.Header{{record.KindLarge, 1}}
~
!!! protectedfield: write to protected field Kind
_ = map[int]*record.Header{0: {Kind: record.KindLarge}}
~
!!! protectedfield: write to protected field Kind
_ = []*record.Header{{Flags: 1}}
}
func copies(h *record.Header, s *record.Small, hs []record.Header) {