ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

cppcheck 无效迭代器解引用检查:derefInvalidIterator 与 derefInvalidIteratorRedundantCheck 原理与实战

cppcheck 无效迭代器解引用检查:derefInvalidIterator 与 derefInvalidIteratorRedundantCheck 原理与实战 开发工具静态分析代码质量质量保障【免费下载链接】cppcheckstatic analysis of C/C code项目地址https://gitcode.com/gh_mirrors/cpp/cppcheck点击查看免费下载本文围绕 cppcheck 的 STL 迭代器安全分析展开深入解析derefInvalidIterator直接判定的无效迭代器解引用与derefInvalidIteratorRedundantCheck邻近有效性检查与解引用位置错位两个检查项包括其触发场景、修复范式、底层实现原理与对应测试用例。读完本文你将能够在自己的 C/C 项目中准确识别这类未定义行为理解 cppcheck 是如何借助 ValueFlow 迭代器值与条件扫描推断迭代器失效并学会通过修复代码、内联抑制等方式处理相关告警。检查项速览属性值检查 IDderefInvalidIterator、derefInvalidIteratorRedundantCheck告警消息Dereference of an invalid iterator: v.begin()-1错误分类Undefined Behaviour未定义行为严重级别Error / Warning适用语言C关联 CWECWE-825在移除操作之后使用已失效的指针检查器文档位于 man/checkers/derefInvalidIterator.md对应的核心实现在 lib/checkstl.cpp测试用例集中在 test/teststl.cpp。两个检查 ID 的区别文档给出了两个既相关又有明确分工的检查 IDderefInvalidIteratorcppcheck 能够在解引用发生的位置直接判定该迭代器可能无效。典型场景包括迭代器指向end()、位于begin()之前例如begin() - 1、超出容器范围或已知容器为空时对begin()/end()的解引用。derefInvalidIteratorRedundantCheck代码中确实存在对同一迭代器的有效性检查但解引用却发生在该检查不覆盖的地方例如检查写在if中解引用却写在if之后。此时二者必居其一要么那个有效性检查是多余的redundant要么这次解引用就是一个 bug。从源码看这两个 ID 由同一个报告函数dereferenceInvalidIteratorError()分发lib/checkstl.cpp当无效解引用的来源带有条件value-condition存在时输出derefInvalidIteratorRedundantCheck始终为 warning当无条件、可直接判定时输出derefInvalidIterator且根据值的确定性value-isKnown()分别以 error 或 warning 报告。为什么这是个必须修复的问题对不指向真实元素的迭代器执行解引用是未定义行为undefined behaviour。C 标准容器std::vector、std::string、std::list、std::map等的迭代器协议约定end()是“最后一个元素之后”的哨兵位置不能解引用任何把迭代器移到begin()之前或end()之后的运算如begin() - 1、end() 1产生的迭代器同样不可解引用。实践中这类错误很容易写得“只差一行”有效性检查在代码里却写在了解引用的错误一侧导致编译通过、运行时行为未定义。如何修复文档中的完整示例修复一直接越界derefInvalidIterator修复前——v.begin() - 1越界#include vector void f() { std::vectorint v{ 1, 2, 3 }; v.erase(v.begin() - 1); // - derefInvalidIterator: v.begin()-1 is out of bounds }修复后——使用合法迭代器#include vector void f() { std::vectorint v{ 1, 2, 3 }; v.erase(v.begin()); }修复二检查与解引用错位derefInvalidIteratorRedundantCheck修复前——if (it ! v.end())这个检查形同虚设解引用发生在检查之外#include vector #include algorithm int f(std::vectorint v, int i) { auto it std::find(v.begin(), v.end(), i); if (it ! v.end()) {} return *it; // - derefInvalidIteratorRedundantCheck: dereferenced outside the if that checked it }修复后——把解引用移入检查分支并在未找到时返回兜底值#include vector #include algorithm int f(std::vectorint v, int i) { auto it std::find(v.begin(), v.end(), i); if (it ! v.end()) return *it; return -1; }底层实现原理cppcheck 对这两类问题的检测分两条独立路径均由CheckStlImpl承担路径一条件表达式扫描checkDereferenceInvalidIteratorcheckDereferenceInvalidIterator()lib/checkstl.cpp遍历符号数据库中的if、while、do、for作用域仅关注由或||连接的条件表达式对纯表达式查找形如x ! v.end()/rend()/cend()/crend()的有效性检查对纯||表达式查找形如x v.end()/...的检查如果在该有效性检查之前就存在对同一变量的解引用* it则判定为解引用先于检查报告derefInvalidIterator。for循环只扫描两个分号之间的条件区段。这一路径对应测试中大量std::isalpha(*i) i ! str.end()类用例。路径二ValueFlow 迭代器值分析checkDereferenceInvalidIterator2checkDereferenceInvalidIterator2()lib/checkstl.cpp基于 ValueFlow 在每个 token 上挂载的值流信息做数值推理收集 token 上的容器大小值isContainerSizeValue()逐一遍历迭代器值isIteratorValue()区分isIteratorEndValue()与isIteratorStartValue()当迭代器为end()且偏移量intvalue 0或为begin()且偏移量 0或begin() n超过容器大小intvalue cValue-intvalue时判定为无效迭代器对空容器上的/--推进emptyAdvance也会单独报告越界。这条路径使 cppcheck 能跨语句追踪迭代器的算术偏移例如f().end() 1、std::end(f()) 1这类通过函数返回值获得的迭代器。报告时若该无效状态来自某个分支条件就会切换为derefInvalidIteratorRedundantCheck并附带条件说明如Either the condition it!v.end() is redundant or there is possible dereference of an invalid iterator。错误的报告与抑制dereferenceInvalidIteratorError()通过reportError输出同时遵循严重级别确定性高known为 error可能性推断possible为 warning确定性Certainty不确定路径或inconclusive时标记为inconclusive抑制机制和其他检查一样支持// cppcheck-suppress derefInvalidIterator行内抑制测试配置 test/cfg/std.cpp 中即有实际使用示例。测试验证与典型行为边界测试集中在 test/teststl.cpp 的dereferenceInvalidIterator()第 5375 行与dereferenceInvalidIterator2()第 5780 行两个用例组中覆盖了以下关键行为场景预期if (std::isalpha(*i) i ! str.end())报derefInvalidIterator解引用先于检查if (i ! str.end() std::isalpha(*i))不报正确顺序while/do-while/for中的同类模式同样检测且for只分析条件区段解引用的是别的变量如*c不报避免误报std::find结果在if外解引用报derefInvalidIteratorRedundantCheck并给出错误路径v.begin() - 1、f().end() 1报derefInvalidIteratorerrorif (i ! v.end() (i1) ! v.end() *(i1) *i)不报双重检查充分dereferenceInvalidIterator2用例组test/teststl.cpp还专门验证了通过函数返回值获得容器的场景(void)std::find(f().begin() 1, f().end(), 0)这类语句中end() 1这类越界偏移会被准确识别。相关检查器eraseIteratorOutOfBounds.md与本文档互为“姊妹检查”——它针对的是用越界迭代器调用erase()而不是解引用的场景对应eraseIteratorOutOfBounds与eraseIteratorOutOfBoundsCond两个 ID。eraseDereference.md更一般的“解引用已被 erase 失效的迭代器”检查其中也交叉引用了本文档。三者共同覆盖了 C 迭代器使用中“越界构造—无效解引用—失效后复用”的常见错误链条。在项目中的启用方式cppcheck 的 STL 检查CheckStl默认启用 error 级别告警warning 级别需要在命令行显式开启# 仅启用 warning 级别derefInvalidIteratorRedundantCheck 属于 warning cppcheck --enablewarning file.cpp # 同时启用 style 与 performance 等全部检查 cppcheck --enableall file.cpp从实现看checkDereferenceInvalidIterator()开头即以mSettings.severity.isEnabled(Severity::warning)作为前置门槛lib/checkstl.cpp因此在默认配置下该检查的 warning 分支不会触发而可确定性判定的 error 分支如v.begin() - 1、f().end() 1无需额外开关即可检出。如需对个别确认无害的告警做抑制可沿用 cppcheck 的标准抑制语法// cppcheck-suppress derefInvalidIterator auto it v.end();小结derefInvalidIterator与derefInvalidIteratorRedundantCheck是 cppcheck 针对 C 未定义行为提供的一对低成本高价值检查前者依托 ValueFlow 的迭代器数值推理直接锁定越界解引用后者则捕捉“有效性检查写了却没起效”这种极易在代码评审中漏掉的错位模式。理解其两条检测路径条件扫描 值流分析与测试用例中的正反样例既能帮助你修复手头代码也能让你在集成 cppcheck 到 CI 时更准确地判断告警的语义与优先级。赞分享开发工具静态分析代码质量质量保障【免费下载链接】cppcheckstatic analysis of C/C code项目地址https://gitcode.com/gh_mirrors/cpp/cppcheck点击查看免费下载相关推荐cppcheck 检查器深度解析danglingTempReference 与 C 悬空临时对象引用的静态检测cppcheck 检查器深度解析danglingTempReference 与 C 悬空临时对象引用的静态检测 danglingTempReference开发工具静态分析代码质量质量保障Infer 的 INFINITE_LOOP 检测Pulse 无限循环检查器的原理、配置与实战Infer 的 INFINITE_LOOP 检测Pulse 无限循环检查器的原理、配置与实战 本文围绕 Infer 的 INFINITE_LOOP 问题文档静态分析代码质量开发工具OmX vs 原生Codex CLI为什么你需要这个多智能体增强层OmX vs 原生Codex CLI为什么你需要这个多智能体增强层 在AI编程助手的世界中OpenAI Codex CLI已经成为了开发者的强大工具。但当你人工智能AI AgentAgent 编排Agent 工作流CLI开发工具AI 技能上一篇NodeGUI vs Electron性能对比和终极选择指南下一篇ESLint-Plugin-React Flat Config终极指南现代React代码规范配置的10个技巧创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表