github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/tools/checklocks/facts.go (about)

     1  // Copyright 2020 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package checklocks
    16  
    17  import (
    18  	"encoding/gob"
    19  	"fmt"
    20  	"go/ast"
    21  	"go/token"
    22  	"go/types"
    23  	"regexp"
    24  	"strings"
    25  
    26  	"golang.org/x/tools/go/analysis/passes/buildssa"
    27  	"golang.org/x/tools/go/ssa"
    28  )
    29  
    30  // atomicAlignment is saved per type.
    31  //
    32  // This represents the alignment required for the type, which may
    33  // be implied and imposed by other types within the aggregate type.
    34  type atomicAlignment int
    35  
    36  // AFact implements analysis.Fact.AFact.
    37  func (*atomicAlignment) AFact() {}
    38  
    39  // atomicDisposition is saved per field.
    40  //
    41  // This represents how the field must be accessed. It must either
    42  // be non-atomic (default), atomic or ignored.
    43  type atomicDisposition int
    44  
    45  const (
    46  	atomicDisallow atomicDisposition = iota
    47  	atomicIgnore
    48  	atomicRequired
    49  )
    50  
    51  // fieldEntry is a single field type.
    52  type fieldEntry interface {
    53  	// synthesize produces a string that is compatible with valueAndObject,
    54  	// along with the same object that should be produced in that case.
    55  	//
    56  	// Note that it is called synthesize because this is produced only the
    57  	// type information, and not with any ssa.Value objects.
    58  	synthesize(s string, typ types.Type) (string, types.Object)
    59  }
    60  
    61  // fieldStruct is a non-pointer struct element.
    62  type fieldStruct int
    63  
    64  // synthesize implements fieldEntry.synthesize.
    65  func (f fieldStruct) synthesize(s string, typ types.Type) (string, types.Object) {
    66  	field, ok := findField(typ, int(f))
    67  	if !ok {
    68  		// Should not happen as long as fieldList construction is correct.
    69  		panic(fmt.Sprintf("unable to resolve field %d in %s", int(f), typ.String()))
    70  	}
    71  	return fmt.Sprintf("&(%s.%s)", s, field.Name()), field
    72  }
    73  
    74  // fieldStructPtr is a pointer struct element.
    75  type fieldStructPtr int
    76  
    77  // synthesize implements fieldEntry.synthesize.
    78  func (f fieldStructPtr) synthesize(s string, typ types.Type) (string, types.Object) {
    79  	field, ok := findField(typ, int(f))
    80  	if !ok {
    81  		// See above, this should not happen.
    82  		panic(fmt.Sprintf("unable to resolve ptr field %d in %s", int(f), typ.String()))
    83  	}
    84  	return fmt.Sprintf("*(&(%s.%s))", s, field.Name()), field
    85  }
    86  
    87  // fieldList is a simple list of fields, used in two types below.
    88  type fieldList []fieldEntry
    89  
    90  // resolvedValue is an ssa.Value with additional fields.
    91  //
    92  // This can be resolved to a string as part of a lock state.
    93  type resolvedValue struct {
    94  	value     ssa.Value
    95  	fieldList fieldList
    96  }
    97  
    98  // makeResolvedValue makes a new resolvedValue.
    99  func makeResolvedValue(v ssa.Value, fl fieldList) resolvedValue {
   100  	return resolvedValue{
   101  		value:     v,
   102  		fieldList: fl,
   103  	}
   104  }
   105  
   106  // valid indicates whether this is a valid resolvedValue.
   107  func (rv *resolvedValue) valid() bool {
   108  	return rv.value != nil
   109  }
   110  
   111  // valueAndObject returns a string and object.
   112  //
   113  // This uses the lockState valueAndObject in order to produce a string and
   114  // object for the base ssa.Value, then synthesizes a string representation
   115  // based on the fieldList.
   116  func (rv *resolvedValue) valueAndObject(ls *lockState) (string, types.Object) {
   117  	// N.B. obj.Type() and typ should be equal, but a check is omitted
   118  	// since, 1) we automatically chase through pointers during field
   119  	// resolution, and 2) obj may be nil if there is no source object.
   120  	s, obj := ls.valueAndObject(rv.value)
   121  	typ := rv.value.Type()
   122  	for _, entry := range rv.fieldList {
   123  		s, obj = entry.synthesize(s, typ)
   124  		typ = obj.Type()
   125  	}
   126  	return s, obj
   127  }
   128  
   129  // fieldGuardResolver details a guard for a field.
   130  type fieldGuardResolver interface {
   131  	// resolveField is used to resolve a guard during a field access. The
   132  	// parent structure is available, as well as the current lock state.
   133  	resolveField(pc *passContext, ls *lockState, parent ssa.Value) resolvedValue
   134  }
   135  
   136  // functionGuardResolver details a guard for a function.
   137  type functionGuardResolver interface {
   138  	// resolveStatic is used to resolve a guard during static analysis,
   139  	// e.g. based on static annotations applied to a method. The function's
   140  	// ssa object is available, as well as the return value.
   141  	resolveStatic(pc *passContext, ls *lockState, fn *ssa.Function, rv any) resolvedValue
   142  
   143  	// resolveCall is used to resolve a guard during a call. The ssa
   144  	// return value is available from the instruction context where the
   145  	// call occurs, but the target's ssa representation is not available.
   146  	resolveCall(pc *passContext, ls *lockState, args []ssa.Value, rv ssa.Value) resolvedValue
   147  }
   148  
   149  // lockGuardFacts contains guard information.
   150  type lockGuardFacts struct {
   151  	// GuardedBy is the set of locks that are guarding this field. The key
   152  	// is the original annotation value, and the field list is the object
   153  	// traversal path.
   154  	GuardedBy map[string]fieldGuardResolver
   155  
   156  	// AtomicDisposition is the disposition for this field. Note that this
   157  	// can affect the interpretation of the GuardedBy field above, see the
   158  	// relevant comment.
   159  	AtomicDisposition atomicDisposition
   160  }
   161  
   162  // AFact implements analysis.Fact.AFact.
   163  func (*lockGuardFacts) AFact() {}
   164  
   165  // globalGuard is a global value.
   166  type globalGuard struct {
   167  	// ObjectName indicates the object from which resolution should occur.
   168  	ObjectName string
   169  
   170  	// PackageName is the package where the object lives.
   171  	PackageName string
   172  
   173  	// FieldList is the traversal path from object.
   174  	FieldList fieldList
   175  }
   176  
   177  // ssaPackager returns the ssa package.
   178  type ssaPackager interface {
   179  	Package() *ssa.Package
   180  }
   181  
   182  // resolveCommon implements resolution for all cases.
   183  func (g *globalGuard) resolveCommon(pc *passContext, ls *lockState) resolvedValue {
   184  	state := pc.pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA)
   185  	pkg := state.Pkg
   186  	if g.PackageName != "" && g.PackageName != state.Pkg.Pkg.Path() {
   187  		pkg = state.Pkg.Prog.ImportedPackage(g.PackageName)
   188  	}
   189  	v := pkg.Members[g.ObjectName].(ssa.Value)
   190  	return makeResolvedValue(v, g.FieldList)
   191  }
   192  
   193  // resolveStatic implements functionGuardResolver.resolveStatic.
   194  func (g *globalGuard) resolveStatic(pc *passContext, ls *lockState, _ *ssa.Function, v any) resolvedValue {
   195  	return g.resolveCommon(pc, ls)
   196  }
   197  
   198  // resolveCall implements functionGuardResolver.resolveCall.
   199  func (g *globalGuard) resolveCall(pc *passContext, ls *lockState, _ []ssa.Value, v ssa.Value) resolvedValue {
   200  	return g.resolveCommon(pc, ls)
   201  }
   202  
   203  // resolveField implements fieldGuardResolver.resolveField.
   204  func (g *globalGuard) resolveField(pc *passContext, ls *lockState, parent ssa.Value) resolvedValue {
   205  	return g.resolveCommon(pc, ls)
   206  }
   207  
   208  // fieldGuard is a field-based guard.
   209  type fieldGuard struct {
   210  	// FieldList is the traversal path from the parent.
   211  	FieldList fieldList
   212  }
   213  
   214  // resolveField implements fieldGuardResolver.resolveField.
   215  func (f *fieldGuard) resolveField(_ *passContext, _ *lockState, parent ssa.Value) resolvedValue {
   216  	return makeResolvedValue(parent, f.FieldList)
   217  }
   218  
   219  // parameterGuard is a parameter-based guard.
   220  type parameterGuard struct {
   221  	// Index is the parameter index of the object that contains the
   222  	// guarding mutex.
   223  	Index int
   224  
   225  	// fieldList is the traversal path from the parameter.
   226  	FieldList fieldList
   227  }
   228  
   229  // resolveStatic implements functionGuardResolver.resolveStatic.
   230  func (p *parameterGuard) resolveStatic(_ *passContext, _ *lockState, fn *ssa.Function, _ any) resolvedValue {
   231  	return makeResolvedValue(fn.Params[p.Index], p.FieldList)
   232  }
   233  
   234  // resolveCall implements functionGuardResolver.resolveCall.
   235  func (p *parameterGuard) resolveCall(_ *passContext, _ *lockState, args []ssa.Value, _ ssa.Value) resolvedValue {
   236  	return makeResolvedValue(args[p.Index], p.FieldList)
   237  }
   238  
   239  // returnGuard is a return-based guard.
   240  type returnGuard struct {
   241  	// Index is the index of the return value.
   242  	Index int
   243  
   244  	// NeedsExtract is used in the case of a return value, and indicates
   245  	// that the field must be extracted from a tuple.
   246  	NeedsExtract bool
   247  
   248  	// FieldList is the traversal path from the return value.
   249  	FieldList fieldList
   250  }
   251  
   252  // resolveCommon implements resolution for both cases.
   253  func (r *returnGuard) resolveCommon(rv any) resolvedValue {
   254  	if rv == nil {
   255  		// For defers and other objects, this may be nil. This is
   256  		// handled in state.go in the actual lock checking logic. This
   257  		// means that there is no resolvedValue available.
   258  		return resolvedValue{}
   259  	}
   260  	// If this is a *ssa.Return object, i.e. we are analyzing the function
   261  	// and not the call site, then we can just pull the result directly.
   262  	if ret, ok := rv.(*ssa.Return); ok {
   263  		return makeResolvedValue(ret.Results[r.Index], r.FieldList)
   264  	}
   265  	if r.NeedsExtract {
   266  		// Resolve on the extracted field, this is necessary if the
   267  		// type here is not an explicit return. Note that rv must be an
   268  		// ssa.Value, since it is not an *ssa.Return.
   269  		v := rv.(ssa.Value)
   270  		if refs := v.Referrers(); refs != nil {
   271  			for _, inst := range *refs {
   272  				if x, ok := inst.(*ssa.Extract); ok && x.Tuple == v && x.Index == r.Index {
   273  					return makeResolvedValue(x, r.FieldList)
   274  				}
   275  			}
   276  		}
   277  		// Nothing resolved.
   278  		return resolvedValue{}
   279  	}
   280  	if r.Index != 0 {
   281  		// This should not happen, NeedsExtract should always be set.
   282  		panic("NeedsExtract is false, but return value index is non-zero")
   283  	}
   284  	// Resolve on the single return.
   285  	return makeResolvedValue(rv.(ssa.Value), r.FieldList)
   286  }
   287  
   288  // resolveStatic implements functionGuardResolver.resolveStatic.
   289  func (r *returnGuard) resolveStatic(_ *passContext, _ *lockState, _ *ssa.Function, rv any) resolvedValue {
   290  	return r.resolveCommon(rv)
   291  }
   292  
   293  // resolveCall implements functionGuardResolver.resolveCall.
   294  func (r *returnGuard) resolveCall(_ *passContext, _ *lockState, _ []ssa.Value, rv ssa.Value) resolvedValue {
   295  	return r.resolveCommon(rv)
   296  }
   297  
   298  // functionGuardInfo is information about a method guard.
   299  type functionGuardInfo struct {
   300  	// Resolver is the resolver for this guard.
   301  	Resolver functionGuardResolver
   302  
   303  	// IsAlias indicates that this guard is an alias.
   304  	IsAlias bool
   305  
   306  	// Exclusive indicates an exclusive lock is required.
   307  	Exclusive bool
   308  }
   309  
   310  // lockFunctionFacts apply on every method.
   311  type lockFunctionFacts struct {
   312  	// HeldOnEntry tracks the names and number of parameter (including receiver)
   313  	// lockFuncfields that guard calls to this function.
   314  	//
   315  	// The key is the name specified in the checklocks annotation. e.g given
   316  	// the following code:
   317  	//
   318  	// ```
   319  	// type A struct {
   320  	//	mu sync.Mutex
   321  	//	a int
   322  	// }
   323  	//
   324  	// // +checklocks:a.mu
   325  	// func xyz(a *A) {..}
   326  	// ```
   327  	//
   328  	// '`+checklocks:a.mu' will result in an entry in this map as shown below.
   329  	// HeldOnEntry: {"a.mu" => {Resolver: &parameterGuard{Index: 0}}
   330  	HeldOnEntry map[string]functionGuardInfo
   331  
   332  	// HeldOnExit tracks the locks that are expected to be held on exit.
   333  	HeldOnExit map[string]functionGuardInfo
   334  
   335  	// Ignore means this function has local analysis ignores.
   336  	//
   337  	// This is not used outside the local package.
   338  	Ignore bool
   339  }
   340  
   341  // AFact implements analysis.Fact.AFact.
   342  func (*lockFunctionFacts) AFact() {}
   343  
   344  // checkGuard validates the guardName.
   345  func (lff *lockFunctionFacts) checkGuard(pc *passContext, d *ast.FuncDecl, guardName string, exclusive bool, allowReturn bool) (functionGuardInfo, bool) {
   346  	if _, ok := lff.HeldOnEntry[guardName]; ok {
   347  		pc.maybeFail(d.Pos(), "annotation %s specified more than once, already required", guardName)
   348  		return functionGuardInfo{}, false
   349  	}
   350  	if _, ok := lff.HeldOnExit[guardName]; ok {
   351  		pc.maybeFail(d.Pos(), "annotation %s specified more than once, already acquired", guardName)
   352  		return functionGuardInfo{}, false
   353  	}
   354  	fg, ok := pc.findFunctionGuard(d, guardName, exclusive, allowReturn)
   355  	return fg, ok
   356  }
   357  
   358  // addGuardedBy adds a field to both HeldOnEntry and HeldOnExit.
   359  func (lff *lockFunctionFacts) addGuardedBy(pc *passContext, d *ast.FuncDecl, guardName string, exclusive bool) {
   360  	if fg, ok := lff.checkGuard(pc, d, guardName, exclusive, false /* allowReturn */); ok {
   361  		if lff.HeldOnEntry == nil {
   362  			lff.HeldOnEntry = make(map[string]functionGuardInfo)
   363  		}
   364  		if lff.HeldOnExit == nil {
   365  			lff.HeldOnExit = make(map[string]functionGuardInfo)
   366  		}
   367  		lff.HeldOnEntry[guardName] = fg
   368  		lff.HeldOnExit[guardName] = fg
   369  	}
   370  }
   371  
   372  // addAcquires adds a field to HeldOnExit.
   373  func (lff *lockFunctionFacts) addAcquires(pc *passContext, d *ast.FuncDecl, guardName string, exclusive bool) {
   374  	if fg, ok := lff.checkGuard(pc, d, guardName, exclusive, true /* allowReturn */); ok {
   375  		if lff.HeldOnExit == nil {
   376  			lff.HeldOnExit = make(map[string]functionGuardInfo)
   377  		}
   378  		lff.HeldOnExit[guardName] = fg
   379  	}
   380  }
   381  
   382  // addReleases adds a field to HeldOnEntry.
   383  func (lff *lockFunctionFacts) addReleases(pc *passContext, d *ast.FuncDecl, guardName string, exclusive bool) {
   384  	if fg, ok := lff.checkGuard(pc, d, guardName, exclusive, false /* allowReturn */); ok {
   385  		if lff.HeldOnEntry == nil {
   386  			lff.HeldOnEntry = make(map[string]functionGuardInfo)
   387  		}
   388  		lff.HeldOnEntry[guardName] = fg
   389  	}
   390  }
   391  
   392  // addAlias adds an alias.
   393  func (lff *lockFunctionFacts) addAlias(pc *passContext, d *ast.FuncDecl, guardName string) {
   394  	// Parse the alias.
   395  	parts := strings.Split(guardName, "=")
   396  	if len(parts) != 2 {
   397  		pc.maybeFail(d.Pos(), "invalid annotation %s for alias", guardName)
   398  		return
   399  	}
   400  
   401  	// Parse the actual guard.
   402  	fg, ok := lff.checkGuard(pc, d, parts[0], true /* exclusive */, true /* allowReturn */)
   403  	if !ok {
   404  		return
   405  	}
   406  	fg.IsAlias = true
   407  
   408  	// Find the existing specification.
   409  	_, entryOk := lff.HeldOnEntry[parts[1]]
   410  	if entryOk {
   411  		lff.HeldOnEntry[guardName] = fg
   412  	}
   413  	_, exitOk := lff.HeldOnExit[parts[1]]
   414  	if exitOk {
   415  		lff.HeldOnExit[guardName] = fg
   416  	}
   417  	if !entryOk && !exitOk {
   418  		pc.maybeFail(d.Pos(), "alias annotation %s does not refer to an existing guard", guardName)
   419  	}
   420  }
   421  
   422  // fieldEntryFor returns the fieldList value for the given object.
   423  func (pc *passContext) fieldEntryFor(fieldObj types.Object, index int) fieldEntry {
   424  
   425  	// Return the resolution path.
   426  	if _, ok := fieldObj.Type().Underlying().(*types.Pointer); ok {
   427  		return fieldStructPtr(index)
   428  	}
   429  	if _, ok := fieldObj.Type().Underlying().(*types.Interface); ok {
   430  		return fieldStructPtr(index)
   431  	}
   432  	return fieldStruct(index)
   433  }
   434  
   435  // findField resolves a field in a single struct.
   436  func (pc *passContext) findField(structType *types.Struct, fieldName string) (fl fieldList, fieldObj types.Object, ok bool) {
   437  	// Scan to match the next field.
   438  	for i := 0; i < structType.NumFields(); i++ {
   439  		fieldObj := structType.Field(i)
   440  		if fieldObj.Name() != fieldName {
   441  			continue
   442  		}
   443  		fl = append(fl, pc.fieldEntryFor(fieldObj, i))
   444  		return fl, fieldObj, true
   445  	}
   446  
   447  	// Is this an embed?
   448  	for i := 0; i < structType.NumFields(); i++ {
   449  		fieldObj := structType.Field(i)
   450  		if !fieldObj.Embedded() {
   451  			continue
   452  		}
   453  
   454  		// Is this an embedded struct?
   455  		structType, ok := resolveStruct(fieldObj.Type())
   456  		if !ok {
   457  			continue
   458  		}
   459  
   460  		// Need to check that there is a resolution path. If there is
   461  		// no resolution path that's not a failure: we just continue
   462  		// scanning the next embed to find a match.
   463  		flEmbed := pc.fieldEntryFor(fieldObj, i)
   464  		flNext, fieldObjNext, ok := pc.findField(structType, fieldName)
   465  		if !ok {
   466  			continue
   467  		}
   468  
   469  		// Found an embedded chain.
   470  		fl = append(fl, flEmbed)
   471  		fl = append(fl, flNext...)
   472  		return fl, fieldObjNext, true
   473  	}
   474  
   475  	return nil, nil, false
   476  }
   477  
   478  var (
   479  	mutexRE   = regexp.MustCompile(".*Mutex")
   480  	rwMutexRE = regexp.MustCompile(".*RWMutex")
   481  	lockerRE  = regexp.MustCompile(".*sync.Locker")
   482  )
   483  
   484  // validateMutex validates the mutex type.
   485  //
   486  // This function returns true iff the object is a valid mutex with an error
   487  // reported at the given position if necessary.
   488  func (pc *passContext) validateMutex(pos token.Pos, obj types.Object, exclusive bool) bool {
   489  	// Check that it is indeed a mutex.
   490  	s := obj.Type().String()
   491  	switch {
   492  	case rwMutexRE.MatchString(s):
   493  		// Safe for all cases.
   494  		return true
   495  	case mutexRE.MatchString(s), lockerRE.MatchString(s):
   496  		// Safe for exclusive cases.
   497  		if !exclusive {
   498  			pc.maybeFail(pos, "field %s must be a RWMutex", obj.Name())
   499  			return false
   500  		}
   501  		return true
   502  	default:
   503  		// Not a mutex at all?
   504  		pc.maybeFail(pos, "field %s is not a Mutex or an RWMutex", obj.Name())
   505  		return false
   506  	}
   507  }
   508  
   509  // findFieldList resolves a set of fields given a string, such a 'a.b.c'.
   510  //
   511  // Note that parts must be non-zero in length. If it may be zero, then
   512  // maybeFindFieldList should be used instead with an appropriate object.
   513  func (pc *passContext) findFieldList(pos token.Pos, structType *types.Struct, parts []string, exclusive bool) (fl fieldList, ok bool) {
   514  	var obj types.Object
   515  
   516  	// This loop requires at least one iteration in order to ensure that
   517  	// obj above is non-nil, and the type can be validated.
   518  	for i, fieldName := range parts {
   519  		flOne, fieldObj, ok := pc.findField(structType, fieldName)
   520  		if !ok {
   521  			return nil, false
   522  		}
   523  		fl = append(fl, flOne...)
   524  		obj = fieldObj
   525  		if i < len(parts)-1 {
   526  			structType, ok = resolveStruct(obj.Type())
   527  			if !ok {
   528  				// N.B. This is associated with the original position.
   529  				pc.maybeFail(pos, "field %s expected to be struct", fieldName)
   530  				return nil, false
   531  			}
   532  		}
   533  	}
   534  
   535  	// Validate the final field. This reports the field to the caller
   536  	// anyways, since the error will be reported only once.
   537  	_ = pc.validateMutex(pos, obj, exclusive)
   538  	return fl, true
   539  }
   540  
   541  // maybeFindFieldList resolves the given object.
   542  //
   543  // Parts may be the empty list, unlike findFieldList.
   544  func (pc *passContext) maybeFindFieldList(pos token.Pos, obj types.Object, parts []string, exclusive bool) (fl fieldList, ok bool) {
   545  	if len(parts) > 0 {
   546  		structType, ok := resolveStruct(obj.Type())
   547  		if !ok {
   548  			// This does not have any fields; the access is not allowed.
   549  			pc.maybeFail(pos, "attempted field access on non-struct")
   550  			return nil, false
   551  		}
   552  		return pc.findFieldList(pos, structType, parts, exclusive)
   553  	}
   554  
   555  	// See above.
   556  	_ = pc.validateMutex(pos, obj, exclusive)
   557  	return nil, true
   558  }
   559  
   560  // findFieldGuardResolver finds a symbol resolver.
   561  type findFieldGuardResolver func(pos token.Pos, guardName string) (fieldGuardResolver, bool)
   562  
   563  // findFunctionGuardResolver finds a symbol resolver.
   564  type findFunctionGuardResolver func(pos token.Pos, guardName string) (functionGuardResolver, bool)
   565  
   566  // fillLockGuardFacts fills the facts with guard information.
   567  func (pc *passContext) fillLockGuardFacts(obj types.Object, cg *ast.CommentGroup, find findFieldGuardResolver, lgf *lockGuardFacts) {
   568  	if cg == nil {
   569  		return
   570  	}
   571  	for _, l := range cg.List {
   572  		pc.extractAnnotations(l.Text, map[string]func(string){
   573  			checkAtomicAnnotation: func(string) {
   574  				switch lgf.AtomicDisposition {
   575  				case atomicRequired:
   576  					pc.maybeFail(obj.Pos(), "annotation is redundant, already atomic required")
   577  				case atomicIgnore:
   578  					pc.maybeFail(obj.Pos(), "annotation is contradictory, already atomic ignored")
   579  				}
   580  				lgf.AtomicDisposition = atomicRequired
   581  			},
   582  			checkLocksIgnore: func(string) {
   583  				switch lgf.AtomicDisposition {
   584  				case atomicIgnore:
   585  					pc.maybeFail(obj.Pos(), "annotation is redundant, already atomic ignored")
   586  				case atomicRequired:
   587  					pc.maybeFail(obj.Pos(), "annotation is contradictory, already atomic required")
   588  				}
   589  				lgf.AtomicDisposition = atomicIgnore
   590  			},
   591  			checkLocksAnnotation: func(guardName string) {
   592  				// Check for a duplicate annotation.
   593  				if _, ok := lgf.GuardedBy[guardName]; ok {
   594  					pc.maybeFail(obj.Pos(), "annotation %s specified more than once", guardName)
   595  					return
   596  				}
   597  				// Add the item.
   598  				if lgf.GuardedBy == nil {
   599  					lgf.GuardedBy = make(map[string]fieldGuardResolver)
   600  				}
   601  				fr, ok := find(obj.Pos(), guardName)
   602  				if !ok {
   603  					pc.maybeFail(obj.Pos(), "annotation %s cannot be resolved", guardName)
   604  					return
   605  				}
   606  				lgf.GuardedBy[guardName] = fr
   607  			},
   608  			// N.B. We support only the vanilla annotation on
   609  			// individual fields. If the field is a read lock, then
   610  			// we will allow read access by default.
   611  			checkLocksAnnotationRead: func(guardName string) {
   612  				pc.maybeFail(obj.Pos(), "annotation %s not legal on fields", guardName)
   613  			},
   614  		})
   615  	}
   616  	// Save only if there is something meaningful.
   617  	if len(lgf.GuardedBy) > 0 || lgf.AtomicDisposition != atomicDisallow {
   618  		pc.pass.ExportObjectFact(obj, lgf)
   619  	}
   620  }
   621  
   622  // findGlobalGuard attempts to resolve a name globally.
   623  func (pc *passContext) findGlobalGuard(pos token.Pos, guardName string) (*globalGuard, bool) {
   624  	// Attempt to resolve the object.
   625  	parts := strings.Split(guardName, ".")
   626  	globalObj := pc.pass.Pkg.Scope().Lookup(parts[0])
   627  	if globalObj == nil {
   628  		// No global object.
   629  		return nil, false
   630  	}
   631  	fl, ok := pc.maybeFindFieldList(pos, globalObj, parts[1:], true /* exclusive */)
   632  	if !ok {
   633  		// Invalid fields.
   634  		return nil, false
   635  	}
   636  	return &globalGuard{
   637  		ObjectName:  parts[0],
   638  		PackageName: pc.pass.Pkg.Path(),
   639  		FieldList:   fl,
   640  	}, true
   641  }
   642  
   643  // findGlobalFieldGuard is compatible with findFieldGuardResolver.
   644  func (pc *passContext) findGlobalFieldGuard(pos token.Pos, guardName string) (fieldGuardResolver, bool) {
   645  	g, ok := pc.findGlobalGuard(pos, guardName)
   646  	return g, ok
   647  }
   648  
   649  // findGlobalFunctionGuard is compatible with findFunctionGuardResolver.
   650  func (pc *passContext) findGlobalFunctionGuard(pos token.Pos, guardName string) (functionGuardResolver, bool) {
   651  	g, ok := pc.findGlobalGuard(pos, guardName)
   652  	return g, ok
   653  }
   654  
   655  // structLockGuardFacts finds all relevant guard information for structures.
   656  func (pc *passContext) structLockGuardFacts(structType *types.Struct, ss *ast.StructType) {
   657  	var fieldObj *types.Var
   658  	findLocal := func(pos token.Pos, guardName string) (fieldGuardResolver, bool) {
   659  		// Try to resolve from the local structure first.
   660  		fl, ok := pc.findFieldList(pos, structType, strings.Split(guardName, "."), true /* exclusive */)
   661  		if ok {
   662  			// Found a valid resolution.
   663  			return &fieldGuard{
   664  				FieldList: fl,
   665  			}, true
   666  		}
   667  		// Attempt a global resolution.
   668  		return pc.findGlobalFieldGuard(pos, guardName)
   669  	}
   670  	for i, field := range ss.Fields.List {
   671  		var lgf lockGuardFacts
   672  		fieldObj = structType.Field(i) // N.B. Captured above.
   673  		pc.fillLockGuardFacts(fieldObj, field.Doc, findLocal, &lgf)
   674  
   675  		// See above, for anonymous structure fields.
   676  		if ss, ok := field.Type.(*ast.StructType); ok {
   677  			if st, ok := fieldObj.Type().(*types.Struct); ok {
   678  				pc.structLockGuardFacts(st, ss)
   679  			}
   680  		}
   681  	}
   682  }
   683  
   684  // globalLockGuardFacts finds all relevant guard information for globals.
   685  //
   686  // Note that the Type is checked in checklocks.go at the top-level.
   687  func (pc *passContext) globalLockGuardFacts(vs *ast.ValueSpec) {
   688  	var lgf lockGuardFacts
   689  	globalObj := pc.pass.TypesInfo.ObjectOf(vs.Names[0])
   690  	pc.fillLockGuardFacts(globalObj, vs.Doc, pc.findGlobalFieldGuard, &lgf)
   691  }
   692  
   693  // countFields gives an accurate field count, according for unnamed arguments
   694  // and return values and the compact identifier format.
   695  func countFields(fl []*ast.Field) (count int) {
   696  	for _, field := range fl {
   697  		if len(field.Names) == 0 {
   698  			count++
   699  			continue
   700  		}
   701  		count += len(field.Names)
   702  	}
   703  	return
   704  }
   705  
   706  // matchFieldList attempts to match the given field.
   707  //
   708  // This function may or may not report an error. This is indicated in the
   709  // reported return value. If reported is true, then the specification is
   710  // ambiguous or not valid, and should be propagated.
   711  func (pc *passContext) matchFieldList(pos token.Pos, fields []*ast.Field, guardName string, exclusive bool) (number int, fl fieldList, reported, ok bool) {
   712  	parts := strings.Split(guardName, ".")
   713  	firstName := parts[0]
   714  	index := 0
   715  	for _, field := range fields {
   716  		// See countFields, above.
   717  		if len(field.Names) == 0 {
   718  			index++
   719  			continue
   720  		}
   721  		for _, name := range field.Names {
   722  			if name.Name != firstName {
   723  				index++
   724  				continue
   725  			}
   726  			obj := pc.pass.TypesInfo.ObjectOf(name)
   727  			fl, ok := pc.maybeFindFieldList(pos, obj, parts[1:], exclusive)
   728  			if !ok {
   729  				// Some intermediate name does not match. The
   730  				// resolveField function will not report.
   731  				pc.maybeFail(pos, "name %s does not resolve to a field", guardName)
   732  				return 0, nil, true, false
   733  			}
   734  			// Successfully found a field.
   735  			return index, fl, false, true
   736  		}
   737  	}
   738  
   739  	// Nothing matching.
   740  	return 0, nil, false, false
   741  }
   742  
   743  // findFunctionGuard identifies the parameter number and field number for a
   744  // particular string of the 'a.b'.
   745  //
   746  // This function will report any errors directly.
   747  func (pc *passContext) findFunctionGuard(d *ast.FuncDecl, guardName string, exclusive bool, allowReturn bool) (functionGuardInfo, bool) {
   748  	// Match against receiver & parameters.
   749  	var parameterList []*ast.Field
   750  	if d.Recv != nil {
   751  		parameterList = append(parameterList, d.Recv.List...)
   752  	}
   753  	if d.Type.Params != nil {
   754  		parameterList = append(parameterList, d.Type.Params.List...)
   755  	}
   756  	if index, fl, reported, ok := pc.matchFieldList(d.Pos(), parameterList, guardName, exclusive); reported || ok {
   757  		if !ok {
   758  			return functionGuardInfo{}, false
   759  		}
   760  		return functionGuardInfo{
   761  			Resolver: &parameterGuard{
   762  				Index:     index,
   763  				FieldList: fl,
   764  			},
   765  			Exclusive: exclusive,
   766  		}, true
   767  	}
   768  
   769  	// Match against return values, if allowed.
   770  	if allowReturn {
   771  		var returnList []*ast.Field
   772  		if d.Type.Results != nil {
   773  			returnList = append(returnList, d.Type.Results.List...)
   774  		}
   775  		if index, fl, reported, ok := pc.matchFieldList(d.Pos(), returnList, guardName, exclusive); reported || ok {
   776  			if !ok {
   777  				return functionGuardInfo{}, false
   778  			}
   779  			return functionGuardInfo{
   780  				Resolver: &returnGuard{
   781  					Index:        index,
   782  					FieldList:    fl,
   783  					NeedsExtract: countFields(returnList) > 1,
   784  				},
   785  				Exclusive: exclusive,
   786  			}, true
   787  		}
   788  	}
   789  
   790  	// Match against globals.
   791  	if g, ok := pc.findGlobalFunctionGuard(d.Pos(), guardName); ok {
   792  		return functionGuardInfo{
   793  			Resolver:  g,
   794  			Exclusive: exclusive,
   795  		}, true
   796  	}
   797  
   798  	// No match found.
   799  	pc.maybeFail(d.Pos(), "annotation %s does not have a match any parameter, return value or global", guardName)
   800  	return functionGuardInfo{}, false
   801  }
   802  
   803  // functionFacts exports relevant function findings.
   804  func (pc *passContext) functionFacts(d *ast.FuncDecl) {
   805  	// Extract guard information.
   806  	if d.Doc == nil || d.Doc.List == nil {
   807  		return
   808  	}
   809  	var lff lockFunctionFacts
   810  	for _, l := range d.Doc.List {
   811  		pc.extractAnnotations(l.Text, map[string]func(string){
   812  			checkLocksIgnore: func(string) {
   813  				// Note that this applies to all atomic
   814  				// analysis as well. There is no provided way
   815  				// to selectively ignore only lock analysis or
   816  				// atomic analysis, as we expect this use to be
   817  				// extremely rare.
   818  				lff.Ignore = true
   819  			},
   820  			checkLocksAnnotation:     func(guardName string) { lff.addGuardedBy(pc, d, guardName, true /* exclusive */) },
   821  			checkLocksAnnotationRead: func(guardName string) { lff.addGuardedBy(pc, d, guardName, false /* exclusive */) },
   822  			checkLocksAcquires:       func(guardName string) { lff.addAcquires(pc, d, guardName, true /* exclusive */) },
   823  			checkLocksAcquiresRead:   func(guardName string) { lff.addAcquires(pc, d, guardName, false /* exclusive */) },
   824  			checkLocksReleases:       func(guardName string) { lff.addReleases(pc, d, guardName, true /* exclusive */) },
   825  			checkLocksReleasesRead:   func(guardName string) { lff.addReleases(pc, d, guardName, false /* exclusive */) },
   826  			checkLocksAlias:          func(guardName string) { lff.addAlias(pc, d, guardName) },
   827  		})
   828  	}
   829  
   830  	// Export the function facts if there is anything to save.
   831  	if lff.Ignore || len(lff.HeldOnEntry) > 0 || len(lff.HeldOnExit) > 0 {
   832  		funcObj := pc.pass.TypesInfo.Defs[d.Name].(*types.Func)
   833  		pc.pass.ExportObjectFact(funcObj, &lff)
   834  	}
   835  }
   836  
   837  func init() {
   838  	gob.Register((*returnGuard)(nil))
   839  	gob.Register((*globalGuard)(nil))
   840  	gob.Register((*parameterGuard)(nil))
   841  	gob.Register((*fieldGuard)(nil))
   842  	gob.Register((*fieldStructPtr)(nil))
   843  	gob.Register((*fieldStruct)(nil))
   844  }