github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/compiler/check.go (about)

     1  // Copyright 2017 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  // Package compiler generates sys descriptions of syscalls, types and resources
     5  // from textual descriptions.
     6  package compiler
     7  
     8  import (
     9  	"errors"
    10  	"fmt"
    11  	"regexp"
    12  	"strings"
    13  
    14  	"github.com/google/syzkaller/pkg/ast"
    15  	"github.com/google/syzkaller/prog"
    16  	"github.com/google/syzkaller/sys/targets"
    17  )
    18  
    19  func (comp *compiler) typecheck() {
    20  	comp.checkComments()
    21  	comp.checkDirectives()
    22  	comp.checkNames()
    23  	comp.checkFlags()
    24  	comp.checkFields()
    25  	comp.checkTypedefs()
    26  	comp.checkTypes()
    27  }
    28  
    29  func (comp *compiler) check(consts map[string]uint64) {
    30  	comp.checkTypeValues()
    31  	comp.checkAttributeValues()
    32  	comp.checkUnused()
    33  	comp.checkRecursion()
    34  	comp.checkFieldPaths()
    35  	comp.checkConstructors()
    36  	comp.checkVarlens()
    37  	comp.checkDupConsts()
    38  	comp.checkConstsFlags(consts)
    39  }
    40  
    41  func (comp *compiler) checkComments() {
    42  	confusingComment := regexp.MustCompile(`^\s*(include|incdir|define)`)
    43  	for _, decl := range comp.desc.Nodes {
    44  		switch n := decl.(type) {
    45  		case *ast.Comment:
    46  			if confusingComment.MatchString(n.Text) {
    47  				comp.error(n.Pos, "confusing comment faking a directive (rephrase if it's intentional)")
    48  			}
    49  		}
    50  	}
    51  }
    52  
    53  func (comp *compiler) checkDirectives() {
    54  	includes := make(map[string]bool)
    55  	incdirs := make(map[string]bool)
    56  	defines := make(map[string]bool)
    57  	for _, decl := range comp.desc.Nodes {
    58  		switch n := decl.(type) {
    59  		case *ast.Include:
    60  			name := n.File.Value
    61  			path := n.Pos.File + "/" + name
    62  			if includes[path] {
    63  				comp.error(n.Pos, "duplicate include %q", name)
    64  			}
    65  			includes[path] = true
    66  		case *ast.Incdir:
    67  			name := n.Dir.Value
    68  			path := n.Pos.File + "/" + name
    69  			if incdirs[path] {
    70  				comp.error(n.Pos, "duplicate incdir %q", name)
    71  			}
    72  			incdirs[path] = true
    73  		case *ast.Define:
    74  			name := n.Name.Name
    75  			path := n.Pos.File + "/" + name
    76  			if defines[path] {
    77  				comp.error(n.Pos, "duplicate define %v", name)
    78  			}
    79  			defines[path] = true
    80  		}
    81  	}
    82  }
    83  
    84  func (comp *compiler) checkNames() {
    85  	calls := make(map[string]*ast.Call)
    86  	for _, decl := range comp.desc.Nodes {
    87  		switch n := decl.(type) {
    88  		case *ast.Resource, *ast.Struct, *ast.TypeDef:
    89  			pos, typ, name := decl.Info()
    90  			if reservedName[name] {
    91  				comp.error(pos, "%v uses reserved name %v", typ, name)
    92  				continue
    93  			}
    94  			if builtinTypes[name] != nil {
    95  				comp.error(pos, "%v name %v conflicts with builtin type", typ, name)
    96  				continue
    97  			}
    98  			if prev := comp.resources[name]; prev != nil {
    99  				comp.error(pos, "type %v redeclared, previously declared as resource at %v",
   100  					name, prev.Pos)
   101  				continue
   102  			}
   103  			if prev := comp.typedefs[name]; prev != nil {
   104  				comp.error(pos, "type %v redeclared, previously declared as type alias at %v",
   105  					name, prev.Pos)
   106  				continue
   107  			}
   108  			if prev := comp.structs[name]; prev != nil {
   109  				_, typ, _ := prev.Info()
   110  				comp.error(pos, "type %v redeclared, previously declared as %v at %v",
   111  					name, typ, prev.Pos)
   112  				continue
   113  			}
   114  			switch n := decl.(type) {
   115  			case *ast.Resource:
   116  				comp.resources[name] = n
   117  			case *ast.TypeDef:
   118  				comp.typedefs[name] = n
   119  			case *ast.Struct:
   120  				comp.structs[name] = n
   121  			}
   122  		case *ast.IntFlags:
   123  			name := n.Name.Name
   124  			if name == "_" {
   125  				continue
   126  			}
   127  			if reservedName[name] {
   128  				comp.error(n.Pos, "flags uses reserved name %v", name)
   129  				continue
   130  			}
   131  			if prev := comp.intFlags[name]; prev != nil {
   132  				comp.error(n.Pos, "flags %v redeclared, previously declared at %v",
   133  					name, prev.Pos)
   134  				continue
   135  			}
   136  			comp.intFlags[name] = n
   137  		case *ast.StrFlags:
   138  			name := n.Name.Name
   139  			if reservedName[name] {
   140  				comp.error(n.Pos, "string flags uses reserved name %v", name)
   141  				continue
   142  			}
   143  			if prev := comp.strFlags[name]; prev != nil {
   144  				comp.error(n.Pos, "string flags %v redeclared, previously declared at %v",
   145  					name, prev.Pos)
   146  				continue
   147  			}
   148  			comp.strFlags[name] = n
   149  		case *ast.Call:
   150  			name := n.Name.Name
   151  			if prev := calls[name]; prev != nil {
   152  				comp.error(n.Pos, "syscall %v redeclared, previously declared at %v",
   153  					name, prev.Pos)
   154  			}
   155  			calls[name] = n
   156  		}
   157  	}
   158  }
   159  
   160  func (comp *compiler) checkFlags() {
   161  	checkFlagsGeneric[*ast.IntFlags, *ast.Int](comp, comp.intFlags)
   162  	checkFlagsGeneric[*ast.StrFlags, *ast.String](comp, comp.strFlags)
   163  }
   164  
   165  func checkFlagsGeneric[F ast.Flags[V], V ast.FlagValue](comp *compiler, allFlags map[string]F) {
   166  	for name, flags := range allFlags {
   167  		inConstIdent := true
   168  		for _, val := range flags.GetValues() {
   169  			if _, ok := allFlags[val.GetName()]; ok {
   170  				inConstIdent = false
   171  			} else {
   172  				if !inConstIdent {
   173  					comp.error(flags.GetPos(), "flags identifier not at the end in %v definition", name)
   174  					break
   175  				}
   176  			}
   177  		}
   178  	}
   179  }
   180  
   181  func (comp *compiler) checkFields() {
   182  	for _, decl := range comp.desc.Nodes {
   183  		switch n := decl.(type) {
   184  		case *ast.Struct:
   185  			_, typ, name := n.Info()
   186  			comp.checkStructFields(n, typ, name)
   187  		case *ast.TypeDef:
   188  			if n.Struct != nil {
   189  				_, typ, _ := n.Struct.Info()
   190  				comp.checkStructFields(n.Struct, "template "+typ, n.Name.Name)
   191  			}
   192  		case *ast.Call:
   193  			name := n.Name.Name
   194  			comp.checkFieldGroup(n.Args, "argument", "syscall "+name)
   195  			if len(n.Args) > prog.MaxArgs {
   196  				comp.error(n.Pos, "syscall %v has %v arguments, allowed maximum is %v",
   197  					name, len(n.Args), prog.MaxArgs)
   198  			}
   199  		}
   200  	}
   201  }
   202  
   203  func (comp *compiler) checkStructFields(n *ast.Struct, typ, name string) {
   204  	comp.checkFieldGroup(n.Fields, "field", typ+" "+name)
   205  	if len(n.Fields) < 1 {
   206  		comp.error(n.Pos, "%v %v has no fields, need at least 1 field", typ, name)
   207  	}
   208  	hasDirections, hasOutOverlay := false, false
   209  	prevFieldHadIf := false
   210  	for fieldIdx, f := range n.Fields {
   211  		if n.IsUnion {
   212  			_, exprs, _ := comp.parseAttrs(unionFieldAttrs, f, f.Attrs)
   213  			if fieldIdx > 0 && fieldIdx+1 < len(n.Fields) &&
   214  				prevFieldHadIf && exprs[attrIf] == nil {
   215  				comp.error(f.Pos, "either no fields have conditions or all except the last")
   216  			}
   217  			prevFieldHadIf = exprs[attrIf] != nil
   218  			if fieldIdx+1 == len(n.Fields) && exprs[attrIf] != nil {
   219  				comp.error(f.Pos, "unions must not have if conditions on the last field")
   220  			}
   221  			continue
   222  		}
   223  		attrs, _, _ := comp.parseAttrs(structFieldAttrs, f, f.Attrs)
   224  		dirCount := attrs[attrIn] + attrs[attrOut] + attrs[attrInOut]
   225  		if dirCount != 0 {
   226  			hasDirections = true
   227  		}
   228  		if dirCount > 1 {
   229  			_, typ, _ := f.Info()
   230  			comp.error(f.Pos, "%v has multiple direction attributes", typ)
   231  		}
   232  		if attrs[attrOutOverlay] > 0 {
   233  			if fieldIdx == 0 {
   234  				comp.error(f.Pos, "%v attribute must not be specified on the first field", attrOutOverlay.Name)
   235  			}
   236  			if hasOutOverlay || attrs[attrOutOverlay] > 1 {
   237  				comp.error(f.Pos, "multiple %v attributes", attrOutOverlay.Name)
   238  			}
   239  			hasOutOverlay = true
   240  		}
   241  		if hasDirections && hasOutOverlay {
   242  			comp.error(f.Pos, "mix of direction and %v attributes is not supported", attrOutOverlay.Name)
   243  		}
   244  	}
   245  }
   246  
   247  func (comp *compiler) checkFieldGroup(fields []*ast.Field, what, ctx string) {
   248  	existing := make(map[string]bool)
   249  	for _, f := range fields {
   250  		fn := f.Name.Name
   251  		if fn == prog.ParentRef || fn == prog.SyscallRef {
   252  			comp.error(f.Pos, "reserved %v name %v in %v", what, fn, ctx)
   253  		}
   254  		if existing[fn] {
   255  			comp.error(f.Pos, "duplicate %v %v in %v", what, fn, ctx)
   256  		}
   257  		existing[fn] = true
   258  	}
   259  }
   260  
   261  const argBase = "BASE"
   262  
   263  func (comp *compiler) checkTypedefs() {
   264  	for _, decl := range comp.desc.Nodes {
   265  		switch n := decl.(type) {
   266  		case *ast.TypeDef:
   267  			if len(n.Args) == 0 {
   268  				// Non-template types are fully typed, so we check them ahead of time.
   269  				err0 := comp.errors
   270  				comp.checkType(checkCtx{}, n.Type, checkIsTypedef)
   271  				if err0 != comp.errors {
   272  					// To not produce confusing errors on broken type usage.
   273  					delete(comp.typedefs, n.Name.Name)
   274  				}
   275  			} else {
   276  				// For templates we only do basic checks of arguments.
   277  				names := make(map[string]bool)
   278  				for i, arg := range n.Args {
   279  					if arg.Name == argBase && i != len(n.Args)-1 {
   280  						comp.error(arg.Pos, "type argument BASE must be the last argument")
   281  					}
   282  					if names[arg.Name] {
   283  						comp.error(arg.Pos, "duplicate type argument %v", arg.Name)
   284  					}
   285  					names[arg.Name] = true
   286  					for _, c := range arg.Name {
   287  						if c >= 'A' && c <= 'Z' ||
   288  							c >= '0' && c <= '9' ||
   289  							c == '_' {
   290  							continue
   291  						}
   292  						comp.error(arg.Pos, "type argument %v must be ALL_CAPS",
   293  							arg.Name)
   294  						break
   295  					}
   296  				}
   297  			}
   298  		}
   299  	}
   300  }
   301  
   302  func (comp *compiler) checkTypes() {
   303  	for _, decl := range comp.desc.Nodes {
   304  		switch n := decl.(type) {
   305  		case *ast.Resource:
   306  			comp.checkType(checkCtx{}, n.Base, checkIsResourceBase)
   307  		case *ast.Struct:
   308  			comp.checkStruct(checkCtx{}, n)
   309  		case *ast.Call:
   310  			comp.checkCall(n)
   311  		}
   312  	}
   313  }
   314  
   315  func (comp *compiler) checkTypeValues() {
   316  	for _, decl := range comp.desc.Nodes {
   317  		switch n := decl.(type) {
   318  		case *ast.Call, *ast.Struct, *ast.Resource, *ast.TypeDef:
   319  			comp.foreachType(decl, func(t *ast.Type, desc *typeDesc,
   320  				args []*ast.Type, base prog.IntTypeCommon) {
   321  				if desc.CheckConsts != nil {
   322  					desc.CheckConsts(comp, t, args, base)
   323  				}
   324  				for i, arg := range args {
   325  					if check := desc.Args[i].Type.CheckConsts; check != nil {
   326  						check(comp, arg)
   327  					}
   328  				}
   329  			})
   330  		case *ast.IntFlags:
   331  			allEqual := len(n.Values) >= 2
   332  			for _, val := range n.Values {
   333  				if val.Value != n.Values[0].Value {
   334  					allEqual = false
   335  				}
   336  			}
   337  			if allEqual {
   338  				comp.error(n.Pos, "all %v values are equal %v", n.Name.Name, n.Values[0].Value)
   339  			}
   340  		}
   341  	}
   342  }
   343  
   344  func (comp *compiler) checkAttributeValues() {
   345  	for _, decl := range comp.desc.Nodes {
   346  		switch n := decl.(type) {
   347  		case *ast.Struct:
   348  			for _, attr := range n.Attrs {
   349  				desc := structOrUnionAttrs(n)[attr.Ident]
   350  				if desc.CheckConsts != nil {
   351  					desc.CheckConsts(comp, n, attr)
   352  				}
   353  			}
   354  			// Check each field's attributes.
   355  			st := decl.(*ast.Struct)
   356  			hasOutOverlay := false
   357  			for _, f := range st.Fields {
   358  				isOut := hasOutOverlay
   359  				for _, attr := range f.Attrs {
   360  					switch attr.Ident {
   361  					case attrOutOverlay.Name:
   362  						hasOutOverlay = true
   363  						fallthrough
   364  					case attrOut.Name, attrInOut.Name:
   365  						isOut = true
   366  					}
   367  				}
   368  				if isOut && comp.getTypeDesc(f.Type).CantBeOut {
   369  					comp.error(f.Pos, "%v type must not be used as output", f.Type.Ident)
   370  				}
   371  			}
   372  		case *ast.Call:
   373  			attrNames := make(map[string]bool)
   374  			descAttrs := comp.parseIntAttrs(callAttrs, n, n.Attrs)
   375  			for desc := range descAttrs {
   376  				attrNames[prog.CppName(desc.Name)] = true
   377  			}
   378  
   379  			checked := make(map[string]bool)
   380  			for _, a := range n.Args {
   381  				comp.checkRequiredCallAttrs(n, attrNames, a.Type, checked)
   382  			}
   383  		}
   384  	}
   385  }
   386  
   387  func (comp *compiler) checkRequiredCallAttrs(call *ast.Call, callAttrNames map[string]bool,
   388  	t *ast.Type, checked map[string]bool) {
   389  	desc := comp.getTypeDesc(t)
   390  	for attr := range desc.RequiresCallAttrs {
   391  		if !callAttrNames[attr] {
   392  			comp.error(call.Pos, "call %v refers to type %v and so must be marked %s", call.Name.Name, t.Ident, attr)
   393  		}
   394  	}
   395  
   396  	switch desc {
   397  	case typeStruct:
   398  		s := comp.structs[t.Ident]
   399  		// Prune recursion, can happen even on correct tree via opt pointers.
   400  		if checked[s.Name.Name] {
   401  			return
   402  		}
   403  		checked[s.Name.Name] = true
   404  		fields := s.Fields
   405  		for _, fld := range fields {
   406  			comp.checkRequiredCallAttrs(call, callAttrNames, fld.Type, checked)
   407  		}
   408  	case typeArray:
   409  		typ := t.Args[0]
   410  		comp.checkRequiredCallAttrs(call, callAttrNames, typ, checked)
   411  	case typePtr:
   412  		typ := t.Args[1]
   413  		comp.checkRequiredCallAttrs(call, callAttrNames, typ, checked)
   414  	}
   415  }
   416  
   417  func (comp *compiler) checkFieldPaths() {
   418  	warned := make(map[string]bool)
   419  	for _, decl := range comp.desc.Nodes {
   420  		switch n := decl.(type) {
   421  		case *ast.Call:
   422  			for _, arg := range n.Args {
   423  				checked := make(map[string]bool)
   424  
   425  				parents := []parentDesc{{fields: n.Args, call: n.Name.Name}}
   426  				comp.checkFieldPathsRec(arg.Type, arg.Type, parents, checked, warned, true)
   427  			}
   428  		}
   429  	}
   430  }
   431  
   432  type parentDesc struct {
   433  	call   string
   434  	name   string
   435  	fields []*ast.Field
   436  }
   437  
   438  func (pd *parentDesc) String() string {
   439  	if pd.call != "" {
   440  		return fmt.Sprintf("<%s>", pd.call)
   441  	}
   442  	return pd.name
   443  }
   444  
   445  // templateBase return the part before '[' for full template names.
   446  func templateBase(name string) string {
   447  	if pos := strings.IndexByte(name, '['); pos != -1 {
   448  		return name[:pos]
   449  	}
   450  	return name
   451  }
   452  
   453  func parentTargetName(s *ast.Struct) string {
   454  	// For template parents name is "struct_name[ARG1, ARG2]", strip the part after '['.
   455  	return templateBase(s.Name.Name)
   456  }
   457  
   458  func (comp *compiler) checkFieldPathsRec(t0, t *ast.Type, parents []parentDesc,
   459  	checked, warned map[string]bool, isArg bool) {
   460  	desc := comp.getTypeDesc(t)
   461  	if desc == typeStruct {
   462  		s := comp.structs[t.Ident]
   463  		// Prune recursion, can happen even on correct tree via opt pointers.
   464  		// There may be several paths to the same type, let's at least look
   465  		// at the nearest parent.
   466  		checkName := s.Name.Name
   467  		if len(parents) > 1 {
   468  			checkName = parents[len(parents)-2].name + " " + checkName
   469  		}
   470  		if checked[checkName] {
   471  			return
   472  		}
   473  		checked[checkName] = true
   474  		fields := s.Fields
   475  		if s.IsUnion {
   476  			fields = nil
   477  		}
   478  		parentName := parentTargetName(s)
   479  		parents = append([]parentDesc{}, parents...)
   480  		parents = append(parents, parentDesc{name: parentName, fields: fields})
   481  		for _, fld := range s.Fields {
   482  			comp.checkFieldPathsRec(fld.Type, fld.Type, parents, checked, warned, false)
   483  			for _, attr := range fld.Attrs {
   484  				attrDesc := structFieldAttrs[attr.Ident]
   485  				if attrDesc == nil || attrDesc.Type != exprAttr {
   486  					continue
   487  				}
   488  				if attrDesc == attrIf {
   489  					comp.checkExprFieldType(fld.Type)
   490  				}
   491  				ast.Recursive(func(n ast.Node) bool {
   492  					exprType, ok := n.(*ast.Type)
   493  					if !ok || exprType.Ident != valueIdent {
   494  						return true
   495  					}
   496  					comp.validateFieldPath(exprType.Args[0], t0, exprType, parents, warned)
   497  					return false
   498  				})(attr.Args[0])
   499  			}
   500  		}
   501  		return
   502  	}
   503  	_, args, _ := comp.getArgsBase(t, isArg)
   504  	for i, arg := range args {
   505  		argDesc := desc.Args[i]
   506  		switch argDesc.Type {
   507  		case typeArgLenTarget:
   508  			comp.validateFieldPath(arg, t0, t, parents, warned)
   509  		case typeArgType:
   510  			comp.checkFieldPathsRec(t0, arg, parents, checked, warned, argDesc.IsArg)
   511  		}
   512  	}
   513  }
   514  
   515  func (comp *compiler) validateFieldPath(arg, fieldType, t *ast.Type, parents []parentDesc,
   516  	warned map[string]bool) {
   517  	targets := append([]*ast.Type{arg}, arg.Colon...)
   518  	const maxParents = 2
   519  	for i, target := range targets {
   520  		if target.Ident == prog.ParentRef &&
   521  			(i >= maxParents || targets[0].Ident != prog.ParentRef) {
   522  			// It's not a fundamental limitation, but it helps prune recursion in checkLenType().
   523  			// If we need more, we need to adjust the key of the "checked" map.
   524  			if !warned[parents[len(parents)-1].name] {
   525  				comp.error(target.Pos, "%v may only stay at the beginning (max %d times)",
   526  					prog.ParentRef, maxParents)
   527  			}
   528  			warned[parents[len(parents)-1].name] = true
   529  			return
   530  		}
   531  		if target.Ident == prog.SyscallRef {
   532  			if i != 0 {
   533  				comp.error(target.Pos, "syscall can't be in the middle of path expressions")
   534  				return
   535  			}
   536  			if len(targets) == 1 {
   537  				comp.error(targets[0].Pos, "no argument name after syscall reference")
   538  				return
   539  			}
   540  		}
   541  	}
   542  	// Drop parents from the prefix (it will simplify further code).
   543  	droppedParents := 0
   544  	for len(targets) > 0 && targets[0].Ident == prog.ParentRef {
   545  		target := targets[0]
   546  		if parents[len(parents)-1].call != "" {
   547  			comp.error(target.Pos, "%v reached the call (%v)",
   548  				prog.ParentRef, parents[0].call)
   549  			return
   550  		}
   551  		droppedParents++
   552  		targets = targets[1:]
   553  		// Ignore the first "parent" item.
   554  		if droppedParents > 1 {
   555  			if len(parents) < 2 {
   556  				comp.error(target.Pos, "too many %v elements", prog.ParentRef)
   557  				return
   558  			}
   559  			parents = parents[:len(parents)-1]
   560  		}
   561  	}
   562  	comp.validateFieldPathRec(fieldType, t, targets, parents, warned)
   563  }
   564  
   565  func (comp *compiler) validateFieldPathRec(t0, t *ast.Type, targets []*ast.Type,
   566  	parents []parentDesc, warned map[string]bool) {
   567  	if len(targets) == 0 {
   568  		if t.Ident == "offsetof" {
   569  			comp.error(t.Pos, "%v must refer to fields", t.Ident)
   570  			return
   571  		}
   572  		return
   573  	}
   574  	isValuePath := t.Ident == valueIdent
   575  	target := targets[0]
   576  	targets = targets[1:]
   577  	fields := parents[len(parents)-1].fields
   578  	for _, fld := range fields {
   579  		if target.Ident != fld.Name.Name {
   580  			continue
   581  		}
   582  		if fld.Type == t0 {
   583  			comp.error(target.Pos, "%v target %v refers to itself", t.Ident, target.Ident)
   584  			return
   585  		}
   586  		if !comp.checkPathField(target, t, fld) {
   587  			return
   588  		}
   589  		if len(targets) == 0 {
   590  			if t.Ident == "len" {
   591  				typ, desc := comp.derefPointers(fld.Type)
   592  				if desc == typeArray && comp.isVarlen(typ.Args[0]) {
   593  					// We can reach the same struct multiple times starting from different
   594  					// syscall arguments. Warn only once.
   595  					if !warned[parents[len(parents)-1].name] {
   596  						warned[parents[len(parents)-1].name] = true
   597  						comp.warning(target.Pos, "len target %v refer to an array with"+
   598  							" variable-size elements (do you mean bytesize?)",
   599  							target.Ident)
   600  					}
   601  				}
   602  			}
   603  			if isValuePath {
   604  				comp.checkExprLastField(target, fld)
   605  			}
   606  			return
   607  		}
   608  		typ, desc := comp.derefPointers(fld.Type)
   609  		if desc != typeStruct {
   610  			comp.error(target.Pos, "%v path %v does not refer to a struct", t.Ident, target.Ident)
   611  			return
   612  		}
   613  		s := comp.structs[typ.Ident]
   614  		if s.IsUnion {
   615  			comp.error(target.Pos, "%v path %v does not refer to a struct", t.Ident, target.Ident)
   616  			return
   617  		}
   618  		parents = append(parents, parentDesc{name: parentTargetName(s), fields: s.Fields})
   619  		comp.validateFieldPathRec(t0, t, targets, parents, warned)
   620  		return
   621  	}
   622  	for pi := len(parents) - 1; pi >= 0; pi-- {
   623  		parent := parents[pi]
   624  		if parent.name != "" && parent.name == target.Ident ||
   625  			parent.name == "" && target.Ident == prog.SyscallRef {
   626  			parents1 := make([]parentDesc, pi+1)
   627  			copy(parents1, parents[:pi+1])
   628  			comp.validateFieldPathRec(t0, t, targets, parents1, warned)
   629  			return
   630  		}
   631  	}
   632  	warnKey := parents[len(parents)-1].name + " " + target.Pos.String()
   633  	if !warned[warnKey] {
   634  		comp.error(target.Pos, "%v target %v does not exist in %s",
   635  			t.Ident, target.Ident, parents[len(parents)-1].String())
   636  	}
   637  	warned[warnKey] = true
   638  }
   639  
   640  func (comp *compiler) checkPathField(target, t *ast.Type, field *ast.Field) bool {
   641  	for _, attr := range field.Attrs {
   642  		desc := structFieldAttrs[attr.Ident]
   643  		if desc == attrIf {
   644  			comp.error(target.Pos, "%s has conditions, so %s path cannot reference it",
   645  				field.Name.Name, t.Ident)
   646  			return false
   647  		}
   648  	}
   649  
   650  	return true
   651  }
   652  
   653  func (comp *compiler) checkExprLastField(target *ast.Type, field *ast.Field) {
   654  	_, desc := comp.derefPointers(field.Type)
   655  	if desc != typeInt && desc != typeFlags && desc != typeConst {
   656  		comp.error(target.Pos, "%v does not refer to a constant, an integer, or a flag", field.Name.Name)
   657  	}
   658  }
   659  
   660  func (comp *compiler) checkExprFieldType(t *ast.Type) {
   661  	desc := comp.getTypeDesc(t)
   662  	if desc == typeInt && len(t.Colon) != 0 {
   663  		comp.error(t.Pos, "bitfields may not have conditions")
   664  	}
   665  }
   666  
   667  func CollectUnused(desc *ast.Description, target *targets.Target, eh ast.ErrorHandler) ([]ast.Node, error) {
   668  	comp := createCompiler(desc, target, eh)
   669  	comp.typecheck()
   670  	if comp.errors > 0 {
   671  		return nil, errors.New("typecheck failed")
   672  	}
   673  
   674  	nodes := comp.collectUnused()
   675  	if comp.errors > 0 {
   676  		return nil, errors.New("collectUnused failed")
   677  	}
   678  	return nodes, nil
   679  }
   680  
   681  // CollectUnusedConsts returns unused defines/includes. This is used only for auto-generated descriptions.
   682  func CollectUnusedConsts(desc *ast.Description, target *targets.Target, includeUse map[string]string,
   683  	eh ast.ErrorHandler) ([]ast.Node, error) {
   684  	comp := createCompiler(desc, target, eh)
   685  	comp.typecheck()
   686  	if comp.errors > 0 {
   687  		return nil, errors.New("typecheck failed")
   688  	}
   689  
   690  	var unused []ast.Node
   691  	for file, info := range comp.extractConsts() {
   692  		if !comp.fileMeta(ast.Pos{File: file}).Automatic {
   693  			continue
   694  		}
   695  		usedDefines := make(map[string]bool)
   696  		usedIncludes := make(map[string]bool)
   697  		for _, c := range info.Consts {
   698  			if c.Used {
   699  				usedDefines[c.Name] = true
   700  				usedIncludes[includeUse[c.Name]] = true
   701  			}
   702  		}
   703  		for _, decl := range comp.desc.Nodes {
   704  			switch n := decl.(type) {
   705  			case *ast.Define:
   706  				if n.Pos.File == file && !usedDefines[n.Name.Name] {
   707  					unused = append(unused, n)
   708  				}
   709  			case *ast.Include:
   710  				if n.Pos.File == file && !usedIncludes[n.File.Value] {
   711  					unused = append(unused, n)
   712  				}
   713  			}
   714  		}
   715  	}
   716  	return unused, nil
   717  }
   718  
   719  func (comp *compiler) collectUnused() []ast.Node {
   720  	var unused []ast.Node
   721  
   722  	comp.used, _, _ = comp.collectUsed(false)
   723  	structs, flags, strflags := comp.collectUsed(true)
   724  
   725  	note := func(n ast.Node) {
   726  		if pos, _, _ := n.Info(); pos.Builtin() {
   727  			return
   728  		}
   729  		unused = append(unused, n)
   730  	}
   731  
   732  	for name, n := range comp.intFlags {
   733  		if !flags[name] {
   734  			note(n)
   735  		}
   736  	}
   737  	for name, n := range comp.strFlags {
   738  		if !strflags[name] {
   739  			note(n)
   740  		}
   741  	}
   742  	for name, n := range comp.resources {
   743  		if !structs[name] {
   744  			note(n)
   745  		}
   746  	}
   747  	for name, n := range comp.structs {
   748  		if !structs[name] {
   749  			note(n)
   750  		}
   751  	}
   752  	for name, n := range comp.typedefs {
   753  		if !comp.usedTypedefs[name] {
   754  			note(n)
   755  		}
   756  	}
   757  
   758  	return unused
   759  }
   760  
   761  func (comp *compiler) collectUsed(all bool) (structs, flags, strflags map[string]bool) {
   762  	structs = make(map[string]bool)
   763  	flags = make(map[string]bool)
   764  	strflags = make(map[string]bool)
   765  	for _, decl := range comp.desc.Nodes {
   766  		switch n := decl.(type) {
   767  		case *ast.Call:
   768  			if !all && n.NR == ^uint64(0) {
   769  				break
   770  			}
   771  			for _, arg := range n.Args {
   772  				comp.collectUsedType(structs, flags, strflags, arg.Type, true)
   773  			}
   774  			if n.Ret != nil {
   775  				comp.collectUsedType(structs, flags, strflags, n.Ret, true)
   776  			}
   777  		}
   778  	}
   779  	return
   780  }
   781  
   782  func (comp *compiler) collectUsedType(structs, flags, strflags map[string]bool, t *ast.Type, isArg bool) {
   783  	desc := comp.getTypeDesc(t)
   784  	if desc == typeResource {
   785  		r := comp.resources[t.Ident]
   786  		for r != nil && !structs[r.Name.Name] {
   787  			structs[r.Name.Name] = true
   788  			r = comp.resources[r.Base.Ident]
   789  		}
   790  		return
   791  	}
   792  	if desc == typeStruct {
   793  		if structs[t.Ident] {
   794  			return
   795  		}
   796  		structs[t.Ident] = true
   797  		s := comp.structs[t.Ident]
   798  		for _, fld := range s.Fields {
   799  			comp.collectUsedType(structs, flags, strflags, fld.Type, false)
   800  		}
   801  		return
   802  	}
   803  	if desc == typeFlags ||
   804  		(desc == typeInt && len(t.Args) > 0 && t.Args[0].Ident != "") {
   805  		flags[t.Args[0].Ident] = true
   806  		return
   807  	}
   808  	if desc == typeString {
   809  		if len(t.Args) != 0 && t.Args[0].Ident != "" {
   810  			strflags[t.Args[0].Ident] = true
   811  		}
   812  		return
   813  	}
   814  	_, args, _ := comp.getArgsBase(t, isArg)
   815  	for i, arg := range args {
   816  		if desc.Args[i].Type == typeArgType {
   817  			comp.collectUsedType(structs, flags, strflags, arg, desc.Args[i].IsArg)
   818  		}
   819  	}
   820  }
   821  
   822  func (comp *compiler) checkUnused() {
   823  	for _, n := range comp.collectUnused() {
   824  		pos, typ, name := n.Info()
   825  		comp.error(pos, "unused %v %v", typ, name)
   826  	}
   827  }
   828  
   829  func (comp *compiler) checkConstsFlags(consts map[string]uint64) {
   830  	for name := range consts {
   831  		if flags, isFlag := comp.intFlags[name]; isFlag {
   832  			pos, _, _ := flags.Info()
   833  			comp.error(pos, "const %v is already a flag", name)
   834  		}
   835  	}
   836  }
   837  
   838  type structDir struct {
   839  	Struct string
   840  	Dir    prog.Dir
   841  }
   842  
   843  func (comp *compiler) checkConstructors() {
   844  	ctors := make(map[string]bool)  // resources for which we have ctors
   845  	inputs := make(map[string]bool) // resources which are used as inputs
   846  	checked := make(map[structDir]bool)
   847  	for _, decl := range comp.desc.Nodes {
   848  		switch n := decl.(type) {
   849  		case *ast.Call:
   850  			for _, arg := range n.Args {
   851  				comp.checkTypeCtors(arg.Type, prog.DirIn, true, true, ctors, inputs, checked, nil)
   852  			}
   853  			if n.Ret != nil {
   854  				comp.checkTypeCtors(n.Ret, prog.DirOut, true, true, ctors, inputs, checked, nil)
   855  			}
   856  		}
   857  	}
   858  	for _, decl := range comp.desc.Nodes {
   859  		switch n := decl.(type) {
   860  		case *ast.Resource:
   861  			name := n.Name.Name
   862  			if !comp.used[name] {
   863  				continue
   864  			}
   865  			if !ctors[name] {
   866  				comp.error(n.Pos, "resource %v can't be created"+
   867  					" (never mentioned as a syscall return value or output argument/field)", name)
   868  			}
   869  			if !inputs[name] {
   870  				comp.error(n.Pos, "resource %v is never used as an input"+
   871  					" (such resources are not useful)", name)
   872  			}
   873  		}
   874  	}
   875  }
   876  
   877  // nolint:revive
   878  func (comp *compiler) checkTypeCtors(t *ast.Type, dir prog.Dir, isArg, canCreate bool,
   879  	ctors, inputs map[string]bool, checked map[structDir]bool, neverOutAt *ast.Pos) {
   880  	desc, args, base := comp.getArgsBase(t, isArg)
   881  	if base.IsOptional {
   882  		canCreate = false
   883  	}
   884  	if desc.CantHaveOut {
   885  		neverOutAt = &t.Pos
   886  	}
   887  	if desc == typeResource {
   888  		// TODO(dvyukov): consider changing this to "dir == prog.DirOut".
   889  		// We have few questionable cases where resources can be created
   890  		// only by inout struct fields. These structs should be split
   891  		// into two different structs: one is in and second is out.
   892  		// But that will require attaching dir to individual fields.
   893  		if dir != prog.DirIn && neverOutAt != nil {
   894  			comp.error(*neverOutAt, "resource %s cannot be created in fmt", t.Ident)
   895  		}
   896  		if canCreate && dir != prog.DirIn {
   897  			r := comp.resources[t.Ident]
   898  			for r != nil && !ctors[r.Name.Name] {
   899  				ctors[r.Name.Name] = true
   900  				r = comp.resources[r.Base.Ident]
   901  			}
   902  		}
   903  		if dir != prog.DirOut {
   904  			r := comp.resources[t.Ident]
   905  			for r != nil && !inputs[r.Name.Name] {
   906  				inputs[r.Name.Name] = true
   907  				r = comp.resources[r.Base.Ident]
   908  			}
   909  		}
   910  		return
   911  	}
   912  	if desc == typeStruct {
   913  		s := comp.structs[t.Ident]
   914  		if s.IsUnion {
   915  			canCreate = false
   916  		}
   917  		name := s.Name.Name
   918  		key := structDir{name, dir}
   919  		if checked[key] {
   920  			return
   921  		}
   922  		checked[key] = true
   923  		for _, fld := range s.Fields {
   924  			fldDir, fldHasDir := comp.genFieldDir(comp.parseIntAttrs(structFieldAttrs, fld, fld.Attrs))
   925  			if !fldHasDir {
   926  				fldDir = dir
   927  			}
   928  			comp.checkTypeCtors(fld.Type, fldDir, false, canCreate, ctors, inputs, checked, neverOutAt)
   929  		}
   930  		return
   931  	}
   932  	if desc == typePtr {
   933  		dir = genDir(t.Args[0])
   934  	}
   935  	for i, arg := range args {
   936  		if desc.Args[i].Type == typeArgType {
   937  			comp.checkTypeCtors(arg, dir, desc.Args[i].IsArg, canCreate, ctors, inputs, checked, neverOutAt)
   938  		}
   939  	}
   940  }
   941  
   942  func (comp *compiler) checkRecursion() {
   943  	checked := make(map[string]bool)
   944  	for _, decl := range comp.desc.Nodes {
   945  		switch n := decl.(type) {
   946  		case *ast.Resource:
   947  			comp.checkResourceRecursion(n)
   948  		case *ast.Struct:
   949  			var path []pathElem
   950  			comp.checkStructRecursion(checked, n, path)
   951  		}
   952  	}
   953  }
   954  
   955  func (comp *compiler) checkResourceRecursion(n *ast.Resource) {
   956  	var seen []string
   957  	for n != nil {
   958  		if arrayContains(seen, n.Name.Name) {
   959  			chain := ""
   960  			for _, r := range seen {
   961  				chain += r + "->"
   962  			}
   963  			chain += n.Name.Name
   964  			comp.error(n.Pos, "recursive resource %v", chain)
   965  			return
   966  		}
   967  		seen = append(seen, n.Name.Name)
   968  		n = comp.resources[n.Base.Ident]
   969  	}
   970  }
   971  
   972  type pathElem struct {
   973  	Pos    ast.Pos
   974  	Struct string
   975  	Field  string
   976  }
   977  
   978  func (comp *compiler) checkStructRecursion(checked map[string]bool, n *ast.Struct, path []pathElem) {
   979  	name := n.Name.Name
   980  	if checked[name] {
   981  		return
   982  	}
   983  	for i, elem := range path {
   984  		if elem.Struct != name {
   985  			continue
   986  		}
   987  		path = path[i:]
   988  		str := ""
   989  		for _, elem := range path {
   990  			str += fmt.Sprintf("%v.%v -> ", elem.Struct, elem.Field)
   991  		}
   992  		str += name
   993  		comp.error(path[0].Pos, "recursive declaration: %v (mark some pointers as opt, or use variable-length arrays)", str)
   994  		checked[name] = true
   995  		return
   996  	}
   997  	for _, f := range n.Fields {
   998  		path = append(path, pathElem{
   999  			Pos:    f.Pos,
  1000  			Struct: name,
  1001  			Field:  f.Name.Name,
  1002  		})
  1003  		comp.recurseField(checked, f.Type, path, false)
  1004  		path = path[:len(path)-1]
  1005  	}
  1006  	checked[name] = true
  1007  }
  1008  
  1009  func (comp *compiler) recurseField(checked map[string]bool, t *ast.Type, path []pathElem, isArg bool) {
  1010  	desc := comp.getTypeDesc(t)
  1011  	if desc == typeStruct {
  1012  		comp.checkStructRecursion(checked, comp.structs[t.Ident], path)
  1013  		return
  1014  	}
  1015  	_, args, base := comp.getArgsBase(t, isArg)
  1016  	if desc == typePtr && base.IsOptional {
  1017  		return // optional pointers prune recursion
  1018  	}
  1019  	if desc == typeArray && len(args) == 1 {
  1020  		return // variable-length arrays prune recursion
  1021  	}
  1022  	for i, arg := range args {
  1023  		if desc.Args[i].Type == typeArgType {
  1024  			isArg := false
  1025  			if t.Ident == "fmt" {
  1026  				isArg = true
  1027  			}
  1028  			comp.recurseField(checked, arg, path, isArg)
  1029  		}
  1030  	}
  1031  }
  1032  
  1033  func (comp *compiler) checkStruct(ctx checkCtx, n *ast.Struct) {
  1034  	var flags checkFlags
  1035  	if !n.IsUnion {
  1036  		flags |= checkIsStruct
  1037  	}
  1038  	for _, f := range n.Fields {
  1039  		comp.checkType(ctx, f.Type, flags)
  1040  	}
  1041  	comp.parseAttrs(structOrUnionAttrs(n), n, n.Attrs)
  1042  }
  1043  
  1044  func (comp *compiler) checkCall(n *ast.Call) {
  1045  	for _, a := range n.Args {
  1046  		comp.checkType(checkCtx{}, a.Type, checkIsArg)
  1047  	}
  1048  	if n.Ret != nil {
  1049  		comp.checkType(checkCtx{}, n.Ret, checkIsArg|checkIsRet)
  1050  	}
  1051  	comp.parseAttrs(callAttrs, n, n.Attrs)
  1052  }
  1053  
  1054  type checkFlags int
  1055  
  1056  const (
  1057  	checkIsArg          checkFlags = 1 << iota // immediate syscall arg type
  1058  	checkIsRet                                 // immediate syscall ret type
  1059  	checkIsStruct                              // immediate struct field type
  1060  	checkIsResourceBase                        // immediate resource base type
  1061  	checkIsTypedef                             // immediate type alias/template type
  1062  )
  1063  
  1064  type checkCtx struct {
  1065  	instantiationStack []string
  1066  }
  1067  
  1068  func (comp *compiler) checkType(ctx checkCtx, t *ast.Type, flags checkFlags) {
  1069  	comp.checkTypeImpl(ctx, t, comp.getTypeDesc(t), flags)
  1070  }
  1071  
  1072  func (comp *compiler) checkTypeImpl(ctx checkCtx, t *ast.Type, desc *typeDesc, flags checkFlags) {
  1073  	if unexpected, _, ok := checkTypeKind(t, kindIdent); !ok {
  1074  		comp.error(t.Pos, "unexpected %v, expect type", unexpected)
  1075  		return
  1076  	}
  1077  	if desc == nil {
  1078  		comp.error(t.Pos, "unknown type %v", t.Ident)
  1079  		return
  1080  	}
  1081  	if desc == typeTypedef {
  1082  		err0 := comp.errors
  1083  		// Replace t with type alias/template target type inplace,
  1084  		// and check the replaced type recursively.
  1085  		comp.replaceTypedef(&ctx, t, flags)
  1086  		if err0 == comp.errors {
  1087  			comp.checkType(ctx, t, flags)
  1088  		}
  1089  		return
  1090  	}
  1091  	err0 := comp.errors
  1092  	comp.checkTypeBasic(t, desc, flags)
  1093  	if err0 != comp.errors {
  1094  		return
  1095  	}
  1096  	args := comp.checkTypeArgs(t, desc, flags)
  1097  	if err0 != comp.errors {
  1098  		return
  1099  	}
  1100  	for i, arg := range args {
  1101  		if desc.Args[i].Type == typeArgType {
  1102  			var innerFlags checkFlags
  1103  			if desc.Args[i].IsArg {
  1104  				innerFlags |= checkIsArg
  1105  			}
  1106  			comp.checkType(ctx, arg, innerFlags)
  1107  		} else {
  1108  			comp.checkTypeArg(t, arg, desc.Args[i])
  1109  		}
  1110  	}
  1111  	if err0 != comp.errors {
  1112  		return
  1113  	}
  1114  	if desc.Check != nil {
  1115  		_, args, base := comp.getArgsBase(t, flags&checkIsArg != 0)
  1116  		desc.Check(comp, t, args, base)
  1117  	}
  1118  }
  1119  
  1120  func (comp *compiler) checkTypeBasic(t *ast.Type, desc *typeDesc, flags checkFlags) {
  1121  	for i, col := range t.Colon {
  1122  		if i >= desc.MaxColon {
  1123  			comp.error(col.Pos, "unexpected ':'")
  1124  			return
  1125  		}
  1126  		if flags&checkIsStruct == 0 {
  1127  			comp.error(col.Pos, "unexpected ':', only struct fields can be bitfields")
  1128  			return
  1129  		}
  1130  	}
  1131  	if flags&checkIsTypedef != 0 && !desc.CanBeTypedef {
  1132  		comp.error(t.Pos, "%v can't be type alias target", t.Ident)
  1133  		return
  1134  	}
  1135  	if flags&checkIsResourceBase != 0 &&
  1136  		(desc.CanBeResourceBase == nil || !desc.CanBeResourceBase(comp, t)) {
  1137  		comp.error(t.Pos, "%v can't be resource base (int types can)", t.Ident)
  1138  		return
  1139  	}
  1140  	canBeArg, canBeRet := false, false
  1141  	if desc.CanBeArgRet != nil {
  1142  		canBeArg, canBeRet = desc.CanBeArgRet(comp, t)
  1143  	}
  1144  	if flags&checkIsRet != 0 && !canBeRet {
  1145  		comp.error(t.Pos, "%v can't be syscall return", t.Ident)
  1146  		return
  1147  	}
  1148  	if flags&checkIsArg != 0 && !canBeArg {
  1149  		comp.error(t.Pos, "%v can't be syscall argument", t.Ident)
  1150  		return
  1151  	}
  1152  }
  1153  
  1154  func (comp *compiler) checkTypeArgs(t *ast.Type, desc *typeDesc, flags checkFlags) []*ast.Type {
  1155  	args, opt := removeOpt(t)
  1156  	if opt != nil {
  1157  		if len(opt.Args) != 0 {
  1158  			comp.error(opt.Pos, "opt can't have arguments")
  1159  		}
  1160  		if flags&checkIsResourceBase != 0 || desc.CantBeOpt {
  1161  			what := "resource base"
  1162  			if desc.CantBeOpt {
  1163  				what = t.Ident
  1164  			}
  1165  			comp.error(opt.Pos, "%v can't be marked as opt", what)
  1166  			return nil
  1167  		}
  1168  	}
  1169  	addArgs := 0
  1170  	needBase := flags&checkIsArg == 0 && desc.NeedBase
  1171  	if needBase {
  1172  		addArgs++ // last arg must be base type, e.g. const[0, int32]
  1173  	}
  1174  	if len(args) > len(desc.Args)+addArgs || len(args) < len(desc.Args)-desc.OptArgs+addArgs {
  1175  		comp.error(t.Pos, "wrong number of arguments for type %v, expect %v",
  1176  			t.Ident, expectedTypeArgs(desc, needBase))
  1177  		return nil
  1178  	}
  1179  	if needBase {
  1180  		base := args[len(args)-1]
  1181  		args = args[:len(args)-1]
  1182  		comp.checkTypeArg(t, base, typeArgBase)
  1183  	}
  1184  	return args
  1185  }
  1186  
  1187  func (comp *compiler) replaceTypedef(ctx *checkCtx, t *ast.Type, flags checkFlags) {
  1188  	typedefName := t.Ident
  1189  	typedef := comp.typedefs[typedefName]
  1190  	fullTypeName := ast.SerializeNode(t)
  1191  	if comp.brokenTypedefs[fullTypeName] {
  1192  		// We've already produced some errors for this exact type instantiation.
  1193  		// Don't produce duplicates, also helps to prevent exponential
  1194  		// slowdown due to some cases of recursion. But increment the number
  1195  		// of errors so that callers can understand that we did not succeed.
  1196  		comp.errors++
  1197  		return
  1198  	}
  1199  	comp.usedTypedefs[typedefName] = true
  1200  	err0 := comp.errors
  1201  	defer func() {
  1202  		comp.brokenTypedefs[fullTypeName] = err0 != comp.errors
  1203  	}()
  1204  	if len(t.Colon) != 0 {
  1205  		comp.error(t.Pos, "type alias %v with ':'", t.Ident)
  1206  		return
  1207  	}
  1208  	// Handling optional BASE argument.
  1209  	if len(typedef.Args) > 0 && typedef.Args[len(typedef.Args)-1].Name == argBase {
  1210  		if flags&checkIsArg != 0 && len(t.Args) == len(typedef.Args)-1 {
  1211  			t.Args = append(t.Args, &ast.Type{
  1212  				Pos:   t.Pos,
  1213  				Ident: "intptr",
  1214  			})
  1215  		} else if len(t.Args) == len(typedef.Args) {
  1216  			comp.checkTypeArg(t, t.Args[len(t.Args)-1], typeArgBase)
  1217  		}
  1218  	}
  1219  	recursion := 0
  1220  	ctx.instantiationStack = append(ctx.instantiationStack, fullTypeName)
  1221  	for i, prev := range ctx.instantiationStack[:len(ctx.instantiationStack)-1] {
  1222  		if typedefName == templateBase(prev) {
  1223  			recursion++
  1224  			if recursion > 10 {
  1225  				comp.error(t.Pos, "type instantiation recursion: %v", strings.Join(ctx.instantiationStack, " -> "))
  1226  				return
  1227  			}
  1228  		}
  1229  		if prev != fullTypeName {
  1230  			continue
  1231  		}
  1232  		comp.error(t.Pos, "type instantiation loop: %v", strings.Join(ctx.instantiationStack[i:], " -> "))
  1233  		return
  1234  	}
  1235  	nargs := len(typedef.Args)
  1236  	args := t.Args
  1237  	if nargs != len(t.Args) {
  1238  		if nargs == 0 {
  1239  			comp.error(t.Pos, "type %v is not a template", typedefName)
  1240  		} else {
  1241  			if flags&checkIsArg != 0 && typedef.Args[len(typedef.Args)-1].Name == argBase {
  1242  				nargs--
  1243  			}
  1244  			comp.error(t.Pos, "template %v needs %v arguments instead of %v",
  1245  				typedefName, nargs, len(t.Args))
  1246  		}
  1247  		return
  1248  	}
  1249  	pos0 := t.Pos
  1250  	if typedef.Type != nil {
  1251  		*t = *typedef.Type.Clone().(*ast.Type)
  1252  		if !comp.instantiate(t, typedef.Args, args) {
  1253  			return
  1254  		}
  1255  	} else {
  1256  		inst := comp.structs[fullTypeName]
  1257  		if inst == nil {
  1258  			inst = typedef.Struct.Clone().(*ast.Struct)
  1259  			inst.Name.Name = fullTypeName
  1260  			if !comp.instantiate(inst, typedef.Args, args) {
  1261  				return
  1262  			}
  1263  			comp.checkStruct(*ctx, inst)
  1264  			if err0 != comp.errors {
  1265  				return
  1266  			}
  1267  			comp.desc.Nodes = append(comp.desc.Nodes, inst)
  1268  			comp.structs[fullTypeName] = inst
  1269  			comp.structFiles[inst] = make(map[string]ast.Pos)
  1270  		}
  1271  		comp.structFiles[inst][pos0.File] = pos0
  1272  		*t = ast.Type{
  1273  			Ident: fullTypeName,
  1274  		}
  1275  	}
  1276  	t.Pos = pos0
  1277  	comp.maybeRemoveBase(t, flags)
  1278  }
  1279  
  1280  func (comp *compiler) maybeRemoveBase(t *ast.Type, flags checkFlags) {
  1281  	// Remove base type if it's not needed in this context.
  1282  	// If desc is nil, will return an error later when we typecheck the result.
  1283  	desc := comp.getTypeDesc(t)
  1284  	if desc != nil && flags&checkIsArg != 0 && desc.NeedBase && len(t.Args) != 0 {
  1285  		baseTypePos := len(t.Args) - 1
  1286  		if t.Args[baseTypePos].Ident == "opt" && len(t.Args) >= 2 {
  1287  			baseTypePos--
  1288  		}
  1289  		copy(t.Args[baseTypePos:], t.Args[baseTypePos+1:])
  1290  		t.Args = t.Args[:len(t.Args)-1]
  1291  	}
  1292  }
  1293  
  1294  func (comp *compiler) instantiate(templ ast.Node, params []*ast.Ident, args []*ast.Type) bool {
  1295  	if len(params) == 0 {
  1296  		return true
  1297  	}
  1298  	argMap := make(map[string]*ast.Type)
  1299  	for i, param := range params {
  1300  		argMap[param.Name] = args[i]
  1301  	}
  1302  	argUsed := make(map[string]bool)
  1303  	err0 := comp.errors
  1304  	ast.PostRecursive(func(n ast.Node) {
  1305  		templArg, ok := n.(*ast.Type)
  1306  		if !ok {
  1307  			return
  1308  		}
  1309  		if concreteArg := argMap[templArg.Ident]; concreteArg != nil {
  1310  			argUsed[templArg.Ident] = true
  1311  			origArgs := templArg.Args
  1312  			if len(origArgs) != 0 && len(concreteArg.Args) != 0 {
  1313  				comp.error(templArg.Pos, "both template parameter %v and its usage"+
  1314  					" have sub-arguments", templArg.Ident)
  1315  				return
  1316  			}
  1317  			*templArg = *concreteArg.Clone().(*ast.Type)
  1318  			if len(origArgs) != 0 {
  1319  				templArg.Args = origArgs
  1320  			}
  1321  		}
  1322  		// TODO(dvyukov): somewhat hacky, but required for int8[0:CONST_ARG]
  1323  		// Need more checks here. E.g. that CONST_ARG does not have subargs.
  1324  		// And if CONST_ARG is a value, then use concreteArg.Value.
  1325  		// Also need to error if CONST_ARG is a string.
  1326  		if len(templArg.Colon) != 0 {
  1327  			col := templArg.Colon[0]
  1328  			if concreteArg := argMap[col.Ident]; concreteArg != nil {
  1329  				argUsed[col.Ident] = true
  1330  				col.Ident = concreteArg.Ident
  1331  				col.Pos = concreteArg.Pos
  1332  			}
  1333  		}
  1334  	})(templ)
  1335  	for _, param := range params {
  1336  		if !argUsed[param.Name] {
  1337  			comp.error(argMap[param.Name].Pos,
  1338  				"template argument %v is not used", param.Name)
  1339  		}
  1340  	}
  1341  	return err0 == comp.errors
  1342  }
  1343  
  1344  func (comp *compiler) checkTypeArg(t, arg *ast.Type, argDesc namedArg) {
  1345  	desc := argDesc.Type
  1346  	if len(desc.Names) != 0 {
  1347  		if unexpected, _, ok := checkTypeKind(arg, kindIdent); !ok {
  1348  			comp.error(arg.Pos, "unexpected %v for %v argument of %v type, expect %+v",
  1349  				unexpected, argDesc.Name, t.Ident, desc.Names)
  1350  			return
  1351  		}
  1352  		if !arrayContains(desc.Names, arg.Ident) {
  1353  			comp.error(arg.Pos, "unexpected value %v for %v argument of %v type, expect %+v",
  1354  				arg.Ident, argDesc.Name, t.Ident, desc.Names)
  1355  			return
  1356  		}
  1357  	} else {
  1358  		if unexpected, expect, ok := checkTypeKind(arg, desc.Kind); !ok {
  1359  			comp.error(arg.Pos, "unexpected %v for %v argument of %v type, expect %v",
  1360  				unexpected, argDesc.Name, t.Ident, expect)
  1361  			return
  1362  		}
  1363  	}
  1364  	for i, col := range arg.Colon {
  1365  		if i >= desc.MaxColon {
  1366  			comp.error(col.Pos, "unexpected ':'")
  1367  			return
  1368  		}
  1369  		// We only want to perform this check if kindIdent is the only kind of
  1370  		// this type. Otherwise, the token after the colon could legitimately
  1371  		// be an int for example.
  1372  		if desc.Kind == kindIdent {
  1373  			if unexpected, expect, ok := checkTypeKind(col, kindIdent); !ok {
  1374  				comp.error(arg.Pos, "unexpected %v after colon, expect %v", unexpected, expect)
  1375  				return
  1376  			}
  1377  		}
  1378  	}
  1379  	if len(arg.Args) > desc.MaxArgs {
  1380  		comp.error(arg.Pos, "%v argument has subargs", argDesc.Name)
  1381  		return
  1382  	}
  1383  	if desc.Check != nil {
  1384  		desc.Check(comp, arg)
  1385  	}
  1386  }
  1387  
  1388  func expectedTypeArgs(desc *typeDesc, needBase bool) string {
  1389  	expect := ""
  1390  	for i, arg := range desc.Args {
  1391  		if expect != "" {
  1392  			expect += ", "
  1393  		}
  1394  		opt := i >= len(desc.Args)-desc.OptArgs
  1395  		if opt {
  1396  			expect += "["
  1397  		}
  1398  		expect += arg.Name
  1399  		if opt {
  1400  			expect += "]"
  1401  		}
  1402  	}
  1403  	if needBase {
  1404  		if expect != "" {
  1405  			expect += ", "
  1406  		}
  1407  		expect += typeArgBase.Name
  1408  	}
  1409  	if !desc.CantBeOpt {
  1410  		if expect != "" {
  1411  			expect += ", "
  1412  		}
  1413  		expect += "[opt]"
  1414  	}
  1415  	if expect == "" {
  1416  		expect = "no arguments"
  1417  	}
  1418  	return expect
  1419  }
  1420  
  1421  func checkTypeKind(t *ast.Type, kind int) (unexpected, expect string, ok bool) {
  1422  	switch {
  1423  	case kind == kindAny:
  1424  		ok = true
  1425  	case t.HasString:
  1426  		ok = kind&kindString != 0
  1427  		if !ok {
  1428  			unexpected = fmt.Sprintf("string %q", t.String)
  1429  		}
  1430  	case t.Ident != "":
  1431  		ok = kind&(kindIdent|kindInt) != 0
  1432  		if !ok {
  1433  			unexpected = fmt.Sprintf("identifier %v", t.Ident)
  1434  		}
  1435  	default:
  1436  		ok = kind&kindInt != 0
  1437  		if !ok {
  1438  			unexpected = fmt.Sprintf("int %v", t.Value)
  1439  		}
  1440  	}
  1441  	if !ok {
  1442  		var expected []string
  1443  		if kind&kindString != 0 {
  1444  			expected = append(expected, "string")
  1445  		}
  1446  		if kind&kindIdent != 0 {
  1447  			expected = append(expected, "identifier")
  1448  		}
  1449  		if kind&kindInt != 0 {
  1450  			expected = append(expected, "int")
  1451  		}
  1452  		expect = strings.Join(expected, " or ")
  1453  	}
  1454  	return
  1455  }
  1456  
  1457  func (comp *compiler) checkVarlens() {
  1458  	for _, decl := range comp.desc.Nodes {
  1459  		switch n := decl.(type) {
  1460  		case *ast.Struct:
  1461  			comp.checkVarlen(n)
  1462  		}
  1463  	}
  1464  }
  1465  
  1466  func (comp *compiler) isVarlen(t *ast.Type) bool {
  1467  	desc, args, _ := comp.getArgsBase(t, false)
  1468  	return desc.Varlen != nil && desc.Varlen(comp, t, args)
  1469  }
  1470  
  1471  func (comp *compiler) isZeroSize(t *ast.Type) bool {
  1472  	// We can recurse here for a struct that recursively contains itself in an array.
  1473  	// In such case it's safe to say that it is zero size, because if all other fields are zero size,
  1474  	// then the struct is indeed zero size (even if it contains several versions of itself transitively).
  1475  	// If there are any other "normal" fields, then we will still correctly conclude that the whole struct
  1476  	// is not zero size.
  1477  	if comp.recursiveQuery[t] {
  1478  		return true
  1479  	}
  1480  	comp.recursiveQuery[t] = true
  1481  	desc, args, _ := comp.getArgsBase(t, false)
  1482  	res := desc.ZeroSize != nil && desc.ZeroSize(comp, t, args)
  1483  	delete(comp.recursiveQuery, t)
  1484  	return res
  1485  }
  1486  
  1487  func (comp *compiler) checkVarlen(n *ast.Struct) {
  1488  	// Non-varlen unions can't have varlen fields.
  1489  	// Non-packed structs can't have varlen fields in the middle.
  1490  	if n.IsUnion {
  1491  		attrs := comp.parseIntAttrs(unionAttrs, n, n.Attrs)
  1492  		if attrs[attrVarlen] != 0 {
  1493  			return
  1494  		}
  1495  	} else {
  1496  		attrs := comp.parseIntAttrs(structAttrs, n, n.Attrs)
  1497  		if attrs[attrPacked] != 0 {
  1498  			return
  1499  		}
  1500  	}
  1501  	for i, f := range n.Fields {
  1502  		_, exprs, _ := comp.parseAttrs(structOrUnionFieldAttrs(n), f, f.Attrs)
  1503  		if !n.IsUnion && i == len(n.Fields)-1 {
  1504  			break
  1505  		}
  1506  		if comp.isVarlen(f.Type) || !n.IsUnion && exprs[attrIf] != nil {
  1507  			if n.IsUnion {
  1508  				comp.error(f.Pos, "variable size field %v in non-varlen union %v",
  1509  					f.Name.Name, n.Name.Name)
  1510  			} else {
  1511  				comp.error(f.Pos, "variable size field %v in the middle of non-packed struct %v",
  1512  					f.Name.Name, n.Name.Name)
  1513  			}
  1514  		}
  1515  	}
  1516  }
  1517  
  1518  func (comp *compiler) checkDupConsts() {
  1519  	// The idea is to detect copy-paste errors in const arguments, e.g.:
  1520  	//   call$FOO(fd fd, arg const[FOO])
  1521  	//   call$BAR(fd fd, arg const[FOO])
  1522  	// The second one is meant to be const[BAR],
  1523  	// Unfortunately, this does not fully work as it detects lots of false positives.
  1524  	// But was useful to find real bugs as well. So for now it's disabled, but can be run manually.
  1525  	if true {
  1526  		return
  1527  	}
  1528  	dups := make(map[string]map[string]dupConstArg)
  1529  	for _, decl := range comp.desc.Nodes {
  1530  		switch n := decl.(type) {
  1531  		case *ast.Call:
  1532  			comp.checkDupConstsCall(n, dups)
  1533  		}
  1534  	}
  1535  }
  1536  
  1537  type dupConstArg struct {
  1538  	pos  ast.Pos
  1539  	name string
  1540  }
  1541  
  1542  func (comp *compiler) checkDupConstsCall(n *ast.Call, dups map[string]map[string]dupConstArg) {
  1543  	if n.NR == ^uint64(0) {
  1544  		return
  1545  	}
  1546  	for dups[n.CallName] == nil {
  1547  		dups[n.CallName] = make(map[string]dupConstArg)
  1548  	}
  1549  	hasConsts := false
  1550  	constArgID := ""
  1551  	for i, arg := range n.Args {
  1552  		desc := comp.getTypeDesc(arg.Type)
  1553  		switch desc {
  1554  		case typeConst:
  1555  			v := arg.Type.Args[0].Value
  1556  			if v != 0 && v != 18446744073709551516 { // AT_FDCWD
  1557  				constArgID += fmt.Sprintf("(%v-%v)", i, fmt.Sprintf("%v", v))
  1558  				hasConsts = true
  1559  			}
  1560  		case typeResource:
  1561  			constArgID += fmt.Sprintf("(%v-%v)", i, arg.Type.Ident)
  1562  		}
  1563  	}
  1564  	if !hasConsts {
  1565  		return
  1566  	}
  1567  	dup, ok := dups[n.CallName][constArgID]
  1568  	if !ok {
  1569  		dups[n.CallName][constArgID] = dupConstArg{
  1570  			pos:  n.Pos,
  1571  			name: n.Name.Name,
  1572  		}
  1573  		return
  1574  	}
  1575  	comp.error(n.Pos, "call %v: duplicate const %v, previously used in call %v at %v",
  1576  		n.Name.Name, constArgID, dup.name, dup.pos)
  1577  }