/
main.go
115 lines (90 loc) · 2.15 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package main
import (
"encoding/binary"
"encoding/hex"
"flag"
"io/ioutil"
"log"
"os"
"runtime"
"github.com/Sereal/Sereal/Go/sereal"
"github.com/davecgh/go-spew/spew"
"github.com/dchest/siphash"
"github.com/dgryski/go-ddmin"
)
func sipuintptr(s []uintptr) uint64 {
b := make([]byte, len(s)*8)
for i, v := range s {
binary.LittleEndian.PutUint64(b[i*8:], uint64(v))
}
return siphash.Hash(0, 0, b)
}
func unmarshal(b []byte) (intf map[string]interface{}, crash uint64, err error) {
defer func() {
if p := recover(); p != nil {
var stack [5]uintptr
runtime.Callers(4, stack[:])
crash = sipuintptr(stack[:])
err = p.(error)
}
}()
d := sereal.Decoder{}
err = d.Unmarshal(b, &intf)
if err != nil {
return nil, 0, err
}
return intf, 0, nil
}
func process(fname string, b []byte) {
intf, _, err := unmarshal(b)
if err != nil {
switch e := err.(type) {
case sereal.ErrCorrupt:
log.Fatalf("error processing %s: %s (%s)", fname, e, e.Err)
default:
log.Fatalf("error processing %s: %s", fname, e)
}
}
spew.Dump(intf)
}
func minimize(b []byte, crashWant uint64, errWant error) []byte {
return ddmin.Minimize(b, func(b []byte) ddmin.Result {
_, crash, got := unmarshal(b)
if got == nil {
return ddmin.Pass
}
if crashWant == crash && got.Error() == errWant.Error() {
return ddmin.Fail
}
return ddmin.Unresolved
})
}
func main() {
optMinimize := flag.Bool("minimize", false, "minimize test input")
flag.Parse()
if *optMinimize {
b, _ := ioutil.ReadAll(os.Stdin)
log.Println("data to minimize length", len(b))
_, crashWant, errWant := unmarshal(b)
if errWant == nil {
log.Fatal("no error received while unmarshalling")
}
log.Printf("crash=%x errWant=%+v\n", crashWant, errWant)
m := minimize(b, crashWant, errWant)
_, crashGot, errGot := unmarshal(m)
log.Printf("crash=%x errGot=%+v\n", crashGot, errGot)
log.Println("minimized length", len(m))
log.Println("\n" + hex.Dump(m))
os.Stdout.Write(m)
return
}
if flag.NArg() == 0 {
b, _ := ioutil.ReadAll(os.Stdin)
process("stdin", b)
return
}
for _, arg := range flag.Args() {
b, _ := ioutil.ReadFile(arg)
process(arg, b)
}
}