Home | History | Annotate | Download | only in prog
      1 // Copyright 2016 syzkaller project authors. All rights reserved.
      2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
      3 
      4 package prog
      5 
      6 import (
      7 	"bytes"
      8 	"fmt"
      9 	"math/rand"
     10 	"reflect"
     11 	"regexp"
     12 	"sort"
     13 	"strings"
     14 	"testing"
     15 )
     16 
     17 func setToArray(s map[string]struct{}) []string {
     18 	a := make([]string, 0, len(s))
     19 	for c := range s {
     20 		a = append(a, c)
     21 	}
     22 	sort.Strings(a)
     23 	return a
     24 }
     25 
     26 func TestSerializeData(t *testing.T) {
     27 	t.Parallel()
     28 	r := rand.New(rand.NewSource(0))
     29 	for i := 0; i < 1e4; i++ {
     30 		data := make([]byte, r.Intn(4))
     31 		for i := range data {
     32 			data[i] = byte(r.Intn(256))
     33 		}
     34 		buf := new(bytes.Buffer)
     35 		serializeData(buf, data)
     36 		p := newParser(buf.Bytes())
     37 		if !p.Scan() {
     38 			t.Fatalf("parser does not scan")
     39 		}
     40 		data1, err := deserializeData(p)
     41 		if err != nil {
     42 			t.Fatalf("failed to deserialize %q -> %s: %v", data, buf.Bytes(), err)
     43 		}
     44 		if !bytes.Equal(data, data1) {
     45 			t.Fatalf("corrupted data %q -> %s -> %q", data, buf.Bytes(), data1)
     46 		}
     47 	}
     48 }
     49 
     50 func TestCallSet(t *testing.T) {
     51 	t.Parallel()
     52 	tests := []struct {
     53 		prog  string
     54 		ok    bool
     55 		calls []string
     56 	}{
     57 		{
     58 			"",
     59 			false,
     60 			[]string{},
     61 		},
     62 		{
     63 			"r0 =  (foo)",
     64 			false,
     65 			[]string{},
     66 		},
     67 		{
     68 			"getpid()",
     69 			true,
     70 			[]string{"getpid"},
     71 		},
     72 		{
     73 			"r11 =  getpid()",
     74 			true,
     75 			[]string{"getpid"},
     76 		},
     77 		{
     78 			"getpid()\n" +
     79 				"open(0x1, something that this package may not understand)\n" +
     80 				"getpid()\n" +
     81 				"#read()\n" +
     82 				"\n" +
     83 				"close$foo(&(0x0000) = {})\n",
     84 			true,
     85 			[]string{"getpid", "open", "close$foo"},
     86 		},
     87 	}
     88 	for i, test := range tests {
     89 		t.Run(fmt.Sprint(i), func(t *testing.T) {
     90 			calls, err := CallSet([]byte(test.prog))
     91 			if err != nil && test.ok {
     92 				t.Fatalf("parsing failed: %v", err)
     93 			}
     94 			if err == nil && !test.ok {
     95 				t.Fatalf("parsing did not fail")
     96 			}
     97 			callArray := setToArray(calls)
     98 			sort.Strings(test.calls)
     99 			if !reflect.DeepEqual(callArray, test.calls) {
    100 				t.Fatalf("got call set %+v, expect %+v", callArray, test.calls)
    101 			}
    102 		})
    103 	}
    104 }
    105 
    106 func TestCallSetRandom(t *testing.T) {
    107 	target, rs, iters := initTest(t)
    108 	for i := 0; i < iters; i++ {
    109 		p := target.Generate(rs, 10, nil)
    110 		calls0 := make(map[string]struct{})
    111 		for _, c := range p.Calls {
    112 			calls0[c.Meta.Name] = struct{}{}
    113 		}
    114 		calls1, err := CallSet(p.Serialize())
    115 		if err != nil {
    116 			t.Fatalf("CallSet failed: %v", err)
    117 		}
    118 		callArray0 := setToArray(calls0)
    119 		callArray1 := setToArray(calls1)
    120 		if !reflect.DeepEqual(callArray0, callArray1) {
    121 			t.Fatalf("got call set:\n%+v\nexpect:\n%+v", callArray1, callArray0)
    122 		}
    123 	}
    124 }
    125 
    126 func TestDeserialize(t *testing.T) {
    127 	target := initTargetTest(t, "test", "64")
    128 	tests := []struct {
    129 		input  string
    130 		output string
    131 		err    *regexp.Regexp
    132 	}{
    133 		{
    134 			input: `test$struct(&(0x7f0000000000)={0x0, {0x0}})`,
    135 		},
    136 		{
    137 			input:  `test$struct(&(0x7f0000000000)=0x0)`,
    138 			output: `test$struct(&(0x7f0000000000))`,
    139 		},
    140 		{
    141 			input: `test$regression1(&(0x7f0000000000)=[{"000000"}, {"0000000000"}])`,
    142 		},
    143 		{
    144 			input: `test$regression2(&(0x7f0000000000)=[0x1, 0x2, 0x3, 0x4, 0x5, 0x6])`,
    145 		},
    146 		{
    147 			input: `test$excessive_args1(0x0, 0x1, {0x1, &(0x7f0000000000)=[0x1, 0x2]})`,
    148 		},
    149 		{
    150 			input: `test$excessive_args2(0x0, 0x1, {0x1, &(0x7f0000000000)={0x1, 0x2}})`,
    151 		},
    152 		{
    153 			input: `test$excessive_args2(0x0, 0x1, {0x1, &(0x7f0000000000)=nil})`,
    154 		},
    155 		{
    156 			input: `test$excessive_args2(0x0, &(0x7f0000000000), 0x0)`,
    157 		},
    158 		{
    159 			input: `test$excessive_fields1(&(0x7f0000000000)={0x1, &(0x7f0000000000)=[{0x0}, 0x2]}, {0x1, 0x2, [0x1, 0x2]})`,
    160 		},
    161 		{
    162 			input:  `test$excessive_fields1(0x0)`,
    163 			output: `test$excessive_fields1(&(0x7f0000000000))`,
    164 		},
    165 		{
    166 			input:  `test$excessive_fields1(r0)`,
    167 			output: `test$excessive_fields1(&(0x7f0000000000))`,
    168 		},
    169 		{
    170 			input:  `test$excessive_args2(r1)`,
    171 			output: `test$excessive_args2(0x0)`,
    172 		},
    173 		{
    174 			input:  `test$excessive_args2({0x0, 0x1})`,
    175 			output: `test$excessive_args2(0x0)`,
    176 		},
    177 		{
    178 			input:  `test$excessive_args2([0x0], 0x0)`,
    179 			output: `test$excessive_args2(0x0)`,
    180 		},
    181 		{
    182 			input:  `test$excessive_args2(@foo)`,
    183 			output: `test$excessive_args2(0x0)`,
    184 		},
    185 		{
    186 			input:  `test$excessive_args2('foo')`,
    187 			output: `test$excessive_args2(0x0)`,
    188 		},
    189 		{
    190 			input:  `test$excessive_args2(&(0x7f0000000000)={0x0, 0x1})`,
    191 			output: `test$excessive_args2(0x0)`,
    192 		},
    193 		{
    194 			input:  `test$excessive_args2(nil)`,
    195 			output: `test$excessive_args2(0x0)`,
    196 		},
    197 		{
    198 			input:  `test$type_confusion1(&(0x7f0000000000)=@unknown)`,
    199 			output: `test$type_confusion1(&(0x7f0000000000))`,
    200 		},
    201 		{
    202 			input:  `test$type_confusion1(&(0x7f0000000000)=@unknown={0x0, 'abc'}, 0x0)`,
    203 			output: `test$type_confusion1(&(0x7f0000000000))`,
    204 		},
    205 		{
    206 			input:  `test$excessive_fields1(&(0x7f0000000000)=0x0)`,
    207 			output: `test$excessive_fields1(&(0x7f0000000000))`,
    208 		},
    209 	}
    210 	buf := make([]byte, ExecBufferSize)
    211 	for _, test := range tests {
    212 		p, err := target.Deserialize([]byte(test.input))
    213 		if err != nil {
    214 			if test.err == nil {
    215 				t.Fatalf("deserialization failed with\n%s\ndata:\n%s\n", err, test.input)
    216 			}
    217 			if !test.err.MatchString(err.Error()) {
    218 				t.Fatalf("deserialization failed with\n%s\nwhich doesn't match\n%s\ndata:\n%s",
    219 					err, test.err, test.input)
    220 			}
    221 			if test.output != "" {
    222 				t.Fatalf("both err and output are set")
    223 			}
    224 		} else {
    225 			if test.err != nil {
    226 				t.Fatalf("deserialization should have failed with:\n%s\ndata:\n%s\n",
    227 					test.err, test.input)
    228 			}
    229 			output := strings.TrimSpace(string(p.Serialize()))
    230 			if test.output != "" && test.output != output {
    231 				t.Fatalf("wrong serialized data:\n%s\nexpect:\n%s\n",
    232 					output, test.output)
    233 			}
    234 			p.SerializeForExec(buf)
    235 		}
    236 	}
    237 }
    238 
    239 func TestSerializeDeserialize(t *testing.T) {
    240 	target := initTargetTest(t, "test", "64")
    241 	tests := [][2]string{
    242 		{
    243 			`serialize0(&(0x7f0000408000)={"6861736800000000000000000000", "4849000000"})`,
    244 			`serialize0(&(0x7f0000408000)={'hash\x00', 'HI\x00'})`,
    245 		},
    246 		{
    247 			`serialize1(&(0x7f0000000000)="0000000000000000", 0x8)`,
    248 			`serialize1(&(0x7f0000000000)=""/8, 0x8)`,
    249 		},
    250 	}
    251 	for _, test := range tests {
    252 		p, err := target.Deserialize([]byte(test[0]))
    253 		if err != nil {
    254 			t.Fatal(err)
    255 		}
    256 		data := p.Serialize()
    257 		test[1] += "\n"
    258 		if string(data) != test[1] {
    259 			t.Fatalf("\ngot : %s\nwant: %s", data, test[1])
    260 		}
    261 	}
    262 }
    263 
    264 func TestSerializeDeserializeRandom(t *testing.T) {
    265 	testEachTargetRandom(t, func(t *testing.T, target *Target, rs rand.Source, iters int) {
    266 		data0 := make([]byte, ExecBufferSize)
    267 		data1 := make([]byte, ExecBufferSize)
    268 		for i := 0; i < iters; i++ {
    269 			p0 := target.Generate(rs, 10, nil)
    270 			if ok, _, _ := testSerializeDeserialize(t, p0, data0, data1); ok {
    271 				continue
    272 			}
    273 			p0, _ = Minimize(p0, -1, false, func(p1 *Prog, _ int) bool {
    274 				ok, _, _ := testSerializeDeserialize(t, p1, data0, data1)
    275 				return !ok
    276 			})
    277 			ok, n0, n1 := testSerializeDeserialize(t, p0, data0, data1)
    278 			if ok {
    279 				t.Fatal("flaky?")
    280 			}
    281 			t.Fatalf("was: %q\ngot: %q\nprogram:\n%s",
    282 				data0[:n0], data1[:n1], p0.Serialize())
    283 		}
    284 	})
    285 }
    286 
    287 func testSerializeDeserialize(t *testing.T, p0 *Prog, data0, data1 []byte) (bool, int, int) {
    288 	n0, err := p0.SerializeForExec(data0)
    289 	if err != nil {
    290 		t.Fatal(err)
    291 	}
    292 	serialized := p0.Serialize()
    293 	p1, err := p0.Target.Deserialize(serialized)
    294 	if err != nil {
    295 		t.Fatal(err)
    296 	}
    297 	n1, err := p1.SerializeForExec(data1)
    298 	if err != nil {
    299 		t.Fatal(err)
    300 	}
    301 	if !bytes.Equal(data0[:n0], data1[:n1]) {
    302 		return false, n0, n1
    303 	}
    304 	return true, 0, 0
    305 }
    306 
    307 func TestDeserializeComments(t *testing.T) {
    308 	target := initTargetTest(t, "test", "64")
    309 	p, err := target.Deserialize([]byte(`
    310 # comment1
    311 # comment2
    312 serialize0()
    313 serialize0()
    314 # comment3
    315 serialize0()
    316 # comment4
    317 serialize0()	#  comment5
    318 #comment6
    319 
    320 serialize0()
    321 #comment7
    322 `))
    323 	if err != nil {
    324 		t.Fatal(err)
    325 	}
    326 	for i, want := range []string{
    327 		"comment2",
    328 		"",
    329 		"comment3",
    330 		"comment5",
    331 		"",
    332 	} {
    333 		if got := p.Calls[i].Comment; got != want {
    334 			t.Errorf("bad call %v comment: %q, want %q", i, got, want)
    335 		}
    336 	}
    337 	wantComments := []string{
    338 		"comment1",
    339 		"comment4",
    340 		"comment6",
    341 		"comment7",
    342 	}
    343 	if !reflect.DeepEqual(p.Comments, wantComments) {
    344 		t.Errorf("bad program comments %q\nwant: %q", p.Comments, wantComments)
    345 	}
    346 }
    347