Support anonymous structs in checklocks.
Fixes #6558 PiperOrigin-RevId: 396393293
This commit is contained in:
parent
63b1c736b3
commit
6bcacb2fd1
|
@ -41,17 +41,6 @@ func (l *linkResolver) confirmReachable(addr tcpip.Address) {
|
|||
|
||||
var _ NetworkInterface = (*nic)(nil)
|
||||
|
||||
// TODO(https://gvisor.dev/issue/6558): Use an anonymous struct in nic for this
|
||||
// once copylocks supports anonymous structs.
|
||||
type packetEPs struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
// eps is protected by the mutex, but the values contained in it are not.
|
||||
//
|
||||
// +checklocks:mu
|
||||
eps map[tcpip.NetworkProtocolNumber]*packetEndpointList
|
||||
}
|
||||
|
||||
// nic represents a "network interface card" to which the networking stack is
|
||||
// attached.
|
||||
type nic struct {
|
||||
|
@ -85,7 +74,14 @@ type nic struct {
|
|||
promiscuous bool
|
||||
}
|
||||
|
||||
packetEPs packetEPs
|
||||
packetEPs struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
// eps is protected by the mutex, but the values contained in it are not.
|
||||
//
|
||||
// +checklocks:mu
|
||||
eps map[tcpip.NetworkProtocolNumber]*packetEndpointList
|
||||
}
|
||||
}
|
||||
|
||||
// makeNICStats initializes the NIC statistics and associates them to the global
|
||||
|
|
|
@ -90,12 +90,14 @@ func run(pass *analysis.Pass) (interface{}, error) {
|
|||
// Find all struct declarations and export relevant facts.
|
||||
pc.forAllTypes(func(ts *ast.TypeSpec) {
|
||||
if ss, ok := ts.Type.(*ast.StructType); ok {
|
||||
pc.exportLockFieldFacts(ts, ss)
|
||||
structType := pc.pass.TypesInfo.TypeOf(ts.Name).Underlying().(*types.Struct)
|
||||
pc.exportLockFieldFacts(structType, ss)
|
||||
}
|
||||
})
|
||||
pc.forAllTypes(func(ts *ast.TypeSpec) {
|
||||
if ss, ok := ts.Type.(*ast.StructType); ok {
|
||||
pc.exportLockGuardFacts(ts, ss)
|
||||
structType := pc.pass.TypesInfo.TypeOf(ts.Name).Underlying().(*types.Struct)
|
||||
pc.exportLockGuardFacts(structType, ss)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -399,13 +399,12 @@ var (
|
|||
)
|
||||
|
||||
// exportLockFieldFacts finds all struct fields that are mutexes, and ensures
|
||||
// that they are annotated approperly.
|
||||
// that they are annotated properly.
|
||||
//
|
||||
// This information is consumed subsequently by exportLockGuardFacts, and this
|
||||
// function must be called first on all structures.
|
||||
func (pc *passContext) exportLockFieldFacts(ts *ast.TypeSpec, ss *ast.StructType) {
|
||||
structType := pc.pass.TypesInfo.TypeOf(ts.Name).Underlying().(*types.Struct)
|
||||
for i := range ss.Fields.List {
|
||||
func (pc *passContext) exportLockFieldFacts(structType *types.Struct, ss *ast.StructType) {
|
||||
for i, field := range ss.Fields.List {
|
||||
lff := &lockFieldFacts{
|
||||
FieldNumber: i,
|
||||
}
|
||||
|
@ -426,6 +425,13 @@ func (pc *passContext) exportLockFieldFacts(ts *ast.TypeSpec, ss *ast.StructType
|
|||
// We must always export the lockFieldFacts, since traversal
|
||||
// can take place along any object in the struct.
|
||||
pc.pass.ExportObjectFact(fieldObj, lff)
|
||||
// If this is an anonymous type, then we won't discover it via
|
||||
// the AST global declarations. We can recurse from here.
|
||||
if ss, ok := field.Type.(*ast.StructType); ok {
|
||||
if st, ok := fieldObj.Type().(*types.Struct); ok {
|
||||
pc.exportLockFieldFacts(st, ss)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,18 +439,15 @@ func (pc *passContext) exportLockFieldFacts(ts *ast.TypeSpec, ss *ast.StructType
|
|||
//
|
||||
// This function requires exportLockFieldFacts be called first on all
|
||||
// structures.
|
||||
func (pc *passContext) exportLockGuardFacts(ts *ast.TypeSpec, ss *ast.StructType) {
|
||||
structType := pc.pass.TypesInfo.TypeOf(ts.Name).Underlying().(*types.Struct)
|
||||
func (pc *passContext) exportLockGuardFacts(structType *types.Struct, ss *ast.StructType) {
|
||||
for i, field := range ss.Fields.List {
|
||||
if field.Doc == nil {
|
||||
continue
|
||||
}
|
||||
fieldObj := structType.Field(i)
|
||||
if field.Doc != nil {
|
||||
var (
|
||||
lff lockFieldFacts
|
||||
lgf lockGuardFacts
|
||||
)
|
||||
pc.pass.ImportObjectFact(structType.Field(i), &lff)
|
||||
fieldObj := structType.Field(i)
|
||||
for _, l := range field.Doc.List {
|
||||
pc.extractAnnotations(l.Text, map[string]func(string){
|
||||
checkAtomicAnnotation: func(string) {
|
||||
|
@ -488,6 +491,13 @@ func (pc *passContext) exportLockGuardFacts(ts *ast.TypeSpec, ss *ast.StructType
|
|||
pc.pass.ExportObjectFact(structType.Field(i), &lgf)
|
||||
}
|
||||
}
|
||||
// See above, for anonymous structure fields.
|
||||
if ss, ok := field.Type.(*ast.StructType); ok {
|
||||
if st, ok := fieldObj.Type().(*types.Struct); ok {
|
||||
pc.exportLockGuardFacts(st, ss)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// countFields gives an accurate field count, according for unnamed arguments
|
||||
|
|
|
@ -6,6 +6,7 @@ go_library(
|
|||
name = "test",
|
||||
srcs = [
|
||||
"alignment.go",
|
||||
"anon.go",
|
||||
"atomics.go",
|
||||
"basics.go",
|
||||
"branches.go",
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2021 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package test
|
||||
|
||||
import "sync"
|
||||
|
||||
type anonStruct struct {
|
||||
anon struct {
|
||||
mu sync.RWMutex
|
||||
// +checklocks:mu
|
||||
x int
|
||||
}
|
||||
}
|
||||
|
||||
func testAnonAccessValid(tc *anonStruct) {
|
||||
tc.anon.mu.Lock()
|
||||
tc.anon.x = 1
|
||||
tc.anon.mu.Unlock()
|
||||
}
|
||||
|
||||
func testAnonAccessInvalid(tc *anonStruct) {
|
||||
tc.anon.x = 1 // +checklocksfail
|
||||
}
|
Loading…
Reference in New Issue