1 package coverage
2
3 import (
4 "fmt"
5 "go/ast"
6 "go/parser"
7 "go/token"
8 "strconv"
9 "strings"
10
11 fuzz "github.com/AdaLogics/go-fuzz-headers"
12 )
13
14 type Walker struct {
15 args []string
16 fuzzerName string
17 fset *token.FileSet
18 src []byte
19 }
20
21
22
23 func (walker *Walker) Visit(node ast.Node) ast.Visitor {
24 if node == nil {
25 return walker
26 }
27 switch n := node.(type) {
28 case *ast.FuncDecl:
29 if n.Name.Name == walker.fuzzerName {
30 bw := &BodyWalker{
31 args: make([]string, 0),
32 fuzzerName: walker.fuzzerName,
33 fset: walker.fset,
34 src: walker.src,
35 }
36 ast.Walk(bw, n.Body)
37 walker.args = bw.args
38 }
39 }
40 return walker
41 }
42
43 type BodyWalker struct {
44 args []string
45 fuzzerName string
46 fset *token.FileSet
47 src []byte
48 }
49
50 func (walker *BodyWalker) Visit(node ast.Node) ast.Visitor {
51 if node == nil {
52 return walker
53 }
54 switch n := node.(type) {
55 case *ast.CallExpr:
56 if aa, ok := n.Fun.(*ast.SelectorExpr); ok {
57 if _, ok := aa.X.(*ast.Ident); ok {
58 if aa.X.(*ast.Ident).Name == "f" && aa.Sel.Name == "Fuzz" {
59
60
61 funcArg := n.Args[0].(*ast.FuncLit)
62
63 walker.addArgs(funcArg.Type.Params.List[1:])
64 }
65 }
66 }
67 }
68 return walker
69 }
70
71
72 func (walker *BodyWalker) addArgs(n []*ast.Field) {
73 for _, names := range n {
74 for _, _ = range names.Names {
75 if a, ok := names.Type.(*ast.ArrayType); ok {
76 walker.addArg(getArrayType(a))
77 } else {
78 walker.addArg(names.Type.(*ast.Ident).Name)
79 }
80 }
81 }
82 }
83
84 func (walker *BodyWalker) addArg(arg string) {
85 walker.args = append(walker.args, arg)
86 }
87
88 func getArrayType(n *ast.ArrayType) string {
89 typeName := n.Elt.(*ast.Ident).Name
90 return fmt.Sprintf("[]%s", typeName)
91 }
92
93 func getFuzzArgs(fuzzerFileContents, fuzzerName string) ([]string, error) {
94 fset := token.NewFileSet()
95 f, err := parser.ParseFile(fset, "fuzz_test.go", fuzzerFileContents, 0)
96 if err != nil {
97 panic(err)
98 }
99 w := &Walker{
100 args: []string{},
101 fuzzerName: fuzzerName,
102 fset: fset,
103 src: []byte(fuzzerFileContents),
104 }
105 ast.Walk(w, f)
106 return w.args, nil
107 }
108
109
110
111
112
113
114
115 func ConvertLibfuzzerSeedToGoSeed(fuzzerFileContents, testCase []byte, fuzzerName string) string {
116 args, err := getFuzzArgs(string(fuzzerFileContents), fuzzerName)
117 if err != nil {
118 panic(err)
119 }
120 newSeed := libFuzzerSeedToGoSeed(testCase, args)
121 return newSeed
122 }
123
124
125 func libFuzzerSeedToGoSeed(testcase []byte, args []string) string {
126 var b strings.Builder
127 b.WriteString("go test fuzz v1\n")
128
129 fuzzConsumer := fuzz.NewConsumer(testcase)
130 for argNumber, arg := range args {
131 fmt.Println(argNumber)
132 switch arg {
133 case "[]uint8", "[]byte":
134 randBytes, err := fuzzConsumer.GetBytes()
135 if err != nil {
136 panic(err)
137 }
138 b.WriteString(fmt.Sprintf("[]byte(\"%s\")", string(randBytes)))
139 if argNumber != len(args)-1 {
140 b.WriteString("\n")
141 }
142 case "string":
143 s, err := fuzzConsumer.GetString()
144 if err != nil {
145 panic(err)
146 }
147 b.WriteString(fmt.Sprintf("string(\"%s\")", s))
148 if argNumber != len(args)-1 {
149 b.WriteString("\n")
150 }
151 case "int":
152 randInt, err := fuzzConsumer.GetInt()
153 if err != nil {
154 panic(err)
155 }
156 b.WriteString(fmt.Sprintf("int(%s)", strconv.Itoa(randInt)))
157 if argNumber != len(args)-1 {
158 b.WriteString("\n")
159 }
160 case "int8":
161 randInt, err := fuzzConsumer.GetInt()
162 if err != nil {
163 panic(err)
164 }
165 b.WriteString(fmt.Sprintf("int8(%s)", strconv.Itoa(randInt)))
166 if argNumber != len(args)-1 {
167 b.WriteString("\n")
168 }
169 case "int16":
170 randInt, err := fuzzConsumer.GetInt()
171 if err != nil {
172 panic(err)
173 }
174 b.WriteString(fmt.Sprintf("int16(%s)", strconv.Itoa(randInt)))
175 if argNumber != len(args)-1 {
176 b.WriteString("\n")
177 }
178 case "int32":
179 randInt, err := fuzzConsumer.GetInt()
180 if err != nil {
181 panic(err)
182 }
183 b.WriteString(fmt.Sprintf("int32(%s)", strconv.Itoa(randInt)))
184 if argNumber != len(args)-1 {
185 b.WriteString("\n")
186 }
187 case "int64":
188 randInt, err := fuzzConsumer.GetInt()
189 if err != nil {
190 panic(err)
191 }
192 b.WriteString(fmt.Sprintf("int64(%s)", strconv.Itoa(randInt)))
193 if argNumber != len(args)-1 {
194 b.WriteString("\n")
195 }
196 case "uint":
197 randInt, err := fuzzConsumer.GetInt()
198 if err != nil {
199 panic(err)
200 }
201 b.WriteString(fmt.Sprintf("uint(%s)", strconv.Itoa(randInt)))
202 if argNumber != len(args)-1 {
203 b.WriteString("\n")
204 }
205 case "uint8":
206 randInt, err := fuzzConsumer.GetInt()
207 if err != nil {
208 panic(err)
209 }
210 b.WriteString(fmt.Sprintf("uint8(%s)", strconv.Itoa(randInt)))
211 if argNumber != len(args)-1 {
212 b.WriteString("\n")
213 }
214 case "uint16":
215 randInt, err := fuzzConsumer.GetUint16()
216 if err != nil {
217 panic(err)
218 }
219 b.WriteString(fmt.Sprintf("uint16(%d)", randInt))
220 if argNumber != len(args)-1 {
221 b.WriteString("\n")
222 }
223 case "uint32":
224 randInt, err := fuzzConsumer.GetUint32()
225 if err != nil {
226 panic(err)
227 }
228 b.WriteString(fmt.Sprintf("uint32(%d)", randInt))
229 if argNumber != len(args)-1 {
230 b.WriteString("\n")
231 }
232 case "uint64":
233 randInt, err := fuzzConsumer.GetUint64()
234 if err != nil {
235 panic(err)
236 }
237 b.WriteString(fmt.Sprintf("uint64(%d)", randInt))
238 if argNumber != len(args)-1 {
239 b.WriteString("\n")
240 }
241 case "rune":
242 randRune, err := fuzzConsumer.GetRune()
243 if err != nil {
244 panic(err)
245 }
246 b.WriteString(fmt.Sprintf("rune(%s)", string(randRune)))
247 if argNumber != len(args)-1 {
248 b.WriteString("\n")
249 }
250 case "float32":
251 randFloat, err := fuzzConsumer.GetFloat32()
252 if err != nil {
253 panic(err)
254 }
255 b.WriteString("float32(")
256 b.WriteString(fmt.Sprintf("%f", randFloat))
257 b.WriteString(")")
258 if argNumber != len(args)-1 {
259 b.WriteString("\n")
260 }
261 case "float64":
262 randFloat, err := fuzzConsumer.GetFloat64()
263 if err != nil {
264 panic(err)
265 }
266 b.WriteString("float64(")
267 b.WriteString(fmt.Sprintf("%f", randFloat))
268 b.WriteString(")")
269 if argNumber != len(args)-1 {
270 b.WriteString("\n")
271 }
272 case "bool":
273 randBool, err := fuzzConsumer.GetBool()
274 if err != nil {
275 panic(err)
276 }
277 b.WriteString(fmt.Sprintf("bool(%t)", randBool))
278 if argNumber != len(args)-1 {
279 b.WriteString("\n")
280 }
281 default:
282 panic("Fuzzer uses unsupported type")
283 }
284 }
285 return b.String()
286 }
287
View as plain text