BugReporterVisitors.cpp revision 23df2437a47ff129d2923ae325d42e79682a7f14
1// BugReporterVisitors.cpp - Helpers for reporting bugs -----------*- C++ -*--// 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// This file defines a set of BugReporter "visitors" which can be used to 11// enhance the diagnostics reported for a bug. 12// 13//===----------------------------------------------------------------------===// 14#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" 15 16#include "clang/AST/Expr.h" 17#include "clang/AST/ExprObjC.h" 18#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 19#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 20#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 21#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 22#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 23#include "llvm/ADT/SmallString.h" 24 25using namespace clang; 26using namespace ento; 27 28//===----------------------------------------------------------------------===// 29// Utility functions. 30//===----------------------------------------------------------------------===// 31 32const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) { 33 // Pattern match for a few useful cases (do something smarter later): 34 // a[0], p->f, *p 35 const Stmt *S = N->getLocationAs<PostStmt>()->getStmt(); 36 37 while (true) { 38 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) { 39 assert(B->isAssignmentOp()); 40 S = B->getLHS()->IgnoreParenCasts(); 41 continue; 42 } 43 else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) { 44 if (U->getOpcode() == UO_Deref) 45 return U->getSubExpr()->IgnoreParenCasts(); 46 } 47 else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) { 48 return ME->getBase()->IgnoreParenCasts(); 49 } 50 else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) { 51 return AE->getBase(); 52 } 53 break; 54 } 55 56 return NULL; 57} 58 59const Stmt *bugreporter::GetDenomExpr(const ExplodedNode *N) { 60 const Stmt *S = N->getLocationAs<PreStmt>()->getStmt(); 61 if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S)) 62 return BE->getRHS(); 63 return NULL; 64} 65 66const Stmt *bugreporter::GetRetValExpr(const ExplodedNode *N) { 67 const Stmt *S = N->getLocationAs<PostStmt>()->getStmt(); 68 if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) 69 return RS->getRetValue(); 70 return NULL; 71} 72 73//===----------------------------------------------------------------------===// 74// Definitions for bug reporter visitors. 75//===----------------------------------------------------------------------===// 76 77PathDiagnosticPiece* 78BugReporterVisitor::getEndPath(BugReporterContext &BRC, 79 const ExplodedNode *EndPathNode, 80 BugReport &BR) { 81 return 0; 82} 83 84PathDiagnosticPiece* 85BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC, 86 const ExplodedNode *EndPathNode, 87 BugReport &BR) { 88 PathDiagnosticLocation L = 89 PathDiagnosticLocation::createEndOfPath(EndPathNode,BRC.getSourceManager()); 90 91 BugReport::ranges_iterator Beg, End; 92 llvm::tie(Beg, End) = BR.getRanges(); 93 94 // Only add the statement itself as a range if we didn't specify any 95 // special ranges for this report. 96 PathDiagnosticPiece *P = new PathDiagnosticEventPiece(L, 97 BR.getDescription(), 98 Beg == End); 99 for (; Beg != End; ++Beg) 100 P->addRange(*Beg); 101 102 return P; 103} 104 105 106void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const { 107 static int tag = 0; 108 ID.AddPointer(&tag); 109 ID.AddPointer(R); 110 ID.Add(V); 111} 112 113PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N, 114 const ExplodedNode *PrevN, 115 BugReporterContext &BRC, 116 BugReport &BR) { 117 118 if (satisfied) 119 return NULL; 120 121 if (!StoreSite) { 122 // Make sure the region is actually bound to value V here. 123 // This is necessary because the region may not actually be live at the 124 // report's error node. 125 if (N->getState()->getSVal(R) != V) 126 return NULL; 127 128 const ExplodedNode *Node = N, *Last = N; 129 130 // Now look for the store of V. 131 for ( ; Node ; Node = Node->getFirstPred()) { 132 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { 133 if (const PostStmt *P = Node->getLocationAs<PostStmt>()) 134 if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) 135 if (DS->getSingleDecl() == VR->getDecl()) { 136 // Record the last seen initialization point. 137 Last = Node; 138 break; 139 } 140 } 141 142 // Does the region still bind to value V? If not, we are done 143 // looking for store sites. 144 if (Node->getState()->getSVal(R) != V) 145 break; 146 147 Last = Node; 148 } 149 150 if (!Node) { 151 satisfied = true; 152 return NULL; 153 } 154 155 StoreSite = Last; 156 } 157 158 if (StoreSite != N) 159 return NULL; 160 161 satisfied = true; 162 SmallString<256> sbuf; 163 llvm::raw_svector_ostream os(sbuf); 164 165 if (const PostStmt *PS = N->getLocationAs<PostStmt>()) { 166 if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) { 167 168 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { 169 os << "Variable '" << *VR->getDecl() << "' "; 170 } 171 else 172 return NULL; 173 174 if (isa<loc::ConcreteInt>(V)) { 175 bool b = false; 176 if (R->isBoundable()) { 177 if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { 178 if (TR->getValueType()->isObjCObjectPointerType()) { 179 os << "initialized to nil"; 180 b = true; 181 } 182 } 183 } 184 185 if (!b) 186 os << "initialized to a null pointer value"; 187 } 188 else if (isa<nonloc::ConcreteInt>(V)) { 189 os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue(); 190 } 191 else if (V.isUndef()) { 192 if (isa<VarRegion>(R)) { 193 const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); 194 if (VD->getInit()) 195 os << "initialized to a garbage value"; 196 else 197 os << "declared without an initial value"; 198 } 199 } 200 else { 201 os << "initialized here"; 202 } 203 } 204 } 205 206 if (os.str().empty()) { 207 if (isa<loc::ConcreteInt>(V)) { 208 bool b = false; 209 if (R->isBoundable()) { 210 if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { 211 if (TR->getValueType()->isObjCObjectPointerType()) { 212 os << "nil object reference stored to "; 213 b = true; 214 } 215 } 216 } 217 218 if (!b) 219 os << "Null pointer value stored to "; 220 } 221 else if (V.isUndef()) { 222 os << "Uninitialized value stored to "; 223 } 224 else if (isa<nonloc::ConcreteInt>(V)) { 225 os << "The value " << cast<nonloc::ConcreteInt>(V).getValue() 226 << " is assigned to "; 227 } 228 else 229 os << "Value assigned to "; 230 231 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { 232 os << '\'' << *VR->getDecl() << '\''; 233 } 234 else 235 return NULL; 236 } 237 238 // Construct a new PathDiagnosticPiece. 239 ProgramPoint P = N->getLocation(); 240 PathDiagnosticLocation L = 241 PathDiagnosticLocation::create(P, BRC.getSourceManager()); 242 if (!L.isValid()) 243 return NULL; 244 return new PathDiagnosticEventPiece(L, os.str()); 245} 246 247void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const { 248 static int tag = 0; 249 ID.AddPointer(&tag); 250 ID.AddBoolean(Assumption); 251 ID.Add(Constraint); 252} 253 254PathDiagnosticPiece * 255TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, 256 const ExplodedNode *PrevN, 257 BugReporterContext &BRC, 258 BugReport &BR) { 259 if (isSatisfied) 260 return NULL; 261 262 // Check if in the previous state it was feasible for this constraint 263 // to *not* be true. 264 if (PrevN->getState()->assume(Constraint, !Assumption)) { 265 266 isSatisfied = true; 267 268 // As a sanity check, make sure that the negation of the constraint 269 // was infeasible in the current state. If it is feasible, we somehow 270 // missed the transition point. 271 if (N->getState()->assume(Constraint, !Assumption)) 272 return NULL; 273 274 // We found the transition point for the constraint. We now need to 275 // pretty-print the constraint. (work-in-progress) 276 std::string sbuf; 277 llvm::raw_string_ostream os(sbuf); 278 279 if (isa<Loc>(Constraint)) { 280 os << "Assuming pointer value is "; 281 os << (Assumption ? "non-null" : "null"); 282 } 283 284 if (os.str().empty()) 285 return NULL; 286 287 // Construct a new PathDiagnosticPiece. 288 ProgramPoint P = N->getLocation(); 289 PathDiagnosticLocation L = 290 PathDiagnosticLocation::create(P, BRC.getSourceManager()); 291 if (!L.isValid()) 292 return NULL; 293 return new PathDiagnosticEventPiece(L, os.str()); 294 } 295 296 return NULL; 297} 298 299namespace { 300class ReturnNullVisitor : public BugReporterVisitorImpl<ReturnNullVisitor> { 301 const ExplodedNode *ReturnNode; 302public: 303 ReturnNullVisitor(const ExplodedNode *N) : ReturnNode(N) {} 304 305 virtual void Profile(llvm::FoldingSetNodeID &ID) const { 306 static int Tag = 0; 307 ID.AddPointer(&Tag); 308 ID.Add(*ReturnNode); 309 } 310 311 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 312 const ExplodedNode *PrevN, 313 BugReporterContext &BRC, 314 BugReport &BR) { 315 if (ReturnNode != BRC.getNodeResolver().getOriginalNode(N)) 316 return 0; 317 318 StmtPoint SP = cast<StmtPoint>(ReturnNode->getLocation()); 319 const ReturnStmt *Ret = cast<ReturnStmt>(SP.getStmt()); 320 PathDiagnosticLocation L(Ret, BRC.getSourceManager(), 321 N->getLocationContext()); 322 323 SmallString<64> Msg; 324 llvm::raw_svector_ostream Out(Msg); 325 326 if (Loc::isLocType(Ret->getRetValue()->getType())) 327 Out << "Returning null pointer"; 328 else 329 Out << "Returning zero"; 330 331 // FIXME: We should have a more generalized printing mechanism. 332 const Expr *RetE = Ret->getRetValue()->IgnoreParenCasts(); 333 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE)) 334 if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl())) 335 Out << " (loaded from '" << *DD << "')"; 336 337 return new PathDiagnosticEventPiece(L, Out.str()); 338 } 339}; 340} // end anonymous namespace 341 342void bugreporter::addTrackNullOrUndefValueVisitor(const ExplodedNode *N, 343 const Stmt *S, 344 BugReport *report) { 345 if (!S || !N) 346 return; 347 348 ProgramStateManager &StateMgr = N->getState()->getStateManager(); 349 350 // Walk through nodes until we get one that matches the statement 351 // exactly. 352 while (N) { 353 const ProgramPoint &pp = N->getLocation(); 354 if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) { 355 if (ps->getStmt() == S) 356 break; 357 } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) { 358 if (CEE->getCalleeContext()->getCallSite() == S) 359 break; 360 } 361 N = N->getFirstPred(); 362 } 363 364 if (!N) 365 return; 366 367 ProgramStateRef state = N->getState(); 368 369 // Walk through lvalue-to-rvalue conversions. 370 const Expr *Ex = dyn_cast<Expr>(S); 371 if (Ex) { 372 Ex = Ex->IgnoreParenCasts(); 373 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { 374 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 375 const VarRegion *R = 376 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); 377 378 // What did we load? 379 SVal V = state->getRawSVal(loc::MemRegionVal(R)); 380 report->markInteresting(R); 381 report->markInteresting(V); 382 383 if (V.getAsLocSymbol()) { 384 BugReporterVisitor *ConstraintTracker 385 = new TrackConstraintBRVisitor(cast<loc::MemRegionVal>(V), false); 386 report->addVisitor(ConstraintTracker); 387 } 388 389 report->addVisitor(new FindLastStoreBRVisitor(V, R)); 390 return; 391 } 392 } 393 } 394 395 SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); 396 397 // Uncomment this to find cases where we aren't properly getting the 398 // base value that was dereferenced. 399 // assert(!V.isUnknownOrUndef()); 400 401 // Is it a symbolic value? 402 if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) { 403 const SubRegion *R = cast<SubRegion>(L->getRegion()); 404 while (R && !isa<SymbolicRegion>(R)) { 405 R = dyn_cast<SubRegion>(R->getSuperRegion()); 406 } 407 408 if (R) { 409 report->markInteresting(R); 410 report->addVisitor(new TrackConstraintBRVisitor(loc::MemRegionVal(R), 411 false)); 412 } 413 } else { 414 // Walk backwards to just before the post-statement checks. 415 ProgramPoint PP = N->getLocation(); 416 while (N && isa<PostStmt>(PP = N->getLocation())) 417 N = N->getFirstPred(); 418 419 if (N && isa<CallExitEnd>(PP)) { 420 // Find a ReturnStmt, if there is one. 421 do { 422 N = N->getFirstPred(); 423 PP = N->getLocation(); 424 } while (!isa<StmtPoint>(PP) && !isa<CallEnter>(PP)); 425 426 if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) { 427 if (const ReturnStmt *Ret = SP->getStmtAs<ReturnStmt>()) { 428 if (const Expr *RetE = Ret->getRetValue()) { 429 report->addVisitor(new ReturnNullVisitor(N)); 430 addTrackNullOrUndefValueVisitor(N, RetE, report); 431 } 432 } 433 } 434 } 435 } 436} 437 438BugReporterVisitor * 439FindLastStoreBRVisitor::createVisitorObject(const ExplodedNode *N, 440 const MemRegion *R) { 441 assert(R && "The memory region is null."); 442 443 ProgramStateRef state = N->getState(); 444 SVal V = state->getSVal(R); 445 if (V.isUnknown()) 446 return 0; 447 448 return new FindLastStoreBRVisitor(V, R); 449} 450 451 452PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, 453 const ExplodedNode *PrevN, 454 BugReporterContext &BRC, 455 BugReport &BR) { 456 const PostStmt *P = N->getLocationAs<PostStmt>(); 457 if (!P) 458 return 0; 459 const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>(); 460 if (!ME) 461 return 0; 462 const Expr *Receiver = ME->getInstanceReceiver(); 463 if (!Receiver) 464 return 0; 465 ProgramStateRef state = N->getState(); 466 const SVal &V = state->getSVal(Receiver, N->getLocationContext()); 467 const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V); 468 if (!DV) 469 return 0; 470 state = state->assume(*DV, true); 471 if (state) 472 return 0; 473 474 // The receiver was nil, and hence the method was skipped. 475 // Register a BugReporterVisitor to issue a message telling us how 476 // the receiver was null. 477 bugreporter::addTrackNullOrUndefValueVisitor(N, Receiver, &BR); 478 // Issue a message saying that the method was skipped. 479 PathDiagnosticLocation L(Receiver, BRC.getSourceManager(), 480 N->getLocationContext()); 481 return new PathDiagnosticEventPiece(L, "No method is called " 482 "because the receiver is nil"); 483} 484 485// Registers every VarDecl inside a Stmt with a last store visitor. 486void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR, 487 const Stmt *S) { 488 const ExplodedNode *N = BR.getErrorNode(); 489 std::deque<const Stmt *> WorkList; 490 WorkList.push_back(S); 491 492 while (!WorkList.empty()) { 493 const Stmt *Head = WorkList.front(); 494 WorkList.pop_front(); 495 496 ProgramStateRef state = N->getState(); 497 ProgramStateManager &StateMgr = state->getStateManager(); 498 499 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Head)) { 500 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 501 const VarRegion *R = 502 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); 503 504 // What did we load? 505 SVal V = state->getSVal(S, N->getLocationContext()); 506 507 if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) { 508 // Register a new visitor with the BugReport. 509 BR.addVisitor(new FindLastStoreBRVisitor(V, R)); 510 } 511 } 512 } 513 514 for (Stmt::const_child_iterator I = Head->child_begin(); 515 I != Head->child_end(); ++I) 516 WorkList.push_back(*I); 517 } 518} 519 520//===----------------------------------------------------------------------===// 521// Visitor that tries to report interesting diagnostics from conditions. 522//===----------------------------------------------------------------------===// 523PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N, 524 const ExplodedNode *Prev, 525 BugReporterContext &BRC, 526 BugReport &BR) { 527 PathDiagnosticPiece *piece = VisitNodeImpl(N, Prev, BRC, BR); 528 if (PathDiagnosticEventPiece *ev = 529 dyn_cast_or_null<PathDiagnosticEventPiece>(piece)) 530 ev->setPrunable(true, /* override */ false); 531 return piece; 532} 533 534PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, 535 const ExplodedNode *Prev, 536 BugReporterContext &BRC, 537 BugReport &BR) { 538 539 const ProgramPoint &progPoint = N->getLocation(); 540 541 ProgramStateRef CurrentState = N->getState(); 542 ProgramStateRef PrevState = Prev->getState(); 543 544 // Compare the GDMs of the state, because that is where constraints 545 // are managed. Note that ensure that we only look at nodes that 546 // were generated by the analyzer engine proper, not checkers. 547 if (CurrentState->getGDM().getRoot() == 548 PrevState->getGDM().getRoot()) 549 return 0; 550 551 // If an assumption was made on a branch, it should be caught 552 // here by looking at the state transition. 553 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&progPoint)) { 554 const CFGBlock *srcBlk = BE->getSrc(); 555 if (const Stmt *term = srcBlk->getTerminator()) 556 return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC); 557 return 0; 558 } 559 560 if (const PostStmt *PS = dyn_cast<PostStmt>(&progPoint)) { 561 // FIXME: Assuming that BugReporter is a GRBugReporter is a layering 562 // violation. 563 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags = 564 cast<GRBugReporter>(BRC.getBugReporter()). 565 getEngine().getEagerlyAssumeTags(); 566 567 const ProgramPointTag *tag = PS->getTag(); 568 if (tag == tags.first) 569 return VisitTrueTest(cast<Expr>(PS->getStmt()), true, 570 BRC, BR, N); 571 if (tag == tags.second) 572 return VisitTrueTest(cast<Expr>(PS->getStmt()), false, 573 BRC, BR, N); 574 575 return 0; 576 } 577 578 return 0; 579} 580 581PathDiagnosticPiece * 582ConditionBRVisitor::VisitTerminator(const Stmt *Term, 583 const ExplodedNode *N, 584 const CFGBlock *srcBlk, 585 const CFGBlock *dstBlk, 586 BugReport &R, 587 BugReporterContext &BRC) { 588 const Expr *Cond = 0; 589 590 switch (Term->getStmtClass()) { 591 default: 592 return 0; 593 case Stmt::IfStmtClass: 594 Cond = cast<IfStmt>(Term)->getCond(); 595 break; 596 case Stmt::ConditionalOperatorClass: 597 Cond = cast<ConditionalOperator>(Term)->getCond(); 598 break; 599 } 600 601 assert(Cond); 602 assert(srcBlk->succ_size() == 2); 603 const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk; 604 return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()), 605 tookTrue, BRC, R, N); 606} 607 608PathDiagnosticPiece * 609ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 610 bool tookTrue, 611 BugReporterContext &BRC, 612 BugReport &R, 613 const ExplodedNode *N) { 614 615 const Expr *Ex = Cond; 616 617 while (true) { 618 Ex = Ex->IgnoreParens(); 619 switch (Ex->getStmtClass()) { 620 default: 621 return 0; 622 case Stmt::BinaryOperatorClass: 623 return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC, 624 R, N); 625 case Stmt::DeclRefExprClass: 626 return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC, 627 R, N); 628 case Stmt::UnaryOperatorClass: { 629 const UnaryOperator *UO = cast<UnaryOperator>(Ex); 630 if (UO->getOpcode() == UO_LNot) { 631 tookTrue = !tookTrue; 632 Ex = UO->getSubExpr()->IgnoreParenNoopCasts(BRC.getASTContext()); 633 continue; 634 } 635 return 0; 636 } 637 } 638 } 639} 640 641bool ConditionBRVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out, 642 BugReporterContext &BRC, 643 BugReport &report, 644 const ExplodedNode *N, 645 llvm::Optional<bool> &prunable) { 646 const Expr *OriginalExpr = Ex; 647 Ex = Ex->IgnoreParenCasts(); 648 649 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { 650 const bool quotes = isa<VarDecl>(DR->getDecl()); 651 if (quotes) { 652 Out << '\''; 653 const LocationContext *LCtx = N->getLocationContext(); 654 const ProgramState *state = N->getState().getPtr(); 655 if (const MemRegion *R = state->getLValue(cast<VarDecl>(DR->getDecl()), 656 LCtx).getAsRegion()) { 657 if (report.isInteresting(R)) 658 prunable = false; 659 else { 660 const ProgramState *state = N->getState().getPtr(); 661 SVal V = state->getSVal(R); 662 if (report.isInteresting(V)) 663 prunable = false; 664 } 665 } 666 } 667 Out << DR->getDecl()->getDeclName().getAsString(); 668 if (quotes) 669 Out << '\''; 670 return quotes; 671 } 672 673 if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(Ex)) { 674 QualType OriginalTy = OriginalExpr->getType(); 675 if (OriginalTy->isPointerType()) { 676 if (IL->getValue() == 0) { 677 Out << "null"; 678 return false; 679 } 680 } 681 else if (OriginalTy->isObjCObjectPointerType()) { 682 if (IL->getValue() == 0) { 683 Out << "nil"; 684 return false; 685 } 686 } 687 688 Out << IL->getValue(); 689 return false; 690 } 691 692 return false; 693} 694 695PathDiagnosticPiece * 696ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 697 const BinaryOperator *BExpr, 698 const bool tookTrue, 699 BugReporterContext &BRC, 700 BugReport &R, 701 const ExplodedNode *N) { 702 703 bool shouldInvert = false; 704 llvm::Optional<bool> shouldPrune; 705 706 SmallString<128> LhsString, RhsString; 707 { 708 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString); 709 const bool isVarLHS = patternMatch(BExpr->getLHS(), OutLHS, BRC, R, N, 710 shouldPrune); 711 const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC, R, N, 712 shouldPrune); 713 714 shouldInvert = !isVarLHS && isVarRHS; 715 } 716 717 BinaryOperator::Opcode Op = BExpr->getOpcode(); 718 719 if (BinaryOperator::isAssignmentOp(Op)) { 720 // For assignment operators, all that we care about is that the LHS 721 // evaluates to "true" or "false". 722 return VisitConditionVariable(LhsString, BExpr->getLHS(), tookTrue, 723 BRC, R, N); 724 } 725 726 // For non-assignment operations, we require that we can understand 727 // both the LHS and RHS. 728 if (LhsString.empty() || RhsString.empty()) 729 return 0; 730 731 // Should we invert the strings if the LHS is not a variable name? 732 SmallString<256> buf; 733 llvm::raw_svector_ostream Out(buf); 734 Out << "Assuming " << (shouldInvert ? RhsString : LhsString) << " is "; 735 736 // Do we need to invert the opcode? 737 if (shouldInvert) 738 switch (Op) { 739 default: break; 740 case BO_LT: Op = BO_GT; break; 741 case BO_GT: Op = BO_LT; break; 742 case BO_LE: Op = BO_GE; break; 743 case BO_GE: Op = BO_LE; break; 744 } 745 746 if (!tookTrue) 747 switch (Op) { 748 case BO_EQ: Op = BO_NE; break; 749 case BO_NE: Op = BO_EQ; break; 750 case BO_LT: Op = BO_GE; break; 751 case BO_GT: Op = BO_LE; break; 752 case BO_LE: Op = BO_GT; break; 753 case BO_GE: Op = BO_LT; break; 754 default: 755 return 0; 756 } 757 758 switch (Op) { 759 case BO_EQ: 760 Out << "equal to "; 761 break; 762 case BO_NE: 763 Out << "not equal to "; 764 break; 765 default: 766 Out << BinaryOperator::getOpcodeStr(Op) << ' '; 767 break; 768 } 769 770 Out << (shouldInvert ? LhsString : RhsString); 771 const LocationContext *LCtx = N->getLocationContext(); 772 PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); 773 PathDiagnosticEventPiece *event = 774 new PathDiagnosticEventPiece(Loc, Out.str()); 775 if (shouldPrune.hasValue()) 776 event->setPrunable(shouldPrune.getValue()); 777 return event; 778} 779 780PathDiagnosticPiece * 781ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, 782 const Expr *CondVarExpr, 783 const bool tookTrue, 784 BugReporterContext &BRC, 785 BugReport &report, 786 const ExplodedNode *N) { 787 // FIXME: If there's already a constraint tracker for this variable, 788 // we shouldn't emit anything here (c.f. the double note in 789 // test/Analysis/inlining/path-notes.c) 790 SmallString<256> buf; 791 llvm::raw_svector_ostream Out(buf); 792 Out << "Assuming " << LhsString << " is "; 793 794 QualType Ty = CondVarExpr->getType(); 795 796 if (Ty->isPointerType()) 797 Out << (tookTrue ? "not null" : "null"); 798 else if (Ty->isObjCObjectPointerType()) 799 Out << (tookTrue ? "not nil" : "nil"); 800 else if (Ty->isBooleanType()) 801 Out << (tookTrue ? "true" : "false"); 802 else if (Ty->isIntegerType()) 803 Out << (tookTrue ? "non-zero" : "zero"); 804 else 805 return 0; 806 807 const LocationContext *LCtx = N->getLocationContext(); 808 PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx); 809 PathDiagnosticEventPiece *event = 810 new PathDiagnosticEventPiece(Loc, Out.str()); 811 812 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(CondVarExpr)) { 813 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 814 const ProgramState *state = N->getState().getPtr(); 815 if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { 816 if (report.isInteresting(R)) 817 event->setPrunable(false); 818 } 819 } 820 } 821 822 return event; 823} 824 825PathDiagnosticPiece * 826ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 827 const DeclRefExpr *DR, 828 const bool tookTrue, 829 BugReporterContext &BRC, 830 BugReport &report, 831 const ExplodedNode *N) { 832 833 const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); 834 if (!VD) 835 return 0; 836 837 SmallString<256> Buf; 838 llvm::raw_svector_ostream Out(Buf); 839 840 Out << "Assuming '"; 841 VD->getDeclName().printName(Out); 842 Out << "' is "; 843 844 QualType VDTy = VD->getType(); 845 846 if (VDTy->isPointerType()) 847 Out << (tookTrue ? "non-null" : "null"); 848 else if (VDTy->isObjCObjectPointerType()) 849 Out << (tookTrue ? "non-nil" : "nil"); 850 else if (VDTy->isScalarType()) 851 Out << (tookTrue ? "not equal to 0" : "0"); 852 else 853 return 0; 854 855 const LocationContext *LCtx = N->getLocationContext(); 856 PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); 857 PathDiagnosticEventPiece *event = 858 new PathDiagnosticEventPiece(Loc, Out.str()); 859 860 const ProgramState *state = N->getState().getPtr(); 861 if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { 862 if (report.isInteresting(R)) 863 event->setPrunable(false); 864 else { 865 SVal V = state->getSVal(R); 866 if (report.isInteresting(V)) 867 event->setPrunable(false); 868 } 869 } 870 return event; 871} 872 873