BugReporterVisitors.cpp revision a1f81bb0e55749a1414b1b5124bb83b9052ff2ac
1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// BugReporterVisitors.cpp - Helpers for reporting bugs -----------*- C++ -*--// 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// The LLVM Compiler Infrastructure 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// This file is distributed under the University of Illinois Open Source 6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// License. See LICENSE.TXT for details. 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//===----------------------------------------------------------------------===// 9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This file defines a set of BugReporter "visitors" which can be used to 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// enhance the diagnostics reported for a bug. 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch//===----------------------------------------------------------------------===// 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 16c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "clang/AST/Expr.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "clang/AST/ExprObjC.h" 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "llvm/ADT/SmallString.h" 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using namespace clang; 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using namespace ento; 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//===----------------------------------------------------------------------===// 30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Utility functions. 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//===----------------------------------------------------------------------===// 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) { 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Pattern match for a few useful cases (do something smarter later): 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // a[0], p->f, *p 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const PostStmt *Loc = N->getLocationAs<PostStmt>(); 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!Loc) 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return 0; 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const Expr *S = dyn_cast<Expr>(Loc->getStmt()); 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!S) 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return 0; 43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch S = S->IgnoreParenCasts(); 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch while (true) { 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) { 47a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) assert(B->isAssignmentOp()); 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) S = B->getLHS()->IgnoreParenCasts(); 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) continue; 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 51a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) { 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (U->getOpcode() == UO_Deref) 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return U->getSubExpr()->IgnoreParenCasts(); 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) { 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return ME->getBase()->IgnoreParenCasts(); 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) { 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return AE->getBase(); 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) break; 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return NULL; 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 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::trackNullOrUndefValue(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 *Succ, 249 const ExplodedNode *Pred, 250 BugReporterContext &BRC, 251 BugReport &BR) { 252 253 if (satisfied) 254 return NULL; 255 256 const ExplodedNode *StoreSite = 0; 257 const Expr *InitE = 0; 258 259 // First see if we reached the declaration of the region. 260 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { 261 if (const PostStmt *P = Pred->getLocationAs<PostStmt>()) { 262 if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) { 263 if (DS->getSingleDecl() == VR->getDecl()) { 264 StoreSite = Pred; 265 InitE = VR->getDecl()->getInit(); 266 } 267 } 268 } 269 } 270 271 // Otherwise, check that Succ has this binding and Pred does not, i.e. this is 272 // where the binding first occurred. 273 if (!StoreSite) { 274 if (Succ->getState()->getSVal(R) != V) 275 return NULL; 276 if (Pred->getState()->getSVal(R) == V) 277 return NULL; 278 279 StoreSite = Succ; 280 281 // If this is an assignment expression, we can track the value 282 // being assigned. 283 if (const PostStmt *P = Succ->getLocationAs<PostStmt>()) 284 if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) 285 if (BO->isAssignmentOp()) 286 InitE = BO->getRHS(); 287 } 288 289 if (!StoreSite) 290 return NULL; 291 satisfied = true; 292 293 // If the value that was stored came from an inlined call, make sure we 294 // step into the call. 295 if (InitE) { 296 InitE = InitE->IgnoreParenCasts(); 297 ReturnVisitor::addVisitorIfNecessary(StoreSite, InitE, BR); 298 } 299 300 // Okay, we've found the binding. Emit an appropriate message. 301 SmallString<256> sbuf; 302 llvm::raw_svector_ostream os(sbuf); 303 304 if (const PostStmt *PS = StoreSite->getLocationAs<PostStmt>()) { 305 if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) { 306 307 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { 308 os << "Variable '" << *VR->getDecl() << "' "; 309 } 310 else 311 return NULL; 312 313 if (isa<loc::ConcreteInt>(V)) { 314 bool b = false; 315 if (R->isBoundable()) { 316 if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { 317 if (TR->getValueType()->isObjCObjectPointerType()) { 318 os << "initialized to nil"; 319 b = true; 320 } 321 } 322 } 323 324 if (!b) 325 os << "initialized to a null pointer value"; 326 } 327 else if (isa<nonloc::ConcreteInt>(V)) { 328 os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue(); 329 } 330 else if (V.isUndef()) { 331 if (isa<VarRegion>(R)) { 332 const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); 333 if (VD->getInit()) 334 os << "initialized to a garbage value"; 335 else 336 os << "declared without an initial value"; 337 } 338 } 339 else { 340 os << "initialized here"; 341 } 342 } 343 } 344 345 if (os.str().empty()) { 346 if (isa<loc::ConcreteInt>(V)) { 347 bool b = false; 348 if (R->isBoundable()) { 349 if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { 350 if (TR->getValueType()->isObjCObjectPointerType()) { 351 os << "nil object reference stored to "; 352 b = true; 353 } 354 } 355 } 356 357 if (!b) 358 os << "Null pointer value stored to "; 359 } 360 else if (V.isUndef()) { 361 os << "Uninitialized value stored to "; 362 } 363 else if (isa<nonloc::ConcreteInt>(V)) { 364 os << "The value " << cast<nonloc::ConcreteInt>(V).getValue() 365 << " is assigned to "; 366 } 367 else 368 os << "Value assigned to "; 369 370 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { 371 os << '\'' << *VR->getDecl() << '\''; 372 } 373 else 374 return NULL; 375 } 376 377 // Construct a new PathDiagnosticPiece. 378 ProgramPoint P = StoreSite->getLocation(); 379 PathDiagnosticLocation L = 380 PathDiagnosticLocation::create(P, BRC.getSourceManager()); 381 if (!L.isValid()) 382 return NULL; 383 return new PathDiagnosticEventPiece(L, os.str()); 384} 385 386void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const { 387 static int tag = 0; 388 ID.AddPointer(&tag); 389 ID.AddBoolean(Assumption); 390 ID.Add(Constraint); 391} 392 393PathDiagnosticPiece * 394TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, 395 const ExplodedNode *PrevN, 396 BugReporterContext &BRC, 397 BugReport &BR) { 398 if (isSatisfied) 399 return NULL; 400 401 // Check if in the previous state it was feasible for this constraint 402 // to *not* be true. 403 if (PrevN->getState()->assume(Constraint, !Assumption)) { 404 405 isSatisfied = true; 406 407 // As a sanity check, make sure that the negation of the constraint 408 // was infeasible in the current state. If it is feasible, we somehow 409 // missed the transition point. 410 if (N->getState()->assume(Constraint, !Assumption)) 411 return NULL; 412 413 // We found the transition point for the constraint. We now need to 414 // pretty-print the constraint. (work-in-progress) 415 std::string sbuf; 416 llvm::raw_string_ostream os(sbuf); 417 418 if (isa<Loc>(Constraint)) { 419 os << "Assuming pointer value is "; 420 os << (Assumption ? "non-null" : "null"); 421 } 422 423 if (os.str().empty()) 424 return NULL; 425 426 // Construct a new PathDiagnosticPiece. 427 ProgramPoint P = N->getLocation(); 428 PathDiagnosticLocation L = 429 PathDiagnosticLocation::create(P, BRC.getSourceManager()); 430 if (!L.isValid()) 431 return NULL; 432 return new PathDiagnosticEventPiece(L, os.str()); 433 } 434 435 return NULL; 436} 437 438void bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, 439 BugReport &report) { 440 if (!S || !N) 441 return; 442 443 ProgramStateManager &StateMgr = N->getState()->getStateManager(); 444 445 // Walk through nodes until we get one that matches the statement exactly. 446 while (N) { 447 const ProgramPoint &pp = N->getLocation(); 448 if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) { 449 if (ps->getStmt() == S) 450 break; 451 } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) { 452 if (CEE->getCalleeContext()->getCallSite() == S) 453 break; 454 } 455 N = N->getFirstPred(); 456 } 457 458 if (!N) 459 return; 460 461 ProgramStateRef state = N->getState(); 462 463 // See if the expression we're interested refers to a variable. 464 // If so, we can track both its contents and constraints on its value. 465 if (const Expr *Ex = dyn_cast<Expr>(S)) { 466 // Strip off parens and casts. Note that this will never have issues with 467 // C++ user-defined implicit conversions, because those have a constructor 468 // or function call inside. 469 Ex = Ex->IgnoreParenCasts(); 470 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { 471 // FIXME: Right now we only track VarDecls because it's non-trivial to 472 // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812> 473 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 474 const VarRegion *R = 475 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); 476 477 // Mark both the variable region and its contents as interesting. 478 SVal V = state->getRawSVal(loc::MemRegionVal(R)); 479 report.markInteresting(R); 480 report.markInteresting(V); 481 482 // If the contents are symbolic, find out when they became null. 483 if (V.getAsLocSymbol()) { 484 BugReporterVisitor *ConstraintTracker 485 = new TrackConstraintBRVisitor(cast<loc::MemRegionVal>(V), false); 486 report.addVisitor(ConstraintTracker); 487 } 488 489 report.addVisitor(new FindLastStoreBRVisitor(V, R)); 490 return; 491 } 492 } 493 } 494 495 // If the expression does NOT refer to a variable, we can still track 496 // constraints on its contents. 497 SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); 498 499 // Uncomment this to find cases where we aren't properly getting the 500 // base value that was dereferenced. 501 // assert(!V.isUnknownOrUndef()); 502 503 // Is it a symbolic value? 504 if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) { 505 const MemRegion *Base = L->getRegion()->getBaseRegion(); 506 if (isa<SymbolicRegion>(Base)) { 507 report.markInteresting(Base); 508 report.addVisitor(new TrackConstraintBRVisitor(loc::MemRegionVal(Base), 509 false)); 510 } 511 } else { 512 // Otherwise, if the value came from an inlined function call, 513 // we should at least make sure that function isn't pruned in our output. 514 ReturnVisitor::addVisitorIfNecessary(N, S, report); 515 } 516} 517 518BugReporterVisitor * 519FindLastStoreBRVisitor::createVisitorObject(const ExplodedNode *N, 520 const MemRegion *R) { 521 assert(R && "The memory region is null."); 522 523 ProgramStateRef state = N->getState(); 524 SVal V = state->getSVal(R); 525 if (V.isUnknown()) 526 return 0; 527 528 return new FindLastStoreBRVisitor(V, R); 529} 530 531 532PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, 533 const ExplodedNode *PrevN, 534 BugReporterContext &BRC, 535 BugReport &BR) { 536 const PostStmt *P = N->getLocationAs<PostStmt>(); 537 if (!P) 538 return 0; 539 const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>(); 540 if (!ME) 541 return 0; 542 const Expr *Receiver = ME->getInstanceReceiver(); 543 if (!Receiver) 544 return 0; 545 ProgramStateRef state = N->getState(); 546 const SVal &V = state->getSVal(Receiver, N->getLocationContext()); 547 const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V); 548 if (!DV) 549 return 0; 550 state = state->assume(*DV, true); 551 if (state) 552 return 0; 553 554 // The receiver was nil, and hence the method was skipped. 555 // Register a BugReporterVisitor to issue a message telling us how 556 // the receiver was null. 557 bugreporter::trackNullOrUndefValue(N, Receiver, BR); 558 // Issue a message saying that the method was skipped. 559 PathDiagnosticLocation L(Receiver, BRC.getSourceManager(), 560 N->getLocationContext()); 561 return new PathDiagnosticEventPiece(L, "No method is called " 562 "because the receiver is nil"); 563} 564 565// Registers every VarDecl inside a Stmt with a last store visitor. 566void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR, 567 const Stmt *S) { 568 const ExplodedNode *N = BR.getErrorNode(); 569 std::deque<const Stmt *> WorkList; 570 WorkList.push_back(S); 571 572 while (!WorkList.empty()) { 573 const Stmt *Head = WorkList.front(); 574 WorkList.pop_front(); 575 576 ProgramStateRef state = N->getState(); 577 ProgramStateManager &StateMgr = state->getStateManager(); 578 579 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Head)) { 580 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 581 const VarRegion *R = 582 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); 583 584 // What did we load? 585 SVal V = state->getSVal(S, N->getLocationContext()); 586 587 if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) { 588 // Register a new visitor with the BugReport. 589 BR.addVisitor(new FindLastStoreBRVisitor(V, R)); 590 } 591 } 592 } 593 594 for (Stmt::const_child_iterator I = Head->child_begin(); 595 I != Head->child_end(); ++I) 596 WorkList.push_back(*I); 597 } 598} 599 600//===----------------------------------------------------------------------===// 601// Visitor that tries to report interesting diagnostics from conditions. 602//===----------------------------------------------------------------------===// 603PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N, 604 const ExplodedNode *Prev, 605 BugReporterContext &BRC, 606 BugReport &BR) { 607 PathDiagnosticPiece *piece = VisitNodeImpl(N, Prev, BRC, BR); 608 if (PathDiagnosticEventPiece *ev = 609 dyn_cast_or_null<PathDiagnosticEventPiece>(piece)) 610 ev->setPrunable(true, /* override */ false); 611 return piece; 612} 613 614PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, 615 const ExplodedNode *Prev, 616 BugReporterContext &BRC, 617 BugReport &BR) { 618 619 const ProgramPoint &progPoint = N->getLocation(); 620 621 ProgramStateRef CurrentState = N->getState(); 622 ProgramStateRef PrevState = Prev->getState(); 623 624 // Compare the GDMs of the state, because that is where constraints 625 // are managed. Note that ensure that we only look at nodes that 626 // were generated by the analyzer engine proper, not checkers. 627 if (CurrentState->getGDM().getRoot() == 628 PrevState->getGDM().getRoot()) 629 return 0; 630 631 // If an assumption was made on a branch, it should be caught 632 // here by looking at the state transition. 633 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&progPoint)) { 634 const CFGBlock *srcBlk = BE->getSrc(); 635 if (const Stmt *term = srcBlk->getTerminator()) 636 return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC); 637 return 0; 638 } 639 640 if (const PostStmt *PS = dyn_cast<PostStmt>(&progPoint)) { 641 // FIXME: Assuming that BugReporter is a GRBugReporter is a layering 642 // violation. 643 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags = 644 cast<GRBugReporter>(BRC.getBugReporter()). 645 getEngine().getEagerlyAssumeTags(); 646 647 const ProgramPointTag *tag = PS->getTag(); 648 if (tag == tags.first) 649 return VisitTrueTest(cast<Expr>(PS->getStmt()), true, 650 BRC, BR, N); 651 if (tag == tags.second) 652 return VisitTrueTest(cast<Expr>(PS->getStmt()), false, 653 BRC, BR, N); 654 655 return 0; 656 } 657 658 return 0; 659} 660 661PathDiagnosticPiece * 662ConditionBRVisitor::VisitTerminator(const Stmt *Term, 663 const ExplodedNode *N, 664 const CFGBlock *srcBlk, 665 const CFGBlock *dstBlk, 666 BugReport &R, 667 BugReporterContext &BRC) { 668 const Expr *Cond = 0; 669 670 switch (Term->getStmtClass()) { 671 default: 672 return 0; 673 case Stmt::IfStmtClass: 674 Cond = cast<IfStmt>(Term)->getCond(); 675 break; 676 case Stmt::ConditionalOperatorClass: 677 Cond = cast<ConditionalOperator>(Term)->getCond(); 678 break; 679 } 680 681 assert(Cond); 682 assert(srcBlk->succ_size() == 2); 683 const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk; 684 return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()), 685 tookTrue, BRC, R, N); 686} 687 688PathDiagnosticPiece * 689ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 690 bool tookTrue, 691 BugReporterContext &BRC, 692 BugReport &R, 693 const ExplodedNode *N) { 694 695 const Expr *Ex = Cond; 696 697 while (true) { 698 Ex = Ex->IgnoreParens(); 699 switch (Ex->getStmtClass()) { 700 default: 701 return 0; 702 case Stmt::BinaryOperatorClass: 703 return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC, 704 R, N); 705 case Stmt::DeclRefExprClass: 706 return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC, 707 R, N); 708 case Stmt::UnaryOperatorClass: { 709 const UnaryOperator *UO = cast<UnaryOperator>(Ex); 710 if (UO->getOpcode() == UO_LNot) { 711 tookTrue = !tookTrue; 712 Ex = UO->getSubExpr()->IgnoreParenNoopCasts(BRC.getASTContext()); 713 continue; 714 } 715 return 0; 716 } 717 } 718 } 719} 720 721bool ConditionBRVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out, 722 BugReporterContext &BRC, 723 BugReport &report, 724 const ExplodedNode *N, 725 llvm::Optional<bool> &prunable) { 726 const Expr *OriginalExpr = Ex; 727 Ex = Ex->IgnoreParenCasts(); 728 729 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { 730 const bool quotes = isa<VarDecl>(DR->getDecl()); 731 if (quotes) { 732 Out << '\''; 733 const LocationContext *LCtx = N->getLocationContext(); 734 const ProgramState *state = N->getState().getPtr(); 735 if (const MemRegion *R = state->getLValue(cast<VarDecl>(DR->getDecl()), 736 LCtx).getAsRegion()) { 737 if (report.isInteresting(R)) 738 prunable = false; 739 else { 740 const ProgramState *state = N->getState().getPtr(); 741 SVal V = state->getSVal(R); 742 if (report.isInteresting(V)) 743 prunable = false; 744 } 745 } 746 } 747 Out << DR->getDecl()->getDeclName().getAsString(); 748 if (quotes) 749 Out << '\''; 750 return quotes; 751 } 752 753 if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(Ex)) { 754 QualType OriginalTy = OriginalExpr->getType(); 755 if (OriginalTy->isPointerType()) { 756 if (IL->getValue() == 0) { 757 Out << "null"; 758 return false; 759 } 760 } 761 else if (OriginalTy->isObjCObjectPointerType()) { 762 if (IL->getValue() == 0) { 763 Out << "nil"; 764 return false; 765 } 766 } 767 768 Out << IL->getValue(); 769 return false; 770 } 771 772 return false; 773} 774 775PathDiagnosticPiece * 776ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 777 const BinaryOperator *BExpr, 778 const bool tookTrue, 779 BugReporterContext &BRC, 780 BugReport &R, 781 const ExplodedNode *N) { 782 783 bool shouldInvert = false; 784 llvm::Optional<bool> shouldPrune; 785 786 SmallString<128> LhsString, RhsString; 787 { 788 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString); 789 const bool isVarLHS = patternMatch(BExpr->getLHS(), OutLHS, BRC, R, N, 790 shouldPrune); 791 const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC, R, N, 792 shouldPrune); 793 794 shouldInvert = !isVarLHS && isVarRHS; 795 } 796 797 BinaryOperator::Opcode Op = BExpr->getOpcode(); 798 799 if (BinaryOperator::isAssignmentOp(Op)) { 800 // For assignment operators, all that we care about is that the LHS 801 // evaluates to "true" or "false". 802 return VisitConditionVariable(LhsString, BExpr->getLHS(), tookTrue, 803 BRC, R, N); 804 } 805 806 // For non-assignment operations, we require that we can understand 807 // both the LHS and RHS. 808 if (LhsString.empty() || RhsString.empty()) 809 return 0; 810 811 // Should we invert the strings if the LHS is not a variable name? 812 SmallString<256> buf; 813 llvm::raw_svector_ostream Out(buf); 814 Out << "Assuming " << (shouldInvert ? RhsString : LhsString) << " is "; 815 816 // Do we need to invert the opcode? 817 if (shouldInvert) 818 switch (Op) { 819 default: break; 820 case BO_LT: Op = BO_GT; break; 821 case BO_GT: Op = BO_LT; break; 822 case BO_LE: Op = BO_GE; break; 823 case BO_GE: Op = BO_LE; break; 824 } 825 826 if (!tookTrue) 827 switch (Op) { 828 case BO_EQ: Op = BO_NE; break; 829 case BO_NE: Op = BO_EQ; break; 830 case BO_LT: Op = BO_GE; break; 831 case BO_GT: Op = BO_LE; break; 832 case BO_LE: Op = BO_GT; break; 833 case BO_GE: Op = BO_LT; break; 834 default: 835 return 0; 836 } 837 838 switch (Op) { 839 case BO_EQ: 840 Out << "equal to "; 841 break; 842 case BO_NE: 843 Out << "not equal to "; 844 break; 845 default: 846 Out << BinaryOperator::getOpcodeStr(Op) << ' '; 847 break; 848 } 849 850 Out << (shouldInvert ? LhsString : RhsString); 851 const LocationContext *LCtx = N->getLocationContext(); 852 PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); 853 PathDiagnosticEventPiece *event = 854 new PathDiagnosticEventPiece(Loc, Out.str()); 855 if (shouldPrune.hasValue()) 856 event->setPrunable(shouldPrune.getValue()); 857 return event; 858} 859 860PathDiagnosticPiece * 861ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, 862 const Expr *CondVarExpr, 863 const bool tookTrue, 864 BugReporterContext &BRC, 865 BugReport &report, 866 const ExplodedNode *N) { 867 // FIXME: If there's already a constraint tracker for this variable, 868 // we shouldn't emit anything here (c.f. the double note in 869 // test/Analysis/inlining/path-notes.c) 870 SmallString<256> buf; 871 llvm::raw_svector_ostream Out(buf); 872 Out << "Assuming " << LhsString << " is "; 873 874 QualType Ty = CondVarExpr->getType(); 875 876 if (Ty->isPointerType()) 877 Out << (tookTrue ? "not null" : "null"); 878 else if (Ty->isObjCObjectPointerType()) 879 Out << (tookTrue ? "not nil" : "nil"); 880 else if (Ty->isBooleanType()) 881 Out << (tookTrue ? "true" : "false"); 882 else if (Ty->isIntegerType()) 883 Out << (tookTrue ? "non-zero" : "zero"); 884 else 885 return 0; 886 887 const LocationContext *LCtx = N->getLocationContext(); 888 PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx); 889 PathDiagnosticEventPiece *event = 890 new PathDiagnosticEventPiece(Loc, Out.str()); 891 892 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(CondVarExpr)) { 893 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 894 const ProgramState *state = N->getState().getPtr(); 895 if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { 896 if (report.isInteresting(R)) 897 event->setPrunable(false); 898 } 899 } 900 } 901 902 return event; 903} 904 905PathDiagnosticPiece * 906ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 907 const DeclRefExpr *DR, 908 const bool tookTrue, 909 BugReporterContext &BRC, 910 BugReport &report, 911 const ExplodedNode *N) { 912 913 const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); 914 if (!VD) 915 return 0; 916 917 SmallString<256> Buf; 918 llvm::raw_svector_ostream Out(Buf); 919 920 Out << "Assuming '"; 921 VD->getDeclName().printName(Out); 922 Out << "' is "; 923 924 QualType VDTy = VD->getType(); 925 926 if (VDTy->isPointerType()) 927 Out << (tookTrue ? "non-null" : "null"); 928 else if (VDTy->isObjCObjectPointerType()) 929 Out << (tookTrue ? "non-nil" : "nil"); 930 else if (VDTy->isScalarType()) 931 Out << (tookTrue ? "not equal to 0" : "0"); 932 else 933 return 0; 934 935 const LocationContext *LCtx = N->getLocationContext(); 936 PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); 937 PathDiagnosticEventPiece *event = 938 new PathDiagnosticEventPiece(Loc, Out.str()); 939 940 const ProgramState *state = N->getState().getPtr(); 941 if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { 942 if (report.isInteresting(R)) 943 event->setPrunable(false); 944 else { 945 SVal V = state->getSVal(R); 946 if (report.isInteresting(V)) 947 event->setPrunable(false); 948 } 949 } 950 return event; 951} 952 953