From 023345d694751261b64f84fde0820982f1e3c2fa Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Wed, 18 Jan 2017 13:07:21 +0100 Subject: prog, sys: correctly calculate size of varlen structs --- sys/align.go | 40 ++++++++++++++++++++++++++++------------ sys/decl.go | 1 + 2 files changed, 29 insertions(+), 12 deletions(-) (limited to 'sys') 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 -- cgit mrf-deployment