prog: don't serialize paddings

Paddings in serialized programs are unnecessary and confusing.
Instead restore them implicitly.
Also use [,,,,] for arrays.
This commit is contained in:
Dmitry Vyukov 2015-12-28 12:58:10 +01:00
parent 9f9ae3fcc3
commit 4eda9b07e5
7 changed files with 95 additions and 30 deletions

View File

@ -43,6 +43,9 @@ func (p *Prog) Serialize() []byte {
}
fmt.Fprintf(buf, "%v(", c.Meta.Name)
for i, a := range c.Args {
if sys.IsPad(a.Type) {
continue
}
if i != 0 {
fmt.Fprintf(buf, ", ")
}
@ -59,7 +62,7 @@ func (a *Arg) serialize(buf io.Writer, vars map[*Arg]int, varSeq *int) {
return
}
if len(a.Uses) != 0 {
fmt.Fprintf(buf, "[r%v=]", *varSeq)
fmt.Fprintf(buf, "<r%v=>", *varSeq)
vars[a] = *varSeq
*varSeq++
}
@ -86,14 +89,26 @@ func (a *Arg) serialize(buf io.Writer, vars map[*Arg]int, varSeq *int) {
case ArgData:
fmt.Fprintf(buf, "\"%v\"", hex.EncodeToString(a.Data))
case ArgGroup:
fmt.Fprintf(buf, "{")
var delims []byte
switch a.Type.(type) {
case sys.StructType:
delims = []byte{'{', '}'}
case sys.ArrayType:
delims = []byte{'[', ']'}
default:
panic("unknown group type")
}
buf.Write([]byte{delims[0]})
for i, a1 := range a.Inner {
if a1 != nil && sys.IsPad(a1.Type) {
continue
}
if i != 0 {
fmt.Fprintf(buf, ", ")
}
a1.serialize(buf, vars, varSeq)
}
fmt.Fprintf(buf, "}")
buf.Write([]byte{delims[1]})
default:
panic("unknown arg kind")
}
@ -123,7 +138,14 @@ func Deserialize(data []byte) (prog *Prog, err error) {
prog.Calls = append(prog.Calls, c)
p.Parse('(')
for i := 0; p.Char() != ')'; i++ {
arg, err := parseArg(p, vars)
if i >= len(meta.Args) {
return nil, fmt.Errorf("wrong call arg count: %v, want %v", i+1, len(meta.Args))
}
typ := meta.Args[i]
if sys.IsPad(typ) {
return nil, fmt.Errorf("padding in syscall %v arguments", name)
}
arg, err := parseArg(typ, p, vars)
if err != nil {
return nil, err
}
@ -155,13 +177,13 @@ func Deserialize(data []byte) (prog *Prog, err error) {
return
}
func parseArg(p *parser, vars map[string]*Arg) (*Arg, error) {
func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) {
r := ""
if p.Char() == '[' {
p.Parse('[')
if p.Char() == '<' {
p.Parse('<')
r = p.Ident()
p.Parse('=')
p.Parse(']')
p.Parse('>')
}
var arg *Arg
switch p.Char() {
@ -198,13 +220,21 @@ func parseArg(p *parser, vars map[string]*Arg) (*Arg, error) {
arg.OpAdd = uintptr(v)
}
case '&':
var typ1 sys.Type
switch t1 := typ.(type) {
case sys.PtrType:
typ1 = t1.Type
case sys.VmaType:
default:
return nil, fmt.Errorf("& arg is not a pointer: %#v", typ)
}
p.Parse('&')
page, off, err := parseAddr(p, true)
if err != nil {
return nil, err
}
p.Parse('=')
inner, err := parseArg(p, vars)
inner, err := parseArg(typ1, p, vars)
if err != nil {
return nil, err
}
@ -228,19 +258,53 @@ func parseArg(p *parser, vars map[string]*Arg) (*Arg, error) {
}
arg = dataArg(data)
case '{':
t1, ok := typ.(sys.StructType)
if !ok {
return nil, fmt.Errorf("'{' arg is not a struct: %#v", typ)
}
p.Parse('{')
var inner []*Arg
for p.Char() != '}' {
arg, err := parseArg(p, vars)
for i := 0; p.Char() != '}'; i++ {
if i >= len(t1.Fields) {
return nil, fmt.Errorf("wrong struct arg count: %v, want %v", i+1, len(t1.Fields))
}
fld := t1.Fields[i]
if sys.IsPad(fld) {
inner = append(inner, constArg(0))
} else {
arg, err := parseArg(fld, p, vars)
if err != nil {
return nil, err
}
inner = append(inner, arg)
if p.Char() != '}' {
p.Parse(',')
}
}
}
p.Parse('}')
if sys.IsPad(t1.Fields[len(t1.Fields)-1]) {
inner = append(inner, constArg(0))
}
arg = groupArg(inner)
case '[':
t1, ok := typ.(sys.ArrayType)
if !ok {
return nil, fmt.Errorf("'[' arg is not an array: %#v", typ)
}
p.Parse('[')
var inner []*Arg
for i := 0; p.Char() != ']'; i++ {
arg, err := parseArg(t1.Type, p, vars)
if err != nil {
return nil, err
}
inner = append(inner, arg)
if p.Char() != '}' {
if p.Char() != ']' {
p.Parse(',')
}
}
p.Parse('}')
p.Parse(']')
arg = groupArg(inner)
case 'n':
p.Parse('n')

View File

@ -8,6 +8,8 @@ package prog
import (
"fmt"
"github.com/google/syzkaller/sys"
)
const (
@ -57,7 +59,7 @@ func (p *Prog) SerializeForExec() []byte {
}
return
}
if pad, _ := arg1.IsPad(); pad {
if sys.IsPad(arg1.Type) {
return
}
if arg1.Kind == ArgData && len(arg1.Data) == 0 {

View File

@ -212,7 +212,7 @@ func TestMinimize(t *testing.T) {
// Remove a call and replace results.
{
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
"pipe2(&(0x7f0000000000)={[r0=]0x0, 0x0}, 0x0)\n" +
"pipe2(&(0x7f0000000000)={<r0=>0x0, 0x0}, 0x0)\n" +
"write(r0, &(0x7f0000000000)=\"1155\", 0x2)\n" +
"sched_yield()\n",
3,
@ -259,7 +259,7 @@ func TestMinimize(t *testing.T) {
for ti, test := range tests {
p, err := Deserialize([]byte(test.orig))
if err != nil {
t.Fatalf("failed to deserialize original program: %v", err)
t.Fatalf("failed to deserialize original program #%v: %v", ti, err)
}
p1, ci := Minimize(p, test.callIndex, test.pred)
res := p1.Serialize()

View File

@ -79,13 +79,6 @@ func (a *Arg) Size(typ sys.Type) uintptr {
}
}
func (a *Arg) IsPad() (bool, uintptr) {
if ct, ok := a.Type.(sys.ConstType); ok && ct.Val == 0 && ct.Name() == "pad" {
return true, ct.TypeSize
}
return false, 0
}
func constArg(v uintptr) *Arg {
return &Arg{Kind: ArgConst, Val: v}
}

View File

@ -462,7 +462,7 @@ func (r *randGen) createResource(s *state, res sys.ResourceType) (arg *Arg, call
// Generate one of them.
meta := metas[r.Intn(len(metas))]
calls := r.generateParticularCall(s, meta)
assignTypeAndDir(calls[len(calls)-1])
//assignTypeAndDir(calls[len(calls)-1])
s1 := newState(s.ct)
s1.analyze(calls[len(calls)-1])
// Now see if we have what we want.

View File

@ -18,12 +18,6 @@ func (p *Prog) validate() error {
ctx := &validCtx{make(map[*Arg]bool), make(map[*Arg]*Arg)}
for _, c := range p.Calls {
if err := c.validate(ctx); err != nil {
fmt.Printf("PROGRAM:\n")
for _, c := range p.Calls {
fmt.Printf(" %v: %+v %p\n", c.Meta.Name, c.Args, c.Ret)
}
return err
}
}
@ -36,6 +30,9 @@ func (p *Prog) validate() error {
}
func (c *Call) validate(ctx *validCtx) error {
if c.Meta == nil {
return fmt.Errorf("call does not have meta information")
}
if len(c.Args) != len(c.Meta.Args) {
return fmt.Errorf("syscall %v: wrong number of arguments, want %v, got %v", c.Meta.Name, len(c.Meta.Args), len(c.Args))
}

View File

@ -23,6 +23,13 @@ type Type interface {
Align() uintptr
}
func IsPad(t Type) bool {
if ct, ok := t.(ConstType); ok && ct.IsPad {
return true
}
return false
}
type TypeCommon struct {
TypeName string
IsOptional bool
@ -313,6 +320,7 @@ type ConstType struct {
TypeCommon
TypeSize uintptr
Val uintptr
IsPad bool
}
func (t ConstType) Size() uintptr {
@ -654,5 +662,6 @@ func makePad(sz uintptr) Type {
TypeCommon: TypeCommon{TypeName: "pad", IsOptional: false},
TypeSize: sz,
Val: 0,
IsPad: true,
}
}