官术网_书友最值得收藏!

45.3 go-fuzz使用方法

1. 安裝go-fuzz

使用go-fuzz需要安裝兩個(gè)重要工具:go-fuzz-build和go-fuzz。通過標(biāo)準(zhǔn)go get就可以安裝它們:

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

go get會(huì)自動(dòng)將兩個(gè)工具安裝到$GOROOT/bin或$GOPATH/bin下,因此你需要確保你的Path環(huán)境變量下包含這兩個(gè)路徑。

2. 帶有模糊測試的項(xiàng)目組織

假設(shè)待測試的Go包名為foo,包源文件路徑為$GOPATH/src/github.com/bigwhite/fuzzexamples/foo。為了應(yīng)用go-fuzz為包foo建立模糊測試,我們一般會(huì)在foo下創(chuàng)建fuzz.go源文件,其內(nèi)容模板如下:

// +build gofuzz

package foo

func Fuzz(data []byte) int {
    ...
}

go-fuzz-build在構(gòu)建用于go-fuzz命令輸入的二進(jìn)制文件時(shí),會(huì)搜索帶有“+build gofuzz”指示符的Go源文件以及其中的Fuzz函數(shù)。如果foo包下沒有這樣的文件,在執(zhí)行g(shù)o-fuzz-build時(shí),你會(huì)得到類似如下的錯(cuò)誤日志:

$go-fuzz-build github.com/bigwhite/fuzzexamples/foo
failed to execute go build: exit status 2
$go-fuzz-main
/var/folders/2h/xr2tmnxx6qxc4w4w13m01fsh0000gn/T/go-fuzz-build641745751/src/go-fuzz-main/main.go:10: undefined: foo.Fuzz

有時(shí)候,待測試包的包內(nèi)功能很多,一個(gè)Fuzz函數(shù)不夠用,我們可以在fuzztest下建立多個(gè)目錄來應(yīng)對(duì):

github.com/bigwhite/fuzzexamples/foo/fuzztest]$tree
.
├── fuzz1
│   ├── corpus
│   ├── fuzz.go
│   └── gen
│       └── main.go
└── fuzz2
    ├── corpus
    ├── fuzz.go
    └── gen
        └── main.go
 ...

其中的fuzz1, fuzz2, …, fuzzN各自為一個(gè)go-fuzz單元,如果要應(yīng)用go-fuzz,則可像下面這樣執(zhí)行:

$ cd fuzz1
$ go-fuzz-build github.com/bigwhite/fuzzexamples/foo/fuzztest/fuzz1
$ go-fuzz -bin=./foo-fuzz.zip -workdir=./

...

$ cd fuzz2
$ go-fuzz-build github.com/bigwhite/fuzzexamples/foo/fuzztest/fuzz2
$ go-fuzz -bin=./foo-fuzz.zip -workdir=./

我們看到,在每個(gè)go-fuzz測試單元下有一套“固定”的目錄組合。以fuzz1目錄為例:

├── fuzz1
│   ├── corpus
│   ├── fuzz.go
│   └── gen
│       └── main.go

其中:

  • corpus為存放輸入數(shù)據(jù)語料的目錄,在go-fuzz執(zhí)行之前,可以放入初始語料;
  • fuzz.go為包含F(xiàn)uzz函數(shù)的源碼文件;
  • gen目錄中包含手工生成初始語料的main.go代碼。

在后續(xù)的示例中,我們會(huì)展示細(xì)節(jié)。

3. go-fuzz-build

go-fuzz-build會(huì)根據(jù)Fuzz函數(shù)構(gòu)建一個(gè)用于go-fuzz執(zhí)行的zip包(PACKAGENAME-fuzz.zip),包里包含了用途不同的三個(gè)文件:

cover.exe metadata sonar.exe

按照go-fuzz作者的解釋,這三個(gè)二進(jìn)制程序的功能分別如下。

  • cover.exe:被注入了代碼測試覆蓋率樁設(shè)施的二進(jìn)制文件。
  • sonar.exe:被注入了sonar統(tǒng)計(jì)樁設(shè)施的二進(jìn)制文件。
  • metadata:包含代碼覆蓋率統(tǒng)計(jì)、sonar的元數(shù)據(jù)以及一些整型、字符串字面值。

不過作為使用者,我們不必過于關(guān)心它們,點(diǎn)到為止。

4. 執(zhí)行g(shù)o-fuzz

一旦生成了foo-fuzz.zip,我們就可以執(zhí)行針對(duì)fuzz1的模糊測試。

$cd fuzz1
$go-fuzz -bin=./foo-fuzz.zip -workdir=./
2019/12/08 17:51:48 workers: 4, corpus: 8 (1s ago), crashers: 0, restarts: 1/0, execs: 0 (0/sec), cover: 0, uptime: 3s
2019/12/08 17:51:51 workers: 4, corpus: 9 (2s ago), crashers: 0, restarts: 1/3851, execs: 11553 (1924/sec), cover: 143, uptime: 6s
2019/12/08 17:51:54 workers: 4, corpus: 9 (5s ago), crashers: 0, restarts: 1/3979, execs: 47756 (5305/sec), cover: 143, uptime: 9s
...

如果corpus目錄中沒有初始語料數(shù)據(jù),那么go-fuzz也會(huì)自行生成相關(guān)數(shù)據(jù)傳遞給Fuzz函數(shù),并且采用遺傳算法,不斷基于corpus中的語料生成新的輸入語料。go-fuzz作者建議corpus初始時(shí)放入的語料越多越好,而且要有足夠的多樣性,這樣基于這些初始語料施展遺傳算法,效果才會(huì)更佳。go-fuzz在執(zhí)行過程中還會(huì)將一些新語料持久化成文件放在corpus中,以供下次模糊測試執(zhí)行時(shí)使用。

前面說過,go-fuzz執(zhí)行時(shí)是一個(gè)無限循環(huán),上面的測試需要手動(dòng)停下來。go-fuzz會(huì)在指定的workdir中創(chuàng)建另兩個(gè)目錄:crashers和suppressions。顧名思義,crashers中存放的是代碼崩潰時(shí)的相關(guān)信息,包括引起崩潰的輸入用例的二進(jìn)制數(shù)據(jù)、輸入數(shù)據(jù)的字符串形式(xxx.quoted)以及基于這個(gè)數(shù)據(jù)的輸出數(shù)據(jù)(xxx.output)。suppressions目錄中則保存著崩潰時(shí)的棧跟蹤信息,方便開發(fā)人員快速定位bug。

主站蜘蛛池模板: 上栗县| 常州市| 石河子市| 安新县| 麟游县| 即墨市| 侯马市| 合山市| 凤城市| 齐河县| 尼玛县| 尚志市| 靖远县| 溆浦县| 东丽区| 全椒县| 龙州县| 乐山市| 大埔区| 旅游| 保亭| 视频| 友谊县| 仁寿县| 萨迦县| 满洲里市| 民县| 临沭县| 灵宝市| 宁化县| 赣榆县| 洮南市| 汾西县| 广元市| 纳雍县| 遵义县| 高要市| 泗阳县| 奉化市| 平安县| 甘德县|