diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2025-01-17 10:39:49 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2025-01-20 13:30:27 +0000 |
| commit | 6e87cfa299c98d36e79e8b8718a4126899a3ba2f (patch) | |
| tree | 471099bb5efb7421704429e59a2e2134bde2842b /pkg/compiler | |
| parent | 520f8c5e11ccf2569cdfb02597c3782ce0760b90 (diff) | |
pkg/compiler: fix struct layout bug
Currently we have a bug in struct layout that affects
some corner cases that involve recursive structs.
The result of this bug is that we use wrong alignment 1
(not yet calculated) for some structs when calculating
layout of other structs.
The root cause of this bug is that we calculate struct
alignment too early in typeStruct.Gen when structs
are not yet laid out.
For this reason we moved struct size calculation to the
later phase (after compiler.layoutStruct).
Move alignment calculation from typeStruct.Gen to
compiler.layoutStruct to fix this.
Diffstat (limited to 'pkg/compiler')
| -rw-r--r-- | pkg/compiler/gen.go | 13 | ||||
| -rw-r--r-- | pkg/compiler/types.go | 17 |
2 files changed, 15 insertions, 15 deletions
diff --git a/pkg/compiler/gen.go b/pkg/compiler/gen.go index 81e8f83bc..688dd7013 100644 --- a/pkg/compiler/gen.go +++ b/pkg/compiler/gen.go @@ -264,9 +264,13 @@ func (comp *compiler) layoutArray(t *prog.ArrayType) { if t.Kind == prog.ArrayRangeLen && t.RangeBegin == t.RangeEnd && !t.Elem.Varlen() { t.TypeSize = t.RangeBegin * t.Elem.Size() } + t.TypeAlign = t.Elem.Alignment() } func (comp *compiler) layoutUnion(t *prog.UnionType) { + for _, fld := range t.Fields { + t.TypeAlign = max(t.TypeAlign, fld.Alignment()) + } t.TypeSize = 0 structNode := comp.structs[t.TypeName] if structNode == conditionalFieldWrapper { @@ -303,6 +307,15 @@ func (comp *compiler) layoutStruct(t *prog.StructType) { attrs := comp.parseIntAttrs(structAttrs, structNode, structNode.Attrs) t.AlignAttr = attrs[attrAlign] comp.layoutStructFields(t, varlen, attrs[attrPacked] != 0) + if align := attrs[attrAlign]; align != 0 { + t.TypeAlign = align + } else if attrs[attrPacked] != 0 { + t.TypeAlign = 1 + } else { + for _, f := range t.Fields { + t.TypeAlign = max(t.TypeAlign, f.Alignment()) + } + } t.TypeSize = 0 if !varlen { var size uint64 diff --git a/pkg/compiler/types.go b/pkg/compiler/types.go index ae0864725..e022efafe 100644 --- a/pkg/compiler/types.go +++ b/pkg/compiler/types.go @@ -358,8 +358,7 @@ var typeArray = &typeDesc{ NoZ: true, } } - // TypeSize is assigned later in layoutArray. - base.TypeAlign = elemType.Alignment() + // TypeSize/TypeAlign are assigned later in layoutArray. return &prog.ArrayType{ TypeCommon: base.TypeCommon, Elem: elemType, @@ -1006,9 +1005,6 @@ func init() { switch typ1 := typ.(type) { case *prog.UnionType: typ1.Fields = fields - for _, f := range fields { - typ1.TypeAlign = max(typ1.TypeAlign, f.Type.Alignment()) - } case *prog.StructType: typ1.Fields = fields for i, field := range fields { @@ -1019,17 +1015,8 @@ func init() { if overlayField >= 0 { typ1.OverlayField = overlayField } - attrs := comp.parseIntAttrs(structAttrs, s, s.Attrs) - if align := attrs[attrAlign]; align != 0 { - typ1.TypeAlign = align - } else if attrs[attrPacked] != 0 { - typ1.TypeAlign = 1 - } else { - for _, f := range fields { - typ1.TypeAlign = max(typ1.TypeAlign, f.Type.Alignment()) - } - } } + // TypeSize/TypeAlign are assigned later in layoutStruct. return typ } } |
