mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-27 13:20:34 +00:00
cfc46d9d0b
Right now Arg is a huge struct (160 bytes), which has many different fields used for different arg kinds. Since most of the args we see in a typical corpus are ArgConst, this results in a significant memory overuse. This change: - makes Arg an interface instead of a struct - adds a SomethingArg struct for each arg kind we have - converts all *Arg pointers into just Arg, since interface variable by itself contains a pointer to the actual data - removes ArgPageSize, now ConstArg is used instead - consolidates correspondence between arg kinds and types, see comments before each SomethingArg struct definition - now LenType args that denote the length of VmaType args are serialized as "0x1000" instead of "(0x1000)"; to preserve backwards compatibility syzkaller is able to parse the old format for now - multiple small changes all over to make the above work After this change syzkaller uses twice less memory after deserializing a typical corpus.
111 lines
2.6 KiB
Go
111 lines
2.6 KiB
Go
// Copyright 2017 syzkaller project authors. All rights reserved.
|
|
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
|
|
package prog
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/google/syzkaller/sys"
|
|
)
|
|
|
|
func generateSize(arg Arg, lenType *sys.LenType) Arg {
|
|
if arg == nil {
|
|
// Arg is an optional pointer, set size to 0.
|
|
return constArg(lenType, 0)
|
|
}
|
|
|
|
switch arg.Type().(type) {
|
|
case *sys.VmaType:
|
|
a := arg.(*PointerArg)
|
|
return constArg(lenType, a.PagesNum*pageSize)
|
|
case *sys.ArrayType:
|
|
a := arg.(*GroupArg)
|
|
if lenType.ByteSize != 0 {
|
|
return constArg(lenType, a.Size()/lenType.ByteSize)
|
|
} else {
|
|
return constArg(lenType, uintptr(len(a.Inner)))
|
|
}
|
|
default:
|
|
if lenType.ByteSize != 0 {
|
|
return constArg(lenType, arg.Size()/lenType.ByteSize)
|
|
} else {
|
|
return constArg(lenType, arg.Size())
|
|
}
|
|
}
|
|
}
|
|
|
|
func assignSizes(args []Arg, parentsMap map[Arg]Arg) {
|
|
// Create a map from field names to args.
|
|
argsMap := make(map[string]Arg)
|
|
for _, arg := range args {
|
|
if sys.IsPad(arg.Type()) {
|
|
continue
|
|
}
|
|
argsMap[arg.Type().FieldName()] = arg
|
|
}
|
|
|
|
// Fill in size arguments.
|
|
for _, arg := range args {
|
|
if arg = InnerArg(arg); arg == nil {
|
|
continue // Pointer to optional len field, no need to fill in value.
|
|
}
|
|
if typ, ok := arg.Type().(*sys.LenType); ok {
|
|
a := arg.(*ConstArg)
|
|
|
|
buf, ok := argsMap[typ.Buf]
|
|
if ok {
|
|
*a = *generateSize(InnerArg(buf), typ).(*ConstArg)
|
|
continue
|
|
}
|
|
|
|
if typ.Buf == "parent" {
|
|
a.Val = parentsMap[arg].Size()
|
|
if typ.ByteSize != 0 {
|
|
a.Val /= typ.ByteSize
|
|
}
|
|
continue
|
|
}
|
|
|
|
sizeAssigned := false
|
|
for parent := parentsMap[arg]; parent != nil; parent = parentsMap[parent] {
|
|
if typ.Buf == parent.Type().Name() {
|
|
a.Val = parent.Size()
|
|
if typ.ByteSize != 0 {
|
|
a.Val /= typ.ByteSize
|
|
}
|
|
sizeAssigned = true
|
|
break
|
|
}
|
|
}
|
|
if sizeAssigned {
|
|
continue
|
|
}
|
|
|
|
panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v",
|
|
typ.FieldName(), typ.Buf, argsMap))
|
|
}
|
|
}
|
|
}
|
|
|
|
func assignSizesArray(args []Arg) {
|
|
parentsMap := make(map[Arg]Arg)
|
|
foreachArgArray(&args, nil, func(arg, base Arg, _ *[]Arg) {
|
|
if _, ok := arg.Type().(*sys.StructType); ok {
|
|
for _, field := range arg.(*GroupArg).Inner {
|
|
parentsMap[InnerArg(field)] = arg
|
|
}
|
|
}
|
|
})
|
|
assignSizes(args, parentsMap)
|
|
foreachArgArray(&args, nil, func(arg, base Arg, _ *[]Arg) {
|
|
if _, ok := arg.Type().(*sys.StructType); ok {
|
|
assignSizes(arg.(*GroupArg).Inner, parentsMap)
|
|
}
|
|
})
|
|
}
|
|
|
|
func assignSizesCall(c *Call) {
|
|
assignSizesArray(c.Args)
|
|
}
|