新闻详情

新闻详情

首页 / 资讯中心 / 详情

CodeQL C++ 安全查询解读:循环条件中的宽类型比较检测(cpp/comparison-with-wider-type)

发布时间:2026/9/25 10:46:58来源:尧图网络
CodeQL C++ 安全查询解读:循环条件中的宽类型比较检测(cpp/comparison-with-wider-type)
静态分析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点击查看免费下载在 C/C 代码中当循环条件把一个窄类型如char、short与一个宽类型如int直接比较时窄一侧的值可能在到达目标值之前发生回绕溢出导致循环永远无法终止。CodeQL 的cpp/comparison-with-wider-type查询专门检测这一类由“与更宽类型比较”引发的隐患其 2021 年 5 月的官方变更说明明确指出该查询经过改进能够产生更少的误报见 变更说明。本文以这条变更为主线结合仓库中的查询源码、示例代码与测试用例完整拆解该查询的判定逻辑、过滤条件与误报抑制手段读完你可以理解 CodeQL 是如何用 SSA 与范围分析精确定位“窄值溢出型”循环比较问题的。问题背景窄类型在循环比较中溢出查询配套的说明文档 ComparisonWithWiderType.qhelp 给出了问题的标准描述在循环条件中窄类型值与宽类型值比较时如果宽类型的取值足够大或小窄类型的值会先发生溢出典型后果是死循环。官方示例代码 ComparisonWithWiderType.c 展示了一个典型场景int16_t bytes_received 0; int max_get INT16_MAX 1; // BAD: bytes_received 与更宽类型的值比较 // 在达到 max_get 之前就会溢出造成死循环 while (bytes_received max_get) bytes_received get_from_input(buf, bytes_received); uint32_t bytes_received2 0; // GOOD: bytes_received2 的类型与 max_get 一样宽 while (bytes_received2 max_get) { bytes_received2 get_from_input(buf, bytes_received2); }由于max_get恰好等于INT16_MAX 1int16_t的bytes_received从 0 开始自增永远无法等于它——一旦回绕到负数就再也小于不了max_get循环永不结束。修复方式如 qhelp 中的建议让比较中较窄一侧的值至少与另一侧一样宽。该问题被映射到 CWE-190整数溢出或回绕、CWE-197数值下溢与 CWE-835死循环。查询元数据与定位查询主文件位于 ComparisonWithWiderType.ql其头部元数据定义了它在扫描体系中的角色元数据值含义idcpp/comparison-with-wider-type查询在规则库中的唯一标识kindproblem以问题而非路径为粒度报告problem.severitywarning警告级严重度security-severity7.8安全评分precisionhigh高精度规则误报少tagsreliability/security/external/cwe/cwe-190/external/cwe/cwe-197/external/cwe/cwe-835归类为可靠性 安全双标签映射三个 CWE查询名被限定为“Comparison of narrow type with wide typein loop condition”——它只关心出现在循环条件里的宽窄比较而非任意比较表达式这一点直接体现在查询主体中rel l.getCondition().getAChild*()这一约束上。核心判定逻辑从宽侧取值到窄侧能否容纳查询导入了三个关键库见 ComparisonWithWiderType.qlimport cpp import semmle.code.cpp.controlflow.Dominance import semmle.code.cpp.controlflow.SSA import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysisSSA构建静态单赋值形式用于追溯变量在循环中的最终定义点Dominance支配关系辅助控制流分析SimpleRangeAnalysis提供upperBound()等值域上界分析是判断“宽侧取值是否大到能撑爆窄侧”的关键。比较宽度的计算参考类型要取基类型C 引用reference本身是指针宽度但比较发生在被引用的值上因此查询不能简单取getType().getSize()int getComparisonSize(Expr e) { if e.getType() instanceof ReferenceType then result e.getType().(ReferenceType).getBaseType().getSize() else result e.getType().getSize() }这个细节保证int这类引用参与比较时按int的 4 字节而非指针宽度计算。有符号类型的“符号位修正”判断窄侧类型是否“装不下”宽侧的取值时还要考虑符号位int getComparisonSizeAdjustment(Expr e) { if e.getType().(IntegralType).isSigned() then result 1 else result 0 }对有符号类型可用数值位要扣除符号位修正量为 1因此窄侧“可表示范围”按size * 8 - 1位计算。主查询中这一步与范围分析结合forall(Expr conv | conv large.getConversion*() | upperBound(conv).log2() (getComparisonSize(small) * 8 - getComparisonSizeAdjustment(small)) )含义是取宽侧表达式的所有隐式转换链large.getConversion*()用SimpleRangeAnalysis的upperBound(conv).log2()估计其取值上界的位数只要存在一条转换链的上界超过窄侧类型的修正后位宽就认为窄侧可能装不下宽侧值从而构成风险。这就是“基于取值范围而非只看类型宽度”的判定——宽侧即使类型更宽若范围分析证明其取值实际落在窄侧表示范围内也不会告警这是抑制误报的核心机制之一。只报告“循环变元”排除循环不变的小变量predicate loopVariant(VariableAccess e, Loop loop) { exists(SsaDefinition d | d.getAUse(e.getTarget()) e | d.getAnUltimateDefiningValue(e.getTarget()) loop.getCondition().getAChild*() or d.getAnUltimateDefiningValue(e.getTarget()).getEnclosingStmt().getParent*() loop.getStmt() or d.getAnUltimateDefiningValue(e.getTarget()) loop.(ForStmt).getUpdate().getAChild*() ) }loopVariant利用 SSA 定义点判定窄侧变量small是否真的是“随循环变化”的变量其最终定义值要么来自循环条件本身、要么位于循环体内、要么是for语句的更新子句。主查询末尾的loopVariant(small, l)注释明确写着ignore loop-invariant smaller variables——如果窄侧变量在循环中从不变化比较不构成死循环风险直接忽略。三道额外的误报抑制过滤除上述两条主判定外主查询还有三组显式排除条件见 ComparisonWithWiderType.ql窄侧类型小于 4 字节才报告small.getExplicitlyConverted().getType().getSize() 4源码注释解释了原因当窄侧本身是int或更宽时确实仍可能溢出但需要“非常大的字符串或数组”才能触发对于从 32 位时代遗留下来的代码库这类报告会非常嘈杂因此有意放弃。注意这里用getExplicitlyConverted()取的是显式转换链末端的类型即变量声明的实际类型。排除整型提升造成的假宽侧not getComparisonSize(large.(DivExpr).getLeftOperand().getExplicitlyConverted()) getComparisonSize(small) and not getComparisonSize(large.(SubExpr).getLeftOperand().getExplicitlyConverted()) getComparisonSize(small) and not getComparisonSize(large.(RShiftExpr).getLeftOperand().getExplicitlyConverted()) getComparisonSize(small)当宽侧是除法、减法或右移表达式时其操作数会先发生整型提升integer promotion提升后的运算可能只是把窄值放大到int并不代表宽侧取值真的超出了窄侧范围。这三条not ... ...条件专门拦截这类“表面上宽、实际值域没变”的场景。报告位置的友好化Element friendlyLoc(Expr e) { result e.(Access).getTarget() or result e.(Call).getTarget() or not e instanceof Access and not e instanceof Call and result e }报告定位优先指向Access/Call的getTarget()即变量声明或函数定义而不是临时的转换节点使告警消息更易读。最终select输出形如Comparison between 小值 of type char and 宽值 of wider type int.$标记同时高亮比较表达式与两个操作数。测试用例与预期结果测试位于 ComparisonWithWiderType 测试目录由 ComparisonWithWiderType.qlref 引用查询本身并通过InlineExpectationsTestQuery.ql做内联期望校验test.c与 ComparisonWithWiderType.expected 一一对应。测试用例覆盖了各种变体char/short与int比较test1–test3、test6、long long参与比较test7、在for更新子句中递减宽侧变量test8、在循环体内递减宽侧变量test9、以及do-while嵌套等结构test10。预期结果共 17 条告警例如test.c:4Comparison between c of type char and x of wider type int.——char c与函数参数int x比较test.c:42Comparison between s1 of type short and 65535 of wider type int.—— 常量上界0x0000ffff超出了short正范围test.c:91/93/95unsigned char与取值分别为65280、16711680、4278190080的常量比较覆盖范围分析对不同上界位数的判定。而test4short s1 short s2同为窄类型与test5比较不在循环中均不出现在预期结果中正好验证了“类型宽度相同不告警”“非循环条件不告警”两条边界。本次改进的意义面向 32 位遗留代码库的降噪2021-05-10 变更说明 只有一句话却指向一个很具体的工程决策The Comparison with wider type (cpp/comparison-with-wider-type) query has been improved to produce fewer false positives.结合查询源码可以看到降噪手段正是上面分析的几层过滤协同作用的结果——用SimpleRangeAnalysis的upperBound估计宽侧实际取值范围而不是仅凭类型宽度下结论让“类型更宽但值域没超出窄侧表示范围”的比较不再误报loopVariant剔除循环不变量避免对不参与循环推进的比较报警对int及以上宽度的窄侧类型整体豁免源码注释直言这类情况“在从 32 位开始的代码库中非常嘈杂”very noisy on codebases that started as 32-bit属于有意牺牲极端场景的召回换取可用性的取舍整型提升过滤避免把/、-、运算中因操作数提升而变宽的表达误判为真实宽值。这套“类型宽度 范围分析 控制流角色”的三重约束使该查询保持了元数据中precision high的承诺报告出的每条告警都意味着窄侧变量在循环推进过程中确实可能在与明显更宽的取值比较时越过自身表示范围。小结cpp/comparison-with-wider-type是一个以“循环条件中的宽窄类型比较”为切入点、以 SSA 与简单范围分析为引擎的可靠性/安全查询它先通过 getComparisonSize 正确解析引用类型宽度再用upperBound(conv).log2()与窄侧位宽扣除符号位比较判定取值溢出风险最后经循环变元、int以上窄侧豁免、整型提升过滤三道关抑制误报。2021 年 5 月的改进正是围绕这套误报抑制机制展开的。若你在维护 C/C 规则集或想理解 CodeQL 高精度规则的设计模式这条查询及其 测试目录 是值得精读的样本。赞分享静态分析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 C 安全查询解析检测无符号减法与 0 的关系比较cpp/unsigned-difference-expression-compared-zeroCodeQL C 安全查询解析检测无符号减法与 0 的关系比较cpp/unsigned difference expression compared静态分析SAST应用安全漏洞扫描代码质量CodeQL C 静态分析「赋值误作比较」查询cpp/assign-where-compare-meant如何降低条件表达式中的误报CodeQL C 静态分析「赋值误作比较」查询cpp/assign where compare meant如何降低条件表达式中的误报 本文围绕 Cod静态分析SAST应用安全漏洞扫描代码质量Ruff 之 ty 类型检查器的循环类型别名检测cyclic-type-alias-definition 规则全解析Ruff 之 ty 类型检查器的循环类型别名检测cyclic type alias definition 规则全解析 本篇文章围绕 Ruff 仓库中内置类型检开发工具Lint格式化静态分析CLI上一篇EIP-858 详解将以太坊区块奖励降至 1 ETH 并推迟难度炸弹的 PoW 减排提案下一篇如何永久保存微信聊天记录用WeChatMsg打造你的个人数字记忆库创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

如何为开源项目 npmx.dev 贡献代码:环境搭建、开发工作流与测试体系指南 2026/9/25 17:36:22

如何为开源项目 npmx.dev 贡献代码:环境搭建、开发工作流与测试体系指南

如何为开源项目 npmx.dev 贡献代码:环境搭建、开发工作流与测试体系指南 【免费下载链接】npmx.dev a fast, modern browser for the npm registry 项目地址: https://gitcode.com/gh_mirrors/np/npmx.dev npmx.dev 是一个快速、现代的 npm 注册表浏览器&…

阅读更多 →
lego v4 到 v5 库迁移完全指南:Context 化、slog 日志与 API 重构要点 2026/9/25 17:36:09

lego v4 到 v5 库迁移完全指南:Context 化、slog 日志与 API 重构要点

网络安全密码学 【免费下载链接】lego Lets Encrypt/ACME client and library written in Go 项目地址: https://gitcode.com/gh_mirrors/le/lego 点击查看 免费下载 本文基于 go-acme/lego 官方迁移文档(docs/content/migration/library.md&#xff09…

阅读更多 →
深入解析 Salt 中 SSH 资源的 test 执行模块覆盖:`salt.resources.ssh.modules.test` 与真实的远端连通性检测 2026/9/25 17:36:02

深入解析 Salt 中 SSH 资源的 test 执行模块覆盖:`salt.resources.ssh.modules.test` 与真实的远端连通性检测

运维配置管理后端 【免费下载链接】salt Software to automate the management and configuration of infrastructure and applications at scale. 项目地址: https://gitcode.com/gh_mirrors/sa/salt 点击查看 免费下载 test.ping 是 Salt 生态中使用频率最高的连…

阅读更多 →
F´ 单元测试框架实战:TesterBase、GTestBase 与 Tester 的自动生成机制、断言写法与覆盖率分析 2026/9/25 17:35:56

F´ 单元测试框架实战:TesterBase、GTestBase 与 Tester 的自动生成机制、断言写法与覆盖率分析

嵌入式系统编程 【免费下载链接】fprime F - A flight software and embedded systems framework 项目地址: https://gitcode.com/gh_mirrors/fp/fprime 点击查看 免费下载 F(F Prime)是一个用于飞行软件(FSW)与嵌入式…

阅读更多 →
Agent技能库设计:从函数调用到工程化技能编排的实践指南 2026/9/25 17:35:43

Agent技能库设计:从函数调用到工程化技能编排的实践指南

我搭建agent-skills这个技能库,最早是因为项目代码里到处重复着给模型拼tool definitions的手写逻辑。当时我们做了好几个智能体应用,表面上是对话、搜索、下单这些能力,背后真正干活的却是一堆散落在各个文件里的函数。每次新增一个功能&…

阅读更多 →
PaddleSpeech 实战:基于 CSMSC 数据集从零训练 SpeedySpeech 中文语音合成声学模型 2026/9/25 17:35:36

PaddleSpeech 实战:基于 CSMSC 数据集从零训练 SpeedySpeech 中文语音合成声学模型

人工智能语音音频 【免费下载链接】PaddleSpeech Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉