@@ -22,33 +22,31 @@ import (
22
22
"strings"
23
23
"testing"
24
24
25
- "github.com/ethereum/go-ethereum/accounts/abi"
26
25
fuzz "github.com/google/gofuzz"
27
26
)
28
27
29
28
// TestReplicate can be used to replicate crashers from the fuzzing tests.
30
29
// Just replace testString with the data in .quoted
31
30
func TestReplicate (t * testing.T ) {
32
- testString := " \x20 \x20 \x20 \x20 \x20 \x20 \x20 \x20 \x80 \x00 \x00 \x00 \x20 \x20 \x20 \x20 \x00 "
33
- data := []byte (testString )
34
- fuzzAbi (data )
31
+ //t.Skip("Test only useful for reproducing issues")
32
+ fuzzAbi ( []byte (" \x20 \x20 \x20 \x20 \x20 \x20 \x20 \x20 \x80 \x00 \x00 \x00 \x20 \x20 \x20 \x20 \x00 " ) )
33
+ // fuzzAbi([]byte("asdfasdfkadsf;lasdf;lasd;lfk") )
35
34
}
36
35
37
- func Fuzz (f * testing.F ) {
36
+ // FuzzABI is the main entrypoint for fuzzing
37
+ func FuzzABI (f * testing.F ) {
38
38
f .Fuzz (func (t * testing.T , data []byte ) {
39
39
fuzzAbi (data )
40
40
})
41
41
}
42
42
43
43
var (
44
- names = []string {"_name" , "name" , "NAME" , "name_" , "__" , "_name_" , "n" }
45
- stateMut = []string {"" , "pure" , "view" , "payable" }
46
- stateMutabilites = []* string {& stateMut [0 ], & stateMut [1 ], & stateMut [2 ], & stateMut [3 ]}
47
- pays = []string {"" , "true" , "false" }
48
- payables = []* string {& pays [0 ], & pays [1 ]}
49
- vNames = []string {"a" , "b" , "c" , "d" , "e" , "f" , "g" }
50
- varNames = append (vNames , names ... )
51
- varTypes = []string {"bool" , "address" , "bytes" , "string" ,
44
+ names = []string {"_name" , "name" , "NAME" , "name_" , "__" , "_name_" , "n" }
45
+ stateMut = []string {"pure" , "view" , "payable" }
46
+ pays = []string {"true" , "false" }
47
+ vNames = []string {"a" , "b" , "c" , "d" , "e" , "f" , "g" }
48
+ varNames = append (vNames , names ... )
49
+ varTypes = []string {"bool" , "address" , "bytes" , "string" ,
52
50
"uint8" , "int8" , "uint8" , "int8" , "uint16" , "int16" ,
53
51
"uint24" , "int24" , "uint32" , "int32" , "uint40" , "int40" , "uint48" , "int48" , "uint56" , "int56" ,
54
52
"uint64" , "int64" , "uint72" , "int72" , "uint80" , "int80" , "uint88" , "int88" , "uint96" , "int96" ,
62
60
"bytes32" , "bytes" }
63
61
)
64
62
65
- func unpackPack (abi abi. ABI , method string , input []byte ) ([]interface {}, bool ) {
63
+ func unpackPack (abi ABI , method string , input []byte ) ([]interface {}, bool ) {
66
64
if out , err := abi .Unpack (method , input ); err == nil {
67
65
_ , err := abi .Pack (method , out ... )
68
66
if err != nil {
@@ -78,7 +76,7 @@ func unpackPack(abi abi.ABI, method string, input []byte) ([]interface{}, bool)
78
76
return nil , false
79
77
}
80
78
81
- func packUnpack (abi abi. ABI , method string , input * []interface {}) bool {
79
+ func packUnpack (abi ABI , method string , input * []interface {}) bool {
82
80
if packed , err := abi .Pack (method , input ); err == nil {
83
81
outptr := reflect .New (reflect .TypeOf (input ))
84
82
err := abi .UnpackIntoInterface (outptr .Interface (), method , packed )
@@ -94,12 +92,12 @@ func packUnpack(abi abi.ABI, method string, input *[]interface{}) bool {
94
92
return false
95
93
}
96
94
97
- type args struct {
95
+ type arg struct {
98
96
name string
99
97
typ string
100
98
}
101
99
102
- func createABI (name string , stateMutability , payable * string , inputs []args ) (abi. ABI , error ) {
100
+ func createABI (name string , stateMutability , payable * string , inputs []arg ) (ABI , error ) {
103
101
sig := fmt .Sprintf (`[{ "type" : "function", "name" : "%v" ` , name )
104
102
if stateMutability != nil {
105
103
sig += fmt .Sprintf (`, "stateMutability": "%v" ` , * stateMutability )
@@ -126,56 +124,55 @@ func createABI(name string, stateMutability, payable *string, inputs []args) (ab
126
124
sig += "} ]"
127
125
}
128
126
sig += `}]`
129
-
130
- return abi . JSON (strings .NewReader (sig ))
127
+ //fmt.Printf("sig: %s\n", sig)
128
+ return JSON (strings .NewReader (sig ))
131
129
}
132
130
133
- func fuzzAbi (input []byte ) int {
134
- good := false
135
- fuzzer := fuzz .NewFromGoFuzz (input )
136
-
137
- name := names [getUInt (fuzzer )% len (names )]
138
- stateM := stateMutabilites [getUInt (fuzzer )% len (stateMutabilites )]
139
- payable := payables [getUInt (fuzzer )% len (payables )]
140
- maxLen := 5
141
- for k := 1 ; k < maxLen ; k ++ {
142
- var arg []args
143
- for i := k ; i > 0 ; i -- {
144
- argName := varNames [i ]
145
- argTyp := varTypes [getUInt (fuzzer )% len (varTypes )]
146
- if getUInt (fuzzer )% 10 == 0 {
147
- argTyp += "[]"
148
- } else if getUInt (fuzzer )% 10 == 0 {
149
- arrayArgs := getUInt (fuzzer )% 30 + 1
150
- argTyp += fmt .Sprintf ("[%d]" , arrayArgs )
151
- }
152
- arg = append (arg , args {
153
- name : argName ,
154
- typ : argTyp ,
155
- })
131
+ func fuzzAbi (input []byte ) {
132
+ var (
133
+ fuzzer = fuzz .NewFromGoFuzz (input )
134
+ name = oneOf (fuzzer , names )
135
+ stateM = oneOfOrNil (fuzzer , stateMut )
136
+ payable = oneOfOrNil (fuzzer , pays )
137
+ arguments []arg
138
+ )
139
+ for i := 0 ; i < upTo (fuzzer , 10 ); i ++ {
140
+ argName := oneOf (fuzzer , varNames )
141
+ argTyp := oneOf (fuzzer , varTypes )
142
+ switch upTo (fuzzer , 10 ) {
143
+ case 0 : // 10% chance to make it a slice
144
+ argTyp += "[]"
145
+ case 1 : // 10% chance to make it an array
146
+ argTyp += fmt .Sprintf ("[%d]" , 1 + upTo (fuzzer , 30 ))
147
+ default :
156
148
}
157
- abi , err := createABI (name , stateM , payable , arg )
158
- if err != nil {
159
- continue
160
- }
161
- structs , b := unpackPack (abi , name , input )
162
- c := packUnpack (abi , name , & structs )
163
- good = good || b || c
149
+ arguments = append (arguments , arg {name : argName , typ : argTyp })
164
150
}
165
- if good {
166
- return 1
151
+ abi , err := createABI (name , stateM , payable , arguments )
152
+ if err != nil {
153
+ //fmt.Printf("err: %v\n", err)
154
+ panic (err )
167
155
}
168
- return 0
156
+ structs , _ := unpackPack (abi , name , input )
157
+ _ = packUnpack (abi , name , & structs )
169
158
}
170
159
171
- func getUInt (fuzzer * fuzz.Fuzzer ) int {
160
+ func upTo (fuzzer * fuzz.Fuzzer , max int ) int {
172
161
var i int
173
162
fuzzer .Fuzz (& i )
174
163
if i < 0 {
175
- i = - i
176
- if i < 0 {
177
- return 0
178
- }
164
+ return (- 1 - i ) % max
165
+ }
166
+ return i % max
167
+ }
168
+
169
+ func oneOf (fuzzer * fuzz.Fuzzer , options []string ) string {
170
+ return options [upTo (fuzzer , len (options ))]
171
+ }
172
+
173
+ func oneOfOrNil (fuzzer * fuzz.Fuzzer , options []string ) * string {
174
+ if i := upTo (fuzzer , len (options )+ 1 ); i < len (options ) {
175
+ return & options [i ]
179
176
}
180
- return i
177
+ return nil
181
178
}
0 commit comments