Skip to content

Instantly share code, notes, and snippets.

@swdunlop
Created January 8, 2011 05:48
Show Gist options
  • Save swdunlop/770585 to your computer and use it in GitHub Desktop.
Save swdunlop/770585 to your computer and use it in GitHub Desktop.
A fuzzer for Go structures that uses reflection to identify and alter fields.
package blur
import "rand"
import "os"
import "reflect"
type Blurrer interface {
Blur() (interface{}, os.Error)
}
func Gen8() uint8 {
return uint8(rand.Intn(1 << 8))
}
func Gen16() uint16 {
return uint16(rand.Intn(1 << 16))
}
func Gen32() uint32 {
return uint32(rand.Int63n(1 << 32))
}
func Gen64() uint64 {
return uint64((rand.Int63() << 1)) + uint64(rand.Intn(2))
}
func Blur(x interface{}) os.Error {
return blurValue(reflect.NewValue(x))
}
func blurValue(val reflect.Value) os.Error {
if !val.CanSet() {
return nil
}
x := val.Interface()
iface, ok := x.(Blurrer)
if ok {
x, err := iface.Blur()
if err != nil {
return err
}
val.SetValue(reflect.NewValue(x))
}
switch val.Type().Kind() {
case reflect.Struct:
return blurStruct(val.(*reflect.StructValue))
case reflect.Slice:
return blurSlice(val.(*reflect.SliceValue))
case reflect.Array:
return blurArray(val.(*reflect.ArrayValue))
case reflect.Ptr:
return blurValue(val.(*reflect.PtrValue).Elem())
case reflect.Uint8:
u := val.(*reflect.UintValue)
u.Set(uint64(Gen8()))
case reflect.Uint16:
u := val.(*reflect.UintValue)
u.Set(uint64(Gen16()))
case reflect.Uint32:
u := val.(*reflect.UintValue)
u.Set(uint64(Gen32()))
case reflect.Uint64:
u := val.(*reflect.UintValue)
u.Set(uint64(Gen64()))
}
//TODO: support blurring signed
//TODO: support blurring strings
return nil
}
func blurStruct(val *reflect.StructValue) os.Error {
sz := val.NumField()
for i := 0; i < sz; i++ {
err := blurValue(val.Field(i))
if err != nil {
return err
}
}
return nil
}
func blurSlice(val *reflect.SliceValue) os.Error {
sz := val.Len()
for i := 0; i < sz; i++ {
err := blurValue(val.Elem(i))
if err != nil {
return err
}
}
return nil
}
func blurArray(val *reflect.ArrayValue) os.Error {
sz := val.Len()
for i := 0; i < sz; i++ {
err := blurValue(val.Elem(i))
if err != nil {
return err
}
}
return nil
}
package blur
import "testing"
import "fmt"
import "rand"
import "time"
type sample struct {
Alpha [8]byte
Beta uint16
Charlie uint64
}
func init() {
rand.Seed(time.Seconds())
}
func TestBlur(t *testing.T) {
var s sample
fmt.Println("BEFORE: ", s)
err := Blur(&s)
if err != nil {
t.Error(err)
}
fmt.Println("AFTER: ", s)
}
GOROOT ?= /opt/go
include $(GOROOT)/src/Make.inc
TARG=blur
GOFILES=blur.go
include $(GOROOT)/src/Make.pkg
@swdunlop
Copy link
Author

swdunlop commented Jan 8, 2011

This is useful with Go-style structure marshal libraries to produce syntactically correct but semantically random test data for fuzzing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment