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 }