diff options
Diffstat (limited to 'include/clang/StaticAnalyzer/Core')
20 files changed, 264 insertions, 177 deletions
diff --git a/include/clang/StaticAnalyzer/Core/Analyses.def b/include/clang/StaticAnalyzer/Core/Analyses.def index dc79450..3355f4b 100644 --- a/include/clang/StaticAnalyzer/Core/Analyses.def +++ b/include/clang/StaticAnalyzer/Core/Analyses.def @@ -24,14 +24,14 @@ ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateR ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager) #ifndef ANALYSIS_DIAGNOSTICS -#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) #endif -ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer, false) -ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer, true) -ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for mult-file bugs)", createPlistMultiFileDiagnosticConsumer, true) -ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer, true) -ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer, true) +ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for mult-file bugs)", createPlistMultiFileDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer) #ifndef ANALYSIS_PURGE #define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index fb35f51..618782e 100644 --- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -52,7 +52,7 @@ NumConstraints /// AnalysisDiagClients - Set of available diagnostic clients for rendering /// analysis results. enum AnalysisDiagClients { -#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) PD_##NAME, +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN) PD_##NAME, #include "clang/StaticAnalyzer/Core/Analyses.def" NUM_ANALYSIS_DIAG_CLIENTS }; @@ -201,6 +201,9 @@ private: /// \sa mayInlineCXXContainerCtorsAndDtors Optional<bool> InlineCXXContainerCtorsAndDtors; + /// \sa mayInlineCXXSharedPtrDtor + Optional<bool> InlineCXXSharedPtrDtor; + /// \sa mayInlineObjCMethod Optional<bool> ObjCInliningMode; @@ -223,6 +226,9 @@ private: /// \sa shouldSuppressFromCXXStandardLibrary Optional<bool> SuppressFromCXXStandardLibrary; + /// \sa reportIssuesInMainSourceFile + Optional<bool> ReportIssuesInMainSourceFile; + /// \sa getGraphTrimInterval Optional<unsigned> GraphTrimInterval; @@ -291,6 +297,16 @@ public: /// accepts the values "true" and "false". bool mayInlineCXXContainerCtorsAndDtors(); + /// Returns whether or not the destructor of C++ 'shared_ptr' may be + /// considered for inlining. + /// + /// This covers std::shared_ptr, std::tr1::shared_ptr, and boost::shared_ptr, + /// and indeed any destructor named "~shared_ptr". + /// + /// This is controlled by the 'c++-shared_ptr-inlining' config option, which + /// accepts the values "true" and "false". + bool mayInlineCXXSharedPtrDtor(); + /// Returns whether or not paths that go through null returns should be /// suppressed. /// @@ -326,6 +342,13 @@ public: /// which accepts the values "true" and "false". bool shouldSuppressFromCXXStandardLibrary(); + /// Returns whether or not the diagnostic report should be always reported + /// in the main source file and not the headers. + /// + /// This is controlled by the 'report-in-main-source-file' config option, + /// which accepts the values "true" and "false". + bool shouldReportIssuesInMainSourceFile(); + /// Returns whether irrelevant parts of a bug report path should be pruned /// out of the final output. /// diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 5c560b2..9584b8b 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_GR_BUGREPORTER #include "clang/Basic/SourceLocation.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" @@ -375,6 +376,7 @@ public: virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0; virtual ASTContext &getASTContext() = 0; virtual SourceManager& getSourceManager() = 0; + virtual AnalyzerOptions& getAnalyzerOptions() = 0; }; /// BugReporter is a utility class for generating PathDiagnostics for analysis. @@ -442,6 +444,8 @@ public: SourceManager& getSourceManager() { return D.getSourceManager(); } + AnalyzerOptions& getAnalyzerOptions() { return D.getAnalyzerOptions(); } + virtual bool generatePathDiagnostic(PathDiagnostic& pathDiagnostic, PathDiagnosticConsumer &PC, ArrayRef<BugReport *> &bugReports) { @@ -462,20 +466,7 @@ public: void EmitBasicReport(const Decl *DeclWithIssue, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, - SourceRange* RangeBeg, unsigned NumRanges); - - void EmitBasicReport(const Decl *DeclWithIssue, - StringRef BugName, StringRef BugCategory, - StringRef BugStr, PathDiagnosticLocation Loc) { - EmitBasicReport(DeclWithIssue, BugName, BugCategory, BugStr, Loc, 0, 0); - } - - void EmitBasicReport(const Decl *DeclWithIssue, - StringRef BugName, StringRef Category, - StringRef BugStr, PathDiagnosticLocation Loc, - SourceRange R) { - EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1); - } + ArrayRef<SourceRange> Ranges = None); private: llvm::StringMap<BugType *> StrBugTypes; diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h index 644aa31..49f9c83 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_ANALYSIS_BUGTYPE #define LLVM_CLANG_ANALYSIS_BUGTYPE +#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/FoldingSet.h" #include <string> @@ -31,10 +32,12 @@ private: const std::string Name; const std::string Category; bool SuppressonSink; + + virtual void anchor(); public: BugType(StringRef name, StringRef cat) : Name(name), Category(cat), SuppressonSink(false) {} - virtual ~BugType(); + virtual ~BugType() {} // FIXME: Should these be made strings as well? StringRef getName() const { return Name; } @@ -50,14 +53,14 @@ public: }; class BuiltinBug : public BugType { - virtual void anchor(); const std::string desc; + virtual void anchor(); public: BuiltinBug(const char *name, const char *description) - : BugType(name, "Logic error"), desc(description) {} + : BugType(name, categories::LogicError), desc(description) {} BuiltinBug(const char *name) - : BugType(name, "Logic error"), desc(name) {} + : BugType(name, categories::LogicError), desc(name) {} StringRef getDescription() const { return desc; } }; diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h new file mode 100644 index 0000000..3f0fe96 --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h @@ -0,0 +1,25 @@ +//=--- CommonBugCategories.h - Provides common issue categories -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATIC_ANALYZER_BUG_CATEGORIES_H +#define LLVM_CLANG_STATIC_ANALYZER_BUG_CATEGORIES_H + +// Common strings used for the "category" of many static analyzer issues. +namespace clang { + namespace ento { + namespace categories { + extern const char * const CoreFoundationObjectiveC; + extern const char * const LogicError; + extern const char * const MemoryCoreFoundationObjectiveC; + extern const char * const UnixAPI; + } + } +} +#endif + diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index a80b5a7..b0670da 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -38,6 +38,7 @@ class ParentMap; class ProgramPoint; class SourceManager; class Stmt; +class CallExpr; namespace ento { @@ -97,7 +98,6 @@ public: enum PathGenerationScheme { None, Minimal, Extensive, AlternateExtensive }; virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } virtual bool supportsLogicalOpControlFlow() const { return false; } - virtual bool supportsAllBlockEdges() const { return false; } /// Return true if the PathDiagnosticConsumer supports individual /// PathDiagnostics that span multiple files. @@ -285,11 +285,13 @@ public: void Profile(llvm::FoldingSetNodeID &ID) const; + void dump() const; + /// \brief Given an exploded node, retrieve the statement that should be used /// for the diagnostic location. static const Stmt *getStmt(const ExplodedNode *N); - /// \brief Retrieve the statement corresponding to the sucessor node. + /// \brief Retrieve the statement corresponding to the successor node. static const Stmt *getNextStmt(const ExplodedNode *N); }; @@ -331,6 +333,10 @@ private: const std::string str; const Kind kind; const DisplayHint Hint; + + /// \brief In the containing bug report, this piece is the last piece from + /// the main source file. + bool LastInMainSourceFile; /// A constant string that can be used to tag the PathDiagnosticPiece, /// typically with the identification of the creator. The actual pointer @@ -389,6 +395,16 @@ public: ArrayRef<SourceRange> getRanges() const { return ranges; } virtual void Profile(llvm::FoldingSetNodeID &ID) const; + + void setAsLastInMainSourceFile() { + LastInMainSourceFile = true; + } + + bool isLastInMainSourceFile() const { + return LastInMainSourceFile; + } + + virtual void dump() const = 0; }; @@ -403,6 +419,8 @@ public: flattenTo(Result, Result, ShouldFlattenMacros); return Result; } + + LLVM_ATTRIBUTE_USED void dump() const; }; class PathDiagnosticSpotPiece : public PathDiagnosticPiece { @@ -421,7 +439,7 @@ public: PathDiagnosticLocation getLocation() const { return Pos; } virtual void flattenLocations() { Pos.flatten(); } - + virtual void Profile(llvm::FoldingSetNodeID &ID) const; static bool classof(const PathDiagnosticPiece *P) { @@ -504,7 +522,7 @@ public: } bool hasCallStackHint() { - return (CallStackHint != 0); + return CallStackHint.isValid(); } /// Produce the hint for the given node. The node contains @@ -515,6 +533,8 @@ public: return ""; } + virtual void dump() const; + static inline bool classof(const PathDiagnosticPiece *P) { return P->getKind() == Event; } @@ -582,6 +602,8 @@ public: static PathDiagnosticCallPiece *construct(PathPieces &pieces, const Decl *caller); + virtual void dump() const; + virtual void Profile(llvm::FoldingSetNodeID &ID) const; static inline bool classof(const PathDiagnosticPiece *P) { @@ -649,7 +671,9 @@ public: static inline bool classof(const PathDiagnosticPiece *P) { return P->getKind() == ControlFlow; } - + + virtual void dump() const; + virtual void Profile(llvm::FoldingSetNodeID &ID) const; }; @@ -673,7 +697,9 @@ public: static inline bool classof(const PathDiagnosticPiece *P) { return P->getKind() == Macro; } - + + virtual void dump() const; + virtual void Profile(llvm::FoldingSetNodeID &ID) const; }; @@ -687,7 +713,10 @@ class PathDiagnostic : public llvm::FoldingSetNode { std::string ShortDesc; std::string Category; std::deque<std::string> OtherDesc; + + /// \brief Loc The location of the path diagnostic report. PathDiagnosticLocation Loc; + PathPieces pathImpl; SmallVector<PathPieces *, 3> pathStack; @@ -735,12 +764,23 @@ public: getActivePath().push_back(EndPiece); } + void appendToDesc(StringRef S) { + if (!ShortDesc.empty()) + ShortDesc.append(S); + VerboseDesc.append(S); + } + void resetPath() { pathStack.clear(); pathImpl.clear(); Loc = PathDiagnosticLocation(); } - + + /// \brief If the last piece of the report point to the header file, resets + /// the location of the report to be the last location in the main source + /// file. + void resetDiagnosticLocationToMainFile(); + StringRef getVerboseDescription() const { return VerboseDesc; } StringRef getShortDescription() const { return ShortDesc.empty() ? VerboseDesc : ShortDesc; @@ -759,7 +799,7 @@ public: void addMeta(StringRef s) { OtherDesc.push_back(s); } PathDiagnosticLocation getLocation() const { - assert(Loc.isValid() && "No end-of-path location set yet!"); + assert(Loc.isValid() && "No report location set yet!"); return Loc; } diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h index 0dbaab0..cf7cf05 100644 --- a/include/clang/StaticAnalyzer/Core/Checker.h +++ b/include/clang/StaticAnalyzer/Core/Checker.h @@ -320,18 +320,35 @@ public: class PointerEscape { template <typename CHECKER> static ProgramStateRef - _checkPointerEscape(void *checker, + _checkPointerEscape(void *Checker, ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind, - bool IsConst) { - if (!IsConst) - return ((const CHECKER *)checker)->checkPointerEscape(State, + RegionAndSymbolInvalidationTraits *ETraits) { + + if (!ETraits) + return ((const CHECKER *)Checker)->checkPointerEscape(State, Escaped, Call, Kind); - return State; + + InvalidatedSymbols RegularEscape; + for (InvalidatedSymbols::const_iterator I = Escaped.begin(), + E = Escaped.end(); I != E; ++I) + if (!ETraits->hasTrait(*I, + RegionAndSymbolInvalidationTraits::TK_PreserveContents) && + !ETraits->hasTrait(*I, + RegionAndSymbolInvalidationTraits::TK_SuppressEscape)) + RegularEscape.insert(*I); + + if (RegularEscape.empty()) + return State; + + return ((const CHECKER *)Checker)->checkPointerEscape(State, + RegularEscape, + Call, + Kind); } public: @@ -346,18 +363,32 @@ public: class ConstPointerEscape { template <typename CHECKER> static ProgramStateRef - _checkConstPointerEscape(void *checker, + _checkConstPointerEscape(void *Checker, ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind, - bool IsConst) { - if (IsConst) - return ((const CHECKER *)checker)->checkConstPointerEscape(State, - Escaped, - Call, - Kind); - return State; + RegionAndSymbolInvalidationTraits *ETraits) { + + if (!ETraits) + return State; + + InvalidatedSymbols ConstEscape; + for (InvalidatedSymbols::const_iterator I = Escaped.begin(), + E = Escaped.end(); I != E; ++I) + if (ETraits->hasTrait(*I, + RegionAndSymbolInvalidationTraits::TK_PreserveContents) && + !ETraits->hasTrait(*I, + RegionAndSymbolInvalidationTraits::TK_SuppressEscape)) + ConstEscape.insert(*I); + + if (ConstEscape.empty()) + return State; + + return ((const CHECKER *)Checker)->checkConstPointerEscape(State, + ConstEscape, + Call, + Kind); } public: @@ -502,10 +533,14 @@ struct ImplicitNullDerefEvent { }; /// \brief A helper class which wraps a boolean value set to false by default. +/// +/// This class should behave exactly like 'bool' except that it doesn't need to +/// be explicitly initialized. struct DefaultBool { bool val; DefaultBool() : val(false) {} - operator bool() const { return val; } + /*implicit*/ operator bool&() { return val; } + /*implicit*/ operator const bool&() const { return val; } DefaultBool &operator=(bool b) { val = b; return *this; } }; diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index b2411e6..8ad67c1 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -19,7 +19,6 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallVector.h" #include <vector> @@ -366,14 +365,16 @@ public: /// \param Escaped The list of escaped symbols. /// \param Call The corresponding CallEvent, if the symbols escape as /// parameters to the given call. - /// \param IsConst Specifies if the pointer is const. + /// \param Kind The reason of pointer escape. + /// \param ITraits Information about invalidation for a particular + /// region/symbol. /// \returns Checkers can modify the state by returning a new one. ProgramStateRef runCheckersForPointerEscape(ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind, - bool IsConst = false); + RegionAndSymbolInvalidationTraits *ITraits); /// \brief Run checkers for handling assumptions on symbolic values. ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state, @@ -465,7 +466,7 @@ public: const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind, - bool IsConst)> + RegionAndSymbolInvalidationTraits *ITraits)> CheckPointerEscapeFunc; typedef CheckerFn<ProgramStateRef (ProgramStateRef, @@ -581,35 +582,12 @@ private: }; std::vector<StmtCheckerInfo> StmtCheckers; - struct CachedStmtCheckersKey { - unsigned StmtKind; - bool IsPreVisit; - - CachedStmtCheckersKey() : StmtKind(0), IsPreVisit(0) { } - CachedStmtCheckersKey(unsigned stmtKind, bool isPreVisit) - : StmtKind(stmtKind), IsPreVisit(isPreVisit) { } - - static CachedStmtCheckersKey getSentinel() { - return CachedStmtCheckersKey(~0U, 0); - } - unsigned getHashValue() const { - llvm::FoldingSetNodeID ID; - ID.AddInteger(StmtKind); - ID.AddBoolean(IsPreVisit); - return ID.ComputeHash(); - } - bool operator==(const CachedStmtCheckersKey &RHS) const { - return StmtKind == RHS.StmtKind && IsPreVisit == RHS.IsPreVisit; - } - }; - friend struct llvm::DenseMapInfo<CachedStmtCheckersKey>; - typedef SmallVector<CheckStmtFunc, 4> CachedStmtCheckers; - typedef llvm::DenseMap<CachedStmtCheckersKey, CachedStmtCheckers> - CachedStmtCheckersMapTy; + typedef llvm::DenseMap<unsigned, CachedStmtCheckers> CachedStmtCheckersMapTy; CachedStmtCheckersMapTy CachedStmtCheckersMap; - CachedStmtCheckers *getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit); + const CachedStmtCheckers &getCachedStmtCheckersFor(const Stmt *S, + bool isPreVisit); std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers; std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers; @@ -659,30 +637,4 @@ private: } // end clang namespace -namespace llvm { - /// Define DenseMapInfo so that CachedStmtCheckersKey can be used as key - /// in DenseMap and DenseSets. - template <> - struct DenseMapInfo<clang::ento::CheckerManager::CachedStmtCheckersKey> { - static inline clang::ento::CheckerManager::CachedStmtCheckersKey - getEmptyKey() { - return clang::ento::CheckerManager::CachedStmtCheckersKey(); - } - static inline clang::ento::CheckerManager::CachedStmtCheckersKey - getTombstoneKey() { - return clang::ento::CheckerManager::CachedStmtCheckersKey::getSentinel(); - } - - static unsigned - getHashValue(clang::ento::CheckerManager::CachedStmtCheckersKey S) { - return S.getHashValue(); - } - - static bool isEqual(clang::ento::CheckerManager::CachedStmtCheckersKey LHS, - clang::ento::CheckerManager::CachedStmtCheckersKey RHS) { - return LHS == RHS; - } - }; -} // end namespace llvm - #endif diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h index 4557aa4..ca68a74 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h +++ b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h @@ -54,10 +54,6 @@ // // For a complete working example, see examples/analyzer-plugin. - -namespace clang { -namespace ento { - #ifndef CLANG_ANALYZER_API_VERSION_STRING // FIXME: The Clang version string is not particularly granular; // the analyzer infrastructure can change a lot between releases. @@ -67,6 +63,9 @@ namespace ento { #define CLANG_ANALYZER_API_VERSION_STRING CLANG_VERSION_STRING #endif +namespace clang { +namespace ento { + class CheckerOptInfo; /// Manages a set of available checkers for running a static analysis. diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h index b856de7..43e9166 100644 --- a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h +++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h @@ -27,18 +27,12 @@ namespace ento { class PathDiagnosticConsumer; typedef std::vector<PathDiagnosticConsumer*> PathDiagnosticConsumers; -#define CREATE_CONSUMER(NAME)\ -void create ## NAME ## DiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,\ - PathDiagnosticConsumers &C,\ - const std::string& prefix,\ - const Preprocessor &PP); - -CREATE_CONSUMER(HTML) -CREATE_CONSUMER(Plist) -CREATE_CONSUMER(PlistMultiFile) -CREATE_CONSUMER(TextPath) - -#undef CREATE_CONSUMER +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN)\ +void CREATEFN(AnalyzerOptions &AnalyzerOpts,\ + PathDiagnosticConsumers &C,\ + const std::string &Prefix,\ + const Preprocessor &PP); +#include "clang/StaticAnalyzer/Core/Analyses.def" } // end 'ento' namespace } // end 'clang' namespace diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h index 458c896..d7d83ce 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -65,6 +65,10 @@ public: StoreManagerCreator getStoreManagerCreator() { return CreateStoreMgr; } + + AnalyzerOptions& getAnalyzerOptions() { + return options; + } ConstraintManagerCreator getConstraintManagerCreator() { return CreateConstraintMgr; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index f990b8d..cfaf085 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -228,11 +228,6 @@ public: return false; } - /// \brief Returns true if this is a call to a variadic function or method. - virtual bool isVariadic() const { - return false; - } - /// \brief Returns a source range for the entire call, suitable for /// outputting in diagnostics. virtual SourceRange getSourceRange() const { @@ -341,6 +336,11 @@ public: /// This will return a null QualType if the result type cannot be determined. static QualType getDeclaredResultType(const Decl *D); + /// \brief Returns true if the given decl is known to be variadic. + /// + /// \p D must not be null. + static bool isVariadic(const Decl *D); + // Iterator access to formal parameters and their types. private: typedef std::const_mem_fun_t<QualType, ParmVarDecl> get_type_fun; @@ -350,19 +350,13 @@ public: /// Returns an iterator over the call's formal parameters. /// - /// If UseDefinitionParams is set, this will return the parameter decls - /// used in the callee's definition (suitable for inlining). Most of the - /// time it is better to use the decl found by name lookup, which likely - /// carries more annotations. - /// /// Remember that the number of formal parameters may not match the number /// of arguments for all calls. However, the first parameter will always /// correspond with the argument value returned by \c getArgSVal(0). /// - /// If the call has no accessible declaration (or definition, if - /// \p UseDefinitionParams is set), \c param_begin() will be equal to - /// \c param_end(). - virtual param_iterator param_begin() const =0; + /// If the call has no accessible declaration, \c param_begin() will be equal + /// to \c param_end(). + virtual param_iterator param_begin() const = 0; /// \sa param_begin() virtual param_iterator param_end() const = 0; @@ -423,10 +417,6 @@ public: return RuntimeDefinition(); } - virtual bool isVariadic() const { - return getDecl()->isVariadic(); - } - virtual bool argumentsMayEscape() const; virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, @@ -527,10 +517,6 @@ public: return RuntimeDefinition(getBlockDecl()); } - virtual bool isVariadic() const { - return getBlockDecl()->isVariadic(); - } - virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, BindingsTy &Bindings) const; @@ -849,9 +835,6 @@ public: virtual const Expr *getArgExpr(unsigned Index) const { return getOriginExpr()->getArg(Index); } - virtual bool isVariadic() const { - return getDecl()->isVariadic(); - } bool isInstanceMessage() const { return getOriginExpr()->isInstanceMessage(); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index edcfc8a..bf17cd8 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -184,7 +184,7 @@ public: bool isSink() const { return Succs.getFlag(); } - bool hasSinglePred() const { + bool hasSinglePred() const { return (pred_size() == 1); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 33e4431..d89dffe 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -203,6 +203,8 @@ public: void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D, ExplodedNode *Pred, ExplodedNodeSet &Dst); + void ProcessDeleteDtor(const CFGDeleteDtor D, + ExplodedNode *Pred, ExplodedNodeSet &Dst); void ProcessBaseDtor(const CFGBaseDtor D, ExplodedNode *Pred, ExplodedNodeSet &Dst); void ProcessMemberDtor(const CFGMemberDtor D, @@ -476,14 +478,14 @@ protected: SVal Loc, SVal Val); /// Call PointerEscape callback when a value escapes as a result of /// region invalidation. - /// \param[in] IsConst Specifies that the pointer is const. + /// \param[in] ITraits Specifies invalidation traits for regions/symbols. ProgramStateRef notifyCheckersOfPointerEscape( ProgramStateRef State, const InvalidatedSymbols *Invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, const CallEvent *Call, - bool IsConst); + RegionAndSymbolInvalidationTraits &ITraits); public: // FIXME: 'tag' should be removed, and a LocationContext should be used diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 9b4f77d..cc790c1 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -635,12 +635,14 @@ class BlockDataRegion : public TypedRegion { friend class MemRegionManager; const BlockTextRegion *BC; const LocationContext *LC; // Can be null */ + unsigned BlockCount; void *ReferencedVars; void *OriginalVars; BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc, - const MemRegion *sreg) + unsigned count, const MemRegion *sreg) : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), + BlockCount(count), ReferencedVars(0), OriginalVars(0) {} public: @@ -692,7 +694,8 @@ public: void Profile(llvm::FoldingSetNodeID& ID) const; static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockTextRegion *, - const LocationContext *, const MemRegion *); + const LocationContext *, unsigned, + const MemRegion *); static bool classof(const MemRegion* R) { return R->getKind() == BlockDataRegionKind; @@ -1270,7 +1273,13 @@ public: /// argument is allowed to be NULL for cases where we have no known /// context. const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc, - const LocationContext *lc = NULL); + const LocationContext *lc, + unsigned blockCount); + + /// Create a CXXTempObjectRegion for temporaries which are lifetime-extended + /// by static references. This differs from getCXXTempObjectRegion in the + /// super-region used. + const CXXTempObjectRegion *getCXXStaticTempObjectRegion(const Expr *Ex); private: template <typename RegionTy, typename A1> @@ -1304,6 +1313,39 @@ private: inline ASTContext &MemRegion::getContext() const { return getMemRegionManager()->getContext(); } + +//===----------------------------------------------------------------------===// +// Means for storing region/symbol handling traits. +//===----------------------------------------------------------------------===// + +/// Information about invalidation for a particular region/symbol. +class RegionAndSymbolInvalidationTraits { + typedef unsigned char StorageTypeForKinds; + llvm::DenseMap<const MemRegion *, StorageTypeForKinds> MRTraitsMap; + llvm::DenseMap<SymbolRef, StorageTypeForKinds> SymTraitsMap; + + typedef llvm::DenseMap<const MemRegion *, StorageTypeForKinds>::const_iterator + const_region_iterator; + typedef llvm::DenseMap<SymbolRef, StorageTypeForKinds>::const_iterator + const_symbol_iterator; + +public: + /// \brief Describes different invalidation traits. + enum InvalidationKinds { + /// Tells that a region's contents is not changed. + TK_PreserveContents = 0x1, + /// Suppress pointer-escaping of a region. + TK_SuppressEscape = 0x2 + + // Do not forget to extend StorageTypeForKinds if number of traits exceed + // the number of bits StorageTypeForKinds can store. + }; + + void setTrait(SymbolRef Sym, InvalidationKinds IK); + void setTrait(const MemRegion *MR, InvalidationKinds IK); + bool hasTrait(SymbolRef Sym, InvalidationKinds IK); + bool hasTrait(const MemRegion *MR, InvalidationKinds IK); +}; } // end GR namespace diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 42ef1db..03739ed 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -232,22 +232,21 @@ public: /// \param IS the set of invalidated symbols. /// \param Call if non-null, the invalidated regions represent parameters to /// the call and should be considered directly invalidated. - /// \param ConstRegions the set of regions whose contents are accessible, - /// even though the regions themselves should not be invalidated. + /// \param ITraits information about special handling for a particular + /// region/symbol. ProgramStateRef invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E, unsigned BlockCount, const LocationContext *LCtx, bool CausesPointerEscape, InvalidatedSymbols *IS = 0, const CallEvent *Call = 0, - ArrayRef<const MemRegion *> ConstRegions = - ArrayRef<const MemRegion *>()) const; + RegionAndSymbolInvalidationTraits *ITraits = 0) const; ProgramStateRef invalidateRegions(ArrayRef<SVal> Regions, const Expr *E, unsigned BlockCount, const LocationContext *LCtx, bool CausesPointerEscape, InvalidatedSymbols *IS = 0, const CallEvent *Call = 0, - ArrayRef<SVal> ConstRegions = ArrayRef<SVal>()) const; + RegionAndSymbolInvalidationTraits *ITraits = 0) const; /// enterStackFrame - Returns the state for entry to the given stack frame, /// preserving the current state. @@ -425,9 +424,9 @@ private: const Expr *E, unsigned BlockCount, const LocationContext *LCtx, bool ResultsInSymbolEscape, - InvalidatedSymbols &IS, - const CallEvent *Call, - ArrayRef<SVal> ConstValues) const; + InvalidatedSymbols *IS, + RegionAndSymbolInvalidationTraits *HTraits, + const CallEvent *Call) const; }; //===----------------------------------------------------------------------===// @@ -516,8 +515,8 @@ public: public: - SVal ArrayToPointer(Loc Array) { - return StoreMgr->ArrayToPointer(Array); + SVal ArrayToPointer(Loc Array, QualType ElementTy) { + return StoreMgr->ArrayToPointer(Array, ElementTy); } // Methods that manipulate the GDM. @@ -798,7 +797,7 @@ CB ProgramState::scanReachableSymbols(const MemRegion * const *beg, /// A Utility class that allows to visit the reachable symbols using a custom /// SymbolVisitor. class ScanReachableSymbols { - typedef llvm::DenseMap<const void*, unsigned> VisitedItems; + typedef llvm::DenseSet<const void*> VisitedItems; VisitedItems visited; ProgramStateRef state; @@ -808,6 +807,7 @@ public: ScanReachableSymbols(ProgramStateRef st, SymbolVisitor& v) : state(st), visitor(v) {} + bool scan(nonloc::LazyCompoundVal val); bool scan(nonloc::CompoundVal val); bool scan(SVal val); bool scan(const MemRegion *R); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index bbb5688..c5d0a92 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -200,7 +200,8 @@ public: DefinedSVal getFunctionPointer(const FunctionDecl *func); DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy, - const LocationContext *locContext); + const LocationContext *locContext, + unsigned blockCount); /// Returns the value of \p E, if it can be determined in a non-path-sensitive /// manner. diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index 326e784..5a426ef 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -290,7 +290,7 @@ public: static inline bool isLocType(QualType T) { return T->isAnyPointerType() || T->isBlockPointerType() || - T->isReferenceType(); + T->isReferenceType() || T->isNullPtrType(); } private: diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index b219495..530dae5 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -111,7 +111,7 @@ public: /// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit /// conversions between arrays and pointers. - virtual SVal ArrayToPointer(Loc Array) = 0; + virtual SVal ArrayToPointer(Loc Array, QualType ElementTy) = 0; /// Evaluates a chain of derived-to-base casts through the path specified in /// \p Cast. @@ -164,8 +164,6 @@ public: /// the given regions. Optionally, invalidates non-static globals as well. /// \param[in] store The initial store /// \param[in] Values The values to invalidate. - /// \param[in] ConstValues The values to invalidate; these are known to be - /// const, so only regions accesible from them should be invalidated. /// \param[in] E The current statement being evaluated. Used to conjure /// symbols to mark the values of invalidated regions. /// \param[in] Count The current block count. Used to conjure @@ -174,13 +172,10 @@ public: /// globals should get invalidated. /// \param[in,out] IS A set to fill with any symbols that are no longer /// accessible. Pass \c NULL if this information will not be used. - /// \param[in,out] ConstIS A set to fill with any symbols corresponding to - /// the ConstValues. + /// \param[in] ITraits Information about invalidation for a particular + /// region/symbol. /// \param[in,out] InvalidatedTopLevel A vector to fill with regions - //// explicitely being invalidated. Pass \c NULL if this - /// information will not be used. - /// \param[in,out] InvalidatedTopLevelConst A vector to fill with const - //// regions explicitely being invalidated. Pass \c NULL if this + //// explicitly being invalidated. Pass \c NULL if this /// information will not be used. /// \param[in,out] Invalidated A vector to fill with any regions being /// invalidated. This should include any regions explicitly invalidated @@ -188,14 +183,12 @@ public: /// information will not be used. virtual StoreRef invalidateRegions(Store store, ArrayRef<SVal> Values, - ArrayRef<SVal> ConstValues, const Expr *E, unsigned Count, const LocationContext *LCtx, const CallEvent *Call, InvalidatedSymbols &IS, - InvalidatedSymbols &ConstIS, + RegionAndSymbolInvalidationTraits &ITraits, InvalidatedRegions *InvalidatedTopLevel, - InvalidatedRegions *InvalidatedTopLevelConst, InvalidatedRegions *Invalidated) = 0; /// enterStackFrame - Let the StoreManager to do something when execution @@ -231,7 +224,7 @@ public: bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R, SVal val); - operator bool() { return First && Binding; } + LLVM_EXPLICIT operator bool() { return First && Binding; } const MemRegion *getRegion() { return Binding; } }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h index d410063..f653c70 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -134,7 +134,7 @@ public: ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, const CallEvent *Call, - bool IsConst = false) = 0; + RegionAndSymbolInvalidationTraits &HTraits) = 0; /// printState - Called by ProgramStateManager to print checker-specific data. virtual void printState(raw_ostream &Out, ProgramStateRef State, |