baloghadamsoftware created this revision. baloghadamsoftware added reviewers: NoQ, szepet, Szelethus. baloghadamsoftware added a project: clang. Herald added subscribers: Charusso, gamesh411, donat.nagy, mikhail.ramalho, dmgreen, a.sidorin, zzheng, rnkovacs, xazax.hun, whisperity.
For-loops with a variable upper boundary do not differ very much from for-loops with integer literals if the value of the variable is known. Unroll these loops as well, similarly to them. This was a TODO anyway. Repository: rC Clang https://reviews.llvm.org/D63279 Files: lib/StaticAnalyzer/Core/LoopUnrolling.cpp test/Analysis/loop-unrolling.cpp Index: test/Analysis/loop-unrolling.cpp =================================================================== --- test/Analysis/loop-unrolling.cpp +++ test/Analysis/loop-unrolling.cpp @@ -499,3 +499,15 @@ clang_analyzer_numTimesReached(); // expected-warning {{6}} } } + +int unroll_known_value_of_variable() { + int a[9]; + int k = 42; + int n = 9; + for (int i = 0; i < n; i++) { + clang_analyzer_numTimesReached(); // expected-warning {{9}} + a[i] = 42; + } + int b = 22 / (k - 42); // expected-warning {{Division by zero}} + return 0; +} Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp =================================================================== --- lib/StaticAnalyzer/Core/LoopUnrolling.cpp +++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp @@ -84,9 +84,8 @@ hasOperatorName("<="), hasOperatorName(">="), hasOperatorName("!=")), hasEitherOperand(ignoringParenImpCasts(declRefExpr( - to(varDecl(hasType(isInteger())).bind(BindName))))), - hasEitherOperand(ignoringParenImpCasts( - integerLiteral().bind("boundNum")))) + to(varDecl(hasType(isInteger())).bind(BindName))) + .bind("boundVarOperand")))) .bind("conditionOperator"); } @@ -200,18 +199,40 @@ if (!isLoopStmt(LoopStmt)) return false; - // TODO: Match the cases where the bound is not a concrete literal but an - // integer with known value auto Matches = match(forLoopMatcher(), *LoopStmt, ASTCtx); if (Matches.empty()) return false; + const auto State = Pred->getState(); + auto &SVB = State->getStateManager().getSValBuilder(); + auto CounterVar = Matches[0].getNodeAs<VarDecl>("initVarName"); - llvm::APInt BoundNum = - Matches[0].getNodeAs<IntegerLiteral>("boundNum")->getValue(); llvm::APInt InitNum = Matches[0].getNodeAs<IntegerLiteral>("initNum")->getValue(); auto CondOp = Matches[0].getNodeAs<BinaryOperator>("conditionOperator"); + + const Expr *BoundExpr = CondOp->getLHS()->IgnoreParenImpCasts(); + if (BoundExpr == Matches[0].getNodeAs<Expr>("boundVarOperand")) + BoundExpr = CondOp->getRHS()->IgnoreParenImpCasts(); + SVal BoundNumVal = Pred->getSVal(BoundExpr); + + // If the value of the expression is unknown and it is a declaration + // reference then try to get the value of the declaration instead + if (BoundNumVal.isUnknown()) { + if (const auto *BoundDeclRefExpr = dyn_cast<DeclRefExpr>(BoundExpr)) { + // FIXME: Add other declarations such as Objective-C fields + if (const auto *BoundVarDecl = + dyn_cast<VarDecl>(BoundDeclRefExpr->getDecl())) { + BoundNumVal = State->getSVal( + State->getLValue(BoundVarDecl, Pred->getLocationContext())); + } + } + } + const llvm::APSInt *BoundNumPtr = SVB.getKnownValue(State, BoundNumVal); + if (!BoundNumPtr) + return false; + llvm::APInt BoundNum = *BoundNumPtr; + if (InitNum.getBitWidth() != BoundNum.getBitWidth()) { InitNum = InitNum.zextOrSelf(BoundNum.getBitWidth()); BoundNum = BoundNum.zextOrSelf(InitNum.getBitWidth());
Index: test/Analysis/loop-unrolling.cpp =================================================================== --- test/Analysis/loop-unrolling.cpp +++ test/Analysis/loop-unrolling.cpp @@ -499,3 +499,15 @@ clang_analyzer_numTimesReached(); // expected-warning {{6}} } } + +int unroll_known_value_of_variable() { + int a[9]; + int k = 42; + int n = 9; + for (int i = 0; i < n; i++) { + clang_analyzer_numTimesReached(); // expected-warning {{9}} + a[i] = 42; + } + int b = 22 / (k - 42); // expected-warning {{Division by zero}} + return 0; +} Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp =================================================================== --- lib/StaticAnalyzer/Core/LoopUnrolling.cpp +++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp @@ -84,9 +84,8 @@ hasOperatorName("<="), hasOperatorName(">="), hasOperatorName("!=")), hasEitherOperand(ignoringParenImpCasts(declRefExpr( - to(varDecl(hasType(isInteger())).bind(BindName))))), - hasEitherOperand(ignoringParenImpCasts( - integerLiteral().bind("boundNum")))) + to(varDecl(hasType(isInteger())).bind(BindName))) + .bind("boundVarOperand")))) .bind("conditionOperator"); } @@ -200,18 +199,40 @@ if (!isLoopStmt(LoopStmt)) return false; - // TODO: Match the cases where the bound is not a concrete literal but an - // integer with known value auto Matches = match(forLoopMatcher(), *LoopStmt, ASTCtx); if (Matches.empty()) return false; + const auto State = Pred->getState(); + auto &SVB = State->getStateManager().getSValBuilder(); + auto CounterVar = Matches[0].getNodeAs<VarDecl>("initVarName"); - llvm::APInt BoundNum = - Matches[0].getNodeAs<IntegerLiteral>("boundNum")->getValue(); llvm::APInt InitNum = Matches[0].getNodeAs<IntegerLiteral>("initNum")->getValue(); auto CondOp = Matches[0].getNodeAs<BinaryOperator>("conditionOperator"); + + const Expr *BoundExpr = CondOp->getLHS()->IgnoreParenImpCasts(); + if (BoundExpr == Matches[0].getNodeAs<Expr>("boundVarOperand")) + BoundExpr = CondOp->getRHS()->IgnoreParenImpCasts(); + SVal BoundNumVal = Pred->getSVal(BoundExpr); + + // If the value of the expression is unknown and it is a declaration + // reference then try to get the value of the declaration instead + if (BoundNumVal.isUnknown()) { + if (const auto *BoundDeclRefExpr = dyn_cast<DeclRefExpr>(BoundExpr)) { + // FIXME: Add other declarations such as Objective-C fields + if (const auto *BoundVarDecl = + dyn_cast<VarDecl>(BoundDeclRefExpr->getDecl())) { + BoundNumVal = State->getSVal( + State->getLValue(BoundVarDecl, Pred->getLocationContext())); + } + } + } + const llvm::APSInt *BoundNumPtr = SVB.getKnownValue(State, BoundNumVal); + if (!BoundNumPtr) + return false; + llvm::APInt BoundNum = *BoundNumPtr; + if (InitNum.getBitWidth() != BoundNum.getBitWidth()) { InitNum = InitNum.zextOrSelf(BoundNum.getBitWidth()); BoundNum = BoundNum.zextOrSelf(InitNum.getBitWidth());
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits