
静态分析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/C 查询库 1.8.0 版本发布说明中针对cpp/new-free-mismatch查询的元数据变更移除external/cwe/cwe-401标签、新增external/cwe/cwe-762标签展开从变更背景、CWE 语义辨析、查询实现原理、底层 QLL 库支撑到测试验证全链路进行讲解。读者读完后既能理解这次标签调整背后的分类学依据也能掌握 CodeQL 如何通过数据流分析在源码级识别new/free、malloc/delete混用这类未定义行为。一、1.8.0 变更说明原文与变更要点变更记录位于仓库 cpp/ql/src/change-notes/released/1.8.0.md全文如下Query Metadata ChangesAdded the tagexternal/cwe/cwe-762tocpp/new-free-mismatch, and removed the tagexternal/cwe/cwe-401. This better matches the behavior of the query.这次变更是一次典型的查询元数据Query Metadata修正核心动作只有两个新增标签external/cwe/cwe-762将查询归类到 CWE-762Mismatched Memory Management Routines内存管理例程不匹配移除标签external/cwe/cwe-401不再将其归类到 CWE-401Improper Release of Memory Before Removing Last Reference释放内存前未移除最后引用即内存泄漏类问题。变更说明明确给出了原因——This better matches the behavior of the query这更贴合查询的实际行为。要理解这句话需要先厘清 CWE-401 与 CWE-762 的语义差异以及该查询真正检测的缺陷模式。二、CWE-401 与 CWE-762 的语义辨析为什么这次调整更准确2.1 CWE-401释放时机不当内存泄漏CWE-401Improper Release of Memory Before Removing Last Reference关注的是内存泄漏问题程序在释放内存之前仍然持有指向该内存的引用导致该内存永远无法被回收。典型场景是失去最后一个指针引用前忘记free/delete其核心矛盾是该释放的没释放。2.2 CWE-762内存管理例程不匹配未定义行为CWE-762Mismatched Memory Management Routines关注的是分配与释放例程不匹配问题用malloc分配的内存却用delete释放或用new分配的内存却用free释放。CWE 对这类问题的描述是当内存通过一种例程分配、却通过另一种不兼容的例程释放时会破坏堆管理器的内部簿记数据结构导致任意代码执行等严重后果。其核心矛盾是释放的方式错了。2.3 二者在 CodeQL 查询行为上的映射对照查询的实际检出行为见下文 cpp/ql/src/Critical/NewFreeMismatch.ql 与测试预期输出cpp/new-free-mismatch只报告分配例程与释放例程种类不一致的问题例如new分配的指针被freemalloc分配的指针被deletenew[]分配的指针被freemalloc分配的指针被delete[]。它并不报告该释放而未释放的内存泄漏——后者属于 CWE-401 的范畴。因此将标签从 CWE-401 调整为 CWE-762使查询的 CWE 分类与其真实行为精确对齐避免安全报告中出现误导性的漏洞归类。这正是变更说明中better matches the behavior of the query的准确含义。三、查询全景定位、元数据与公开文档3.1 查询元数据cpp/new-free-mismatch查询的完整元数据定义在 cpp/ql/src/Critical/NewFreeMismatch.ql 的头部注释中当前仓库状态已包含更新后的cwe-762标签name Mismatching new/free or malloc/delete description An object that was allocated with malloc or new is being freed using a mismatching free or delete. kind problem problem.severity warning security-severity 7.5 precision high id cpp/new-free-mismatch tags reliability security external/cwe/cwe-762要点解读元数据项取值含义idcpp/new-free-mismatch查询在 C/C 语言查询库中的唯一标识是变更说明中引用的名字nameMismatching new/free or malloc/delete查询显示名概括了检出的两类不匹配problem.severitywarning问题级别为警告security-severity7.5安全严重度评分CVSS 风格 010 区间属于高危级别反映了混用分配/释放例程可能引发的堆破坏风险precisionhigh高精度即误报率低、结果可信度高tagsreliability、security、external/cwe/cwe-762可靠性类 安全类并归属 CWE-762注意tags同时带有reliability与security两个标签这与缺陷本质一致new/free混用首先是未定义行为可靠性问题在攻击者可影响分配路径时又可能升级为可利用的内存破坏安全问题。3.2 公开文档qhelp查询配套的人工阅读文档位于 cpp/ql/src/Critical/NewFreeMismatch.qhelp其中明确了检测范围与修复建议检测范围找出参数指向malloc分配内存的delete表达式以及参数指向new分配内存的free调用。此类行为属于未定义行为应当避免。修复建议用new分配的内存必须用delete释放用malloc分配的内存必须用free释放。示例见 cpp/ql/src/Critical/NewFreeMismatch.cppRecord *ptr new Record(...); ... free(ptr); // BAD: ptr was created using new, but is being freed using free四、查询实现原理数据流驱动的分配/释放配对分析4.1 主查询结构NewFreeMismatch.ql的核心逻辑非常凝练全文仅 39 行由三个部分协作完成correspondingKinds谓词定义合法的分配/释放配对只有malloc→free与new→delete两种组合被认为是对应的predicate correspondingKinds(string allocKind, string freeKind) { allocKind malloc and freeKind free or allocKind new and freeKind delete }主查询体通过allocReaches(freed, alloc, allocKind)证明某个被释放的表达式freed的值来源于一次分配alloc通过freeExprOrIndirect(free, freed, freeKind)识别释放表达式及其种类然后剥掉数组后缀replaceAll([], )后做种类比对——这样new[]/free会退化为new/free被判为不匹配new[]/delete[]则退化为new/delete被认定为合法where allocReaches(freed, alloc, allocKind) and freeExprOrIndirect(free, freed, freeKind) and allocKindSimple allocKind.replaceAll([], ) and freeKindSimple freeKind.replaceAll([], ) and not correspondingKinds(allocKindSimple, freeKindSimple) select free, There is a allocKindSimple / freeKindSimple mismatch between this freeKind and the corresponding $., alloc, allocKind告警消息动态拼接出如 There is a new/free mismatch between this free and the correspondingnew 的可读消息并通过$将分配点alloc作为链接元素嵌入告警帮助开发者直接跳转到产生指针的分配位置。4.2 底层库支撑NewDelete.qll查询引用的NewDelete库实现在 cpp/ql/src/Critical/NewDelete.qll约 167 行它提供了关联 new/malloc 与 delete/free的一整套谓词是查询能力的基石1allocExpr识别分配表达式operator new/operator new[]函数调用被归类为new/new[]非OperatorNewAllocationFunction的分配函数调用被归类为malloc从源码看这意味着任何未被识别为new运算符的分配函数都按malloc处理NewExpr/NewArrayExpr语法节点分别归为new/new[]关键设计排除 placement new 及自定义重载参数个数 1 的分配器因为这些形态可能不遵循标准内存管理假设避免误报同时排除未实例化模板中的分配alloc.isFromUninstantiatedTemplate(_)。2allocExprOrIndirect穿透包装函数除了直接分配该谓词还通过函数返回语句递归识别包装了 malloc/new 的包装函数——例如自定义的my_malloc内部调用malloc并返回其结果或返回语句与结果之间存在局部数据流DataFlow::localExprFlow从而把对my_malloc的调用也识别为一次malloc分配。3allocReaches分配结果的值流传播这是全库最复杂的部分它回答当前被释放的表达式e是否只能来源于某次分配。实现基于三条路径直接路径e就是分配表达式本身SSA 路径通过semmle.code.cpp.controlflow.SSA的SsaDefinition与getAnUltimateDefiningValue/getAUse沿静态单赋值链追踪局部变量的值来源全局路径非栈变量全局/静态变量通过getAnAssignedValue与allocReaches0递归关联并设置strictcount(...) 50的访问次数上限以避免极端昂贵的分析。allocReaches还额外施加一个唯一性约束只有当表达式e的值来源只有kind这一种分配类型时才算成立not exists(... kind ! k2)从而保证指向确定由某类分配产生的内存这一前提可靠。4freeExpr/freeExprOrIndirect识别释放操作直接释放operator delete/operator delete[]调用归为delete/delete[]非OperatorDeleteDeallocationFunction的函数调用归为freeDeleteExpr/DeleteArrayExpr语法节点也分别归为delete/delete[]间接释放识别包装了 free/delete 的包装函数通过函数形参与实参的对应关系把外层调用的实参映射为内层真正被释放的表达式。从源码结构可以推断这套直接 间接穿透包装 值流传播的组合设计是查询在保持high精度的同时仍能跨函数、跨全局变量捕捉不匹配释放的关键。五、测试验证从预期输出看检出的缺陷全貌5.1 测试配置查询的回归测试配置在 cpp/ql/test/query-tests/Critical/NewFree/NewFreeMismatch.qlref内容为query: Critical/NewFreeMismatch.ql postprocess: utils/test/InlineExpectationsTestQuery.ql即对Critical/NewFreeMismatch.ql运行测试并使用InlineExpectationsTestQuery做结果后处理。5.2 预期输出解析测试预期文件 cpp/ql/test/query-tests/Critical/NewFree/NewFreeMismatch.expected 覆盖了大量真实场景从中可以归纳出该查询的能力边界new/free不匹配test.cpp:41、test.cpp:75等new后freemalloc/delete不匹配test.cpp:36、test.cpp:68等malloc后delete数组形态test.cpp:76检出new[]/freetest.cpp:233检出malloc/delete[]印证了主查询中剥除[]后缀再比对的设计间接分配包装函数test.cpp:91my_malloc包装malloc后delete、test.cpp:99malloc后调用包装的my_delete、test.cpp:135/test.cpp:152二级包装my_malloc_2/my_malloc_3印证allocExprOrIndirect/freeExprOrIndirect的穿透能力库函数别名test.cpp:441strdup、test.cpp:443strndup、test.cpp:445wcsdup分配的内存被delete说明这些返回malloc内存的字符串复制函数也被纳入了分配识别范围释放点同时覆盖test2.cpp:57delete与test2.cpp:58operator delete对同一malloc结果的两类释放形态都被检出。值得注意的是预期输出中同时存在new/free mismatch与malloc/delete mismatch两类消息这与查询nameMismatching new/free or malloc/delete及description的表述完全一致也从行为层面再次验证了归属 CWE-762 的合理性这些缺陷无一例外都是分配与释放例程不匹配。六、变更的实际影响与使用建议6.1 对查询结果使用者的影响元数据标签的调整不改变查询的分析逻辑也不改变检出结果本身但它会影响下游消费者对告警的解读安全报告分类在按 CWE 聚合的安全仪表盘、漏洞数据库或合规审计中该查询的告警将归入 CWE-762内存管理例程不匹配而非 CWE-401内存泄漏分类更准确便于安全团队按正确的缺陷类型分流处置查询筛选使用 CodeQL CLI 或查询套件按tags过滤查询时通过cwe-762可以精确筛选到此类问题依赖 CWE-401 标签的旧筛选规则需相应更新。6.2 修复实践依据 NewFreeMismatch.qhelp 的建议修复时只需保证分配与释放例程成对// 修复 1new 分配 → delete 释放 Record *ptr new Record(...); ... delete ptr; // 修复 2malloc 分配 → free 释放 char *buf (char *)malloc(BUFSIZE); ... free(buf);同时注意数组形态的对应关系new[]必须配delete[]。此外从库实现可以看出自定义包装函数如my_malloc与strdup等库函数同样在分配识别范围内因此修复时要追溯指针的真实来源而不只是看释放点的写法。七、小结cpp/new-free-mismatch是 CodeQL C/C 库中一处小而关键的可靠性/安全查询它以allocReaches数据流传播 分配/释放种类比对为核心覆盖直接、间接包装函数、数组形态与库函数别名等丰富场景并以high精度、warning级别、security-severity 7.5的属性产出告警。1.8.0 版本将其 CWE 标签从 CWE-401 调整为 CWE-762是一次严谨的元数据纠偏——让漏洞分类与查询真实行为保持一致也为后续按 CWE 维度的告警治理提供了更准确的依据。如需深入查阅可继续阅读查询本体 NewFreeMismatch.ql、支撑库 NewDelete.qll 及测试预期 NewFreeMismatch.expected。赞分享静态分析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.6.1 版本新增检测能力深度解析cpp/double-free 与 cpp/use-after-free 内存安全查询CodeQL C 0.6.1 版本新增检测能力深度解析cpp/double free 与 cpp/use after free 内存安全查询 本文围绕 C静态分析SAST应用安全漏洞扫描代码质量CodeQL C 1.3.0 版本详解新增 cpp/guarded-free 查询与 cpp/too-few-arguments 改进CodeQL C 1.3.0 版本详解新增 cpp/guarded free 查询与 cpp/too few arguments 改进 本篇技术文章以 C静态分析SAST应用安全漏洞扫描代码质量CodeQL C/C 分析器 1.2.3 变更解读cpp/incorrect-allocation-error-handling 查询的精度提升与误报治理CodeQL C/C 分析器 1.2.3 变更解读cpp/incorrect allocation error handling 查询的精度提升与误报治理静态分析SAST应用安全漏洞扫描代码质量上一篇Styled System 组件类型Component Types实战指南用 compose 打造统一风格与一致 Props API 的 UI 组件体系下一篇TranslucentTB进阶指南Windows多显示器任务栏透明配置专业实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考