Tutorial ini memperkenalkan dasar-dasar dari fuzzing pada Go. Dengan fuzzing, data acak dijalankan pada tes dengan tujuan menemukan celah keamanan atau input yang menyebabkan program berhenti. Beberapa contoh celah keamanan yang dapat ditemukan oleh fuzzing yaitu serangan injeksi SQL, buffer overflow, denial of service, dan cross-site scripting.
Dalam tutorial ini, kita akan menulis sebuah pengujian fuzz untuk sebuah fungsi sederhana, mempelajari perintah-perintah go test untuk fuzzing, dan mencari dan memperbaiki isu-isu yang ditemukan fuzz tes.
Untuk informasi lebih lanjut tentang terminologi dalam tutorial ini, lihatlah glosarium Go Fuzzing.
Kita akan mempelajari beberapa bagian-bagian berikut,
|
Note
|
Untuk tutorial lainnya, lihat Tutorial. |
|
Note
|
Saat ini fuzzing pada Go hanya mendukung sebagian dari tipe-tipe bawaan, yang terdaftar di dokumentasi Go Fuzzing, dukungan tipe bawaan lainnya akan ditambahkan di masa depan. |
Kebutuhan
-
Pemasangan Go 1.18 atau versi terbaru. Untuk instruksi pemasangan, lihat Memasang Go.
-
Perkakas untuk menyunting kode.
-
Terminal perintah. Go bekerja pada terminal apa pun di Linux dan Mac, dan PowerShell atau cmd pada Windows.
-
Sistem yang mendukung fuzzing. Fuzzing pada Go dengan instrumentasi cakupan saat ini hanya tersedia pada arsitektur AMD64 dan ARM64.
Membuat direktori penyimpanan kode
Untuk memulai, buatlah sebuah direktori tempat berkas kode akan disimpan,
-
Buka terminal dan pindah ke direktori pengguna Anda,
Pada Linux atau Mac:
$ cd
Pada Windows:
C:\> cd %HOMEPATH%
Selanjutnya pada tutorial ini, penulisan
$ditandai sebagai prompt pada terminal. Perintah yang digunakan pada prompt tersebut bisa berjalan di Windows. -
Dari terminal, buat sebuah direktori untuk kode Anda yang diberi nama
fuzz.$ mkdir fuzz $ cd fuzz
-
Buatlah sebuah Go modul untuk menyimpan kode Anda.
Jalankan perintah
go mod init, dengan menambahkan path ke modul kode Anda.$ go mod init example/fuzz go: creating new go.mod: module example/fuzz
NoteUntuk kode tingkat lanjut, Anda sebaiknya menamakan path modul yang lebih spesifik sesuai kebutuhan Anda. Untuk informasi lebih lanjut lihat Manajemen dependensi.
Selanjutnya, kita akan menambahkan fungsi sederhana untuk membalikan sebuah string, yang akan kita fuzz tes nantinya.
Menambahkan kode yang akan dites
Pada langkah ini, kita akan membuat sebuah fungsi untuk membalikan sebuah string.
Menulis kode
-
Menggunakan perkakas sunting, buat sebuah berkas bernama
main.godi dalam direktori fuzz. -
Di dalam
main.go, salin lah deklarasi paket berikutpackage main
Sebuah program (bukan sebuah pustaka) selalu dibuat dengan paket
main. -
Di bawah deklarasi paket, salin deklarasi fungsi berikut.
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) }Fungsi ini menerima sebuah string
s, melakukan pengulangan per tiapbytedari strings, dan mengembalikan sebuah string yang terbalik.NoteKode ini berdasarkan fungsi stringutil.Reverseyang ada di dalam golang.org/x/example. -
Pada bagian selanjutnya, salin fungsi
mainberikut yang menginisialisasi sebuah stringinput, membalikkan isinya, mencetaknya, dan membalikkan isinya lagi.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) }Fungsi ini akan menjalankan operasi
Reverse, mencetak hasilnya ke terminal. Hal ini berguna untuk melihat operasi dari kode dan juga untuk memeriksa hasilnya. -
Fungsi
mainmenggunakan paketfmt, jadi kita harus mengimpornya.Baris-baris awal pada
main.gomenjadi seperti berikut,package main import "fmt"
Jalankan kode
Dari terminal, masih di dalam direktori yang berisi main.go, jalankan kode
dengan cara berikut
$ 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"
Kita dapat melihat string asli, hasil dari pembalikan, dan hasil dari pembalikan kedua kalinya, yang seharusnya sama dengan yang asli.
Setelah kode berjalan, saatnya untuk membuat unit tes.
Menambahkan unit tes
Pada langkah ini, kita akan menulis sebuah unit tes sederhana untuk fungsi
Reverse.
Menulis kode
-
Menggunakan perkakas sunting, buat sebuah berkas bernama
reverse_test.godi dalam direktorifuzz. -
Salin kode berikut ke dalam berkas
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) } } }Kode tes tersebut akan memeriksa bahwa daftar string input akan secara benar terbalik.
Menambahkan fuzz tes
Unit tes memiliki batasan, setiap input harus ditambahkan secara manual ke dalam tes kode. Salah satu kelebihan dari fuzzing yaitu ia menemukan dan menambahkan input ke dalam tes kode secara otomatis, dan bisa menemukan kasus-kasus khusus yang mana tidak terpikirkan pada unit tes biasa.
Pada bagian ini kita akan mengonversi unit tes menjadi fuzz tes supaya kita dapat memiliki input pengujian lebih banyak dengan sedikit bekerja!
Ingatlah bahwa kita bisa menyimpan kode unit tes, benchmark, dan fuzz tes
di dalam berkas *_test.go yang sama, namun untuk contoh ini kita akan
mengonversi unit tes menjadi fuzz tes.
Menulis kode fuzz tes
Pada perkakas sunting Anda, timpa unit tes di dalam reverse_test.go dengan
fuzz tes berikut.
func FuzzReverse(f *testing.F) {
testcases := []string{"Hello, world", " ", "!12345"}
for _, tc := range testcases {
f.Add(tc) // Penambahan input ke bibit 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 juga memiliki beberapa batasan.
Pada unit tes, kita bisa memprediksi ekspektasi keluaran dari fungsi
Reverse, dan memverifikasi bahwa keluaran sama dengan ekspektasi.
Contohnya, pada kasus Reverse("Hello, world"), kita dapat menentukan
ekspektasi keluaran sebagai "dlrow ,olleH".
Pada fuzzing, kita tidak dapat memprediksi ekspektasi keluaran, secara kita tidak punya kontrol terhadap input.
Namun, ada beberapa properti dari fungsi Reverse yang dapat kita verifikasi
dalam fuzz tes.
Dua properti yang kita cek dalam fuzz tes adalah:
-
Membalikan sebuah string dua kali akan mengeluarkan string aslinya.
-
String yang terbalik adalah UTF-8 yang valid.
Perhatikan perbedaan sintaksis antara unit tes dan fuzz tes:
-
Fungsi dimulai dengan
FuzzXxxbukanTestXxx, dan menerima*testing.Fbukan*testing.T. -
Di unit tes kita menggunakan
t.Run, di fuzz tes kita menggunakanf.Fuzzyang menerima sebuah fungsi target dengan parameter*testing.Tdan tipe-tipe yang akan di-fuzz. Input-input dari unit tes diberikan sebagai bibit corpus menggunakanf.Add.
Selanjutnya, pastikan paket unicode/utf8 telah diimpor.
package main import ( "testing" "unicode/utf8" )
Dengan unit tes yang telah dikonversi menjadi fuzz tes, saatnya kita jalankan kembali pengujian.
Menjalankan tes
-
Jalankan fuzz tes tanpa opsi fuzzing untuk memastikan bibit input benar.
$ go test PASS ok example/fuzz 0.013s
Kita juga dapat menjalankan dengan cara
go test -run=Fuzzjika ada unit tes lain di dalam berkas namun kita ingin hanya menjalankan fuzz tes. -
Jalankan
FuzzReversedengan fuzzing, untuk melihat apakah string input yang dihasilkan secara acak akan menyebabkan kegagalan.Caranya yaitu dengan mengeksekusi
go testdengan opsi-fuzzdan parameterFuzz. Salin perintah berikut ke terminal,$ go test -fuzz=Fuzz
Opsi fuzzing lain yang berguna yaitu
-fuzztime, yang membatasi waktu berjalannya sebuah fuzz tes. Contohnya, menggunakan opsi-fuzztime 10sberarti selama tidak ada kesalahan terjadi, fuzz tes akan berhenti setelah 10 detik. Lihat bagian opsi testing dari dokumentasi "cmd/go" untuk mengetahui lebih lanjut tentang opsi-opsi pengujian.Sekarang jalankan perintah tersebut,
$ 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/af69258a12129d6c To re-run: go test -run=FuzzReverse/af69258a12129d6c FAIL exit status 1 FAIL example/fuzz 0.030sSebuah kegagalan terjadi selama fuzzing, dan input yang menyebabkan kegagalan tersebut ditulis ke dalam berkas bibit corpus yang akan dijalankan kembali saat
go testdieksekusi, walaupun tanpa opsi-fuzz. Untuk melihat input yang menyebabkan kegagalan, bukalah berkas yang ada di dalam direktori "testdata/fuzz/FuzzReverse/". Berkas bibit corpus Anda bisa jadi berbeda, namun formatnya akan sama.go test fuzz v1 string("泃")Baris pertama dari berkas corpus mengindikasikan versi fuzz tes. Baris selanjutnya merepresentasikan nilai dari setiap tipe yang digunakan sebagai parameter saat mem-fuzzing fungsi target
FuzzReverse. Secara fungsi target hanya menerima 1 input, maka hanya ada 1 nilai. -
Jalankan lagi
go testtanpa opsi-fuzz; maka isi di dalam bibit corpus akan secara otomatis digunakan:$ go test --- FAIL: FuzzReverse (0.00s) --- FAIL: FuzzReverse/af69258a12129d6c (0.00s) reverse_test.go:20: Reverse produced invalid UTF-8 string "\x9c\xdd" FAIL exit status 1 FAIL example/fuzz 0.016sSecara tes kita sudah gagal, saatnya melakukan pemeriksaan dan memperbaiki kode.
Memperbaiki kesalahan karena string tidak valid
Pada bagian ini, kita akan memeriksa penyebab dari kesalahan string tidak valid dan memperbaikinya.
Anda bisa mencoba memeriksa dan memperbaikinya sendiri terlebih dahulu sebelum lanjut ke bagian selanjutnya.
Diagnosis kesalahan
Ada beberapa cara untuk mendiagnosis kesalahan pada kode. Jika Anda menggunakan perkakas VS Code, Anda dapat mengatur debugger untuk menginvestigasinya.
Pada tutorial ini, kita akan memeriksa kode dengan menulis hasil ke terminal.
Pertama, perhatikan dokumentasi dari
utf8.ValidString.
ValidString reports whether s consists entirely of valid UTF-8-encoded runes.
Fungsi Reverse yang sekarang membalikan string secara per-byte, dan
disanalah letak kesalahan kita.
Untuk menjaga string tetap valid pada UTF-8, kita harus membalikan string
per-rune.
Untuk memeriksa kenapa input (pada kasus ini, karakter China 泃) menyebabkan
fungsi Reverse menghasilkan string tidak valid saat dibalik, kita dapat
memeriksa jumlah rune di dalam string yang telah dibalik.
Menulis kode
Dalam perkakas sunting Anda, timpa target fuzz FuzzReverse dengan kode
berikut.
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)
}
})
Baris t.Logf akan mencetak ke terminal bila kesalahan terjadi, atau bila
menjalankan tes dengan opsi -v, yang dapat membantu mendiagnosis kesalahan.
Menjalankan tes
Jalankan tes dengan go test
$ go test
--- FAIL: FuzzReverse (0.00s)
--- FAIL: FuzzReverse/af69258a12129d6c (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
Seluruh bibit corpus berisi string yang mana setiap karakter adalah
sebuah byte, sehingga apabila dibalik hasilnya sesuai dengan yang kita
bayangkan.
Namun, karakter 泃 membutuhkan beberapa byte.
Maka, membalikannya satu per satu per-byte akan menyebabkan string tidak
valid.
|
Note
|
Jika Anda penasaran bagaimana Go memperlakukan string, bacalah blog String, byte, rune, dan karakter dalam Go untuk memahami lebih lanjut. |
Dengan lebih memahami kesalahan yang terjadi, mari kita dapat memperbaiki
fungsi Reverse.
Memperbaiki kesalahan
Untuk memperbaiki fungsi Reverse, kita lakukan pengulangan pada string
dengan cara per-rune bukan per-byte.
Menulis kode
Pada perkakas sunting, timpa fungsi Reverse dengan kode berikut.
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)
}
Kunci perbedaannya yaitu fungsi Reverse yang baru diiterasi untuk setiap
rune pada string, bukan setiap byte.
Ingatlah bahwa ini hanyalah contoh saja, fungsi ini tidak menangani kasus
karakter kombinasi
secara benar.
Jalankan kode
-
Jalankan tes menggunakan
go test$ go test PASS ok example/fuzz 0.016s
Tes sekarang berjalan dengan benar!
-
Jalankan fuzz tes kembali dengan
go test -fuzz, untuk melihat apakah ada kecacatan baru.$ go test -fuzz=Fuzz fuzz: elapsed: 0s, gathering baseline coverage: 0/10 completed fuzz: minimizing 49-byte failing input file fuzz: elapsed: 0s, gathering baseline coverage: 6/10 completed --- FAIL: FuzzReverse (0.00s) --- FAIL: FuzzReverse (0.00s) reverse_test.go:16: Number of runes: orig=1, rev=1, doubleRev=1 reverse_test.go:20: Before: "\x8d", after: "�" Failing input written to testdata/fuzz/FuzzReverse/4e4e4dc480dc461c To re-run: go test -run=FuzzReverse/4e4e4dc480dc461c FAIL exit status 1 FAIL example/fuzz 0.005sKita dapat lihat bahwa hasil string terakhir berbeda dari yang aslinya setelah dibalikkan dua kali. Kecacatan ini disebabkan oleh input dengan unicode tidak valid. Bagaimana ini bisa terjadi?
Mari kita periksa kembali.
Memperbaiki kesalahan pada pembalikan dua kali
Pada bagian ini, kita akan memerikan kesalahan karena pembalikan dua kali dan memperbaikinya.
Anda bisa memeriksa dan memperbaikinya sendiri terlebih dahulu sebelum lanjut ke bagian selanjutnya.
Diagnosis kesalahan
Seperti sebelumnya, ada beberapa cara untuk mendiagnosis kesalahan ini. Pada kasus ini, menggunakan debugger adalah pendekatan yang lebih baik.
Dalam tutorial ini, kita akan mendiagnosis dengan menulis informasi yang diperlukan ke terminal.
Perhatikan secara seksama pada hasil string terbalik yang pertama untuk
menemukan kesalahan yang terjadi.
Pada Go,
sebuah string adalah rangkaian byte-byte read-only
dan dapat berisi byte yang tidak valid dalam UTF-8.
String input berisi satu byte, "\x8d".
Saat input string dikonversi menjadi []rune, Go mengubah rangkaian byte
menjadi UTF-8, dan menimpa byte "\8d" menjadi karakter "�".
Saat kita membandingkan karakter UTF-8 yang telah dibalikan lagi dengan
rangkaian input byte, mereka tidak akan sama.
Menulis kode
Pada perkakas sunting Anda, timpa fungsi Reverse dengan kode berikut,
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)
}
Hal ini akan membantu kita memahami apa yang menyebabkan kesalahan saat mengonversi string ke slice rune.
Menjalankan kode
Kali ini, kita hanya ingin menjalankan tes yang gagal untuk memeriksa log.
Untuk itu, kita akan menggunakan go test -run.
Untuk menjalankan isi dari corpus tertentu dalam testdata/FuzzXxx, kita
dapat mengirim opsi {FuzzTestName}/{nama berkas} pada opsi -run.
Hal ini sangat berguna saat melakukan diagnosis.
Salin nilai hash dari terminal pada hasil tes sebelumnya pada opsi -run
(nilai hash bisa berbeda dengan yang tertulis di bawah),
$ go test -run=FuzzReverse/4e4e4dc480dc461c
input: "\x8d"
runes: ['�']
input: "�"
runes: ['�']
--- FAIL: FuzzReverse (0.00s)
--- FAIL: FuzzReverse/4e4e4dc480dc461c (0.00s)
reverse_test.go:16: Number of runes: orig=1, rev=1, doubleRev=1
reverse_test.go:20: Before: "\x8d", after: "�"
FAIL
exit status 1
FAIL example/fuzz 0.001s
Setelah mengetahui bahwa input adalah unicode yang tidak valid, mari kita
perbaiki kesalahan pada fungsi Reverse kita.
Memperbaiki kesalahan
Untuk memperbaiki kesalahan, kita kembalikan sebuah error bila input dari
fungsi Reverse bukanlah UTF-8 yang valid.
Menulis kode
-
Pada perkakas sunting, timpa fungsi
Reversedengan kode berikut.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 }Perubahan ini akan mengembalikan sebuah
errorbila string input berisi karakter UTF-8 yang tidak valid. -
Secara fungsi
Reversesekarang mengembalikan sebuaherror, ubah fungsimainuntuk mengabaikan nilaierror. Timpa fungsimaindengan kode berikut.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) }Pemanggilan
Reverseseharusnya mengembalikan nilaierrornil, secara string input adalah UTF-8 yang valid. -
Kita impor paket
errorsdanunicode/utf8.Perintah impor pada
main.goberbentuk seperti berikut.import ( "errors" "fmt" "unicode/utf8" )
-
Ubah berkas
reverse_test.gountuk memeriksa error dan mengabaikan tes bilaerrordikembalikan tidak nil.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) } }) }Selain dengan menggunakan
return, kita juga dapat memanggilt.Skip()untuk menghentikan eksekusi dari input fuzz.
Menjalankan kode
-
Jalankan tes dengan
go test$ go test PASS ok example/fuzz 0.019s
-
Jalankan fuzz tes dengan
go test -fuzz=Fuzz, kemudian setelah beberapa detik, hentikan fuzzing dengan menekanCTRL-C.Fuzz tes akan terus berjalan sampai ia menemukan input yang menyebabkan kegagalan kecuali kita menambahkan opsi
-fuzztime. Secara bawaan ia akan berjalan terus jika tidak ada kesalahan ditemukan, namun proses tersebut dapat dihentikan paksa denganCTRL-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
-
Jalankan fuzz dengan
go test -fuzz=Fuzz -fuzztime 30syang akan berhenti setelah 30 detik bila tidak ditemukan kesalahan.$ 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
Pengujian fuzz sukses!
Sebagai tambahan dari opsi
-fuzz, ada beberapa opsi baru yang telah ditambahkan kego testyang dapat dilihat di dokumentasi.Lihat Go Fuzzing untuk informasi lebih lanjut tentang istilah-istilah pada keluaran fuzzing. Misalnya, istilah "new interesting" mengacu pada input-input baru yang telah ditambahkan sesuai cakupan kode dari corpus fuzz tes yang telah ada. Jumlah input dari "new interesting" bisa meningkat saat fuzzing dimulai, terus naik beberapa kali saat menjelajahi baris kode yang baru, kemudian berkurang seiring waktu.
Kesimpulan
Selamat! Anda baru saja berkenalan dengan fuzzing pada Go.
Langkah selanjutnya yaitu memilih sebuah fungsi pada kode Anda yang dapat dites dengan fuzzing, dan mencobanya! Jika fuzzing menemukan kecacatan dalam kode Anda, tambahkan proyek Anda ke lemari piala pada wiki Go.
Jika Anda mengalami kendala atau memiliki sebuah ide untuk fitur baru, silahkan buat isu baru.
Untuk diskusi dan umpan balik tentang fitur, Anda dapat berpartisipasi dalam kanal #fuzzing di Slack Gophers.
Lihatlah dokumentasi tentang Go Fuzzing untuk bacaan lebih lanjut.
Seluruh kode
Berkas main.go,
package main
import (
"errors"
"fmt"
"unicode/utf8"
)
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
}
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)
}
Berkas reverse_test.go,
package main
import (
"testing"
"unicode/utf8"
)
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)
}
})
}