GoFuzz模糊测试坑点
2021-05-29

Abstract

尝试使用 go fuzz 来测试程序,本文记录一下测试过程。
其中遇到了一些新鲜的点,值得记录一下。

1、国内下载安装

gofuzz 的官方安装方法如下

go get github.com/dvyukov/go-fuzz/go-fuzz
go get github.com/dvyukov/go-fuzz/go-fuzz-build

但国内服务器可能无法正常下载。
可以运行以下命令来手动安装gofuzz

cd $GOPATH/src/github.com/dvyukov/
git clone https://github.com/dvyukov/go-fuzz.git
cd go-fuzz/

go install
cd ../go-fuzz-build/
go install

2、Fuzz函数仅接收byte类型

使用gofuzz测试程序,只能将byte类型的值作为输入。

// +build gofuzz
package foo
func Fuzz(data []byte) int {
    ... ...
}

如果需要测试多参数函数,复杂类型参数的函数,需要做一些序列化。

例如,下面的代码用来测试NewMsgIssue函数。
由于Fuzz函数仅接收[]byte类型作为参数。
我们需要自己写一个receivedCorpus函数,将收到的语料data反序列化为结构体。

func Fuzz(data []byte) int {
	FuzzParam := receivedCorpus(data)
	coinIssueInfo := types.IssueParams{
		Name:               FuzzParam.Name,
		Symbol:             strings.ToUpper(FuzzParam.Symbol),
		TotalSupply:        sdk.NewInt(FuzzParam.TotalSupply),
	}
	msg := types.NewMsgIssue(sdk.AccAddress([]byte("hello")), &coinIssueInfo)
	return 0
}

上述代码中,receivedCorpus函数为了实现从语料的byte中反序列化出结构体,我使用的是第三方库gob
使用方法如下

type issueParamfuzz struct{ //要传输的测试语料
	Name string
	Symbol string
	TotalSupply int64
}

func receivedCorpus(data []byte) (issueParamfuzz,bool){
	ret := issueParamfuzz{}
	b := bytes.Buffer{}
	b.Read(data)
	dec := gob.NewDecoder(&b)
	dec.Decode(&ret)
	return ret,false
}

这里不要使用encoding/binary库,因为binary不能序列化任何引用类型或复杂类型。