- Go語言精進(jìn)之路:從新手到高手的編程思想、方法和技巧(2)
- 白明
- 1110字
- 2022-01-04 17:42:24
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。
- .NET之美:.NET關(guān)鍵技術(shù)深入解析
- Mastering Entity Framework
- Practical Windows Forensics
- Mastering C# Concurrency
- UI智能化與前端智能化:工程技術(shù)、實(shí)現(xiàn)方法與編程思想
- JavaScript by Example
- 實(shí)戰(zhàn)Java高并發(fā)程序設(shè)計(jì)(第3版)
- Mastering JavaScript High Performance
- Linux:Embedded Development
- Instant Nancy Web Development
- Visual Studio 2015高級(jí)編程(第6版)
- 一本書講透Java線程:原理與實(shí)踐
- Android初級(jí)應(yīng)用開發(fā)
- JavaScript高級(jí)程序設(shè)計(jì)(第4版)
- Mastering Unity Scripting