1 //===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- 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 the PathDiagnostic-related interfaces. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 15 #include "clang/AST/Decl.h" 16 #include "clang/AST/DeclCXX.h" 17 #include "clang/AST/DeclObjC.h" 18 #include "clang/AST/Expr.h" 19 #include "clang/AST/ExprCXX.h" 20 #include "clang/AST/ParentMap.h" 21 #include "clang/AST/StmtCXX.h" 22 #include "clang/Basic/SourceManager.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 24 #include "llvm/ADT/SmallString.h" 25 #include "llvm/ADT/StringExtras.h" 26 #include "llvm/Support/raw_ostream.h" 27 28 using namespace clang; 29 using namespace ento; 30 31 bool PathDiagnosticMacroPiece::containsEvent() const { 32 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 33 I!=E; ++I) { 34 if (isa<PathDiagnosticEventPiece>(*I)) 35 return true; 36 if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I)) 37 if (MP->containsEvent()) 38 return true; 39 } 40 return false; 41 } 42 43 static StringRef StripTrailingDots(StringRef s) { 44 for (StringRef::size_type i = s.size(); i != 0; --i) 45 if (s[i - 1] != '.') 46 return s.substr(0, i); 47 return ""; 48 } 49 50 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, 51 Kind k, DisplayHint hint) 52 : str(StripTrailingDots(s)), kind(k), Hint(hint), 53 LastInMainSourceFile(false) {} 54 55 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 56 : kind(k), Hint(hint), LastInMainSourceFile(false) {} 57 58 PathDiagnosticPiece::~PathDiagnosticPiece() {} 59 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {} 60 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {} 61 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} 62 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {} 63 64 65 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, 66 bool ShouldFlattenMacros) const { 67 for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { 68 PathDiagnosticPiece *Piece = I->get(); 69 70 switch (Piece->getKind()) { 71 case PathDiagnosticPiece::Call: { 72 PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece); 73 IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter = 74 Call->getCallEnterEvent(); 75 if (CallEnter) 76 Current.push_back(CallEnter); 77 Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros); 78 IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit = 79 Call->getCallExitEvent(); 80 if (callExit) 81 Current.push_back(callExit); 82 break; 83 } 84 case PathDiagnosticPiece::Macro: { 85 PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece); 86 if (ShouldFlattenMacros) { 87 Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros); 88 } else { 89 Current.push_back(Piece); 90 PathPieces NewPath; 91 Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros); 92 // FIXME: This probably shouldn't mutate the original path piece. 93 Macro->subPieces = NewPath; 94 } 95 break; 96 } 97 case PathDiagnosticPiece::Event: 98 case PathDiagnosticPiece::ControlFlow: 99 Current.push_back(Piece); 100 break; 101 } 102 } 103 } 104 105 106 PathDiagnostic::~PathDiagnostic() {} 107 108 PathDiagnostic::PathDiagnostic(StringRef CheckName, const Decl *declWithIssue, 109 StringRef bugtype, StringRef verboseDesc, 110 StringRef shortDesc, StringRef category, 111 PathDiagnosticLocation LocationToUnique, 112 const Decl *DeclToUnique) 113 : CheckName(CheckName), 114 DeclWithIssue(declWithIssue), 115 BugType(StripTrailingDots(bugtype)), 116 VerboseDesc(StripTrailingDots(verboseDesc)), 117 ShortDesc(StripTrailingDots(shortDesc)), 118 Category(StripTrailingDots(category)), 119 UniqueingLoc(LocationToUnique), 120 UniqueingDecl(DeclToUnique), 121 path(pathImpl) {} 122 123 static PathDiagnosticCallPiece * 124 getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, 125 const SourceManager &SMgr) { 126 SourceLocation CallLoc = CP->callEnter.asLocation(); 127 128 // If the call is within a macro, don't do anything (for now). 129 if (CallLoc.isMacroID()) 130 return nullptr; 131 132 assert(SMgr.isInMainFile(CallLoc) && 133 "The call piece should be in the main file."); 134 135 // Check if CP represents a path through a function outside of the main file. 136 if (!SMgr.isInMainFile(CP->callEnterWithin.asLocation())) 137 return CP; 138 139 const PathPieces &Path = CP->path; 140 if (Path.empty()) 141 return nullptr; 142 143 // Check if the last piece in the callee path is a call to a function outside 144 // of the main file. 145 if (PathDiagnosticCallPiece *CPInner = 146 dyn_cast<PathDiagnosticCallPiece>(Path.back())) { 147 return getFirstStackedCallToHeaderFile(CPInner, SMgr); 148 } 149 150 // Otherwise, the last piece is in the main file. 151 return nullptr; 152 } 153 154 void PathDiagnostic::resetDiagnosticLocationToMainFile() { 155 if (path.empty()) 156 return; 157 158 PathDiagnosticPiece *LastP = path.back().get(); 159 assert(LastP); 160 const SourceManager &SMgr = LastP->getLocation().getManager(); 161 162 // We only need to check if the report ends inside headers, if the last piece 163 // is a call piece. 164 if (PathDiagnosticCallPiece *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) { 165 CP = getFirstStackedCallToHeaderFile(CP, SMgr); 166 if (CP) { 167 // Mark the piece. 168 CP->setAsLastInMainSourceFile(); 169 170 // Update the path diagnostic message. 171 const NamedDecl *ND = dyn_cast<NamedDecl>(CP->getCallee()); 172 if (ND) { 173 SmallString<200> buf; 174 llvm::raw_svector_ostream os(buf); 175 os << " (within a call to '" << ND->getDeclName() << "')"; 176 appendToDesc(os.str()); 177 } 178 179 // Reset the report containing declaration and location. 180 DeclWithIssue = CP->getCaller(); 181 Loc = CP->getLocation(); 182 183 return; 184 } 185 } 186 } 187 188 void PathDiagnosticConsumer::anchor() { } 189 190 PathDiagnosticConsumer::~PathDiagnosticConsumer() { 191 // Delete the contents of the FoldingSet if it isn't empty already. 192 for (llvm::FoldingSet<PathDiagnostic>::iterator it = 193 Diags.begin(), et = Diags.end() ; it != et ; ++it) { 194 delete &*it; 195 } 196 } 197 198 void PathDiagnosticConsumer::HandlePathDiagnostic( 199 std::unique_ptr<PathDiagnostic> D) { 200 if (!D || D->path.empty()) 201 return; 202 203 // We need to flatten the locations (convert Stmt* to locations) because 204 // the referenced statements may be freed by the time the diagnostics 205 // are emitted. 206 D->flattenLocations(); 207 208 // If the PathDiagnosticConsumer does not support diagnostics that 209 // cross file boundaries, prune out such diagnostics now. 210 if (!supportsCrossFileDiagnostics()) { 211 // Verify that the entire path is from the same FileID. 212 FileID FID; 213 const SourceManager &SMgr = D->path.front()->getLocation().getManager(); 214 SmallVector<const PathPieces *, 5> WorkList; 215 WorkList.push_back(&D->path); 216 217 while (!WorkList.empty()) { 218 const PathPieces &path = *WorkList.pop_back_val(); 219 220 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; 221 ++I) { 222 const PathDiagnosticPiece *piece = I->get(); 223 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); 224 225 if (FID.isInvalid()) { 226 FID = SMgr.getFileID(L); 227 } else if (SMgr.getFileID(L) != FID) 228 return; // FIXME: Emit a warning? 229 230 // Check the source ranges. 231 ArrayRef<SourceRange> Ranges = piece->getRanges(); 232 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), 233 E = Ranges.end(); I != E; ++I) { 234 SourceLocation L = SMgr.getExpansionLoc(I->getBegin()); 235 if (!L.isFileID() || SMgr.getFileID(L) != FID) 236 return; // FIXME: Emit a warning? 237 L = SMgr.getExpansionLoc(I->getEnd()); 238 if (!L.isFileID() || SMgr.getFileID(L) != FID) 239 return; // FIXME: Emit a warning? 240 } 241 242 if (const PathDiagnosticCallPiece *call = 243 dyn_cast<PathDiagnosticCallPiece>(piece)) { 244 WorkList.push_back(&call->path); 245 } 246 else if (const PathDiagnosticMacroPiece *macro = 247 dyn_cast<PathDiagnosticMacroPiece>(piece)) { 248 WorkList.push_back(¯o->subPieces); 249 } 250 } 251 } 252 253 if (FID.isInvalid()) 254 return; // FIXME: Emit a warning? 255 } 256 257 // Profile the node to see if we already have something matching it 258 llvm::FoldingSetNodeID profile; 259 D->Profile(profile); 260 void *InsertPos = nullptr; 261 262 if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { 263 // Keep the PathDiagnostic with the shorter path. 264 // Note, the enclosing routine is called in deterministic order, so the 265 // results will be consistent between runs (no reason to break ties if the 266 // size is the same). 267 const unsigned orig_size = orig->full_size(); 268 const unsigned new_size = D->full_size(); 269 if (orig_size <= new_size) 270 return; 271 272 assert(orig != D.get()); 273 Diags.RemoveNode(orig); 274 delete orig; 275 } 276 277 Diags.InsertNode(D.release()); 278 } 279 280 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y); 281 static Optional<bool> 282 compareControlFlow(const PathDiagnosticControlFlowPiece &X, 283 const PathDiagnosticControlFlowPiece &Y) { 284 FullSourceLoc XSL = X.getStartLocation().asLocation(); 285 FullSourceLoc YSL = Y.getStartLocation().asLocation(); 286 if (XSL != YSL) 287 return XSL.isBeforeInTranslationUnitThan(YSL); 288 FullSourceLoc XEL = X.getEndLocation().asLocation(); 289 FullSourceLoc YEL = Y.getEndLocation().asLocation(); 290 if (XEL != YEL) 291 return XEL.isBeforeInTranslationUnitThan(YEL); 292 return None; 293 } 294 295 static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X, 296 const PathDiagnosticMacroPiece &Y) { 297 return comparePath(X.subPieces, Y.subPieces); 298 } 299 300 static Optional<bool> compareCall(const PathDiagnosticCallPiece &X, 301 const PathDiagnosticCallPiece &Y) { 302 FullSourceLoc X_CEL = X.callEnter.asLocation(); 303 FullSourceLoc Y_CEL = Y.callEnter.asLocation(); 304 if (X_CEL != Y_CEL) 305 return X_CEL.isBeforeInTranslationUnitThan(Y_CEL); 306 FullSourceLoc X_CEWL = X.callEnterWithin.asLocation(); 307 FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation(); 308 if (X_CEWL != Y_CEWL) 309 return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL); 310 FullSourceLoc X_CRL = X.callReturn.asLocation(); 311 FullSourceLoc Y_CRL = Y.callReturn.asLocation(); 312 if (X_CRL != Y_CRL) 313 return X_CRL.isBeforeInTranslationUnitThan(Y_CRL); 314 return comparePath(X.path, Y.path); 315 } 316 317 static Optional<bool> comparePiece(const PathDiagnosticPiece &X, 318 const PathDiagnosticPiece &Y) { 319 if (X.getKind() != Y.getKind()) 320 return X.getKind() < Y.getKind(); 321 322 FullSourceLoc XL = X.getLocation().asLocation(); 323 FullSourceLoc YL = Y.getLocation().asLocation(); 324 if (XL != YL) 325 return XL.isBeforeInTranslationUnitThan(YL); 326 327 if (X.getString() != Y.getString()) 328 return X.getString() < Y.getString(); 329 330 if (X.getRanges().size() != Y.getRanges().size()) 331 return X.getRanges().size() < Y.getRanges().size(); 332 333 const SourceManager &SM = XL.getManager(); 334 335 for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { 336 SourceRange XR = X.getRanges()[i]; 337 SourceRange YR = Y.getRanges()[i]; 338 if (XR != YR) { 339 if (XR.getBegin() != YR.getBegin()) 340 return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); 341 return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); 342 } 343 } 344 345 switch (X.getKind()) { 346 case clang::ento::PathDiagnosticPiece::ControlFlow: 347 return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), 348 cast<PathDiagnosticControlFlowPiece>(Y)); 349 case clang::ento::PathDiagnosticPiece::Event: 350 return None; 351 case clang::ento::PathDiagnosticPiece::Macro: 352 return compareMacro(cast<PathDiagnosticMacroPiece>(X), 353 cast<PathDiagnosticMacroPiece>(Y)); 354 case clang::ento::PathDiagnosticPiece::Call: 355 return compareCall(cast<PathDiagnosticCallPiece>(X), 356 cast<PathDiagnosticCallPiece>(Y)); 357 } 358 llvm_unreachable("all cases handled"); 359 } 360 361 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { 362 if (X.size() != Y.size()) 363 return X.size() < Y.size(); 364 365 PathPieces::const_iterator X_I = X.begin(), X_end = X.end(); 366 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end(); 367 368 for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) { 369 Optional<bool> b = comparePiece(**X_I, **Y_I); 370 if (b.hasValue()) 371 return b.getValue(); 372 } 373 374 return None; 375 } 376 377 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { 378 FullSourceLoc XL = X.getLocation().asLocation(); 379 FullSourceLoc YL = Y.getLocation().asLocation(); 380 if (XL != YL) 381 return XL.isBeforeInTranslationUnitThan(YL); 382 if (X.getBugType() != Y.getBugType()) 383 return X.getBugType() < Y.getBugType(); 384 if (X.getCategory() != Y.getCategory()) 385 return X.getCategory() < Y.getCategory(); 386 if (X.getVerboseDescription() != Y.getVerboseDescription()) 387 return X.getVerboseDescription() < Y.getVerboseDescription(); 388 if (X.getShortDescription() != Y.getShortDescription()) 389 return X.getShortDescription() < Y.getShortDescription(); 390 if (X.getDeclWithIssue() != Y.getDeclWithIssue()) { 391 const Decl *XD = X.getDeclWithIssue(); 392 if (!XD) 393 return true; 394 const Decl *YD = Y.getDeclWithIssue(); 395 if (!YD) 396 return false; 397 SourceLocation XDL = XD->getLocation(); 398 SourceLocation YDL = YD->getLocation(); 399 if (XDL != YDL) { 400 const SourceManager &SM = XL.getManager(); 401 return SM.isBeforeInTranslationUnit(XDL, YDL); 402 } 403 } 404 PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end(); 405 PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end(); 406 if (XE - XI != YE - YI) 407 return (XE - XI) < (YE - YI); 408 for ( ; XI != XE ; ++XI, ++YI) { 409 if (*XI != *YI) 410 return (*XI) < (*YI); 411 } 412 Optional<bool> b = comparePath(X.path, Y.path); 413 assert(b.hasValue()); 414 return b.getValue(); 415 } 416 417 void PathDiagnosticConsumer::FlushDiagnostics( 418 PathDiagnosticConsumer::FilesMade *Files) { 419 if (flushed) 420 return; 421 422 flushed = true; 423 424 std::vector<const PathDiagnostic *> BatchDiags; 425 for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(), 426 et = Diags.end(); it != et; ++it) { 427 const PathDiagnostic *D = &*it; 428 BatchDiags.push_back(D); 429 } 430 431 // Sort the diagnostics so that they are always emitted in a deterministic 432 // order. 433 int (*Comp)(const PathDiagnostic *const *, const PathDiagnostic *const *) = 434 [](const PathDiagnostic *const *X, const PathDiagnostic *const *Y) { 435 assert(*X != *Y && "PathDiagnostics not uniqued!"); 436 if (compare(**X, **Y)) 437 return -1; 438 assert(compare(**Y, **X) && "Not a total order!"); 439 return 1; 440 }; 441 array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp); 442 443 FlushDiagnosticsImpl(BatchDiags, Files); 444 445 // Delete the flushed diagnostics. 446 for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(), 447 et = BatchDiags.end(); it != et; ++it) { 448 const PathDiagnostic *D = *it; 449 delete D; 450 } 451 452 // Clear out the FoldingSet. 453 Diags.clear(); 454 } 455 456 PathDiagnosticConsumer::FilesMade::~FilesMade() { 457 for (PDFileEntry &Entry : Set) 458 Entry.~PDFileEntry(); 459 } 460 461 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, 462 StringRef ConsumerName, 463 StringRef FileName) { 464 llvm::FoldingSetNodeID NodeID; 465 NodeID.Add(PD); 466 void *InsertPos; 467 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos); 468 if (!Entry) { 469 Entry = Alloc.Allocate<PDFileEntry>(); 470 Entry = new (Entry) PDFileEntry(NodeID); 471 Set.InsertNode(Entry, InsertPos); 472 } 473 474 // Allocate persistent storage for the file name. 475 char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1); 476 memcpy(FileName_cstr, FileName.data(), FileName.size()); 477 478 Entry->files.push_back(std::make_pair(ConsumerName, 479 StringRef(FileName_cstr, 480 FileName.size()))); 481 } 482 483 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles * 484 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { 485 llvm::FoldingSetNodeID NodeID; 486 NodeID.Add(PD); 487 void *InsertPos; 488 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos); 489 if (!Entry) 490 return nullptr; 491 return &Entry->files; 492 } 493 494 //===----------------------------------------------------------------------===// 495 // PathDiagnosticLocation methods. 496 //===----------------------------------------------------------------------===// 497 498 static SourceLocation getValidSourceLocation(const Stmt* S, 499 LocationOrAnalysisDeclContext LAC, 500 bool UseEnd = false) { 501 SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart(); 502 assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should " 503 "be passed to PathDiagnosticLocation upon creation."); 504 505 // S might be a temporary statement that does not have a location in the 506 // source code, so find an enclosing statement and use its location. 507 if (!L.isValid()) { 508 509 AnalysisDeclContext *ADC; 510 if (LAC.is<const LocationContext*>()) 511 ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext(); 512 else 513 ADC = LAC.get<AnalysisDeclContext*>(); 514 515 ParentMap &PM = ADC->getParentMap(); 516 517 const Stmt *Parent = S; 518 do { 519 Parent = PM.getParent(Parent); 520 521 // In rare cases, we have implicit top-level expressions, 522 // such as arguments for implicit member initializers. 523 // In this case, fall back to the start of the body (even if we were 524 // asked for the statement end location). 525 if (!Parent) { 526 const Stmt *Body = ADC->getBody(); 527 if (Body) 528 L = Body->getLocStart(); 529 else 530 L = ADC->getDecl()->getLocEnd(); 531 break; 532 } 533 534 L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart(); 535 } while (!L.isValid()); 536 } 537 538 return L; 539 } 540 541 static PathDiagnosticLocation 542 getLocationForCaller(const StackFrameContext *SFC, 543 const LocationContext *CallerCtx, 544 const SourceManager &SM) { 545 const CFGBlock &Block = *SFC->getCallSiteBlock(); 546 CFGElement Source = Block[SFC->getIndex()]; 547 548 switch (Source.getKind()) { 549 case CFGElement::Statement: 550 return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), 551 SM, CallerCtx); 552 case CFGElement::Initializer: { 553 const CFGInitializer &Init = Source.castAs<CFGInitializer>(); 554 return PathDiagnosticLocation(Init.getInitializer()->getInit(), 555 SM, CallerCtx); 556 } 557 case CFGElement::AutomaticObjectDtor: { 558 const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>(); 559 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), 560 SM, CallerCtx); 561 } 562 case CFGElement::DeleteDtor: { 563 const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>(); 564 return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx); 565 } 566 case CFGElement::BaseDtor: 567 case CFGElement::MemberDtor: { 568 const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext(); 569 if (const Stmt *CallerBody = CallerInfo->getBody()) 570 return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx); 571 return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); 572 } 573 case CFGElement::TemporaryDtor: 574 case CFGElement::NewAllocator: 575 llvm_unreachable("not yet implemented!"); 576 } 577 578 llvm_unreachable("Unknown CFGElement kind"); 579 } 580 581 582 PathDiagnosticLocation 583 PathDiagnosticLocation::createBegin(const Decl *D, 584 const SourceManager &SM) { 585 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK); 586 } 587 588 PathDiagnosticLocation 589 PathDiagnosticLocation::createBegin(const Stmt *S, 590 const SourceManager &SM, 591 LocationOrAnalysisDeclContext LAC) { 592 return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 593 SM, SingleLocK); 594 } 595 596 597 PathDiagnosticLocation 598 PathDiagnosticLocation::createEnd(const Stmt *S, 599 const SourceManager &SM, 600 LocationOrAnalysisDeclContext LAC) { 601 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) 602 return createEndBrace(CS, SM); 603 return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true), 604 SM, SingleLocK); 605 } 606 607 PathDiagnosticLocation 608 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 609 const SourceManager &SM) { 610 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 611 } 612 613 PathDiagnosticLocation 614 PathDiagnosticLocation::createConditionalColonLoc( 615 const ConditionalOperator *CO, 616 const SourceManager &SM) { 617 return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK); 618 } 619 620 621 PathDiagnosticLocation 622 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, 623 const SourceManager &SM) { 624 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); 625 } 626 627 PathDiagnosticLocation 628 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 629 const SourceManager &SM) { 630 SourceLocation L = CS->getLBracLoc(); 631 return PathDiagnosticLocation(L, SM, SingleLocK); 632 } 633 634 PathDiagnosticLocation 635 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 636 const SourceManager &SM) { 637 SourceLocation L = CS->getRBracLoc(); 638 return PathDiagnosticLocation(L, SM, SingleLocK); 639 } 640 641 PathDiagnosticLocation 642 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, 643 const SourceManager &SM) { 644 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. 645 if (const CompoundStmt *CS = 646 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) 647 if (!CS->body_empty()) { 648 SourceLocation Loc = (*CS->body_begin())->getLocStart(); 649 return PathDiagnosticLocation(Loc, SM, SingleLocK); 650 } 651 652 return PathDiagnosticLocation(); 653 } 654 655 PathDiagnosticLocation 656 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, 657 const SourceManager &SM) { 658 SourceLocation L = LC->getDecl()->getBodyRBrace(); 659 return PathDiagnosticLocation(L, SM, SingleLocK); 660 } 661 662 PathDiagnosticLocation 663 PathDiagnosticLocation::create(const ProgramPoint& P, 664 const SourceManager &SMng) { 665 666 const Stmt* S = nullptr; 667 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { 668 const CFGBlock *BSrc = BE->getSrc(); 669 S = BSrc->getTerminatorCondition(); 670 } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) { 671 S = SP->getStmt(); 672 if (P.getAs<PostStmtPurgeDeadSymbols>()) 673 return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); 674 } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { 675 return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), 676 SMng); 677 } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { 678 return PathDiagnosticLocation(PIE->getLocation(), SMng); 679 } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { 680 return getLocationForCaller(CE->getCalleeContext(), 681 CE->getLocationContext(), 682 SMng); 683 } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { 684 return getLocationForCaller(CEE->getCalleeContext(), 685 CEE->getLocationContext(), 686 SMng); 687 } else { 688 llvm_unreachable("Unexpected ProgramPoint"); 689 } 690 691 return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 692 } 693 694 const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { 695 ProgramPoint P = N->getLocation(); 696 if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) 697 return SP->getStmt(); 698 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) 699 return BE->getSrc()->getTerminator(); 700 if (Optional<CallEnter> CE = P.getAs<CallEnter>()) 701 return CE->getCallExpr(); 702 if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) 703 return CEE->getCalleeContext()->getCallSite(); 704 if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>()) 705 return PIPP->getInitializer()->getInit(); 706 707 return nullptr; 708 } 709 710 const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { 711 for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) { 712 if (const Stmt *S = getStmt(N)) { 713 // Check if the statement is '?' or '&&'/'||'. These are "merges", 714 // not actual statement points. 715 switch (S->getStmtClass()) { 716 case Stmt::ChooseExprClass: 717 case Stmt::BinaryConditionalOperatorClass: 718 case Stmt::ConditionalOperatorClass: 719 continue; 720 case Stmt::BinaryOperatorClass: { 721 BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode(); 722 if (Op == BO_LAnd || Op == BO_LOr) 723 continue; 724 break; 725 } 726 default: 727 break; 728 } 729 // We found the statement, so return it. 730 return S; 731 } 732 } 733 734 return nullptr; 735 } 736 737 PathDiagnosticLocation 738 PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N, 739 const SourceManager &SM) { 740 assert(N && "Cannot create a location with a null node."); 741 const Stmt *S = getStmt(N); 742 743 if (!S) { 744 // If this is an implicit call, return the implicit call point location. 745 if (Optional<PreImplicitCall> PIE = N->getLocationAs<PreImplicitCall>()) 746 return PathDiagnosticLocation(PIE->getLocation(), SM); 747 S = getNextStmt(N); 748 } 749 750 if (S) { 751 ProgramPoint P = N->getLocation(); 752 const LocationContext *LC = N->getLocationContext(); 753 754 // For member expressions, return the location of the '.' or '->'. 755 if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) 756 return PathDiagnosticLocation::createMemberLoc(ME, SM); 757 758 // For binary operators, return the location of the operator. 759 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) 760 return PathDiagnosticLocation::createOperatorLoc(B, SM); 761 762 if (P.getAs<PostStmtPurgeDeadSymbols>()) 763 return PathDiagnosticLocation::createEnd(S, SM, LC); 764 765 if (S->getLocStart().isValid()) 766 return PathDiagnosticLocation(S, SM, LC); 767 return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM); 768 } 769 770 return createDeclEnd(N->getLocationContext(), SM); 771 } 772 773 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 774 const PathDiagnosticLocation &PDL) { 775 FullSourceLoc L = PDL.asLocation(); 776 return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 777 } 778 779 FullSourceLoc 780 PathDiagnosticLocation::genLocation(SourceLocation L, 781 LocationOrAnalysisDeclContext LAC) const { 782 assert(isValid()); 783 // Note that we want a 'switch' here so that the compiler can warn us in 784 // case we add more cases. 785 switch (K) { 786 case SingleLocK: 787 case RangeK: 788 break; 789 case StmtK: 790 // Defensive checking. 791 if (!S) 792 break; 793 return FullSourceLoc(getValidSourceLocation(S, LAC), 794 const_cast<SourceManager&>(*SM)); 795 case DeclK: 796 // Defensive checking. 797 if (!D) 798 break; 799 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 800 } 801 802 return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); 803 } 804 805 PathDiagnosticRange 806 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { 807 assert(isValid()); 808 // Note that we want a 'switch' here so that the compiler can warn us in 809 // case we add more cases. 810 switch (K) { 811 case SingleLocK: 812 return PathDiagnosticRange(SourceRange(Loc,Loc), true); 813 case RangeK: 814 break; 815 case StmtK: { 816 const Stmt *S = asStmt(); 817 switch (S->getStmtClass()) { 818 default: 819 break; 820 case Stmt::DeclStmtClass: { 821 const DeclStmt *DS = cast<DeclStmt>(S); 822 if (DS->isSingleDecl()) { 823 // Should always be the case, but we'll be defensive. 824 return SourceRange(DS->getLocStart(), 825 DS->getSingleDecl()->getLocation()); 826 } 827 break; 828 } 829 // FIXME: Provide better range information for different 830 // terminators. 831 case Stmt::IfStmtClass: 832 case Stmt::WhileStmtClass: 833 case Stmt::DoStmtClass: 834 case Stmt::ForStmtClass: 835 case Stmt::ChooseExprClass: 836 case Stmt::IndirectGotoStmtClass: 837 case Stmt::SwitchStmtClass: 838 case Stmt::BinaryConditionalOperatorClass: 839 case Stmt::ConditionalOperatorClass: 840 case Stmt::ObjCForCollectionStmtClass: { 841 SourceLocation L = getValidSourceLocation(S, LAC); 842 return SourceRange(L, L); 843 } 844 } 845 SourceRange R = S->getSourceRange(); 846 if (R.isValid()) 847 return R; 848 break; 849 } 850 case DeclK: 851 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 852 return MD->getSourceRange(); 853 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 854 if (Stmt *Body = FD->getBody()) 855 return Body->getSourceRange(); 856 } 857 else { 858 SourceLocation L = D->getLocation(); 859 return PathDiagnosticRange(SourceRange(L, L), true); 860 } 861 } 862 863 return SourceRange(Loc,Loc); 864 } 865 866 void PathDiagnosticLocation::flatten() { 867 if (K == StmtK) { 868 K = RangeK; 869 S = nullptr; 870 D = nullptr; 871 } 872 else if (K == DeclK) { 873 K = SingleLocK; 874 S = nullptr; 875 D = nullptr; 876 } 877 } 878 879 //===----------------------------------------------------------------------===// 880 // Manipulation of PathDiagnosticCallPieces. 881 //===----------------------------------------------------------------------===// 882 883 PathDiagnosticCallPiece * 884 PathDiagnosticCallPiece::construct(const ExplodedNode *N, 885 const CallExitEnd &CE, 886 const SourceManager &SM) { 887 const Decl *caller = CE.getLocationContext()->getDecl(); 888 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(), 889 CE.getLocationContext(), 890 SM); 891 return new PathDiagnosticCallPiece(caller, pos); 892 } 893 894 PathDiagnosticCallPiece * 895 PathDiagnosticCallPiece::construct(PathPieces &path, 896 const Decl *caller) { 897 PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller); 898 path.clear(); 899 path.push_front(C); 900 return C; 901 } 902 903 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 904 const SourceManager &SM) { 905 const StackFrameContext *CalleeCtx = CE.getCalleeContext(); 906 Callee = CalleeCtx->getDecl(); 907 908 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); 909 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); 910 } 911 912 static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D, 913 StringRef Prefix = StringRef()) { 914 if (!D->getIdentifier()) 915 return; 916 Out << Prefix << '\'' << *D << '\''; 917 } 918 919 static bool describeCodeDecl(raw_ostream &Out, const Decl *D, 920 bool ExtendedDescription, 921 StringRef Prefix = StringRef()) { 922 if (!D) 923 return false; 924 925 if (isa<BlockDecl>(D)) { 926 if (ExtendedDescription) 927 Out << Prefix << "anonymous block"; 928 return ExtendedDescription; 929 } 930 931 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { 932 Out << Prefix; 933 if (ExtendedDescription && !MD->isUserProvided()) { 934 if (MD->isExplicitlyDefaulted()) 935 Out << "defaulted "; 936 else 937 Out << "implicit "; 938 } 939 940 if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) { 941 if (CD->isDefaultConstructor()) 942 Out << "default "; 943 else if (CD->isCopyConstructor()) 944 Out << "copy "; 945 else if (CD->isMoveConstructor()) 946 Out << "move "; 947 948 Out << "constructor"; 949 describeClass(Out, MD->getParent(), " for "); 950 951 } else if (isa<CXXDestructorDecl>(MD)) { 952 if (!MD->isUserProvided()) { 953 Out << "destructor"; 954 describeClass(Out, MD->getParent(), " for "); 955 } else { 956 // Use ~Foo for explicitly-written destructors. 957 Out << "'" << *MD << "'"; 958 } 959 960 } else if (MD->isCopyAssignmentOperator()) { 961 Out << "copy assignment operator"; 962 describeClass(Out, MD->getParent(), " for "); 963 964 } else if (MD->isMoveAssignmentOperator()) { 965 Out << "move assignment operator"; 966 describeClass(Out, MD->getParent(), " for "); 967 968 } else { 969 if (MD->getParent()->getIdentifier()) 970 Out << "'" << *MD->getParent() << "::" << *MD << "'"; 971 else 972 Out << "'" << *MD << "'"; 973 } 974 975 return true; 976 } 977 978 Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\''; 979 return true; 980 } 981 982 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 983 PathDiagnosticCallPiece::getCallEnterEvent() const { 984 if (!Callee) 985 return nullptr; 986 987 SmallString<256> buf; 988 llvm::raw_svector_ostream Out(buf); 989 990 Out << "Calling "; 991 describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true); 992 993 assert(callEnter.asLocation().isValid()); 994 return new PathDiagnosticEventPiece(callEnter, Out.str()); 995 } 996 997 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 998 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { 999 if (!callEnterWithin.asLocation().isValid()) 1000 return nullptr; 1001 if (Callee->isImplicit() || !Callee->hasBody()) 1002 return nullptr; 1003 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee)) 1004 if (MD->isDefaulted()) 1005 return nullptr; 1006 1007 SmallString<256> buf; 1008 llvm::raw_svector_ostream Out(buf); 1009 1010 Out << "Entered call"; 1011 describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from "); 1012 1013 return new PathDiagnosticEventPiece(callEnterWithin, Out.str()); 1014 } 1015 1016 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 1017 PathDiagnosticCallPiece::getCallExitEvent() const { 1018 if (NoExit) 1019 return nullptr; 1020 1021 SmallString<256> buf; 1022 llvm::raw_svector_ostream Out(buf); 1023 1024 if (!CallStackMessage.empty()) { 1025 Out << CallStackMessage; 1026 } else { 1027 bool DidDescribe = describeCodeDecl(Out, Callee, 1028 /*ExtendedDescription=*/false, 1029 "Returning from "); 1030 if (!DidDescribe) 1031 Out << "Returning to caller"; 1032 } 1033 1034 assert(callReturn.asLocation().isValid()); 1035 return new PathDiagnosticEventPiece(callReturn, Out.str()); 1036 } 1037 1038 static void compute_path_size(const PathPieces &pieces, unsigned &size) { 1039 for (PathPieces::const_iterator it = pieces.begin(), 1040 et = pieces.end(); it != et; ++it) { 1041 const PathDiagnosticPiece *piece = it->get(); 1042 if (const PathDiagnosticCallPiece *cp = 1043 dyn_cast<PathDiagnosticCallPiece>(piece)) { 1044 compute_path_size(cp->path, size); 1045 } 1046 else 1047 ++size; 1048 } 1049 } 1050 1051 unsigned PathDiagnostic::full_size() { 1052 unsigned size = 0; 1053 compute_path_size(path, size); 1054 return size; 1055 } 1056 1057 //===----------------------------------------------------------------------===// 1058 // FoldingSet profiling methods. 1059 //===----------------------------------------------------------------------===// 1060 1061 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 1062 ID.AddInteger(Range.getBegin().getRawEncoding()); 1063 ID.AddInteger(Range.getEnd().getRawEncoding()); 1064 ID.AddInteger(Loc.getRawEncoding()); 1065 return; 1066 } 1067 1068 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1069 ID.AddInteger((unsigned) getKind()); 1070 ID.AddString(str); 1071 // FIXME: Add profiling support for code hints. 1072 ID.AddInteger((unsigned) getDisplayHint()); 1073 ArrayRef<SourceRange> Ranges = getRanges(); 1074 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); 1075 I != E; ++I) { 1076 ID.AddInteger(I->getBegin().getRawEncoding()); 1077 ID.AddInteger(I->getEnd().getRawEncoding()); 1078 } 1079 } 1080 1081 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1082 PathDiagnosticPiece::Profile(ID); 1083 for (PathPieces::const_iterator it = path.begin(), 1084 et = path.end(); it != et; ++it) { 1085 ID.Add(**it); 1086 } 1087 } 1088 1089 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1090 PathDiagnosticPiece::Profile(ID); 1091 ID.Add(Pos); 1092 } 1093 1094 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1095 PathDiagnosticPiece::Profile(ID); 1096 for (const_iterator I = begin(), E = end(); I != E; ++I) 1097 ID.Add(*I); 1098 } 1099 1100 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1101 PathDiagnosticSpotPiece::Profile(ID); 1102 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 1103 I != E; ++I) 1104 ID.Add(**I); 1105 } 1106 1107 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 1108 ID.Add(getLocation()); 1109 ID.AddString(BugType); 1110 ID.AddString(VerboseDesc); 1111 ID.AddString(Category); 1112 } 1113 1114 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { 1115 Profile(ID); 1116 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) 1117 ID.Add(**I); 1118 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 1119 ID.AddString(*I); 1120 } 1121 1122 StackHintGenerator::~StackHintGenerator() {} 1123 1124 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ 1125 ProgramPoint P = N->getLocation(); 1126 CallExitEnd CExit = P.castAs<CallExitEnd>(); 1127 1128 // FIXME: Use CallEvent to abstract this over all calls. 1129 const Stmt *CallSite = CExit.getCalleeContext()->getCallSite(); 1130 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite); 1131 if (!CE) 1132 return ""; 1133 1134 if (!N) 1135 return getMessageForSymbolNotFound(); 1136 1137 // Check if one of the parameters are set to the interesting symbol. 1138 ProgramStateRef State = N->getState(); 1139 const LocationContext *LCtx = N->getLocationContext(); 1140 unsigned ArgIndex = 0; 1141 for (CallExpr::const_arg_iterator I = CE->arg_begin(), 1142 E = CE->arg_end(); I != E; ++I, ++ArgIndex){ 1143 SVal SV = State->getSVal(*I, LCtx); 1144 1145 // Check if the variable corresponding to the symbol is passed by value. 1146 SymbolRef AS = SV.getAsLocSymbol(); 1147 if (AS == Sym) { 1148 return getMessageForArg(*I, ArgIndex); 1149 } 1150 1151 // Check if the parameter is a pointer to the symbol. 1152 if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) { 1153 SVal PSV = State->getSVal(Reg->getRegion()); 1154 SymbolRef AS = PSV.getAsLocSymbol(); 1155 if (AS == Sym) { 1156 return getMessageForArg(*I, ArgIndex); 1157 } 1158 } 1159 } 1160 1161 // Check if we are returning the interesting symbol. 1162 SVal SV = State->getSVal(CE, LCtx); 1163 SymbolRef RetSym = SV.getAsLocSymbol(); 1164 if (RetSym == Sym) { 1165 return getMessageForReturn(CE); 1166 } 1167 1168 return getMessageForSymbolNotFound(); 1169 } 1170 1171 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE, 1172 unsigned ArgIndex) { 1173 // Printed parameters start at 1, not 0. 1174 ++ArgIndex; 1175 1176 SmallString<200> buf; 1177 llvm::raw_svector_ostream os(buf); 1178 1179 os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex) 1180 << " parameter"; 1181 1182 return os.str(); 1183 } 1184