diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2020-04-25 15:05:19 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2020-05-05 14:01:52 +0200 |
| commit | 4b76dd258977f4bc9b8a1996680f8b9fd96713d2 (patch) | |
| tree | 5de611ae32f2f137053888d73bf81b40feaf59b1 /prog | |
| parent | 8cbfd71747917061fa744c07972ba65a7f73a236 (diff) | |
prog: use Ref as Arg type
Use Ref in Arg instead of full Type interface.
This reduces size of all args. In partiuclar the most common
ConstArg is reduces from 32 bytes to 16 and now does not
contain any pointers (better for GC).
Running syz-db bench on a beefy corpus: before:
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.704699958s
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.873792394s
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.820479906s
after:
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1023 MB, live allocs 379 MB (8 M), time 8.938939937s
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1087 MB, live allocs 379 MB (8 M), time 9.410243167s
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1023 MB, live allocs 379 MB (8 M), time 9.38225806s
Max heap and live heap are reduced by 20%.
Update #1580
Diffstat (limited to 'prog')
| -rw-r--r-- | prog/any.go | 19 | ||||
| -rw-r--r-- | prog/prog.go | 35 | ||||
| -rw-r--r-- | prog/rand.go | 2 | ||||
| -rw-r--r-- | prog/target.go | 28 | ||||
| -rw-r--r-- | prog/types.go | 17 |
5 files changed, 72 insertions, 29 deletions
diff --git a/prog/any.go b/prog/any.go index 7bf38b6be..bb80eaa38 100644 --- a/prog/any.go +++ b/prog/any.go @@ -135,8 +135,9 @@ func (target *Target) squashPtr(arg *PointerArg) { size0 := res0.Size() var elems []Arg target.squashPtrImpl(arg.Res, &elems) - arg.typ = target.getAnyPtrType(arg.Type().Size()) - arg.Res = MakeGroupArg(arg.typ.(*PtrType).Elem, DirIn, elems) + newType := target.getAnyPtrType(arg.Type().Size()) + arg.ref = newType.ref() + arg.Res = MakeGroupArg(newType.Elem, DirIn, elems) if size := arg.Res.Size(); size != size0 { panic(fmt.Sprintf("squash changed size %v->%v for %v", size0, size, res0.Type())) } @@ -206,28 +207,30 @@ func (target *Target) squashConst(arg *ConstArg, elems *[]Arg) { } func (target *Target) squashResult(arg *ResultArg, elems *[]Arg) { + var typ *ResourceType index := -1 switch arg.Type().Format() { case FormatNative, FormatBigEndian: switch arg.Size() { case 2: - arg.typ, index = target.any.res16, 1 + typ, index = target.any.res16, 1 case 4: - arg.typ, index = target.any.res32, 2 + typ, index = target.any.res32, 2 case 8: - arg.typ, index = target.any.res64, 3 + typ, index = target.any.res64, 3 default: panic("bad size") } case FormatStrDec: - arg.typ, index = target.any.resdec, 4 + typ, index = target.any.resdec, 4 case FormatStrHex: - arg.typ, index = target.any.reshex, 5 + typ, index = target.any.reshex, 5 case FormatStrOct: - arg.typ, index = target.any.resoct, 6 + typ, index = target.any.resoct, 6 default: panic("bad") } + arg.ref = typ.ref() arg.dir = DirIn *elems = append(*elems, MakeUnionArg(target.any.union, DirIn, arg, index)) } diff --git a/prog/prog.go b/prog/prog.go index 00e290175..3e46e15ea 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -30,12 +30,15 @@ type Arg interface { } type ArgCommon struct { - typ Type + ref Ref dir Dir } -func (arg *ArgCommon) Type() Type { - return arg.typ +func (arg ArgCommon) Type() Type { + if arg.ref == 0 { + panic("broken type ref") + } + return typeRefs.Load().([]Type)[arg.ref] } func (arg *ArgCommon) Dir() Dir { @@ -49,11 +52,11 @@ type ConstArg struct { } func MakeConstArg(t Type, dir Dir, v uint64) *ConstArg { - return &ConstArg{ArgCommon: ArgCommon{typ: t, dir: dir}, Val: v} + return &ConstArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Val: v} } func (arg *ConstArg) Size() uint64 { - return arg.typ.Size() + return arg.Type().Size() } // Value returns value and pid stride. @@ -95,7 +98,7 @@ func MakePointerArg(t Type, dir Dir, addr uint64, data Arg) *PointerArg { panic("nil pointer data arg") } return &PointerArg{ - ArgCommon: ArgCommon{typ: t, dir: DirIn}, // pointers are always in + ArgCommon: ArgCommon{ref: t.ref(), dir: DirIn}, // pointers are always in Address: addr, Res: data, } @@ -106,7 +109,7 @@ func MakeVmaPointerArg(t Type, dir Dir, addr, size uint64) *PointerArg { panic("unaligned vma address") } return &PointerArg{ - ArgCommon: ArgCommon{typ: t, dir: dir}, + ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Address: addr, VmaSize: size, } @@ -120,13 +123,13 @@ func MakeSpecialPointerArg(t Type, dir Dir, index uint64) *PointerArg { dir = DirIn // pointers are always in } return &PointerArg{ - ArgCommon: ArgCommon{typ: t, dir: dir}, + ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Address: -index, } } func (arg *PointerArg) Size() uint64 { - return arg.typ.Size() + return arg.Type().Size() } func (arg *PointerArg) IsSpecial() bool { @@ -151,14 +154,14 @@ func MakeDataArg(t Type, dir Dir, data []byte) *DataArg { if dir == DirOut { panic("non-empty output data arg") } - return &DataArg{ArgCommon: ArgCommon{typ: t, dir: dir}, data: append([]byte{}, data...)} + return &DataArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, data: append([]byte{}, data...)} } func MakeOutDataArg(t Type, dir Dir, size uint64) *DataArg { if dir != DirOut { panic("empty input data arg") } - return &DataArg{ArgCommon: ArgCommon{typ: t, dir: dir}, size: size} + return &DataArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, size: size} } func (arg *DataArg) Size() uint64 { @@ -190,7 +193,7 @@ type GroupArg struct { } func MakeGroupArg(t Type, dir Dir, inner []Arg) *GroupArg { - return &GroupArg{ArgCommon: ArgCommon{typ: t, dir: dir}, Inner: inner} + return &GroupArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Inner: inner} } func (arg *GroupArg) Size() uint64 { @@ -238,7 +241,7 @@ type UnionArg struct { } func MakeUnionArg(t Type, dir Dir, opt Arg, index int) *UnionArg { - return &UnionArg{ArgCommon: ArgCommon{typ: t, dir: dir}, Option: opt, Index: index} + return &UnionArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Option: opt, Index: index} } func (arg *UnionArg) Size() uint64 { @@ -261,7 +264,7 @@ type ResultArg struct { } func MakeResultArg(t Type, dir Dir, r *ResultArg, v uint64) *ResultArg { - arg := &ResultArg{ArgCommon: ArgCommon{typ: t, dir: dir}, Res: r, Val: v} + arg := &ResultArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Res: r, Val: v} if r == nil { return arg } @@ -276,11 +279,11 @@ func MakeReturnArg(t Type) *ResultArg { if t == nil { return nil } - return &ResultArg{ArgCommon: ArgCommon{typ: t, dir: DirOut}} + return &ResultArg{ArgCommon: ArgCommon{ref: t.ref(), dir: DirOut}} } func (arg *ResultArg) Size() uint64 { - return arg.typ.Size() + return arg.Type().Size() } // Returns inner arg for pointer args. diff --git a/prog/rand.go b/prog/rand.go index 18c86d77a..019745161 100644 --- a/prog/rand.go +++ b/prog/rand.go @@ -901,7 +901,7 @@ func getCompatibleResources(p *Prog, resourceType string, r *randGen) (resources if !ok || len(a.uses) == 0 || a.Dir() != DirOut { return } - if !r.target.isCompatibleResource(resourceType, a.typ.Name()) { + if !r.target.isCompatibleResource(resourceType, a.Type().Name()) { return } resources = append(resources, a) diff --git a/prog/target.go b/prog/target.go index 630fb7cbf..f19ed3fa2 100644 --- a/prog/target.go +++ b/prog/target.go @@ -8,6 +8,7 @@ import ( "math/rand" "sort" "sync" + "sync/atomic" ) // Target describes target OS/arch pair. @@ -182,16 +183,35 @@ func RestoreLinks(syscalls []*Syscall, resources []*ResourceDesc, types []Type) restoreLinks(syscalls, resources, types) } +var ( + typeRefMu sync.Mutex + typeRefs atomic.Value // []Type +) + func restoreLinks(syscalls []*Syscall, resources []*ResourceDesc, types []Type) map[string]*ResourceDesc { + typeRefMu.Lock() + defer typeRefMu.Unlock() + refs := []Type{nil} + if old := typeRefs.Load(); old != nil { + refs = old.([]Type) + } + for _, typ := range types { + typ.setRef(Ref(len(refs))) + refs = append(refs, typ) + } + typeRefs.Store(refs) + resourceMap := make(map[string]*ResourceDesc) for _, res := range resources { resourceMap[res.Name] = res } - ForeachType(syscalls, func(_ Type, ctx TypeCtx) { - if ref, ok := (*ctx.Ptr).(Ref); ok { - *ctx.Ptr = types[ref] + + ForeachType(syscalls, func(typ Type, ctx TypeCtx) { + if ref, ok := typ.(Ref); ok { + typ = types[ref] + *ctx.Ptr = typ } - switch t := (*ctx.Ptr).(type) { + switch t := typ.(type) { case *ResourceType: t.Desc = resourceMap[t.TypeName] if t.Desc == nil { diff --git a/prog/types.go b/prog/types.go index 33c7bd356..2928e54c8 100644 --- a/prog/types.go +++ b/prog/types.go @@ -104,6 +104,8 @@ type Type interface { mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) minimize(ctx *minimizeArgsCtx, arg Arg, path string) bool + ref() Ref + setRef(ref Ref) } type Ref uint32 @@ -135,6 +137,8 @@ func (ti Ref) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (floa func (ti Ref) minimize(ctx *minimizeArgsCtx, arg Arg, path string) bool { panic("prog.Ref method called") } +func (ti Ref) ref() Ref { panic("prog.Ref method called") } +func (ti Ref) setRef(ref Ref) { panic("prog.Ref method called") } func IsPad(t Type) bool { if ct, ok := t.(*ConstType); ok && ct.IsPad { @@ -149,6 +153,8 @@ type TypeCommon struct { TypeSize uint64 IsOptional bool IsVarlen bool + + self Ref } func (t *TypeCommon) Name() string { @@ -206,6 +212,17 @@ func (t *TypeCommon) IsBitfield() bool { return false } +func (t *TypeCommon) ref() Ref { + if t.self == 0 { + panic("ref is not assigned yet") + } + return t.self +} + +func (t *TypeCommon) setRef(ref Ref) { + t.self = ref +} + type ResourceDesc struct { Name string Kind []string |
