fuzz函数跑不起来主要因四个硬性条件:函数名未用大驼峰(如fuzzparsejson)、参数非*testing.f、文件无_test.go后缀、或遗漏f.add();go模糊测试静默跳过而非报错。

Fuzz 函数跑不起来,大概率是卡在四个硬性条件上:函数名没大驼峰、参数不是 *testing.F、文件没带 _test.go 后缀、或者漏了 f.Add()。Go 模糊测试不会报错提示,而是直接跳过——你看到的“没输出”,其实是被静默忽略了。
函数名和文件名必须严格匹配 Go 的识别规则
Go 只认以 Fuzz 开头、紧接大写字母的函数名(如 FuzzParseJSON),fuzzParseJSON、Fuzzparsejson、Fuzz_parse 全部无效。文件也必须是 xxx_test.go,放在同一包下;哪怕内容只有一行 package main,只要不是测试文件,go test -fuzz= 就找不到它。
-
FuzzParseUser✅ -
fuzzParseUser❌(小写 f) -
Fuzzparseuser❌(第二字母没大写) -
parser.go❌(缺_test)
f.Add() 不是可选步骤,而是启动 fuzz 的钥匙
没有 f.Add(),f.Fuzz() 闭包根本不会执行——引擎连第一个输入都没有,变异无从谈起。常见错误是只写 f.Fuzz(...),或写了 f.Add("hello") 但闭包参数是 []byte,类型不匹配直接 panic。
- 闭包签名是
func(t *testing.T, s string)→f.Add("a")、f.Add("test{}") - 闭包签名是
func(t *testing.T, b []byte)→f.Add([]byte("a"))、f.Add([]byte{0x00, 0xff}) - 别用
f.Add("hello")配[]byte参数,会 panic - 至少喂一个种子,哪怕
f.Add([]byte{})也比不加强
f.Fuzz() 闭包里只能用基础类型,结构体得拆开测
Go 原生 fuzz 引擎不支持自定义 struct、指针(除 *T 显式声明外)、嵌套切片。想测 JSON 解析器?不能传 User 结构体,得用 string 或 []byte 接收原始字节,再调 json.Unmarshal。
- ✅ 支持:
string、[]byte、int64、float64、bool - ❌ 不支持:
type Config struct{ Port int }、*string(未显式声明)、[]User - 若需字段级覆盖,单独写
FuzzParsePort,参数用int,f.Add(0)、f.Add(65536)、f.Add(-1)
跑起来没 crash,不代表没 bug
go test -fuzz= 默认只对 panic、崩溃、t.Fatal 做响应并保存复现输入;逻辑错误(比如解析错 JSON 但没 panic)、recover 捕获的 panic、goroutine 内 panic 都不会触发保存。你 Ctrl+C 中断后看到 fuzz/crashers/ 为空,不等于安全。
- 在
f.Fuzz()闭包开头加defer func() { if r := recover(); r != nil { panic(r) } }(),让 recover 不吞掉 panic - 对数值计算,别只看是否 panic,要主动校验:
if got != want { t.Fatal("overflow missed") } - 加
-v看覆盖率进展:go test -fuzz=FuzzParse -fuzztime=20s -v - 崩溃用例默认存在
fuzz/crashers/,文件名如00a7e1,直接cat fuzz/crashers/00a7e1复现
"{}",引擎永远变异不出 {"arr":[{},{},]} 这种嵌套结构;喂一堆 ASCII 字符串,它很难撞上 UTF-8 边界或 \x00。别指望随机变异补足设计缺口——f.Add() 是你唯一能掌控的引导点。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











