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