aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-03-17 14:32:13 +0100
committerDmitry Vyukov <dvyukov@google.com>2020-03-17 21:19:13 +0100
commit2e9037c55f6a3308190ab4eb0ce110dddc7a6f2b (patch)
tree7f97740e9d496a53a990d88a41405e67b8d4af44 /pkg
parent0bcbb36f9fff81ac0bff9ec0959b9ea4c444a700 (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')
-rw-r--r--pkg/compiler/gen.go66
-rw-r--r--pkg/compiler/testdata/errors2.txt4
-rw-r--r--pkg/compiler/testdata/errors3.txt3
-rw-r--r--pkg/compiler/types.go26
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,