aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-09-29 13:28:03 +0200
committerDmitry Vyukov <dvyukov@google.com>2016-09-29 13:30:08 +0200
commit3ca39dfc4dd8a2dda5b3a9b8c29e295839490af3 (patch)
treed3f4161d07c22e4a08eb0d3edfd61b485ef10579
parentbf21057e7c36c72c1b46aa71bea8dc48509d4c40 (diff)
sys: add padding to structs again
Struct padding was accidentially lost after: 852e3d2eae98a913b7ec91822ba4dc61059a6955 Restore it. Now with tests. Fixes #78
-rw-r--r--prog/encodingexec_test.go26
-rw-r--r--sys/align.go50
-rw-r--r--sys/decl.go47
-rw-r--r--sys/test.txt25
-rw-r--r--sysgen/sysgen.go2
-rw-r--r--sysparser/lexer.go13
6 files changed, 119 insertions, 44 deletions
diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go
index 651352fd6..eddda5199 100644
--- a/prog/encodingexec_test.go
+++ b/prog/encodingexec_test.go
@@ -67,15 +67,26 @@ func TestSerializeForExec(t *testing.T) {
},
},
{
- // TODO: the offsets are currently caclulated incorrectly.
"syz_test$align0(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})",
[]uint64{
instrCopyin, dataOffset + 0, argConst, 2, 1,
+ instrCopyin, dataOffset + 4, argConst, 4, 2,
+ instrCopyin, dataOffset + 8, argConst, 1, 3,
+ instrCopyin, dataOffset + 10, argConst, 2, 4,
+ instrCopyin, dataOffset + 16, argConst, 8, 5,
+ callID("syz_test$align0"), 1, argConst, ptrSize, dataOffset,
+ instrEOF,
+ },
+ },
+ {
+ "syz_test$align1(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})",
+ []uint64{
+ instrCopyin, dataOffset + 0, argConst, 2, 1,
instrCopyin, dataOffset + 2, argConst, 4, 2,
instrCopyin, dataOffset + 6, argConst, 1, 3,
instrCopyin, dataOffset + 7, argConst, 2, 4,
instrCopyin, dataOffset + 9, argConst, 8, 5,
- callID("syz_test$align0"), 1, argConst, ptrSize, dataOffset,
+ callID("syz_test$align1"), 1, argConst, ptrSize, dataOffset,
instrEOF,
},
},
@@ -88,6 +99,17 @@ func TestSerializeForExec(t *testing.T) {
instrEOF,
},
},
+ {
+ "syz_test$array0(&(0x7f0000000000)={0x1, [@f0=0x2, @f1=0x3], 0x4})",
+ []uint64{
+ instrCopyin, dataOffset + 0, argConst, 1, 1,
+ instrCopyin, dataOffset + 1, argConst, 2, 2,
+ instrCopyin, dataOffset + 3, argConst, 8, 3,
+ instrCopyin, dataOffset + 11, argConst, 8, 4,
+ callID("syz_test$array0"), 1, argConst, ptrSize, dataOffset,
+ instrEOF,
+ },
+ },
}
for i, test := range tests {
diff --git a/sys/align.go b/sys/align.go
index 4c91c28be..6e8563da4 100644
--- a/sys/align.go
+++ b/sys/align.go
@@ -3,51 +3,37 @@
package sys
-import (
- "fmt"
-)
-
func initAlign() {
- var rec func(t Type) Type
- rec = func(t Type) Type {
+ var rec func(t Type)
+ rec = func(t Type) {
switch t1 := t.(type) {
case PtrType:
- t1.Type = rec(t1.Type)
- t = t1
+ rec(t1.Type)
case ArrayType:
- t1.Type = rec(t1.Type)
- t = t1
+ rec(t1.Type)
case *StructType:
- for i, f := range t1.Fields {
- t1.Fields[i] = rec(f)
+ if !t1.padded {
+ t1.padded = true
+ for _, f := range t1.Fields {
+ rec(f)
+ }
+ addAlignment(t1)
}
- t = addAlignment(t1)
case *UnionType:
- opts := make(map[string]bool)
- for i, opt := range t1.Options {
- if opts[opt.Name()] {
- panic(fmt.Sprintf("duplicate option %v in union %v", opt.Name(), t.Name()))
- }
- opts[opt.Name()] = true
- t1.Options[i] = rec(opt)
+ for _, opt := range t1.Options {
+ rec(opt)
}
}
- return t
}
- for _, c := range Calls {
- for i, t := range c.Args {
- c.Args[i] = rec(t)
- }
- if c.Ret != nil {
- c.Ret = rec(c.Ret)
- }
+
+ for _, s := range Structs {
+ rec(s)
}
}
-func addAlignment(t *StructType) Type {
+func addAlignment(t *StructType) {
if t.packed {
- t.padded = true
- return t
+ return
}
var fields []Type
var off, align uintptr
@@ -77,8 +63,6 @@ func addAlignment(t *StructType) Type {
fields = append(fields, makePad(pad))
}
t.Fields = fields
- t.padded = true
- return t
}
func makePad(sz uintptr) Type {
diff --git a/sys/decl.go b/sys/decl.go
index 2cc8f22e5..f792f541c 100644
--- a/sys/decl.go
+++ b/sys/decl.go
@@ -252,11 +252,14 @@ type ArrayType struct {
}
func (t ArrayType) Size() uintptr {
- panic("should not be called")
+ if t.RangeBegin == t.RangeEnd {
+ return t.RangeBegin * t.Type.Size()
+ }
+ return 0 // for trailing embed arrays
}
func (t ArrayType) Align() uintptr {
- panic("should not be called")
+ return t.Type.Align()
}
type PtrType struct {
@@ -282,11 +285,27 @@ type StructType struct {
}
func (t *StructType) Size() uintptr {
- panic("not called")
+ if !t.padded {
+ panic("struct is not padded yet")
+ }
+ var size uintptr
+ for _, f := range t.Fields {
+ size += f.Size()
+ }
+ return size
}
func (t *StructType) Align() uintptr {
- panic("not called")
+ if t.align != 0 {
+ return t.align // overrided by user attribute
+ }
+ var align uintptr
+ for _, f := range t.Fields {
+ if a1 := f.Align(); align < a1 {
+ align = a1
+ }
+ }
+ return align
}
type UnionType struct {
@@ -296,11 +315,26 @@ type UnionType struct {
}
func (t *UnionType) Size() uintptr {
- panic("not called")
+ if t.varlen {
+ panic("union size is not statically known")
+ }
+ size := t.Options[0].Size()
+ for _, opt := range t.Options {
+ if size < opt.Size() {
+ size = opt.Size()
+ }
+ }
+ return size
}
func (t *UnionType) Align() uintptr {
- panic("not called")
+ var align uintptr
+ for _, opt := range t.Options {
+ if a1 := opt.Align(); align < a1 {
+ align = a1
+ }
+ }
+ return align
}
type Dir int
@@ -503,6 +537,7 @@ var (
func init() {
initCalls()
+ initStructFields()
initResources()
initAlign()
diff --git a/sys/test.txt b/sys/test.txt
index 2fc41e677..a01c6b3c2 100644
--- a/sys/test.txt
+++ b/sys/test.txt
@@ -15,6 +15,7 @@ syz_test$opt2(a0 vma[opt])
# Struct alignment.
syz_test$align0(a0 ptr[in, syz_align0])
+syz_test$align1(a0 ptr[in, syz_align1])
syz_align0 {
f0 int16
@@ -24,6 +25,14 @@ syz_align0 {
f4 int64
}
+syz_align1 {
+ f0 int16
+ f1 int32
+ f2 int8
+ f3 int16
+ f4 int64
+} [packed]
+
# Unions.
syz_test$union0(a0 ptr[in, syz_union_struct])
@@ -38,3 +47,19 @@ syz_union0 [
f1 array[int64, 10]
f2 int8
]
+
+# Arrays.
+
+syz_test$array0(a0 ptr[in, syz_array_struct])
+
+# Struct with a variable-length array or variable-length unions.
+syz_array_struct {
+ f0 int8
+ f1 array[syz_array_union, 1:2]
+ f2 int64
+} [packed]
+
+syz_array_union [
+ f0 int16
+ f1 int64
+] [varlen]
diff --git a/sysgen/sysgen.go b/sysgen/sysgen.go
index e7a0fae00..c27e413c3 100644
--- a/sysgen/sysgen.go
+++ b/sysgen/sysgen.go
@@ -283,7 +283,7 @@ func generateStructs(desc *Description, consts map[string]uint64, out io.Writer)
}
fmt.Fprintf(out, "}\n")
- fmt.Fprintf(out, "func init() {\n")
+ fmt.Fprintf(out, "func initStructFields() {\n")
for _, str := range structArray {
typ := "StructType"
fields := "Fields"
diff --git a/sysparser/lexer.go b/sysparser/lexer.go
index 21c7b77ef..85f657d41 100644
--- a/sysparser/lexer.go
+++ b/sysparser/lexer.go
@@ -86,8 +86,17 @@ func Parse(in io.Reader) *Description {
}
}
}
- if str.IsUnion && len(str.Flds) <= 1 {
- failf("union %v has only %v fields, need at least 2", str.Name, len(str.Flds))
+ if str.IsUnion {
+ if len(str.Flds) <= 1 {
+ failf("union %v has only %v fields, need at least 2", str.Name, len(str.Flds))
+ }
+ fields := make(map[string]bool)
+ for _, f := range str.Flds {
+ if fields[f[0]] {
+ failf("duplicate filed %v in struct/union %v", f[0], str.Name)
+ }
+ fields[f[0]] = true
+ }
}
structs[str.Name] = *str
str = nil