尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

CodeQL C++ 库 0.0.8 版本解析:升级包合并与 `%x` 格式串缓冲区长度估算的区间分析增强

发布时间:2026/9/26 3:02:46

资讯中心
01
ARTICLE

CodeQL C++ 库 0.0.8 版本解析:升级包合并与 `%x` 格式串缓冲区长度估算的区间分析增强

CodeQL C++ 库 0.0.8 版本解析:升级包合并与 `%x` 格式串缓冲区长度估算的区间分析增强
静态分析SAST应用安全漏洞扫描代码质量【免费下载链接】codeqlCodeQL: the libraries and queries that power security researchers around the world, as well as code scanning in GitHub Advanced Security项目地址https://gitcode.com/gh_mirrors/co/codeql点击查看免费下载导读本文以 CodeQL 仓库 cpp/ql/lib/change-notes/released/0.0.8.md 为主线深度解析 C 分析库 0.0.8 版本的两项核心变更codeql/cpp-upgrades包被废弃并入codeql/cpp-all以及FormatLiteral::getMaxConvertedLength在%x十六进制整数格式化场景中引入区间分析range analysis来获得更精确的输出长度上界。读完本文你将理解 CodeQL 升级脚本的包组织方式以及缓冲区溢出类查询中“格式化结果长度估算”这一关键机制在源码层面的实现原理。一、版本概览0.0.8 的核心变更cpp/ql/lib/change-notes/released/0.0.8.md记录了 CodeQL C 分析库 0.0.8 版本发布时的两条变更全部位于cpp/ql/lib即codeql/cpp-all与codeql/cpp-upgrades两个 CodeQL 包的源码目录变更类型内容Deprecated APIscodeql/cpp-upgradesCodeQL 包被移除其全部升级脚本合并进codeql/cpp-all包Minor Analysis ImprovementsFormatLiteral::getMaxConvertedLength改用区间分析为以%x格式化的整数提供更准确的转换长度估算该文件同时被汇总进仓库的 cpp/ql/lib/CHANGELOG.md因此它是理解 C 分析库后续版本演进尤其是格式串长度估算体系的重要基线。二、codeql/cpp-upgrades包废弃升级脚本统一归入codeql/cpp-all2.1 变更动机CodeQL 数据库在多个版本之间演进时旧版本的数据库需要经过升级upgrade步骤才能被新版本分析工具读取。这些升级由成对的.ql/.dbscheme脚本驱动存放在各语言的downgrades/upgrades目录中。在 0.0.8 之前C 语言的升级脚本被单独打包为codeql/cpp-upgrades从 0.0.8 起该包被移除所有升级脚本统一并入codeql/cpp-all。2.2 仓库中的实际形态合并后的升级脚本以目录形式存在于 cpp/downgrades 下每个子目录以数据库校验和命名典型结构为cpp/downgrades/ ├── initial/ # 初始 dbscheme ├── 02a123a1a681f98cf502f189a2a79b0dfb398e59/ │ ├── *.dbscheme # 升级目标/源 schema │ ├── *.ql # 升级逻辑数据迁移 │ └── *.properties # 元数据如 sourceDbscheme └── ...同时 cpp/downgrades/qlpack.yml 声明了该目录所属的包。这种“校验和目录 双 schema 迁移查询”的组织方式使 CodeQL CLI 在打开旧数据库时能自动定位对应的升级路径。2.3 对使用者的影响查询作者编写或分发依赖 C 升级机制的查询时不再需要单独引用codeql/cpp-upgrades包只需依赖codeql/cpp-all对应 cpp/ql/lib 目录即可。升级维护者新增 dbscheme 迁移只需在 cpp/downgrades 下添加校验和目录并保持 cpp/downgrades/qlpack.yml 的包声明正确即可。该变更属于“废弃 API”级别意味着旧包引用在 0.0.8 及以后版本中不再有效需要及时迁移。三、核心改进%x转换长度的区间分析估算3.1 背景为什么需要估算格式化输出长度CodeQL C 库中有一批缓冲区溢出buffer overflow相关查询它们需要判断sprintf/snprintf等格式化写入是否会超过目标缓冲区大小。由于实际运行时参数值是未知的分析器必须估算格式串每个转换说明符conversion specifier能产出的最大字符数。这个估算越精确查询的误报越少、检出越准。该估算的核心 API 就是FormatLiteral::getMaxConvertedLength定义于 cpp/ql/lib/semmle/code/cpp/commons/Printf.qll/** * Gets the maximum length of the string that can be produced by the nth * conversion specifier of this format string; has no result if this cannot * be determined. */ int getMaxConvertedLength(int n) { result max(this.getMaxConvertedLength(n, _)) }3.2 0.0.8 之前的估算方式纯类型边界以%x为例0.0.8 之前getMaxConvertedLength只依据参数的静态类型计算上界TTypeBoundsAnalysis。例如对unsigned int类型的参数固定按类型占 4 字节32 位估算最多可输出FFFFFFFF这样 8 个十六进制字符——即2 * sizeof(type)个数字位见 Printf.qllthis.getConversionChar(n).toLowerCase() x and // e.g. 12345678 exists(int baseLen, int typeBasedBound, int valueBasedBound | typeBasedBound min(int digits | digits 2 * this.getIntegralDisplayType(n).getSize() or exists(IntegralType t | t this.getUse().getConversionArgument(n).getType().getUnderlyingType() | t.isUnsigned() and digits 2 * t.getSize() ) ) and ... baseLen valueBasedBound.minimum(typeBasedBound) and if this.hasAlternateFlag(n) then len 2 baseLen else len baseLen // 0x )这种做法的缺点是保守即使参数在代码中恒为0x1估算结果仍是 8 个字符导致缓冲区长度检查过度悲观产生大量误报。3.3 0.0.8 的改进引入区间分析0.0.8 起%x分支在类型边界之外同时使用区间分析range analysis计算基于取值范围的“值边界”valueBasedBound并取两者中的较小值exists(Expr arg, float lower, float upper, float typeLower, float typeUpper | arg this.getUse().getConversionArgument(n) and lower lowerBound(arg.getFullyConverted()) and upper upperBound(arg.getFullyConverted()) and typeLower exprMinVal(arg.getFullyConverted()) and typeUpper exprMaxVal(arg.getFullyConverted()) | valueBasedBound lengthInBase16(max(float cand | // If lower can be negative we use (unsigned)-1 as the candidate value. lower 0 and cand 2.pow(any(IntType t | t.isUnsigned()).getSize() * 8) or cand upper )) and ( if lower typeLower or upper typeUpper then reason TValueFlowAnalysis() else reason TTypeBoundsAnalysis() ) ) and baseLen valueBasedBound.minimum(typeBasedBound) and if this.hasAlternateFlag(n) then len 2 baseLen else len baseLen // 0x关键点拆解数据来源lowerBound(arg.getFullyConverted())与upperBound(arg.getFullyConverted())是区间分析产出的参数取值上下界exprMinVal/exprMaxVal给出类型的固有极值。长度计算lengthInBase16(max(lower, upper 候选))取上界的十六进制位数作为值边界。负值处理若lower 0则按(unsigned)-1即无符号类型最大值计算候选值因为负数经%x转换时会按无符号解释输出。取值裁剪valueBasedBound.minimum(typeBasedBound)保证值边界永远不会超过类型边界从而只收紧、不放宽保持分析的健全性。估算原因标记当区间分析成功缩小了范围lower typeLower or upper typeUpper时标记为TValueFlowAnalysis否则回退为TTypeBoundsAnalysis。这个原因会被BufferWriteEstimationReason组合并向上传播帮助查询作者判断估算依据。3.4 浮点数与getMaxConvertedLengthLimited值得说明的是%d、%i、%u等整数格式在更早的版本已引入区间分析见 Printf.qll 中d/i分支与u分支0.0.8 将同一思路补齐到了%x。此外库中还提供getMaxConvertedLengthLimited系列 API将浮点转字符串的长度假定为 8 个字符用于区分“缓冲区溢出是否由过长的浮点转换引起”/** * ... except that float to string conversions are assumed to be 8 * characters. This is helpful for determining whether a buffer overflow is * caused by long float to string conversions. */ int getMaxConvertedLengthLimited(int n, BufferWriteEstimationReason reason) { if this.getConversionChar(n).toLowerCase() f then result this.getMaxConvertedLength(n, reason).minimum(8) else result this.getMaxConvertedLength(n, reason) }从实现可见Limited变体只对%f做 8 字符封顶其余转换仍走完整估算。四、下游消费估算结果如何进入缓冲区检查getMaxConvertedLength的计算结果最终被 cpp/ql/lib/semmle/code/cpp/security/BufferWrite.qll 中的写入模型消费例如result fl.getMaxConvertedLengthWithReason(reason) * this.getCharSize() // BufferWrite.qll 约 L271 result fl.getMaxConvertedLengthLimitedWithReason(reason) * this.getCharSize() // BufferWrite.qll 约 L284 result (fl.getMaxConvertedLength(arg - this.getParamArgs()) 1) * this.getCharSize() // 1 计终止空字符约 L501此处将“格式化输出最大字符数”乘以字符宽度getCharSize()并对字符串类写入额外1计入NUL终止符再与目标缓冲区容量比较从而判定是否可能溢出。因此%x分支估算精度的提升会直接降低涉及%x的sprintf/snprintf场景的误报同时保持对真实溢出的检出能力。在 cpp/ql/lib/semmle/code/cpp/commons/Scanf.qll 中同样存在getMaxConvertedLength(int n)的对应实现说明该估算机制同时服务printf族与scanf族两条分析路径。五、如何在仓库中验证该变更变更记录阅读 cpp/ql/lib/change-notes/released/0.0.8.md并结合 cpp/ql/lib/CHANGELOG.md 查看后续版本对同一机制的持续改进例如 0.4.3 的 change notes 亦提及getMaxConvertedLength。核心实现精读 Printf.qll重点关注%x分支约 L1253-L1290与d/i/u分支的对比体会“类型边界 值边界取最小”的估算策略。下游验证在 BufferWrite.qll 中跟踪getMaxConvertedLength*的调用点理解估算结果如何参与缓冲区容量比较。升级脚本结构浏览 cpp/downgrades 目录确认cpp-upgrades合并后升级脚本的实际存放与 qlpack 声明方式。六、小结CodeQL C 库 0.0.8 的两次变更看似轻量实则意义明确工程层面codeql/cpp-upgrades并入codeql/cpp-all简化了升级脚本的分发与依赖管理分析精度层面%x分支引入区间分析后FormatLiteral::getMaxConvertedLength得以用参数的实际取值区间收紧输出长度上界使依赖它的缓冲区溢出查询在%x场景下更精确、更少误报。对于希望深入 CodeQL C 分析原理的读者getMaxConvertedLength及其BufferWriteEstimationReason机制是理解“如何在未知输入下做健全且精确的长度估算”的绝佳范例——它以类型边界为上限、以值流分析为收紧手段二者取小既保证了不会漏报溢出又最大限度地压缩了保守估算带来的误差。赞分享静态分析SAST应用安全漏洞扫描代码质量【免费下载链接】codeqlCodeQL: the libraries and queries that power security researchers around the world, as well as code scanning in GitHub Advanced Security项目地址https://gitcode.com/gh_mirrors/co/codeql点击查看免费下载相关推荐TiXL CombineBuffers 算子全解析点缓冲区的 GPU 级合并原理与实战TiXL CombineBuffers 算子全解析点缓冲区的 GPU 级合并原理与实战 CombineBuffers 是 TiXLtooll3实时运动图形音视频图形学桌面应用Crystal 1.17 版本深度解析宏字符串化增强、Colorize 默认行为变更与时间/时区能力升级Crystal 1.17 版本深度解析宏字符串化增强、Colorize 默认行为变更与时间/时区能力升级 Crystal 1.17 是 2025 年 7 月发编程语言编译器标准库语言运行时合并区间排序与贪心算法的区间合并合并区间排序与贪心算法的区间合并 问题引入 在处理时间安排、日程管理、资源分配等实际问题时我们经常会遇到区间重叠的情况。例如 会议安排系统需要合并重叠的会示例工程教程上一篇三分钟快速上手猫抓浏览器视频下载的终极解决方案下一篇cwc-workshops Docker部署全解从构建PPTX渲染镜像到运行评测容器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。