Skip to content

Commit c474b64

Browse files
authored
tests: Port flate fuzz test (#660)
1 parent 5d754d7 commit c474b64

File tree

5 files changed

+246
-120
lines changed

5 files changed

+246
-120
lines changed

flate/fuzz_test.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//go:build go1.18
2+
// +build go1.18
3+
4+
package flate
5+
6+
import (
7+
"bytes"
8+
"io"
9+
"strconv"
10+
"testing"
11+
12+
"github.com/klauspost/compress/internal/fuzz"
13+
)
14+
15+
func FuzzEncoding(f *testing.F) {
16+
fuzz.AddFromZip(f, "testdata/regression.zip", true, false)
17+
fuzz.AddFromZip(f, "testdata/fuzz/encode-raw-corpus.zip", true, testing.Short())
18+
fuzz.AddFromZip(f, "testdata/fuzz/FuzzEncoding.zip", false, testing.Short())
19+
// Fuzzing tweaks:
20+
const (
21+
// Test a subset of encoders.
22+
startFuzz = HuffmanOnly
23+
endFuzz = BestCompression
24+
25+
// Also tests with dictionaries...
26+
testDicts = true
27+
28+
// Max input size:
29+
maxSize = 1 << 20
30+
)
31+
decoder := NewReader(nil)
32+
buf := new(bytes.Buffer)
33+
34+
f.Fuzz(func(t *testing.T, data []byte) {
35+
if len(data) > maxSize {
36+
return
37+
}
38+
for level := startFuzz; level <= endFuzz; level++ {
39+
msg := "level " + strconv.Itoa(level) + ":"
40+
buf.Reset()
41+
fw, err := NewWriter(buf, level)
42+
if err != nil {
43+
t.Fatal(msg + err.Error())
44+
}
45+
n, err := fw.Write(data)
46+
if n != len(data) {
47+
t.Fatal(msg + "short write")
48+
}
49+
if err != nil {
50+
t.Fatal(msg + err.Error())
51+
}
52+
err = fw.Close()
53+
if err != nil {
54+
t.Fatal(msg + err.Error())
55+
}
56+
decoder.(Resetter).Reset(buf, nil)
57+
data2, err := io.ReadAll(decoder)
58+
if err != nil {
59+
t.Fatal(msg + err.Error())
60+
}
61+
if !bytes.Equal(data, data2) {
62+
t.Fatal(msg + "not equal")
63+
}
64+
// Do it again...
65+
msg = "level " + strconv.Itoa(level) + " (reset):"
66+
buf.Reset()
67+
fw.Reset(buf)
68+
n, err = fw.Write(data)
69+
if n != len(data) {
70+
t.Fatal(msg + "short write")
71+
}
72+
if err != nil {
73+
t.Fatal(msg + err.Error())
74+
}
75+
err = fw.Close()
76+
if err != nil {
77+
t.Fatal(msg + err.Error())
78+
}
79+
decoder.(Resetter).Reset(buf, nil)
80+
data2, err = io.ReadAll(decoder)
81+
if err != nil {
82+
t.Fatal(msg + err.Error())
83+
}
84+
if !bytes.Equal(data, data2) {
85+
t.Fatal(msg + "not equal")
86+
}
87+
}
88+
89+
// Split into two and use history...
90+
buf.Reset()
91+
err := StatelessDeflate(buf, data[:len(data)/2], false, nil)
92+
if err != nil {
93+
t.Error(err)
94+
}
95+
96+
// Use top half as dictionary...
97+
dict := data[:len(data)/2]
98+
err = StatelessDeflate(buf, data[len(data)/2:], true, dict)
99+
if err != nil {
100+
t.Error(err)
101+
}
102+
103+
decoder.(Resetter).Reset(buf, nil)
104+
data2, err := io.ReadAll(decoder)
105+
if err != nil {
106+
t.Error(err)
107+
}
108+
if !bytes.Equal(data, data2) {
109+
//fmt.Printf("want:%x\ngot: %x\n", data1, data2)
110+
t.Error("not equal")
111+
}
112+
})
113+
}
1 MB
Binary file not shown.
667 KB
Binary file not shown.

internal/fuzz/helpers.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//go:build go1.18
2+
// +build go1.18
3+
4+
package fuzz
5+
6+
import (
7+
"archive/zip"
8+
"bytes"
9+
"fmt"
10+
"go/ast"
11+
"go/parser"
12+
"go/token"
13+
"io"
14+
"os"
15+
"strconv"
16+
"testing"
17+
)
18+
19+
// AddFromZip will read the supplied zip and add all as corpus for f.
20+
func AddFromZip(f *testing.F, filename string, raw, short bool) {
21+
file, err := os.Open(filename)
22+
if err != nil {
23+
f.Fatal(err)
24+
}
25+
fi, err := file.Stat()
26+
if err != nil {
27+
f.Fatal(err)
28+
}
29+
zr, err := zip.NewReader(file, fi.Size())
30+
if err != nil {
31+
f.Fatal(err)
32+
}
33+
for i, file := range zr.File {
34+
if short && i%10 != 0 {
35+
continue
36+
}
37+
rc, err := file.Open()
38+
if err != nil {
39+
f.Fatal(err)
40+
}
41+
42+
b, err := io.ReadAll(rc)
43+
if err != nil {
44+
f.Fatal(err)
45+
}
46+
rc.Close()
47+
raw := raw
48+
if bytes.HasPrefix(b, []byte("go test fuzz")) {
49+
raw = false
50+
}
51+
if raw {
52+
f.Add(b)
53+
continue
54+
}
55+
vals, err := unmarshalCorpusFile(b)
56+
if err != nil {
57+
f.Fatal(err)
58+
}
59+
for _, v := range vals {
60+
f.Add(v)
61+
}
62+
}
63+
}
64+
65+
// unmarshalCorpusFile decodes corpus bytes into their respective values.
66+
func unmarshalCorpusFile(b []byte) ([][]byte, error) {
67+
if len(b) == 0 {
68+
return nil, fmt.Errorf("cannot unmarshal empty string")
69+
}
70+
lines := bytes.Split(b, []byte("\n"))
71+
if len(lines) < 2 {
72+
return nil, fmt.Errorf("must include version and at least one value")
73+
}
74+
var vals = make([][]byte, 0, len(lines)-1)
75+
for _, line := range lines[1:] {
76+
line = bytes.TrimSpace(line)
77+
if len(line) == 0 {
78+
continue
79+
}
80+
v, err := parseCorpusValue(line)
81+
if err != nil {
82+
return nil, fmt.Errorf("malformed line %q: %v", line, err)
83+
}
84+
vals = append(vals, v)
85+
}
86+
return vals, nil
87+
}
88+
89+
// parseCorpusValue
90+
func parseCorpusValue(line []byte) ([]byte, error) {
91+
fs := token.NewFileSet()
92+
expr, err := parser.ParseExprFrom(fs, "(test)", line, 0)
93+
if err != nil {
94+
return nil, err
95+
}
96+
call, ok := expr.(*ast.CallExpr)
97+
if !ok {
98+
return nil, fmt.Errorf("expected call expression")
99+
}
100+
if len(call.Args) != 1 {
101+
return nil, fmt.Errorf("expected call expression with 1 argument; got %d", len(call.Args))
102+
}
103+
arg := call.Args[0]
104+
105+
if arrayType, ok := call.Fun.(*ast.ArrayType); ok {
106+
if arrayType.Len != nil {
107+
return nil, fmt.Errorf("expected []byte or primitive type")
108+
}
109+
elt, ok := arrayType.Elt.(*ast.Ident)
110+
if !ok || elt.Name != "byte" {
111+
return nil, fmt.Errorf("expected []byte")
112+
}
113+
lit, ok := arg.(*ast.BasicLit)
114+
if !ok || lit.Kind != token.STRING {
115+
return nil, fmt.Errorf("string literal required for type []byte")
116+
}
117+
s, err := strconv.Unquote(lit.Value)
118+
if err != nil {
119+
return nil, err
120+
}
121+
return []byte(s), nil
122+
}
123+
return nil, fmt.Errorf("expected []byte")
124+
}

0 commit comments

Comments
 (0)