aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-03-02 15:44:54 +0100
committerDmitry Vyukov <dvyukov@google.com>2018-03-05 12:10:27 +0100
commit5ef8dbdf5a63ccf7e069527dbb2493dc2ef0c319 (patch)
tree25f38d85ac74951764770ed777033ee8ed9ac542
parenta339951e5f3c045290340330bcea3ff4155b8334 (diff)
pkg/compiler: support size attribute for unions
-rw-r--r--executor/syscalls_test.h10
-rw-r--r--pkg/compiler/check.go9
-rw-r--r--pkg/compiler/compiler.go50
-rw-r--r--pkg/compiler/consts.go4
-rw-r--r--pkg/compiler/gen.go16
-rw-r--r--pkg/compiler/testdata/errors2.txt8
-rw-r--r--prog/size_test.go4
-rw-r--r--sys/test/32.go9
-rw-r--r--sys/test/64.go9
-rw-r--r--sys/test/test.txt5
10 files changed, 89 insertions, 35 deletions
diff --git a/executor/syscalls_test.h b/executor/syscalls_test.h
index 9468387e1..d5be16213 100644
--- a/executor/syscalls_test.h
+++ b/executor/syscalls_test.h
@@ -2,11 +2,11 @@
#if 0
#define GOARCH "32"
-#define SYZ_REVISION "035aa7331fff3c8bb13bc8925ae43befcbc94a71"
+#define SYZ_REVISION "d4cbc2aec52e291fefa8155c6c6ca397ba3c9e49"
#define SYZ_PAGE_SIZE 8192
#define SYZ_NUM_PAGES 2048
#define SYZ_DATA_OFFSET 536870912
-unsigned syscall_count = 91;
+unsigned syscall_count = 92;
call_t syscalls[] = {
{"foo$any0", 0, (syscall_t)foo},
{"foo$anyres", 0, (syscall_t)foo},
@@ -68,6 +68,7 @@ call_t syscalls[] = {
{"syz_test$length25", 0, (syscall_t)syz_test},
{"syz_test$length26", 0, (syscall_t)syz_test},
{"syz_test$length27", 0, (syscall_t)syz_test},
+ {"syz_test$length28", 0, (syscall_t)syz_test},
{"syz_test$length3", 0, (syscall_t)syz_test},
{"syz_test$length4", 0, (syscall_t)syz_test},
{"syz_test$length5", 0, (syscall_t)syz_test},
@@ -105,11 +106,11 @@ call_t syscalls[] = {
#if 0
#define GOARCH "64"
-#define SYZ_REVISION "7106e9ab2b7a52203a8ad681140f3326e8b3d7ce"
+#define SYZ_REVISION "cabe73c3b49273a8b0cd13bff35d40897dd88138"
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
-unsigned syscall_count = 91;
+unsigned syscall_count = 92;
call_t syscalls[] = {
{"foo$any0", 0, (syscall_t)foo},
{"foo$anyres", 0, (syscall_t)foo},
@@ -171,6 +172,7 @@ call_t syscalls[] = {
{"syz_test$length25", 0, (syscall_t)syz_test},
{"syz_test$length26", 0, (syscall_t)syz_test},
{"syz_test$length27", 0, (syscall_t)syz_test},
+ {"syz_test$length28", 0, (syscall_t)syz_test},
{"syz_test$length3", 0, (syscall_t)syz_test},
{"syz_test$length4", 0, (syscall_t)syz_test},
{"syz_test$length5", 0, (syscall_t)syz_test},
diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go
index 2a6afae3a..4dac37260 100644
--- a/pkg/compiler/check.go
+++ b/pkg/compiler/check.go
@@ -240,10 +240,11 @@ func (comp *compiler) checkAttributeValues() {
switch n := decl.(type) {
case *ast.Struct:
for _, attr := range n.Attrs {
- if !n.IsUnion && attr.Ident == "size" {
+ if attr.Ident == "size" {
+ _, typ, name := n.Info()
if comp.structIsVarlen(n.Name.Name) {
- comp.error(attr.Pos, "varlen struct %v has size attribute",
- n.Name.Name)
+ comp.error(attr.Pos, "varlen %v %v has size attribute",
+ typ, name)
}
sz := attr.Args[0].Value
if sz == 0 || sz > 1<<20 {
@@ -906,7 +907,7 @@ func (comp *compiler) checkVarlen(n *ast.Struct) {
// Non-varlen unions can't have varlen fields.
// Non-packed structs can't have varlen fields in the middle.
if n.IsUnion {
- if varlen := comp.parseUnionAttrs(n); varlen {
+ if varlen, _ := comp.parseUnionAttrs(n); varlen {
return
}
} else {
diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go
index 314cbef41..f0d1176e7 100644
--- a/pkg/compiler/compiler.go
+++ b/pkg/compiler/compiler.go
@@ -145,9 +145,11 @@ func (comp *compiler) structIsVarlen(name string) bool {
return varlen
}
s := comp.structs[name]
- if s.IsUnion && comp.parseUnionAttrs(s) {
- comp.structVarlen[name] = true
- return true
+ if s.IsUnion {
+ if varlen, _ := comp.parseUnionAttrs(s); varlen {
+ comp.structVarlen[name] = true
+ return true
+ }
}
comp.structVarlen[name] = false // to not hang on recursive types
varlen := false
@@ -161,18 +163,21 @@ func (comp *compiler) structIsVarlen(name string) bool {
return varlen
}
-func (comp *compiler) parseUnionAttrs(n *ast.Struct) (varlen bool) {
+func (comp *compiler) parseUnionAttrs(n *ast.Struct) (varlen bool, size uint64) {
+ size = sizeUnassigned
for _, attr := range n.Attrs {
switch attr.Ident {
case "varlen":
+ if len(attr.Args) != 0 {
+ comp.error(attr.Pos, "%v attribute has args", attr.Ident)
+ }
varlen = true
+ case "size":
+ size = comp.parseSizeAttr(n, attr)
default:
comp.error(attr.Pos, "unknown union %v attribute %v",
n.Name.Name, attr.Ident)
}
- if len(attr.Args) != 0 {
- comp.error(attr.Pos, "%v attribute has args", attr.Ident)
- }
}
return
}
@@ -207,19 +212,7 @@ func (comp *compiler) parseStructAttrs(n *ast.Struct) (packed bool, size, align
}
align = a
case attr.Ident == "size":
- if len(attr.Args) != 1 {
- comp.error(attr.Pos, "%v attribute is expected to have 1 argument", attr.Ident)
- }
- sz := attr.Args[0]
- if unexpected, _, ok := checkTypeKind(sz, kindInt); !ok {
- comp.error(sz.Pos, "unexpected %v, expect int", unexpected)
- return
- }
- if sz.HasColon || len(sz.Args) != 0 {
- comp.error(sz.Pos, "size attribute has colon or args")
- return
- }
- size = sz.Value
+ size = comp.parseSizeAttr(n, attr)
default:
comp.error(attr.Pos, "unknown struct %v attribute %v",
n.Name.Name, attr.Ident)
@@ -228,6 +221,23 @@ func (comp *compiler) parseStructAttrs(n *ast.Struct) (packed bool, size, align
return
}
+func (comp *compiler) parseSizeAttr(n *ast.Struct, attr *ast.Type) uint64 {
+ if len(attr.Args) != 1 {
+ comp.error(attr.Pos, "%v attribute is expected to have 1 argument", attr.Ident)
+ return sizeUnassigned
+ }
+ sz := attr.Args[0]
+ if unexpected, _, ok := checkTypeKind(sz, kindInt); !ok {
+ comp.error(sz.Pos, "unexpected %v, expect int", unexpected)
+ return sizeUnassigned
+ }
+ if sz.HasColon || len(sz.Args) != 0 {
+ comp.error(sz.Pos, "size attribute has colon or args")
+ return sizeUnassigned
+ }
+ return sz.Value
+}
+
func (comp *compiler) getTypeDesc(t *ast.Type) *typeDesc {
if desc := builtinTypes[t.Ident]; desc != nil {
return desc
diff --git a/pkg/compiler/consts.go b/pkg/compiler/consts.go
index 789674578..1b008bd4f 100644
--- a/pkg/compiler/consts.go
+++ b/pkg/compiler/consts.go
@@ -87,7 +87,7 @@ func (comp *compiler) extractConsts() map[string]*ConstInfo {
switch n := decl.(type) {
case *ast.Struct:
for _, attr := range n.Attrs {
- if !n.IsUnion && attr.Ident == "size" {
+ if attr.Ident == "size" {
info := getConstInfo(infos, attr.Pos)
info.consts[attr.Args[0].Ident] = true
}
@@ -199,7 +199,7 @@ func (comp *compiler) patchConsts(consts map[string]uint64) {
}
if n, ok := decl.(*ast.Struct); ok {
for _, attr := range n.Attrs {
- if !n.IsUnion && attr.Ident == "size" {
+ if attr.Ident == "size" {
sz := attr.Args[0]
comp.patchIntConst(sz.Pos, &sz.Value,
&sz.Ident, consts, &missing)
diff --git a/pkg/compiler/gen.go b/pkg/compiler/gen.go
index 74d1b5d78..5bf239e79 100644
--- a/pkg/compiler/gen.go
+++ b/pkg/compiler/gen.go
@@ -165,14 +165,24 @@ func (comp *compiler) genStructDescs(syscalls []*prog.Syscall) []*prog.KeyedStru
if !checkStruct(t.Key, &t.StructDesc) {
return
}
+ structNode := comp.structNodes[t.StructDesc]
+ varlen, sizeAttr := comp.parseUnionAttrs(structNode)
t.TypeSize = 0
- varlen := comp.parseUnionAttrs(comp.structNodes[t.StructDesc])
if !varlen {
for _, fld := range t.Fields {
- if t.TypeSize < fld.Size() {
- t.TypeSize = fld.Size()
+ sz := fld.Size()
+ if sizeAttr != sizeUnassigned && sz > sizeAttr {
+ comp.error(structNode.Pos, "union %v has size attribute %v"+
+ " which is less than field %v size %v",
+ structNode.Name.Name, sizeAttr, fld.Name(), sz)
+ }
+ if t.TypeSize < sz {
+ t.TypeSize = sz
}
}
+ if sizeAttr != sizeUnassigned {
+ t.TypeSize = sizeAttr
+ }
}
}
}
diff --git a/pkg/compiler/testdata/errors2.txt b/pkg/compiler/testdata/errors2.txt
index a8d29789a..86148a563 100644
--- a/pkg/compiler/testdata/errors2.txt
+++ b/pkg/compiler/testdata/errors2.txt
@@ -91,6 +91,14 @@ u1 [
f2 len[f1, int32] ### len target f1 does not exist
]
+u2 [
+ f1 int8
+] [size[0]] ### size attribute has bad value 0, expect [1, 1<<20]
+
+u3 [
+ f1 int8
+] [varlen, size[8]] ### varlen union u3 has size attribute
+
foo$200(a ptr[in, s2])
foo$201(a ptr[in, s1])
foo$202(a u1)
diff --git a/prog/size_test.go b/prog/size_test.go
index f5ac9a958..08b7cba92 100644
--- a/prog/size_test.go
+++ b/prog/size_test.go
@@ -142,6 +142,10 @@ func TestAssignSize(t *testing.T) {
"syz_test$length27(&(0x7f0000000000), 0x0)",
"syz_test$length27(&(0x7f0000000000), 0x2a)",
},
+ {
+ "syz_test$length28(&(0x7f0000000000), 0x0)",
+ "syz_test$length28(&(0x7f0000000000)=@f1, 0x2a)",
+ },
}
for i, test := range tests {
diff --git a/sys/test/32.go b/sys/test/32.go
index 2afb57717..7425c8bd9 100644
--- a/sys/test/32.go
+++ b/sys/test/32.go
@@ -54,6 +54,9 @@ var structDescs_32 = []*KeyedStruct{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "f1", TypeSize: 1}}},
&ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 41}}, IsPad: true},
}}},
+ {Key: StructKey{Name: "explicitly_sized_union"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "explicitly_sized_union", TypeSize: 42}, Fields: []Type{
+ &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "f1", TypeSize: 1}}},
+ }}},
{Key: StructKey{Name: "len_nontemp4"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "len_nontemp4", TypeSize: 4}, Fields: []Type{
&LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "f1", TypeSize: 4}}, Buf: "len_temp3"},
}}},
@@ -683,6 +686,10 @@ var syscalls_32 = []*Syscall{
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 4}, Type: &StructType{Key: StructKey{Name: "explicitly_sized"}}},
&LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "a1", TypeSize: 4}}, Buf: "a0"},
}},
+ {Name: "syz_test$length28", CallName: "syz_test", Args: []Type{
+ &PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 4}, Type: &UnionType{Key: StructKey{Name: "explicitly_sized_union"}}},
+ &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "a1", TypeSize: 4}}, Buf: "a0"},
+ }},
{Name: "syz_test$length3", CallName: "syz_test", Args: []Type{
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 4}, Type: &StructType{Key: StructKey{Name: "syz_length_len_struct"}}},
}},
@@ -790,4 +797,4 @@ var consts_32 = []ConstValue{
{Name: "ONLY_32BITS_CONST", Value: 1},
}
-const revision_32 = "035aa7331fff3c8bb13bc8925ae43befcbc94a71"
+const revision_32 = "d4cbc2aec52e291fefa8155c6c6ca397ba3c9e49"
diff --git a/sys/test/64.go b/sys/test/64.go
index ac32ebbe8..4b48d9b05 100644
--- a/sys/test/64.go
+++ b/sys/test/64.go
@@ -54,6 +54,9 @@ var structDescs_64 = []*KeyedStruct{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "f1", TypeSize: 1}}},
&ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 41}}, IsPad: true},
}}},
+ {Key: StructKey{Name: "explicitly_sized_union"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "explicitly_sized_union", TypeSize: 42}, Fields: []Type{
+ &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "f1", TypeSize: 1}}},
+ }}},
{Key: StructKey{Name: "len_nontemp4"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "len_nontemp4", TypeSize: 4}, Fields: []Type{
&LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "f1", TypeSize: 4}}, Buf: "len_temp3"},
}}},
@@ -682,6 +685,10 @@ var syscalls_64 = []*Syscall{
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 8}, Type: &StructType{Key: StructKey{Name: "explicitly_sized"}}},
&LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "a1", TypeSize: 8}}, Buf: "a0"},
}},
+ {Name: "syz_test$length28", CallName: "syz_test", Args: []Type{
+ &PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 8}, Type: &UnionType{Key: StructKey{Name: "explicitly_sized_union"}}},
+ &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "a1", TypeSize: 8}}, Buf: "a0"},
+ }},
{Name: "syz_test$length3", CallName: "syz_test", Args: []Type{
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 8}, Type: &StructType{Key: StructKey{Name: "syz_length_len_struct"}}},
}},
@@ -788,4 +795,4 @@ var consts_64 = []ConstValue{
{Name: "IPPROTO_UDP", Value: 17},
}
-const revision_64 = "7106e9ab2b7a52203a8ad681140f3326e8b3d7ce"
+const revision_64 = "cabe73c3b49273a8b0cd13bff35d40897dd88138"
diff --git a/sys/test/test.txt b/sys/test/test.txt
index 063a9a2e2..ca548d073 100644
--- a/sys/test/test.txt
+++ b/sys/test/test.txt
@@ -405,10 +405,15 @@ explicitly_sized {
f1 int8
} [size[42]]
+explicitly_sized_union [
+ f1 int8
+] [size[42]]
+
syz_test$length24(a ptr[in, len_nontemp5])
syz_test$length25(a0 ptr[in, array[array[int8]]], a1 len[a0])
syz_test$length26(a ptr[in, len_unaligned], b bytesize[a])
syz_test$length27(a0 ptr[in, explicitly_sized], a1 len[a0])
+syz_test$length28(a0 ptr[in, explicitly_sized_union], a1 len[a0])
# Big endian