前言
Go 1.18在go工具鏈裡引入了fuzzing模糊測試,可以幫助我們發現Go程式碼裡的漏洞或者可能導致程式崩潰的輸入。Go官方團隊也在官網釋出了fuzzing入門教程,幫助大家快速上手。
本人對Go官方教程在翻譯的基礎上做了一些表述上的優化,以饗讀者。
注意:fuzzing模糊測試和Go已有的單元測試以及效能測試框架是互為補充的,並不是替代關係。
教程內容
這篇教程會介紹Go fuzzing的入門基礎知識。fuzzing可以構造隨機資料來找出程式碼裡的漏洞或者可能導致程式崩潰的輸入。通過fuzzing可以找出的漏洞包括SQL隱碼攻擊、緩衝區溢位、拒絕服務(Denial of Service)攻擊和XSS(cross-site scripting)攻擊等。
在這個教程裡,你會給一個函式寫一段fuzz test(模糊測試)程式,然後執行go命令來發現程式碼裡的問題,最後通過除錯來修復問題。
本文裡涉及的專業術語,可以參考 Go Fuzzing glossary。
接下來會按照如下章節介紹:
準備工作
- 安裝Go 1.18 Beta 1或者更新的版本。安裝指引可以參考下面的介紹。
- 有一個程式碼編輯工具。任何文字編輯器都可以。
- 有一個命令列終端。Go可以執行在Linux,Mac上的任何命令列終端,也可以執行在Windows的PowerShell或者cmd之上。
- 有一個支援fuzzing的環境。目前Go fuzzing只支援AMD64和ARM64架構。
安裝和使用beta版本
這個教程需要使用Go 1.18 Beta 1或以上版本的泛型功能。使用如下步驟,安裝beta版本
使用下面的命令安裝beta版本
$ go install golang.org/dl/go1.18beta1@latest
執行如下命令來下載更新
$ go1.18beta1 download
注意:如果在MAC或者Linux上執行
go1.18beta1
提示command not found
,需要設定bash
或者zsh
對應的profile環境變數檔案。bash
設定在~/.bash_profile
檔案裡,內容為:export GOROOT=/usr/local/opt/go/libexec export GOPATH=$HOME/go export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
GOROOT
和GOPATH
的值可以通過go env
命令檢視,設定完後執行source ~/.bash_profile
讓設定生效,再執行go1.18beta1
就不報錯了。使用beta版本的go命令,不要去使用release版本的go命令
你可以通過直接使用
go1.18beta1
命令或者給go1.18beta1
起一個簡單的別名直接使用
go1.18beta1
命令$ go1.18beta1 version
給
go1.18beta1
命令起一個別名$ alias go=go1.18beta1 $ go version
下面的教程都假設你已經把
go1.18beta1
命令設定了別名go
。
為你的程式碼建立一個目錄
首先建立一個目錄用於存放你寫的程式碼。
開啟一個命令列終端,切換到你的
home
目錄在Linux或者Mac上執行如下命令(Linux或者Mac上只需要執行
cd
就可以進入到home
目錄)cd
在Windows上執行如下命令
C:\> cd %HOMEPATH%
在命令列終端,建立一個名為
fuzz
的目錄,並進入該目錄$ mkdir fuzz $ cd fuzz
建立一個go module
執行
go mod init
命令,來給你的專案設定module路徑$ go mod init example/fuzz
注意:對於生產程式碼,你可以根據專案實際情況來指定module路徑,如果想了解更多,可以參考Go Module依賴管理。
接下來,我們來使用map寫一些簡單的程式碼來做字串的反轉,然後使用fuzzing來做模糊測試。
實現一個函式
在這個章節,你需要實現一個函式來對字串做反轉。
編寫程式碼
- 開啟你的文字編輯器,在fuzz目錄下建立一個
main.go
原始檔。 在
main.go
裡編寫如下程式碼:// maing.go package main import "fmt" func Reverse(s string) string { b := []byte(s) for i, j := 0, len(b)-1; i < len(b)/2; i, j = i+1, j-1 { b[i], b[j] = b[j], b[i] } return string(b) } func main() { input := "The quick brown fox jumped over the lazy dog" rev := Reverse(input) doubleRev := Reverse(rev) fmt.Printf("original: %q\n", input) fmt.Printf("reversed: %q\n", rev) fmt.Printf("reversed again: %q\n", doubleRev) }
執行程式碼
在main.go
所在目錄執行命令go run .
來執行程式碼,結果如下:
$ go run .
original: "The quick brown fox jumped over the lazy dog"
reversed: "god yzal eht revo depmuj xof nworb kciuq ehT"
reversed again: "The quick brown fox jumped over the lazy dog"
增加單元測試
在這個章節,你會給Reverse
函式編寫單元測試程式碼。
編寫單元測試
- 在fuzz目錄下建立檔案
reverse_test.go
。 在
reverse_test.go
裡編寫如下程式碼:package main import ( "testing" ) func TestReverse(t *testing.T) { testcases := []struct { in, want string }{ {"Hello, world", "dlrow ,olleH"}, {" ", " "}, {"!12345", "54321!"}, } for _, tc := range testcases { rev := Reverse(tc.in) if rev != tc.want { t.Errorf("Reverse: %q, want %q", rev, tc.want) } } }
執行單元測試
使用go test
命令來執行單元測試
$ go test
PASS
ok example/fuzz 0.013s
接下來,我們給Reverse
函式增加模糊測試(fuzz test)程式碼。
增加模糊測試
單元測試有侷限性,每個測試輸入必須由開發者指定加到單元測試的測試用例裡。
fuzzing的優點之一是可以基於開發者程式碼裡指定的測試輸入作為基礎資料,進一步自動生成新的隨機測試資料,用來發現指定測試輸入沒有覆蓋到的邊界情況。
在這個章節,我們會把單元測試轉換成模糊測試,這樣可以更輕鬆地生成更多的測試輸入。
注意:你可以把單元測試、效能測試和模糊測試放在同一個*_test.go
檔案裡。
編寫模糊測試
在文字編輯器裡把reverse_test.go
裡的單元測試程式碼TestReverse
替換成如下的模糊測試程式碼FuzzReverse
。
func FuzzReverse(f *testing.F) {
testcases := []string{"Hello, world", " ", "!12345"}
for _, tc := range testcases {
f.Add(tc) // Use f.Add to provide a seed corpus
}
f.Fuzz(func(t *testing.T, orig string) {
rev := Reverse(orig)
doubleRev := Reverse(rev)
if orig != doubleRev {
t.Errorf("Before: %q, after: %q", orig, doubleRev)
}
if utf8.ValidString(orig) && !utf8.ValidString(rev) {
t.Errorf("Reverse produced invalid UTF-8 string %q", rev)
}
})
}
Fuzzing也有一定的侷限性。
在單元測試裡,因為測試輸入是固定的,你可以知道呼叫Reverse
函式後每個輸入字串得到的反轉字串應該是什麼,然後在單元測試的程式碼裡判斷Reverse
的執行結果是否和預期相符。例如,對於測試用例Reverse("Hello, world")
,單元測試預期的結果是 "dlrow ,olleH"
。
但是使用fuzzing時,我們沒辦法預期輸出結果是什麼,因為測試的輸入除了我們程式碼裡指定的用例之外,還有fuzzing隨機生成的。對於隨機生成的測試輸入,我們當然沒辦法提前知道輸出結果是什麼。
雖然如此,本文裡的Reverse
函式有幾個特性我們還是可以在模糊測試裡做驗證。
- 對一個字串做2次反轉,得到的結果和源字串相同
- 反轉後的字串也仍然是一個有效的UTF-8編碼的字串
注意:fuzzing模糊測試和Go已有的單元測試以及效能測試框架是互為補充的,並不是替代關係。
比如我們實現的Reverse
函式如果是一個錯誤的版本,直接return返回輸入的字串,是完全可以通過上面的模糊測試的,但是沒法通過我們前面編寫的單元測試。因此單元測試和模糊測試是互為補充的,不是替代關係。
Go模糊測試和單元測試在語法上有如下差異:
- Go模糊測試函式以FuzzXxx開頭,單元測試函式以TestXxx開頭
- Go模糊測試函式以
*testing.F
作為入參,單元測試函式以*testing.T
作為入參 Go模糊測試會呼叫
f.Add
函式和f.Fuzz
函式。f.Add
函式把指定輸入作為模糊測試的種子語料庫(seed corpus),fuzzing基於種子語料庫生成隨機輸入。f.Fuzz
函式接收一個fuzz target函式作為入參。fuzz target函式有多個引數,第一個引數是*testing.T
,其它引數是被模糊的型別(注意:被模糊的型別目前只支援部分內建型別, 列在 Go Fuzzing docs,未來會支援更多的內建型別)。
上面的FuzzReverse
函式裡用到了utf8
這個package,因此要在reverse_test.go
開頭import這個package,參考如下程式碼:
package main
import (
"testing"
"unicode/utf8"
)
執行模糊測試
執行如下命令來執行模糊測試。
這個方式只會使用種子語料庫,而不會生成隨機測試資料。通過這種方式可以用來驗證種子語料庫的測試資料是否可以測試通過。(fuzz test without fuzzing)
$ go test PASS ok example/fuzz 0.013s
如果
reverse_test.go
檔案裡有其它單元測試函式或者模糊測試函式,但是隻想執行FuzzReverse
模糊測試函式,我們可以執行go test -run=FuzzReverse
命令。注意:
go test
預設會執行所有以TestXxx
開頭的單元測試函式和以FuzzXxx
開頭的模糊測試函式,預設不執行以BenchmarkXxx
開頭的效能測試函式,如果我們想執行 benchmark用例,則需要加上-bench
引數。如果要基於種子語料庫生成隨機測試資料用於模糊測試,需要給
go test
命令增加-fuzz
引數。(fuzz test with fuzzing)$ go test -fuzz=Fuzz fuzz: elapsed: 0s, gathering baseline coverage: 0/3 completed fuzz: elapsed: 0s, gathering baseline coverage: 3/3 completed, now fuzzing with 8 workers fuzz: minimizing 38-byte failing input file... --- FAIL: FuzzReverse (0.01s) --- FAIL: FuzzReverse (0.00s) reverse_test.go:20: Reverse produced invalid UTF-8 string "\x9c\xdd" Failing input written to testdata/fuzz/FuzzReverse/af69258a12129d6cbba438df5d5f25ba0ec050461c116f777e77ea7c9a0d217a To re-run: go test -run=FuzzReverse/af69258a12129d6cbba438df5d5f25ba0ec050461c116f777e77ea7c9a0d217a FAIL exit status 1 FAIL example/fuzz 0.030s
上面的fuzzing測試結果是
FAIL
,引起FAIL
的輸入資料被寫到了一個語料庫檔案裡。下次執行go test
命令的時候,即使沒有-fuzz
引數,這個語料庫檔案裡的測試資料也會被用到。可以用文字編輯器開啟
testdata/fuzz/FuzzReverse
目錄下的檔案,看看引起Fuzzing測試失敗的測試資料長什麼樣。下面是一個示例檔案,你那邊執行後得到的測試資料可能和這個不一樣,但檔案裡的內容格式會是一樣的。go test fuzz v1 string("泃")
語料庫檔案裡的第1行標識的是編碼版本(encoding version,說直白點,就是這個種子語料庫檔案裡內容格式的版本),雖然目前只有v1這1個版本,但是Fuzzing設計者考慮到未來可能引入新的編碼版本,於是加了編碼版本的概念。
從第2行開始,每一行資料對應的是語料庫的每條測試資料(corpus entry)的其中一個引數,按照引數先後順序排列。
f.Fuzz(func(t *testing.T, orig string) { rev := Reverse(orig) doubleRev := Reverse(rev) if orig != doubleRev { t.Errorf("Before: %q, after: %q", orig, doubleRev) } if utf8.ValidString(orig) && !utf8.ValidString(rev) { t.Errorf("Reverse produced invalid UTF-8 string %q %q", orig, rev) } })
本文的
FuzzReverse
裡的fuzz target函式func(t *testing.T, orig string)
只有orig
這1個引數作為真正的測試輸入,也就是每條測試資料其實就1個輸入,因此在上面示例的testdata/fuzz/FuzzReverse
目錄下的檔案裡只有string("泃")
這一行。如果每條測試資料有N個引數,那fuzzing找出的導致fuzz test失敗的每條測試資料在
testdata
目錄下的檔案裡會有N行,第i
行對應第i
個引數。再次執行
go test
命令,這次不帶-fuzz
引數。我們會發現雖然沒有
-fuzz
引數,但是模糊測試的時候仍然用到了上面第2步找到的測試資料。$ go test --- FAIL: FuzzReverse (0.00s) --- FAIL: FuzzReverse/af69258a12129d6cbba438df5d5f25ba0ec050461c116f777e77ea7c9a0d217a (0.00s) reverse_test.go:20: Reverse produced invalid string FAIL exit status 1 FAIL example/fuzz 0.016s
既然Go fuzzing測試沒通過,那就需要我們除錯程式碼來找出問題所在了。
修復2個bug
在這個章節,我們會除錯程式,修復Go fuzzing測出來的bug。
你可以自己花一些時間思考下,先嚐試自己解決問題。
定位問題
你可以使用不同的方法來除錯上面發現的bug。
如果你使用的是VS Code,那可以在VS Code裡設定你的Debug偵錯程式來加斷點進行除錯。
本文裡,我們會使用列印日誌的方式進行除錯。
執行模糊測試時的報錯資訊為:reverse_test.go:20: Reverse produced invalid UTF-8 string "\x9c\xdd"
基於這個報錯,我們來看看文件裡對於 utf8.ValidString
的描述。
ValidString reports whether s consists entirely of valid UTF-8-encoded runes.
我們實現的Reverse
函式是按照位元組(byte)為維度進行字串反轉,這就是問題所在。
比如中文裡的字元 泃
其實是由3個位元組組成的,如果按照位元組反轉,反轉後得到的就是一個無效的字串了。
因此為了保證字串反轉後得到的仍然是一個有效的UTF-8編碼的字串,我們要按照rune
進行字串反轉。
為了更好地方便大家理解中文裡的字元 泃
按照rune
為維度有多少個rune
,以及按照byte反轉後得到的結果長什麼樣,我們對程式碼做一些修改。
編寫程式碼
按照如下方式修改FuzzReverse
裡的程式碼。
f.Fuzz(func(t *testing.T, orig string) {
rev := Reverse(orig)
doubleRev := Reverse(rev)
t.Logf("Number of runes: orig=%d, rev=%d, doubleRev=%d", utf8.RuneCountInString(orig), utf8.RuneCountInString(rev), utf8.RuneCountInString(doubleRev))
if orig != doubleRev {
t.Errorf("Before: %q, after: %q", orig, doubleRev)
}
if utf8.ValidString(orig) && !utf8.ValidString(rev) {
t.Errorf("Reverse produced invalid UTF-8 string %q", rev)
}
})
執行程式碼
$ go test
--- FAIL: FuzzReverse (0.00s)
--- FAIL: FuzzReverse/28f36ef487f23e6c7a81ebdaa9feffe2f2b02b4cddaa6252e87f69863046a5e0 (0.00s)
reverse_test.go:16: Number of runes: orig=1, rev=3, doubleRev=1
reverse_test.go:21: Reverse produced invalid UTF-8 string "\x83\xb3\xe6"
FAIL
exit status 1
FAIL example/fuzz 0.598s
我們的種子語料庫裡每個符號都是單個位元組。但是像 泃
這樣的中文符號由多個位元組組成,如果以位元組為維度進行反轉,就會得到無效的結果。
注意:如果你對於Go如何處理字串感興趣,可以閱讀官方部落格裡的這篇文章 Strings, bytes, runes and characters in Go 來加深理解。
既然我們明確了問題,那我們就可以修復這個bug了。
修復問題
以rune
為維度進行字串反轉。
編寫程式碼
修改Reverse
函式的實現如下:
func Reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
執行程式碼
執行命令:
go test
$ go test PASS ok example/fuzz 0.016s
測試通過啦!(別高興太早,這個只是通過了種子語料庫和之前)
再次執行
go test -fuzz
,看看我們是否會發現新的bug$ go test -fuzz=Fuzz fuzz: elapsed: 0s, gathering baseline coverage: 0/37 completed fuzz: minimizing 506-byte failing input file... fuzz: elapsed: 0s, gathering baseline coverage: 5/37 completed --- FAIL: FuzzReverse (0.02s) --- FAIL: FuzzReverse (0.00s) reverse_test.go:33: Before: "\x91", after: "�" Failing input written to testdata/fuzz/FuzzReverse/1ffc28f7538e29d79fce69fef20ce5ea72648529a9ca10bea392bcff28cd015c To re-run: go test -run=FuzzReverse/1ffc28f7538e29d79fce69fef20ce5ea72648529a9ca10bea392bcff28cd015c FAIL exit status 1 FAIL example/fuzz 0.032s
通過上面的報錯,我們發現對一個字串做了2次反轉後得到的和原字串不一樣。
這次測試輸入本身是非法的unicode,但是為什麼會2次反轉後得到的字串還不一樣呢?
我們繼續除錯。
修復2次字串反轉的bug
定位問題
對於這個問題,加斷點除錯會很好定位。為了方便講解,本文使用加日誌的方式進行除錯。
我們可以仔細觀察原字串第一次反轉後得到的結果來定位問題。
編寫程式碼
修改
Reverse
函式。func Reverse(s string) string { fmt.Printf("input: %q\n", s) r := []rune(s) fmt.Printf("runes: %q\n", r) for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { r[i], r[j] = r[j], r[i] } return string(r) }
這可以幫助我們理解把原字串轉成
rune
切片後發生了什麼。
執行程式碼
這一次,我們只執行讓fuzz test失敗的測試資料,使用 go test -run
命令。
執行FuzzXxx/testdata目錄下指定的語料庫測試資料,可以給-run
引數指定值 {FuzzTestName}/{filename} ,這可以讓我們聚焦在讓fuzz test失敗的測試資料上。
$ go test -run=FuzzReverse/28f36ef487f23e6c7a81ebdaa9feffe2f2b02b4cddaa6252e87f69863046a5e0
input: "\x91"
runes: ['�']
input: "�"
runes: ['�']
--- FAIL: FuzzReverse (0.00s)
--- FAIL: FuzzReverse/28f36ef487f23e6c7a81ebdaa9feffe2f2b02b4cddaa6252e87f69863046a5e0 (0.00s)
reverse_test.go:16: Number of runes: orig=1, rev=1, doubleRev=1
reverse_test.go:18: Before: "\x91", after: "�"
FAIL
exit status 1
FAIL example/fuzz 0.145s
首先我們要了解:在Go語言裡,字串是隻讀的位元組切片(In Go, a string is a read only slice of bytes),位元組切片裡的每個位元組不一定都是有效的UTF-8編碼的位元組,詳情可以參考a string is a read only slice of bytes。
上面的例子裡,輸入的字串是隻有1個byte的位元組切片,這1個byte是\x91
。
當我們把這個輸入的字串轉成[]rune
時,Go會把位元組切片編碼為UTF-8,於是就把\x91
替換成了'�','�'飯莊後還是'�',一次就導致原字串\x91
反轉後得到的字串是'�'了。
現在問題明確了,是因為輸入的資料是非法的unicode。那接下來我們就可以修正Reverse
函式的實現了。
修復問題
修復方式為:在Reverse
裡檢查輸入是否為合法的UTF-8編碼字串,如果非法,就返回eror。
編寫程式碼
修改
Reverse
實現如下:func Reverse(s string) (string, error) { if !utf8.ValidString(s) { return s, errors.New("input is not valid UTF-8") } r := []rune(s) for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { r[i], r[j] = r[j], r[i] } return string(r), nil }
由於
Reverse
函式現在會返回error,因此要修改main.go
裡的對應程式碼,修改如下:func main() { input := "The quick brown fox jumped over the lazy dog" rev, revErr := Reverse(input) doubleRev, doubleRevErr := Reverse(rev) fmt.Printf("original: %q\n", input) fmt.Printf("reversed: %q, err: %v\n", rev, revErr) fmt.Printf("reversed again: %q, err: %v\n", doubleRev, doubleRevErr) }
因為
main
函式裡都是有效的UTF-8編碼字串,所以對Reverse
的呼叫會返回一個值為nil的error。由於
Reverse
函式用到了errors
和utf8
這2個package,因此在main.go
的開頭要import這2個package。import ( "errors" "fmt" "unicode/utf8" )
同樣,我們需要修改
reverse_test.go
檔案,對於非法的字串輸入,可以直接跳過測試。func FuzzReverse(f *testing.F) { testcases := []string {"Hello, world", " ", "!12345"} for _, tc := range testcases { f.Add(tc) // Use f.Add to provide a seed corpus } f.Fuzz(func(t *testing.T, orig string) { rev, err1 := Reverse(orig) if err1 != nil { return } doubleRev, err2 := Reverse(rev) if err2 != nil { return } if orig != doubleRev { t.Errorf("Before: %q, after: %q", orig, doubleRev) } if utf8.ValidString(orig) && !utf8.ValidString(rev) { t.Errorf("Reverse produced invalid UTF-8 string %q", rev) } }) }
除了使用return,你還可以呼叫
t.Skip()
來跳過當前的測試輸入,繼續下一輪測試輸入。
執行程式碼
執行測試程式碼
$ go test PASS ok example/fuzz 0.019s
執行模糊測試
go test -fuzz=Fuzz
,執行幾秒後,使用ctrl-C
結束測試。$ go test -fuzz=Fuzz fuzz: elapsed: 0s, gathering baseline coverage: 0/38 completed fuzz: elapsed: 0s, gathering baseline coverage: 38/38 completed, now fuzzing with 4 workers fuzz: elapsed: 3s, execs: 86342 (28778/sec), new interesting: 2 (total: 35) fuzz: elapsed: 6s, execs: 193490 (35714/sec), new interesting: 4 (total: 37) fuzz: elapsed: 9s, execs: 304390 (36961/sec), new interesting: 4 (total: 37) ... fuzz: elapsed: 3m45s, execs: 7246222 (32357/sec), new interesting: 8 (total: 41) ^Cfuzz: elapsed: 3m48s, execs: 7335316 (31648/sec), new interesting: 8 (total: 41) PASS ok example/fuzz 228.000s
fuzz test如果沒有遇到錯誤,預設會一直執行下去,需要使用
ctrl-C
結束測試。也可以傳遞
-fuzztime
引數來指定測試時間,這樣就不用ctrl-C
了。指定測試時間。
go test -fuzz=Fuzz -fuzztime 30s
如果沒有遇到錯誤會執行30s後自動結束。$ go test -fuzz=Fuzz -fuzztime 30s fuzz: elapsed: 0s, gathering baseline coverage: 0/5 completed fuzz: elapsed: 0s, gathering baseline coverage: 5/5 completed, now fuzzing with 4 workers fuzz: elapsed: 3s, execs: 80290 (26763/sec), new interesting: 12 (total: 12) fuzz: elapsed: 6s, execs: 210803 (43501/sec), new interesting: 14 (total: 14) fuzz: elapsed: 9s, execs: 292882 (27360/sec), new interesting: 14 (total: 14) fuzz: elapsed: 12s, execs: 371872 (26329/sec), new interesting: 14 (total: 14) fuzz: elapsed: 15s, execs: 517169 (48433/sec), new interesting: 15 (total: 15) fuzz: elapsed: 18s, execs: 663276 (48699/sec), new interesting: 15 (total: 15) fuzz: elapsed: 21s, execs: 771698 (36143/sec), new interesting: 15 (total: 15) fuzz: elapsed: 24s, execs: 924768 (50990/sec), new interesting: 16 (total: 16) fuzz: elapsed: 27s, execs: 1082025 (52427/sec), new interesting: 17 (total: 17) fuzz: elapsed: 30s, execs: 1172817 (30281/sec), new interesting: 17 (total: 17) fuzz: elapsed: 31s, execs: 1172817 (0/sec), new interesting: 17 (total: 17) PASS ok example/fuzz 31.025s
Fuzzing測試通過!
除了
-fuzz
引數外,有幾個新的引數也被引入到了go test
命令,具體可以參考 documentation。
總結
目前你已經學會了Go fuzzing的使用方法。
接下來,你可以在自己寫過的程式碼裡,嘗試使用fuzzing來發現程式碼裡的bug。
如果你真的發現了bug,請考慮把案例提交到了trophy case。
如果你發現了Go fuzzing的任何問題或者想提feature,可以在這裡反饋file an issue。
檢視文件 go.dev/doc/fuzz瞭解更多Go Fuzzing的知識。
本文的完整程式碼參考Go Fuzzing示例程式碼。
開源地址
文章和示例程式碼開源在GitHub: Go語言初級、中級和高階教程。
公眾號:coding進階。關注公眾號可以獲取最新Go面試題和技術棧。
個人網站:Jincheng's Blog。
知乎:無忌。
References
- Fuzzing教程:https://go.dev/doc/tutorial/fuzz
- Fuzzing提案:https://github.com/golang/go/...
- Fuzzing介紹:https://go.dev/doc/fuzz/