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