☰
CodeQL C 库 5.0.0 变更详解:C 13 分析能力升级与 API 迁移指南
2026/10/9 2:54:20 网站建设 项目流程
  • 静态分析
  • SAST
  • 应用安全
  • 漏洞扫描
  • 代码质量

【免费下载链接】codeql

CodeQL: 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# 查询库(csharp/ql/lib)的 5.0.0 版本变更说明 csharp/ql/lib/change-notes/released/5.0.0.md 为主线,系统梳理该版本引入的破坏性 API 变更与 C# 13 新增分析能力:UnboundGenericType.getInstanceType与ControlFlowGraph中Node.getElement的移除、ReadOnlySpan重载的 MaD 数据流模型、OverloadResolutionPriority特性支持,以及部分属性(partial properties)与索引器支持。读完本文,你将了解如何在升级 CodeQL C# 查询库时完成对应代码迁移,并能利用新增的 QL 类与模型文件扩展 C# 13 代码的污点追踪与数据流分析。

一、版本定位:C# 13 / .NET 9 全量支持的衔接版本

在仓库总变更日志 csharp/ql/lib/CHANGELOG.md 中,5.0.0 位于 4.0.x 之后、6.0.0 之前。紧随其后的 6.0.0 版本宣布"Full support for C# 13 / .NET 9. All new language features are now supported by the extractor"(见 csharp/ql/lib/CHANGELOG.md#L340-L346),而 5.0.0 正是为 C# 13 全面落地铺路的衔接版本:它一面清理历史遗留的废弃 API(Breaking Changes),一面为 C# 13 的三项新语言特性补上 QL 库支持与数据流模型。

因此,5.0.0 的变更可以归纳为两条主线:

  • 破坏性变更:删除两个已废弃的 QL 谓词,属于 API 清理与语义对齐;
  • 分析能力增强:围绕 C# 13 的ReadOnlySpan重载建模、OverloadResolutionPriority特性与 partial 成员,扩展了数据流模型与 QL 类。

下文分别展开。

二、破坏性变更:两个废弃谓词的移除与迁移

2.1 删除UnboundGenericType.getInstanceType

5.0.0 删除了UnboundGenericType类上的废弃谓词getInstanceType。该类的定义位于 csharp/ql/lib/semmle/code/csharp/Generics.qll#L128-L164,从源码注释可见:

An unbound generic type. This is a generic type with type parameters (for exampleList<T>) or elided type parameters (for exampleList`1).

即"未绑定泛型类型"代表List<T>这类带类型参数的泛型声明本身,与之相对的是G<int>这类已构造(constructed)类型。UnboundGenericType当前提供的核心接口包括:

  • getAConstructedGeneric():获取该未绑定泛型的一个已构造版本,涵盖封闭构造类型(如G<int>)与开放构造类型(如class Other<T> { G<T> g; }中的G<T>);
  • getUnboundDeclaration():获取自身的未绑定声明;
  • getChild(int n)/getTypeParameter(n):遍历类型参数;
  • toStringWithTypes()/getName():类型名输出。

被删除的getInstanceType正是从"未绑定泛型"反查"实例类型"的旧入口。从仓库当前代码看,这一查询意图已由类型体系自身的继承关系(ConstructedType与UnboundGeneric家族)承载,例如Conversion.qll中通过ConstructedType.getUnboundGeneric()在两种类型间来回切换(见 csharp/ql/lib/semmle/code/csharp/Conversion.qll#L110-L118)。

迁移建议:若你的自定义查询中调用了UnboundGenericType.getInstanceType(),需改为通过ConstructedType/ValueOrRefType的类型层次遍历来获取实例类型;典型替代模式是使用getAConstructedGeneric()获得构造类型后再取具体实例。

2.2 删除ControlFlowGraph.qll中Node.getElement,改用getAstNode

第二个破坏性变更影响控制流图(CFG)API:ControlFlowGraph.qll的Node类上废弃的getElement谓词被删除,官方迁移路径是改用getAstNode。

公共模块 csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll 通过private import internal.ControlFlowGraph引入内部实现,而内部实现 csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll#L71-L74 中定义了:

module Ast implements AstSig<Location> { class AstNode = ControlFlowElementOrCallable; ... }

可见AstNode是"控制流元素或可调用对象"的别名,getAstNode()返回的正是与 CFG 节点对应的 AST 节点(ControlFlowElement或Callable)。仓库内部的既有代码已经全面迁移到新 API,例如 csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowReachability.qll#L14-L16 中:

node.getAstNode() = result not exists(node.getAstNode()) and result = node.getEnclosingCallable()

迁移建议:将自定义查询中的node.getElement()直接替换为node.getAstNode()。两者语义一致(返回 CFG 节点对应的 AST 元素),旧名仅是历史遗留的别名,替换不改变分析结果。

三、C# 13:ReadOnlySpan重载的 MaD 数据流模型

3.1 背景:MaD(Model-as-Data)模型机制

CodeQL 的数据流分析将"哪些库调用是污点源/汇/传递步骤"声明为外部模型(external models),以 YAML 形式存放在csharp/ql/lib/ext/目录下。这些模型通过可扩展谓词summaryModel被加载进分析,其定义见 csharp/ql/lib/semmle/code/csharp/dataflow/internal/ExternalFlowExtensions.qll#L42-L45:

extensible predicate summaryModel( string namespace, string type, boolean subtypes, string name, string signature, string ext, string input, string output, string kind, string provenance, QlBuiltins::ExtensionId madId );

模型列语义在 csharp/ql/lib/semmle/code/csharp/dataflow/internal/ExternalFlow.qll#L60-L95 中有权威说明,要点如下:

  • input/output描述数据流端点:Argument[n](参数,this表示限定符)、ReturnValue(返回值)、Parameter等;
  • 端点可追加后缀:.Element(选择集合中的元素)、.Field[f](字段内容)、.Property[p](属性内容);
  • kind标记模型类别:taint(默认附加污点传播步骤)、value(全局值保持步骤);
  • provenance标记模型来源:manual(人工编写)、df-generated(模型生成器产出)等。

5.0.0 的改动正是为 C# 13 中新增的、以System.ReadOnlySpan<T>为参数的 .NET 重载补充summaryModel,使污点流能够穿越这些新签名。

3.2 具体模型示例

变更说明中点名的示例是String.Format(System.String, System.ReadOnlySpan<System.Object>)。虽然该具体条目属于生成模型,但仓库中同类ReadOnlySpan模型遍布 csharp/ql/lib/ext/System.Text.model.yml,例如:

- ["System.Text", "Encoding", True, "GetBytes", "(System.ReadOnlySpan<System.Char>,System.Span<System.Byte>)", "", "Argument[0].Element", "Argument[1]", "taint", "manual"] - ["System.Text", "Encoding", False, "GetString", "(System.ReadOnlySpan<System.Byte>)", "", "Argument[0].Element", "ReturnValue", "taint", "manual"] - ["System.Text", "StringBuilder", False, "AppendFormat", "(System.String,System.ReadOnlySpan<System.Object>)", "", "Argument[1].Element", "Argument[this]", "taint", "manual"]

逐列解读StringBuilder.AppendFormat(System.String, System.ReadOnlySpan<System.Object>)这条模型:

列值含义
namespaceSystem.Text命名空间
typeStringBuilder类型
subtypesFalse仅精确匹配,不覆盖子类型
nameAppendFormat方法名
signature(System.String,System.ReadOnlySpan<System.Object>)参数签名
ext(空)扩展限定
inputArgument[1].Element污点从第 2 个参数(format 字符串)进入
outputArgument[this]流向StringBuilder实例本身
kindtaint污点传播步骤
provenancemanual人工编写

类似的ReadOnlySpan模型还出现在 csharp/ql/lib/ext/System.IO.model.yml(如Path.Combine(System.ReadOnlySpan<System.String>)、Stream.Write(System.ReadOnlySpan<System.Byte>))与 csharp/ql/lib/ext/System.Collections.Immutable.model.yml(如ImmutableArray.ToImmutableArray<T>(System.ReadOnlySpan<T>))中。

分析能力提升:.Element后缀意味着分析器会把"span 中元素"与"span 整体"当作可传播的污点载体,从而让 C# 13 时代惯用的ReadOnlySpan<byte>、ReadOnlySpan<char>等零拷贝 API 之间的污点链不再断裂——这对检测格式字符串注入、路径操纵、编码转换类漏洞至关重要。

四、C# 13:OverloadResolutionPriority特性支持

C# 13 引入[OverloadResolutionPriority(int)]特性,允许开发者显式声明重载的解析优先级。5.0.0 为此新增了专用 QL 类SystemRuntimeCompilerServicesOverloadResolutionPriorityAttribute,定义于 csharp/ql/lib/semmle/code/csharp/frameworks/system/runtime/CompilerServices.qll#L87-L98:

/** An attribute of type `System.Runtime.CompilerServices.OverloadResolutionPriority`. */ class SystemRuntimeCompilerServicesOverloadResolutionPriorityAttribute extends Attribute { SystemRuntimeCompilerServicesOverloadResolutionPriorityAttribute() { this.getNamespace() instanceof SystemRuntimeCompilerServicesNamespace and this.getType().hasName("OverloadResolutionPriorityAttribute") } /** * Gets the priority number. */ int getPriority() { result = this.getConstructorArgument(0).getIntValue() } }

该类的设计要点:

  • 通过命名空间(System.Runtime.CompilerServices)加类型名双重约束完成识别,避免误匹配其他同名特性;
  • 核心方法getPriority()从构造参数[0]解析出整型优先级数值。

查询用例:借助该类,可以编写 QL 查询找出所有标注了OverloadResolutionPriority的方法及其优先级数值,例如:

import csharp from SystemRuntimeCompilerServicesOverloadResolutionPriorityAttribute attr select attr, attr.getPriority(), attr.getAnnotatedElement()

由于该特性影响编译器在多个重载间的选择,建模后数据流分析也能更准确地判定"实际被调用的重载"是哪一个,从而提升调用图与污点分析精度。

五、C# 13:partial 属性与索引器支持

C# 13 允许属性和索引器像方法一样使用partial修饰符拆分声明与实现。5.0.0 为该语言特性补齐了 QL 库支持。

从类型系统层面看,Property与Indexer两个类分别定义在 csharp/ql/lib/semmle/code/csharp/Property.qll#L137 与 csharp/ql/lib/semmle/code/csharp/Property.qll#L313,二者均继承DeclarationWithGetSetAccessors(带 get/set 访问器的声明基类)。而partial修饰符的判定能力来自成员基类 csharp/ql/lib/semmle/code/csharp/Member.qll#L145-L146:

/** Holds if this declaration is `partial`. */ predicate isPartial() { this.hasModifier("partial") }

因此,新增支持后可以直接在查询中识别 partial 属性/索引器并关联其多个声明片段:

import csharp from Property p where p.isPartial() select p, "partial property declaration"

仓库中对 partial 声明的处理已有先例——ExprOrStmtParent.qll中通过e.(Modifiable).isPartial()判断 partial 成员(见 csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll#L84),DataFlowDispatch.qll也注明 partial 方法可能有多个源码位置(见 csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll#L65)。5.0.0 将此能力扩展至属性与索引器,使跨文件拆分的属性声明在 AST 与数据流层面被完整识别。

六、升级与验证建议

升级路径:升级 CodeQL CLI 及 C# 查询包到包含 5.0.0 的版本后,自定义 QL 查询若仍引用两个被删谓词,编译器会直接报错,可按上文迁移建议逐个替换为getAConstructedGeneric()/getAstNode()。

验证方式:

  1. 用仓库自带的 QL 测试框架对迁移后的查询跑回归测试,确认与旧版本输出一致(CFG 节点的getAstNode替换属纯重命名,不应改变结果);
  2. 针对 C# 13 代码库(如使用ReadOnlySpan的String.Format、标注OverloadResolutionPriority的重载、跨文件 partial 属性),运行数据流/污点类查询(如注入、路径操纵)验证新模型与类是否生效;
  3. 查询模型加载情况可通过ExternalFlow.qll的summaryModel谓词间接确认——若模型未生效,涉及ReadOnlySpan签名的方法将不产生对应的污点传播步骤。

参考资料

  • 变更说明原文:csharp/ql/lib/change-notes/released/5.0.0.md
  • 总变更日志:csharp/ql/lib/CHANGELOG.md
  • UnboundGenericType定义:csharp/ql/lib/semmle/code/csharp/Generics.qll
  • CFG 公共/内部模块:csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll 与 csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll
  • OverloadResolutionPriorityQL 类:csharp/ql/lib/semmle/code/csharp/frameworks/system/runtime/CompilerServices.qll
  • 模型语法规范:csharp/ql/lib/semmle/code/csharp/dataflow/internal/ExternalFlow.qll
  • 模型文件示例:csharp/ql/lib/ext/System.Text.model.yml、csharp/ql/lib/ext/System.IO.model.yml、csharp/ql/lib/ext/System.Collections.Immutable.model.yml
  • 静态分析
  • SAST
  • 应用安全
  • 漏洞扫描
  • 代码质量

【免费下载链接】codeql

CodeQL: 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
点击查看免费下载

相关推荐

上一篇:FunASR中FSMN-VAD模型句尾检测优化实践
下一篇:Frappe HR未来工作:远程办公与自动化趋势

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询