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