[PATCH] D73270: [clang-tidy] Fix false positive in bugprone-infinite-loop
Balogh, Ádám via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 24 07:35:42 PST 2020
baloghadamsoftware marked 3 inline comments as done.
baloghadamsoftware added inline comments.
================
Comment at: clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp:186
+ }
+ }
+
----------------
gribozavr2 wrote:
> baloghadamsoftware wrote:
> > gribozavr2 wrote:
> > > I think this logic should go into `isChanged()`, similarly to how it handles for loops today.
> > `isChanged()` looks for changes of a specific variable. This part collects the variables to check. The fundamental problem with the current logic is that it only look for the condition variables in the `Condition` of the loop statement, but it does not contain the initial value of the variable declared inside the condition part of the `while` statement. Thus in case of `while (int m = n) { n--; }` the condition is only the expression `m`. Thus we simply cannot grab `n` by only checking the condition thus consider this loop as infinite because `m` is not changed. Taking the whole loop statement instead of the condition is also wrong because then the following obviously infinite loop is not detected: `while (n) { m--; }` because `m` is also grabbed from the body which must not. We must explicitly check the variable of the initialization expression of variable declared in the condition of `while` loops because it is a separate child of the statement.
> Yes, I see what you mean -- and my suggestion was incorrect.
>
> However, right now the variable declared in the while loop is being treated like something that carries over to the next loop iteration:
>
> ```
> while (int k = Limit) { k--; } // no warning with this patch
> ```
>
> This is because this while loop still has a condition that checks that `k != 0`, and we scan that in the isAtLeastOneCondVarChanged call on line 173.
>
> I think a better fix would bind `Cond` to the initialization expression of the while loop variable. Like this:
>
> ```
> void InfiniteLoopCheck::check(const MatchFinder::MatchResult &Result) {
> const auto *Cond = Result.Nodes.getNodeAs<Expr>("condition");
> const auto *LoopStmt = Result.Nodes.getNodeAs<Stmt>("loop-stmt");
> const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
>
> bool ShouldHaveConditionVariables = true;
> if (const auto *While = dyn_cast<WhileStmt>(LoopStmt)) {
> if (const VarDecl *LoopVarDecl = While->getConditionVariable()) {
> if (const Expr *Init = LoopVarDecl->getInit()) {
> ShouldHaveConditionVariables = false;
> Cond = Init;
> }
> }
> }
> Cond->dump();
>
> if (isAtLeastOneCondVarChanged(Func, LoopStmt, Cond, Result.Context)) {
> return;
> }
>
> std::string CondVarNames = getCondVarNames(Cond);
> if (ShouldHaveConditionVariables && CondVarNames.empty())
> return;
>
> if (CondVarNames.empty()) {
> diag(LoopStmt->getBeginLoc(),
> "this loop is infinite; it does not check any variables in the condition");
> } else {
> diag(LoopStmt->getBeginLoc(),
> "this loop is infinite; none of its condition variables (%0)"
> " are updated in the loop body")
> << CondVarNames;
> }
> }
> ```
>
> If you agree, please also add `while (int k = Limit) { k--; }` to the tests.
Oh, I forgot that the declared variable gets a new value at every iteration thus its changes are not relevant. Thank you, I fixed this now.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D73270/new/
https://reviews.llvm.org/D73270
More information about the cfe-commits
mailing list