From 3ca39dfc4dd8a2dda5b3a9b8c29e295839490af3 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 29 Sep 2016 13:28:03 +0200 Subject: sys: add padding to structs again Struct padding was accidentially lost after: 852e3d2eae98a913b7ec91822ba4dc61059a6955 Restore it. Now with tests. Fixes #78 --- prog/encodingexec_test.go | 26 ++++++++++++++++++++++-- sys/align.go | 50 ++++++++++++++++------------------------------- sys/decl.go | 47 ++++++++++++++++++++++++++++++++++++++------ sys/test.txt | 25 ++++++++++++++++++++++++ sysgen/sysgen.go | 2 +- sysparser/lexer.go | 13 ++++++++++-- 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 -- cgit mrf-deployment