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