go原生fuzz已足够用,fuzzxxx函数需以fuzz开头、参数为*testing.f、调用f.add()和f.fuzz();种子应覆盖边界值,f.fuzz闭包仅支持基础类型,避免全局状态修改,注意输入有效性与panic捕获。

Go 原生 fuzz 已足够用,无需额外装 go-fuzz,除非你要测 Cgo 或长期运行服务。
怎么写一个能跑起来的 FuzzXxx 函数
模糊测试函数不是随便起名、随便传参就能被识别的。必须严格满足:函数名以 Fuzz 开头,参数类型是 *testing.F,且内部调用 f.Add() 和 f.Fuzz()。
-
f.Add()传的是「种子输入」,建议覆盖合法值、空值、超长字符串、含\x00的字节流等,比如f.Add([]byte{"a", 0, "b"}) -
f.Fuzz()里的闭包签名决定 fuzz 引擎生成什么类型数据——只支持string、[]byte、整数/浮点/布尔等基础类型,不支持结构体或自定义类型 - 别在
f.Fuzz()里做全局状态修改(如改包级变量、打开文件),每个 case 是独立进程,状态不共享但副作用会污染后续执行
为什么加了 f.Add() 还总卡在“no interesting inputs”
这是最常遇到的假失败:fuzzer 没触发任何新代码路径,并非你代码没 bug,而是种子太弱或目标逻辑太“钝”。
- 检查被测函数是否过早返回(比如开头就
if len(input) == 0 { return },而你的种子全是空字符串) - 确保
f.Add()提供的输入能真正进入关键分支,例如 JSON 解析要带真实字段,不能只传"{}" - 如果目标函数接受
[]byte,但你只f.Add("hello"),引擎可能一直变异出 ASCII 字符串,漏掉二进制边界——显式加f.Add([]byte{0xff, 0xfe}) - Go 1.21+ 支持
-fuzzminimize,发现 crash 后自动压缩输入,但默认不启用;若想更快收敛,先手动加几个已知易崩溃的种子(如超大 slice、NaN 浮点)
go test -fuzz 报 panic 却没保存复现用例?
Go 原生 fuzz 默认只对导致进程崩溃(crash)或 panic 的 case 保存最小化输入,但有些 panic 被 recover 捕获了,或者 panic 发生在 goroutine 里,主流程没退出——这时你就看不到 crashers/ 目录。
- 加
-fuzzcachedir=fuzzcache显式指定缓存目录,避免临时目录被清理 - 在
f.Fuzz()闭包里主动加defer func() { if r := recover(); r != nil { panic(r) } }(),让 goroutine 内 panic 透出到主测试线程 - 若被测逻辑涉及并发(如启动 http.Server),务必用
t.Parallel()配合超时控制,否则 fuzz 可能卡死在阻塞调用上 - 注意:
panic("something")会被捕获并报告,但os.Exit(1)或 SIGSEGV 不会触发保存逻辑——这类需用go-fuzz工具链
最容易被忽略的是:fuzz 不是万能探针,它只对「输入驱动行为」的函数有效。如果你的函数依赖环境变量、当前时间、随机数种子或外部网络,那 fuzz 很可能永远摸不到深层路径——先把它变成纯函数,再 fuzz。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











