aboutsummaryrefslogtreecommitdiffstats
path: root/sys
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 /sys
parentbf21057e7c36c72c1b46aa71bea8dc48509d4c40 (diff)
sys: add padding to structs again
Struct padding was accidentially lost after: 852e3d2eae98a913b7ec91822ba4dc61059a6955 Restore it. Now with tests. Fixes #78
Diffstat (limited to 'sys')
-rw-r--r--sys/align.go50
-rw-r--r--sys/decl.go47
-rw-r--r--sys/test.txt25
3 files changed, 83 insertions, 39 deletions
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]