当前位置:首页 > 文章列表 > Golang > Go教程 > Go fuzzing 怎样让输入先通过格式预检查

Go fuzzing 怎样让输入先通过格式预检查

来源:17golang原创 2026-10-18 23:03:13 0浏览 收藏

在 Go fuzz target 的回调入口先检查长度、固定头部或字符范围,不满足本目标前提时用 t.Skip 或直接返回,再对通过的输入执行解码和较昂贵的性质断言。预检查不会让 fuzz 引擎只生成合法输入,而是让不适用的输入尽早结束;它也不应该把本来要测试的解析错误挡在被测函数之外。

官方说明:https://go.dev/doc/security/fuzz/。testing 的跳过规则见 https://go.dev/src/testing/testing.go。下面比较三种策略,示例只限定输入筛选与单次测试成本,不把执行量当成覆盖率或性能结论。

先限定昂贵断言的输入域

例如,目标性质是“合法十六进制文本解码、规范化之后,内容摘要保持一致”。奇数长度或包含非十六进制字符的字符串,并不满足该性质的前提。让它们继续做摘要或业务对象构造没有意义,宜先筛掉。

但如果目标是“解码器面对任意文本应正确拒绝非法格式且不崩溃”,非法输入就是测试主体,不能过滤。先把这两个目标分开命名,比在同一个回调中到处遇错 return 更清楚。

比较直接返回、Skip与构造输入

return 适合结束当前回调,不需要额外说明;t.Skip 明确表达该输入不属于当前目标的有效域,适合排查种子为何未进入断言。二者都不是修复数据,也不能代替发现错误时的 t.Fatal。不要先标记失败,再期待 Skip 将失败抹掉。

第三种策略是 fuzz 原始字节,再通过 hex.EncodeToString 构造合法文本。它适合专测合法数据后的业务性质,能避免反复生成坏格式;代价是只探索构造器可表达的文本形式,例如统一小写,不能覆盖各种大小写、空白或畸形文本。本文选择字符级筛选,保留输入文本本身的变化。

用轻量格式检查约束目标

在现有 Go 模块中新建 hexcheck_test.go,写入下面的完整示例。长度上限 4096 是本例成本预算,不代表标准库只允许这么长。空串符合偶数长度和字符条件,必须保留,不能顺手把空输入当作非法输入跳过。

package hexcheck

import (
    "crypto/sha256"
    "encoding/hex"
    "strings"
    "testing"
)

// 小样本上限属于本测试的成本预算,不是十六进制格式的通用限制。
const maxHexLen = 4096

func isHexByte(c byte) bool {
    return c >= '0' && c = 'a' && c = 'A' && c  maxHexLen || len(s)%2 != 0 { return false }
    for i := 0; i 

检查器先判断字节长度,再检查 ASCII 字符,避免为了筛选而提前完整解码、分配大型对象。进入有效域后,如果 DecodeString 返回错误,就应失败,而不是再次 Skip;否则预检查与解码器之间的分歧会被藏起来。摘要只是一个可复制的性质示例,真实业务可替换为确定性的业务断言。

合法输入目标中的格式约束与属性检查静态依赖
图1:静态结构说明图。输入约束包含长度和字符规则,合法域目标依赖这些条件;连线表示依赖而非执行步骤,不是运行截图。

把预检查成本和有效样本分开看

该筛选最多扫描预算内的字符串;只有格式通过后才分配解码结果。它仍有扫描开销,如果后续计算本来就很便宜,重复实现格式规则未必划算。对于 JSON、复杂协议或压缩格式,另写一个接近完整解析器的预检查器尤其容易成本倒挂,可优先用已有解析结果决定后续性质是否适用。

大量合法种子不代表变异输入都会合法,f.Add 只是起点。判断筛选是否值得时,应分别观察单次筛选成本、后续断言成本,以及进入断言的样本是否足够多。fuzz 的 execs 不是“执行了昂贵断言的次数”。本文没有执行压测,不提供虚构的加速倍数或跳过比例。

保留不应被筛掉的坏输入

下面增加独立的拒绝路径目标。它只设置长度预算,不在调用解码器之前排除坏格式。十六进制语法简单,因此用字符规则建立接受性期望;复杂格式不宜复制整套生产解析逻辑作为所谓独立判断。

// 与上面的代码放在同一个 _test.go 文件中,复用导入和常量。
func FuzzHexReject(f *testing.F) {
    for _, s := range []string{"0", "gg", "0x12", "a b"} { f.Add(s) }
    f.Fuzz(func(t *testing.T, s string) {
        // 此目标只限制测试预算,不按格式预先跳过。
        if len(s) > maxHexLen { t.Skip("超过本目标预算") }
        wantValid := len(s)%2 == 0
        for i := 0; i 

FuzzHexDigest 负责合法输入性质;FuzzHexReject 负责预算内原始输入的接受性。两者共享 maxHexLen 和字符定义,但不共享“坏格式立即跳过”的策略。这个组合依然不测试超过 4096 字节的数据,若大输入属于产品风险,应另设有明确资源预算的测试,而不是声称已经全覆盖。

合法性质目标与原始输入接受性目标的覆盖边界
图2:静态边界说明图。两个目标分别依赖性质断言和接受性判断,共享长度预算;分组不表示先后,也不代表实测覆盖结果。

按目标选择筛选方式

目标选择主要代价
合法格式后的昂贵性质轻量检查加 Skip无效变异仍会消耗调用成本
只关心合法载荷业务计算原始字节加编码构造文本形式受到构造器限制
解析器拒绝行为不按格式筛选需要单独控制长度和计算预算
预检查几乎等于完整解析复用解析结果需明确解析错误是否属于预期域外

以下命令供读者在自己的模块包目录运行。普通 go test 可运行种子,持续 fuzz 使用精确匹配选择一个目标;分别运行两个目标,不把同一次执行当作同时变异两个目标。本文未执行命令。

# 先运行这两个目标已有的种子,不启动持续变异。
go test -run '^FuzzHex(Digest|Reject)$' -count=1 .
# 只对合法性质目标做有限时长变异。
go test -run '^$' -fuzz '^FuzzHexDigest$' -fuzztime=20s .
# 单独探索原始文本的接受性。
go test -run '^$' -fuzz '^FuzzHexReject$' -fuzztime=20s .

预检查失败应该用 Fatal 吗?

如果它只是说明输入不满足该性质前提,应 Skip 或结束回调;若检查的是被测实现必须履行的承诺,则应报错,不能跳过。

能用 recover 忽略所有 panic 吗?

不应这样做。把真实崩溃转成跳过会掩盖缺陷。筛选条件应来自目标的输入契约,而不是失败现象。

只加合法种子就能取消预检查吗?

不能据此假设后续输入都合法。要么保留适当筛选,要么用构造器明确控制格式域,并另测原始坏输入。

选择规则很简单:先问正在测试“合法输入后的性质”还是“格式接受与拒绝”,再决定是否筛选。省掉无意义的昂贵断言是合理目标,省掉需要发现的失败不是。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go unsafe.StringData 怎样处理只读字节视图Go unsafe.StringData 怎样处理只读字节视图
上一篇
Go unsafe.StringData 怎样处理只读字节视图
Go HTTP/2 怎样限制并发流
下一篇
Go HTTP/2 怎样限制并发流
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之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模型性能。
    529次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    587次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    613次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    565次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    388次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码