• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
6package compiler
7
8import (
9	"fmt"
10	"strings"
11
12	"github.com/google/syzkaller/pkg/ast"
13	"github.com/google/syzkaller/prog"
14)
15
16func (comp *compiler) typecheck() {
17	comp.checkDirectives()
18	comp.checkNames()
19	comp.checkFields()
20	comp.checkTypedefs()
21	comp.checkTypes()
22}
23
24func (comp *compiler) check() {
25	comp.checkTypeValues()
26	comp.checkAttributeValues()
27	comp.checkUnused()
28	comp.checkRecursion()
29	comp.checkLenTargets()
30	comp.checkConstructors()
31	comp.checkVarlens()
32	comp.checkDupConsts()
33}
34
35func (comp *compiler) checkDirectives() {
36	includes := make(map[string]bool)
37	incdirs := make(map[string]bool)
38	defines := make(map[string]bool)
39	for _, decl := range comp.desc.Nodes {
40		switch n := decl.(type) {
41		case *ast.Include:
42			name := n.File.Value
43			path := n.Pos.File + "/" + name
44			if includes[path] {
45				comp.error(n.Pos, "duplicate include %q", name)
46			}
47			includes[path] = true
48		case *ast.Incdir:
49			name := n.Dir.Value
50			path := n.Pos.File + "/" + name
51			if incdirs[path] {
52				comp.error(n.Pos, "duplicate incdir %q", name)
53			}
54			incdirs[path] = true
55		case *ast.Define:
56			name := n.Name.Name
57			path := n.Pos.File + "/" + name
58			if defines[path] {
59				comp.error(n.Pos, "duplicate define %v", name)
60			}
61			defines[path] = true
62		}
63	}
64}
65
66func (comp *compiler) checkNames() {
67	calls := make(map[string]*ast.Call)
68	for _, decl := range comp.desc.Nodes {
69		switch n := decl.(type) {
70		case *ast.Resource, *ast.Struct, *ast.TypeDef:
71			pos, typ, name := decl.Info()
72			if reservedName[name] {
73				comp.error(pos, "%v uses reserved name %v", typ, name)
74				continue
75			}
76			if builtinTypes[name] != nil || builtinTypedefs[name] != nil {
77				comp.error(pos, "%v name %v conflicts with builtin type", typ, name)
78				continue
79			}
80			if prev := comp.resources[name]; prev != nil {
81				comp.error(pos, "type %v redeclared, previously declared as resource at %v",
82					name, prev.Pos)
83				continue
84			}
85			if prev := comp.typedefs[name]; prev != nil {
86				comp.error(pos, "type %v redeclared, previously declared as type alias at %v",
87					name, prev.Pos)
88				continue
89			}
90			if prev := comp.structs[name]; prev != nil {
91				_, typ, _ := prev.Info()
92				comp.error(pos, "type %v redeclared, previously declared as %v at %v",
93					name, typ, prev.Pos)
94				continue
95			}
96			switch n := decl.(type) {
97			case *ast.Resource:
98				comp.resources[name] = n
99			case *ast.TypeDef:
100				comp.typedefs[name] = n
101			case *ast.Struct:
102				comp.structs[name] = n
103			}
104		case *ast.IntFlags:
105			name := n.Name.Name
106			if name == "_" {
107				continue
108			}
109			if reservedName[name] {
110				comp.error(n.Pos, "flags uses reserved name %v", name)
111				continue
112			}
113			if prev := comp.intFlags[name]; prev != nil {
114				comp.error(n.Pos, "flags %v redeclared, previously declared at %v",
115					name, prev.Pos)
116				continue
117			}
118			comp.intFlags[name] = n
119		case *ast.StrFlags:
120			name := n.Name.Name
121			if reservedName[name] {
122				comp.error(n.Pos, "string flags uses reserved name %v", name)
123				continue
124			}
125			if builtinStrFlags[name] != nil {
126				comp.error(n.Pos, "string flags %v conflicts with builtin flags", name)
127				continue
128			}
129			if prev := comp.strFlags[name]; prev != nil {
130				comp.error(n.Pos, "string flags %v redeclared, previously declared at %v",
131					name, prev.Pos)
132				continue
133			}
134			comp.strFlags[name] = n
135		case *ast.Call:
136			name := n.Name.Name
137			if prev := calls[name]; prev != nil {
138				comp.error(n.Pos, "syscall %v redeclared, previously declared at %v",
139					name, prev.Pos)
140			}
141			calls[name] = n
142		}
143	}
144}
145
146func (comp *compiler) checkFields() {
147	const maxArgs = 9 // executor does not support more
148	for _, decl := range comp.desc.Nodes {
149		switch n := decl.(type) {
150		case *ast.Struct:
151			_, typ, name := n.Info()
152			comp.checkStructFields(n, typ, name)
153		case *ast.TypeDef:
154			if n.Struct != nil {
155				_, typ, _ := n.Struct.Info()
156				comp.checkStructFields(n.Struct, "template "+typ, n.Name.Name)
157			}
158		case *ast.Call:
159			name := n.Name.Name
160			comp.checkFieldGroup(n.Args, "argument", "syscall "+name)
161			if len(n.Args) > maxArgs {
162				comp.error(n.Pos, "syscall %v has %v arguments, allowed maximum is %v",
163					name, len(n.Args), maxArgs)
164			}
165		}
166	}
167}
168
169func (comp *compiler) checkStructFields(n *ast.Struct, typ, name string) {
170	comp.checkFieldGroup(n.Fields, "field", typ+" "+name)
171	if len(n.Fields) < 1 {
172		comp.error(n.Pos, "%v %v has no fields, need at least 1 field", typ, name)
173	}
174}
175
176func (comp *compiler) checkFieldGroup(fields []*ast.Field, what, ctx string) {
177	existing := make(map[string]bool)
178	for _, f := range fields {
179		fn := f.Name.Name
180		if fn == "parent" {
181			comp.error(f.Pos, "reserved %v name %v in %v", what, fn, ctx)
182		}
183		if existing[fn] {
184			comp.error(f.Pos, "duplicate %v %v in %v", what, fn, ctx)
185		}
186		existing[fn] = true
187	}
188}
189
190func (comp *compiler) checkTypedefs() {
191	for _, decl := range comp.desc.Nodes {
192		switch n := decl.(type) {
193		case *ast.TypeDef:
194			if len(n.Args) == 0 {
195				// Non-template types are fully typed, so we check them ahead of time.
196				err0 := comp.errors
197				comp.checkType(checkCtx{}, n.Type, checkIsTypedef)
198				if err0 != comp.errors {
199					// To not produce confusing errors on broken type usage.
200					delete(comp.typedefs, n.Name.Name)
201				}
202			} else {
203				// For templates we only do basic checks of arguments.
204				names := make(map[string]bool)
205				for _, arg := range n.Args {
206					if names[arg.Name] {
207						comp.error(arg.Pos, "duplicate type argument %v", arg.Name)
208					}
209					names[arg.Name] = true
210					for _, c := range arg.Name {
211						if c >= 'A' && c <= 'Z' ||
212							c >= '0' && c <= '9' ||
213							c == '_' {
214							continue
215						}
216						comp.error(arg.Pos, "type argument %v must be ALL_CAPS",
217							arg.Name)
218						break
219					}
220				}
221			}
222		}
223	}
224}
225
226func (comp *compiler) checkTypes() {
227	for _, decl := range comp.desc.Nodes {
228		switch n := decl.(type) {
229		case *ast.Resource:
230			comp.checkType(checkCtx{}, n.Base, checkIsResourceBase)
231		case *ast.Struct:
232			comp.checkStruct(checkCtx{}, n)
233		case *ast.Call:
234			for _, a := range n.Args {
235				comp.checkType(checkCtx{}, a.Type, checkIsArg)
236			}
237			if n.Ret != nil {
238				comp.checkType(checkCtx{}, n.Ret, checkIsArg|checkIsRet)
239			}
240		}
241	}
242}
243
244func (comp *compiler) checkTypeValues() {
245	for _, decl := range comp.desc.Nodes {
246		switch decl.(type) {
247		case *ast.Call, *ast.Struct, *ast.Resource, *ast.TypeDef:
248			comp.foreachType(decl, func(t *ast.Type, desc *typeDesc,
249				args []*ast.Type, base prog.IntTypeCommon) {
250				if desc.CheckConsts != nil {
251					desc.CheckConsts(comp, t, args, base)
252				}
253				for i, arg := range args {
254					if check := desc.Args[i].Type.CheckConsts; check != nil {
255						check(comp, arg)
256					}
257				}
258			})
259		}
260	}
261}
262
263func (comp *compiler) checkAttributeValues() {
264	for _, decl := range comp.desc.Nodes {
265		switch n := decl.(type) {
266		case *ast.Struct:
267			for _, attr := range n.Attrs {
268				if attr.Ident == "size" {
269					_, typ, name := n.Info()
270					if comp.structIsVarlen(n.Name.Name) {
271						comp.error(attr.Pos, "varlen %v %v has size attribute",
272							typ, name)
273					}
274					sz := attr.Args[0].Value
275					if sz == 0 || sz > 1<<20 {
276						comp.error(attr.Args[0].Pos, "size attribute has bad value %v"+
277							", expect [1, 1<<20]", sz)
278					}
279				}
280			}
281		}
282	}
283}
284
285func (comp *compiler) checkLenTargets() {
286	for _, decl := range comp.desc.Nodes {
287		switch n := decl.(type) {
288		case *ast.Call:
289			for _, arg := range n.Args {
290				comp.checkLenType(arg.Type, arg.Name.Name, n.Args, nil, make(map[string]bool), true)
291			}
292		}
293	}
294}
295
296func (comp *compiler) checkLenType(t *ast.Type, name string, fields []*ast.Field,
297	parents []*ast.Struct, checked map[string]bool, isArg bool) {
298	desc := comp.getTypeDesc(t)
299	if desc == typeStruct {
300		s := comp.structs[t.Ident]
301		// Prune recursion, can happen even on correct tree via opt pointers.
302		if checked[s.Name.Name] {
303			return
304		}
305		checked[s.Name.Name] = true
306		parents = append(parents, s)
307		if !s.IsUnion {
308			fields = s.Fields
309		}
310		for _, fld := range s.Fields {
311			comp.checkLenType(fld.Type, fld.Name.Name, fields, parents, checked, false)
312		}
313		return
314	}
315	_, args, _ := comp.getArgsBase(t, "", prog.DirIn, isArg)
316	for i, arg := range args {
317		argDesc := desc.Args[i]
318		if argDesc.Type == typeArgLenTarget {
319			comp.checkLenTarget(t, name, arg.Ident, fields, parents)
320		} else if argDesc.Type == typeArgType {
321			comp.checkLenType(arg, name, fields, parents, checked, argDesc.IsArg)
322		}
323	}
324}
325
326func (comp *compiler) checkLenTarget(t *ast.Type, name, target string, fields []*ast.Field, parents []*ast.Struct) {
327	if target == name {
328		comp.error(t.Pos, "%v target %v refer to itself", t.Ident, target)
329		return
330	}
331	if target == "parent" {
332		if len(parents) == 0 {
333			comp.error(t.Pos, "%v target %v does not exist", t.Ident, target)
334		}
335		return
336	}
337	for _, fld := range fields {
338		if target != fld.Name.Name {
339			continue
340		}
341		if fld.Type == t {
342			comp.error(t.Pos, "%v target %v refer to itself", t.Ident, target)
343		}
344		if t.Ident == "len" {
345			inner := fld.Type
346			desc, args, _ := comp.getArgsBase(inner, "", prog.DirIn, false)
347			for desc == typePtr {
348				if desc != typePtr {
349					break
350				}
351				inner = args[1]
352				desc, args, _ = comp.getArgsBase(inner, "", prog.DirIn, false)
353			}
354			if desc == typeArray && comp.isVarlen(args[0]) {
355				comp.warning(t.Pos, "len target %v refer to an array with"+
356					" variable-size elements (do you mean bytesize?)", target)
357			}
358		}
359		return
360	}
361	for _, parent := range parents {
362		parentName := parent.Name.Name
363		if pos := strings.IndexByte(parentName, '['); pos != -1 {
364			// For template parents name is "struct_name[ARG1, ARG2]", strip the part after '['.
365			parentName = parentName[:pos]
366		}
367		if target == parentName {
368			return
369		}
370	}
371	comp.error(t.Pos, "%v target %v does not exist", t.Ident, target)
372}
373
374func (comp *compiler) collectUsed(all bool) (structs, flags, strflags map[string]bool) {
375	structs = make(map[string]bool)
376	flags = make(map[string]bool)
377	strflags = make(map[string]bool)
378	for _, decl := range comp.desc.Nodes {
379		switch n := decl.(type) {
380		case *ast.Call:
381			if !all && n.NR == ^uint64(0) {
382				break
383			}
384			for _, arg := range n.Args {
385				comp.collectUsedType(structs, flags, strflags, arg.Type, true)
386			}
387			if n.Ret != nil {
388				comp.collectUsedType(structs, flags, strflags, n.Ret, true)
389			}
390		}
391	}
392	return
393}
394
395func (comp *compiler) collectUsedType(structs, flags, strflags map[string]bool, t *ast.Type, isArg bool) {
396	desc := comp.getTypeDesc(t)
397	if desc == typeResource {
398		r := comp.resources[t.Ident]
399		for r != nil && !structs[r.Name.Name] {
400			structs[r.Name.Name] = true
401			r = comp.resources[r.Base.Ident]
402		}
403		return
404	}
405	if desc == typeStruct {
406		if structs[t.Ident] {
407			return
408		}
409		structs[t.Ident] = true
410		s := comp.structs[t.Ident]
411		for _, fld := range s.Fields {
412			comp.collectUsedType(structs, flags, strflags, fld.Type, false)
413		}
414		return
415	}
416	if desc == typeFlags {
417		flags[t.Args[0].Ident] = true
418		return
419	}
420	if desc == typeString {
421		if len(t.Args) != 0 && t.Args[0].Ident != "" {
422			strflags[t.Args[0].Ident] = true
423		}
424		return
425	}
426	_, args, _ := comp.getArgsBase(t, "", prog.DirIn, isArg)
427	for i, arg := range args {
428		if desc.Args[i].Type == typeArgType {
429			comp.collectUsedType(structs, flags, strflags, arg, desc.Args[i].IsArg)
430		}
431	}
432}
433
434func (comp *compiler) checkUnused() {
435	comp.used, _, _ = comp.collectUsed(false)
436	structs, flags, strflags := comp.collectUsed(true)
437	_, _, _ = structs, flags, strflags
438
439	for name, n := range comp.intFlags {
440		if !flags[name] {
441			comp.error(n.Pos, "unused flags %v", name)
442		}
443	}
444	for name, n := range comp.strFlags {
445		if !strflags[name] && builtinStrFlags[name] == nil {
446			comp.error(n.Pos, "unused string flags %v", name)
447		}
448	}
449	for name, n := range comp.resources {
450		if !structs[name] {
451			comp.error(n.Pos, "unused resource %v", name)
452		}
453	}
454	for name, n := range comp.structs {
455		if !structs[name] {
456			_, typ, _ := n.Info()
457			comp.error(n.Pos, "unused %v %v", typ, name)
458		}
459	}
460	for name, n := range comp.typedefs {
461		if !comp.usedTypedefs[name] {
462			comp.error(n.Pos, "unused type %v", name)
463		}
464	}
465}
466
467type structDir struct {
468	Struct string
469	Dir    prog.Dir
470}
471
472func (comp *compiler) checkConstructors() {
473	ctors := make(map[string]bool) // resources for which we have ctors
474	checked := make(map[structDir]bool)
475	for _, decl := range comp.desc.Nodes {
476		switch n := decl.(type) {
477		case *ast.Call:
478			for _, arg := range n.Args {
479				comp.checkTypeCtors(arg.Type, prog.DirIn, true, ctors, checked)
480			}
481			if n.Ret != nil {
482				comp.checkTypeCtors(n.Ret, prog.DirOut, true, ctors, checked)
483			}
484		}
485	}
486	for _, decl := range comp.desc.Nodes {
487		switch n := decl.(type) {
488		case *ast.Resource:
489			name := n.Name.Name
490			if !ctors[name] && comp.used[name] {
491				comp.error(n.Pos, "resource %v can't be created"+
492					" (never mentioned as a syscall return value or output argument/field)",
493					name)
494			}
495		}
496	}
497}
498
499func (comp *compiler) checkTypeCtors(t *ast.Type, dir prog.Dir, isArg bool,
500	ctors map[string]bool, checked map[structDir]bool) {
501	desc := comp.getTypeDesc(t)
502	if desc == typeResource {
503		// TODO(dvyukov): consider changing this to "dir == prog.DirOut".
504		// We have few questionable cases where resources can be created
505		// only by inout struct fields. These structs should be split
506		// into two different structs: one is in and second is out.
507		// But that will require attaching dir to individual fields.
508		if dir != prog.DirIn {
509			r := comp.resources[t.Ident]
510			for r != nil && !ctors[r.Name.Name] {
511				ctors[r.Name.Name] = true
512				r = comp.resources[r.Base.Ident]
513			}
514		}
515		return
516	}
517	if desc == typeStruct {
518		s := comp.structs[t.Ident]
519		name := s.Name.Name
520		key := structDir{name, dir}
521		if checked[key] {
522			return
523		}
524		checked[key] = true
525		for _, fld := range s.Fields {
526			comp.checkTypeCtors(fld.Type, dir, false, ctors, checked)
527		}
528		return
529	}
530	if desc == typePtr {
531		dir = genDir(t.Args[0])
532	}
533	_, args, _ := comp.getArgsBase(t, "", dir, isArg)
534	for i, arg := range args {
535		if desc.Args[i].Type == typeArgType {
536			comp.checkTypeCtors(arg, dir, desc.Args[i].IsArg, ctors, checked)
537		}
538	}
539}
540
541func (comp *compiler) checkRecursion() {
542	checked := make(map[string]bool)
543	for _, decl := range comp.desc.Nodes {
544		switch n := decl.(type) {
545		case *ast.Resource:
546			comp.checkResourceRecursion(n)
547		case *ast.Struct:
548			var path []pathElem
549			comp.checkStructRecursion(checked, n, path)
550		}
551	}
552}
553
554func (comp *compiler) checkResourceRecursion(n *ast.Resource) {
555	var seen []string
556	for n != nil {
557		if arrayContains(seen, n.Name.Name) {
558			chain := ""
559			for _, r := range seen {
560				chain += r + "->"
561			}
562			chain += n.Name.Name
563			comp.error(n.Pos, "recursive resource %v", chain)
564			return
565		}
566		seen = append(seen, n.Name.Name)
567		n = comp.resources[n.Base.Ident]
568	}
569}
570
571type pathElem struct {
572	Pos    ast.Pos
573	Struct string
574	Field  string
575}
576
577func (comp *compiler) checkStructRecursion(checked map[string]bool, n *ast.Struct, path []pathElem) {
578	name := n.Name.Name
579	if checked[name] {
580		return
581	}
582	for i, elem := range path {
583		if elem.Struct != name {
584			continue
585		}
586		path = path[i:]
587		str := ""
588		for _, elem := range path {
589			str += fmt.Sprintf("%v.%v -> ", elem.Struct, elem.Field)
590		}
591		str += name
592		comp.error(path[0].Pos, "recursive declaration: %v (mark some pointers as opt)", str)
593		checked[name] = true
594		return
595	}
596	for _, f := range n.Fields {
597		path = append(path, pathElem{
598			Pos:    f.Pos,
599			Struct: name,
600			Field:  f.Name.Name,
601		})
602		comp.recurseField(checked, f.Type, path)
603		path = path[:len(path)-1]
604	}
605	checked[name] = true
606}
607
608func (comp *compiler) recurseField(checked map[string]bool, t *ast.Type, path []pathElem) {
609	desc := comp.getTypeDesc(t)
610	if desc == typeStruct {
611		comp.checkStructRecursion(checked, comp.structs[t.Ident], path)
612		return
613	}
614	_, args, base := comp.getArgsBase(t, "", prog.DirIn, false)
615	if desc == typePtr && base.IsOptional {
616		return // optional pointers prune recursion
617	}
618	for i, arg := range args {
619		if desc.Args[i].Type == typeArgType {
620			comp.recurseField(checked, arg, path)
621		}
622	}
623}
624
625func (comp *compiler) checkStruct(ctx checkCtx, n *ast.Struct) {
626	var flags checkFlags
627	if !n.IsUnion {
628		flags |= checkIsStruct
629	}
630	for _, f := range n.Fields {
631		comp.checkType(ctx, f.Type, flags)
632	}
633	for _, attr := range n.Attrs {
634		if unexpected, _, ok := checkTypeKind(attr, kindIdent); !ok {
635			comp.error(attr.Pos, "unexpected %v, expect attribute", unexpected)
636			return
637		}
638		if attr.HasColon {
639			comp.error(attr.Pos2, "unexpected ':'")
640			return
641		}
642	}
643	if n.IsUnion {
644		comp.parseUnionAttrs(n)
645	} else {
646		comp.parseStructAttrs(n)
647	}
648}
649
650type checkFlags int
651
652const (
653	checkIsArg          checkFlags = 1 << iota // immediate syscall arg type
654	checkIsRet                                 // immediate syscall ret type
655	checkIsStruct                              // immediate struct field type
656	checkIsResourceBase                        // immediate resource base type
657	checkIsTypedef                             // immediate type alias/template type
658)
659
660type checkCtx struct {
661	instantiationStack []string
662}
663
664func (comp *compiler) checkType(ctx checkCtx, t *ast.Type, flags checkFlags) {
665	if unexpected, _, ok := checkTypeKind(t, kindIdent); !ok {
666		comp.error(t.Pos, "unexpected %v, expect type", unexpected)
667		return
668	}
669	desc := comp.getTypeDesc(t)
670	if desc == nil {
671		comp.error(t.Pos, "unknown type %v", t.Ident)
672		return
673	}
674	if desc == typeTypedef {
675		err0 := comp.errors
676		// Replace t with type alias/template target type inplace,
677		// and check the replaced type recursively.
678		comp.replaceTypedef(&ctx, t, flags)
679		if err0 == comp.errors {
680			comp.checkType(ctx, t, flags)
681		}
682		return
683	}
684	err0 := comp.errors
685	comp.checkTypeBasic(t, desc, flags)
686	if err0 != comp.errors {
687		return
688	}
689	args := comp.checkTypeArgs(t, desc, flags)
690	if err0 != comp.errors {
691		return
692	}
693	for i, arg := range args {
694		if desc.Args[i].Type == typeArgType {
695			var innerFlags checkFlags
696			if desc.Args[i].IsArg {
697				innerFlags |= checkIsArg
698			}
699			comp.checkType(ctx, arg, innerFlags)
700		} else {
701			comp.checkTypeArg(t, arg, desc.Args[i])
702		}
703	}
704	if err0 != comp.errors {
705		return
706	}
707	if desc.Check != nil {
708		_, args, base := comp.getArgsBase(t, "", prog.DirIn, flags&checkIsArg != 0)
709		desc.Check(comp, t, args, base)
710	}
711}
712
713func (comp *compiler) checkTypeBasic(t *ast.Type, desc *typeDesc, flags checkFlags) {
714	if t.HasColon {
715		if !desc.AllowColon {
716			comp.error(t.Pos2, "unexpected ':'")
717			return
718		}
719		if flags&checkIsStruct == 0 {
720			comp.error(t.Pos2, "unexpected ':', only struct fields can be bitfields")
721			return
722		}
723	}
724	if flags&checkIsTypedef != 0 && !desc.CanBeTypedef {
725		comp.error(t.Pos, "%v can't be type alias target", t.Ident)
726		return
727	}
728	if flags&checkIsResourceBase != 0 && !desc.ResourceBase {
729		comp.error(t.Pos, "%v can't be resource base (int types can)", t.Ident)
730		return
731	}
732	canBeArg, canBeRet := false, false
733	if desc.CanBeArgRet != nil {
734		canBeArg, canBeRet = desc.CanBeArgRet(comp, t)
735	}
736	if flags&checkIsRet != 0 && !canBeRet {
737		comp.error(t.Pos, "%v can't be syscall return", t.Ident)
738		return
739	}
740	if flags&checkIsArg != 0 && !canBeArg {
741		comp.error(t.Pos, "%v can't be syscall argument", t.Ident)
742		return
743	}
744}
745
746func (comp *compiler) checkTypeArgs(t *ast.Type, desc *typeDesc, flags checkFlags) []*ast.Type {
747	args, opt := removeOpt(t)
748	if opt != nil {
749		if len(opt.Args) != 0 {
750			comp.error(opt.Pos, "opt can't have arguments")
751		}
752		if flags&checkIsResourceBase != 0 || desc.CantBeOpt {
753			what := "resource base"
754			if desc.CantBeOpt {
755				what = t.Ident
756			}
757			comp.error(opt.Pos, "%v can't be marked as opt", what)
758			return nil
759		}
760	}
761	addArgs := 0
762	needBase := flags&checkIsArg == 0 && desc.NeedBase
763	if needBase {
764		addArgs++ // last arg must be base type, e.g. const[0, int32]
765	}
766	if len(args) > len(desc.Args)+addArgs || len(args) < len(desc.Args)-desc.OptArgs+addArgs {
767		comp.error(t.Pos, "wrong number of arguments for type %v, expect %v",
768			t.Ident, expectedTypeArgs(desc, needBase))
769		return nil
770	}
771	if needBase {
772		base := args[len(args)-1]
773		args = args[:len(args)-1]
774		comp.checkTypeArg(t, base, typeArgBase)
775	}
776	return args
777}
778
779func (comp *compiler) replaceTypedef(ctx *checkCtx, t *ast.Type, flags checkFlags) {
780	typedefName := t.Ident
781	comp.usedTypedefs[typedefName] = true
782	if t.HasColon {
783		comp.error(t.Pos, "type alias %v with ':'", t.Ident)
784		return
785	}
786	typedef := comp.typedefs[typedefName]
787	fullTypeName := ast.SerializeNode(t)
788	for i, prev := range ctx.instantiationStack {
789		if prev == fullTypeName {
790			ctx.instantiationStack = append(ctx.instantiationStack, fullTypeName)
791			path := ""
792			for j := i; j < len(ctx.instantiationStack); j++ {
793				if j != i {
794					path += " -> "
795				}
796				path += ctx.instantiationStack[j]
797			}
798			comp.error(t.Pos, "type instantiation loop: %v", path)
799			return
800		}
801	}
802	ctx.instantiationStack = append(ctx.instantiationStack, fullTypeName)
803	nargs := len(typedef.Args)
804	args := t.Args
805	if nargs != len(t.Args) {
806		if nargs == 0 {
807			comp.error(t.Pos, "type %v is not a template", typedefName)
808		} else {
809			comp.error(t.Pos, "template %v needs %v arguments instead of %v",
810				typedefName, nargs, len(t.Args))
811		}
812		return
813	}
814	pos0 := t.Pos
815	if typedef.Type != nil {
816		*t = *typedef.Type.Clone().(*ast.Type)
817		if !comp.instantiate(t, typedef.Args, args) {
818			return
819		}
820	} else {
821		if comp.structs[fullTypeName] == nil {
822			inst := typedef.Struct.Clone().(*ast.Struct)
823			inst.Name.Name = fullTypeName
824			if !comp.instantiate(inst, typedef.Args, args) {
825				return
826			}
827			comp.checkStruct(*ctx, inst)
828			comp.desc.Nodes = append(comp.desc.Nodes, inst)
829			comp.structs[fullTypeName] = inst
830		}
831		*t = ast.Type{
832			Ident: fullTypeName,
833		}
834	}
835	t.Pos = pos0
836
837	// Remove base type if it's not needed in this context.
838	desc := comp.getTypeDesc(t)
839	if flags&checkIsArg != 0 && desc.NeedBase {
840		baseTypePos := len(t.Args) - 1
841		if t.Args[baseTypePos].Ident == "opt" {
842			baseTypePos--
843		}
844		copy(t.Args[baseTypePos:], t.Args[baseTypePos+1:])
845		t.Args = t.Args[:len(t.Args)-1]
846	}
847}
848
849func (comp *compiler) instantiate(templ ast.Node, params []*ast.Ident, args []*ast.Type) bool {
850	if len(params) == 0 {
851		return true
852	}
853	argMap := make(map[string]*ast.Type)
854	for i, param := range params {
855		argMap[param.Name] = args[i]
856	}
857	err0 := comp.errors
858	templ.Walk(ast.Recursive(func(n ast.Node) {
859		templArg, ok := n.(*ast.Type)
860		if !ok {
861			return
862		}
863		if concreteArg := argMap[templArg.Ident]; concreteArg != nil {
864			origArgs := templArg.Args
865			if len(origArgs) != 0 && len(concreteArg.Args) != 0 {
866				comp.error(templArg.Pos, "both template parameter %v and its usage"+
867					" have sub-arguments", templArg.Ident)
868				return
869			}
870			*templArg = *concreteArg.Clone().(*ast.Type)
871			if len(origArgs) != 0 {
872				templArg.Args = origArgs
873			}
874		}
875		// TODO(dvyukov): somewhat hacky, but required for int8[0:CONST_ARG]
876		// Need more checks here. E.g. that CONST_ARG does not have subargs.
877		// And if CONST_ARG is a value, then use concreteArg.Value.
878		// Also need to error if CONST_ARG is a string.
879		if concreteArg := argMap[templArg.Ident2]; concreteArg != nil {
880			templArg.Ident2 = concreteArg.Ident
881			templArg.Pos2 = concreteArg.Pos
882		}
883	}))
884	return err0 == comp.errors
885}
886
887func (comp *compiler) checkTypeArg(t, arg *ast.Type, argDesc namedArg) {
888	desc := argDesc.Type
889	if len(desc.Names) != 0 {
890		if unexpected, _, ok := checkTypeKind(arg, kindIdent); !ok {
891			comp.error(arg.Pos, "unexpected %v for %v argument of %v type, expect %+v",
892				unexpected, argDesc.Name, t.Ident, desc.Names)
893			return
894		}
895		if !arrayContains(desc.Names, arg.Ident) {
896			comp.error(arg.Pos, "unexpected value %v for %v argument of %v type, expect %+v",
897				arg.Ident, argDesc.Name, t.Ident, desc.Names)
898			return
899		}
900	} else {
901		if unexpected, expect, ok := checkTypeKind(arg, desc.Kind); !ok {
902			comp.error(arg.Pos, "unexpected %v for %v argument of %v type, expect %v",
903				unexpected, argDesc.Name, t.Ident, expect)
904			return
905		}
906	}
907	if !desc.AllowColon && arg.HasColon {
908		comp.error(arg.Pos2, "unexpected ':'")
909		return
910	}
911	if len(arg.Args) > desc.MaxArgs {
912		comp.error(arg.Pos, "%v argument has subargs", argDesc.Name)
913		return
914	}
915	if desc.Check != nil {
916		desc.Check(comp, arg)
917	}
918}
919
920func expectedTypeArgs(desc *typeDesc, needBase bool) string {
921	expect := ""
922	for i, arg := range desc.Args {
923		if expect != "" {
924			expect += ", "
925		}
926		opt := i >= len(desc.Args)-desc.OptArgs
927		if opt {
928			expect += "["
929		}
930		expect += arg.Name
931		if opt {
932			expect += "]"
933		}
934	}
935	if needBase {
936		if expect != "" {
937			expect += ", "
938		}
939		expect += typeArgBase.Name
940	}
941	if !desc.CantBeOpt {
942		if expect != "" {
943			expect += ", "
944		}
945		expect += "[opt]"
946	}
947	if expect == "" {
948		expect = "no arguments"
949	}
950	return expect
951}
952
953func checkTypeKind(t *ast.Type, kind int) (unexpected string, expect string, ok bool) {
954	switch {
955	case kind == kindAny:
956		ok = true
957	case t.HasString:
958		ok = kind == kindString
959		if !ok {
960			unexpected = fmt.Sprintf("string %q", t.String)
961		}
962	case t.Ident != "":
963		ok = kind == kindIdent || kind == kindInt
964		if !ok {
965			unexpected = fmt.Sprintf("identifier %v", t.Ident)
966		}
967	default:
968		ok = kind == kindInt
969		if !ok {
970			unexpected = fmt.Sprintf("int %v", t.Value)
971		}
972	}
973	if !ok {
974		switch kind {
975		case kindString:
976			expect = "string"
977		case kindIdent:
978			expect = "identifier"
979		case kindInt:
980			expect = "int"
981		}
982	}
983	return
984}
985
986func (comp *compiler) checkVarlens() {
987	for _, decl := range comp.desc.Nodes {
988		switch n := decl.(type) {
989		case *ast.Struct:
990			comp.checkVarlen(n)
991		}
992	}
993}
994
995func (comp *compiler) isVarlen(t *ast.Type) bool {
996	desc, args, _ := comp.getArgsBase(t, "", prog.DirIn, false)
997	return desc.Varlen != nil && desc.Varlen(comp, t, args)
998}
999
1000func (comp *compiler) isZeroSize(t *ast.Type) bool {
1001	desc, args, _ := comp.getArgsBase(t, "", prog.DirIn, false)
1002	return desc.ZeroSize != nil && desc.ZeroSize(comp, t, args)
1003}
1004
1005func (comp *compiler) checkVarlen(n *ast.Struct) {
1006	// Non-varlen unions can't have varlen fields.
1007	// Non-packed structs can't have varlen fields in the middle.
1008	if n.IsUnion {
1009		if varlen, _ := comp.parseUnionAttrs(n); varlen {
1010			return
1011		}
1012	} else {
1013		if packed, _, _ := comp.parseStructAttrs(n); packed {
1014			return
1015		}
1016	}
1017	for i, f := range n.Fields {
1018		if !n.IsUnion && i == len(n.Fields)-1 {
1019			break
1020		}
1021		if comp.isVarlen(f.Type) {
1022			if n.IsUnion {
1023				comp.error(f.Pos, "variable size field %v in non-varlen union %v",
1024					f.Name.Name, n.Name.Name)
1025			} else {
1026				comp.error(f.Pos, "variable size field %v in the middle of non-packed struct %v",
1027					f.Name.Name, n.Name.Name)
1028			}
1029		}
1030	}
1031}
1032
1033func (comp *compiler) checkDupConsts() {
1034	// The idea is to detect copy-paste errors in const arguments, e.g.:
1035	//   call$FOO(fd fd, arg const[FOO])
1036	//   call$BAR(fd fd, arg const[FOO])
1037	// The second one is meant to be const[BAR],
1038	// Unfortunately, this does not fully work as it detects lots of false positives.
1039	// But was useful to find real bugs as well. So for now it's disabled, but can be run manually.
1040	if true {
1041		return
1042	}
1043	dups := make(map[string]map[string]dupConstArg)
1044	for _, decl := range comp.desc.Nodes {
1045		switch n := decl.(type) {
1046		case *ast.Call:
1047			comp.checkDupConstsCall(n, dups)
1048		}
1049	}
1050}
1051
1052type dupConstArg struct {
1053	pos  ast.Pos
1054	name string
1055}
1056
1057func (comp *compiler) checkDupConstsCall(n *ast.Call, dups map[string]map[string]dupConstArg) {
1058	if n.NR == ^uint64(0) {
1059		return
1060	}
1061	for dups[n.CallName] == nil {
1062		dups[n.CallName] = make(map[string]dupConstArg)
1063	}
1064	hasConsts := false
1065	constArgID := ""
1066	for i, arg := range n.Args {
1067		desc := comp.getTypeDesc(arg.Type)
1068		if desc == typeConst {
1069			v := arg.Type.Args[0].Value
1070			if v != 0 && v != 18446744073709551516 { // AT_FDCWD
1071				constArgID += fmt.Sprintf("(%v-%v)", i, fmt.Sprintf("%v", v))
1072				hasConsts = true
1073			}
1074		} else if desc == typeResource {
1075			constArgID += fmt.Sprintf("(%v-%v)", i, arg.Type.Ident)
1076		}
1077	}
1078	if !hasConsts {
1079		return
1080	}
1081	dup, ok := dups[n.CallName][constArgID]
1082	if !ok {
1083		dups[n.CallName][constArgID] = dupConstArg{
1084			pos:  n.Pos,
1085			name: n.Name.Name,
1086		}
1087		return
1088	}
1089	comp.error(n.Pos, "call %v: duplicate const %v, previously used in call %v at %v",
1090		n.Name.Name, constArgID, dup.name, dup.pos)
1091}
1092