aboutsummaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorAndrey Konovalov <andreyknvl@google.com>2017-01-18 13:07:21 +0100
committerAndrey Konovalov <andreyknvl@google.com>2017-01-18 19:16:11 +0100
commit023345d694751261b64f84fde0820982f1e3c2fa (patch)
tree0fda9eea2ee208f54daa1e8ef81fe0ed068568c8 /sys
parent109c58ef682799fc7e92d7a74a9c3073f1ccd0ec (diff)
prog, sys: correctly calculate size of varlen structs
Diffstat (limited to 'sys')
-rw-r--r--sys/align.go40
-rw-r--r--sys/decl.go1
2 files changed, 29 insertions, 12 deletions
diff --git a/sys/align.go b/sys/align.go
index be0cbb3c4..3c672b83e 100644
--- a/sys/align.go
+++ b/sys/align.go
@@ -22,6 +22,7 @@ func initAlign() {
rec(f)
}
markBitfields(t1)
+ markVarlen(t1)
addAlignment(t1)
}
case *UnionType:
@@ -76,14 +77,38 @@ func markBitfields(t *StructType) {
}
}
+func markVarlen(t *StructType) {
+ for i, f := range t.Fields {
+ if at, ok := f.(*StructType); ok && at.Varlen {
+ t.Varlen = true
+ }
+ if at, ok := f.(*UnionType); ok && at.Varlen {
+ t.Varlen = true
+ }
+ if at, ok := f.(*ArrayType); ok && (at.Kind == ArrayRandLen || (at.Kind == ArrayRangeLen && at.RangeBegin != at.RangeEnd)) {
+ t.Varlen = true
+ }
+ if at, ok := f.(*BufferType); ok && (at.Kind == BufferBlobRand || (at.Kind == BufferBlobRange && at.RangeBegin != at.RangeEnd)) {
+ t.Varlen = true
+ }
+ if !t.packed && t.Varlen && i != len(t.Fields)-1 {
+ panic(fmt.Sprintf("variable length field %+v in the middle of a struct %+v", f, t))
+ }
+ }
+}
+
func addAlignment(t *StructType) {
if t.packed {
+ // If a struct is packed, statically sized and has explicitly set alignment, add a padding.
+ if !t.Varlen && t.align != 0 && t.Size()%t.align != 0 {
+ pad := t.align - t.Size()%t.align
+ t.Fields = append(t.Fields, makePad(pad))
+ }
return
}
var fields []Type
var off uintptr
align := t.align
- varLen := false
for i, f := range t.Fields {
a := f.Align()
if align < a {
@@ -98,21 +123,12 @@ func addAlignment(t *StructType) {
}
}
fields = append(fields, f)
- if at, ok := f.(*ArrayType); ok && (at.Kind == ArrayRandLen || (at.Kind == ArrayRangeLen && at.RangeBegin != at.RangeEnd)) {
- varLen = true
- }
- if at, ok := f.(*BufferType); ok && (at.Kind == BufferBlobRand || (at.Kind == BufferBlobRange && at.RangeBegin != at.RangeEnd)) {
- varLen = true
- }
- if varLen && i != len(t.Fields)-1 {
- panic("embed array in middle of a struct")
- }
- if (f.BitfieldLength() == 0 || f.BitfieldLast()) && !varLen {
+ if (f.BitfieldLength() == 0 || f.BitfieldLast()) && !t.Varlen {
// Increase offset if the current field is not a bitfield or it's the last bitfield in a set.
off += f.Size()
}
}
- if align != 0 && off%align != 0 && !varLen {
+ if align != 0 && off%align != 0 && !t.Varlen {
pad := align - off%align
off += pad
fields = append(fields, makePad(pad))
diff --git a/sys/decl.go b/sys/decl.go
index 94d05e0c3..08df93dd2 100644
--- a/sys/decl.go
+++ b/sys/decl.go
@@ -293,6 +293,7 @@ func (t *PtrType) Align() uintptr {
type StructType struct {
TypeCommon
Fields []Type
+ Varlen bool
padded bool
packed bool
align uintptr