diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2020-03-17 14:32:13 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2020-03-17 21:19:13 +0100 |
| commit | 2e9037c55f6a3308190ab4eb0ce110dddc7a6f2b (patch) | |
| tree | 7f97740e9d496a53a990d88a41405e67b8d4af44 /pkg/compiler | |
| parent | 0bcbb36f9fff81ac0bff9ec0959b9ea4c444a700 (diff) | |
pkg/compiler: check that const values fit into base type
const[0x12345678, int8] is always an error, detect these cases.
Found some bugs in mptcp, socket proto and fuchsia fidl descriptions.
Diffstat (limited to 'pkg/compiler')
| -rw-r--r-- | pkg/compiler/gen.go | 66 | ||||
| -rw-r--r-- | pkg/compiler/testdata/errors2.txt | 4 | ||||
| -rw-r--r-- | pkg/compiler/testdata/errors3.txt | 3 | ||||
| -rw-r--r-- | pkg/compiler/types.go | 26 |
4 files changed, 53 insertions, 46 deletions
diff --git a/pkg/compiler/gen.go b/pkg/compiler/gen.go index 30080f56a..5a658ce15 100644 --- a/pkg/compiler/gen.go +++ b/pkg/compiler/gen.go @@ -60,10 +60,10 @@ func (comp *compiler) collectCallArgSizes() map[string][]uint64 { argSizes := callArgSizes[n.CallName] for i, arg := range n.Args { if len(argSizes) <= i { - argSizes = append(argSizes, 0) + argSizes = append(argSizes, comp.ptrSize) } desc, _, _ := comp.getArgsBase(arg.Type, arg.Name.Name, prog.DirIn, true) - typ := comp.genField(arg, prog.DirIn, true) + typ := comp.genField(arg, prog.DirIn, comp.ptrSize) // Ignore all types with base (const, flags). We don't have base in syscall args. // Also ignore resources and pointers because fd can be 32-bits and pointer 64-bits, // and then there is no way to fix this. @@ -76,7 +76,7 @@ func (comp *compiler) collectCallArgSizes() map[string][]uint64 { continue } argID := fmt.Sprintf("%v|%v", n.CallName, i) - if argSizes[i] == 0 { + if _, ok := argPos[argID]; !ok { argSizes[i] = typ.Size() argPos[argID] = arg.Pos continue @@ -109,45 +109,18 @@ func (comp *compiler) genSyscalls() []*prog.Syscall { func (comp *compiler) genSyscall(n *ast.Call, argSizes []uint64) *prog.Syscall { var ret prog.Type if n.Ret != nil { - ret = comp.genType(n.Ret, "ret", prog.DirOut, true) - } - args := comp.genFieldArray(n.Args, prog.DirIn, true) - for i, arg := range args { - // Now that we know a more precise size, patch the type. - // This is somewhat hacky. Ideally we figure out the size earlier, - // store it somewhere and use during generation of the arg base type. - if argSizes[i] != 0 { - patchArgBaseSize(arg, argSizes[i]) - } + ret = comp.genType(n.Ret, "ret", prog.DirOut, comp.ptrSize) } return &prog.Syscall{ Name: n.Name.Name, CallName: n.CallName, NR: n.NR, MissingArgs: len(argSizes) - len(n.Args), - Args: args, + Args: comp.genFieldArray(n.Args, prog.DirIn, argSizes), Ret: ret, } } -func patchArgBaseSize(t0 prog.Type, size uint64) { - // We only need types that (1) can be arg, (2) have base type. - switch t := t0.(type) { - case *prog.ConstType: - t.TypeSize = size - case *prog.LenType: - t.TypeSize = size - case *prog.FlagsType: - t.TypeSize = size - case *prog.ProcType: - t.TypeSize = size - case *prog.IntType, *prog.ResourceType, *prog.PtrType, *prog.VmaType, *prog.UnionType: - // These don't have base. - default: - panic(fmt.Sprintf("type %#v can't be an arg", t)) - } -} - func (comp *compiler) genStructDescs(syscalls []*prog.Syscall) []*prog.KeyedStruct { // Calculate struct/union/array sizes, add padding to structs and detach // StructDesc's from StructType's. StructType's can be recursive so it's @@ -321,7 +294,7 @@ func (comp *compiler) genStructDesc(res *prog.StructDesc, n *ast.Struct, dir pro common.IsVarlen = varlen *res = prog.StructDesc{ TypeCommon: common, - Fields: comp.genFieldArray(n.Fields, dir, false), + Fields: comp.genFieldArray(n.Fields, dir, make([]uint64, len(n.Fields))), } } @@ -517,23 +490,32 @@ func genPad(size uint64) prog.Type { } } -func (comp *compiler) genField(f *ast.Field, dir prog.Dir, isArg bool) prog.Type { - return comp.genType(f.Type, f.Name.Name, dir, isArg) -} - -func (comp *compiler) genFieldArray(fields []*ast.Field, dir prog.Dir, isArg bool) []prog.Type { +func (comp *compiler) genFieldArray(fields []*ast.Field, dir prog.Dir, argSizes []uint64) []prog.Type { var res []prog.Type - for _, f := range fields { - res = append(res, comp.genField(f, dir, isArg)) + for i, f := range fields { + res = append(res, comp.genField(f, dir, argSizes[i])) } return res } -func (comp *compiler) genType(t *ast.Type, field string, dir prog.Dir, isArg bool) prog.Type { - desc, args, base := comp.getArgsBase(t, field, dir, isArg) +func (comp *compiler) genField(f *ast.Field, dir prog.Dir, argSize uint64) prog.Type { + return comp.genType(f.Type, f.Name.Name, dir, argSize) +} + +func (comp *compiler) genType(t *ast.Type, field string, dir prog.Dir, argSize uint64) prog.Type { + desc, args, base := comp.getArgsBase(t, field, dir, argSize != 0) if desc.Gen == nil { panic(fmt.Sprintf("no gen for %v %#v", field, t)) } + if argSize != 0 { + // Now that we know a more precise size, patch the type. + // This is somewhat hacky. Ideally we figure out the size earlier, + // store it somewhere and use during generation of the arg base type. + base.TypeSize = argSize + if desc.CheckConsts != nil { + desc.CheckConsts(comp, t, args, base) + } + } base.IsVarlen = desc.Varlen != nil && desc.Varlen(comp, t, args) return desc.Gen(comp, t, args, base) } diff --git a/pkg/compiler/testdata/errors2.txt b/pkg/compiler/testdata/errors2.txt index 2b24d3628..4ec52d6cb 100644 --- a/pkg/compiler/testdata/errors2.txt +++ b/pkg/compiler/testdata/errors2.txt @@ -270,6 +270,10 @@ foo$526(a int8[-255:255]) ### int range [18446744073709551361:255] is too large foo$527(a int16[-40000:40000]) ### int range [18446744073709511616:40000] is too large for base type of size 16 foo$528(a ptr[in, s405]) foo$529(a ptr[in, string[`abcdde`, 3]]) ### string value "\xab\xcd\xde\x00" exceeds buffer length 3 +foo$530(a ptr[in, const[0x1ab, int8]]) ### const val 0x1ab does not fit into 8 bits +foo$531(a ptr[in, const[0xffffffffffffffab, int8]]) +foo$532(a ptr[in, const[0x7234567812345678, int64]]) +foo$533(a ptr[in, const[0x12, int8:4]]) ### const val 0x12 does not fit into 4 bits type type500 proc[C1, 8, int8] ### values starting from 1 with step 8 overflow base type for 32 procs type type501 int8 ### unused type type501 diff --git a/pkg/compiler/testdata/errors3.txt b/pkg/compiler/testdata/errors3.txt index 65bd20092..3221ee5dc 100644 --- a/pkg/compiler/testdata/errors3.txt +++ b/pkg/compiler/testdata/errors3.txt @@ -6,6 +6,9 @@ discrimination(a int32) discrimination$1(a int16) ### discrimination$1 arg a is redeclared with size 2, previously declared with size 4 at LOCATION +arg_size$1(a int16) +arg_size$2(a const[0x12345]) ### const val 0x12345 does not fit into 16 bits + bad_size_attr_struct { a int64 } [size[4]] ### struct bad_size_attr_struct has size attribute 4 which is less than struct size 8 diff --git a/pkg/compiler/types.go b/pkg/compiler/types.go index 43efee202..0c05c82fa 100644 --- a/pkg/compiler/types.go +++ b/pkg/compiler/types.go @@ -163,7 +163,7 @@ var typePtr = &typeDesc{ } return &prog.PtrType{ TypeCommon: base.TypeCommon, - Type: comp.genType(args[1], "", genDir(args[0]), false), + Type: comp.genType(args[1], "", genDir(args[0]), 0), } }, } @@ -212,7 +212,7 @@ var typeArray = &typeDesc{ return comp.isZeroSize(args[0]) }, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { - elemType := comp.genType(args[0], "", base.ArgDir, false) + elemType := comp.genType(args[0], "", base.ArgDir, 0) kind, begin, end := prog.ArrayRandLen, uint64(0), uint64(0) if len(args) > 1 { kind, begin, end = prog.ArrayRangeLen, args[1].Value, args[1].Value @@ -289,6 +289,24 @@ var typeConst = &typeDesc{ CantBeOpt: true, NeedBase: true, Args: []namedArg{{Name: "value", Type: typeArgInt}}, + CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { + size := base.BitfieldLen + if size == 0 { + size = base.TypeSize * 8 + } + if size == 64 { + return + } + v0 := args[0].Value + mask := uint64(1)<<size - 1 + v := v0 & mask + if int64(v<<(64-size)) < 0 && int64(v0) < 0 { + v |= ^mask + } + if v0 != v { + comp.error(args[0].Pos, "const val 0x%x does not fit into %v bits", v0, size) + } + }, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { return &prog.ConstType{ IntTypeCommon: base, @@ -681,7 +699,7 @@ var typeFmt = &typeDesc{ format = prog.FormatStrOct size = 23 } - typ := comp.genType(args[1], "", base.TypeCommon.ArgDir, true) + typ := comp.genType(args[1], "", base.TypeCommon.ArgDir, comp.ptrSize) switch t := typ.(type) { case *prog.ResourceType: t.ArgFormat = format @@ -730,7 +748,7 @@ func init() { baseType = r.Base r = comp.resources[r.Base.Ident] } - baseProgType := comp.genType(baseType, "", prog.DirIn, false) + baseProgType := comp.genType(baseType, "", prog.DirIn, 0) base.TypeSize = baseProgType.Size() return &prog.ResourceType{ TypeCommon: base.TypeCommon, |
