当前位置:首页 > 文章列表 > Golang > Go教程 > Go fuzzing 怎样用语料库复现输入

Go fuzzing 怎样用语料库复现输入

来源:17golang原创 2026-10-20 08:05:40 0浏览 收藏

Go 原生 fuzzing 的关键不是把每次随机输入都保存下来,而是把有价值的输入变成可重复运行的语料。固定样本可以通过 f.Add 注册,也可以放进 testdata/fuzz/;当 fuzzing 找到失败输入时,Go 会把它写回同一个语料目录。这样,之后直接运行 go test 就能重新执行这条回归样本,调试时还可以用 -run 精确定位它。

官方文档:https://go.dev/doc/security/fuzz/

testing 包文档:https://pkg.go.dev/testing#F.Add

想复现一次 fuzzing 失败,先看输出中的 FuzzTest 名称和哈希后缀;想让问题长期留在回归测试里,就保留生成的语料文件,并用不带 -fuzz 的 go test 重跑。

先把种子语料和失败语料分开看

Go 的 fuzz test 至少有两类输入来源。第一类是开发者主动提供的种子:可以在调用 f.Fuzz 之前用 f.Add 注册,也可以把文件放入 testdata/fuzz/FuzzXxx。第二类是 fuzzing 过程中发现的失败输入,测试引擎会把它保存为新的语料文件。

两者都会在默认的 go test 中执行。区别在于,种子是你用来引导初始覆盖范围的输入,失败语料则是已经暴露出问题、应该被长期保留的回归样本。不要把所有随机输入都手工复制进代码,真正有价值的是能覆盖边界或复现缺陷的少量样本。

Go fuzzing 中 F.Add、testdata 语料和失败输入文件的静态关系
图1:Go fuzzing 的两类语料来源与默认测试入口的静态说明图,不是运行截图或执行证据。

用 F.Add 注册一组稳定的初始输入

F.Add 必须写在 F.Fuzz 之前,传入的参数类型要和 fuzz target 的参数一一对应。下面的例子用字符串覆盖空值、普通文本、包含分隔符的文本和多字节字符;这些输入不是为了模拟所有随机情况,而是为了让每次默认测试都有稳定的起点。

func FuzzNormalize(f *testing.F) {
    // 种子覆盖空值、分隔符和多字节文本,帮助快速触达边界。
    f.Add("")
    f.Add("  go-fuzz  ")
    f.Add("a,b,c")
    f.Add("中文输入")

    f.Fuzz(func(t *testing.T, input string) {
        // fuzz target 要保持快速、确定,并只使用当前输入。
        got := normalize(input)
        if strings.Contains(got, "\\n") {
            // 失败会让当前输入进入可复现的失败语料路径。
            t.Fatalf("结果仍含换行符: %q", got)
        }
    })
}

如果 target 接收的是 []byte、int 或多个参数,f.Add 也必须用完全相同的参数类型和顺序。类型不匹配时,问题应在编写测试时直接修正,不要试图用字符串化方式绕过 fuzz target 的签名。

找到失败输入后看哪个目录

启用 fuzzing 时,如果 target 因某组输入失败,测试输出会给出类似 testdata/fuzz/FuzzNormalize/ 的路径。文件第一行是 go test fuzz v1,后续每一行对应 fuzz target 的一个参数。它是 Go 的语料编码,不是普通日志,也不应该把注释写进文件。

例如一个只接收字符串的语料文件可能是:

go test fuzz v1
string("异常输入")

如果 target 接收 []byte 和 int64,文件中的两条值就必须按同样顺序出现。官方文档还说明,若项目目录不可写,失败输入可能暂时写入构建缓存中的 fuzz cache;在通常可写的项目中,优先以测试输出给出的项目内路径为准。

Go fuzzing 失败语料文件、Fuzz target 和 go test 复现命令的静态关系
图2:失败语料的编码内容、fuzz target 参数和复现命令之间的静态说明图,不是运行截图或执行证据。

不带 -fuzz 也能把失败输入跑起来

开发者第一次看到失败输出时,容易以为必须重新运行一轮随机 fuzzing。其实,失败语料保存后,默认的 go test 会把它当作种子执行。这个特性让发现问题和回归验证分开:第一次用 -fuzz 找到输入,后续普通测试负责稳定地确认修复没有回退。

# 先只执行已登记的单元测试、种子语料和失败语料。
go test ./...

# 需要继续探索时,才指定一个 fuzz test,并限制本次探索时间。
go test -fuzz=FuzzNormalize -fuzztime=30s

如果项目里有多个 fuzz test,可以先用普通的 go test 确认全部语料,再用 -fuzz=FuzzNormalize 选择目标。-fuzztime 只限制 fuzzing 探索阶段的时间,不改变已有语料的含义。

用 -run 精确复现一条语料

当一个 fuzz test 的语料很多,或只有某一条输入触发问题时,可以从失败输出复制完整的子测试标识。Go 官方示例使用 go test -run=FuzzFoo/9ddb952d9814 运行单条 seed corpus 输入。实际使用时,把 FuzzFoo 换成你的 fuzz test 名称,把后面的哈希换成输出中的实际标识。

# 只复现 FuzzNormalize 下的一条失败语料。
go test -run='^FuzzNormalize/9ddb952d9814$'

# 只运行该 fuzz test 的全部种子,不开启随机探索。
go test -run='^FuzzNormalize$'

这里的 -run 是筛选已经存在的测试和子测试;它不会生成新的随机输入。若哈希或测试名称复制错误,命令可能匹配不到目标,先回到原始失败日志重新复制完整标识。

语料库维护时记住三个边界

问题应该怎么做原因
固定样本放哪里少量可读样本用 f.Add,较大的或长期维护的样本放 testdata/fuzz/FuzzXxx两者都会进入默认种子集合,但文件更适合管理较大输入
失败输入要不要删除修复问题前保留;修复后把它作为回归样本继续运行它记录了曾经触发缺陷的真实边界
如何缩小调试范围从失败输出复制 FuzzXxx/哈希,传给 go test -run只执行目标语料,不重新进行随机探索

最后再强调一次:种子语料应该小而有代表性,fuzz target 应该快速、确定且不依赖共享可变状态。语料库的价值是让问题可以重复出现,而不是用文件数量制造覆盖率幻觉。

常见问题

失败语料必须手动转换成 f.Add 吗?

不需要。Go 会按语料文件格式读取它;只有当你确实想把小样本直接写在测试代码里时,才把它改写成 f.Add。

为什么普通 go test 也会失败?

因为失败语料已经成为该 fuzz test 的默认种子。修复代码后,普通测试应当通过;如果仍失败,说明这个输入对应的缺陷还没有处理。

可以只用 -fuzz 不保留语料吗?

可以临时探索,但不适合作为回归流程。要让问题在后续构建和提交中持续可见,应保留失败语料或等价的稳定种子。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go testing.B.Loop 怎样编写稳定基准循环Go testing.B.Loop 怎样编写稳定基准循环
上一篇
Go testing.B.Loop 怎样编写稳定基准循环
Go go:embed 怎样嵌入目录树
下一篇
Go go:embed 怎样嵌入目录树
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    558次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    606次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    633次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    589次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    413次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码