| | |
| | |
| | |
| |
|
| | package fuzz |
| |
|
| | import ( |
| | "math" |
| | "strconv" |
| | "testing" |
| | "unicode" |
| | ) |
| |
|
| | func TestUnmarshalMarshal(t *testing.T) { |
| | var tests = []struct { |
| | desc string |
| | in string |
| | reject bool |
| | want string |
| | }{ |
| | { |
| | desc: "missing version", |
| | in: "int(1234)", |
| | reject: true, |
| | }, |
| | { |
| | desc: "malformed string", |
| | in: `go test fuzz v1 |
| | string("a"bcad")`, |
| | reject: true, |
| | }, |
| | { |
| | desc: "empty value", |
| | in: `go test fuzz v1 |
| | int()`, |
| | reject: true, |
| | }, |
| | { |
| | desc: "negative uint", |
| | in: `go test fuzz v1 |
| | uint(-32)`, |
| | reject: true, |
| | }, |
| | { |
| | desc: "int8 too large", |
| | in: `go test fuzz v1 |
| | int8(1234456)`, |
| | reject: true, |
| | }, |
| | { |
| | desc: "multiplication in int value", |
| | in: `go test fuzz v1 |
| | int(20*5)`, |
| | reject: true, |
| | }, |
| | { |
| | desc: "double negation", |
| | in: `go test fuzz v1 |
| | int(--5)`, |
| | reject: true, |
| | }, |
| | { |
| | desc: "malformed bool", |
| | in: `go test fuzz v1 |
| | bool(0)`, |
| | reject: true, |
| | }, |
| | { |
| | desc: "malformed byte", |
| | in: `go test fuzz v1 |
| | byte('aa)`, |
| | reject: true, |
| | }, |
| | { |
| | desc: "byte out of range", |
| | in: `go test fuzz v1 |
| | byte('☃')`, |
| | reject: true, |
| | }, |
| | { |
| | desc: "extra newline", |
| | in: `go test fuzz v1 |
| | string("has extra newline") |
| | `, |
| | want: `go test fuzz v1 |
| | string("has extra newline")`, |
| | }, |
| | { |
| | desc: "trailing spaces", |
| | in: `go test fuzz v1 |
| | string("extra") |
| | []byte("spacing") |
| | `, |
| | want: `go test fuzz v1 |
| | string("extra") |
| | []byte("spacing")`, |
| | }, |
| | { |
| | desc: "float types", |
| | in: `go test fuzz v1 |
| | float64(0) |
| | float32(0)`, |
| | }, |
| | { |
| | desc: "various types", |
| | in: `go test fuzz v1 |
| | int(-23) |
| | int8(-2) |
| | int64(2342425) |
| | uint(1) |
| | uint16(234) |
| | uint32(352342) |
| | uint64(123) |
| | rune('œ') |
| | byte('K') |
| | byte('ÿ') |
| | []byte("hello¿") |
| | []byte("a") |
| | bool(true) |
| | string("hello\\xbd\\xb2=\\xbc ⌘") |
| | float64(-12.5) |
| | float32(2.5)`, |
| | }, |
| | { |
| | desc: "float edge cases", |
| | |
| | |
| | |
| | |
| | |
| | |
| | in: `go test fuzz v1 |
| | float32(-0) |
| | float64(-0) |
| | float32(+Inf) |
| | float32(-Inf) |
| | float32(NaN) |
| | float64(+Inf) |
| | float64(-Inf) |
| | float64(NaN) |
| | math.Float64frombits(0x7ff8000000000002) |
| | math.Float32frombits(0x7fc00001)`, |
| | }, |
| | { |
| | desc: "int variations", |
| | |
| | |
| | |
| | |
| | in: `go test fuzz v1 |
| | int(0x0) |
| | int32(0x41) |
| | int64(0xfffffffff) |
| | uint32(0xcafef00d) |
| | uint64(0xffffffffffffffff) |
| | uint8(0b0000000) |
| | byte(0x0) |
| | byte('\000') |
| | byte('\u0000') |
| | byte('\'') |
| | math.Float64frombits(9221120237041090562) |
| | math.Float32frombits(2143289345)`, |
| | want: `go test fuzz v1 |
| | int(0) |
| | rune('A') |
| | int64(68719476735) |
| | uint32(3405705229) |
| | uint64(18446744073709551615) |
| | byte('\x00') |
| | byte('\x00') |
| | byte('\x00') |
| | byte('\x00') |
| | byte('\'') |
| | math.Float64frombits(0x7ff8000000000002) |
| | math.Float32frombits(0x7fc00001)`, |
| | }, |
| | { |
| | desc: "rune validation", |
| | in: `go test fuzz v1 |
| | rune(0) |
| | rune(0x41) |
| | rune(-1) |
| | rune(0xfffd) |
| | rune(0xd800) |
| | rune(0x10ffff) |
| | rune(0x110000) |
| | `, |
| | want: `go test fuzz v1 |
| | rune('\x00') |
| | rune('A') |
| | int32(-1) |
| | rune('�') |
| | int32(55296) |
| | rune('\U0010ffff') |
| | int32(1114112)`, |
| | }, |
| | { |
| | desc: "int overflow", |
| | in: `go test fuzz v1 |
| | int(0x7fffffffffffffff) |
| | uint(0xffffffffffffffff)`, |
| | want: func() string { |
| | switch strconv.IntSize { |
| | case 32: |
| | return `go test fuzz v1 |
| | int(-1) |
| | uint(4294967295)` |
| | case 64: |
| | return `go test fuzz v1 |
| | int(9223372036854775807) |
| | uint(18446744073709551615)` |
| | default: |
| | panic("unreachable") |
| | } |
| | }(), |
| | }, |
| | { |
| | desc: "windows new line", |
| | in: "go test fuzz v1\r\nint(0)\r\n", |
| | want: "go test fuzz v1\nint(0)", |
| | }, |
| | } |
| | for _, test := range tests { |
| | t.Run(test.desc, func(t *testing.T) { |
| | vals, err := unmarshalCorpusFile([]byte(test.in)) |
| | if test.reject { |
| | if err == nil { |
| | t.Fatalf("unmarshal unexpected success") |
| | } |
| | return |
| | } |
| | if err != nil { |
| | t.Fatalf("unmarshal unexpected error: %v", err) |
| | } |
| | newB := marshalCorpusFile(vals...) |
| | if newB[len(newB)-1] != '\n' { |
| | t.Error("didn't write final newline to corpus file") |
| | } |
| |
|
| | want := test.want |
| | if want == "" { |
| | want = test.in |
| | } |
| | want += "\n" |
| | got := string(newB) |
| | if got != want { |
| | t.Errorf("unexpected marshaled value\ngot:\n%s\nwant:\n%s", got, want) |
| | } |
| | }) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func BenchmarkMarshalCorpusFile(b *testing.B) { |
| | buf := make([]byte, 1024*1024) |
| | for i := 0; i < len(buf); i++ { |
| | buf[i] = byte(i) |
| | } |
| |
|
| | for sz := 1; sz <= len(buf); sz <<= 1 { |
| | b.Run(strconv.Itoa(sz), func(b *testing.B) { |
| | for i := 0; i < b.N; i++ { |
| | b.SetBytes(int64(sz)) |
| | marshalCorpusFile(buf[:sz]) |
| | } |
| | }) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func BenchmarkUnmarshalCorpusFile(b *testing.B) { |
| | buf := make([]byte, 1024*1024) |
| | for i := 0; i < len(buf); i++ { |
| | buf[i] = byte(i) |
| | } |
| |
|
| | for sz := 1; sz <= len(buf); sz <<= 1 { |
| | data := marshalCorpusFile(buf[:sz]) |
| | b.Run(strconv.Itoa(sz), func(b *testing.B) { |
| | for i := 0; i < b.N; i++ { |
| | b.SetBytes(int64(sz)) |
| | unmarshalCorpusFile(data) |
| | } |
| | }) |
| | } |
| | } |
| |
|
| | func TestByteRoundTrip(t *testing.T) { |
| | for x := 0; x < 256; x++ { |
| | b1 := byte(x) |
| | buf := marshalCorpusFile(b1) |
| | vs, err := unmarshalCorpusFile(buf) |
| | if err != nil { |
| | t.Fatal(err) |
| | } |
| | b2 := vs[0].(byte) |
| | if b2 != b1 { |
| | t.Fatalf("unmarshaled %v, want %v:\n%s", b2, b1, buf) |
| | } |
| | } |
| | } |
| |
|
| | func TestInt8RoundTrip(t *testing.T) { |
| | for x := -128; x < 128; x++ { |
| | i1 := int8(x) |
| | buf := marshalCorpusFile(i1) |
| | vs, err := unmarshalCorpusFile(buf) |
| | if err != nil { |
| | t.Fatal(err) |
| | } |
| | i2 := vs[0].(int8) |
| | if i2 != i1 { |
| | t.Fatalf("unmarshaled %v, want %v:\n%s", i2, i1, buf) |
| | } |
| | } |
| | } |
| |
|
| | func FuzzFloat64RoundTrip(f *testing.F) { |
| | f.Add(math.Float64bits(0)) |
| | f.Add(math.Float64bits(math.Copysign(0, -1))) |
| | f.Add(math.Float64bits(math.MaxFloat64)) |
| | f.Add(math.Float64bits(math.SmallestNonzeroFloat64)) |
| | f.Add(math.Float64bits(math.NaN())) |
| | f.Add(uint64(0x7FF0000000000001)) |
| | f.Add(math.Float64bits(math.Inf(1))) |
| | f.Add(math.Float64bits(math.Inf(-1))) |
| |
|
| | f.Fuzz(func(t *testing.T, u1 uint64) { |
| | x1 := math.Float64frombits(u1) |
| |
|
| | b := marshalCorpusFile(x1) |
| | t.Logf("marshaled math.Float64frombits(0x%x):\n%s", u1, b) |
| |
|
| | xs, err := unmarshalCorpusFile(b) |
| | if err != nil { |
| | t.Fatal(err) |
| | } |
| | if len(xs) != 1 { |
| | t.Fatalf("unmarshaled %d values", len(xs)) |
| | } |
| | x2 := xs[0].(float64) |
| | u2 := math.Float64bits(x2) |
| | if u2 != u1 { |
| | t.Errorf("unmarshaled %v (bits 0x%x)", x2, u2) |
| | } |
| | }) |
| | } |
| |
|
| | func FuzzRuneRoundTrip(f *testing.F) { |
| | f.Add(rune(-1)) |
| | f.Add(rune(0xd800)) |
| | f.Add(rune(0xdfff)) |
| | f.Add(rune(unicode.ReplacementChar)) |
| | f.Add(rune(unicode.MaxASCII)) |
| | f.Add(rune(unicode.MaxLatin1)) |
| | f.Add(rune(unicode.MaxRune)) |
| | f.Add(rune(unicode.MaxRune + 1)) |
| | f.Add(rune(-0x80000000)) |
| | f.Add(rune(0x7fffffff)) |
| |
|
| | f.Fuzz(func(t *testing.T, r1 rune) { |
| | b := marshalCorpusFile(r1) |
| | t.Logf("marshaled rune(0x%x):\n%s", r1, b) |
| |
|
| | rs, err := unmarshalCorpusFile(b) |
| | if err != nil { |
| | t.Fatal(err) |
| | } |
| | if len(rs) != 1 { |
| | t.Fatalf("unmarshaled %d values", len(rs)) |
| | } |
| | r2 := rs[0].(rune) |
| | if r2 != r1 { |
| | t.Errorf("unmarshaled rune(0x%x)", r2) |
| | } |
| | }) |
| | } |
| |
|
| | func FuzzStringRoundTrip(f *testing.F) { |
| | f.Add("") |
| | f.Add("\x00") |
| | f.Add(string([]rune{unicode.ReplacementChar})) |
| |
|
| | f.Fuzz(func(t *testing.T, s1 string) { |
| | b := marshalCorpusFile(s1) |
| | t.Logf("marshaled %q:\n%s", s1, b) |
| |
|
| | rs, err := unmarshalCorpusFile(b) |
| | if err != nil { |
| | t.Fatal(err) |
| | } |
| | if len(rs) != 1 { |
| | t.Fatalf("unmarshaled %d values", len(rs)) |
| | } |
| | s2 := rs[0].(string) |
| | if s2 != s1 { |
| | t.Errorf("unmarshaled %q", s2) |
| | } |
| | }) |
| | } |
| |
|