- 静态分析
- SAST
- 应用安全
- 漏洞扫描
- 代码质量
【免费下载链接】codeql
CodeQL: the libraries and queries that power security researchers around the world, as well as code scanning in GitHub Advanced Security
本篇技术指南以 C++ 查询库 7.0.0 发布说明 为骨架,逐条拆解该版本引入的破坏性变更、API 弃用与新增能力、常量分析行为调整,以及数据流屏障谓词的缺陷修复,并结合 Call.qll、Access.qll、Ssa.qll 等源码给出实现级佐证。读完本文,你将掌握 7.0.0 中各 API 的准确迁移路径(如何替换被弃用的谓词、如何适配屏障节点语义变化),并能据此评估升级对既有 C/C++ 查询的影响。
版本发布说明在仓库中的位置与阅读方式
该文档位于cpp/ql/lib/change-notes/released/目录,与 0.0.x、6.x、8.x、9.x 等历代版本的说明并列存放,完整记录了 C/C++ 查询库 qlpack 自发布以来的每一次 API 变化。7.0.0 的变更条目按 CodeQL 变更说明的惯例分为五类:
- Breaking Changes:破坏性变更,升级后可能影响既有查询的编译或结果;
- Deprecated APIs:已弃用但仍可使用的 API,应尽快迁移;
- New Features:新增的类、谓词与内建操作支持;
- Minor Analysis Improvements:分析精度的细微调整;
- Bug Fixes:缺陷修复,可能改变查询结果。
这些条目同样被汇总进了 cpp/ql/lib/CHANGELOG.md,便于按版本号检索。下面逐类展开。
Breaking Changes:_Decimal32/64/128不再作为内建类型暴露
7.0.0 最直接的破坏性变更是:_Decimal32、_Decimal64、_Decimal128这三个 GCC 特有的十进制浮点类型,不再被 CodeQL 暴露为内建类型(builtin types)。
文档给出的理由有两层:
- 对这些类型的支持本身不完整("Support for these gcc-specific types was incomplete"),即此前的建模存在缺口;
- 这类类型在真实 C/C++ 代码库中很少使用("generally not used in C/C++ codebases"),投入产出比低。
对查询作者的实际影响:任何在查询中直接引用这三个类型名(例如在类型模式、instanceof判断或getType().getName()比较中匹配_Decimal32等字符串)的既有查询,升级后可能不再命中或无法解析对应类型实体。如果确实需要处理这类代码,建议改用更通用的数值类型建模路径,或基于类型特征的间接匹配方式,而不是依赖内建类型名的直接引用。
Deprecated APIs:OverloadedArrayExpr::getArrayOffset/0弃用与迁移
背景:OverloadedArrayExpr是什么
在 Call.qll 中,OverloadedArrayExpr被定义为"用户自定义二元operator[]作用于其参数的一次实例",即重载下标运算符的调用表达式。典型场景:
struct T2 { T1 operator[](const T3 &); }; T1 a; T2 b; T3 c; a = b[c]; // 这里 b[c] 就是一个 OverloadedArrayExpr源码中该类通过this.getTarget().hasName("operator[]")识别目标函数,并提供两个基础访问器:
getArrayBase():被下标的对象表达式(优先取限定符getQualifier(),否则取第 0 个子节点);- 下标索引相关的
getArrayOffset系列谓词。
弃用细节与推荐替代
7.0.0 将无参版本getArrayOffset/0标记为deprecated(见 Call.qll#L388-L393),其旧实现等价于getArrayOffset(0),即"取第一个(第 0 个)下标"。弃用后的推荐写法:
OverloadedArrayExpr::getArrayOffset/1:按索引取第 n 个下标表达式;OverloadedArrayExpr::getAnArrayOffset:取任意一个下标表达式(数量不限)。
从实现看,getArrayOffset(int n)在存在限定符时返回this.getChild(n),否则返回this.getChild(n + 1)(因为此时第 0 个子节点是被下标对象本身),而getAnArrayOffset只是对getArrayOffset(_)的存在量化封装。也就是说:只要你的查询需要访问"第一个下标"的语义,把getArrayOffset()替换成getArrayOffset(0)即可获得完全一致的行为;需要遍历全部下标时则改用getAnArrayOffset。被弃用的谓词在本版本中仍可用,但会在后续版本移除,建议尽早迁移。
New Features:三项新增能力
1.__is_bitwise_cloneable、__is_invocable、__is_nothrow_invocable内建操作子类
7.0.0 为BuiltInOperations增加了三个新的子类,对应三种编译器内建操作(见 BuiltInOperations.qll):
| 新增类 | 对应内建 | 语义 |
|---|---|---|
| 位可克隆性检查 | __is_bitwise_cloneable | 判断类型是否可按位复制(常用于is_bitwise_cloneable这类 traits 的实现) |
| 可调用性检查 | __is_invocable | 判断函数类型/参数包是否可被调用(std::is_invocable的底层实现) |
| 无异常可调用性检查 | __is_nothrow_invocable | 判断调用是否保证不抛异常(std::is_nothrow_invocable的底层实现) |
在此之前,这类表达式可能只能被当作泛化的内建调用处理,无法用具体子类精确匹配。新增子类后,查询作者可以直接按instanceof分支或在BuiltInOperations的getAPrimaryQlClass分派中区分这三种操作,便于围绕 C++ 类型特征(traits)展开更精细的分析。
2.ParamAccessForType::isThisAccess:识别隐式对象参数访问
ParamAccessForType表示"为decltype目的而对函数签名参数进行的访问"。典型场景:
template <typename L, typename R> auto add(L lhs, R rhs) -> decltype(lhs + rhs) { return lhs + rhs; }这里返回类型decltype(lhs + rhs)内部是一个加法表达式,其两个子节点都是ParamAccessForType(见 Access.qll#L382-L402)。
新谓词isThisAccess在该访问指向函数的隐式对象参数(即成员函数的this)时成立,实现上依赖param_ref_to_this(underlyingElement(this))这一底层关系。对分析decltype上下文中的this引用、以及在类型层面建模成员函数签名时,这个谓词提供了直接、可判定的判断入口,无需再自行推导"该参数引用是否为 this"。
3.getArrayOffset/1与getAnArrayOffset:支撑 C++23 多维下标运算符
C++23 允许用户为类类型重载多维下标运算符,例如a[i, j, k]。这意味着一个OverloadedArrayExpr可能携带多个下标表达式,而旧版getArrayOffset/0只能取到第一个下标,信息不完整。
7.0.0 通过新增两个谓词补齐这一能力:
getArrayOffset(int n):按位序取第 n 个下标(n >= 0),支持访问任意维度;getAnArrayOffset:不限定维度地枚举所有下标表达式。
两者已在 Call.qll#L395-L406 落地。配套地,原getArrayOffset/0被弃用(见上文),避免查询作者继续使用"只能取第一个下标"的旧语义而漏掉多维场景。对于编写数组越界、下标污染(taint)等与下标相关的 C/C++ 安全查询,这是一个需要同步跟进的重要 API 变化。
Minor Analysis Improvements:常量改为展开的表达式树表示
7.0.0 调整了常量的表示方式:部分常量不再以折叠后的单值形式存在,而改用其展开的表达式树(unfolded expression trees)来表示。由此带来一个直接后果:Expr的isConstant谓词对这些常量不再成立(不再返回结果)。
结合 Expr.qll#L188-L195 的实现来看,isConstant目前由三类来源支撑:
valuebind(_, underlyingElement(this)):与提取器写入的值绑定表关联的常量;addressConstantExpression(this):地址常量表达式(如函数地址、constexpr 变量地址、lvalue 地址及其加减常量);constantTemplateLiteral(this):未实例化模板中的常量模板字面量。
"展开的表达式树"表示意味着某些常量在 AST 中保留了完整的运算结构(例如1 + 2不再直接折叠成字面量3),因此无法再从值绑定中直接命中,isConstant也就不再成立。
影响评估:依赖isConstant判断"表达式是否为编译期常量"的查询(如 RangeAnalysisUtils.qll、Scanf.qll 中对常量操作数的依赖)可能观察到行为变化。如果你的查询需要同时覆盖折叠常量与展开表达式,应结合 AST 结构(如Constant字面量、FoldExpr等)与isConstant共同判断,而不是单独依赖单一谓词。
Bug Fixes:BarrierGuard::getABarrierNode的间接寻址缺陷修复
缺陷本质
7.0.0 修复了DataFlow::BarrierGuard<...>::getABarrierNode中的一个 bug:该谓词此前会返回带有错误间接层级(indirections)的DataFlow::Node。也就是说,屏障节点所对应的数据流值层级与实际守卫对象不符,可能导致isBarrier/isSanitizer中基于getABarrierNode实现的屏障未能正确拦截污点传播。
从 Ssa.qll#L2079-L2090 的实现脉络看,BarrierGuard模块通过BarrierGuardWithState把"守卫检查谓词"(guardChecks(g, e, val))与 SSA 定义/读取关联起来,getABarrierNode最终聚合出"被该守卫安全检查的节点"。间接层级错误意味着聚合出的节点在其指针/引用层级上与守卫表达式不一致。
对你的查询的影响
修复后,如果你用getABarrierNode实现 dataflow/taint-tracking 查询的屏障,可能会看到更多的查询结果(更多告警)——因为此前错误层级掩盖了部分本应被判定为"受污染数据仍可达"的路径。文档给出的应对方案:
- 若新增结果属于误报,可使用
DataFlow::BarrierGuard<...>::getAnIndirectBarrierNode来移除这些额外结果; - 换言之,
getABarrierNode现在只应匹配"恰好与该守卫值层级一致"的节点,而getAnIndirectBarrierNode用于覆盖经间接访问(如指针解引用、成员访问)后仍受守卫保护的情况。
迁移建议:升级到 7.0.0 后,请重新跑一遍依赖屏障机制的 dataflow/taint 查询,对比结果集变化;在isBarrier/isSanitizer中按需将getABarrierNode替换为getAnIndirectBarrierNode,并根据告警的增减判断取舍。该谓词定义于共享模块 shared/ssa/codeql/ssa/Ssa.qll,被各语言查询库的数据流库复用,因此这一修复的影响面不限于 C/C++ 查询。
升级核对清单
综合以上五类变更,从 6.x 升级到 7.0.0 时建议逐项核对:
- 搜索弃用调用:检查查询中所有
OverloadedArrayExpr的.getArrayOffset()无参调用,替换为getArrayOffset(0)或getAnArrayOffset; - 复查类型引用:确认没有查询依赖
_Decimal32/64/128内建类型名; - 重跑屏障相关查询:对使用
BarrierGuard的 dataflow/taint 查询做结果对比,按需改用getAnIndirectBarrierNode; - 复核常量判断:对依赖
isConstant的查询补充 AST 结构判断,避免常量展开表示带来的漏报; - 新能力接入:如需处理 C++23 多维下标或
decltype中的this访问,直接使用新增的getArrayOffset/1、getAnArrayOffset与isThisAccess。
各变更条目的官方记录以 7.0.0 发布说明 为准,并可在 cpp/ql/lib/CHANGELOG.md 中按版本检索到完整演进历史。升级前建议在目标查询集上运行一次全量回归测试,以量化结果集变化。
- 静态分析
- SAST
- 应用安全
- 漏洞扫描
- 代码质量
【免费下载链接】codeql
CodeQL: the libraries and queries that power security researchers around the world, as well as code scanning in GitHub Advanced Security
相关推荐
CodeQL C/C++ 库 3.2.0 变更深度解析:数据流屏障、C++20/23 语法建模与模板分析增强
CodeQL C/C++ 库 3.2.0 变更深度解析:数据流屏障、C++20/23 语法建模与模板分析增强 本篇文章聚焦 CodeQL 开源仓库中 C/C++
静态分析SAST应用安全漏洞扫描代码质量CodeQL C++ 数据流库 6.1.1:`FieldContent` 全面支持 union 字段访问与 API 变更解析
CodeQL C++ 数据流库 6.1.1: FieldContent 全面支持 union 字段访问与 API 变更解析 本文以 CodeQL 仓库中 C++
静态分析SAST应用安全漏洞扫描代码质量CodeQL C++ 查询库 5.2.0 变更解读:SEH 建模重构、`__leave` 语句支持与类型解析修复
CodeQL C++ 查询库 5.2.0 变更解读:SEH 建模重构、 __leave 语句支持与类型解析修复 导读 本文基于 CodeQL 仓库中 C++ 查
静态分析SAST应用安全漏洞扫描代码质量
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考