aboutsummaryrefslogtreecommitdiffstats
path: root/prog
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-04-25 15:05:19 +0200
committerDmitry Vyukov <dvyukov@google.com>2020-05-05 14:01:52 +0200
commit4b76dd258977f4bc9b8a1996680f8b9fd96713d2 (patch)
tree5de611ae32f2f137053888d73bf81b40feaf59b1 /prog
parent8cbfd71747917061fa744c07972ba65a7f73a236 (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.go19
-rw-r--r--prog/prog.go35
-rw-r--r--prog/rand.go2
-rw-r--r--prog/target.go28
-rw-r--r--prog/types.go17
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