diff options
| author | Aleksandr Nogikh <nogikh@google.com> | 2021-09-03 16:20:07 +0000 |
|---|---|---|
| committer | Aleksandr Nogikh <wp32pw@gmail.com> | 2021-09-22 15:40:02 +0200 |
| commit | 1c202847db0380015a8920bfd21375c2d9f28ddb (patch) | |
| tree | 6693da3a936398a9ac6678842ac181c5f0e3e429 /prog | |
| parent | a7ce77be27d8e3728b97122a005bc5b23298cfc3 (diff) | |
all: refactor fault injection into call props
Now that call properties mechanism is implemented, we can refactor
fault injection.
Unfortunately, it is impossible to remove all traces of the previous apprach.
In reprolist and while performing syz-ci jobs, syzkaller still needs to
parse the old format.
Remove the old prog options-based approach whenever possible and replace
it with the use of call properties.
Diffstat (limited to 'prog')
| -rw-r--r-- | prog/analysis.go | 9 | ||||
| -rw-r--r-- | prog/decodeexec.go | 3 | ||||
| -rw-r--r-- | prog/encoding.go | 6 | ||||
| -rw-r--r-- | prog/encoding_test.go | 8 | ||||
| -rw-r--r-- | prog/encodingexec.go | 10 | ||||
| -rw-r--r-- | prog/encodingexec_test.go | 406 | ||||
| -rw-r--r-- | prog/minimization.go | 18 | ||||
| -rw-r--r-- | prog/minimization_test.go | 22 | ||||
| -rw-r--r-- | prog/parse.go | 29 | ||||
| -rw-r--r-- | prog/parse_test.go | 20 | ||||
| -rw-r--r-- | prog/prog.go | 13 |
11 files changed, 277 insertions, 267 deletions
diff --git a/prog/analysis.go b/prog/analysis.go index 0ac0a97b9..6643941ff 100644 --- a/prog/analysis.go +++ b/prog/analysis.go @@ -176,6 +176,15 @@ func RequiredFeatures(p *Prog) (bitmasks, csums bool) { return } +func (p *Prog) HasFaultInjection() bool { + for _, call := range p.Calls { + if call.Props.FailNth > 0 { + return true + } + } + return false +} + type CallFlags int const ( diff --git a/prog/decodeexec.go b/prog/decodeexec.go index ff1ab5727..f803d5b4c 100644 --- a/prog/decodeexec.go +++ b/prog/decodeexec.go @@ -115,13 +115,14 @@ func (dec *execDecoder) parse() { case execInstrEOF: dec.commitCall() return + case execInstrSetProps: + dec.readCallProps(&dec.call.Props) default: dec.commitCall() if instr >= uint64(len(dec.target.Syscalls)) { dec.setErr(fmt.Errorf("bad syscall %v", instr)) return } - dec.readCallProps(&dec.call.Props) dec.call.Meta = dec.target.Syscalls[instr] dec.call.Index = dec.read() for i := dec.read(); i > 0; i-- { diff --git a/prog/encoding.go b/prog/encoding.go index 3f1c918a7..9161da6b2 100644 --- a/prog/encoding.go +++ b/prog/encoding.go @@ -81,11 +81,9 @@ func (ctx *serializer) call(c *Call) { } ctx.printf(")") - defaultProps := DefaultCallProps() anyChangedProps := false c.Props.ForeachProp(func(name, key string, value reflect.Value) { - defaultValue := reflect.ValueOf(defaultProps).FieldByName(name) - if reflect.DeepEqual(value.Interface(), defaultValue.Interface()) { + if value.IsZero() { return } @@ -352,7 +350,7 @@ func (p *parser) parseProg() (*Prog, error) { func (p *parser) parseCallProps() CallProps { nameToValue := map[string]reflect.Value{} - callProps := DefaultCallProps() + callProps := CallProps{} callProps.ForeachProp(func(_, key string, value reflect.Value) { nameToValue[key] = value }) diff --git a/prog/encoding_test.go b/prog/encoding_test.go index d7171248f..11e71867f 100644 --- a/prog/encoding_test.go +++ b/prog/encoding_test.go @@ -327,6 +327,10 @@ func TestDeserialize(t *testing.T) { Out: `test$opt2(0x0) (fail_nth: 1)`, StrictErr: `unknown call property: non_existing_prop`, }, + { + In: `test$opt2(0x0) (fail_nth: 0)`, + Out: `test$opt2(0x0)`, + }, }) } @@ -409,11 +413,11 @@ func TestSerializeCallProps(t *testing.T) { tests := []SerializeCallPropsTest{ { "serialize0(0x0)\n", - []CallProps{DefaultCallProps()}, + []CallProps{{}}, }, { "serialize0(0x0) ()\n", - []CallProps{DefaultCallProps()}, + []CallProps{{}}, }, { "serialize0(0x0) (fail_nth: 5)\n", diff --git a/prog/encodingexec.go b/prog/encodingexec.go index 296fcf0cf..fea114717 100644 --- a/prog/encodingexec.go +++ b/prog/encodingexec.go @@ -6,7 +6,7 @@ // Exec format is an sequence of uint64's which encodes a sequence of calls. // The sequence is terminated by a speciall call execInstrEOF. -// Each call is (call ID, call props, copyout index, number of arguments, arguments...). +// Each call is (call ID, copyout index, number of arguments, arguments...). // Each argument is (type, size, value). // There are 4 types of arguments: // - execArgConst: value is const value @@ -30,6 +30,7 @@ const ( execInstrEOF = ^uint64(iota) execInstrCopyin execInstrCopyout + execInstrSetProps ) const ( @@ -88,10 +89,12 @@ func (w *execContext) serializeCall(c *Call) { // Generate checksum calculation instructions starting from the last one, // since checksum values can depend on values of the latter ones w.writeChecksums() + if !reflect.DeepEqual(c.Props, CallProps{}) { + // Push call properties. + w.writeCallProps(c.Props) + } // Generate the call itself. w.write(uint64(c.Meta.ID)) - // Generate call properties fragment. - w.writeCallProps(c.Props) if c.Ret != nil && len(c.Ret.uses) != 0 { if _, ok := w.args[c.Ret]; ok { panic("argInfo is already created for return value") @@ -129,6 +132,7 @@ type argInfo struct { } func (w *execContext) writeCallProps(props CallProps) { + w.write(execInstrSetProps) props.ForeachProp(func(_, _ string, value reflect.Value) { switch kind := value.Kind(); kind { case reflect.Int: diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go index a7085be0c..4a8e5c7fd 100644 --- a/prog/encodingexec_test.go +++ b/prog/encodingexec_test.go @@ -54,27 +54,6 @@ func TestSerializeForExec(t *testing.T) { buf[7] = byte(v >> 56) return HostEndian.Uint64(buf) } - - join := func(objects ...interface{}) []uint64 { - ret := []uint64{} - for _, val := range objects { - switch v := val.(type) { - case uint64: - ret = append(ret, v) - case int: - ret = append(ret, uint64(v)) - case []uint64: - ret = append(ret, v...) - default: - panic(fmt.Sprintf("unsupported object type %T", v)) - } - } - return ret - } - - defaultCallPropsSlice := []uint64{ - 0xFFFFFFFFFFFFFFFF, - } tests := []struct { prog string serialized []uint64 @@ -82,244 +61,215 @@ func TestSerializeForExec(t *testing.T) { }{ { "test()", - join( - callID("test"), defaultCallPropsSlice, - ExecNoCopyout, 0, + []uint64{ + callID("test"), ExecNoCopyout, 0, execInstrEOF, - ), + }, &ExecProg{ Calls: []ExecCall{ { Meta: target.SyscallMap["test"], Index: ExecNoCopyout, - Props: DefaultCallProps(), }, }, }, }, { "test$int(0x1, 0x2, 0x3, 0x4, 0x5)", - join( - callID("test$int"), defaultCallPropsSlice, - ExecNoCopyout, 5, + []uint64{ + callID("test$int"), ExecNoCopyout, 5, execArgConst, 8, 1, execArgConst, 1, 2, execArgConst, 2, 3, execArgConst, 4, 4, execArgConst, 8, 5, execInstrEOF, - ), - nil, - }, - { - "test() (fail_nth: 3)", - join( - callID("test"), - 3, - ExecNoCopyout, 0, - execInstrEOF, - ), + }, nil, }, { "test$align0(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 2, 1, - execInstrCopyin, dataOffset+4, execArgConst, 4, 2, - execInstrCopyin, dataOffset+8, execArgConst, 1, 3, - execInstrCopyin, dataOffset+10, execArgConst, 2, 4, - execInstrCopyin, dataOffset+16, execArgConst, 8, 5, - callID("test$align0"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 2, 1, + execInstrCopyin, dataOffset + 4, execArgConst, 4, 2, + execInstrCopyin, dataOffset + 8, execArgConst, 1, 3, + execInstrCopyin, dataOffset + 10, execArgConst, 2, 4, + execInstrCopyin, dataOffset + 16, execArgConst, 8, 5, + callID("test$align0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$align1(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 2, 1, - execInstrCopyin, dataOffset+2, execArgConst, 4, 2, - execInstrCopyin, dataOffset+6, execArgConst, 1, 3, - execInstrCopyin, dataOffset+7, execArgConst, 2, 4, - execInstrCopyin, dataOffset+9, execArgConst, 8, 5, - callID("test$align1"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 2, 1, + execInstrCopyin, dataOffset + 2, execArgConst, 4, 2, + execInstrCopyin, dataOffset + 6, execArgConst, 1, 3, + execInstrCopyin, dataOffset + 7, execArgConst, 2, 4, + execInstrCopyin, dataOffset + 9, execArgConst, 8, 5, + callID("test$align1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$align2(&(0x7f0000000000)={0x42, {[0x43]}, {[0x44]}})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 1, 0x42, - execInstrCopyin, dataOffset+1, execArgConst, 2, 0x43, - execInstrCopyin, dataOffset+4, execArgConst, 2, 0x44, - callID("test$align2"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, + execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43, + execInstrCopyin, dataOffset + 4, execArgConst, 2, 0x44, + callID("test$align2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$align3(&(0x7f0000000000)={0x42, {0x43}, {0x44}})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 1, 0x42, - execInstrCopyin, dataOffset+1, execArgConst, 1, 0x43, - execInstrCopyin, dataOffset+4, execArgConst, 1, 0x44, - callID("test$align3"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, + execInstrCopyin, dataOffset + 1, execArgConst, 1, 0x43, + execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44, + callID("test$align3"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$align4(&(0x7f0000000000)={{0x42, 0x43}, 0x44})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 1, 0x42, - execInstrCopyin, dataOffset+1, execArgConst, 2, 0x43, - execInstrCopyin, dataOffset+4, execArgConst, 1, 0x44, - callID("test$align4"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, + execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43, + execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44, + callID("test$align4"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$align5(&(0x7f0000000000)={{0x42, []}, {0x43, [0x44, 0x45, 0x46]}, 0x47})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 8, 0x42, - execInstrCopyin, dataOffset+8, execArgConst, 8, 0x43, - execInstrCopyin, dataOffset+16, execArgConst, 2, 0x44, - execInstrCopyin, dataOffset+18, execArgConst, 2, 0x45, - execInstrCopyin, dataOffset+20, execArgConst, 2, 0x46, - execInstrCopyin, dataOffset+22, execArgConst, 1, 0x47, - callID("test$align5"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 8, 0x42, + execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x43, + execInstrCopyin, dataOffset + 16, execArgConst, 2, 0x44, + execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x45, + execInstrCopyin, dataOffset + 20, execArgConst, 2, 0x46, + execInstrCopyin, dataOffset + 22, execArgConst, 1, 0x47, + callID("test$align5"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$align6(&(0x7f0000000000)={0x42, [0x43]})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 1, 0x42, - execInstrCopyin, dataOffset+4, execArgConst, 4, 0x43, - callID("test$align6"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, + execInstrCopyin, dataOffset + 4, execArgConst, 4, 0x43, + callID("test$align6"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$union0(&(0x7f0000000000)={0x1, @f2=0x2})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 8, 1, - execInstrCopyin, dataOffset+8, execArgConst, 1, 2, - callID("test$union0"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 8, 1, + execInstrCopyin, dataOffset + 8, execArgConst, 1, 2, + callID("test$union0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$union1(&(0x7f0000000000)={@f1=0x42, 0x43})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 4, 0x42, - execInstrCopyin, dataOffset+8, execArgConst, 1, 0x43, - callID("test$union1"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42, + execInstrCopyin, dataOffset + 8, execArgConst, 1, 0x43, + callID("test$union1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$union2(&(0x7f0000000000)={@f1=0x42, 0x43})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 4, 0x42, - execInstrCopyin, dataOffset+4, execArgConst, 1, 0x43, - callID("test$union2"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42, + execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x43, + callID("test$union2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$array0(&(0x7f0000000000)={0x1, [@f0=0x2, @f1=0x3], 0x4})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 1, 1, - execInstrCopyin, dataOffset+1, execArgConst, 2, 2, - execInstrCopyin, dataOffset+3, execArgConst, 8, 3, - execInstrCopyin, dataOffset+11, execArgConst, 8, 4, - callID("test$array0"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 1, 1, + execInstrCopyin, dataOffset + 1, execArgConst, 2, 2, + execInstrCopyin, dataOffset + 3, execArgConst, 8, 3, + execInstrCopyin, dataOffset + 11, execArgConst, 8, 4, + callID("test$array0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$array1(&(0x7f0000000000)={0x42, \"0102030405\"})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 1, 0x42, - execInstrCopyin, dataOffset+1, execArgData, 5, letoh64(0x0504030201), - callID("test$array1"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, + execInstrCopyin, dataOffset + 1, execArgData, 5, letoh64(0x0504030201), + callID("test$array1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$array2(&(0x7f0000000000)={0x42, \"aaaaaaaabbbbbbbbccccccccdddddddd\", 0x43})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 2, 0x42, - execInstrCopyin, dataOffset+2, execArgData, 16, letoh64(0xbbbbbbbbaaaaaaaa), letoh64(0xddddddddcccccccc), - execInstrCopyin, dataOffset+18, execArgConst, 2, 0x43, - callID("test$array2"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x42, + execInstrCopyin, dataOffset + 2, execArgData, 16, letoh64(0xbbbbbbbbaaaaaaaa), letoh64(0xddddddddcccccccc), + execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x43, + callID("test$array2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$end0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 1, 0x42, - execInstrCopyin, dataOffset+1, execArgConst, 2|1<<8, 0x42, - execInstrCopyin, dataOffset+3, execArgConst, 4|1<<8, 0x42, - execInstrCopyin, dataOffset+7, execArgConst, 8|1<<8, 0x42, - callID("test$end0"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, + execInstrCopyin, dataOffset + 1, execArgConst, 2 | 1<<8, 0x42, + execInstrCopyin, dataOffset + 3, execArgConst, 4 | 1<<8, 0x42, + execInstrCopyin, dataOffset + 7, execArgConst, 8 | 1<<8, 0x42, + callID("test$end0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$end1(&(0x7f0000000000)={0xe, 0x42, 0x1})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 2|1<<8, 0xe, - execInstrCopyin, dataOffset+2, execArgConst, 4|1<<8, 0x42, - execInstrCopyin, dataOffset+6, execArgConst, 8|1<<8, 0x1, - callID("test$end1"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 2 | 1<<8, 0xe, + execInstrCopyin, dataOffset + 2, execArgConst, 4 | 1<<8, 0x42, + execInstrCopyin, dataOffset + 6, execArgConst, 8 | 1<<8, 0x1, + callID("test$end1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$bf0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 2|0<<16|10<<24, 0x42, - execInstrCopyin, dataOffset+8, execArgConst, 8, 0x42, - execInstrCopyin, dataOffset+16, execArgConst, 2|0<<16|5<<24, 0x42, - execInstrCopyin, dataOffset+16, execArgConst, 2|5<<16|6<<24, 0x42, - execInstrCopyin, dataOffset+16, execArgConst, 4|11<<16|15<<24, 0x42, - execInstrCopyin, dataOffset+20, execArgConst, 2|0<<16|11<<24, 0x42, - execInstrCopyin, dataOffset+22, execArgConst, 2|1<<8|0<<16|11<<24, 0x42, - execInstrCopyin, dataOffset+24, execArgConst, 1, 0x42, - callID("test$bf0"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 2 | 0<<16 | 10<<24, 0x42, + execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x42, + execInstrCopyin, dataOffset + 16, execArgConst, 2 | 0<<16 | 5<<24, 0x42, + execInstrCopyin, dataOffset + 16, execArgConst, 2 | 5<<16 | 6<<24, 0x42, + execInstrCopyin, dataOffset + 16, execArgConst, 4 | 11<<16 | 15<<24, 0x42, + execInstrCopyin, dataOffset + 20, execArgConst, 2 | 0<<16 | 11<<24, 0x42, + execInstrCopyin, dataOffset + 22, execArgConst, 2 | 1<<8 | 0<<16 | 11<<24, 0x42, + execInstrCopyin, dataOffset + 24, execArgConst, 1, 0x42, + callID("test$bf0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, &ExecProg{ Calls: []ExecCall{ { @@ -331,7 +281,6 @@ func TestSerializeForExec(t *testing.T) { Value: dataOffset, }, }, - Props: DefaultCallProps(), Copyin: []ExecCopyin{ { Addr: dataOffset + 0, @@ -409,120 +358,127 @@ func TestSerializeForExec(t *testing.T) { }, { "test$bf1(&(0x7f0000000000)={{0x42, 0x42, 0x42}, 0x42})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 4|0<<16|10<<24, 0x42, - execInstrCopyin, dataOffset+0, execArgConst, 4|10<<16|10<<24, 0x42, - execInstrCopyin, dataOffset+0, execArgConst, 4|20<<16|10<<24, 0x42, - execInstrCopyin, dataOffset+4, execArgConst, 1, 0x42, - callID("test$bf1"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 4 | 0<<16 | 10<<24, 0x42, + execInstrCopyin, dataOffset + 0, execArgConst, 4 | 10<<16 | 10<<24, 0x42, + execInstrCopyin, dataOffset + 0, execArgConst, 4 | 20<<16 | 10<<24, 0x42, + execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x42, + callID("test$bf1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$res1(0xffff)", - join( - callID("test$res1"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, 4, 0xffff, + []uint64{ + callID("test$res1"), ExecNoCopyout, 1, execArgConst, 4, 0xffff, execInstrEOF, - ), + }, nil, }, { "test$opt3(0x0)", - join( - callID("test$opt3"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, 8|4<<32, 0x64, + []uint64{ + callID("test$opt3"), ExecNoCopyout, 1, execArgConst, 8 | 4<<32, 0x64, execInstrEOF, - ), + }, nil, }, { // Special value that translates to 0 for all procs. "test$opt3(0xffffffffffffffff)", - join( - callID("test$opt3"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, 8, 0, + []uint64{ + callID("test$opt3"), ExecNoCopyout, 1, execArgConst, 8, 0, execInstrEOF, - ), + }, nil, }, { // NULL pointer must be encoded os 0. "test$opt1(0x0)", - join( - callID("test$opt1"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, 8, 0, + []uint64{ + callID("test$opt1"), ExecNoCopyout, 1, execArgConst, 8, 0, execInstrEOF, - ), + }, nil, }, { "test$align7(&(0x7f0000000000)={{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}, 0x42})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 1|0<<16|1<<24, 0x1, - execInstrCopyin, dataOffset+0, execArgConst, 1|1<<16|1<<24, 0x2, - execInstrCopyin, dataOffset+0, execArgConst, 1|2<<16|1<<24, 0x3, - execInstrCopyin, dataOffset+0, execArgConst, 2|3<<16|1<<24, 0x4, - execInstrCopyin, dataOffset+0, execArgConst, 2|4<<16|1<<24, 0x5, - execInstrCopyin, dataOffset+0, execArgConst, 2|5<<16|1<<24, 0x6, - execInstrCopyin, dataOffset+8, execArgConst, 1, 0x42, - callID("test$align7"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 1 | 0<<16 | 1<<24, 0x1, + execInstrCopyin, dataOffset + 0, execArgConst, 1 | 1<<16 | 1<<24, 0x2, + execInstrCopyin, dataOffset + 0, execArgConst, 1 | 2<<16 | 1<<24, 0x3, + execInstrCopyin, dataOffset + 0, execArgConst, 2 | 3<<16 | 1<<24, 0x4, + execInstrCopyin, dataOffset + 0, execArgConst, 2 | 4<<16 | 1<<24, 0x5, + execInstrCopyin, dataOffset + 0, execArgConst, 2 | 5<<16 | 1<<24, 0x6, + execInstrCopyin, dataOffset + 8, execArgConst, 1, 0x42, + callID("test$align7"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, { "test$excessive_fields1(0x0)", - join( - callID("test$excessive_fields1"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, 0x0, + []uint64{ + callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, 0x0, execInstrEOF, - ), + }, nil, }, { "test$excessive_fields1(0xffffffffffffffff)", - join( - callID("test$excessive_fields1"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, uint64(0xffffffffffffffff), + []uint64{ + callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, 0xffffffffffffffff, execInstrEOF, - ), + }, nil, }, { "test$excessive_fields1(0xfffffffffffffffe)", - join( - callID("test$excessive_fields1"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, uint64(0x9999999999999999), + []uint64{ + callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, 0x9999999999999999, execInstrEOF, - ), + }, nil, }, { "test$csum_ipv4_tcp(&(0x7f0000000000)={{0x0, 0x1, 0x2}, {{0x0}, \"ab\"}})", - join( - execInstrCopyin, dataOffset+0, execArgConst, 2, 0x0, - execInstrCopyin, dataOffset+2, execArgConst, 4|1<<8, 0x1, - execInstrCopyin, dataOffset+6, execArgConst, 4|1<<8, 0x2, - execInstrCopyin, dataOffset+10, execArgConst, 2, 0x0, - execInstrCopyin, dataOffset+12, execArgData, 1, letoh64(0xab), - execInstrCopyin, dataOffset+10, execArgCsum, 2, ExecArgCsumInet, 5, - ExecArgCsumChunkData, dataOffset+2, 4, - ExecArgCsumChunkData, dataOffset+6, 4, + []uint64{ + execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x0, + execInstrCopyin, dataOffset + 2, execArgConst, 4 | 1<<8, 0x1, + execInstrCopyin, dataOffset + 6, execArgConst, 4 | 1<<8, 0x2, + execInstrCopyin, dataOffset + 10, execArgConst, 2, 0x0, + execInstrCopyin, dataOffset + 12, execArgData, 1, letoh64(0xab), + execInstrCopyin, dataOffset + 10, execArgCsum, 2, ExecArgCsumInet, 5, + ExecArgCsumChunkData, dataOffset + 2, 4, + ExecArgCsumChunkData, dataOffset + 6, 4, ExecArgCsumChunkConst, 0x0600, 2, ExecArgCsumChunkConst, 0x0300, 2, - ExecArgCsumChunkData, dataOffset+10, 3, - execInstrCopyin, dataOffset+0, execArgCsum, 2, ExecArgCsumInet, 1, - ExecArgCsumChunkData, dataOffset+0, 10, - callID("test$csum_ipv4_tcp"), defaultCallPropsSlice, - ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, + ExecArgCsumChunkData, dataOffset + 10, 3, + execInstrCopyin, dataOffset + 0, execArgCsum, 2, ExecArgCsumInet, 1, + ExecArgCsumChunkData, dataOffset + 0, 10, + callID("test$csum_ipv4_tcp"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, - ), + }, nil, }, + { + "test() (fail_nth: 3)", + []uint64{ + execInstrSetProps, 3, + callID("test"), ExecNoCopyout, 0, + execInstrEOF, + }, + &ExecProg{ + Calls: []ExecCall{ + { + Meta: target.SyscallMap["test"], + Index: ExecNoCopyout, + Props: CallProps{3}, + }, + }, + }, + }, } buf := make([]byte, ExecBufferSize) @@ -591,7 +547,7 @@ func TestSerializeForExecOverflow(t *testing.T) { overflow: false, gen: func(w *bytes.Buffer) { fmt.Fprintf(w, "r0 = test$res0()\n") - for i := 0; i < 42e3; i++ { + for i := 0; i < 58e3; i++ { fmt.Fprintf(w, "test$res1(r0)\n") } }, diff --git a/prog/minimization.go b/prog/minimization.go index 5e0383bb8..71320d92e 100644 --- a/prog/minimization.go +++ b/prog/minimization.go @@ -28,7 +28,7 @@ func Minimize(p0 *Prog, callIndex0 int, crash bool, pred0 func(*Prog, int) bool) // Try to remove all calls except the last one one-by-one. p0, callIndex0 = removeCalls(p0, callIndex0, crash, pred) - // Try to minimize individual args. + // Try to minimize individual calls. for i := 0; i < len(p0.Calls); i++ { ctx := &minimizeArgsCtx{ target: p0.Target, @@ -46,6 +46,7 @@ func Minimize(p0 *Prog, callIndex0 int, crash bool, pred0 func(*Prog, int) bool) goto again } } + p0 = minimizeCallProps(p0, i, callIndex0, pred) } if callIndex0 != -1 { @@ -77,6 +78,21 @@ func removeCalls(p0 *Prog, callIndex0 int, crash bool, pred func(*Prog, int) boo return p0, callIndex0 } +func minimizeCallProps(p0 *Prog, callIndex, callIndex0 int, pred func(*Prog, int) bool) *Prog { + props := p0.Calls[callIndex].Props + + // Try to drop fault injection. + if props.FailNth > 0 { + p := p0.Clone() + p.Calls[callIndex].Props.FailNth = 0 + if pred(p, callIndex0) { + p0 = p + } + } + + return p0 +} + type minimizeArgsCtx struct { target *Target p0 **Prog diff --git a/prog/minimization_test.go b/prog/minimization_test.go index 36b65763d..032b2b080 100644 --- a/prog/minimization_test.go +++ b/prog/minimization_test.go @@ -149,6 +149,28 @@ func TestMinimize(t *testing.T) { "minimize$0(0x1, 0xffffffffffffffff)\n", -1, }, + // Clear unneeded fault injection. + { + "linux", "amd64", + "pipe2(0x0, 0x0) (fail_nth: 5)\n", + -1, + func(p *Prog, callIndex int) bool { + return len(p.Calls) == 1 && p.Calls[0].Meta.Name == "pipe2" + }, + "pipe2(0x0, 0x0)\n", + -1, + }, + // Keep important fault injection. + { + "linux", "amd64", + "pipe2(0x0, 0x0) (fail_nth: 5)\n", + -1, + func(p *Prog, callIndex int) bool { + return len(p.Calls) == 1 && p.Calls[0].Meta.Name == "pipe2" && p.Calls[0].Props.FailNth == 5 + }, + "pipe2(0x0, 0x0) (fail_nth: 5)\n", + -1, + }, } t.Parallel() for ti, test := range tests { diff --git a/prog/parse.go b/prog/parse.go index 7a46322df..77812f5b4 100644 --- a/prog/parse.go +++ b/prog/parse.go @@ -10,19 +10,17 @@ import ( // LogEntry describes one program in execution log. type LogEntry struct { - P *Prog - Proc int // index of parallel proc - Start int // start offset in log - End int // end offset in log - Fault bool // program was executed with fault injection in FaultCall/FaultNth - FaultCall int - FaultNth int + P *Prog + Proc int // index of parallel proc + Start int // start offset in log + End int // end offset in log } func (target *Target) ParseLog(data []byte) []*LogEntry { var entries []*LogEntry ent := &LogEntry{} var cur []byte + faultCall, faultNth := -1, -1 for pos := 0; pos < len(data); { nl := bytes.IndexByte(data[pos:], '\n') if nl == -1 { @@ -38,15 +36,17 @@ func (target *Target) ParseLog(data []byte) []*LogEntry { if ent.P != nil && len(ent.P.Calls) != 0 { ent.End = pos0 entries = append(entries, ent) + faultCall, faultNth = -1, -1 } ent = &LogEntry{ Proc: proc, Start: pos0, } - if faultCall, ok := extractInt(line, "fault-call:"); ok { - ent.Fault = true - ent.FaultCall = faultCall - ent.FaultNth, _ = extractInt(line, "fault-nth:") + // We no longer print it this way, but we still parse such fragments to preserve + // the backward compatibility. + if parsedFaultCall, ok := extractInt(line, "fault-call:"); ok { + faultCall = parsedFaultCall + faultNth, _ = extractInt(line, "fault-nth:") } cur = nil continue @@ -55,10 +55,17 @@ func (target *Target) ParseLog(data []byte) []*LogEntry { continue } tmp := append(cur, line...) + p, err := target.Deserialize(tmp, NonStrict) if err != nil { continue } + + if faultCall >= 0 && faultCall < len(p.Calls) { + // We add 1 because now the property is 1-based. + p.Calls[faultCall].Props.FailNth = faultNth + 1 + } + cur = tmp ent.P = p } diff --git a/prog/parse_test.go b/prog/parse_test.go index 48e3cd203..8de2e36da 100644 --- a/prog/parse_test.go +++ b/prog/parse_test.go @@ -30,7 +30,7 @@ gettid() if ent.Proc != 0 { t.Fatalf("proc %v, want 0", ent.Proc) } - if ent.Fault || ent.FaultCall != 0 || ent.FaultNth != 0 { + if ent.P.HasFaultInjection() { t.Fatalf("fault injection enabled") } want := "getpid-gettid" @@ -67,7 +67,7 @@ func TestParseMulti(t *testing.T) { t.Fatalf("bad procs") } for i, ent := range entries { - if ent.Fault || ent.FaultCall != 0 || ent.FaultNth != 0 { + if ent.P.HasFaultInjection() { t.Fatalf("prog %v has fault injection enabled", i) } } @@ -123,14 +123,14 @@ getpid() t.Fatalf("got %v programs, want 1", len(entries)) } ent := entries[0] - if !ent.Fault { - t.Fatalf("fault injection is not enabled") - } - if ent.FaultCall != 1 { - t.Fatalf("fault call: got %v, want 1", ent.FaultCall) - } - if ent.FaultNth != 55 { - t.Fatalf("fault nth: got %v, want 55", ent.FaultNth) + faultCall := ent.P.Calls[1] + normalCall := ent.P.Calls[0] + if faultCall.Props.FailNth != 56 { + // We want 56 (not 55!) because the number is now not 0-based. + t.Fatalf("fault nth on the 2nd call: got %v, want 56", faultCall.Props.FailNth) + } + if normalCall.Props.FailNth != 0 { + t.Fatalf("fault nth on the 1st call: got %v, want 0", normalCall.Props.FailNth) } want := "gettid-getpid" got := ent.P.String() diff --git a/prog/prog.go b/prog/prog.go index 6ead4d47e..068198ffe 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -22,12 +22,6 @@ type CallProps struct { FailNth int `key:"fail_nth"` } -func DefaultCallProps() CallProps { - return CallProps{ - FailNth: -1, - } -} - type Call struct { Meta *Syscall Args []Arg @@ -38,10 +32,9 @@ type Call struct { func MakeCall(meta *Syscall, args []Arg) *Call { return &Call{ - Meta: meta, - Args: args, - Ret: MakeReturnArg(meta.Ret), - Props: DefaultCallProps(), + Meta: meta, + Args: args, + Ret: MakeReturnArg(meta.Ret), } } |
