ARTICLE DETAIL

资讯详情

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

cppcheck 检查器详解:identicalConditionAfterEarlyExit——提前退出后必然为假的重复条件

cppcheck 检查器详解:identicalConditionAfterEarlyExit——提前退出后必然为假的重复条件 开发工具静态分析代码质量质量保障【免费下载链接】cppcheckstatic analysis of C/C code项目地址https://gitcode.com/gh_mirrors/cpp/cppcheck点击查看免费下载本文以 cppcheck 官方检查器文档 identicalConditionAfterEarlyExit.md 为主体结合 lib/checkcondition.cpp 的源码实现与 test/testcondition.cpp 的测试用例系统讲解该检查器的工作原理、触发场景、修复方式与相关检查器帮助你准确理解并运用这条 Code Quality代码质量类告警。检查器速览项目内容检查器 IDidenticalConditionAfterEarlyExit默认消息Identical condition x1, second condition is always false分类Code Quality严重级别Warning适用语言C / CCWE 编号CWE-398Indicator of Poor Code Quality置信度Certainty::normal该检查器位于条件表达式家族检查器CheckCondition中核心逻辑集中在 lib/checkcondition.cpp 的multiCondition2()函数与identicalConditionAfterEarlyExitError()上报函数内。问题本质提前退出之后同样的条件只能为假触发场景代码中先出现了带有提前退出语句的if分支例如if (cond) return; // 也可以是 throw / continue / break当执行流越过这个if继续向下时cond已经被证明为假——否则函数或循环、switch早已退出。此时如果在后面再次测试同一个条件那么这个第二次的条件必然永远为假void f(int x) { if (x 1) return; if (x 1) {} // - 到这里 x1 已经不可能成立恒为假 }第二个if (x 1)要么是永远无法进入的死代码要么是开发者本想检查其他条件却写错了即“两个条件本意不同”的笔误信号。官方文档用一句话概括其动机Once execution passes the early exit, the condition that would have triggered it is already known to be false for the rest of the function - re-testing it is always false, so its either dead code or a sign the two conditions were meant to check different things.翻译过来即一旦执行通过提前退出点触发该退出的条件在函数剩余部分必然为假再次测试它恒为假因此这要么是死代码要么是“两个条件本应检查不同事物”的暗示。源码中的实现位置该逻辑实现在 lib/checkcondition.cpp 的multiCondition2()中。函数开头有一个门控判断if (!mSettings.severity.isEnabled(Severity::warning) !mSettings.isPremiumEnabled(identicalConditionAfterEarlyExit) !mSettings.isPremiumEnabled(identicalInnerCondition)) return;从这段代码可以看出两点默认启用依赖 warning 级告警开关--enablewarning或默认配置下均满足identicalConditionAfterEarlyExit同时被列入premium 检查器映射表。在 lib/checkersidmapping.cpp 中可以看到它与其他检查器一起被归入 premium 分组{0.0.2, compareBoolExpressionWithInt,compareValueOutOfTypeRangeError,identicalConditionAfterEarlyExit,identicalInnerCondition,knownConditionTrueFalse},isPremiumEnabled的接口声明位于 lib/settings.h。也就是说即便 warning 级被禁用只要 premium 功能开启该检查器仍可工作。上报函数的两种消息形态实际告警由identicalConditionAfterEarlyExitError()生成lib/checkcondition.cpp。它先判断第二个条件是否出现在return语句中const bool isReturnValue cond2 Token::simpleMatch(cond2-astParent(), return);若第二次出现的条件位于普通if条件中消息为Identical condition expr, second condition is always false若第二次出现的条件位于return expr的返回值表达式中消息变为Identical condition and return expression expr, return value is always false若表达式类型为bool或...return value is always 0其余类型。同时errorPath会记录两条路径信息让 IDE 输出中呈现第一处条件 → 第二处条件的跳转关联errorPath.emplace_back(cond1, If condition expr is true, the function will return/exit); errorPath.emplace_back(cond2, (isReturnValue ? Returning identical expression expr : Testing identical condition expr));这两条路径与 CWE-398、Certainty::normal一起通过reportError上报因此输出中会带有[文件:行:列] - [文件:行:列]的关联格式。触发与修复示例标准修复删除冗余的第二个if官方文档给出的“Before / After”对比例子// Before —— 第二个 if 恒为假 void f(int x) { if (x 1) return; if (x 1) {} // - always false here } // After —— 删除恒假的重复条件 void f(int x) { if (x 1) return; }变体return 表达式中的重复条件除了if条件重复条件也可能出现在函数的return表达式中bool f(int x) { if (x 100) { return false; } return x 100; // - 到这里 x100 必为假返回值恒为 false }这条用例与前面的if形态一起被收录在 test/testcondition.cpp 的identicalConditionAfterEarlyExit测试用例中对应的期望输出分别为[test.cpp:2:9] - [test.cpp:3:9]: (warning) Identical condition x100, second condition is always false [identicalConditionAfterEarlyExit] [test.cpp:2:9] - [test.cpp:3:12]: (warning) Identical condition and return expression x100, return value is always false [identicalConditionAfterEarlyExit]复合条件与复合表达式同样覆盖测试还验证了该检查器能识别第二个条件复合表达式中的子条件例如if (x 100 || y 100)与if (x 100 y 100)中重复出现的x 100都会被单独报出中间穿插无关语句如if (abc) {}也不会阻断分析只要被跟踪的变量没有被改写。注意提前退出语句的形态文档明确指出提前退出语句可以是return、throw、continue、break四种。源码中通过如下匹配来判定是否存在提前退出分支if (Token::Match(scope.bodyStart, { return|throw|continue|break)) types.push_back(MULTICONDITIONTYPE::AFTER);即只有当if的第一个子语句就是return/throw/continue/break时才会进入 AFTER 模式的分析lib/checkcondition.cpp。分析流程与保守退出机制multiCondition2()的整体流程可以概括为遍历函数作用域只处理if、while、for三种条件作用域提取第一个条件cond1对第一个条件做静态审查遍历 AST 收集其中出现的变量vars、是否包含函数调用functionCall、是否包含非 const 函数调用nonConstFunctionCall、是否引用了非局部变量nonlocal。若条件中调用了非 const 函数则直接放弃continue因为其返回值不可预期顺序扫描后续 token寻找第二个条件若if体首句是提前退出语句则同时从if体内部INNER即嵌套在 if 内部的重复条件与if体之后AFTER即提前退出之后的重复条件两个方向分析遇到会改变条件所依赖变量的代码时立即中断见下文保守退出。第二条件的比较逻辑对 AFTER 方向源码遍历第二个条件的 AST 子节点if ((!cond1-hasKnownIntValue() || !secondCondition-hasKnownIntValue()) isSameExpression(true, cond1, secondCondition, mSettings, true, true, errorPath)) { if (!isAliased(vars) !mTokenizer-hasIfdef(cond1, secondCondition)) { identicalConditionAfterEarlyExitError(cond1, secondCondition, errorPath);关键点两个条件都必须尚未具备已知整数值hasKnownIntValue避免与knownConditionTrueFalse检查器重复告警使用isSameExpression做表达式等价判定可识别等价写法如handle ! 0与handle、handle ! nullptr与handle见 test/testcondition.cpp变量被别名alias引用时不上报!isAliased(vars)两个条件之间存在#ifdef预处理分支时不上报hasIfdef避免跨配置误报对应测试 #8858。何时停止扫描避免误报的关键源码在扫描过程中设置了大量“刹车”逻辑确保只在条件依赖的变量确定未被修改时才继续isExpressionChangedAt(cond1, tok, ...)变量在中间被修改立即中断遇到case|break|continue|return|throw且与当前作用域一致立即中断遇到标签; {} %name% :中断遇到for|while|do循环若循环体内可能修改被跟踪变量则中断当前对循环的处理仍标记为 TODO变量发生赋值/自增自减%name% %assign%||--、通过指针/引用/数组下标间接修改、流式读取isLikelyStreamRead、取地址传参等均触发中断被跟踪变量所属对象调用非 const 成员函数时中断条件位于lambda 表达式内部时跳过isNestedInLambda。测试用例中有多条不该报警的场景可佐证这些保守策略例如条件含非 const 成员函数调用且对象非 constif(!coreTree.build()) return; coreTree.dostuff(); if(!coreTree.build()) {}不报警除非对象是 const 引用见 test/testcondition.cppswitch中不同case使用相同条件不报警因为不同 case 是互斥路径见 #daca: labplot 用例全局静态变量在中间被修改时不报警static int failed用例条件之间发生变量自增start时不报警daca icu 用例输入流读取之间测试同一变量不报警daca iqtree 用例。何时启用 exhaustive 检查级别文档特别注明This check may need--check-levelexhaustiveto see every case.multiCondition2()中大量使用了findExpressionChanged/isExpressionChangedAt这类依赖值流valueflow分析的辅助函数。值流分析深度直接受--check-level控制其命令行帮助文本位于 cli/cmdlineparser.cpp--check-levellevel Configure how much valueflow analysis you want: * reduced: Reduce valueflow to finish checking quickly. * normal: Cppcheck uses some compromises in the analysis so the checking will finish in reasonable time. * exhaustive: deeper analysis that you choose when you can wait. The default choice is normal.需要说明的是Settings构造函数内部默认值是exhaustive见 lib/settings.cpp但 CLI 入口在解析参数前会显式回退为normal见 cli/cmdlineparser.cpp 的注释 default to --check-levelnormal from CLI for now。因此从命令行运行 cppcheck 时默认是 normal。想要完整检出所有identicalConditionAfterEarlyExit场景可使用cppcheck --check-levelexhaustive your_file.cpp与相邻检查器的关系一个家族三种形态该检查器属于 cppcheck 条件重复检查家族理解家族全貌有助于选用正确的检查器检查器形态消息特征严重级别identicalConditionAfterEarlyExit本文提前退出return/throw/continue/break之后再次测试同一条件Identical condition ..., second condition is always falseWarningduplicateCondition两个连续平铺的if测试同一条件中间无提前退出The if condition is the same as the previous if conditionStylemultiConditionif/else if链中条件重复死代码或完全相反恒真Expression is always false because else if condition matches previous condition...StyleidenticalInnerCondition直接嵌套在另一个if内部的相同条件Identical inner if condition is always trueWarningoppositeInnerCondition嵌套if的条件与外部条件完全相反Opposite inner if condition leads to a dead code blockWarningoverlappingInnerCondition嵌套if的条件与外部条件部分重叠Overlapping inner if condition is always trueWarning以上四类检查器identicalConditionAfterEarlyExit、identicalInnerCondition、oppositeInnerCondition、overlappingInnerCondition都在multiCondition2()中统一处理共享同一套变量跟踪、isSameExpression/isOppositeCond/isOverlappingCond判定与保守退出机制而duplicateCondition与multiCondition则由相邻的multiCondition()逻辑覆盖。三者的差异仅在于重复条件出现的位置结构平铺if无退出→duplicateConditionelse if链 →multiCondition嵌套if内部 →identicalInnerCondition/oppositeInnerCondition/overlappingInnerCondition提前退出之后 →identicalConditionAfterEarlyExit实战要点总结修复方式直接删除第二个恒假的if或return表达式如果两处条件本应不同则修正为真正想检查的条件。启用方式默认warning 开启即可触发若场景复杂、希望覆盖全部情况加--check-levelexhaustive深度分析。误报保护检查器会主动跳过条件变量被修改、别名引用、跨#ifdef、非 const 函数调用、循环修改、lambda 嵌套等场景若你对结果存疑可对照 test/testcondition.cpp 中的正反用例核对边界。调试手段可在输出中看到[行:列] - [行:列]的 errorPath 关联格式第一处是触发提前退出的条件第二处是恒假的重复条件便于快速定位。深入源码分析主逻辑见 lib/checkcondition.cpp消息构造见 lib/checkcondition.cpp完整测试见 test/testcondition.cpp 起的identicalConditionAfterEarlyExit()用例。赞分享开发工具静态分析代码质量质量保障【免费下载链接】cppcheckstatic analysis of C/C code项目地址https://gitcode.com/gh_mirrors/cpp/cppcheck点击查看免费下载相关推荐awesome-gpt-image-2-API-and-Prompts 角色设计案例指南从人物设定卡到 40K 动力装甲的 GPT-Image-2 提示词工程awesome gpt image 2 API and Prompts 角色设计案例指南从人物设定卡到 40K 动力装甲的 GPT Image 2 提示词工程开发工具静态分析代码质量质量保障cppcheck duplicateConditionalAssign 检查详解识别与 if 条件重复的冗余赋值cppcheck duplicateConditionalAssign 检查详解识别与 if 条件重复的冗余赋值 duplicateConditionalAs开发工具静态分析代码质量质量保障AG-UI × AWS Strands Python 集成 0.4.0 深度解析usage 上报、原生中断、SSRF 加固与协议统一AG UI × AWS Strands Python 集成 0.4.0 深度解析usage 上报、原生中断、SSRF 加固与协议统一 本篇技术指南围绕 AG开发工具静态分析代码质量质量保障上一篇基于 Sub-Agent 路由原语构建多会话 AI 聊天multi-ai-chat 示例深度解析下一篇深度解析chromem-go查询优化从余弦相似度到并行计算的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表