BugReporterVisitors.cpp revision 907344e4977ac704f248d82ef235b88be08584d5
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 if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) { 38 if (U->getOpcode() == UO_Deref) 39 return U->getSubExpr()->IgnoreParenCasts(); 40 } 41 else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) { 42 return ME->getBase()->IgnoreParenCasts(); 43 } 44 else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) { 45 return AE->getBase(); 46 } 47 48 return NULL; 49} 50 51const Stmt *bugreporter::GetDenomExpr(const ExplodedNode *N) { 52 const Stmt *S = N->getLocationAs<PreStmt>()->getStmt(); 53 if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S)) 54 return BE->getRHS(); 55 return NULL; 56} 57 58const Stmt *bugreporter::GetCalleeExpr(const ExplodedNode *N) { 59 // Callee is checked as a PreVisit to the CallExpr. 60 const Stmt *S = N->getLocationAs<PreStmt>()->getStmt(); 61 if (const CallExpr *CE = dyn_cast<CallExpr>(S)) 62 return CE->getCallee(); 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 const ExplodedNode *Node = N, *Last = NULL; 123 124 for ( ; Node ; Node = Node->getFirstPred()) { 125 126 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { 127 if (const PostStmt *P = Node->getLocationAs<PostStmt>()) 128 if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) 129 if (DS->getSingleDecl() == VR->getDecl()) { 130 // Record the last seen initialization point. 131 Last = Node; 132 break; 133 } 134 } 135 136 // Does the region still bind to value V? If not, we are done 137 // looking for store sites. 138 if (Node->getState()->getSVal(R) != V) 139 break; 140 } 141 142 if (!Node || !Last) { 143 satisfied = true; 144 return NULL; 145 } 146 147 StoreSite = Last; 148 } 149 150 if (StoreSite != N) 151 return NULL; 152 153 satisfied = true; 154 SmallString<256> sbuf; 155 llvm::raw_svector_ostream os(sbuf); 156 157 if (const PostStmt *PS = N->getLocationAs<PostStmt>()) { 158 if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) { 159 160 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { 161 os << "Variable '" << *VR->getDecl() << "' "; 162 } 163 else 164 return NULL; 165 166 if (isa<loc::ConcreteInt>(V)) { 167 bool b = false; 168 if (R->isBoundable()) { 169 if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { 170 if (TR->getValueType()->isObjCObjectPointerType()) { 171 os << "initialized to nil"; 172 b = true; 173 } 174 } 175 } 176 177 if (!b) 178 os << "initialized to a null pointer value"; 179 } 180 else if (isa<nonloc::ConcreteInt>(V)) { 181 os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue(); 182 } 183 else if (V.isUndef()) { 184 if (isa<VarRegion>(R)) { 185 const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); 186 if (VD->getInit()) 187 os << "initialized to a garbage value"; 188 else 189 os << "declared without an initial value"; 190 } 191 } 192 } 193 } 194 195 if (os.str().empty()) { 196 if (isa<loc::ConcreteInt>(V)) { 197 bool b = false; 198 if (R->isBoundable()) { 199 if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { 200 if (TR->getValueType()->isObjCObjectPointerType()) { 201 os << "nil object reference stored to "; 202 b = true; 203 } 204 } 205 } 206 207 if (!b) 208 os << "Null pointer value stored to "; 209 } 210 else if (V.isUndef()) { 211 os << "Uninitialized value stored to "; 212 } 213 else if (isa<nonloc::ConcreteInt>(V)) { 214 os << "The value " << cast<nonloc::ConcreteInt>(V).getValue() 215 << " is assigned to "; 216 } 217 else 218 return NULL; 219 220 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { 221 os << '\'' << *VR->getDecl() << '\''; 222 } 223 else 224 return NULL; 225 } 226 227 // Construct a new PathDiagnosticPiece. 228 ProgramPoint P = N->getLocation(); 229 PathDiagnosticLocation L = 230 PathDiagnosticLocation::create(P, BRC.getSourceManager()); 231 if (!L.isValid()) 232 return NULL; 233 return new PathDiagnosticEventPiece(L, os.str()); 234} 235 236void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const { 237 static int tag = 0; 238 ID.AddPointer(&tag); 239 ID.AddBoolean(Assumption); 240 ID.Add(Constraint); 241} 242 243PathDiagnosticPiece * 244TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, 245 const ExplodedNode *PrevN, 246 BugReporterContext &BRC, 247 BugReport &BR) { 248 if (isSatisfied) 249 return NULL; 250 251 // Check if in the previous state it was feasible for this constraint 252 // to *not* be true. 253 if (PrevN->getState()->assume(Constraint, !Assumption)) { 254 255 isSatisfied = true; 256 257 // As a sanity check, make sure that the negation of the constraint 258 // was infeasible in the current state. If it is feasible, we somehow 259 // missed the transition point. 260 if (N->getState()->assume(Constraint, !Assumption)) 261 return NULL; 262 263 // We found the transition point for the constraint. We now need to 264 // pretty-print the constraint. (work-in-progress) 265 std::string sbuf; 266 llvm::raw_string_ostream os(sbuf); 267 268 if (isa<Loc>(Constraint)) { 269 os << "Assuming pointer value is "; 270 os << (Assumption ? "non-null" : "null"); 271 } 272 273 if (os.str().empty()) 274 return NULL; 275 276 // Construct a new PathDiagnosticPiece. 277 ProgramPoint P = N->getLocation(); 278 PathDiagnosticLocation L = 279 PathDiagnosticLocation::create(P, BRC.getSourceManager()); 280 if (!L.isValid()) 281 return NULL; 282 return new PathDiagnosticEventPiece(L, os.str()); 283 } 284 285 return NULL; 286} 287 288BugReporterVisitor * 289bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N, 290 const Stmt *S, 291 BugReport *report) { 292 if (!S || !N) 293 return 0; 294 295 ProgramStateManager &StateMgr = N->getState()->getStateManager(); 296 297 // Walk through nodes until we get one that matches the statement 298 // exactly. 299 while (N) { 300 const ProgramPoint &pp = N->getLocation(); 301 if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) { 302 if (ps->getStmt() == S) 303 break; 304 } 305 N = N->getFirstPred(); 306 } 307 308 if (!N) 309 return 0; 310 311 ProgramStateRef state = N->getState(); 312 313 // Walk through lvalue-to-rvalue conversions. 314 const Expr *Ex = dyn_cast<Expr>(S); 315 if (Ex) { 316 Ex = Ex->IgnoreParenLValueCasts(); 317 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { 318 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 319 const VarRegion *R = 320 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); 321 322 // What did we load? 323 SVal V = state->getSVal(loc::MemRegionVal(R)); 324 report->markInteresting(R); 325 report->markInteresting(V); 326 return new FindLastStoreBRVisitor(V, R); 327 } 328 } 329 } 330 331 SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); 332 333 // Uncomment this to find cases where we aren't properly getting the 334 // base value that was dereferenced. 335 // assert(!V.isUnknownOrUndef()); 336 337 // Is it a symbolic value? 338 if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) { 339 const SubRegion *R = cast<SubRegion>(L->getRegion()); 340 while (R && !isa<SymbolicRegion>(R)) { 341 R = dyn_cast<SubRegion>(R->getSuperRegion()); 342 } 343 344 if (R) { 345 report->markInteresting(R); 346 return new TrackConstraintBRVisitor(loc::MemRegionVal(R), false); 347 } 348 } 349 350 return 0; 351} 352 353BugReporterVisitor * 354FindLastStoreBRVisitor::createVisitorObject(const ExplodedNode *N, 355 const MemRegion *R) { 356 assert(R && "The memory region is null."); 357 358 ProgramStateRef state = N->getState(); 359 SVal V = state->getSVal(R); 360 if (V.isUnknown()) 361 return 0; 362 363 return new FindLastStoreBRVisitor(V, R); 364} 365 366 367PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, 368 const ExplodedNode *PrevN, 369 BugReporterContext &BRC, 370 BugReport &BR) { 371 const PostStmt *P = N->getLocationAs<PostStmt>(); 372 if (!P) 373 return 0; 374 const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>(); 375 if (!ME) 376 return 0; 377 const Expr *Receiver = ME->getInstanceReceiver(); 378 if (!Receiver) 379 return 0; 380 ProgramStateRef state = N->getState(); 381 const SVal &V = state->getSVal(Receiver, N->getLocationContext()); 382 const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V); 383 if (!DV) 384 return 0; 385 state = state->assume(*DV, true); 386 if (state) 387 return 0; 388 389 // The receiver was nil, and hence the method was skipped. 390 // Register a BugReporterVisitor to issue a message telling us how 391 // the receiver was null. 392 BR.addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Receiver, &BR)); 393 // Issue a message saying that the method was skipped. 394 PathDiagnosticLocation L(Receiver, BRC.getSourceManager(), 395 N->getLocationContext()); 396 return new PathDiagnosticEventPiece(L, "No method is called " 397 "because the receiver is nil"); 398} 399 400// Registers every VarDecl inside a Stmt with a last store visitor. 401void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR, 402 const Stmt *S) { 403 const ExplodedNode *N = BR.getErrorNode(); 404 std::deque<const Stmt *> WorkList; 405 WorkList.push_back(S); 406 407 while (!WorkList.empty()) { 408 const Stmt *Head = WorkList.front(); 409 WorkList.pop_front(); 410 411 ProgramStateRef state = N->getState(); 412 ProgramStateManager &StateMgr = state->getStateManager(); 413 414 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Head)) { 415 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 416 const VarRegion *R = 417 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); 418 419 // What did we load? 420 SVal V = state->getSVal(S, N->getLocationContext()); 421 422 if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) { 423 // Register a new visitor with the BugReport. 424 BR.addVisitor(new FindLastStoreBRVisitor(V, R)); 425 } 426 } 427 } 428 429 for (Stmt::const_child_iterator I = Head->child_begin(); 430 I != Head->child_end(); ++I) 431 WorkList.push_back(*I); 432 } 433} 434 435//===----------------------------------------------------------------------===// 436// Visitor that tries to report interesting diagnostics from conditions. 437//===----------------------------------------------------------------------===// 438PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N, 439 const ExplodedNode *Prev, 440 BugReporterContext &BRC, 441 BugReport &BR) { 442 PathDiagnosticPiece *piece = VisitNodeImpl(N, Prev, BRC, BR); 443 if (PathDiagnosticEventPiece *ev = 444 dyn_cast_or_null<PathDiagnosticEventPiece>(piece)) 445 ev->setPrunable(true, /* override */ false); 446 return piece; 447} 448 449PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, 450 const ExplodedNode *Prev, 451 BugReporterContext &BRC, 452 BugReport &BR) { 453 454 const ProgramPoint &progPoint = N->getLocation(); 455 456 ProgramStateRef CurrentState = N->getState(); 457 ProgramStateRef PrevState = Prev->getState(); 458 459 // Compare the GDMs of the state, because that is where constraints 460 // are managed. Note that ensure that we only look at nodes that 461 // were generated by the analyzer engine proper, not checkers. 462 if (CurrentState->getGDM().getRoot() == 463 PrevState->getGDM().getRoot()) 464 return 0; 465 466 // If an assumption was made on a branch, it should be caught 467 // here by looking at the state transition. 468 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&progPoint)) { 469 const CFGBlock *srcBlk = BE->getSrc(); 470 if (const Stmt *term = srcBlk->getTerminator()) 471 return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC); 472 return 0; 473 } 474 475 if (const PostStmt *PS = dyn_cast<PostStmt>(&progPoint)) { 476 // FIXME: Assuming that BugReporter is a GRBugReporter is a layering 477 // violation. 478 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags = 479 cast<GRBugReporter>(BRC.getBugReporter()). 480 getEngine().getEagerlyAssumeTags(); 481 482 const ProgramPointTag *tag = PS->getTag(); 483 if (tag == tags.first) 484 return VisitTrueTest(cast<Expr>(PS->getStmt()), true, 485 BRC, BR, N); 486 if (tag == tags.second) 487 return VisitTrueTest(cast<Expr>(PS->getStmt()), false, 488 BRC, BR, N); 489 490 return 0; 491 } 492 493 return 0; 494} 495 496PathDiagnosticPiece * 497ConditionBRVisitor::VisitTerminator(const Stmt *Term, 498 const ExplodedNode *N, 499 const CFGBlock *srcBlk, 500 const CFGBlock *dstBlk, 501 BugReport &R, 502 BugReporterContext &BRC) { 503 const Expr *Cond = 0; 504 505 switch (Term->getStmtClass()) { 506 default: 507 return 0; 508 case Stmt::IfStmtClass: 509 Cond = cast<IfStmt>(Term)->getCond(); 510 break; 511 case Stmt::ConditionalOperatorClass: 512 Cond = cast<ConditionalOperator>(Term)->getCond(); 513 break; 514 } 515 516 assert(Cond); 517 assert(srcBlk->succ_size() == 2); 518 const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk; 519 return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()), 520 tookTrue, BRC, R, N); 521} 522 523PathDiagnosticPiece * 524ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 525 bool tookTrue, 526 BugReporterContext &BRC, 527 BugReport &R, 528 const ExplodedNode *N) { 529 530 const Expr *Ex = Cond; 531 532 while (true) { 533 Ex = Ex->IgnoreParens(); 534 switch (Ex->getStmtClass()) { 535 default: 536 return 0; 537 case Stmt::BinaryOperatorClass: 538 return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC, 539 R, N); 540 case Stmt::DeclRefExprClass: 541 return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC, 542 R, N); 543 case Stmt::UnaryOperatorClass: { 544 const UnaryOperator *UO = cast<UnaryOperator>(Ex); 545 if (UO->getOpcode() == UO_LNot) { 546 tookTrue = !tookTrue; 547 Ex = UO->getSubExpr()->IgnoreParenNoopCasts(BRC.getASTContext()); 548 continue; 549 } 550 return 0; 551 } 552 } 553 } 554} 555 556bool ConditionBRVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out, 557 BugReporterContext &BRC, 558 BugReport &report, 559 const ExplodedNode *N, 560 llvm::Optional<bool> &prunable) { 561 const Expr *OriginalExpr = Ex; 562 Ex = Ex->IgnoreParenCasts(); 563 564 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { 565 const bool quotes = isa<VarDecl>(DR->getDecl()); 566 if (quotes) { 567 Out << '\''; 568 const LocationContext *LCtx = N->getLocationContext(); 569 const ProgramState *state = N->getState().getPtr(); 570 if (const MemRegion *R = state->getLValue(cast<VarDecl>(DR->getDecl()), 571 LCtx).getAsRegion()) { 572 if (report.isInteresting(R)) 573 prunable = false; 574 else { 575 const ProgramState *state = N->getState().getPtr(); 576 SVal V = state->getSVal(R); 577 if (report.isInteresting(V)) 578 prunable = false; 579 } 580 } 581 } 582 Out << DR->getDecl()->getDeclName().getAsString(); 583 if (quotes) 584 Out << '\''; 585 return quotes; 586 } 587 588 if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(Ex)) { 589 QualType OriginalTy = OriginalExpr->getType(); 590 if (OriginalTy->isPointerType()) { 591 if (IL->getValue() == 0) { 592 Out << "null"; 593 return false; 594 } 595 } 596 else if (OriginalTy->isObjCObjectPointerType()) { 597 if (IL->getValue() == 0) { 598 Out << "nil"; 599 return false; 600 } 601 } 602 603 Out << IL->getValue(); 604 return false; 605 } 606 607 return false; 608} 609 610PathDiagnosticPiece * 611ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 612 const BinaryOperator *BExpr, 613 const bool tookTrue, 614 BugReporterContext &BRC, 615 BugReport &R, 616 const ExplodedNode *N) { 617 618 bool shouldInvert = false; 619 llvm::Optional<bool> shouldPrune; 620 621 SmallString<128> LhsString, RhsString; 622 { 623 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString); 624 const bool isVarLHS = patternMatch(BExpr->getLHS(), OutLHS, BRC, R, N, 625 shouldPrune); 626 const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC, R, N, 627 shouldPrune); 628 629 shouldInvert = !isVarLHS && isVarRHS; 630 } 631 632 BinaryOperator::Opcode Op = BExpr->getOpcode(); 633 634 if (BinaryOperator::isAssignmentOp(Op)) { 635 // For assignment operators, all that we care about is that the LHS 636 // evaluates to "true" or "false". 637 return VisitConditionVariable(LhsString, BExpr->getLHS(), tookTrue, 638 BRC, R, N); 639 } 640 641 // For non-assignment operations, we require that we can understand 642 // both the LHS and RHS. 643 if (LhsString.empty() || RhsString.empty()) 644 return 0; 645 646 // Should we invert the strings if the LHS is not a variable name? 647 SmallString<256> buf; 648 llvm::raw_svector_ostream Out(buf); 649 Out << "Assuming " << (shouldInvert ? RhsString : LhsString) << " is "; 650 651 // Do we need to invert the opcode? 652 if (shouldInvert) 653 switch (Op) { 654 default: break; 655 case BO_LT: Op = BO_GT; break; 656 case BO_GT: Op = BO_LT; break; 657 case BO_LE: Op = BO_GE; break; 658 case BO_GE: Op = BO_LE; break; 659 } 660 661 if (!tookTrue) 662 switch (Op) { 663 case BO_EQ: Op = BO_NE; break; 664 case BO_NE: Op = BO_EQ; break; 665 case BO_LT: Op = BO_GE; break; 666 case BO_GT: Op = BO_LE; break; 667 case BO_LE: Op = BO_GT; break; 668 case BO_GE: Op = BO_LT; break; 669 default: 670 return 0; 671 } 672 673 switch (Op) { 674 case BO_EQ: 675 Out << "equal to "; 676 break; 677 case BO_NE: 678 Out << "not equal to "; 679 break; 680 default: 681 Out << BinaryOperator::getOpcodeStr(Op) << ' '; 682 break; 683 } 684 685 Out << (shouldInvert ? LhsString : RhsString); 686 const LocationContext *LCtx = N->getLocationContext(); 687 PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); 688 PathDiagnosticEventPiece *event = 689 new PathDiagnosticEventPiece(Loc, Out.str()); 690 if (shouldPrune.hasValue()) 691 event->setPrunable(shouldPrune.getValue()); 692 return event; 693} 694 695PathDiagnosticPiece * 696ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, 697 const Expr *CondVarExpr, 698 const bool tookTrue, 699 BugReporterContext &BRC, 700 BugReport &report, 701 const ExplodedNode *N) { 702 SmallString<256> buf; 703 llvm::raw_svector_ostream Out(buf); 704 Out << "Assuming " << LhsString << " is "; 705 706 QualType Ty = CondVarExpr->getType(); 707 708 if (Ty->isPointerType()) 709 Out << (tookTrue ? "not null" : "null"); 710 else if (Ty->isObjCObjectPointerType()) 711 Out << (tookTrue ? "not nil" : "nil"); 712 else if (Ty->isBooleanType()) 713 Out << (tookTrue ? "true" : "false"); 714 else if (Ty->isIntegerType()) 715 Out << (tookTrue ? "non-zero" : "zero"); 716 else 717 return 0; 718 719 const LocationContext *LCtx = N->getLocationContext(); 720 PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx); 721 PathDiagnosticEventPiece *event = 722 new PathDiagnosticEventPiece(Loc, Out.str()); 723 724 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(CondVarExpr)) { 725 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 726 const ProgramState *state = N->getState().getPtr(); 727 if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { 728 if (report.isInteresting(R)) 729 event->setPrunable(false); 730 } 731 } 732 } 733 734 return event; 735} 736 737PathDiagnosticPiece * 738ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 739 const DeclRefExpr *DR, 740 const bool tookTrue, 741 BugReporterContext &BRC, 742 BugReport &report, 743 const ExplodedNode *N) { 744 745 const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); 746 if (!VD) 747 return 0; 748 749 SmallString<256> Buf; 750 llvm::raw_svector_ostream Out(Buf); 751 752 Out << "Assuming '"; 753 VD->getDeclName().printName(Out); 754 Out << "' is "; 755 756 QualType VDTy = VD->getType(); 757 758 if (VDTy->isPointerType()) 759 Out << (tookTrue ? "non-null" : "null"); 760 else if (VDTy->isObjCObjectPointerType()) 761 Out << (tookTrue ? "non-nil" : "nil"); 762 else if (VDTy->isScalarType()) 763 Out << (tookTrue ? "not equal to 0" : "0"); 764 else 765 return 0; 766 767 const LocationContext *LCtx = N->getLocationContext(); 768 PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); 769 PathDiagnosticEventPiece *event = 770 new PathDiagnosticEventPiece(Loc, Out.str()); 771 772 const ProgramState *state = N->getState().getPtr(); 773 if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { 774 if (report.isInteresting(R)) 775 event->setPrunable(false); 776 else { 777 SVal V = state->getSVal(R); 778 if (report.isInteresting(V)) 779 event->setPrunable(false); 780 } 781 } 782 return event; 783} 784 785