diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core')
33 files changed, 1037 insertions, 904 deletions
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index 9dcf58babd278..7944c7eb00037 100644 --- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -39,7 +39,7 @@ IPAKind AnalyzerOptions::getIPAMode() { // Use the User Mode to set the default IPA value. // Note, we have to add the string to the Config map for the ConfigDumper // checker to function properly. - const char *DefaultIPA = 0; + const char *DefaultIPA = nullptr; UserModeKind HighLevelMode = getUserMode(); if (HighLevelMode == UMK_Shallow) DefaultIPA = "inlining"; @@ -134,8 +134,14 @@ bool AnalyzerOptions::mayInlineTemplateFunctions() { /*Default=*/true); } -bool AnalyzerOptions::mayInlineCXXContainerCtorsAndDtors() { - return getBooleanOption(InlineCXXContainerCtorsAndDtors, +bool AnalyzerOptions::mayInlineCXXAllocator() { + return getBooleanOption(InlineCXXAllocator, + "c++-allocator-inlining", + /*Default=*/false); +} + +bool AnalyzerOptions::mayInlineCXXContainerMethods() { + return getBooleanOption(InlineCXXContainerMethods, "c++-container-inlining", /*Default=*/false); } @@ -183,6 +189,13 @@ bool AnalyzerOptions::shouldReportIssuesInMainSourceFile() { /* Default = */ false); } + +bool AnalyzerOptions::shouldWriteStableReportFilename() { + return getBooleanOption(StableReportFilename, + "stable-report-filename", + /* Default = */ false); +} + int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) { SmallString<10> StrBuf; llvm::raw_svector_ostream OS(StrBuf); diff --git a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp index a6c400f3704d2..0e90566839ca7 100644 --- a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp +++ b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp @@ -173,12 +173,12 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, // FIXME: Expand these checks to include all undefined behavior. if (V2.isSigned() && V2.isNegative()) - return NULL; + return nullptr; uint64_t Amt = V2.getZExtValue(); - if (Amt > V1.getBitWidth()) - return NULL; + if (Amt >= V1.getBitWidth()) + return nullptr; return &getValue( V1.operator<<( (unsigned) Amt )); } @@ -191,12 +191,12 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, // FIXME: Expand these checks to include all undefined behavior. if (V2.isSigned() && V2.isNegative()) - return NULL; + return nullptr; uint64_t Amt = V2.getZExtValue(); - if (Amt > V1.getBitWidth()) - return NULL; + if (Amt >= V1.getBitWidth()) + return nullptr; return &getValue( V1.operator>>( (unsigned) Amt )); } diff --git a/lib/StaticAnalyzer/Core/BlockCounter.cpp b/lib/StaticAnalyzer/Core/BlockCounter.cpp index 74d761e1ecc1d..c1ac03d5ab97d 100644 --- a/lib/StaticAnalyzer/Core/BlockCounter.cpp +++ b/lib/StaticAnalyzer/Core/BlockCounter.cpp @@ -34,8 +34,7 @@ public: } bool operator<(const CountKey &RHS) const { - return (CallSite == RHS.CallSite) ? (BlockID < RHS.BlockID) - : (CallSite < RHS.CallSite); + return std::tie(CallSite, BlockID) < std::tie(RHS.CallSite, RHS.BlockID); } void Profile(llvm::FoldingSetNodeID &ID) const { diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index 1940fa79fda3b..141a48ba10b35 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -12,16 +12,14 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "BugReporter" - #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ParentMap.h" -#include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/ProgramPoint.h" #include "clang/Basic/SourceManager.h" @@ -30,16 +28,18 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/raw_ostream.h" +#include <memory> #include <queue> using namespace clang; using namespace ento; +#define DEBUG_TYPE "BugReporter" + STATISTIC(MaxBugClassSize, "The maximum number of bug reports in the same equivalence class"); STATISTIC(MaxValidBugClassSize, @@ -59,7 +59,7 @@ static const Stmt *GetPreviousStmt(const ExplodedNode *N) { if (const Stmt *S = PathDiagnosticLocation::getStmt(N)) return S; - return 0; + return nullptr; } static inline const Stmt* @@ -83,15 +83,15 @@ eventsDescribeSameCondition(PathDiagnosticEventPiece *X, const void *tagLesser = TrackConstraintBRVisitor::getTag(); if (X->getLocation() != Y->getLocation()) - return 0; - + return nullptr; + if (X->getTag() == tagPreferred && Y->getTag() == tagLesser) return X; if (Y->getTag() == tagPreferred && X->getTag() == tagLesser) return Y; - - return 0; + + return nullptr; } /// An optimization pass over PathPieces that removes redundant diagnostics @@ -125,7 +125,7 @@ static void removeRedundantMsgs(PathPieces &path) { break; if (PathDiagnosticEventPiece *nextEvent = - dyn_cast<PathDiagnosticEventPiece>(path.front().getPtr())) { + dyn_cast<PathDiagnosticEventPiece>(path.front().get())) { PathDiagnosticEventPiece *event = cast<PathDiagnosticEventPiece>(piece); // Check to see if we should keep one of the two pieces. If we @@ -214,8 +214,9 @@ static bool hasImplicitBody(const Decl *D) { /// Recursively scan through a path and make sure that all call pieces have /// valid locations. -static void adjustCallLocations(PathPieces &Pieces, - PathDiagnosticLocation *LastCallLocation = 0) { +static void +adjustCallLocations(PathPieces &Pieces, + PathDiagnosticLocation *LastCallLocation = nullptr) { for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E; ++I) { PathDiagnosticCallPiece *Call = dyn_cast<PathDiagnosticCallPiece>(*I); @@ -265,7 +266,7 @@ static void removeEdgesToDefaultInitializers(PathPieces &Pieces) { I = Pieces.erase(I); continue; } else if (End && isa<CXXDefaultInitExpr>(End)) { - PathPieces::iterator Next = llvm::next(I); + PathPieces::iterator Next = std::next(I); if (Next != E) { if (PathDiagnosticControlFlowPiece *NextCF = dyn_cast<PathDiagnosticControlFlowPiece>(*Next)) { @@ -311,7 +312,7 @@ class NodeMapClosure : public BugReport::NodeResolver { public: NodeMapClosure(InterExplodedGraphMap &m) : M(m) {} - const ExplodedNode *getOriginalNode(const ExplodedNode *N) { + const ExplodedNode *getOriginalNode(const ExplodedNode *N) override { return M.lookup(N); } }; @@ -345,7 +346,7 @@ public: return getParentMap().getParent(S); } - virtual NodeMapClosure& getNodeResolver() { return NMC; } + NodeMapClosure& getNodeResolver() override { return NMC; } PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S); @@ -405,7 +406,7 @@ static const Stmt *getEnclosingParent(const Stmt *S, const ParentMap &PM) { const Stmt *Parent = PM.getParentIgnoreParens(S); if (!Parent) - return 0; + return nullptr; switch (Parent->getStmtClass()) { case Stmt::ForStmtClass: @@ -418,7 +419,7 @@ static const Stmt *getEnclosingParent(const Stmt *S, const ParentMap &PM) { break; } - return 0; + return nullptr; } static PathDiagnosticLocation @@ -564,7 +565,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD, SourceManager& SMgr = PDB.getSourceManager(); const LocationContext *LC = PDB.LC; const ExplodedNode *NextNode = N->pred_empty() - ? NULL : *(N->pred_begin()); + ? nullptr : *(N->pred_begin()); StackDiagVector CallStack; @@ -1263,8 +1264,8 @@ static void reversePropagateIntererstingSymbols(BugReport &R, SVal ChildV = State->getSVal(child, LCtx); R.markInteresting(ChildV); } - break; } + break; } } @@ -1351,11 +1352,11 @@ static const Stmt *getStmtBeforeCond(ParentMap &PM, const Stmt *Term, } N = N->getFirstPred(); } - return 0; + return nullptr; } static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) { - const Stmt *LoopBody = 0; + const Stmt *LoopBody = nullptr; switch (Term->getStmtClass()) { case Stmt::CXXForRangeStmtClass: { const CXXForRangeStmt *FR = cast<CXXForRangeStmt>(Term); @@ -1401,7 +1402,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, StackDiagVector CallStack; InterestingExprs IE; - const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin()); + const ExplodedNode *NextNode = N->pred_empty() ? nullptr : *(N->pred_begin()); while (NextNode) { N = NextNode; NextNode = N->getFirstPred(); @@ -1411,7 +1412,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, if (Optional<PostStmt> PS = P.getAs<PostStmt>()) { if (const Expr *Ex = PS->getStmtAs<Expr>()) reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, - N->getState().getPtr(), Ex, + N->getState().get(), Ex, N->getLocationContext()); } @@ -1419,7 +1420,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, const Stmt *S = CE->getCalleeContext()->getCallSite(); if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) { reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, - N->getState().getPtr(), Ex, + N->getState().get(), Ex, N->getLocationContext()); } @@ -1490,7 +1491,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, const LocationContext *CalleeCtx = PDB.LC; if (CallerCtx != CalleeCtx) { reversePropagateInterestingSymbols(*PDB.getBugReport(), IE, - N->getState().getPtr(), + N->getState().get(), CalleeCtx, CallerCtx); } } @@ -1498,7 +1499,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, // Are we jumping to the head of a loop? Add a special diagnostic. if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) { PathDiagnosticLocation L(Loop, SM, PDB.LC); - const CompoundStmt *CS = NULL; + const CompoundStmt *CS = nullptr; if (const ForStmt *FS = dyn_cast<ForStmt>(Loop)) CS = dyn_cast<CompoundStmt>(FS->getBody()); @@ -1673,7 +1674,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, PathDiagnosticCallPiece *C; if (VisitedEntireCall) { - PathDiagnosticPiece *P = PD.getActivePath().front().getPtr(); + PathDiagnosticPiece *P = PD.getActivePath().front().get(); C = cast<PathDiagnosticCallPiece>(P); } else { const Decl *Caller = CE->getLocationContext()->getDecl(); @@ -1683,11 +1684,11 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, // reset the mapping from active to location context. assert(PD.getActivePath().size() == 1 && PD.getActivePath().front() == C); - LCM[&PD.getActivePath()] = 0; + LCM[&PD.getActivePath()] = nullptr; // Record the location context mapping for the path within // the call. - assert(LCM[&C->path] == 0 || + assert(LCM[&C->path] == nullptr || LCM[&C->path] == CE->getCalleeContext()); LCM[&C->path] = CE->getCalleeContext(); @@ -1727,7 +1728,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, // Propagate the interesting symbols accordingly. if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) { reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, - N->getState().getPtr(), Ex, + N->getState().get(), Ex, N->getLocationContext()); } @@ -1755,7 +1756,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, // interesting symbols correctly. if (const Expr *Ex = PS->getStmtAs<Expr>()) reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, - N->getState().getPtr(), Ex, + N->getState().get(), Ex, N->getLocationContext()); // Add an edge. If this is an ObjCForCollectionStmt do @@ -1778,7 +1779,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, const LocationContext *CalleeCtx = PDB.LC; if (CallerCtx != CalleeCtx) { reversePropagateInterestingSymbols(*PDB.getBugReport(), IE, - N->getState().getPtr(), + N->getState().get(), CalleeCtx, CallerCtx); } } @@ -1786,7 +1787,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, // Are we jumping to the head of a loop? Add a special diagnostic. if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) { PathDiagnosticLocation L(Loop, SM, PDB.LC); - const Stmt *Body = NULL; + const Stmt *Body = nullptr; if (const ForStmt *FS = dyn_cast<ForStmt>(Loop)) Body = FS->getBody(); @@ -1827,7 +1828,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, bool IsInLoopBody = isInLoopBody(PM, getStmtBeforeCond(PM, TermCond, N), Term); - const char *str = 0; + const char *str = nullptr; if (isJumpToFalseBranch(&*BE)) { if (!IsInLoopBody) { @@ -1890,13 +1891,13 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, static const Stmt *getLocStmt(PathDiagnosticLocation L) { if (!L.isValid()) - return 0; + return nullptr; return L.asStmt(); } static const Stmt *getStmtParent(const Stmt *S, const ParentMap &PM) { if (!S) - return 0; + return nullptr; while (true) { S = PM.getParentIgnoreParens(S); @@ -1988,7 +1989,7 @@ static void addContextEdges(PathPieces &pieces, SourceManager &SM, SmallVector<PathDiagnosticLocation, 4> SrcContexts; PathDiagnosticLocation NextSrcContext = SrcLoc; - const Stmt *InnerStmt = 0; + const Stmt *InnerStmt = nullptr; while (NextSrcContext.isValid() && NextSrcContext.asStmt() != InnerStmt) { SrcContexts.push_back(NextSrcContext); InnerStmt = NextSrcContext.asStmt(); @@ -2073,7 +2074,7 @@ static void simplifySimpleBranches(PathPieces &pieces) { if (NextI == E) break; - PathDiagnosticControlFlowPiece *PieceNextI = 0; + PathDiagnosticControlFlowPiece *PieceNextI = nullptr; while (true) { if (NextI == E) @@ -2579,8 +2580,8 @@ const Decl *BugReport::getDeclWithIssue() const { const ExplodedNode *N = getErrorNode(); if (!N) - return 0; - + return nullptr; + const LocationContext *LC = N->getLocationContext(); return LC->getCurrentStackFrame()->getDecl(); } @@ -2703,10 +2704,10 @@ void BugReport::popInterestingSymbolsAndRegions() { const Stmt *BugReport::getStmt() const { if (!ErrorNode) - return 0; + return nullptr; ProgramPoint ProgP = ErrorNode->getLocation(); - const Stmt *S = NULL; + const Stmt *S = nullptr; if (Optional<BlockEntrance> BE = ProgP.getAs<BlockEntrance>()) { CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit(); @@ -2742,12 +2743,10 @@ PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const { assert(!Location.isValid() && "Either Location or ErrorNode should be specified but not both."); return PathDiagnosticLocation::createEndOfPath(ErrorNode, SM); - } else { - assert(Location.isValid()); - return Location; } - return PathDiagnosticLocation(); + assert(Location.isValid()); + return Location; } //===----------------------------------------------------------------------===// @@ -2802,9 +2801,7 @@ void BugReporter::FlushReports() { // EmitBasicReport. // FIXME: There are leaks from checkers that assume that the BugTypes they // create will be destroyed by the BugReporter. - for (llvm::StringMap<BugType*>::iterator - I = StrBugTypes.begin(), E = StrBugTypes.end(); I != E; ++I) - delete I->second; + llvm::DeleteContainerSeconds(StrBugTypes); // Remove all references to the BugType objects. BugTypes = F.getEmptySet(); @@ -2820,7 +2817,7 @@ namespace { class ReportGraph { public: InterExplodedGraphMap BackMap; - OwningPtr<ExplodedGraph> Graph; + std::unique_ptr<ExplodedGraph> Graph; const ExplodedNode *ErrorNode; size_t Index; }; @@ -2835,7 +2832,7 @@ class TrimmedGraph { typedef std::pair<const ExplodedNode *, size_t> NodeIndexPair; SmallVector<NodeIndexPair, 32> ReportNodes; - OwningPtr<ExplodedGraph> G; + std::unique_ptr<ExplodedGraph> G; /// A helper class for sorting ExplodedNodes by priority. template <bool Descending> @@ -2906,7 +2903,7 @@ TrimmedGraph::TrimmedGraph(const ExplodedGraph *OriginalGraph, PriorityMapTy::iterator PriorityEntry; bool IsNew; - llvm::tie(PriorityEntry, IsNew) = + std::tie(PriorityEntry, IsNew) = PriorityMap.insert(std::make_pair(Node, Priority)); ++Priority; @@ -2935,7 +2932,7 @@ bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) { return false; const ExplodedNode *OrigN; - llvm::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val(); + std::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val(); assert(PriorityMap.find(OrigN) != PriorityMap.end() && "error node not accessible from root"); @@ -2947,7 +2944,7 @@ bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) { // Now walk from the error node up the BFS path, always taking the // predeccessor with the lowest number. - ExplodedNode *Succ = 0; + ExplodedNode *Succ = nullptr; while (true) { // Create the equivalent node in the new graph with the same state // and location. @@ -2998,7 +2995,7 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) { for (PathPieces::const_iterator I = path.begin(), E = path.end(); I!=E; ++I) { - PathDiagnosticPiece *piece = I->getPtr(); + PathDiagnosticPiece *piece = I->get(); // Recursively compact calls. if (PathDiagnosticCallPiece *call=dyn_cast<PathDiagnosticCallPiece>(piece)){ @@ -3095,7 +3092,7 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD, } else { // Keep the errorNodes list in sync with the bugReports list. HasInvalid = true; - errorNodes.push_back(0); + errorNodes.push_back(nullptr); } } @@ -3153,21 +3150,21 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD, // Generate the very last diagnostic piece - the piece is visible before // the trace is expanded. - PathDiagnosticPiece *LastPiece = 0; + std::unique_ptr<PathDiagnosticPiece> LastPiece; for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end(); I != E; ++I) { if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) { assert (!LastPiece && "There can only be one final piece in a diagnostic."); - LastPiece = Piece; + LastPiece.reset(Piece); } } if (ActiveScheme != PathDiagnosticConsumer::None) { if (!LastPiece) - LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R); + LastPiece.reset(BugReporterVisitor::getDefaultEndPath(PDB, N, *R)); assert(LastPiece); - PD.setEndOfPath(LastPiece); + PD.setEndOfPath(LastPiece.release()); } // Make sure we get a clean location context map so we don't @@ -3247,6 +3244,9 @@ void BugReporter::Register(BugType *BT) { } void BugReporter::emitReport(BugReport* R) { + // To guarantee memory release. + std::unique_ptr<BugReport> UniqueR(R); + // Defensive checking: throw the bug away if it comes from a BodyFarm- // generated body. We do this very early because report processing relies // on the report's location being valid. @@ -3277,12 +3277,12 @@ void BugReporter::emitReport(BugReport* R) { BugReportEquivClass* EQ = EQClasses.FindNodeOrInsertPos(ID, InsertPos); if (!EQ) { - EQ = new BugReportEquivClass(R); + EQ = new BugReportEquivClass(UniqueR.release()); EQClasses.InsertNode(EQ, InsertPos); EQClassesVector.push_back(EQ); } else - EQ->AddReport(R); + EQ->AddReport(UniqueR.release()); } @@ -3329,7 +3329,7 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ, // DFS traversal of the ExplodedGraph to find a non-sink node. We could write // this as a recursive function, but we don't want to risk blowing out the // stack for very long paths. - BugReport *exampleReport = 0; + BugReport *exampleReport = nullptr; for (; I != E; ++I) { const ExplodedNode *errorNode = I->getErrorNode(); @@ -3403,10 +3403,8 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { SmallVector<BugReport*, 10> bugReports; BugReport *exampleReport = FindReportInEquivalenceClass(EQ, bugReports); if (exampleReport) { - const PathDiagnosticConsumers &C = getPathDiagnosticConsumers(); - for (PathDiagnosticConsumers::const_iterator I=C.begin(), - E=C.end(); I != E; ++I) { - FlushReport(exampleReport, **I, bugReports); + for (PathDiagnosticConsumer *PDC : getPathDiagnosticConsumers()) { + FlushReport(exampleReport, *PDC, bugReports); } } } @@ -3419,14 +3417,13 @@ void BugReporter::FlushReport(BugReport *exampleReport, // Probably doesn't make a difference in practice. BugType& BT = exampleReport->getBugType(); - OwningPtr<PathDiagnostic> - D(new PathDiagnostic(exampleReport->getDeclWithIssue(), - exampleReport->getBugType().getName(), - exampleReport->getDescription(), - exampleReport->getShortDescription(/*Fallback=*/false), - BT.getCategory(), - exampleReport->getUniqueingLocation(), - exampleReport->getUniqueingDecl())); + std::unique_ptr<PathDiagnostic> D(new PathDiagnostic( + exampleReport->getBugType().getCheckName(), + exampleReport->getDeclWithIssue(), exampleReport->getBugType().getName(), + exampleReport->getDescription(), + exampleReport->getShortDescription(/*Fallback=*/false), BT.getCategory(), + exampleReport->getUniqueingLocation(), + exampleReport->getUniqueingDecl())); MaxBugClassSize = std::max(bugReports.size(), static_cast<size_t>(MaxBugClassSize)); @@ -3455,7 +3452,7 @@ void BugReporter::FlushReport(BugReport *exampleReport, PathDiagnosticPiece *piece = new PathDiagnosticEventPiece(L, exampleReport->getDescription()); BugReport::ranges_iterator Beg, End; - llvm::tie(Beg, End) = exampleReport->getRanges(); + std::tie(Beg, End) = exampleReport->getRanges(); for ( ; Beg != End; ++Beg) piece->addRange(*Beg); D->setEndOfPath(piece); @@ -3468,17 +3465,25 @@ void BugReporter::FlushReport(BugReport *exampleReport, D->addMeta(*i); } - PD.HandlePathDiagnostic(D.take()); + PD.HandlePathDiagnostic(D.release()); } void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, - StringRef name, - StringRef category, + const CheckerBase *Checker, + StringRef Name, StringRef Category, + StringRef Str, PathDiagnosticLocation Loc, + ArrayRef<SourceRange> Ranges) { + EmitBasicReport(DeclWithIssue, Checker->getCheckName(), Name, Category, Str, + Loc, Ranges); +} +void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, + CheckName CheckName, + StringRef name, StringRef category, StringRef str, PathDiagnosticLocation Loc, ArrayRef<SourceRange> Ranges) { // 'BT' is owned by BugReporter. - BugType *BT = getBugTypeForName(name, category); + BugType *BT = getBugTypeForName(CheckName, name, category); BugReport *R = new BugReport(*BT, str, Loc); R->setDeclWithIssue(DeclWithIssue); for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); @@ -3487,22 +3492,22 @@ void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, emitReport(R); } -BugType *BugReporter::getBugTypeForName(StringRef name, +BugType *BugReporter::getBugTypeForName(CheckName CheckName, StringRef name, StringRef category) { SmallString<136> fullDesc; - llvm::raw_svector_ostream(fullDesc) << name << ":" << category; + llvm::raw_svector_ostream(fullDesc) << CheckName.getName() << ":" << name + << ":" << category; llvm::StringMapEntry<BugType *> & entry = StrBugTypes.GetOrCreateValue(fullDesc); BugType *BT = entry.getValue(); if (!BT) { - BT = new BugType(name, category); + BT = new BugType(CheckName, name, category); entry.setValue(BT); } return BT; } - -void PathPieces::dump() const { +LLVM_DUMP_METHOD void PathPieces::dump() const { unsigned index = 0; for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { llvm::errs() << "[" << index++ << "] "; diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index e1a92b30c6be6..0503acec051a0 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -45,7 +45,7 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) { // a[0], p->f, *p const Expr *E = dyn_cast<Expr>(S); if (!E) - return 0; + return nullptr; E = E->IgnoreParenCasts(); while (true) { @@ -79,21 +79,21 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) { break; } - return NULL; + return nullptr; } const Stmt *bugreporter::GetDenomExpr(const ExplodedNode *N) { const Stmt *S = N->getLocationAs<PreStmt>()->getStmt(); if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S)) return BE->getRHS(); - return NULL; + return nullptr; } const Stmt *bugreporter::GetRetValExpr(const ExplodedNode *N) { const Stmt *S = N->getLocationAs<PostStmt>()->getStmt(); if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) return RS->getRetValue(); - return NULL; + return nullptr; } //===----------------------------------------------------------------------===// @@ -104,7 +104,7 @@ PathDiagnosticPiece* BugReporterVisitor::getEndPath(BugReporterContext &BRC, const ExplodedNode *EndPathNode, BugReport &BR) { - return 0; + return nullptr; } PathDiagnosticPiece* @@ -115,7 +115,7 @@ BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC, PathDiagnosticLocation::createEndOfPath(EndPathNode,BRC.getSourceManager()); BugReport::ranges_iterator Beg, End; - llvm::tie(Beg, End) = BR.getRanges(); + std::tie(Beg, End) = BR.getRanges(); // Only add the statement itself as a range if we didn't specify any // special ranges for this report. @@ -156,7 +156,7 @@ public: return static_cast<void *>(&Tag); } - virtual void Profile(llvm::FoldingSetNodeID &ID) const { + void Profile(llvm::FoldingSetNodeID &ID) const override { ID.AddPointer(ReturnVisitor::getTag()); ID.AddPointer(StackFrame); ID.AddBoolean(EnableNullFPSuppression); @@ -237,22 +237,22 @@ public: BugReport &BR) { // Only print a message at the interesting return statement. if (N->getLocationContext() != StackFrame) - return 0; + return nullptr; Optional<StmtPoint> SP = N->getLocationAs<StmtPoint>(); if (!SP) - return 0; + return nullptr; const ReturnStmt *Ret = dyn_cast<ReturnStmt>(SP->getStmt()); if (!Ret) - return 0; + return nullptr; // Okay, we're at the right return statement, but do we have the return // value available? ProgramStateRef State = N->getState(); SVal V = State->getSVal(Ret, StackFrame); if (V.isUnknownOrUndef()) - return 0; + return nullptr; // Don't print any more notes after this one. Mode = Satisfied; @@ -273,7 +273,7 @@ public: // Ignore aggregate rvalues. if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::CompoundVal>()) - return 0; + return nullptr; RetE = RetE->IgnoreParenCasts(); @@ -283,7 +283,7 @@ public: BR.markInteresting(V); ReturnVisitor::addVisitorIfNecessary(N, RetE, BR, EnableNullFPSuppression); - return 0; + return nullptr; } // If we're returning 0, we should track where that 0 came from. @@ -343,10 +343,10 @@ public: // Are we at the entry node for this call? Optional<CallEnter> CE = N->getLocationAs<CallEnter>(); if (!CE) - return 0; + return nullptr; if (CE->getCalleeContext() != StackFrame) - return 0; + return nullptr; Mode = Satisfied; @@ -380,20 +380,20 @@ public: // (We will still look at the other arguments, though.) } - return 0; + return nullptr; } PathDiagnosticPiece *VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, - BugReport &BR) { + BugReport &BR) override { switch (Mode) { case Initial: return visitNodeInitial(N, PrevN, BRC, BR); case MaybeUnsuppress: return visitNodeMaybeUnsuppress(N, PrevN, BRC, BR); case Satisfied: - return 0; + return nullptr; } llvm_unreachable("Invalid visit mode!"); @@ -401,10 +401,10 @@ public: PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, const ExplodedNode *N, - BugReport &BR) { + BugReport &BR) override { if (EnableNullFPSuppression) BR.markInvalid(ReturnVisitor::getTag(), StackFrame); - return 0; + return nullptr; } }; } // end anonymous namespace @@ -453,10 +453,10 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, BugReport &BR) { if (Satisfied) - return NULL; + return nullptr; - const ExplodedNode *StoreSite = 0; - const Expr *InitE = 0; + const ExplodedNode *StoreSite = nullptr; + const Expr *InitE = nullptr; bool IsParam = false; // First see if we reached the declaration of the region. @@ -484,12 +484,12 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, // the same binding was re-assigned here. if (!StoreSite) { if (Succ->getState()->getSVal(R) != V) - return NULL; + return nullptr; if (Pred->getState()->getSVal(R) == V) { Optional<PostStore> PS = Succ->getLocationAs<PostStore>(); if (!PS || PS->getLocationValue() != R) - return NULL; + return nullptr; } StoreSite = Succ; @@ -526,7 +526,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, } if (!StoreSite) - return NULL; + return nullptr; Satisfied = true; // If we have an expression that provided the value, try to track where it @@ -550,7 +550,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, if (Optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) { const Stmt *S = PS->getStmt(); - const char *action = 0; + const char *action = nullptr; const DeclStmt *DS = dyn_cast<DeclStmt>(S); const VarRegion *VR = dyn_cast<VarRegion>(R); @@ -703,7 +703,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, L = PathDiagnosticLocation::create(P, BRC.getSourceManager()); if (!L.isValid() || !L.asLocation().isValid()) - return NULL; + return nullptr; return new PathDiagnosticEventPiece(L, os.str()); } @@ -724,7 +724,7 @@ const char *TrackConstraintBRVisitor::getTag() { bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const { if (IsZeroCheck) return N->getState()->isNull(Constraint).isUnderconstrained(); - return N->getState()->assume(Constraint, !Assumption); + return (bool)N->getState()->assume(Constraint, !Assumption); } PathDiagnosticPiece * @@ -733,7 +733,7 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC, BugReport &BR) { if (IsSatisfied) - return NULL; + return nullptr; // Start tracking after we see the first state in which the value is // constrained. @@ -741,7 +741,7 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, if (!isUnderconstrained(N)) IsTrackingTurnedOn = true; if (!IsTrackingTurnedOn) - return 0; + return nullptr; // Check if in the previous state it was feasible for this constraint // to *not* be true. @@ -765,21 +765,21 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, } if (os.str().empty()) - return NULL; + return nullptr; // Construct a new PathDiagnosticPiece. ProgramPoint P = N->getLocation(); PathDiagnosticLocation L = PathDiagnosticLocation::create(P, BRC.getSourceManager()); if (!L.isValid()) - return NULL; - + return nullptr; + PathDiagnosticEventPiece *X = new PathDiagnosticEventPiece(L, os.str()); X->setTag(getTag()); return X; } - return NULL; + return nullptr; } SuppressInlineDefensiveChecksVisitor:: @@ -813,14 +813,14 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, BugReport &BR) { if (IsSatisfied) - return 0; + return nullptr; // Start tracking after we see the first state in which the value is null. if (!IsTrackingTurnedOn) if (Succ->getState()->isNull(V).isConstrainedTrue()) IsTrackingTurnedOn = true; if (!IsTrackingTurnedOn) - return 0; + return nullptr; // Check if in the previous state it was feasible for this value // to *not* be null. @@ -835,7 +835,7 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ, if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) BR.markInvalid("Suppress IDC", CurLC); } - return 0; + return nullptr; } static const MemRegion *getLocationRegionIfReference(const Expr *E, @@ -843,7 +843,7 @@ static const MemRegion *getLocationRegionIfReference(const Expr *E, if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) { if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { if (!VD->getType()->isReferenceType()) - return 0; + return nullptr; ProgramStateManager &StateMgr = N->getState()->getStateManager(); MemRegionManager &MRMgr = StateMgr.getRegionManager(); return MRMgr.getVarRegion(VD, N->getLocationContext()); @@ -856,7 +856,7 @@ static const MemRegion *getLocationRegionIfReference(const Expr *E, // Wrapper w = { *(int *)0 }; // w.ref = 1; - return 0; + return nullptr; } static const Expr *peelOffOuterExpr(const Expr *Ex, @@ -869,7 +869,7 @@ static const Expr *peelOffOuterExpr(const Expr *Ex, // Peel off the ternary operator. if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(Ex)) { - // Find a node where the branching occured and find out which branch + // Find a node where the branching occurred and find out which branch // we took (true/false) by looking at the ExplodedGraph. const ExplodedNode *NI = N; do { @@ -906,7 +906,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, S = PeeledEx; } - const Expr *Inner = 0; + const Expr *Inner = nullptr; if (const Expr *Ex = dyn_cast<Expr>(S)) { Ex = Ex->IgnoreParenCasts(); if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex)) @@ -948,7 +948,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, // See if the expression we're interested refers to a variable. // If so, we can track both its contents and constraints on its value. if (Inner && ExplodedGraph::isInterestingLValueExpr(Inner)) { - const MemRegion *R = 0; + const MemRegion *R = nullptr; // Find the ExplodedNode where the lvalue (the value of 'Ex') // was computed. We need this for getting the location value. @@ -1060,14 +1060,14 @@ const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S, const ExplodedNode *N) { const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S); if (!ME) - return 0; + return nullptr; if (const Expr *Receiver = ME->getInstanceReceiver()) { ProgramStateRef state = N->getState(); SVal V = state->getSVal(Receiver, N->getLocationContext()); if (state->isNull(V).isConstrainedTrue()) return Receiver; } - return 0; + return nullptr; } PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, @@ -1076,18 +1076,20 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, BugReport &BR) { Optional<PreStmt> P = N->getLocationAs<PreStmt>(); if (!P) - return 0; + return nullptr; const Stmt *S = P->getStmt(); const Expr *Receiver = getNilReceiver(S, N); if (!Receiver) - return 0; + return nullptr; llvm::SmallString<256> Buf; llvm::raw_svector_ostream OS(Buf); if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) { - OS << "'" << ME->getSelector().getAsString() << "' not called"; + OS << "'"; + ME->getSelector().print(OS); + OS << "' not called"; } else { OS << "No method is called"; @@ -1179,15 +1181,15 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, // were generated by the analyzer engine proper, not checkers. if (CurrentState->getGDM().getRoot() == PrevState->getGDM().getRoot()) - return 0; - + return nullptr; + // If an assumption was made on a branch, it should be caught // here by looking at the state transition. if (Optional<BlockEdge> BE = progPoint.getAs<BlockEdge>()) { const CFGBlock *srcBlk = BE->getSrc(); if (const Stmt *term = srcBlk->getTerminator()) return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC); - return 0; + return nullptr; } if (Optional<PostStmt> PS = progPoint.getAs<PostStmt>()) { @@ -1204,11 +1206,11 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, if (tag == tags.second) return VisitTrueTest(cast<Expr>(PS->getStmt()), false, BRC, BR, N); - - return 0; + + return nullptr; } - - return 0; + + return nullptr; } PathDiagnosticPiece * @@ -1218,11 +1220,11 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term, const CFGBlock *dstBlk, BugReport &R, BugReporterContext &BRC) { - const Expr *Cond = 0; - + const Expr *Cond = nullptr; + switch (Term->getStmtClass()) { default: - return 0; + return nullptr; case Stmt::IfStmtClass: Cond = cast<IfStmt>(Term)->getCond(); break; @@ -1250,7 +1252,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, Ex = Ex->IgnoreParenCasts(); switch (Ex->getStmtClass()) { default: - return 0; + return nullptr; case Stmt::BinaryOperatorClass: return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC, R, N); @@ -1264,7 +1266,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, Ex = UO->getSubExpr(); continue; } - return 0; + return nullptr; } } } @@ -1283,13 +1285,13 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex, raw_ostream &Out, if (quotes) { Out << '\''; const LocationContext *LCtx = N->getLocationContext(); - const ProgramState *state = N->getState().getPtr(); + const ProgramState *state = N->getState().get(); if (const MemRegion *R = state->getLValue(cast<VarDecl>(DR->getDecl()), LCtx).getAsRegion()) { if (report.isInteresting(R)) prunable = false; else { - const ProgramState *state = N->getState().getPtr(); + const ProgramState *state = N->getState().get(); SVal V = state->getSVal(R); if (report.isInteresting(V)) prunable = false; @@ -1359,8 +1361,8 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, // both the LHS and RHS. if (LhsString.empty() || RhsString.empty() || !BinaryOperator::isComparisonOp(Op)) - return 0; - + return nullptr; + // Should we invert the strings if the LHS is not a variable name? SmallString<256> buf; llvm::raw_svector_ostream Out(buf); @@ -1385,7 +1387,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, case BO_LE: Op = BO_GT; break; case BO_GE: Op = BO_LT; break; default: - return 0; + return nullptr; } switch (Op) { @@ -1435,7 +1437,7 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, else if (Ty->isIntegralOrEnumerationType()) Out << (tookTrue ? "non-zero" : "zero"); else - return 0; + return nullptr; const LocationContext *LCtx = N->getLocationContext(); PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx); @@ -1444,7 +1446,7 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(CondVarExpr)) { if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { - const ProgramState *state = N->getState().getPtr(); + const ProgramState *state = N->getState().get(); if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { if (report.isInteresting(R)) event->setPrunable(false); @@ -1465,8 +1467,8 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); if (!VD) - return 0; - + return nullptr; + SmallString<256> Buf; llvm::raw_svector_ostream Out(Buf); @@ -1481,14 +1483,14 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, else if (VDTy->isScalarType()) Out << (tookTrue ? "not equal to 0" : "0"); else - return 0; - + return nullptr; + const LocationContext *LCtx = N->getLocationContext(); PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); PathDiagnosticEventPiece *event = new PathDiagnosticEventPiece(Loc, Out.str()); - const ProgramState *state = N->getState().getPtr(); + const ProgramState *state = N->getState().get(); if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { if (report.isInteresting(R)) event->setPrunable(false); @@ -1512,7 +1514,7 @@ static bool isInStdNamespace(const Decl *D) { while (const NamespaceDecl *Parent = dyn_cast<NamespaceDecl>(ND->getParent())) ND = Parent; - return ND->getName() == "std"; + return ND->isStdNamespace(); } @@ -1532,8 +1534,8 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, // Note that this will not help for any other data structure libraries, like // TR1, Boost, or llvm/ADT. if (Options.shouldSuppressFromCXXStandardLibrary()) { - BR.markInvalid(getTag(), 0); - return 0; + BR.markInvalid(getTag(), nullptr); + return nullptr; } else { // If the the complete 'std' suppression is not enabled, suppress reports @@ -1545,8 +1547,8 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { const CXXRecordDecl *CD = MD->getParent(); if (CD->getName() == "list") { - BR.markInvalid(getTag(), 0); - return 0; + BR.markInvalid(getTag(), nullptr); + return nullptr; } } @@ -1556,25 +1558,18 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, // std::u16string s; s += u'a'; // because we cannot reason about the internal invariants of the // datastructure. - const LocationContext *LCtx = N->getLocationContext(); - do { + for (const LocationContext *LCtx = N->getLocationContext(); LCtx; + LCtx = LCtx->getParent()) { const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl()); if (!MD) - break; + continue; const CXXRecordDecl *CD = MD->getParent(); if (CD->getName() == "basic_string") { - BR.markInvalid(getTag(), 0); - return 0; - } else if (CD->getName().find("allocator") == StringRef::npos) { - // Only keep searching if the current method is in a class with the - // word "allocator" in its name, e.g. std::allocator or - // allocator_traits. - break; + BR.markInvalid(getTag(), nullptr); + return nullptr; } - - LCtx = LCtx->getParent(); - } while (LCtx); + } } } @@ -1585,12 +1580,12 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, while (Loc.isMacroID()) { Loc = Loc.getSpellingLoc(); if (SM.getFilename(Loc).endswith("sys/queue.h")) { - BR.markInvalid(getTag(), 0); - return 0; + BR.markInvalid(getTag(), nullptr); + return nullptr; } } - return 0; + return nullptr; } PathDiagnosticPiece * @@ -1605,14 +1600,16 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, // We are only interested in visiting CallEnter nodes. Optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>(); if (!CEnter) - return 0; + return nullptr; // Check if one of the arguments is the region the visitor is tracking. CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager(); CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State); unsigned Idx = 0; - for (CallEvent::param_iterator I = Call->param_begin(), - E = Call->param_end(); I != E; ++I, ++Idx) { + ArrayRef<ParmVarDecl*> parms = Call->parameters(); + + for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end(); + I != E; ++I, ++Idx) { const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion(); // Are we tracking the argument or its subregion? @@ -1639,8 +1636,8 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, SVal BoundVal = State->getSVal(R); if (BoundVal.isUndef() || BoundVal.isZeroConstant()) { BR.markInteresting(CEnter->getCalleeContext()); - return 0; + return nullptr; } } - return 0; + return nullptr; } diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt index 013f8a56b4330..59a6b6fbc5951 100644 --- a/lib/StaticAnalyzer/Core/CMakeLists.txt +++ b/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -39,21 +39,11 @@ add_clang_library(clangStaticAnalyzerCore Store.cpp SubEngine.cpp SymbolManager.cpp - ) - -add_dependencies(clangStaticAnalyzerCore - ClangAttrClasses - ClangAttrList - ClangCommentNodes - ClangDeclNodes - ClangDiagnosticCommon - ClangStmtNodes - ) -target_link_libraries(clangStaticAnalyzerCore + LINK_LIBS + clangAST + clangAnalysis clangBasic clangLex - clangAST - clangFrontend - clangRewriteCore + clangRewrite ) diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index a3b34f4790a97..7e0670a06608a 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -68,8 +68,7 @@ static bool isCallbackArg(SVal V, QualType T) { if (const RecordType *RT = T->getAsStructureType()) { const RecordDecl *RD = RT->getDecl(); - for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); - I != E; ++I) { + for (const auto *I : RD->fields()) { QualType FieldT = I->getType(); if (FieldT->isBlockPointerType() || FieldT->isFunctionPointerType()) return true; @@ -140,6 +139,11 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, ProgramStateRef Orig) const { ProgramStateRef Result = (Orig ? Orig : getState()); + // Don't invalidate anything if the callee is marked pure/const. + if (const Decl *callee = getDecl()) + if (callee->hasAttr<PureAttr>() || callee->hasAttr<ConstAttr>()) + return Result; + SmallVector<SVal, 8> ValuesToInvalidate; RegionAndSymbolInvalidationTraits ETraits; @@ -168,7 +172,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(), BlockCount, getLocationContext(), /*CausedByPointerEscape*/ true, - /*Symbols=*/0, this, &ETraits); + /*Symbols=*/nullptr, this, &ETraits); } ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit, @@ -209,14 +213,12 @@ SVal CallEvent::getReturnValue() const { return getSVal(E); } -void CallEvent::dump() const { - dump(llvm::errs()); -} +LLVM_DUMP_METHOD void CallEvent::dump() const { dump(llvm::errs()); } void CallEvent::dump(raw_ostream &Out) const { ASTContext &Ctx = getState()->getStateManager().getContext(); if (const Expr *E = getOriginExpr()) { - E->printPretty(Out, 0, Ctx.getPrintingPolicy()); + E->printPretty(Out, nullptr, Ctx.getPrintingPolicy()); Out << "\n"; return; } @@ -241,9 +243,9 @@ bool CallEvent::isCallStmt(const Stmt *S) { QualType CallEvent::getDeclaredResultType(const Decl *D) { assert(D); if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) - return FD->getResultType(); + return FD->getReturnType(); if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D)) - return MD->getResultType(); + return MD->getReturnType(); if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { // Blocks are difficult because the return type may not be stored in the // BlockDecl itself. The AST should probably be enhanced, but for now we @@ -256,7 +258,7 @@ QualType CallEvent::getDeclaredResultType(const Decl *D) { if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten()) { QualType Ty = TSI->getType(); if (const FunctionType *FT = Ty->getAs<FunctionType>()) - Ty = FT->getResultType(); + Ty = FT->getReturnType(); if (!Ty->isDependentType()) return Ty; } @@ -284,14 +286,14 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx, CallEvent::BindingsTy &Bindings, SValBuilder &SVB, const CallEvent &Call, - CallEvent::param_iterator I, - CallEvent::param_iterator E) { + ArrayRef<ParmVarDecl*> parameters) { MemRegionManager &MRMgr = SVB.getRegionManager(); // If the function has fewer parameters than the call has arguments, we simply // do not bind any values to them. unsigned NumArgs = Call.getNumArgs(); unsigned Idx = 0; + ArrayRef<ParmVarDecl*>::iterator I = parameters.begin(), E = parameters.end(); for (; I != E && Idx < NumArgs; ++I, ++Idx) { const ParmVarDecl *ParamDecl = *I; assert(ParamDecl && "Formal parameter has no decl?"); @@ -306,21 +308,11 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx, // FIXME: Variadic arguments are not handled at all right now. } - -CallEvent::param_iterator AnyFunctionCall::param_begin() const { - const FunctionDecl *D = getDecl(); - if (!D) - return 0; - - return D->param_begin(); -} - -CallEvent::param_iterator AnyFunctionCall::param_end() const { +ArrayRef<ParmVarDecl*> AnyFunctionCall::parameters() const { const FunctionDecl *D = getDecl(); if (!D) - return 0; - - return D->param_end(); + return None; + return D->parameters(); } void AnyFunctionCall::getInitialStackFrameContents( @@ -329,7 +321,7 @@ void AnyFunctionCall::getInitialStackFrameContents( const FunctionDecl *D = cast<FunctionDecl>(CalleeCtx->getDecl()); SValBuilder &SVB = getState()->getStateManager().getSValBuilder(); addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this, - D->param_begin(), D->param_end()); + D->parameters()); } bool AnyFunctionCall::argumentsMayEscape() const { @@ -389,7 +381,7 @@ bool AnyFunctionCall::argumentsMayEscape() const { } -const FunctionDecl *SimpleCall::getDecl() const { +const FunctionDecl *SimpleFunctionCall::getDecl() const { const FunctionDecl *D = getOriginExpr()->getDirectCallee(); if (D) return D; @@ -484,7 +476,7 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { // that ExprEngine can decide what to do with it. if (DynType.canBeASubClass()) return RuntimeDefinition(Definition, R->StripCasts()); - return RuntimeDefinition(Definition, /*DispatchRegion=*/0); + return RuntimeDefinition(Definition, /*DispatchRegion=*/nullptr); } void CXXInstanceCall::getInitialStackFrameContents( @@ -550,18 +542,11 @@ const BlockDataRegion *BlockCall::getBlockRegion() const { return dyn_cast_or_null<BlockDataRegion>(DataReg); } -CallEvent::param_iterator BlockCall::param_begin() const { - const BlockDecl *D = getBlockDecl(); +ArrayRef<ParmVarDecl*> BlockCall::parameters() const { + const BlockDecl *D = getDecl(); if (!D) - return 0; - return D->param_begin(); -} - -CallEvent::param_iterator BlockCall::param_end() const { - const BlockDecl *D = getBlockDecl(); - if (!D) - return 0; - return D->param_end(); + return nullptr; + return D->parameters(); } void BlockCall::getExtraInvalidatedValues(ValueList &Values) const { @@ -575,7 +560,7 @@ void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx, const BlockDecl *D = cast<BlockDecl>(CalleeCtx->getDecl()); SValBuilder &SVB = getState()->getStateManager().getSValBuilder(); addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this, - D->param_begin(), D->param_end()); + D->parameters()); } @@ -604,8 +589,6 @@ void CXXConstructorCall::getInitialStackFrameContents( } } - - SVal CXXDestructorCall::getCXXThisVal() const { if (Data) return loc::MemRegionVal(DtorDataTy::getFromOpaqueValue(Data).getPointer()); @@ -621,21 +604,11 @@ RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const { return CXXInstanceCall::getRuntimeDefinition(); } - -CallEvent::param_iterator ObjCMethodCall::param_begin() const { +ArrayRef<ParmVarDecl*> ObjCMethodCall::parameters() const { const ObjCMethodDecl *D = getDecl(); if (!D) - return 0; - - return D->param_begin(); -} - -CallEvent::param_iterator ObjCMethodCall::param_end() const { - const ObjCMethodDecl *D = getDecl(); - if (!D) - return 0; - - return D->param_end(); + return ArrayRef<ParmVarDecl*>(); + return D->parameters(); } void @@ -694,13 +667,13 @@ SourceRange ObjCMethodCall::getSourceRange() const { typedef llvm::PointerIntPair<const PseudoObjectExpr *, 2> ObjCMessageDataTy; const PseudoObjectExpr *ObjCMethodCall::getContainingPseudoObjectExpr() const { - assert(Data != 0 && "Lazy lookup not yet performed."); + assert(Data && "Lazy lookup not yet performed."); assert(getMessageKind() != OCM_Message && "Explicit message send."); return ObjCMessageDataTy::getFromOpaqueValue(Data).getPointer(); } ObjCMessageKind ObjCMethodCall::getMessageKind() const { - if (Data == 0) { + if (!Data) { // Find the parent, ignoring implicit casts. ParentMap &PM = getLocationContext()->getParentMap(); @@ -738,7 +711,7 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const { } const_cast<ObjCMethodCall *>(this)->Data - = ObjCMessageDataTy(0, 1).getOpaqueValue(); + = ObjCMessageDataTy(nullptr, 1).getOpaqueValue(); assert(getMessageKind() == OCM_Message); return OCM_Message; } @@ -774,7 +747,7 @@ bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl, // Find the first declaration in the class hierarchy that declares // the selector. - ObjCMethodDecl *D = 0; + ObjCMethodDecl *D = nullptr; while (true) { D = IDecl->lookupMethod(Sel, true); @@ -813,10 +786,10 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { if (E->isInstanceMessage()) { // Find the the receiver type. - const ObjCObjectPointerType *ReceiverT = 0; + const ObjCObjectPointerType *ReceiverT = nullptr; bool CanBeSubClassed = false; QualType SupersType = E->getSuperType(); - const MemRegion *Receiver = 0; + const MemRegion *Receiver = nullptr; if (!SupersType.isNull()) { // Super always means the type of immediate predecessor to the method @@ -865,14 +838,22 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { Optional<const ObjCMethodDecl *> &Val = PMC[std::make_pair(IDecl, Sel)]; // Query lookupPrivateMethod() if the cache does not hit. - if (!Val.hasValue()) + if (!Val.hasValue()) { Val = IDecl->lookupPrivateMethod(Sel); + // If the method is a property accessor, we should try to "inline" it + // even if we don't actually have an implementation. + if (!*Val) + if (const ObjCMethodDecl *CompileTimeMD = E->getMethodDecl()) + if (CompileTimeMD->isPropertyAccessor()) + Val = IDecl->lookupInstanceMethod(Sel); + } + const ObjCMethodDecl *MD = Val.getValue(); if (CanBeSubClassed) return RuntimeDefinition(MD, Receiver); else - return RuntimeDefinition(MD, 0); + return RuntimeDefinition(MD, nullptr); } } else { @@ -888,13 +869,24 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { return RuntimeDefinition(); } +bool ObjCMethodCall::argumentsMayEscape() const { + if (isInSystemHeader() && !isInstanceMessage()) { + Selector Sel = getSelector(); + if (Sel.getNumArgs() == 1 && + Sel.getIdentifierInfoForSlot(0)->isStr("valueWithPointer")) + return true; + } + + return CallEvent::argumentsMayEscape(); +} + void ObjCMethodCall::getInitialStackFrameContents( const StackFrameContext *CalleeCtx, BindingsTy &Bindings) const { const ObjCMethodDecl *D = cast<ObjCMethodDecl>(CalleeCtx->getDecl()); SValBuilder &SVB = getState()->getStateManager().getSValBuilder(); addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this, - D->param_begin(), D->param_end()); + D->parameters()); SVal SelfVal = getReceiverSVal(); if (!SelfVal.isUnknown()) { @@ -923,7 +915,7 @@ CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State, // Otherwise, it's a normal function call, static member function call, or // something we can't reason about. - return create<FunctionCall>(CE, State, LCtx); + return create<SimpleFunctionCall>(CE, State, LCtx); } diff --git a/lib/StaticAnalyzer/Core/Checker.cpp b/lib/StaticAnalyzer/Core/Checker.cpp index 07e0aac2d4298..1a3965acaf421 100644 --- a/lib/StaticAnalyzer/Core/Checker.cpp +++ b/lib/StaticAnalyzer/Core/Checker.cpp @@ -18,8 +18,23 @@ using namespace clang; using namespace ento; StringRef CheckerBase::getTagDescription() const { - // FIXME: We want to return the package + name of the checker here. - return "A Checker"; + return getCheckName().getName(); +} + +CheckName CheckerBase::getCheckName() const { return Name; } + +CheckerProgramPointTag::CheckerProgramPointTag(StringRef CheckerName, + StringRef Msg) + : SimpleProgramPointTag(CheckerName, Msg) {} + +CheckerProgramPointTag::CheckerProgramPointTag(const CheckerBase *Checker, + StringRef Msg) + : SimpleProgramPointTag(Checker->getCheckName().getName(), Msg) {} + +raw_ostream& clang::ento::operator<<(raw_ostream &Out, + const CheckerBase &Checker) { + Out << Checker.getCheckName().getName(); + return Out; } void Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index c1ae7e9d812c9..2684cc78be750 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -58,7 +58,7 @@ void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, assert(D); unsigned DeclKind = D->getKind(); - CachedDeclCheckers *checkers = 0; + CachedDeclCheckers *checkers = nullptr; CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind); if (CCI != CachedDeclCheckersMap.end()) { checkers = &(CCI->second); @@ -109,7 +109,7 @@ static void expandGraphWithCheckers(CHECK_CTX checkCtx, const ExplodedNodeSet *PrevSet = &Src; for (; I != E; ++I) { - ExplodedNodeSet *CurrSet = 0; + ExplodedNodeSet *CurrSet = nullptr; if (I+1 == E) CurrSet = &Dst; else { @@ -477,7 +477,7 @@ CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, // If any checker declares the state infeasible (or if it starts that way), // bail out. if (!state) - return NULL; + return nullptr; state = RegionChangesCheckers[i].CheckFn(state, invalidated, ExplicitRegions, Regions, Call); } @@ -491,7 +491,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, const CallEvent *Call, PointerEscapeKind Kind, RegionAndSymbolInvalidationTraits *ETraits) { - assert((Call != NULL || + assert((Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && "Call must not be NULL when escaping on call"); @@ -499,7 +499,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, // If any checker declares the state infeasible (or if it starts that // way), bail out. if (!State) - return NULL; + return nullptr; State = PointerEscapeCheckers[i](State, Escaped, Call, Kind, ETraits); } return State; @@ -513,7 +513,7 @@ CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, // If any checker declares the state infeasible (or if it starts that way), // bail out. if (!state) - return NULL; + return nullptr; state = EvalAssumeCheckers[i](state, Cond, Assumption); } return state; diff --git a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp index 47299030cc450..b64e30b31007a 100644 --- a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp +++ b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp @@ -45,7 +45,7 @@ static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers, const llvm::StringMap<size_t> &packageSizes, CheckerOptInfo &opt, CheckerInfoSet &collected) { // Use a binary search to find the possible start of the package. - CheckerRegistry::CheckerInfo packageInfo(NULL, opt.getName(), ""); + CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.getName(), ""); CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end(); CheckerRegistry::CheckerInfoList::const_iterator i = std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT); @@ -84,10 +84,10 @@ void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name, // Record the presence of the checker in its packages. StringRef packageName, leafName; - llvm::tie(packageName, leafName) = name.rsplit(PackageSeparator); + std::tie(packageName, leafName) = name.rsplit(PackageSeparator); while (!leafName.empty()) { Packages[packageName] += 1; - llvm::tie(packageName, leafName) = packageName.rsplit(PackageSeparator); + std::tie(packageName, leafName) = packageName.rsplit(PackageSeparator); } } @@ -106,6 +106,7 @@ void CheckerRegistry::initializeManager(CheckerManager &checkerMgr, // Initialize the CheckerManager with all enabled checkers. for (CheckerInfoSet::iterator i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) { + checkerMgr.setCurrentCheckName(CheckName((*i)->FullName)); (*i)->Initialize(checkerMgr); } } diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp index b09b2c2ddfabd..4623c358a9e2c 100644 --- a/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -12,8 +12,6 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "CoreEngine" - #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" #include "clang/AST/Expr.h" #include "clang/AST/StmtCXX.h" @@ -26,6 +24,8 @@ using namespace clang; using namespace ento; +#define DEBUG_TYPE "CoreEngine" + STATISTIC(NumSteps, "The # of steps executed."); STATISTIC(NumReachedMaxSteps, @@ -43,22 +43,22 @@ namespace { class DFS : public WorkList { SmallVector<WorkListUnit,20> Stack; public: - virtual bool hasWork() const { + bool hasWork() const override { return !Stack.empty(); } - virtual void enqueue(const WorkListUnit& U) { + void enqueue(const WorkListUnit& U) override { Stack.push_back(U); } - virtual WorkListUnit dequeue() { + WorkListUnit dequeue() override { assert (!Stack.empty()); const WorkListUnit& U = Stack.back(); Stack.pop_back(); // This technically "invalidates" U, but we are fine. return U; } - - virtual bool visitItemsInWorkList(Visitor &V) { + + bool visitItemsInWorkList(Visitor &V) override { for (SmallVectorImpl<WorkListUnit>::iterator I = Stack.begin(), E = Stack.end(); I != E; ++I) { if (V.visit(*I)) @@ -71,21 +71,21 @@ public: class BFS : public WorkList { std::deque<WorkListUnit> Queue; public: - virtual bool hasWork() const { + bool hasWork() const override { return !Queue.empty(); } - virtual void enqueue(const WorkListUnit& U) { + void enqueue(const WorkListUnit& U) override { Queue.push_back(U); } - virtual WorkListUnit dequeue() { + WorkListUnit dequeue() override { WorkListUnit U = Queue.front(); Queue.pop_front(); return U; } - - virtual bool visitItemsInWorkList(Visitor &V) { + + bool visitItemsInWorkList(Visitor &V) override { for (std::deque<WorkListUnit>::iterator I = Queue.begin(), E = Queue.end(); I != E; ++I) { if (V.visit(*I)) @@ -109,18 +109,18 @@ namespace { std::deque<WorkListUnit> Queue; SmallVector<WorkListUnit,20> Stack; public: - virtual bool hasWork() const { + bool hasWork() const override { return !Queue.empty() || !Stack.empty(); } - virtual void enqueue(const WorkListUnit& U) { + void enqueue(const WorkListUnit& U) override { if (U.getNode()->getLocation().getAs<BlockEntrance>()) Queue.push_front(U); else Stack.push_back(U); } - virtual WorkListUnit dequeue() { + WorkListUnit dequeue() override { // Process all basic blocks to completion. if (!Stack.empty()) { const WorkListUnit& U = Stack.back(); @@ -135,7 +135,7 @@ namespace { Queue.pop_front(); return U; } - virtual bool visitItemsInWorkList(Visitor &V) { + bool visitItemsInWorkList(Visitor &V) override { for (SmallVectorImpl<WorkListUnit>::iterator I = Stack.begin(), E = Stack.end(); I != E; ++I) { if (V.visit(*I)) @@ -192,9 +192,9 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, if (!InitState) // Generate the root. - generateNode(StartLoc, SubEng.getInitialState(L), 0); + generateNode(StartLoc, SubEng.getInitialState(L), nullptr); else - generateNode(StartLoc, InitState, 0); + generateNode(StartLoc, InitState, nullptr); } // Check if we have a steps limit @@ -532,11 +532,16 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N, return; } + if ((*Block)[Idx].getKind() == CFGElement::NewAllocator) { + WList->enqueue(N, Block, Idx+1); + return; + } + // At this point, we know we're processing a normal statement. CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>(); PostStmt Loc(CS.getStmt(), N->getLocationContext()); - if (Loc == N->getLocation()) { + if (Loc == N->getLocation().withTag(nullptr)) { // Note: 'N' should be a fresh node because otherwise it shouldn't be // a member of Deferred. WList->enqueue(N, Block, Idx+1); @@ -562,7 +567,7 @@ ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N) { bool isNew; ExplodedNode *Node = G->getNode(Loc, N->getState(), false, &isNew); Node->addPredecessor(N, *G); - return isNew ? Node : 0; + return isNew ? Node : nullptr; } @@ -611,7 +616,7 @@ ExplodedNode* NodeBuilder::generateNodeImpl(const ProgramPoint &Loc, Frontier.erase(FromN); if (!IsNew) - return 0; + return nullptr; if (!MarkAsSink) Frontier.Add(N); @@ -635,7 +640,7 @@ ExplodedNode *BranchNodeBuilder::generateNode(ProgramStateRef State, ExplodedNode *NodePred) { // If the branch has been marked infeasible we should not generate a node. if (!isFeasible(branch)) - return NULL; + return nullptr; ProgramPoint Loc = BlockEdge(C.Block, branch ? DstT:DstF, NodePred->getLocationContext()); @@ -654,7 +659,7 @@ IndirectGotoNodeBuilder::generateNode(const iterator &I, Succ->addPredecessor(Pred, *Eng.G); if (!IsNew) - return 0; + return nullptr; if (!IsSink) Eng.WList->enqueue(Succ); @@ -673,7 +678,7 @@ SwitchNodeBuilder::generateCaseStmtNode(const iterator &I, false, &IsNew); Succ->addPredecessor(Pred, *Eng.G); if (!IsNew) - return 0; + return nullptr; Eng.WList->enqueue(Succ); return Succ; @@ -690,8 +695,8 @@ SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St, // Sanity check for default blocks that are unreachable and not caught // by earlier stages. if (!DefaultBlock) - return NULL; - + return nullptr; + bool IsNew; ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock, Pred->getLocationContext()), St, @@ -699,7 +704,7 @@ SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St, Succ->addPredecessor(Pred, *Eng.G); if (!IsNew) - return 0; + return nullptr; if (!IsSink) Eng.WList->enqueue(Succ); diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp index 7b133f6bf645f..ae5a4cc8b4aad 100644 --- a/lib/StaticAnalyzer/Core/Environment.cpp +++ b/lib/StaticAnalyzer/Core/Environment.cpp @@ -54,7 +54,8 @@ static const Stmt *ignoreTransparentExprs(const Stmt *S) { EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L) : std::pair<const Stmt *, const StackFrameContext *>(ignoreTransparentExprs(S), - L ? L->getCurrentStackFrame() : 0) {} + L ? L->getCurrentStackFrame() + : nullptr) {} SVal Environment::lookupExpr(const EnvironmentEntry &E) const { const SVal* X = ExprBindings.lookup(E); @@ -123,11 +124,11 @@ class MarkLiveCallback : public SymbolVisitor { SymbolReaper &SymReaper; public: MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {} - bool VisitSymbol(SymbolRef sym) { + bool VisitSymbol(SymbolRef sym) override { SymReaper.markLive(sym); return true; } - bool VisitMemRegion(const MemRegion *R) { + bool VisitMemRegion(const MemRegion *R) override { SymReaper.markLive(R); return true; } @@ -204,11 +205,12 @@ void Environment::print(raw_ostream &Out, const char *NL, } const Stmt *S = En.getStmt(); - + assert(S != nullptr && "Expected non-null Stmt"); + Out << " (" << (const void*) En.getLocationContext() << ',' << (const void*) S << ") "; LangOptions LO; // FIXME. - S->printPretty(Out, 0, PrintingPolicy(LO)); + S->printPretty(Out, nullptr, PrintingPolicy(LO)); Out << " : " << I.getData(); } } diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index e9c4a35de6e8d..1c9a282b82987 100644 --- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -34,7 +34,7 @@ using namespace ento; ExplodedNode::Auditor::~Auditor() {} #ifndef NDEBUG -static ExplodedNode::Auditor* NodeAuditor = 0; +static ExplodedNode::Auditor* NodeAuditor = nullptr; #endif void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) { @@ -90,8 +90,9 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { // (7) The LocationContext is the same as the predecessor. // (8) Expressions that are *not* lvalue expressions. // (9) The PostStmt isn't for a non-consumed Stmt or Expr. - // (10) The successor is not a CallExpr StmtPoint (so that we would - // be able to find it when retrying a call with no inlining). + // (10) The successor is neither a CallExpr StmtPoint nor a CallEnter or + // PreImplicitCall (so that we would be able to find it when retrying a + // call with no inlining). // FIXME: It may be safe to reclaim PreCall and PostCall nodes as well. // Conditions 1 and 2. @@ -153,6 +154,10 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { if (CallEvent::isCallStmt(SP->getStmt())) return false; + // Condition 10, continuation. + if (SuccLoc.getAs<CallEnter>() || SuccLoc.getAs<PreImplicitCall>()) + return false; + return true; } @@ -271,11 +276,11 @@ unsigned ExplodedNode::NodeGroup::size() const { ExplodedNode * const *ExplodedNode::NodeGroup::begin() const { if (getFlag()) - return 0; + return nullptr; const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P); if (Storage.isNull()) - return 0; + return nullptr; if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>()) return V->begin(); return Storage.getAddrOfPtr1(); @@ -283,11 +288,11 @@ ExplodedNode * const *ExplodedNode::NodeGroup::begin() const { ExplodedNode * const *ExplodedNode::NodeGroup::end() const { if (getFlag()) - return 0; + return nullptr; const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P); if (Storage.isNull()) - return 0; + return nullptr; if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>()) return V->end(); return Storage.getAddrOfPtr1() + 1; @@ -299,7 +304,7 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L, bool* IsNew) { // Profile 'State' to determine if we already have an existing node. llvm::FoldingSetNodeID profile; - void *InsertPos = 0; + void *InsertPos = nullptr; NodeTy::Profile(profile, L, State, IsSink); NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos); @@ -337,7 +342,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, InterExplodedGraphMap *InverseMap) const{ if (Nodes.empty()) - return 0; + return nullptr; typedef llvm::DenseSet<const ExplodedNode*> Pass1Ty; Pass1Ty Pass1; @@ -380,7 +385,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, // We didn't hit a root? Return with a null pointer for the new graph. if (WL2.empty()) - return 0; + return nullptr; // Create an empty graph. ExplodedGraph* G = MakeEmptyGraph(); @@ -395,7 +400,8 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, // Create the corresponding node in the new graph and record the mapping // from the old node to the new node. - ExplodedNode *NewN = G->getNode(N->getLocation(), N->State, N->isSink(), 0); + ExplodedNode *NewN = G->getNode(N->getLocation(), N->State, N->isSink(), + nullptr); Pass2[N] = NewN; // Also record the reverse mapping from the new node to the old node. diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 9907d0cbf9b85..4e4095c5e0d84 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -13,8 +13,6 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "ExprEngine" - #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "PrettyStackTraceLocationContext.h" #include "clang/AST/CharUnits.h" @@ -40,6 +38,8 @@ using namespace clang; using namespace ento; using llvm::APSInt; +#define DEBUG_TYPE "ExprEngine" + STATISTIC(NumRemoveDeadBindings, "The # of times RemoveDeadBindings is called"); STATISTIC(NumMaxBlockCountReached, @@ -55,6 +55,8 @@ STATISTIC(NumTimesRetriedWithoutInlining, // Engine construction and deletion. //===----------------------------------------------------------------------===// +static const char* TagProviderName = "ExprEngine"; + ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled, SetOfConstDecls *VisitedCalleesIn, FunctionSummariesTy *FS, @@ -68,7 +70,7 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled, this), SymMgr(StateMgr.getSymbolManager()), svalBuilder(StateMgr.getSValBuilder()), - currStmtIdx(0), currBldrCtx(0), + currStmtIdx(0), currBldrCtx(nullptr), ObjCNoRet(mgr.getASTContext()), ObjCGCEnabled(gcEnabled), BR(mgr, *this), VisitedCallees(VisitedCalleesIn), @@ -118,7 +120,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) { SVal V = state->getSVal(loc::MemRegionVal(R)); SVal Constraint_untested = evalBinOp(state, BO_GT, V, svalBuilder.makeZeroVal(T), - getContext().IntTy); + svalBuilder.getConditionType()); Optional<DefinedOrUnknownSVal> Constraint = Constraint_untested.getAs<DefinedOrUnknownSVal>(); @@ -153,7 +155,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) { // top-level function. This is our starting assumption for // analyzing an "open" program. const StackFrameContext *SFC = InitLoc->getCurrentStackFrame(); - if (SFC->getParent() == 0) { + if (SFC->getParent() == nullptr) { loc::MemRegionVal L = svalBuilder.getCXXThis(MD, SFC); SVal V = state->getSVal(L); if (Optional<Loc> LV = V.getAs<Loc>()) { @@ -209,7 +211,7 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, // Create a temporary object region for the inner expression (which may have // a more derived type) and bind the value into it. - const TypedValueRegion *TR = NULL; + const TypedValueRegion *TR = nullptr; if (const MaterializeTemporaryExpr *MT = dyn_cast<MaterializeTemporaryExpr>(Result)) { StorageDuration SD = MT->getStorageDuration(); @@ -286,6 +288,10 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, case CFGElement::Initializer: ProcessInitializer(E.castAs<CFGInitializer>().getInitializer(), Pred); return; + case CFGElement::NewAllocator: + ProcessNewAllocator(E.castAs<CFGNewAllocator>().getAllocatorExpr(), + Pred); + return; case CFGElement::AutomaticObjectDtor: case CFGElement::DeleteDtor: case CFGElement::BaseDtor: @@ -329,7 +335,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, const Stmt *DiagnosticStmt, ProgramPoint::Kind K) { assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind || - ReferenceStmt == 0 || isa<ReturnStmt>(ReferenceStmt)) + ReferenceStmt == nullptr || isa<ReturnStmt>(ReferenceStmt)) && "PostStmt is not generally supported by the SymbolReaper yet"); assert(LC && "Must pass the current (or expiring) LocationContext"); @@ -350,7 +356,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, LC = LC->getParent(); } - const StackFrameContext *SFC = LC ? LC->getCurrentStackFrame() : 0; + const StackFrameContext *SFC = LC ? LC->getCurrentStackFrame() : nullptr; SymbolReaper SymReaper(SFC, ReferenceStmt, SymMgr, getStoreManager()); getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper); @@ -362,7 +368,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, // Process any special transfer function for dead symbols. // A tag to track convenience transitions, which can be removed at cleanup. - static SimpleProgramPointTag cleanupTag("ExprEngine : Clean Node"); + static SimpleProgramPointTag cleanupTag(TagProviderName, "Clean Node"); if (!SymReaper.hasDeadSymbols()) { // Generate a CleanedNode that has the environment and store cleaned // up. Since no symbols are dead, we can optimize and not clean out @@ -547,6 +553,25 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); } +void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE, + ExplodedNode *Pred) { + ExplodedNodeSet Dst; + AnalysisManager &AMgr = getAnalysisManager(); + AnalyzerOptions &Opts = AMgr.options; + // TODO: We're not evaluating allocators for all cases just yet as + // we're not handling the return value correctly, which causes false + // positives when the alpha.cplusplus.NewDeleteLeaks check is on. + if (Opts.mayInlineCXXAllocator()) + VisitCXXNewAllocatorCall(NE, Pred, Dst); + else { + NodeBuilder Bldr(Pred, Dst, *currBldrCtx); + const LocationContext *LCtx = Pred->getLocationContext(); + PostImplicitCall PP(NE->getOperatorNew(), NE->getLocStart(), LCtx); + Bldr.generateNode(PP, Pred->getState(), Pred); + } + Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); +} + void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor, ExplodedNode *Pred, ExplodedNodeSet &Dst) { @@ -598,7 +623,6 @@ void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor, void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D, ExplodedNode *Pred, ExplodedNodeSet &Dst) { const LocationContext *LCtx = Pred->getLocationContext(); - ProgramStateRef State = Pred->getState(); const CXXDestructorDecl *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl()); Loc ThisPtr = getSValBuilder().getCXXThis(CurDtor, @@ -640,7 +664,7 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, // FIXME: Inlining of temporary destructors is not supported yet anyway, so we // just put a NULL region for now. This will need to be changed later. - VisitCXXDestructor(varType, NULL, D.getBindTemporaryExpr(), + VisitCXXDestructor(varType, nullptr, D.getBindTemporaryExpr(), /*IsBase=*/ false, Pred, Dst); } @@ -664,8 +688,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::MSPropertyRefExprClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::DependentScopeDeclRefExprClass: - case Stmt::UnaryTypeTraitExprClass: - case Stmt::BinaryTypeTraitExprClass: case Stmt::TypeTraitExprClass: case Stmt::ArrayTypeTraitExprClass: case Stmt::ExpressionTraitExprClass: @@ -677,6 +699,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::FunctionParmPackExprClass: case Stmt::SEHTryStmtClass: case Stmt::SEHExceptStmtClass: + case Stmt::SEHLeaveStmtClass: case Stmt::LambdaExprClass: case Stmt::SEHFinallyStmtClass: { const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); @@ -709,6 +732,20 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Expr::MSDependentExistsStmtClass: case Stmt::CapturedStmtClass: case Stmt::OMPParallelDirectiveClass: + case Stmt::OMPSimdDirectiveClass: + case Stmt::OMPForDirectiveClass: + case Stmt::OMPSectionsDirectiveClass: + case Stmt::OMPSectionDirectiveClass: + case Stmt::OMPSingleDirectiveClass: + case Stmt::OMPMasterDirectiveClass: + case Stmt::OMPCriticalDirectiveClass: + case Stmt::OMPParallelForDirectiveClass: + case Stmt::OMPParallelSectionsDirectiveClass: + case Stmt::OMPTaskDirectiveClass: + case Stmt::OMPTaskyieldDirectiveClass: + case Stmt::OMPBarrierDirectiveClass: + case Stmt::OMPTaskwaitDirectiveClass: + case Stmt::OMPFlushDirectiveClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); case Stmt::ObjCSubscriptRefExprClass: @@ -848,7 +885,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, it != et; ++it) { ExplodedNode *N = *it; const LocationContext *LCtx = N->getLocationContext(); - SVal result = svalBuilder.conjureSymbolVal(0, Ex, LCtx, resultType, + SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, + resultType, currBldrCtx->blockCount()); ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result); Bldr2.generateNode(S, N, state); @@ -928,7 +966,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, ProgramStateRef NewState = createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0)); if (NewState != State) { - Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/0, + Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/nullptr, ProgramPoint::PreStmtKind); // Did we cache out? if (!Pred) @@ -1187,14 +1225,14 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N, const StackFrameContext *CalleeSF = CalleeLC->getCurrentStackFrame(); const StackFrameContext *CallerSF = CalleeSF->getParent()->getCurrentStackFrame(); assert(CalleeSF && CallerSF); - ExplodedNode *BeforeProcessingCall = 0; + ExplodedNode *BeforeProcessingCall = nullptr; const Stmt *CE = CalleeSF->getCallSite(); // Find the first node before we started processing the call expression. while (N) { ProgramPoint L = N->getLocation(); BeforeProcessingCall = N; - N = N->pred_empty() ? NULL : *(N->pred_begin()); + N = N->pred_empty() ? nullptr : *(N->pred_begin()); // Skip the nodes corresponding to the inlined code. if (L.getLocationContext()->getCurrentStackFrame() != CallerSF) @@ -1253,7 +1291,7 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, // FIXME: Refactor this into a checker. if (nodeBuilder.getContext().blockCount() >= AMgr.options.maxBlockVisitOnPath) { - static SimpleProgramPointTag tag("ExprEngine : Block count exceeded"); + static SimpleProgramPointTag tag(TagProviderName, "Block count exceeded"); const ExplodedNode *Sink = nodeBuilder.generateSink(Pred->getState(), Pred, &tag); @@ -1329,6 +1367,33 @@ static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr, return state->getSVal(Ex, LCtx); } +#ifndef NDEBUG +static const Stmt *getRightmostLeaf(const Stmt *Condition) { + while (Condition) { + const BinaryOperator *BO = dyn_cast<BinaryOperator>(Condition); + if (!BO || !BO->isLogicalOp()) { + return Condition; + } + Condition = BO->getRHS()->IgnoreParens(); + } + return nullptr; +} +#endif + +// Returns the condition the branch at the end of 'B' depends on and whose value +// has been evaluated within 'B'. +// In most cases, the terminator condition of 'B' will be evaluated fully in +// the last statement of 'B'; in those cases, the resolved condition is the +// given 'Condition'. +// If the condition of the branch is a logical binary operator tree, the CFG is +// optimized: in that case, we know that the expression formed by all but the +// rightmost leaf of the logical binary operator tree must be true, and thus +// the branch condition is at this point equivalent to the truth value of that +// rightmost leaf; the CFG block thus only evaluates this rightmost leaf +// expression in its final statement. As the full condition in that case was +// not evaluated, and is thus not in the SVal cache, we need to use that leaf +// expression to evaluate the truth value of the condition in the current state +// space. static const Stmt *ResolveCondition(const Stmt *Condition, const CFGBlock *B) { if (const Expr *Ex = dyn_cast<Expr>(Condition)) @@ -1338,6 +1403,12 @@ static const Stmt *ResolveCondition(const Stmt *Condition, if (!BO || !BO->isLogicalOp()) return Condition; + // FIXME: This is a workaround until we handle temporary destructor branches + // correctly; currently, temporary destructor branches lead to blocks that + // only have a terminator (and no statements). These blocks violate the + // invariant this function assumes. + if (B->getTerminator().isTemporaryDtorsBranch()) return Condition; + // For logical operations, we still have the case where some branches // use the traditional "merge" approach and others sink the branch // directly into the basic blocks representing the logical operation. @@ -1352,18 +1423,9 @@ static const Stmt *ResolveCondition(const Stmt *Condition, Optional<CFGStmt> CS = Elem.getAs<CFGStmt>(); if (!CS) continue; - if (CS->getStmt() != Condition) - break; - return Condition; - } - - assert(I != E); - - while (Condition) { - BO = dyn_cast<BinaryOperator>(Condition); - if (!BO || !BO->isLogicalOp()) - return Condition; - Condition = BO->getRHS()->IgnoreParens(); + const Stmt *LastStmt = CS->getStmt(); + assert(LastStmt == Condition || LastStmt == getRightmostLeaf(Condition)); + return LastStmt; } llvm_unreachable("could not resolve condition"); } @@ -1443,7 +1505,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, DefinedSVal V = X.castAs<DefinedSVal>(); ProgramStateRef StTrue, StFalse; - tie(StTrue, StFalse) = PrevState->assume(V); + std::tie(StTrue, StFalse) = PrevState->assume(V); // Process the true branch. if (builder.isFeasible(true)) { @@ -1461,7 +1523,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, builder.markInfeasible(false); } } - currBldrCtx = 0; + currBldrCtx = nullptr; } /// The GDM component containing the set of global variables which have been @@ -1490,7 +1552,7 @@ void ExprEngine::processStaticInitializer(const DeclStmt *DS, builder.generateNode(state, initHasRun, Pred); builder.markInfeasible(!initHasRun); - currBldrCtx = 0; + currBldrCtx = nullptr; } /// processIndirectGoto - Called by CoreEngine. Used to generate successor @@ -1631,7 +1693,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { } else { defaultIsFeasible = false; - DefaultSt = NULL; + DefaultSt = nullptr; } } @@ -1692,7 +1754,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, V = UnknownVal(); } - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, ProgramPoint::PostLValueKind); return; } @@ -1704,7 +1766,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, } if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { SVal V = svalBuilder.getFunctionPointer(FD); - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, ProgramPoint::PostLValueKind); return; } @@ -1715,7 +1777,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy, currBldrCtx->blockCount()); state = state->assume(V.castAs<DefinedOrUnknownSVal>(), true); - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, ProgramPoint::PostLValueKind); return; } @@ -1745,82 +1807,91 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, state->getSVal(Idx, LCtx), state->getSVal(Base, LCtx)); assert(A->isGLValue()); - Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), 0, + Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), nullptr, ProgramPoint::PostLValueKind); } } /// VisitMemberExpr - Transfer function for member expressions. void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, - ExplodedNodeSet &TopDst) { + ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, TopDst, *currBldrCtx); - ExplodedNodeSet Dst; + // FIXME: Prechecks eventually go in ::Visit(). + ExplodedNodeSet CheckedSet; + getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, M, *this); + + ExplodedNodeSet EvalSet; ValueDecl *Member = M->getMemberDecl(); // Handle static member variables and enum constants accessed via // member syntax. if (isa<VarDecl>(Member) || isa<EnumConstantDecl>(Member)) { - Bldr.takeNodes(Pred); - VisitCommonDeclRefExpr(M, Member, Pred, Dst); - Bldr.addNodes(Dst); - return; - } - - ProgramStateRef state = Pred->getState(); - const LocationContext *LCtx = Pred->getLocationContext(); - Expr *BaseExpr = M->getBase(); + ExplodedNodeSet Dst; + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I != E; ++I) { + VisitCommonDeclRefExpr(M, Member, Pred, EvalSet); + } + } else { + StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx); + ExplodedNodeSet Tmp; - // Handle C++ method calls. - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) { - if (MD->isInstance()) - state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I != E; ++I) { + ProgramStateRef state = (*I)->getState(); + const LocationContext *LCtx = (*I)->getLocationContext(); + Expr *BaseExpr = M->getBase(); - SVal MDVal = svalBuilder.getFunctionPointer(MD); - state = state->BindExpr(M, LCtx, MDVal); + // Handle C++ method calls. + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) { + if (MD->isInstance()) + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); - Bldr.generateNode(M, Pred, state); - return; - } + SVal MDVal = svalBuilder.getFunctionPointer(MD); + state = state->BindExpr(M, LCtx, MDVal); - // Handle regular struct fields / member variables. - state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); - SVal baseExprVal = state->getSVal(BaseExpr, LCtx); - - FieldDecl *field = cast<FieldDecl>(Member); - SVal L = state->getLValue(field, baseExprVal); - - if (M->isGLValue() || M->getType()->isArrayType()) { - - // We special case rvalue of array type because the analyzer cannot reason - // about it, since we expect all regions to be wrapped in Locs. So we will - // treat these as lvalues assuming that they will decay to pointers as soon - // as they are used. - if (!M->isGLValue()) { - assert(M->getType()->isArrayType()); - const ImplicitCastExpr *PE = - dyn_cast<ImplicitCastExpr>(Pred->getParentMap().getParent(M)); - if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) { - assert(false && - "We assume that array is always wrapped in ArrayToPointerDecay"); - L = UnknownVal(); + Bldr.generateNode(M, *I, state); + continue; } - } - if (field->getType()->isReferenceType()) { - if (const MemRegion *R = L.getAsRegion()) - L = state->getSVal(R); - else - L = UnknownVal(); - } + // Handle regular struct fields / member variables. + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); + SVal baseExprVal = state->getSVal(BaseExpr, LCtx); + + FieldDecl *field = cast<FieldDecl>(Member); + SVal L = state->getLValue(field, baseExprVal); + + if (M->isGLValue() || M->getType()->isArrayType()) { + // We special-case rvalues of array type because the analyzer cannot + // reason about them, since we expect all regions to be wrapped in Locs. + // We instead treat these as lvalues and assume that they will decay to + // pointers as soon as they are used. + if (!M->isGLValue()) { + assert(M->getType()->isArrayType()); + const ImplicitCastExpr *PE = + dyn_cast<ImplicitCastExpr>((*I)->getParentMap().getParent(M)); + if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) { + llvm_unreachable("should always be wrapped in ArrayToPointerDecay"); + } + } - Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), 0, - ProgramPoint::PostLValueKind); - } else { - Bldr.takeNodes(Pred); - evalLoad(Dst, M, M, Pred, state, L); - Bldr.addNodes(Dst); + if (field->getType()->isReferenceType()) { + if (const MemRegion *R = L.getAsRegion()) + L = state->getSVal(R); + else + L = UnknownVal(); + } + + Bldr.generateNode(M, *I, state->BindExpr(M, LCtx, L), nullptr, + ProgramPoint::PostLValueKind); + } else { + Bldr.takeNodes(*I); + evalLoad(Tmp, M, M, *I, state, L); + Bldr.addNodes(Tmp); + } + } } + + getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, M, *this); } namespace { @@ -1830,7 +1901,7 @@ public: CollectReachableSymbolsCallback(ProgramStateRef State) {} const InvalidatedSymbols &getSymbols() const { return Symbols; } - bool VisitSymbol(SymbolRef Sym) { + bool VisitSymbol(SymbolRef Sym) override { Symbols.insert(Sym); return true; } @@ -1876,9 +1947,9 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, const InvalidatedSymbols &EscapedSymbols = Scanner.getSymbols(); State = getCheckerManager().runCheckersForPointerEscape(State, EscapedSymbols, - /*CallEvent*/ 0, + /*CallEvent*/ nullptr, PSK_EscapeOnBind, - 0); + nullptr); return State; } @@ -1897,7 +1968,7 @@ ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State, if (!Call) return getCheckerManager().runCheckersForPointerEscape(State, *Invalidated, - 0, + nullptr, PSK_EscapeOther, &ITraits); @@ -1954,7 +2025,8 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, // If the location is not a 'Loc', it will already be handled by // the checkers. There is nothing left to do. if (!location.getAs<Loc>()) { - const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/0, /*tag*/0); + const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/nullptr, + /*tag*/nullptr); ProgramStateRef state = Pred->getState(); state = processPointerEscapedOnBind(state, location, Val); Bldr.generateNode(L, state, Pred); @@ -1975,13 +2047,13 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, state = state->bindLoc(location.castAs<Loc>(), Val, /* notifyChanges = */ !atDeclInit); - const MemRegion *LocReg = 0; + const MemRegion *LocReg = nullptr; if (Optional<loc::MemRegionVal> LocRegVal = location.getAs<loc::MemRegionVal>()) { LocReg = LocRegVal->getRegion(); } - - const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0); + + const ProgramPoint L = PostStore(StoreE, LC, LocReg, nullptr); Bldr.generateNode(L, state, PredI); } } @@ -2037,7 +2109,7 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst, QualType ValTy = TR->getValueType(); if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) { static SimpleProgramPointTag - loadReferenceTag("ExprEngine : Load Reference"); + loadReferenceTag(TagProviderName, "Load Reference"); ExplodedNodeSet Tmp; evalLoadCommon(Tmp, NodeEx, BoundEx, Pred, state, location, &loadReferenceTag, @@ -2120,7 +2192,7 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, // instead "int *p" is noted as // "Variable 'p' initialized to a null pointer value" - static SimpleProgramPointTag tag("ExprEngine: Location"); + static SimpleProgramPointTag tag(TagProviderName, "Location"); Bldr.generateNode(NodeEx, Pred, state, &tag); } ExplodedNodeSet Tmp; @@ -2132,8 +2204,10 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, std::pair<const ProgramPointTag *, const ProgramPointTag*> ExprEngine::geteagerlyAssumeBinOpBifurcationTags() { static SimpleProgramPointTag - eagerlyAssumeBinOpBifurcationTrue("ExprEngine : Eagerly Assume True"), - eagerlyAssumeBinOpBifurcationFalse("ExprEngine : Eagerly Assume False"); + eagerlyAssumeBinOpBifurcationTrue(TagProviderName, + "Eagerly Assume True"), + eagerlyAssumeBinOpBifurcationFalse(TagProviderName, + "Eagerly Assume False"); return std::make_pair(&eagerlyAssumeBinOpBifurcationTrue, &eagerlyAssumeBinOpBifurcationFalse); } @@ -2161,7 +2235,7 @@ void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, geteagerlyAssumeBinOpBifurcationTags(); ProgramStateRef StateTrue, StateFalse; - tie(StateTrue, StateFalse) = state->assume(*SEV); + std::tie(StateTrue, StateFalse) = state->assume(*SEV); // First assume that the condition is true. if (StateTrue) { @@ -2192,9 +2266,8 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, ProgramStateRef state = Pred->getState(); - for (GCCAsmStmt::const_outputs_iterator OI = A->begin_outputs(), - OE = A->end_outputs(); OI != OE; ++OI) { - SVal X = state->getSVal(*OI, Pred->getLocationContext()); + for (const Expr *O : A->outputs()) { + SVal X = state->getSVal(O, Pred->getLocationContext()); assert (!X.getAs<NonLoc>()); // Should be an Lval, or unknown, undef. if (Optional<Loc> LV = X.getAs<Loc>()) @@ -2368,11 +2441,12 @@ struct DOTGraphTraits<ExplodedNode*> : if (const CaseStmt *C = dyn_cast<CaseStmt>(Label)) { Out << "\\lcase "; LangOptions LO; // FIXME. - C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO)); + if (C->getLHS()) + C->getLHS()->printPretty(Out, nullptr, PrintingPolicy(LO)); if (const Stmt *RHS = C->getRHS()) { Out << " .. "; - RHS->printPretty(Out, 0, PrintingPolicy(LO)); + RHS->printPretty(Out, nullptr, PrintingPolicy(LO)); } Out << ":"; @@ -2411,10 +2485,11 @@ struct DOTGraphTraits<ExplodedNode*> : default: { const Stmt *S = Loc.castAs<StmtPoint>().getStmt(); + assert(S != nullptr && "Expecting non-null Stmt"); Out << S->getStmtClassName() << ' ' << (const void*) S << ' '; LangOptions LO; // FIXME. - S->printPretty(Out, 0, PrintingPolicy(LO)); + S->printPretty(Out, nullptr, PrintingPolicy(LO)); printLocation(Out, S->getLocStart()); if (Loc.getAs<PreStmt>()) @@ -2452,7 +2527,7 @@ struct DOTGraphTraits<ExplodedNode*> : } ProgramStateRef state = N->getState(); - Out << "\\|StateID: " << (const void*) state.getPtr() + Out << "\\|StateID: " << (const void*) state.get() << " NodeID: " << (const void*) N << "\\|"; state->printDOT(Out); @@ -2504,8 +2579,8 @@ void ExprEngine::ViewGraph(bool trim) { llvm::ViewGraph(*G.roots_begin(), "ExprEngine"); - GraphPrintCheckerState = NULL; - GraphPrintSourceManager = NULL; + GraphPrintCheckerState = nullptr; + GraphPrintSourceManager = nullptr; } #endif } @@ -2515,14 +2590,14 @@ void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode*> Nodes) { GraphPrintCheckerState = this; GraphPrintSourceManager = &getContext().getSourceManager(); - OwningPtr<ExplodedGraph> TrimmedG(G.trim(Nodes)); + std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Nodes)); if (!TrimmedG.get()) llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n"; else llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedExprEngine"); - GraphPrintCheckerState = NULL; - GraphPrintSourceManager = NULL; + GraphPrintCheckerState = nullptr; + GraphPrintSourceManager = nullptr; #endif } diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 983fda00a2ffc..ffda52709dc2f 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -47,7 +47,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // FIXME: Handle structs. if (RightV.isUnknown()) { unsigned Count = currBldrCtx->blockCount(); - RightV = svalBuilder.conjureSymbolVal(0, B->getRHS(), LCtx, Count); + RightV = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, + Count); } // Simulate the effects of a "store": bind the value of the RHS // to the L-Value represented by the LHS. @@ -81,6 +82,12 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, } } + // Although we don't yet model pointers-to-members, we do need to make + // sure that the members of temporaries have a valid 'this' pointer for + // other checks. + if (B->getOpcode() == BO_PtrMemD) + state = createTemporaryRegionIfNeeded(state, LCtx, LHS); + // Process non-assignments except commas or short-circuited // logical expressions (LAnd and LOr). SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType()); @@ -151,7 +158,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // The symbolic value is actually for the type of the left-hand side // expression, not the computation type, as this is the value the // LValue on the LHS will bind to. - LHSVal = svalBuilder.conjureSymbolVal(0, B->getRHS(), LCtx, LTy, + LHSVal = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, LTy, currBldrCtx->blockCount()); // However, we need to convert the symbol to the computation type. Result = svalBuilder.evalCast(LHSVal, CTy, LTy); @@ -211,8 +218,8 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx); Bldr.generateNode(BE, Pred, State->BindExpr(BE, Pred->getLocationContext(), V), - 0, ProgramPoint::PostLValueKind); - + nullptr, ProgramPoint::PostLValueKind); + // FIXME: Move all post/pre visits to ::Visit(). getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this); } @@ -286,6 +293,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_Dependent: case CK_ArrayToPointerDecay: case CK_BitCast: + case CK_AddressSpaceConversion: case CK_IntegralCast: case CK_NullToPointer: case CK_IntegralToPointer: @@ -360,7 +368,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, // If we don't know if the cast succeeded, conjure a new symbol. if (val.isUnknown()) { DefinedOrUnknownSVal NewSym = - svalBuilder.conjureSymbolVal(0, CastE, LCtx, resultType, + svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType, currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, NewSym); } else @@ -388,7 +396,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, QualType resultType = CastE->getType(); if (CastE->isGLValue()) resultType = getContext().getPointerType(resultType); - SVal result = svalBuilder.conjureSymbolVal(0, CastE, LCtx, + SVal result = svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType, currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, result); @@ -486,7 +494,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, Ty = getContext().getPointerType(Ty); } - InitVal = svalBuilder.conjureSymbolVal(0, InitEx, LC, Ty, + InitVal = svalBuilder.conjureSymbolVal(nullptr, InitEx, LC, Ty, currBldrCtx->blockCount()); } @@ -554,7 +562,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, } else { DefinedOrUnknownSVal DefinedRHS = RHSVal.castAs<DefinedOrUnknownSVal>(); ProgramStateRef StTrue, StFalse; - llvm::tie(StTrue, StFalse) = N->getState()->assume(DefinedRHS); + std::tie(StTrue, StFalse) = N->getState()->assume(DefinedRHS); if (StTrue) { if (StFalse) { // We can't constrain the value to 0 or 1. @@ -633,7 +641,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, StmtNodeBuilder B(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); - const CFGBlock *SrcBlock = 0; + const CFGBlock *SrcBlock = nullptr; // Find the predecessor block. ProgramStateRef SrcState = state; @@ -678,7 +686,8 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, } if (!hasValue) - V = svalBuilder.conjureSymbolVal(0, Ex, LCtx, currBldrCtx->blockCount()); + V = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, + currBldrCtx->blockCount()); // Generate a new node with the binding from the appropriate path. B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V, true)); @@ -707,34 +716,43 @@ void ExprEngine:: VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); + // FIXME: Prechecks eventually go in ::Visit(). + ExplodedNodeSet CheckedSet; + getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, Ex, *this); + + ExplodedNodeSet EvalSet; + StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx); QualType T = Ex->getTypeOfArgument(); - - if (Ex->getKind() == UETT_SizeOf) { - if (!T->isIncompleteType() && !T->isConstantSizeType()) { - assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); - - // FIXME: Add support for VLA type arguments and VLA expressions. - // When that happens, we should probably refactor VLASizeChecker's code. - return; - } - else if (T->getAs<ObjCObjectType>()) { - // Some code tries to take the sizeof an ObjCObjectType, relying that - // the compiler has laid out its representation. Just report Unknown - // for these. - return; + + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I != E; ++I) { + if (Ex->getKind() == UETT_SizeOf) { + if (!T->isIncompleteType() && !T->isConstantSizeType()) { + assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); + + // FIXME: Add support for VLA type arguments and VLA expressions. + // When that happens, we should probably refactor VLASizeChecker's code. + continue; + } else if (T->getAs<ObjCObjectType>()) { + // Some code tries to take the sizeof an ObjCObjectType, relying that + // the compiler has laid out its representation. Just report Unknown + // for these. + continue; + } } + + APSInt Value = Ex->EvaluateKnownConstInt(getContext()); + CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue()); + + ProgramStateRef state = (*I)->getState(); + state = state->BindExpr(Ex, (*I)->getLocationContext(), + svalBuilder.makeIntVal(amt.getQuantity(), + Ex->getType())); + Bldr.generateNode(Ex, *I, state); } - - APSInt Value = Ex->EvaluateKnownConstInt(getContext()); - CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue()); - - ProgramStateRef state = Pred->getState(); - state = state->BindExpr(Ex, Pred->getLocationContext(), - svalBuilder.makeIntVal(amt.getQuantity(), - Ex->getType())); - Bldr.generateNode(Ex, Pred, state); + + getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this); } void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, @@ -919,7 +937,8 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, // Conjure a new symbol if necessary to recover precision. if (Result.isUnknown()){ DefinedOrUnknownSVal SymVal = - svalBuilder.conjureSymbolVal(0, Ex, LCtx, currBldrCtx->blockCount()); + svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, + currBldrCtx->blockCount()); Result = SymVal; // If the value is a location, ++/-- should always preserve diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index eba4f94d80e66..2a766218aaeb1 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -91,12 +91,6 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, /// If the type is not an array type at all, the original value is returned. static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue, QualType &Ty) { - // FIXME: This check is just a temporary workaround, because - // ProcessTemporaryDtor sends us NULL regions. It will not be necessary once - // we can properly process temporary destructors. - if (!LValue.getAsRegion()) - return LValue; - SValBuilder &SVB = State->getStateManager().getSValBuilder(); ASTContext &Ctx = SVB.getContext(); @@ -108,13 +102,85 @@ static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue, return LValue; } + +static const MemRegion *getRegionForConstructedObject( + const CXXConstructExpr *CE, ExplodedNode *Pred, ExprEngine &Eng, + unsigned int CurrStmtIdx) { + const LocationContext *LCtx = Pred->getLocationContext(); + ProgramStateRef State = Pred->getState(); + const NodeBuilderContext &CurrBldrCtx = Eng.getBuilderContext(); + + // See if we're constructing an existing region by looking at the next + // element in the CFG. + const CFGBlock *B = CurrBldrCtx.getBlock(); + unsigned int NextStmtIdx = CurrStmtIdx + 1; + if (NextStmtIdx < B->size()) { + CFGElement Next = (*B)[NextStmtIdx]; + + // Is this a destructor? If so, we might be in the middle of an assignment + // to a local or member: look ahead one more element to see what we find. + while (Next.getAs<CFGImplicitDtor>() && NextStmtIdx + 1 < B->size()) { + ++NextStmtIdx; + Next = (*B)[NextStmtIdx]; + } + + // Is this a constructor for a local variable? + if (Optional<CFGStmt> StmtElem = Next.getAs<CFGStmt>()) { + if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt())) { + if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) { + if (Var->getInit() && Var->getInit()->IgnoreImplicit() == CE) { + SVal LValue = State->getLValue(Var, LCtx); + QualType Ty = Var->getType(); + LValue = makeZeroElementRegion(State, LValue, Ty); + return LValue.getAsRegion(); + } + } + } + } + + // Is this a constructor for a member? + if (Optional<CFGInitializer> InitElem = Next.getAs<CFGInitializer>()) { + const CXXCtorInitializer *Init = InitElem->getInitializer(); + assert(Init->isAnyMemberInitializer()); + + const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl()); + Loc ThisPtr = Eng.getSValBuilder().getCXXThis(CurCtor, + LCtx->getCurrentStackFrame()); + SVal ThisVal = State->getSVal(ThisPtr); + + const ValueDecl *Field; + SVal FieldVal; + if (Init->isIndirectMemberInitializer()) { + Field = Init->getIndirectMember(); + FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal); + } else { + Field = Init->getMember(); + FieldVal = State->getLValue(Init->getMember(), ThisVal); + } + + QualType Ty = Field->getType(); + FieldVal = makeZeroElementRegion(State, FieldVal, Ty); + return FieldVal.getAsRegion(); + } + + // FIXME: This will eventually need to handle new-expressions as well. + // Don't forget to update the pre-constructor initialization code in + // ExprEngine::VisitCXXConstructExpr. + } + + // If we couldn't find an existing region to construct into, assume we're + // constructing a temporary. + MemRegionManager &MRMgr = Eng.getSValBuilder().getRegionManager(); + return MRMgr.getCXXTempObjectRegion(CE, LCtx); +} + void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ExplodedNode *Pred, ExplodedNodeSet &destNodes) { const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); - const MemRegion *Target = 0; + const MemRegion *Target = nullptr; // FIXME: Handle arrays, which run the same constructor for every element. // For now, we just run the first constructor (which should still invalidate @@ -122,62 +188,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, switch (CE->getConstructionKind()) { case CXXConstructExpr::CK_Complete: { - // See if we're constructing an existing region by looking at the next - // element in the CFG. - const CFGBlock *B = currBldrCtx->getBlock(); - if (currStmtIdx + 1 < B->size()) { - CFGElement Next = (*B)[currStmtIdx+1]; - - // Is this a constructor for a local variable? - if (Optional<CFGStmt> StmtElem = Next.getAs<CFGStmt>()) { - if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt())) { - if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) { - if (Var->getInit()->IgnoreImplicit() == CE) { - SVal LValue = State->getLValue(Var, LCtx); - QualType Ty = Var->getType(); - LValue = makeZeroElementRegion(State, LValue, Ty); - Target = LValue.getAsRegion(); - } - } - } - } - - // Is this a constructor for a member? - if (Optional<CFGInitializer> InitElem = Next.getAs<CFGInitializer>()) { - const CXXCtorInitializer *Init = InitElem->getInitializer(); - assert(Init->isAnyMemberInitializer()); - - const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl()); - Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor, - LCtx->getCurrentStackFrame()); - SVal ThisVal = State->getSVal(ThisPtr); - - const ValueDecl *Field; - SVal FieldVal; - if (Init->isIndirectMemberInitializer()) { - Field = Init->getIndirectMember(); - FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal); - } else { - Field = Init->getMember(); - FieldVal = State->getLValue(Init->getMember(), ThisVal); - } - - QualType Ty = Field->getType(); - FieldVal = makeZeroElementRegion(State, FieldVal, Ty); - Target = FieldVal.getAsRegion(); - } - - // FIXME: This will eventually need to handle new-expressions as well. - // Don't forget to update the pre-constructor initialization code below. - } - - // If we couldn't find an existing region to construct into, assume we're - // constructing a temporary. - if (!Target) { - MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); - Target = MRMgr.getCXXTempObjectRegion(CE, LCtx); - } - + Target = getRegionForConstructedObject(CE, Pred, *this, currStmtIdx); break; } case CXXConstructExpr::CK_VirtualBase: @@ -251,7 +262,8 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, // since it's then possible to be initializing one part of a multi- // dimensional array. State = State->bindDefault(loc::MemRegionVal(Target), ZeroVal); - Bldr.generateNode(CE, *I, State, /*tag=*/0, ProgramPoint::PreStmtKind); + Bldr.generateNode(CE, *I, State, /*tag=*/nullptr, + ProgramPoint::PreStmtKind); } } } @@ -329,6 +341,32 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType, *Call, *this); } +void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + ProgramStateRef State = Pred->getState(); + const LocationContext *LCtx = Pred->getLocationContext(); + PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), + CNE->getStartLoc(), + "Error evaluating New Allocator Call"); + CallEventManager &CEMgr = getStateManager().getCallEventManager(); + CallEventRef<CXXAllocatorCall> Call = + CEMgr.getCXXAllocatorCall(CNE, State, LCtx); + + ExplodedNodeSet DstPreCall; + getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, + *Call, *this); + + ExplodedNodeSet DstInvalidated; + StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx); + for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); + I != E; ++I) + defaultEvalCall(Bldr, *I, *Call); + getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated, + *Call, *this); +} + + void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // FIXME: Much of this should eventually migrate to CXXAllocatorCall. @@ -360,7 +398,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, if (IsStandardGlobalOpNewFunction) symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount); else - symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx, CNE->getType(), + symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(), blockCount); ProgramStateRef State = Pred->getState(); diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 06328e4ffce99..3f608ba79ebc3 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -11,8 +11,6 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "ExprEngine" - #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "PrettyStackTraceLocationContext.h" #include "clang/AST/CXXInheritance.h" @@ -28,6 +26,8 @@ using namespace clang; using namespace ento; +#define DEBUG_TYPE "ExprEngine" + STATISTIC(NumOfDynamicDispatchPathSplits, "The # of times we split the path due to imprecise dynamic dispatch info"); @@ -49,7 +49,7 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) { assert(Entry->empty()); assert(Entry->succ_size() == 1); - // Get the solitary sucessor. + // Get the solitary successor. const CFGBlock *Succ = *(Entry->succ_begin()); // Construct an edge representing the starting location in the callee. @@ -69,8 +69,8 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) { // corresponding Block. static std::pair<const Stmt*, const CFGBlock*> getLastStmt(const ExplodedNode *Node) { - const Stmt *S = 0; - const CFGBlock *Blk = 0; + const Stmt *S = nullptr; + const CFGBlock *Blk = nullptr; const StackFrameContext *SF = Node->getLocation().getLocationContext()->getCurrentStackFrame(); @@ -108,12 +108,12 @@ static std::pair<const Stmt*, } if (Node->pred_empty()) - return std::pair<const Stmt*, const CFGBlock*>((Stmt*)0, (CFGBlock*)0); + return std::make_pair(nullptr, nullptr); Node = *Node->pred_begin(); } - return std::pair<const Stmt*, const CFGBlock*>(S, Blk); + return std::make_pair(S, Blk); } /// Adjusts a return value when the called function's return type does not @@ -160,9 +160,9 @@ void ExprEngine::removeDeadOnEndOfFunction(NodeBuilderContext& BC, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // Find the last statement in the function and the corresponding basic block. - const Stmt *LastSt = 0; - const CFGBlock *Blk = 0; - llvm::tie(LastSt, Blk) = getLastStmt(Pred); + const Stmt *LastSt = nullptr; + const CFGBlock *Blk = nullptr; + std::tie(LastSt, Blk) = getLastStmt(Pred); if (!Blk || !LastSt) { Dst.Add(Pred); return; @@ -229,9 +229,9 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { const Stmt *CE = calleeCtx->getCallSite(); ProgramStateRef state = CEBNode->getState(); // Find the last statement in the function and the corresponding basic block. - const Stmt *LastSt = 0; - const CFGBlock *Blk = 0; - llvm::tie(LastSt, Blk) = getLastStmt(CEBNode); + const Stmt *LastSt = nullptr; + const CFGBlock *Blk = nullptr; + std::tie(LastSt, Blk) = getLastStmt(CEBNode); // Generate a CallEvent /before/ cleaning the state, so that we can get the // correct value for 'this' (if necessary). @@ -282,7 +282,7 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { // they occurred. ExplodedNodeSet CleanedNodes; if (LastSt && Blk && AMgr.options.AnalysisPurgeOpt != PurgeNone) { - static SimpleProgramPointTag retValBind("ExprEngine : Bind Return Value"); + static SimpleProgramPointTag retValBind("ExprEngine", "Bind Return Value"); PostStmt Loc(LastSt, calleeCtx, &retValBind); bool isNew; ExplodedNode *BindedRetNode = G.getNode(Loc, state, false, &isNew); @@ -296,10 +296,10 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { // context, telling it to clean up everything in the callee's context // (and its children). We use the callee's function body as a diagnostic // statement, with which the program point will be associated. - removeDead(BindedRetNode, CleanedNodes, 0, calleeCtx, + removeDead(BindedRetNode, CleanedNodes, nullptr, calleeCtx, calleeCtx->getAnalysisDeclContext()->getBody(), ProgramPoint::PostStmtPurgeDeadSymbolsKind); - currBldrCtx = 0; + currBldrCtx = nullptr; } else { CleanedNodes.Add(CEBNode); } @@ -387,14 +387,14 @@ static bool IsInStdNamespace(const FunctionDecl *FD) { const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC); if (!ND) return false; - + while (const DeclContext *Parent = ND->getParent()) { if (!isa<NamespaceDecl>(Parent)) break; ND = cast<NamespaceDecl>(Parent); } - return ND->getName() == "std"; + return ND->isStdNamespace(); } // The GDM component containing the dynamic dispatch bifurcation info. When @@ -471,7 +471,7 @@ static ProgramStateRef getInlineFailedState(ProgramStateRef State, const Stmt *CallE) { const void *ReplayState = State->get<ReplayWithoutInlining>(); if (!ReplayState) - return 0; + return nullptr; assert(ReplayState == CallE && "Backtracked to the wrong call."); (void)CallE; @@ -565,7 +565,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, QualType ResultTy = Call.getResultType(); SValBuilder &SVB = getSValBuilder(); unsigned Count = currBldrCtx->blockCount(); - SVal R = SVB.conjureSymbolVal(0, E, LCtx, ResultTy, Count); + SVal R = SVB.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count); return State->BindExpr(E, LCtx, R); } @@ -664,6 +664,8 @@ static CallInlinePolicy mayInlineCallKind(const CallEvent &Call, break; } case CE_CXXAllocator: + if (Opts.mayInlineCXXAllocator()) + break; // Do not inline allocators until we model deallocators. // This is unfortunate, but basically necessary for smart pointers and such. return CIP_DisallowedAlways; @@ -706,18 +708,16 @@ static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD) { hasMember(Ctx, RD, "iterator_category"); } -/// Returns true if the given function refers to a constructor or destructor of -/// a C++ container or iterator. +/// Returns true if the given function refers to a method of a C++ container +/// or iterator. /// -/// We generally do a poor job modeling most containers right now, and would -/// prefer not to inline their setup and teardown. -static bool isContainerCtorOrDtor(const ASTContext &Ctx, - const FunctionDecl *FD) { - if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD))) - return false; - - const CXXRecordDecl *RD = cast<CXXMethodDecl>(FD)->getParent(); - return isContainerClass(Ctx, RD); +/// We generally do a poor job modeling most containers right now, and might +/// prefer not to inline their methods. +static bool isContainerMethod(const ASTContext &Ctx, + const FunctionDecl *FD) { + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) + return isContainerClass(Ctx, MD->getParent()); + return false; } /// Returns true if the given function is the destructor of a class named @@ -763,9 +763,9 @@ static bool mayInlineDecl(AnalysisDeclContext *CalleeADC, // Conditionally control the inlining of methods on objects that look // like C++ containers. - if (!Opts.mayInlineCXXContainerCtorsAndDtors()) + if (!Opts.mayInlineCXXContainerMethods()) if (!Ctx.getSourceManager().isInMainFile(FD->getLocation())) - if (isContainerCtorOrDtor(Ctx, FD)) + if (isContainerMethod(Ctx, FD)) return false; // Conditionally control the inlining of the destructor of C++ shared_ptr. diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp index d276d92446149..a6611e050dc9b 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp @@ -77,7 +77,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) { const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl()); - assert(elemD->getInit() == 0); + assert(elemD->getInit() == nullptr); elementV = state->getLValue(elemD, Pred->getLocationContext()); } else { @@ -85,7 +85,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, } ExplodedNodeSet dstLocation; - evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false); + evalLocation(dstLocation, S, elem, Pred, state, elementV, nullptr, false); ExplodedNodeSet Tmp; StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx); @@ -165,7 +165,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME, recVal.castAs<DefinedOrUnknownSVal>(); ProgramStateRef notNilState, nilState; - llvm::tie(notNilState, nilState) = State->assume(receiverVal); + std::tie(notNilState, nilState) = State->assume(receiverVal); // There are three cases: can be nil or non-nil, must be nil, must be // non-nil. We ignore must be nil, and merge the rest two into non-nil. diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index 365f6ab70de74..b1e9f06cae000 100644 --- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -20,11 +20,13 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Rewrite/Core/HTMLRewrite.h" #include "clang/Rewrite/Core/Rewriter.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include <sstream> using namespace clang; using namespace ento; @@ -39,15 +41,16 @@ class HTMLDiagnostics : public PathDiagnosticConsumer { std::string Directory; bool createdDir, noDir; const Preprocessor &PP; + AnalyzerOptions &AnalyzerOpts; public: - HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp); + HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, const Preprocessor &pp); - virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); } + virtual ~HTMLDiagnostics() { FlushDiagnostics(nullptr); } - virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, - FilesMade *filesMade); + void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, + FilesMade *filesMade) override; - virtual StringRef getName() const { + StringRef getName() const override { return "HTMLDiagnostics"; } @@ -68,16 +71,17 @@ public: } // end anonymous namespace -HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, +HTMLDiagnostics::HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, + const std::string& prefix, const Preprocessor &pp) - : Directory(prefix), createdDir(false), noDir(false), PP(pp) { + : Directory(prefix), createdDir(false), noDir(false), PP(pp), AnalyzerOpts(AnalyzerOpts) { } void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, const std::string& prefix, const Preprocessor &PP) { - C.push_back(new HTMLDiagnostics(prefix, PP)); + C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP)); } //===----------------------------------------------------------------------===// @@ -95,13 +99,11 @@ void HTMLDiagnostics::FlushDiagnosticsImpl( void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, FilesMade *filesMade) { - + // Create the HTML directory if it is missing. if (!createdDir) { createdDir = true; - bool existed; - if (llvm::error_code ec = - llvm::sys::fs::create_directories(Directory, existed)) { + if (std::error_code ec = llvm::sys::fs::create_directories(Directory)) { llvm::errs() << "warning: could not create directory '" << Directory << "': " << ec.message() << '\n'; @@ -128,11 +130,30 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, // Create a new rewriter to generate HTML. Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOpts()); + // Get the function/method name + SmallString<128> declName("unknown"); + int offsetDecl = 0; + if (const Decl *DeclWithIssue = D.getDeclWithIssue()) { + if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) { + declName = ND->getDeclName().getAsString(); + } + + if (const Stmt *Body = DeclWithIssue->getBody()) { + // Retrieve the relative position of the declaration which will be used + // for the file name + FullSourceLoc L( + SMgr.getExpansionLoc((*path.rbegin())->getLocation().asLocation()), + SMgr); + FullSourceLoc FunL(SMgr.getExpansionLoc(Body->getLocStart()), SMgr); + offsetDecl = L.getExpansionLineNumber() - FunL.getExpansionLineNumber(); + } + } + // Process the path. unsigned n = path.size(); unsigned max = n; - for (PathPieces::const_reverse_iterator I = path.rbegin(), + for (PathPieces::const_reverse_iterator I = path.rbegin(), E = path.rend(); I != E; ++I, --n) HandlePiece(R, FID, **I, n, max); @@ -165,6 +186,9 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, DirName += '/'; } + int LineNumber = (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber(); + int ColumnNumber = (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber(); + // Add the name of the file as an <h1> tag. { @@ -178,9 +202,9 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, << html::EscapeText(Entry->getName()) << "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>" "<a href=\"#EndPath\">line " - << (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber() + << LineNumber << ", column " - << (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber() + << ColumnNumber << "</a></td></tr>\n" "<tr><td class=\"rowname\">Description:</td><td>" << D.getVerboseDescription() << "</td></tr>\n"; @@ -217,12 +241,16 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n"; + os << "\n<!-- FILENAME " << llvm::sys::path::filename(Entry->getName()) << " -->\n"; + + os << "\n<!-- FUNCTIONNAME " << declName << " -->\n"; + os << "\n<!-- BUGLINE " - << path.back()->getLocation().asLocation().getExpansionLineNumber() + << LineNumber << " -->\n"; os << "\n<!-- BUGCOLUMN " - << path.back()->getLocation().asLocation().getExpansionColumnNumber() + << ColumnNumber << " -->\n"; os << "\n<!-- BUGPATHLENGTH " << path.size() << " -->\n"; @@ -249,13 +277,42 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, // Create a path for the target HTML file. int FD; SmallString<128> Model, ResultPath; - llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); - if (llvm::error_code EC = + if (!AnalyzerOpts.shouldWriteStableReportFilename()) { + llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); + + if (std::error_code EC = llvm::sys::fs::createUniqueFile(Model.str(), FD, ResultPath)) { - llvm::errs() << "warning: could not create file in '" << Directory - << "': " << EC.message() << '\n'; - return; + llvm::errs() << "warning: could not create file in '" << Directory + << "': " << EC.message() << '\n'; + return; + } + + } else { + int i = 1; + std::error_code EC; + do { + // Find a filename which is not already used + std::stringstream filename; + Model = ""; + filename << "report-" + << llvm::sys::path::filename(Entry->getName()).str() + << "-" << declName.c_str() + << "-" << offsetDecl + << "-" << i << ".html"; + llvm::sys::path::append(Model, Directory, + filename.str()); + EC = llvm::sys::fs::openFileForWrite(Model.str(), + FD, + llvm::sys::fs::F_RW | + llvm::sys::fs::F_Excl); + if (EC && EC != std::errc::file_exists) { + llvm::errs() << "warning: could not create file '" << Model.str() + << "': " << EC.message() << '\n'; + return; + } + i++; + } while (EC); } llvm::raw_fd_ostream os(FD, true); @@ -309,7 +366,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, // Create the html for the message. - const char *Kind = 0; + const char *Kind = nullptr; switch (P.getKind()) { case PathDiagnosticPiece::Call: llvm_unreachable("Calls should already be handled"); @@ -460,7 +517,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, << (num + 1) << ")\">→</a></div></td>"; } - + os << "</tr></table>"; } } diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index 162cd33264952..22711f54239ae 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -148,7 +148,7 @@ MemRegionManager::~MemRegionManager() { bool SubRegion::isSubRegionOf(const MemRegion* R) const { const MemRegion* r = getSuperRegion(); - while (r != 0) { + while (r != nullptr) { if (r == R) return true; if (const SubRegion* sr = dyn_cast<SubRegion>(r)) @@ -173,7 +173,7 @@ MemRegionManager* SubRegion::getMemRegionManager() const { const StackFrameContext *VarRegion::getStackFrame() const { const StackSpaceRegion *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace()); - return SSR ? SSR->getStackFrame() : NULL; + return SSR ? SSR->getStackFrame() : nullptr; } //===----------------------------------------------------------------------===// @@ -508,11 +508,13 @@ void ObjCIvarRegion::dumpToStream(raw_ostream &os) const { } void StringRegion::dumpToStream(raw_ostream &os) const { - Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOpts())); + assert(Str != nullptr && "Expecting non-null StringLiteral"); + Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts())); } void ObjCStringRegion::dumpToStream(raw_ostream &os) const { - Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOpts())); + assert(Str != nullptr && "Expecting non-null ObjCStringLiteral"); + Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts())); } void SymbolicRegion::dumpToStream(raw_ostream &os) const { @@ -757,12 +759,12 @@ getStackOrCaptureRegionForDeclContext(const LocationContext *LC, LC = LC->getParent(); } - return (const StackFrameContext*)0; + return (const StackFrameContext *)nullptr; } const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, const LocationContext *LC) { - const MemRegion *sReg = 0; + const MemRegion *sReg = nullptr; if (D->hasGlobalStorage() && !D->isStaticLocal()) { @@ -850,7 +852,7 @@ const BlockDataRegion * MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC, const LocationContext *LC, unsigned blockCount) { - const MemRegion *sReg = 0; + const MemRegion *sReg = nullptr; const BlockDecl *BD = BC->getDecl(); if (!BD->hasCaptures()) { // This handles 'static' blocks. @@ -877,14 +879,14 @@ MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC, const CXXTempObjectRegion * MemRegionManager::getCXXStaticTempObjectRegion(const Expr *Ex) { return getSubRegion<CXXTempObjectRegion>( - Ex, getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, NULL)); + Ex, getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, nullptr)); } const CompoundLiteralRegion* MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL, const LocationContext *LC) { - const MemRegion *sReg = 0; + const MemRegion *sReg = nullptr; if (CL->isFileScope()) sReg = getGlobalsRegion(); @@ -975,10 +977,8 @@ static bool isValidBaseClass(const CXXRecordDecl *BaseClass, if (IsVirtual) return Class->isVirtuallyDerivedFrom(BaseClass); - for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(), - E = Class->bases_end(); - I != E; ++I) { - if (I->getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass) + for (const auto &I : Class->bases()) { + if (I.getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass) return true; } @@ -1113,7 +1113,7 @@ const SymbolicRegion *MemRegion::getSymbolicBase() const { return SymR; SubR = dyn_cast<SubRegion>(SubR->getSuperRegion()); } - return 0; + return nullptr; } // FIXME: Merge with the implementation of the same method in Store.cpp @@ -1130,7 +1130,7 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { RegionRawOffset ElementRegion::getAsArrayOffset() const { CharUnits offset = CharUnits::Zero(); const ElementRegion *ER = this; - const MemRegion *superR = NULL; + const MemRegion *superR = nullptr; ASTContext &C = getContext(); // FIXME: Handle multi-dimensional arrays. @@ -1162,7 +1162,7 @@ RegionRawOffset ElementRegion::getAsArrayOffset() const { continue; } - return NULL; + return nullptr; } assert(superR && "super region cannot be NULL"); @@ -1176,10 +1176,8 @@ static bool isImmediateBase(const CXXRecordDecl *Child, // Note that we do NOT canonicalize the base class here, because // ASTRecordLayout doesn't either. If that leads us down the wrong path, // so be it; at least we won't crash. - for (CXXRecordDecl::base_class_const_iterator I = Child->bases_begin(), - E = Child->bases_end(); - I != E; ++I) { - if (I->getType()->getAsCXXRecordDecl() == Base) + for (const auto &I : Child->bases()) { + if (I.getType()->getAsCXXRecordDecl() == Base) return true; } @@ -1188,7 +1186,7 @@ static bool isImmediateBase(const CXXRecordDecl *Child, RegionOffset MemRegion::getAsOffset() const { const MemRegion *R = this; - const MemRegion *SymbolicOffsetBase = 0; + const MemRegion *SymbolicOffsetBase = nullptr; int64_t Offset = 0; while (1) { @@ -1360,10 +1358,10 @@ RegionOffset MemRegion::getAsOffset() const { std::pair<const VarRegion *, const VarRegion *> BlockDataRegion::getCaptureRegions(const VarDecl *VD) { MemRegionManager &MemMgr = *getMemRegionManager(); - const VarRegion *VR = 0; - const VarRegion *OriginalVR = 0; + const VarRegion *VR = nullptr; + const VarRegion *OriginalVR = nullptr; - if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage()) { + if (!VD->hasAttr<BlocksAttr>() && VD->hasLocalStorage()) { VR = MemMgr.getVarRegion(VD, this); OriginalVR = MemMgr.getVarRegion(VD, LC); } @@ -1386,7 +1384,7 @@ void BlockDataRegion::LazyInitializeReferencedVars() { AnalysisDeclContext *AC = getCodeRegion()->getAnalysisDeclContext(); AnalysisDeclContext::referenced_decls_iterator I, E; - llvm::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl()); + std::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl()); if (I == E) { ReferencedVars = (void*) 0x1; @@ -1404,9 +1402,9 @@ void BlockDataRegion::LazyInitializeReferencedVars() { new (BVOriginal) VarVec(BC, E - I); for ( ; I != E; ++I) { - const VarRegion *VR = 0; - const VarRegion *OriginalVR = 0; - llvm::tie(VR, OriginalVR) = getCaptureRegions(*I); + const VarRegion *VR = nullptr; + const VarRegion *OriginalVR = nullptr; + std::tie(VR, OriginalVR) = getCaptureRegions(*I); assert(VR); assert(OriginalVR); BV->push_back(VR, BC); @@ -1425,8 +1423,8 @@ BlockDataRegion::referenced_vars_begin() const { static_cast<BumpVector<const MemRegion*>*>(ReferencedVars); if (Vec == (void*) 0x1) - return BlockDataRegion::referenced_vars_iterator(0, 0); - + return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr); + BumpVector<const MemRegion*> *VecOriginal = static_cast<BumpVector<const MemRegion*>*>(OriginalVars); @@ -1442,8 +1440,8 @@ BlockDataRegion::referenced_vars_end() const { static_cast<BumpVector<const MemRegion*>*>(ReferencedVars); if (Vec == (void*) 0x1) - return BlockDataRegion::referenced_vars_iterator(0, 0); - + return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr); + BumpVector<const MemRegion*> *VecOriginal = static_cast<BumpVector<const MemRegion*>*>(OriginalVars); @@ -1458,7 +1456,7 @@ const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const { if (I.getCapturedRegion() == R) return I.getOriginalRegion(); } - return 0; + return nullptr; } //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index b504db6349ee6..fd25bd8e3af3a 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -16,6 +16,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/SourceManager.h" @@ -66,7 +67,7 @@ PathPieces::~PathPieces() {} void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, bool ShouldFlattenMacros) const { for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { - PathDiagnosticPiece *Piece = I->getPtr(); + PathDiagnosticPiece *Piece = I->get(); switch (Piece->getKind()) { case PathDiagnosticPiece::Call: { @@ -106,12 +107,13 @@ void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, PathDiagnostic::~PathDiagnostic() {} -PathDiagnostic::PathDiagnostic(const Decl *declWithIssue, +PathDiagnostic::PathDiagnostic(StringRef CheckName, const Decl *declWithIssue, StringRef bugtype, StringRef verboseDesc, StringRef shortDesc, StringRef category, PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique) - : DeclWithIssue(declWithIssue), + : CheckName(CheckName), + DeclWithIssue(declWithIssue), BugType(StripTrailingDots(bugtype)), VerboseDesc(StripTrailingDots(verboseDesc)), ShortDesc(StripTrailingDots(shortDesc)), @@ -127,7 +129,7 @@ getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, // If the call is within a macro, don't do anything (for now). if (CallLoc.isMacroID()) - return 0; + return nullptr; assert(SMgr.isInMainFile(CallLoc) && "The call piece should be in the main file."); @@ -138,7 +140,7 @@ getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, const PathPieces &Path = CP->path; if (Path.empty()) - return 0; + return nullptr; // Check if the last piece in the callee path is a call to a function outside // of the main file. @@ -148,14 +150,14 @@ getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, } // Otherwise, the last piece is in the main file. - return 0; + return nullptr; } void PathDiagnostic::resetDiagnosticLocationToMainFile() { if (path.empty()) return; - PathDiagnosticPiece *LastP = path.back().getPtr(); + PathDiagnosticPiece *LastP = path.back().get(); assert(LastP); const SourceManager &SMgr = LastP->getLocation().getManager(); @@ -196,8 +198,8 @@ PathDiagnosticConsumer::~PathDiagnosticConsumer() { } void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { - OwningPtr<PathDiagnostic> OwningD(D); - + std::unique_ptr<PathDiagnostic> OwningD(D); + if (!D || D->path.empty()) return; @@ -220,7 +222,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) { - const PathDiagnosticPiece *piece = I->getPtr(); + const PathDiagnosticPiece *piece = I->get(); FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); if (FID.isInvalid()) { @@ -258,7 +260,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { // Profile the node to see if we already have something matching it llvm::FoldingSetNodeID profile; D->Profile(profile); - void *InsertPos = 0; + void *InsertPos = nullptr; if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { // Keep the PathDiagnostic with the shorter path. @@ -274,8 +276,8 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { Diags.RemoveNode(orig); delete orig; } - - Diags.InsertNode(OwningD.take()); + + Diags.InsertNode(OwningD.release()); } static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y); @@ -415,17 +417,6 @@ static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { return b.getValue(); } -namespace { -struct CompareDiagnostics { - // Compare if 'X' is "<" than 'Y'. - bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { - if (X == Y) - return false; - return compare(*X, *Y); - } -}; -} - void PathDiagnosticConsumer::FlushDiagnostics( PathDiagnosticConsumer::FilesMade *Files) { if (flushed) @@ -443,8 +434,11 @@ void PathDiagnosticConsumer::FlushDiagnostics( // Sort the diagnostics so that they are always emitted in a deterministic // order. if (!BatchDiags.empty()) - std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics()); - + std::sort(BatchDiags.begin(), BatchDiags.end(), + [](const PathDiagnostic *X, const PathDiagnostic *Y) { + return X != Y && compare(*X, *Y); + }); + FlushDiagnosticsImpl(BatchDiags, Files); // Delete the flushed diagnostics. @@ -458,6 +452,11 @@ void PathDiagnosticConsumer::FlushDiagnostics( Diags.clear(); } +PathDiagnosticConsumer::FilesMade::~FilesMade() { + for (PDFileEntry &Entry : *this) + Entry.~PDFileEntry(); +} + void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, StringRef ConsumerName, StringRef FileName) { @@ -487,7 +486,7 @@ PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { void *InsertPos; PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); if (!Entry) - return 0; + return nullptr; return &Entry->files; } @@ -571,6 +570,7 @@ getLocationForCaller(const StackFrameContext *SFC, return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); } case CFGElement::TemporaryDtor: + case CFGElement::NewAllocator: llvm_unreachable("not yet implemented!"); } @@ -610,6 +610,14 @@ PathDiagnosticLocation } PathDiagnosticLocation + PathDiagnosticLocation::createConditionalColonLoc( + const ConditionalOperator *CO, + const SourceManager &SM) { + return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK); +} + + +PathDiagnosticLocation PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, const SourceManager &SM) { return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); @@ -654,7 +662,7 @@ PathDiagnosticLocation PathDiagnosticLocation::create(const ProgramPoint& P, const SourceManager &SMng) { - const Stmt* S = 0; + const Stmt* S = nullptr; if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { const CFGBlock *BSrc = BE->getSrc(); S = BSrc->getTerminatorCondition(); @@ -695,7 +703,7 @@ const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>()) return PIPP->getInitializer()->getInit(); - return 0; + return nullptr; } const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { @@ -722,7 +730,7 @@ const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { } } - return 0; + return nullptr; } PathDiagnosticLocation @@ -731,8 +739,12 @@ PathDiagnosticLocation assert(N && "Cannot create a location with a null node."); const Stmt *S = getStmt(N); - if (!S) + if (!S) { + // If this is an implicit call, return the implicit call point location. + if (Optional<PreImplicitCall> PIE = N->getLocationAs<PreImplicitCall>()) + return PathDiagnosticLocation(PIE->getLocation(), SM); S = getNextStmt(N); + } if (S) { ProgramPoint P = N->getLocation(); @@ -853,13 +865,13 @@ PathDiagnosticRange void PathDiagnosticLocation::flatten() { if (K == StmtK) { K = RangeK; - S = 0; - D = 0; + S = nullptr; + D = nullptr; } else if (K == DeclK) { K = SingleLocK; - S = 0; - D = 0; + S = nullptr; + D = nullptr; } } @@ -969,7 +981,7 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D, IntrusiveRefCntPtr<PathDiagnosticEventPiece> PathDiagnosticCallPiece::getCallEnterEvent() const { if (!Callee) - return 0; + return nullptr; SmallString<256> buf; llvm::raw_svector_ostream Out(buf); @@ -984,12 +996,12 @@ PathDiagnosticCallPiece::getCallEnterEvent() const { IntrusiveRefCntPtr<PathDiagnosticEventPiece> PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { if (!callEnterWithin.asLocation().isValid()) - return 0; + return nullptr; if (Callee->isImplicit() || !Callee->hasBody()) - return 0; + return nullptr; if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee)) if (MD->isDefaulted()) - return 0; + return nullptr; SmallString<256> buf; llvm::raw_svector_ostream Out(buf); @@ -1003,7 +1015,7 @@ PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { IntrusiveRefCntPtr<PathDiagnosticEventPiece> PathDiagnosticCallPiece::getCallExitEvent() const { if (NoExit) - return 0; + return nullptr; SmallString<256> buf; llvm::raw_svector_ostream Out(buf); @@ -1025,7 +1037,7 @@ PathDiagnosticCallPiece::getCallExitEvent() const { static void compute_path_size(const PathPieces &pieces, unsigned &size) { for (PathPieces::const_iterator it = pieces.begin(), et = pieces.end(); it != et; ++it) { - const PathDiagnosticPiece *piece = it->getPtr(); + const PathDiagnosticPiece *piece = it->get(); if (const PathDiagnosticCallPiece *cp = dyn_cast<PathDiagnosticCallPiece>(piece)) { compute_path_size(cp->path, size); diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index 5dca811722ac9..ba3ad2ef16c5e 100644 --- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -13,6 +13,7 @@ #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/PlistSupport.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" #include "clang/Lex/Preprocessor.h" @@ -21,12 +22,9 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace ento; - -typedef llvm::DenseMap<FileID, unsigned> FIDMap; - +using namespace markup; namespace { class PlistDiagnostics : public PathDiagnosticConsumer { @@ -42,15 +40,17 @@ namespace { virtual ~PlistDiagnostics() {} void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, - FilesMade *filesMade); - - virtual StringRef getName() const { + FilesMade *filesMade) override; + + virtual StringRef getName() const override { return "PlistDiagnostics"; } - PathGenerationScheme getGenerationScheme() const { return Extensive; } - bool supportsLogicalOpControlFlow() const { return true; } - virtual bool supportsCrossFileDiagnostics() const { + PathGenerationScheme getGenerationScheme() const override { + return Extensive; + } + bool supportsLogicalOpControlFlow() const override { return true; } + bool supportsCrossFileDiagnostics() const override { return SupportsCrossFileDiagnostics; } }; @@ -80,84 +80,6 @@ void ento::createPlistMultiFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, PP.getLangOpts(), true)); } -static void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V, - const SourceManager* SM, SourceLocation L) { - - FileID FID = SM->getFileID(SM->getExpansionLoc(L)); - FIDMap::iterator I = FIDs.find(FID); - if (I != FIDs.end()) return; - FIDs[FID] = V.size(); - V.push_back(FID); -} - -static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM, - SourceLocation L) { - FileID FID = SM.getFileID(SM.getExpansionLoc(L)); - FIDMap::const_iterator I = FIDs.find(FID); - assert(I != FIDs.end()); - return I->second; -} - -static raw_ostream &Indent(raw_ostream &o, const unsigned indent) { - for (unsigned i = 0; i < indent; ++i) o << ' '; - return o; -} - -static void EmitLocation(raw_ostream &o, const SourceManager &SM, - const LangOptions &LangOpts, - SourceLocation L, const FIDMap &FM, - unsigned indent, bool extend = false) { - - FullSourceLoc Loc(SM.getExpansionLoc(L), const_cast<SourceManager&>(SM)); - - // Add in the length of the token, so that we cover multi-char tokens. - unsigned offset = - extend ? Lexer::MeasureTokenLength(Loc, SM, LangOpts) - 1 : 0; - - Indent(o, indent) << "<dict>\n"; - Indent(o, indent) << " <key>line</key><integer>" - << Loc.getExpansionLineNumber() << "</integer>\n"; - Indent(o, indent) << " <key>col</key><integer>" - << Loc.getExpansionColumnNumber() + offset << "</integer>\n"; - Indent(o, indent) << " <key>file</key><integer>" - << GetFID(FM, SM, Loc) << "</integer>\n"; - Indent(o, indent) << "</dict>\n"; -} - -static void EmitLocation(raw_ostream &o, const SourceManager &SM, - const LangOptions &LangOpts, - const PathDiagnosticLocation &L, const FIDMap& FM, - unsigned indent, bool extend = false) { - EmitLocation(o, SM, LangOpts, L.asLocation(), FM, indent, extend); -} - -static void EmitRange(raw_ostream &o, const SourceManager &SM, - const LangOptions &LangOpts, - PathDiagnosticRange R, const FIDMap &FM, - unsigned indent) { - Indent(o, indent) << "<array>\n"; - EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1); - EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, !R.isPoint); - Indent(o, indent) << "</array>\n"; -} - -static raw_ostream &EmitString(raw_ostream &o, StringRef s) { - o << "<string>"; - for (StringRef::const_iterator I = s.begin(), E = s.end(); I != E; ++I) { - char c = *I; - switch (c) { - default: o << c; break; - case '&': o << "&"; break; - case '<': o << "<"; break; - case '>': o << ">"; break; - case '\'': o << "'"; break; - case '\"': o << """; break; - } - } - o << "</string>"; - return o; -} - static void ReportControlFlow(raw_ostream &o, const PathDiagnosticControlFlowPiece& P, const FIDMap& FM, @@ -185,11 +107,13 @@ static void ReportControlFlow(raw_ostream &o, // logic for clients. Indent(o, indent) << "<key>start</key>\n"; SourceLocation StartEdge = I->getStart().asRange().getBegin(); - EmitRange(o, SM, LangOpts, SourceRange(StartEdge, StartEdge), FM, indent+1); + EmitRange(o, SM, LangOpts, CharSourceRange::getTokenRange(StartEdge), FM, + indent + 1); Indent(o, indent) << "<key>end</key>\n"; SourceLocation EndEdge = I->getEnd().asRange().getBegin(); - EmitRange(o, SM, LangOpts, SourceRange(EndEdge, EndEdge), FM, indent+1); + EmitRange(o, SM, LangOpts, CharSourceRange::getTokenRange(EndEdge), FM, + indent + 1); --indent; Indent(o, indent) << "</dict>\n"; @@ -241,15 +165,16 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P, ++indent; for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { - EmitRange(o, SM, LangOpts, *I, FM, indent+1); + EmitRange(o, SM, LangOpts, CharSourceRange::getTokenRange(*I), FM, + indent + 1); } --indent; Indent(o, indent) << "</array>\n"; } // Output the call depth. - Indent(o, indent) << "<key>depth</key>" - << "<integer>" << depth << "</integer>\n"; + Indent(o, indent) << "<key>depth</key>"; + EmitInteger(o, depth) << '\n'; // Output the text. assert(!P.getString().empty()); @@ -367,7 +292,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl( // ranges of the diagnostics. FIDMap FM; SmallVector<FileID, 10> Fids; - const SourceManager* SM = 0; + const SourceManager* SM = nullptr; if (!Diags.empty()) SM = &(*(*Diags.begin())->path.begin())->getLocation().getManager(); @@ -386,13 +311,13 @@ void PlistDiagnostics::FlushDiagnosticsImpl( for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) { - const PathDiagnosticPiece *piece = I->getPtr(); - AddFID(FM, Fids, SM, piece->getLocation().asLocation()); + const PathDiagnosticPiece *piece = I->get(); + AddFID(FM, Fids, *SM, piece->getLocation().asLocation()); ArrayRef<SourceRange> Ranges = piece->getRanges(); for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { - AddFID(FM, Fids, SM, I->getBegin()); - AddFID(FM, Fids, SM, I->getEnd()); + AddFID(FM, Fids, *SM, I->getBegin()); + AddFID(FM, Fids, *SM, I->getEnd()); } if (const PathDiagnosticCallPiece *call = @@ -400,7 +325,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl( IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnterWithin = call->getCallEnterWithinCallerEvent(); if (callEnterWithin) - AddFID(FM, Fids, SM, callEnterWithin->getLocation().asLocation()); + AddFID(FM, Fids, *SM, callEnterWithin->getLocation().asLocation()); WorkList.push_back(&call->path); } @@ -414,17 +339,13 @@ void PlistDiagnostics::FlushDiagnosticsImpl( // Open the file. std::string ErrMsg; - llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg); + llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg, llvm::sys::fs::F_Text); if (!ErrMsg.empty()) { llvm::errs() << "warning: could not create file: " << OutputFile << '\n'; return; } - // Write the plist header. - o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" - "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" " - "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" - "<plist version=\"1.0\">\n"; + EmitPlistHeader(o); // Write the root object: a <dict> containing... // - "clang_version", the string representation of clang version @@ -436,11 +357,8 @@ void PlistDiagnostics::FlushDiagnosticsImpl( o << " <key>files</key>\n" " <array>\n"; - for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end(); - I!=E; ++I) { - o << " "; - EmitString(o, SM->getFileEntryForID(*I)->getName()) << '\n'; - } + for (FileID FID : Fids) + EmitString(o << " ", SM->getFileEntryForID(FID)->getName()) << '\n'; o << " </array>\n" " <key>diagnostics</key>\n" @@ -535,7 +453,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl( // Output the location of the bug. o << " <key>location</key>\n"; - EmitLocation(o, *SM, LangOpts, D->getLocation(), FM, 2); + EmitLocation(o, *SM, LangOpts, D->getLocation().asLocation(), FM, 2); // Output the diagnostic to the sub-diagnostic client, if any. if (!filesMade->empty()) { diff --git a/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h b/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h index ed64fcbec761e..c2af36f407044 100644 --- a/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h +++ b/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h @@ -33,7 +33,7 @@ public: assert(LCtx); } - virtual void print(raw_ostream &OS) const { + void print(raw_ostream &OS) const override { OS << "While analyzing stack: \n"; LCtx->dumpStack(OS, "\t"); } diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index 6e23668144063..1714a2744a1aa 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -175,7 +175,6 @@ ProgramState::invalidateRegionsImpl(ValueList Values, const CallEvent *Call) const { ProgramStateManager &Mgr = getStateManager(); SubEngine* Eng = Mgr.getOwningEngine(); - InvalidatedSymbols ConstIS; InvalidatedSymbols Invalidated; if (!IS) @@ -208,7 +207,7 @@ ProgramState::invalidateRegionsImpl(ValueList Values, const StoreRef &newStore = Mgr.StoreMgr->invalidateRegions(getStore(), Values, E, Count, LCtx, Call, - *IS, *ITraits, NULL, NULL); + *IS, *ITraits, nullptr, nullptr); return makeWithStore(newStore); } @@ -388,7 +387,7 @@ ProgramStateRef ProgramStateManager::getPersistentState(ProgramState &State) { if (ProgramState *I = StateSet.FindNodeOrInsertPos(ID, InsertPos)) return I; - ProgramState *newState = 0; + ProgramState *newState = nullptr; if (!freeStates.empty()) { newState = freeStates.back(); freeStates.pop_back(); diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index 3606e099cec2e..77578d378fb34 100644 --- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -45,7 +45,7 @@ public: return *second; } const llvm::APSInt *getConcreteValue() const { - return &From() == &To() ? &From() : NULL; + return &From() == &To() ? &From() : nullptr; } void Profile(llvm::FoldingSetNodeID &ID) const { @@ -98,7 +98,7 @@ public: /// constant then this method returns that value. Otherwise, it returns /// NULL. const llvm::APSInt* getConcreteValue() const { - return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : 0; + return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : nullptr; } private: @@ -290,35 +290,37 @@ public: ProgramStateRef assumeSymNE(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& Int, - const llvm::APSInt& Adjustment); + const llvm::APSInt& Adjustment) override; ProgramStateRef assumeSymEQ(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& Int, - const llvm::APSInt& Adjustment); + const llvm::APSInt& Adjustment) override; ProgramStateRef assumeSymLT(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& Int, - const llvm::APSInt& Adjustment); + const llvm::APSInt& Adjustment) override; ProgramStateRef assumeSymGT(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& Int, - const llvm::APSInt& Adjustment); + const llvm::APSInt& Adjustment) override; ProgramStateRef assumeSymGE(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& Int, - const llvm::APSInt& Adjustment); + const llvm::APSInt& Adjustment) override; ProgramStateRef assumeSymLE(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& Int, - const llvm::APSInt& Adjustment); + const llvm::APSInt& Adjustment) override; - const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) const; - ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym); + const llvm::APSInt* getSymVal(ProgramStateRef St, + SymbolRef sym) const override; + ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override; - ProgramStateRef removeDeadBindings(ProgramStateRef St, SymbolReaper& SymReaper); + ProgramStateRef removeDeadBindings(ProgramStateRef St, + SymbolReaper& SymReaper) override; void print(ProgramStateRef St, raw_ostream &Out, - const char* nl, const char *sep); + const char* nl, const char *sep) override; private: RangeSet::Factory F; @@ -334,7 +336,7 @@ ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) { const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St, SymbolRef sym) const { const ConstraintRangeTy::data_type *T = St->get<ConstraintRange>(sym); - return T ? T->getConcreteValue() : NULL; + return T ? T->getConcreteValue() : nullptr; } ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State, @@ -430,7 +432,7 @@ RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym, // [Int-Adjustment+1, Int-Adjustment-1] // Notice that the lower bound is greater than the upper bound. RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Upper, Lower); - return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New); + return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); } ProgramStateRef @@ -440,12 +442,12 @@ RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym, // Before we do any real work, see if the value can even show up. APSIntType AdjustmentType(Adjustment); if (AdjustmentType.testInRange(Int, true) != APSIntType::RTR_Within) - return NULL; + return nullptr; // [Int-Adjustment, Int-Adjustment] llvm::APSInt AdjInt = AdjustmentType.convert(Int) - Adjustment; RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, AdjInt, AdjInt); - return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New); + return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); } ProgramStateRef @@ -456,7 +458,7 @@ RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym, APSIntType AdjustmentType(Adjustment); switch (AdjustmentType.testInRange(Int, true)) { case APSIntType::RTR_Below: - return NULL; + return nullptr; case APSIntType::RTR_Within: break; case APSIntType::RTR_Above: @@ -467,14 +469,14 @@ RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym, llvm::APSInt ComparisonVal = AdjustmentType.convert(Int); llvm::APSInt Min = AdjustmentType.getMinValue(); if (ComparisonVal == Min) - return NULL; + return nullptr; llvm::APSInt Lower = Min-Adjustment; llvm::APSInt Upper = ComparisonVal-Adjustment; --Upper; RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper); - return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New); + return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); } ProgramStateRef @@ -489,21 +491,21 @@ RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym, case APSIntType::RTR_Within: break; case APSIntType::RTR_Above: - return NULL; + return nullptr; } // Special case for Int == Max. This is always false. llvm::APSInt ComparisonVal = AdjustmentType.convert(Int); llvm::APSInt Max = AdjustmentType.getMaxValue(); if (ComparisonVal == Max) - return NULL; + return nullptr; llvm::APSInt Lower = ComparisonVal-Adjustment; llvm::APSInt Upper = Max-Adjustment; ++Lower; RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper); - return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New); + return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); } ProgramStateRef @@ -518,7 +520,7 @@ RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym, case APSIntType::RTR_Within: break; case APSIntType::RTR_Above: - return NULL; + return nullptr; } // Special case for Int == Min. This is always feasible. @@ -532,7 +534,7 @@ RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym, llvm::APSInt Upper = Max-Adjustment; RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper); - return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New); + return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); } ProgramStateRef @@ -543,7 +545,7 @@ RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym, APSIntType AdjustmentType(Adjustment); switch (AdjustmentType.testInRange(Int, true)) { case APSIntType::RTR_Below: - return NULL; + return nullptr; case APSIntType::RTR_Within: break; case APSIntType::RTR_Above: @@ -561,7 +563,7 @@ RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym, llvm::APSInt Upper = ComparisonVal-Adjustment; RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper); - return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New); + return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); } //===------------------------------------------------------------------------=== diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index 0b519768aa049..3bbbb3430792b 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -104,7 +104,7 @@ public: Data == X.Data; } - LLVM_ATTRIBUTE_USED void dump() const; + void dump() const; }; } // end anonymous namespace @@ -133,9 +133,7 @@ namespace llvm { }; } // end llvm namespace -void BindingKey::dump() const { - llvm::errs() << *this; -} +LLVM_DUMP_METHOD void BindingKey::dump() const { llvm::errs() << *this; } //===----------------------------------------------------------------------===// // Actual Store type. @@ -224,9 +222,7 @@ public: } } - LLVM_ATTRIBUTE_USED void dump() const { - dump(llvm::errs(), "\n"); - } + LLVM_DUMP_METHOD void dump() const { dump(llvm::errs(), "\n"); } }; } // end anonymous namespace @@ -266,7 +262,7 @@ RegionBindingsRef RegionBindingsRef::addBinding(const MemRegion *R, const SVal *RegionBindingsRef::lookup(BindingKey K) const { const ClusterBindings *Cluster = lookup(K.getBaseRegion()); if (!Cluster) - return 0; + return nullptr; return Cluster->lookup(K); } @@ -376,9 +372,9 @@ public: /// version of that lvalue (i.e., a pointer to the first element of /// the array). This is called by ExprEngine when evaluating /// casts from arrays to pointers. - SVal ArrayToPointer(Loc Array, QualType ElementTy); + SVal ArrayToPointer(Loc Array, QualType ElementTy) override; - StoreRef getInitialStore(const LocationContext *InitLoc) { + StoreRef getInitialStore(const LocationContext *InitLoc) override { return StoreRef(RBFactory.getEmptyMap().getRootWithoutRetain(), *this); } @@ -400,24 +396,24 @@ public: InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits, InvalidatedRegions *Invalidated, - InvalidatedRegions *InvalidatedTopLevel); + InvalidatedRegions *InvalidatedTopLevel) override; bool scanReachableSymbols(Store S, const MemRegion *R, - ScanReachableSymbols &Callbacks); + ScanReachableSymbols &Callbacks) override; RegionBindingsRef removeSubRegionBindings(RegionBindingsConstRef B, const SubRegion *R); public: // Part of public interface to class. - virtual StoreRef Bind(Store store, Loc LV, SVal V) { + StoreRef Bind(Store store, Loc LV, SVal V) override { return StoreRef(bind(getRegionBindings(store), LV, V).asStore(), *this); } RegionBindingsRef bind(RegionBindingsConstRef B, Loc LV, SVal V); // BindDefault is only used to initialize a region with a default value. - StoreRef BindDefault(Store store, const MemRegion *R, SVal V) { + StoreRef BindDefault(Store store, const MemRegion *R, SVal V) override { RegionBindingsRef B = getRegionBindings(store); assert(!B.lookup(R, BindingKey::Direct)); @@ -471,20 +467,20 @@ public: // Part of public interface to class. /// \brief Create a new store with the specified binding removed. /// \param ST the original store, that is the basis for the new store. /// \param L the location whose binding should be removed. - virtual StoreRef killBinding(Store ST, Loc L); + StoreRef killBinding(Store ST, Loc L) override; - void incrementReferenceCount(Store store) { + void incrementReferenceCount(Store store) override { getRegionBindings(store).manualRetain(); } /// If the StoreManager supports it, decrement the reference count of /// the specified Store object. If the reference count hits 0, the memory /// associated with the object is recycled. - void decrementReferenceCount(Store store) { + void decrementReferenceCount(Store store) override { getRegionBindings(store).manualRelease(); } - - bool includedInBindings(Store store, const MemRegion *region) const; + + bool includedInBindings(Store store, const MemRegion *region) const override; /// \brief Return the value bound to specified location in a given state. /// @@ -499,7 +495,7 @@ public: // Part of public interface to class. /// return undefined /// else /// return symbolic - virtual SVal getBinding(Store S, Loc L, QualType T) { + SVal getBinding(Store S, Loc L, QualType T) override { return getBinding(getRegionBindings(S), L, T); } @@ -564,15 +560,16 @@ public: // Part of public interface to class. /// removeDeadBindings - Scans the RegionStore of 'state' for dead values. /// It returns a new Store with these values removed. StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx, - SymbolReaper& SymReaper); - + SymbolReaper& SymReaper) override; + //===------------------------------------------------------------------===// // Region "extents". //===------------------------------------------------------------------===// // FIXME: This method will soon be eliminated; see the note in Store.h. DefinedOrUnknownSVal getSizeInElements(ProgramStateRef state, - const MemRegion* R, QualType EleTy); + const MemRegion* R, + QualType EleTy) override; //===------------------------------------------------------------------===// // Utility methods. @@ -585,9 +582,9 @@ public: // Part of public interface to class. } void print(Store store, raw_ostream &Out, const char* nl, - const char *sep); + const char *sep) override; - void iterBindings(Store store, BindingsHandler& f) { + void iterBindings(Store store, BindingsHandler& f) override { RegionBindingsRef B = getRegionBindings(store); for (RegionBindingsRef::iterator I = B.begin(), E = B.end(); I != E; ++I) { const ClusterBindings &Cluster = I.getData(); @@ -1016,7 +1013,7 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR, BI != BE; ++BI) { const VarRegion *VR = BI.getCapturedRegion(); const VarDecl *VD = VR->getDecl(); - if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage()) { + if (VD->hasAttr<BlocksAttr>() || !VD->hasLocalStorage()) { AddToWorkList(VR); } else if (Loc::isLocType(VR->getValueType())) { @@ -1628,9 +1625,9 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B, // getBindingForField if 'R' has a direct binding. // Lazy binding? - Store lazyBindingStore = NULL; - const SubRegion *lazyBindingRegion = NULL; - llvm::tie(lazyBindingStore, lazyBindingRegion) = findLazyBinding(B, R, R); + Store lazyBindingStore = nullptr; + const SubRegion *lazyBindingRegion = nullptr; + std::tie(lazyBindingStore, lazyBindingRegion) = findLazyBinding(B, R, R); if (lazyBindingRegion) return getLazyBinding(lazyBindingRegion, getRegionBindings(lazyBindingStore)); @@ -1791,7 +1788,7 @@ RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) { // values to return. const ClusterBindings *Cluster = B.lookup(LazyR->getBaseRegion()); if (!Cluster) - return (LazyBindingsMap[LCV.getCVData()] = llvm_move(List)); + return (LazyBindingsMap[LCV.getCVData()] = std::move(List)); SmallVector<BindingPair, 32> Bindings; collectSubRegionBindings(Bindings, svalBuilder, *Cluster, LazyR, @@ -1813,7 +1810,7 @@ RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) { List.push_back(V); } - return (LazyBindingsMap[LCV.getCVData()] = llvm_move(List)); + return (LazyBindingsMap[LCV.getCVData()] = std::move(List)); } NonLoc RegionStoreManager::createLazyBinding(RegionBindingsConstRef B, @@ -2066,9 +2063,7 @@ RegionStoreManager::tryBindSmallStruct(RegionBindingsConstRef B, if (Class->getNumBases() != 0 || Class->getNumVBases() != 0) return None; - for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); - I != E; ++I) { - const FieldDecl *FD = *I; + for (const auto *FD : RD->fields()) { if (FD->isUnnamedBitfield()) continue; @@ -2081,7 +2076,7 @@ RegionStoreManager::tryBindSmallStruct(RegionBindingsConstRef B, if (!(Ty->isScalarType() || Ty->isReferenceType())) return None; - Fields.push_back(*I); + Fields.push_back(FD); } RegionBindingsRef NewB = B; @@ -2296,7 +2291,7 @@ bool removeDeadBindingsWorker::UpdatePostponed() { if (const SymbolicRegion *SR = *I) { if (SymReaper.isLive(SR->getSymbol())) { changed |= AddToWorkList(SR); - *I = NULL; + *I = nullptr; } } } diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp index adc54659911ae..3ed2bde1e4f84 100644 --- a/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -362,7 +362,7 @@ SVal SValBuilder::evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, DefinedOrUnknownSVal SValBuilder::evalEQ(ProgramStateRef state, DefinedOrUnknownSVal lhs, DefinedOrUnknownSVal rhs) { - return evalBinOp(state, BO_EQ, lhs, rhs, Context.IntTy) + return evalBinOp(state, BO_EQ, lhs, rhs, getConditionType()) .castAs<DefinedOrUnknownSVal>(); } @@ -376,7 +376,7 @@ static bool shouldBeModeledWithNoOp(ASTContext &Context, QualType ToTy, ToTy = Context.getUnqualifiedArrayType(ToTy, Quals1); FromTy = Context.getUnqualifiedArrayType(FromTy, Quals2); - // Make sure that non cvr-qualifiers the other qualifiers (e.g., address + // Make sure that non-cvr-qualifiers the other qualifiers (e.g., address // spaces) are identical. Quals1.removeCVRQualifiers(); Quals2.removeCVRQualifiers(); diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp index 650691535f7e6..8de939f47d86f 100644 --- a/lib/StaticAnalyzer/Core/SVals.cpp +++ b/lib/StaticAnalyzer/Core/SVals.cpp @@ -56,7 +56,7 @@ const FunctionDecl *SVal::getAsFunctionDecl() const { return FD; } - return 0; + return nullptr; } /// \brief If this SVal is a location (subclasses Loc) and wraps a symbol, @@ -78,7 +78,7 @@ SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const { dyn_cast<SymbolicRegion>(R->StripCasts())) return SymR->getSymbol(); } - return 0; + return nullptr; } /// Get the symbol in the SVal or its base region. @@ -86,7 +86,7 @@ SymbolRef SVal::getLocSymbolInBase() const { Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>(); if (!X) - return 0; + return nullptr; const MemRegion *R = X->getRegion(); @@ -97,7 +97,7 @@ SymbolRef SVal::getLocSymbolInBase() const { R = SR->getSuperRegion(); } - return 0; + return nullptr; } // TODO: The next 3 functions have to be simplified. @@ -139,12 +139,12 @@ const MemRegion *SVal::getAsRegion() const { if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>()) return X->getLoc().getAsRegion(); - return 0; + return nullptr; } const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const { const MemRegion *R = getRegion(); - return R ? R->StripCasts(StripBaseCasts) : NULL; + return R ? R->StripCasts(StripBaseCasts) : nullptr; } const void *nonloc::LazyCompoundVal::getStore() const { diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp index e6653ae6e4b56..35930e47f82a0 100644 --- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp +++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp @@ -181,7 +181,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state, case nonloc::ConcreteIntKind: { bool b = Cond.castAs<nonloc::ConcreteInt>().getValue() != 0; bool isFeasible = b ? Assumption : !Assumption; - return isFeasible ? state : NULL; + return isFeasible ? state : nullptr; } case nonloc::LocAsIntegerKind: diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h index 28a9a4ded9dec..21e2283511ae7 100644 --- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h +++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h @@ -34,7 +34,7 @@ public: //===------------------------------------------------------------------===// ProgramStateRef assume(ProgramStateRef state, DefinedSVal Cond, - bool Assumption); + bool Assumption) override; ProgramStateRef assume(ProgramStateRef state, NonLoc Cond, bool Assumption); @@ -82,7 +82,7 @@ protected: BasicValueFactory &getBasicVals() const { return SVB.getBasicValueFactory(); } SymbolManager &getSymbolManager() const { return SVB.getSymbolManager(); } - bool canReasonAbout(SVal X) const; + bool canReasonAbout(SVal X) const override; ProgramStateRef assumeAux(ProgramStateRef state, NonLoc Cond, diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index cc0ee0b5c7a91..df9e4d6f91997 100644 --- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -21,9 +21,9 @@ using namespace ento; namespace { class SimpleSValBuilder : public SValBuilder { protected: - virtual SVal dispatchCast(SVal val, QualType castTy); - virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy); - virtual SVal evalCastFromLoc(Loc val, QualType castTy); + SVal dispatchCast(SVal val, QualType castTy) override; + SVal evalCastFromNonLoc(NonLoc val, QualType castTy) override; + SVal evalCastFromLoc(Loc val, QualType castTy) override; public: SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context, @@ -31,19 +31,19 @@ public: : SValBuilder(alloc, context, stateMgr) {} virtual ~SimpleSValBuilder() {} - virtual SVal evalMinus(NonLoc val); - virtual SVal evalComplement(NonLoc val); - virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, - NonLoc lhs, NonLoc rhs, QualType resultTy); - virtual SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op, - Loc lhs, Loc rhs, QualType resultTy); - virtual SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op, - Loc lhs, NonLoc rhs, QualType resultTy); + SVal evalMinus(NonLoc val) override; + SVal evalComplement(NonLoc val) override; + SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, + NonLoc lhs, NonLoc rhs, QualType resultTy) override; + SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op, + Loc lhs, Loc rhs, QualType resultTy) override; + SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op, + Loc lhs, NonLoc rhs, QualType resultTy) override; /// getKnownValue - evaluates a given SVal. If the SVal has only one possible /// (integer) value, that value is returned. Otherwise, returns NULL. - virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal V); - + const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal V) override; + SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op, const llvm::APSInt &RHS, QualType resultTy); }; @@ -97,7 +97,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { return UnknownVal(); } - // If value is a non integer constant, produce unknown. + // If value is a non-integer constant, produce unknown. if (!val.getAs<nonloc::ConcreteInt>()) return UnknownVal(); @@ -108,7 +108,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { } // Only handle casts from integers to integers - if val is an integer constant - // being cast to a non integer type, produce unknown. + // being cast to a non-integer type, produce unknown. if (!isLocType && !castTy->isIntegralOrEnumerationType()) return UnknownVal(); @@ -158,7 +158,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) { } case loc::GotoLabelKind: - // Labels and non symbolic memory regions are always true. + // Labels and non-symbolic memory regions are always true. return makeTruthVal(true, castTy); } } @@ -569,11 +569,10 @@ static SVal evalBinOpFieldRegionFieldRegion(const FieldRegion *LeftFR, // members and the units in which bit-fields reside have addresses that // increase in the order in which they are declared." bool leftFirst = (op == BO_LT || op == BO_LE); - for (RecordDecl::field_iterator I = RD->field_begin(), - E = RD->field_end(); I!=E; ++I) { - if (*I == LeftFD) + for (const auto *I : RD->fields()) { + if (I == LeftFD) return SVB.makeTruthVal(leftFirst, resultTy); - if (*I == RightFD) + if (I == RightFD) return SVB.makeTruthVal(!leftFirst, resultTy); } @@ -818,7 +817,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state, RegionOffset LeftOffset = LeftMR->getAsOffset(); RegionOffset RightOffset = RightMR->getAsOffset(); - if (LeftOffset.getRegion() != NULL && + if (LeftOffset.getRegion() != nullptr && LeftOffset.getRegion() == RightOffset.getRegion() && !LeftOffset.hasSymbolicOffset() && !RightOffset.hasSymbolicOffset()) { int64_t left = LeftOffset.getOffset(); @@ -901,7 +900,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state, if (const MemRegion *region = lhs.getAsRegion()) { rhs = convertToArrayIndex(rhs).castAs<NonLoc>(); SVal index = UnknownVal(); - const MemRegion *superR = 0; + const MemRegion *superR = nullptr; QualType elementType; if (const ElementRegion *elemReg = dyn_cast<ElementRegion>(region)) { @@ -929,7 +928,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state, const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state, SVal V) { if (V.isUnknownOrUndef()) - return NULL; + return nullptr; if (Optional<loc::ConcreteInt> X = V.getAs<loc::ConcreteInt>()) return &X->getValue(); @@ -941,5 +940,5 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state, return state->getConstraintManager().getSymVal(state, Sym); // FIXME: Add support for SymExprs. - return NULL; + return nullptr; } diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp index 0beb9dbbc5be6..e38be3e0b7dd9 100644 --- a/lib/StaticAnalyzer/Core/Store.cpp +++ b/lib/StaticAnalyzer/Core/Store.cpp @@ -88,7 +88,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) // We don't know what to make of it. Return a NULL region, which // will be interpretted as UnknownVal. - return NULL; + return nullptr; } // Now assume we are casting from pointer to pointer. Other cases should @@ -166,7 +166,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) // If we cannot compute a raw offset, throw up our hands and return // a NULL MemRegion*. if (!baseR) - return NULL; + return nullptr; CharUnits off = rawOff.getOffset(); @@ -193,7 +193,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) // Compute the index for the new ElementRegion. int64_t newIndex = 0; - const MemRegion *newSuperR = 0; + const MemRegion *newSuperR = nullptr; // We can only compute sizeof(PointeeTy) if it is a complete type. if (IsCompleteType(Ctx, PointeeTy)) { @@ -300,7 +300,7 @@ static const CXXRecordDecl *getCXXRecordType(const MemRegion *MR) { return TVR->getValueType()->getAsCXXRecordDecl(); if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) return SR->getSymbol()->getType()->getPointeeCXXRecordDecl(); - return 0; + return nullptr; } SVal StoreManager::evalDynamicCast(SVal Base, QualType TargetType, @@ -401,7 +401,7 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) { return Base; Loc BaseL = Base.castAs<Loc>(); - const MemRegion* BaseR = 0; + const MemRegion* BaseR = nullptr; switch (BaseL.getSubKind()) { case loc::MemRegionKind: diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp index 1b56f82dc60fc..cca0461a47486 100644 --- a/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -326,11 +326,7 @@ QualType SymbolRegionValue::getType() const { } SymbolManager::~SymbolManager() { - for (SymbolDependTy::const_iterator I = SymbolDependencies.begin(), - E = SymbolDependencies.end(); I != E; ++I) { - delete I->second; - } - + llvm::DeleteContainerSeconds(SymbolDependencies); } bool SymbolManager::canSymbolicate(QualType T) { @@ -351,7 +347,7 @@ bool SymbolManager::canSymbolicate(QualType T) { void SymbolManager::addSymbolDependency(const SymbolRef Primary, const SymbolRef Dependent) { SymbolDependTy::iterator I = SymbolDependencies.find(Primary); - SymbolRefSmallVectorTy *dependencies = 0; + SymbolRefSmallVectorTy *dependencies = nullptr; if (I == SymbolDependencies.end()) { dependencies = new SymbolRefSmallVectorTy(); SymbolDependencies[Primary] = dependencies; @@ -365,7 +361,7 @@ const SymbolRefSmallVectorTy *SymbolManager::getDependentSymbols( const SymbolRef Primary) { SymbolDependTy::const_iterator I = SymbolDependencies.find(Primary); if (I == SymbolDependencies.end()) - return 0; + return nullptr; return I->second; } @@ -491,7 +487,7 @@ bool SymbolReaper::isLive(SymbolRef sym) { bool SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const { - if (LCtx == 0) + if (LCtx == nullptr) return false; if (LCtx != ELCtx) { |