1 //== IdenticalExprChecker.cpp - Identical expression checker----------------==// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// \brief This defines IdenticalExprChecker, a check that warns about 12 /// unintended use of identical expressions. 13 /// 14 /// It checks for use of identical expressions with comparison operators and 15 /// inside conditional expressions. 16 /// 17 //===----------------------------------------------------------------------===// 18 19 #include "ClangSACheckers.h" 20 #include "clang/AST/RecursiveASTVisitor.h" 21 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 22 #include "clang/StaticAnalyzer/Core/Checker.h" 23 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 24 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 25 26 using namespace clang; 27 using namespace ento; 28 29 static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, 30 const Stmt *Stmt2, bool IgnoreSideEffects = false); 31 //===----------------------------------------------------------------------===// 32 // FindIdenticalExprVisitor - Identify nodes using identical expressions. 33 //===----------------------------------------------------------------------===// 34 35 namespace { 36 class FindIdenticalExprVisitor 37 : public RecursiveASTVisitor<FindIdenticalExprVisitor> { 38 BugReporter &BR; 39 const CheckerBase *Checker; 40 AnalysisDeclContext *AC; 41 public: 42 explicit FindIdenticalExprVisitor(BugReporter &B, 43 const CheckerBase *Checker, 44 AnalysisDeclContext *A) 45 : BR(B), Checker(Checker), AC(A) {} 46 // FindIdenticalExprVisitor only visits nodes 47 // that are binary operators, if statements or 48 // conditional operators. 49 bool VisitBinaryOperator(const BinaryOperator *B); 50 bool VisitIfStmt(const IfStmt *I); 51 bool VisitConditionalOperator(const ConditionalOperator *C); 52 53 private: 54 void reportIdenticalExpr(const BinaryOperator *B, bool CheckBitwise, 55 ArrayRef<SourceRange> Sr); 56 void checkBitwiseOrLogicalOp(const BinaryOperator *B, bool CheckBitwise); 57 void checkComparisonOp(const BinaryOperator *B); 58 }; 59 } // end anonymous namespace 60 61 void FindIdenticalExprVisitor::reportIdenticalExpr(const BinaryOperator *B, 62 bool CheckBitwise, 63 ArrayRef<SourceRange> Sr) { 64 StringRef Message; 65 if (CheckBitwise) 66 Message = "identical expressions on both sides of bitwise operator"; 67 else 68 Message = "identical expressions on both sides of logical operator"; 69 70 PathDiagnosticLocation ELoc = 71 PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager()); 72 BR.EmitBasicReport(AC->getDecl(), Checker, 73 "Use of identical expressions", 74 categories::LogicError, 75 Message, ELoc, Sr); 76 } 77 78 void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B, 79 bool CheckBitwise) { 80 SourceRange Sr[2]; 81 82 const Expr *LHS = B->getLHS(); 83 const Expr *RHS = B->getRHS(); 84 85 // Split operators as long as we still have operators to split on. We will 86 // get called for every binary operator in an expression so there is no need 87 // to check every one against each other here, just the right most one with 88 // the others. 89 while (const BinaryOperator *B2 = dyn_cast<BinaryOperator>(LHS)) { 90 if (B->getOpcode() != B2->getOpcode()) 91 break; 92 if (isIdenticalStmt(AC->getASTContext(), RHS, B2->getRHS())) { 93 Sr[0] = RHS->getSourceRange(); 94 Sr[1] = B2->getRHS()->getSourceRange(); 95 reportIdenticalExpr(B, CheckBitwise, Sr); 96 } 97 LHS = B2->getLHS(); 98 } 99 100 if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) { 101 Sr[0] = RHS->getSourceRange(); 102 Sr[1] = LHS->getSourceRange(); 103 reportIdenticalExpr(B, CheckBitwise, Sr); 104 } 105 } 106 107 bool FindIdenticalExprVisitor::VisitIfStmt(const IfStmt *I) { 108 const Stmt *Stmt1 = I->getThen(); 109 const Stmt *Stmt2 = I->getElse(); 110 111 if (!Stmt1 || !Stmt2) 112 return true; 113 114 // Special handling for code like: 115 // 116 // if (b) { 117 // i = 1; 118 // } else 119 // i = 1; 120 if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) { 121 if (CompStmt->size() == 1) 122 Stmt1 = CompStmt->body_back(); 123 } 124 if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) { 125 if (CompStmt->size() == 1) 126 Stmt2 = CompStmt->body_back(); 127 } 128 129 if (isIdenticalStmt(AC->getASTContext(), Stmt1, Stmt2, true)) { 130 PathDiagnosticLocation ELoc = 131 PathDiagnosticLocation::createBegin(I, BR.getSourceManager(), AC); 132 BR.EmitBasicReport(AC->getDecl(), Checker, 133 "Identical branches", 134 categories::LogicError, 135 "true and false branches are identical", ELoc); 136 } 137 return true; 138 } 139 140 bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) { 141 BinaryOperator::Opcode Op = B->getOpcode(); 142 143 if (BinaryOperator::isBitwiseOp(Op)) 144 checkBitwiseOrLogicalOp(B, true); 145 146 if (BinaryOperator::isLogicalOp(Op)) 147 checkBitwiseOrLogicalOp(B, false); 148 149 if (BinaryOperator::isComparisonOp(Op)) 150 checkComparisonOp(B); 151 152 // We want to visit ALL nodes (subexpressions of binary comparison 153 // expressions too) that contains comparison operators. 154 // True is always returned to traverse ALL nodes. 155 return true; 156 } 157 158 void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) { 159 BinaryOperator::Opcode Op = B->getOpcode(); 160 161 // 162 // Special case for floating-point representation. 163 // 164 // If expressions on both sides of comparison operator are of type float, 165 // then for some comparison operators no warning shall be 166 // reported even if the expressions are identical from a symbolic point of 167 // view. Comparison between expressions, declared variables and literals 168 // are treated differently. 169 // 170 // != and == between float literals that have the same value should NOT warn. 171 // < > between float literals that have the same value SHOULD warn. 172 // 173 // != and == between the same float declaration should NOT warn. 174 // < > between the same float declaration SHOULD warn. 175 // 176 // != and == between eq. expressions that evaluates into float 177 // should NOT warn. 178 // < > between eq. expressions that evaluates into float 179 // should NOT warn. 180 // 181 const Expr *LHS = B->getLHS()->IgnoreParenImpCasts(); 182 const Expr *RHS = B->getRHS()->IgnoreParenImpCasts(); 183 184 const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(LHS); 185 const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(RHS); 186 const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(LHS); 187 const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(RHS); 188 if ((DeclRef1) && (DeclRef2)) { 189 if ((DeclRef1->getType()->hasFloatingRepresentation()) && 190 (DeclRef2->getType()->hasFloatingRepresentation())) { 191 if (DeclRef1->getDecl() == DeclRef2->getDecl()) { 192 if ((Op == BO_EQ) || (Op == BO_NE)) { 193 return; 194 } 195 } 196 } 197 } else if ((FloatLit1) && (FloatLit2)) { 198 if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) { 199 if ((Op == BO_EQ) || (Op == BO_NE)) { 200 return; 201 } 202 } 203 } else if (LHS->getType()->hasFloatingRepresentation()) { 204 // If any side of comparison operator still has floating-point 205 // representation, then it's an expression. Don't warn. 206 // Here only LHS is checked since RHS will be implicit casted to float. 207 return; 208 } else { 209 // No special case with floating-point representation, report as usual. 210 } 211 212 if (isIdenticalStmt(AC->getASTContext(), B->getLHS(), B->getRHS())) { 213 PathDiagnosticLocation ELoc = 214 PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager()); 215 StringRef Message; 216 if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE))) 217 Message = "comparison of identical expressions always evaluates to true"; 218 else 219 Message = "comparison of identical expressions always evaluates to false"; 220 BR.EmitBasicReport(AC->getDecl(), Checker, 221 "Compare of identical expressions", 222 categories::LogicError, Message, ELoc); 223 } 224 } 225 226 bool FindIdenticalExprVisitor::VisitConditionalOperator( 227 const ConditionalOperator *C) { 228 229 // Check if expressions in conditional expression are identical 230 // from a symbolic point of view. 231 232 if (isIdenticalStmt(AC->getASTContext(), C->getTrueExpr(), 233 C->getFalseExpr(), true)) { 234 PathDiagnosticLocation ELoc = 235 PathDiagnosticLocation::createConditionalColonLoc( 236 C, BR.getSourceManager()); 237 238 SourceRange Sr[2]; 239 Sr[0] = C->getTrueExpr()->getSourceRange(); 240 Sr[1] = C->getFalseExpr()->getSourceRange(); 241 BR.EmitBasicReport( 242 AC->getDecl(), Checker, 243 "Identical expressions in conditional expression", 244 categories::LogicError, 245 "identical expressions on both sides of ':' in conditional expression", 246 ELoc, Sr); 247 } 248 // We want to visit ALL nodes (expressions in conditional 249 // expressions too) that contains conditional operators, 250 // thus always return true to traverse ALL nodes. 251 return true; 252 } 253 254 /// \brief Determines whether two statement trees are identical regarding 255 /// operators and symbols. 256 /// 257 /// Exceptions: expressions containing macros or functions with possible side 258 /// effects are never considered identical. 259 /// Limitations: (t + u) and (u + t) are not considered identical. 260 /// t*(u + t) and t*u + t*t are not considered identical. 261 /// 262 static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, 263 const Stmt *Stmt2, bool IgnoreSideEffects) { 264 265 if (!Stmt1 || !Stmt2) { 266 if (!Stmt1 && !Stmt2) 267 return true; 268 return false; 269 } 270 271 // If Stmt1 & Stmt2 are of different class then they are not 272 // identical statements. 273 if (Stmt1->getStmtClass() != Stmt2->getStmtClass()) 274 return false; 275 276 const Expr *Expr1 = dyn_cast<Expr>(Stmt1); 277 const Expr *Expr2 = dyn_cast<Expr>(Stmt2); 278 279 if (Expr1 && Expr2) { 280 // If Stmt1 has side effects then don't warn even if expressions 281 // are identical. 282 if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx)) 283 return false; 284 // If either expression comes from a macro then don't warn even if 285 // the expressions are identical. 286 if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID())) 287 return false; 288 289 // If all children of two expressions are identical, return true. 290 Expr::const_child_iterator I1 = Expr1->child_begin(); 291 Expr::const_child_iterator I2 = Expr2->child_begin(); 292 while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) { 293 if (!*I1 || !*I2 || !isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects)) 294 return false; 295 ++I1; 296 ++I2; 297 } 298 // If there are different number of children in the statements, return 299 // false. 300 if (I1 != Expr1->child_end()) 301 return false; 302 if (I2 != Expr2->child_end()) 303 return false; 304 } 305 306 switch (Stmt1->getStmtClass()) { 307 default: 308 return false; 309 case Stmt::CallExprClass: 310 case Stmt::ArraySubscriptExprClass: 311 case Stmt::ImplicitCastExprClass: 312 case Stmt::ParenExprClass: 313 case Stmt::BreakStmtClass: 314 case Stmt::ContinueStmtClass: 315 case Stmt::NullStmtClass: 316 return true; 317 case Stmt::CStyleCastExprClass: { 318 const CStyleCastExpr* CastExpr1 = cast<CStyleCastExpr>(Stmt1); 319 const CStyleCastExpr* CastExpr2 = cast<CStyleCastExpr>(Stmt2); 320 321 return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten(); 322 } 323 case Stmt::ReturnStmtClass: { 324 const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1); 325 const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2); 326 327 return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(), 328 ReturnStmt2->getRetValue(), IgnoreSideEffects); 329 } 330 case Stmt::ForStmtClass: { 331 const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1); 332 const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2); 333 334 if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(), 335 IgnoreSideEffects)) 336 return false; 337 if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(), 338 IgnoreSideEffects)) 339 return false; 340 if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(), 341 IgnoreSideEffects)) 342 return false; 343 if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(), 344 IgnoreSideEffects)) 345 return false; 346 return true; 347 } 348 case Stmt::DoStmtClass: { 349 const DoStmt *DStmt1 = cast<DoStmt>(Stmt1); 350 const DoStmt *DStmt2 = cast<DoStmt>(Stmt2); 351 352 if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(), 353 IgnoreSideEffects)) 354 return false; 355 if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(), 356 IgnoreSideEffects)) 357 return false; 358 return true; 359 } 360 case Stmt::WhileStmtClass: { 361 const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1); 362 const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2); 363 364 if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(), 365 IgnoreSideEffects)) 366 return false; 367 if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(), 368 IgnoreSideEffects)) 369 return false; 370 return true; 371 } 372 case Stmt::IfStmtClass: { 373 const IfStmt *IStmt1 = cast<IfStmt>(Stmt1); 374 const IfStmt *IStmt2 = cast<IfStmt>(Stmt2); 375 376 if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(), 377 IgnoreSideEffects)) 378 return false; 379 if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(), 380 IgnoreSideEffects)) 381 return false; 382 if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(), 383 IgnoreSideEffects)) 384 return false; 385 return true; 386 } 387 case Stmt::CompoundStmtClass: { 388 const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1); 389 const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2); 390 391 if (CompStmt1->size() != CompStmt2->size()) 392 return false; 393 394 CompoundStmt::const_body_iterator I1 = CompStmt1->body_begin(); 395 CompoundStmt::const_body_iterator I2 = CompStmt2->body_begin(); 396 while (I1 != CompStmt1->body_end() && I2 != CompStmt2->body_end()) { 397 if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects)) 398 return false; 399 ++I1; 400 ++I2; 401 } 402 403 return true; 404 } 405 case Stmt::CompoundAssignOperatorClass: 406 case Stmt::BinaryOperatorClass: { 407 const BinaryOperator *BinOp1 = cast<BinaryOperator>(Stmt1); 408 const BinaryOperator *BinOp2 = cast<BinaryOperator>(Stmt2); 409 return BinOp1->getOpcode() == BinOp2->getOpcode(); 410 } 411 case Stmt::CharacterLiteralClass: { 412 const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Stmt1); 413 const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Stmt2); 414 return CharLit1->getValue() == CharLit2->getValue(); 415 } 416 case Stmt::DeclRefExprClass: { 417 const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1); 418 const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2); 419 return DeclRef1->getDecl() == DeclRef2->getDecl(); 420 } 421 case Stmt::IntegerLiteralClass: { 422 const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1); 423 const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2); 424 return IntLit1->getValue() == IntLit2->getValue(); 425 } 426 case Stmt::FloatingLiteralClass: { 427 const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Stmt1); 428 const FloatingLiteral *FloatLit2 = cast<FloatingLiteral>(Stmt2); 429 return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue()); 430 } 431 case Stmt::StringLiteralClass: { 432 const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1); 433 const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2); 434 return StringLit1->getString() == StringLit2->getString(); 435 } 436 case Stmt::MemberExprClass: { 437 const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1); 438 const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2); 439 return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl(); 440 } 441 case Stmt::UnaryOperatorClass: { 442 const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Stmt1); 443 const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Stmt2); 444 return UnaryOp1->getOpcode() == UnaryOp2->getOpcode(); 445 } 446 } 447 } 448 449 //===----------------------------------------------------------------------===// 450 // FindIdenticalExprChecker 451 //===----------------------------------------------------------------------===// 452 453 namespace { 454 class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> { 455 public: 456 void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr, 457 BugReporter &BR) const { 458 FindIdenticalExprVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D)); 459 Visitor.TraverseDecl(const_cast<Decl *>(D)); 460 } 461 }; 462 } // end anonymous namespace 463 464 void ento::registerIdenticalExprChecker(CheckerManager &Mgr) { 465 Mgr.registerChecker<FindIdenticalExprChecker>(); 466 } 467