diff options
Diffstat (limited to 'include/clang/StaticAnalyzer/Core')
21 files changed, 409 insertions, 213 deletions
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index eb58803065..fb35f518ef 100644 --- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -198,6 +198,9 @@ private: /// \sa mayInlineTemplateFunctions Optional<bool> InlineTemplateFunctions; + /// \sa mayInlineCXXContainerCtorsAndDtors + Optional<bool> InlineCXXContainerCtorsAndDtors; + /// \sa mayInlineObjCMethod Optional<bool> ObjCInliningMode; @@ -217,6 +220,9 @@ private: /// \sa shouldSuppressInlinedDefensiveChecks Optional<bool> SuppressInlinedDefensiveChecks; + /// \sa shouldSuppressFromCXXStandardLibrary + Optional<bool> SuppressFromCXXStandardLibrary; + /// \sa getGraphTrimInterval Optional<unsigned> GraphTrimInterval; @@ -226,6 +232,7 @@ private: /// \sa getMaxNodesPerTopLevelFunction Optional<unsigned> MaxNodesPerTopLevelFunction; +public: /// Interprets an option's string value as a boolean. /// /// Accepts the strings "true" and "false". @@ -238,7 +245,6 @@ private: /// Interprets an option's string value as an integer value. int getOptionAsInteger(StringRef Name, int DefaultVal); -public: /// \brief Retrieves and sets the UserMode. This is a high-level option, /// which is used to set other low-level options. It is not accessible /// outside of AnalyzerOptions. @@ -278,6 +284,13 @@ public: /// accepts the values "true" and "false". bool mayInlineTemplateFunctions(); + /// Returns whether or not constructors and destructors of C++ container + /// objects may be considered for inlining. + /// + /// This is controlled by the 'c++-container-inlining' config option, which + /// accepts the values "true" and "false". + bool mayInlineCXXContainerCtorsAndDtors(); + /// Returns whether or not paths that go through null returns should be /// suppressed. /// @@ -306,6 +319,13 @@ public: /// option, which accepts the values "true" and "false". bool shouldSuppressInlinedDefensiveChecks(); + /// Returns whether or not diagnostics reported within the C++ standard + /// library should be suppressed. + /// + /// This is controlled by the 'suppress-c++-stdlib' config option, + /// which accepts the values "true" and "false". + bool shouldSuppressFromCXXStandardLibrary(); + /// Returns whether irrelevant parts of a bug report path should be pruned /// out of the final output. /// @@ -313,6 +333,10 @@ public: /// values "true" and "false". bool shouldPrunePaths(); + /// Returns true if 'static' initializers should be in conditional logic + /// in the CFG. + bool shouldConditionalizeStaticInitializers(); + // Returns the size of the functions (in basic blocks), which should be // considered to be small enough to always inline. // diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 7a87e47f74..5c560b2f0e 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -406,11 +406,6 @@ private: /// A vector of BugReports for tracking the allocated pointers and cleanup. std::vector<BugReportEquivClass *> EQClassesVector; - /// A map from PathDiagnosticPiece to the LocationContext of the inlined - /// function call it represents. - llvm::DenseMap<const PathDiagnosticCallPiece*, - const LocationContext*> LocationContextMap; - protected: BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k), D(d) {} @@ -482,10 +477,6 @@ public: EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1); } - void addCallPieceLocationContextPair(const PathDiagnosticCallPiece *C, - const LocationContext *LC) { - LocationContextMap[C] = LC; - } private: llvm::StringMap<BugType *> StrBugTypes; diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h index 17c1009853..2e67180bea 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h @@ -101,21 +101,22 @@ class FindLastStoreBRVisitor SVal V; bool Satisfied; -public: - /// \brief Convenience method to create a visitor given only the MemRegion. - /// Returns NULL if the visitor cannot be created. For example, when the - /// corresponding value is unknown. - static BugReporterVisitor *createVisitorObject(const ExplodedNode *N, - const MemRegion *R); + /// If the visitor is tracking the value directly responsible for the + /// bug, we are going to employ false positive suppression. + bool EnableNullFPSuppression; +public: /// Creates a visitor for every VarDecl inside a Stmt and registers it with /// the BugReport. - static void registerStatementVarDecls(BugReport &BR, const Stmt *S); + static void registerStatementVarDecls(BugReport &BR, const Stmt *S, + bool EnableNullFPSuppression); - FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R) + FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R, + bool InEnableNullFPSuppression) : R(R), V(V), - Satisfied(false) {} + Satisfied(false), + EnableNullFPSuppression(InEnableNullFPSuppression) {} void Profile(llvm::FoldingSetNodeID &ID) const; @@ -129,12 +130,19 @@ class TrackConstraintBRVisitor : public BugReporterVisitorImpl<TrackConstraintBRVisitor> { DefinedSVal Constraint; - const bool Assumption; - bool isSatisfied; + bool Assumption; + bool IsSatisfied; + bool IsZeroCheck; + + /// We should start tracking from the last node along the path in which the + /// value is constrained. + bool IsTrackingTurnedOn; public: TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) - : Constraint(constraint), Assumption(assumption), isSatisfied(false) {} + : Constraint(constraint), Assumption(assumption), IsSatisfied(false), + IsZeroCheck(!Assumption && Constraint.getAs<Loc>()), + IsTrackingTurnedOn(false) {} void Profile(llvm::FoldingSetNodeID &ID) const; @@ -146,12 +154,19 @@ public: const ExplodedNode *PrevN, BugReporterContext &BRC, BugReport &BR); + +private: + /// Checks if the constraint is valid in the current state. + bool isUnderconstrained(const ExplodedNode *N) const; + }; +/// \class NilReceiverBRVisitor +/// \brief Prints path notes when a message is sent to a nil receiver. class NilReceiverBRVisitor - : public BugReporterVisitorImpl<NilReceiverBRVisitor> -{ + : public BugReporterVisitorImpl<NilReceiverBRVisitor> { public: + void Profile(llvm::FoldingSetNodeID &ID) const { static int x = 0; ID.AddPointer(&x); @@ -161,6 +176,10 @@ public: const ExplodedNode *PrevN, BugReporterContext &BRC, BugReport &BR); + + /// If the statement is a message send expression with nil receiver, returns + /// the receiver expression. Returns NULL otherwise. + static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N); }; /// Visitor that tries to report interesting diagnostics from conditions. @@ -290,12 +309,12 @@ class SuppressInlineDefensiveChecksVisitor /// Track if we found the node where the constraint was first added. bool IsSatisfied; - /// \brief The node from which we should start tracking the value. - /// Note: Since the visitors can be registered on nodes previous to the last + /// Since the visitors can be registered on nodes previous to the last /// node in the BugReport, but the path traversal always starts with the last /// node, the visitor invariant (that we start with a node in which V is null) - /// might not hold when node visitation starts. - const ExplodedNode *StartN; + /// might not hold when node visitation starts. We are going to start tracking + /// from the last node in which the value is null. + bool IsTrackingTurnedOn; public: SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N); @@ -306,10 +325,6 @@ public: /// to make all PathDiagnosticPieces created by this visitor. static const char *getTag(); - PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, - const ExplodedNode *N, - BugReport &BR); - PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred, BugReporterContext &BRC, @@ -328,12 +343,15 @@ namespace bugreporter { /// \param IsArg Whether the statement is an argument to an inlined function. /// If this is the case, \p N \em must be the CallEnter node for /// the function. +/// \param EnableNullFPSuppression Whether we should employ false positive +/// suppression (inlined defensive checks, returned null). /// /// \return Whether or not the function was able to add visitors for this /// statement. Note that returning \c true does not actually imply /// that any visitors were added. bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, - bool IsArg = false); + bool IsArg = false, + bool EnableNullFPSuppression = true); const Expr *getDerefExpr(const Stmt *S); const Stmt *GetDenomExpr(const ExplodedNode *N); diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 3f0a1b1bc1..a80b5a7a24 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -21,6 +21,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerUnion.h" #include <deque> +#include <list> #include <iterator> #include <string> #include <vector> @@ -93,7 +94,7 @@ public: void HandlePathDiagnostic(PathDiagnostic *D); - enum PathGenerationScheme { None, Minimal, Extensive }; + enum PathGenerationScheme { None, Minimal, Extensive, AlternateExtensive }; virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } virtual bool supportsLogicalOpControlFlow() const { return false; } virtual bool supportsAllBlockEdges() const { return false; } @@ -283,6 +284,13 @@ public: const SourceManager& getManager() const { assert(isValid()); return *SM; } void Profile(llvm::FoldingSetNodeID &ID) 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. + static const Stmt *getNextStmt(const ExplodedNode *N); }; class PathDiagnosticLocationPair { @@ -296,6 +304,9 @@ public: const PathDiagnosticLocation &getStart() const { return Start; } const PathDiagnosticLocation &getEnd() const { return End; } + void setStart(const PathDiagnosticLocation &L) { Start = L; } + void setEnd(const PathDiagnosticLocation &L) { End = L; } + void flatten() { Start.flatten(); End.flatten(); @@ -381,7 +392,7 @@ public: }; -class PathPieces : public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > { +class PathPieces : public std::list<IntrusiveRefCntPtr<PathDiagnosticPiece> > { void flattenTo(PathPieces &Primary, PathPieces &Current, bool ShouldFlattenMacros) const; public: @@ -608,6 +619,14 @@ public: return LPairs[0].getEnd(); } + void setStartLocation(const PathDiagnosticLocation &L) { + LPairs[0].setStart(L); + } + + void setEndLocation(const PathDiagnosticLocation &L) { + LPairs[0].setEnd(L); + } + void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } virtual PathDiagnosticLocation getLocation() const { diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h index 305ae2579d..0dbaab033d 100644 --- a/include/clang/StaticAnalyzer/Core/Checker.h +++ b/include/clang/StaticAnalyzer/Core/Checker.h @@ -324,11 +324,14 @@ class PointerEscape { ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, - PointerEscapeKind Kind) { - return ((const CHECKER *)checker)->checkPointerEscape(State, - Escaped, - Call, - Kind); + PointerEscapeKind Kind, + bool IsConst) { + if (!IsConst) + return ((const CHECKER *)checker)->checkPointerEscape(State, + Escaped, + Call, + Kind); + return State; } public: @@ -340,6 +343,33 @@ public: } }; +class ConstPointerEscape { + template <typename CHECKER> + static ProgramStateRef + _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; + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPointerEscape( + CheckerManager::CheckPointerEscapeFunc(checker, + _checkConstPointerEscape<CHECKER>)); + } +}; + + template <typename EVENT> class Event { template <typename CHECKER> diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index 4353ebf015..b2411e6e65 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -17,6 +17,7 @@ #include "clang/Analysis/ProgramPoint.h" #include "clang/Basic/LangOptions.h" #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" @@ -134,9 +135,13 @@ enum PointerEscapeKind { class CheckerManager { const LangOptions LangOpts; - + AnalyzerOptionsRef AOptions; public: - CheckerManager(const LangOptions &langOpts) : LangOpts(langOpts) { } + CheckerManager(const LangOptions &langOpts, + AnalyzerOptionsRef AOptions) + : LangOpts(langOpts), + AOptions(AOptions) {} + ~CheckerManager(); bool hasPathSensitiveCheckers() const; @@ -144,6 +149,7 @@ public: void finishedCheckerRegistration(); const LangOptions &getLangOpts() const { return LangOpts; } + AnalyzerOptions &getAnalyzerOptions() { return *AOptions; } typedef CheckerBase *CheckerRef; typedef const void *CheckerTag; @@ -170,6 +176,20 @@ public: return checker; } + template <typename CHECKER> + CHECKER *registerChecker(AnalyzerOptions &AOpts) { + CheckerTag tag = getTag<CHECKER>(); + CheckerRef &ref = CheckerTags[tag]; + if (ref) + return static_cast<CHECKER *>(ref); // already registered. + + CHECKER *checker = new CHECKER(AOpts); + CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>)); + CHECKER::_register(checker, *this); + ref = checker; + return checker; + } + //===----------------------------------------------------------------------===// // Functions for running checkers for AST traversing.. //===----------------------------------------------------------------------===// @@ -346,12 +366,14 @@ 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. /// \returns Checkers can modify the state by returning a new one. ProgramStateRef runCheckersForPointerEscape(ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, - PointerEscapeKind Kind); + PointerEscapeKind Kind, + bool IsConst = false); /// \brief Run checkers for handling assumptions on symbolic values. ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state, @@ -442,7 +464,8 @@ public: typedef CheckerFn<ProgramStateRef (ProgramStateRef, const InvalidatedSymbols &Escaped, const CallEvent *Call, - PointerEscapeKind Kind)> + PointerEscapeKind Kind, + bool IsConst)> CheckPointerEscapeFunc; typedef CheckerFn<ProgramStateRef (ProgramStateRef, @@ -487,6 +510,8 @@ public: void _registerForPointerEscape(CheckPointerEscapeFunc checkfn); + void _registerForConstPointerEscape(CheckPointerEscapeFunc checkfn); + void _registerForEvalAssume(EvalAssumeFunc checkfn); void _registerForEvalCall(EvalCallFunc checkfn); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h index 27f3677bba..9502900f7e 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h @@ -81,9 +81,12 @@ public: /// Tests whether a given value is losslessly representable using this type. /// - /// Note that signedness conversions will be rejected, even with the same bit - /// pattern. For example, -1s8 is not in range for 'unsigned char' (u8). - RangeTestResultKind testInRange(const llvm::APSInt &Val) const LLVM_READONLY; + /// \param Val The value to test. + /// \param AllowMixedSign Whether or not to allow signedness conversions. + /// This determines whether -1s8 is considered in range + /// for 'unsigned char' (u8). + RangeTestResultKind testInRange(const llvm::APSInt &Val, + bool AllowMixedSign) const LLVM_READONLY; bool operator==(const APSIntType &Other) const { return BitWidth == Other.BitWidth && IsUnsigned == Other.IsUnsigned; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h index 1135b51144..2c799c0db4 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -93,7 +93,7 @@ public: /// Returns the type of the APSInt used to store values of the given QualType. APSIntType getAPSIntType(QualType T) const { - assert(T->isIntegerType() || Loc::isLocType(T)); + assert(T->isIntegralOrEnumerationType() || Loc::isLocType(T)); return APSIntType(Ctx.getTypeSize(T), !T->isSignedIntegerOrEnumerationType()); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index 1c67668618..f990b8dcd0 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -162,11 +162,11 @@ protected: } - typedef SmallVectorImpl<const MemRegion *> RegionList; + typedef SmallVectorImpl<SVal> ValueList; /// \brief Used to specify non-argument regions that will be invalidated as a /// result of this call. - virtual void getExtraInvalidatedRegions(RegionList &Regions) const {} + virtual void getExtraInvalidatedValues(ValueList &Values) const {} public: virtual ~CallEvent() {} @@ -504,7 +504,7 @@ protected: BlockCall(const BlockCall &Other) : SimpleCall(Other) {} virtual void cloneTo(void *Dest) const { new (Dest) BlockCall(*this); } - virtual void getExtraInvalidatedRegions(RegionList &Regions) const; + virtual void getExtraInvalidatedValues(ValueList &Values) const; public: /// \brief Returns the region associated with this instance of the block. @@ -548,7 +548,7 @@ public: /// it is written. class CXXInstanceCall : public AnyFunctionCall { protected: - virtual void getExtraInvalidatedRegions(RegionList &Regions) const; + virtual void getExtraInvalidatedValues(ValueList &Values) const; CXXInstanceCall(const CallExpr *CE, ProgramStateRef St, const LocationContext *LCtx) @@ -731,7 +731,7 @@ protected: CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){} virtual void cloneTo(void *Dest) const { new (Dest) CXXConstructorCall(*this); } - virtual void getExtraInvalidatedRegions(RegionList &Regions) const; + virtual void getExtraInvalidatedValues(ValueList &Values) const; public: virtual const CXXConstructExpr *getOriginExpr() const { @@ -830,7 +830,7 @@ protected: ObjCMethodCall(const ObjCMethodCall &Other) : CallEvent(Other) {} virtual void cloneTo(void *Dest) const { new (Dest) ObjCMethodCall(*this); } - virtual void getExtraInvalidatedRegions(RegionList &Regions) const; + virtual void getExtraInvalidatedValues(ValueList &Values) const; /// Check if the selector may have multiple definitions (may have overrides). virtual bool canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl, @@ -1042,7 +1042,7 @@ namespace llvm { typedef const T *SimpleType; static SimpleType - getSimplifiedValue(const clang::ento::CallEventRef<T>& Val) { + getSimplifiedValue(clang::ento::CallEventRef<T> Val) { return Val.getPtr(); } }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index cda1366a43..0b9762ac42 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -110,10 +110,6 @@ public: StoreManager &getStoreManager() { return Eng.getStoreManager(); } - - const AnalyzerOptions::ConfigTable &getConfig() const { - return Eng.getAnalysisManager().options.Config; - } /// \brief Returns the previous node in the exploded graph, which includes /// the state of the program before the checker ran. Note, checkers should diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index d8a7245730..a2e211edea 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -96,6 +96,10 @@ private: void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B, ExplodedNode *Pred); + /// Handle conditional logic for running static initializers. + void HandleStaticInit(const DeclStmt *DS, const CFGBlock *B, + ExplodedNode *Pred); + private: CoreEngine(const CoreEngine &) LLVM_DELETED_FUNCTION; void operator=(const CoreEngine &) LLVM_DELETED_FUNCTION; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index 70be1f8c63..edcfc8a6c0 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -196,6 +196,10 @@ public: return const_cast<ExplodedNode*>(this)->getFirstPred(); } + const ExplodedNode *getFirstSucc() const { + return succ_empty() ? NULL : *(succ_begin()); + } + // Iterators over successor and predecessor vertices. typedef ExplodedNode* const * succ_iterator; typedef const ExplodedNode* const * const_succ_iterator; @@ -239,18 +243,8 @@ private: void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); } }; -// FIXME: Is this class necessary? -class InterExplodedGraphMap { - virtual void anchor(); - llvm::DenseMap<const ExplodedNode*, ExplodedNode*> M; - friend class ExplodedGraph; - -public: - ExplodedNode *getMappedNode(const ExplodedNode *N) const; - - InterExplodedGraphMap() {} - virtual ~InterExplodedGraphMap() {} -}; +typedef llvm::DenseMap<const ExplodedNode *, const ExplodedNode *> + InterExplodedGraphMap; class ExplodedGraph { protected: @@ -368,14 +362,19 @@ public: typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap; - std::pair<ExplodedGraph*, InterExplodedGraphMap*> - Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd, - llvm::DenseMap<const void*, const void*> *InverseMap = 0) const; - - ExplodedGraph* TrimInternal(const ExplodedNode* const * NBeg, - const ExplodedNode* const * NEnd, - InterExplodedGraphMap *M, - llvm::DenseMap<const void*, const void*> *InverseMap) const; + /// Creates a trimmed version of the graph that only contains paths leading + /// to the given nodes. + /// + /// \param Nodes The nodes which must appear in the final graph. Presumably + /// these are end-of-path nodes (i.e. they have no successors). + /// \param[out] ForwardMap A optional map from nodes in this graph to nodes in + /// the returned graph. + /// \param[out] InverseMap An optional map from nodes in the returned graph to + /// nodes in this graph. + /// \returns The trimmed graph + ExplodedGraph *trim(ArrayRef<const NodeTy *> Nodes, + InterExplodedGraphMap *ForwardMap = 0, + InterExplodedGraphMap *InverseMap = 0) const; /// Enable tracking of recently allocated nodes for potential reclamation /// when calling reclaimRecentlyAllocatedNodes(). diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 60c35f807e..33e4431eb4 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -48,13 +48,13 @@ class CXXConstructorCall; class ExprEngine : public SubEngine { public: - /// The modes of inlining. + /// The modes of inlining, which override the default analysis-wide settings. enum InliningModes { - /// Do not inline any of the callees. - Inline_None = 0, - /// Inline all callees. - Inline_All = 0x1 - } ; + /// Follow the default settings for inlining callees. + Inline_Regular = 0, + /// Do minimal inlining of callees. + Inline_Minimal = 0x1 + }; private: AnalysisManager &AMgr; @@ -146,11 +146,12 @@ public: void enqueueEndOfPath(ExplodedNodeSet &S); void GenerateCallExitNode(ExplodedNode *N); - /// ViewGraph - Visualize the ExplodedGraph created by executing the - /// simulation. + /// Visualize the ExplodedGraph created by executing the simulation. void ViewGraph(bool trim = false); - void ViewGraph(ExplodedNode** Beg, ExplodedNode** End); + /// Visualize a trimmed ExplodedGraph that only contains paths to the given + /// nodes. + void ViewGraph(ArrayRef<const ExplodedNode*> Nodes); /// getInitialState - Return the initial state used for the root vertex /// in the ExplodedGraph. @@ -223,6 +224,15 @@ public: const CFGBlock *DstT, const CFGBlock *DstF); + /// Called by CoreEngine. Used to processing branching behavior + /// at static initalizers. + void processStaticInitializer(const DeclStmt *DS, + NodeBuilderContext& BuilderCtx, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF); + /// processIndirectGoto - Called by CoreEngine. Used to generate successor /// nodes by processing the 'effects' of a computed goto jump. void processIndirectGoto(IndirectGotoNodeBuilder& builder); @@ -466,12 +476,14 @@ protected: SVal Loc, SVal Val); /// Call PointerEscape callback when a value escapes as a result of /// region invalidation. - ProgramStateRef processPointerEscapedOnInvalidateRegions( + /// \param[in] IsConst Specifies that the pointer is const. + ProgramStateRef notifyCheckersOfPointerEscape( ProgramStateRef State, const InvalidatedSymbols *Invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, - const CallEvent *Call); + const CallEvent *Call, + bool IsConst); public: // FIXME: 'tag' should be removed, and a LocationContext should be used @@ -552,9 +564,10 @@ private: bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC); - /// Models a trivial copy or move constructor call with a simple bind. + /// Models a trivial copy or move constructor or trivial assignment operator + /// call with a simple bind. void performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, - const CXXConstructorCall &Call); + const CallEvent &Call); /// If the value of the given expression is a NonLoc, copy it into a new /// temporary object region, and replace the value of the expression with diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h index 546cec568f..169af939f0 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h @@ -7,110 +7,126 @@ // //===----------------------------------------------------------------------===// // -// This file defines a summary of a function gathered/used by static analyzes. +// This file defines a summary of a function gathered/used by static analysis. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_GR_FUNCTIONSUMMARY_H #define LLVM_CLANG_GR_FUNCTIONSUMMARY_H -#include "clang/AST/Decl.h" -#include "llvm/ADT/BitVector.h" +#include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallBitVector.h" #include <deque> namespace clang { +class Decl; + namespace ento { typedef std::deque<Decl*> SetOfDecls; typedef llvm::DenseSet<const Decl*> SetOfConstDecls; class FunctionSummariesTy { - struct FunctionSummary { - /// True if this function has reached a max block count while inlined from - /// at least one call site. - bool MayReachMaxBlockCount; + class FunctionSummary { + public: + /// Marks the IDs of the basic blocks visited during the analyzes. + llvm::SmallBitVector VisitedBasicBlocks; /// Total number of blocks in the function. - unsigned TotalBasicBlocks; + unsigned TotalBasicBlocks : 30; - /// Marks the IDs of the basic blocks visited during the analyzes. - llvm::BitVector VisitedBasicBlocks; + /// True if this function has been checked against the rules for which + /// functions may be inlined. + unsigned InlineChecked : 1; + + /// True if this function may be inlined. + unsigned MayInline : 1; /// The number of times the function has been inlined. - unsigned TimesInlined; + unsigned TimesInlined : 32; FunctionSummary() : - MayReachMaxBlockCount(false), TotalBasicBlocks(0), - VisitedBasicBlocks(0), + InlineChecked(0), TimesInlined(0) {} }; - typedef llvm::DenseMap<const Decl*, FunctionSummary*> MapTy; + typedef llvm::DenseMap<const Decl *, FunctionSummary> MapTy; MapTy Map; public: - ~FunctionSummariesTy(); - MapTy::iterator findOrInsertSummary(const Decl *D) { MapTy::iterator I = Map.find(D); if (I != Map.end()) return I; - FunctionSummary *DS = new FunctionSummary(); - I = Map.insert(std::pair<const Decl*, FunctionSummary*>(D, DS)).first; + + typedef std::pair<const Decl *, FunctionSummary> KVPair; + I = Map.insert(KVPair(D, FunctionSummary())).first; assert(I != Map.end()); return I; } - void markReachedMaxBlockCount(const Decl* D) { + void markMayInline(const Decl *D) { MapTy::iterator I = findOrInsertSummary(D); - I->second->MayReachMaxBlockCount = true; + I->second.InlineChecked = 1; + I->second.MayInline = 1; } - bool hasReachedMaxBlockCount(const Decl* D) { - MapTy::const_iterator I = Map.find(D); - if (I != Map.end()) - return I->second->MayReachMaxBlockCount; - return false; + void markShouldNotInline(const Decl *D) { + MapTy::iterator I = findOrInsertSummary(D); + I->second.InlineChecked = 1; + I->second.MayInline = 0; + } + + void markReachedMaxBlockCount(const Decl *D) { + markShouldNotInline(D); + } + + Optional<bool> mayInline(const Decl *D) { + MapTy::const_iterator I = Map.find(D); + if (I != Map.end() && I->second.InlineChecked) + return I->second.MayInline; + return None; } void markVisitedBasicBlock(unsigned ID, const Decl* D, unsigned TotalIDs) { MapTy::iterator I = findOrInsertSummary(D); - llvm::BitVector &Blocks = I->second->VisitedBasicBlocks; + llvm::SmallBitVector &Blocks = I->second.VisitedBasicBlocks; assert(ID < TotalIDs); if (TotalIDs > Blocks.size()) { Blocks.resize(TotalIDs); - I->second->TotalBasicBlocks = TotalIDs; + I->second.TotalBasicBlocks = TotalIDs; } - Blocks[ID] = true; + Blocks.set(ID); } unsigned getNumVisitedBasicBlocks(const Decl* D) { MapTy::const_iterator I = Map.find(D); if (I != Map.end()) - return I->second->VisitedBasicBlocks.count(); + return I->second.VisitedBasicBlocks.count(); return 0; } unsigned getNumTimesInlined(const Decl* D) { MapTy::const_iterator I = Map.find(D); if (I != Map.end()) - return I->second->TimesInlined; + return I->second.TimesInlined; return 0; } void bumpNumTimesInlined(const Decl* D) { MapTy::iterator I = findOrInsertSummary(D); - I->second->TimesInlined++; + I->second.TimesInlined++; } /// Get the percentage of the reachable blocks. unsigned getPercentBlocksReachable(const Decl *D) { MapTy::const_iterator I = Map.find(D); if (I != Map.end()) - return ((I->second->VisitedBasicBlocks.count() * 100) / - I->second->TotalBasicBlocks); + return ((I->second.VisitedBasicBlocks.count() * 100) / + I->second.TotalBasicBlocks); return 0; } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index af2f365ead..9b4f77dd67 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -37,11 +37,12 @@ class StackFrameContext; namespace ento { +class CodeTextRegion; class MemRegionManager; class MemSpaceRegion; class SValBuilder; +class SymbolicRegion; class VarRegion; -class CodeTextRegion; /// Represent a region's offset within the top level base region. class RegionOffset { @@ -145,6 +146,10 @@ public: const MemRegion *StripCasts(bool StripBaseCasts = true) const; + /// \brief If this is a symbolic region, returns the region. Otherwise, + /// goes up the base chain looking for the first symbolic base region. + const SymbolicRegion *getSymbolicBase() const; + bool hasGlobalsOrParametersStorage() const; bool hasStackStorage() const; @@ -169,6 +174,16 @@ public: /// \brief Print the region for use in diagnostics. virtual void printPretty(raw_ostream &os) const; + /// \brief Returns true if this region's textual representation can be used + /// as part of a larger expression. + virtual bool canPrintPrettyAsExpr() const; + + /// \brief Print the region as expression. + /// + /// When this region represents a subexpression, the method is for printing + /// an expression containing it. + virtual void printPrettyAsExpr(raw_ostream &os) const; + Kind getKind() const { return kind; } template<typename RegionTy> const RegionTy* getAs() const; @@ -874,8 +889,9 @@ public: return R->getKind() == VarRegionKind; } - bool canPrintPretty() const; - void printPretty(raw_ostream &os) const; + bool canPrintPrettyAsExpr() const; + + void printPrettyAsExpr(raw_ostream &os) const; }; /// CXXThisRegion - Represents the region for the implicit 'this' parameter @@ -937,6 +953,8 @@ public: bool canPrintPretty() const; void printPretty(raw_ostream &os) const; + bool canPrintPrettyAsExpr() const; + void printPrettyAsExpr(raw_ostream &os) const; }; class ObjCIvarRegion : public DeclRegion { @@ -952,8 +970,8 @@ public: const ObjCIvarDecl *getDecl() const; QualType getValueType() const; - bool canPrintPretty() const; - void printPretty(raw_ostream &os) const; + bool canPrintPrettyAsExpr() const; + void printPrettyAsExpr(raw_ostream &os) const; void dumpToStream(raw_ostream &os) const; @@ -1082,6 +1100,10 @@ public: static bool classof(const MemRegion *region) { return region->getKind() == CXXBaseObjectRegionKind; } + + bool canPrintPrettyAsExpr() const; + + void printPrettyAsExpr(raw_ostream &os) const; }; template<typename RegionTy> diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 39e7429344..42ef1db455 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -201,14 +201,6 @@ public: // Binding and retrieving values to/from the environment and symbolic store. //==---------------------------------------------------------------------==// - /// \brief Create a new state with the specified CompoundLiteral binding. - /// \param CL the compound literal expression (the binding key) - /// \param LC the LocationContext of the binding - /// \param V the value to bind. - ProgramStateRef bindCompoundLiteral(const CompoundLiteralExpr *CL, - const LocationContext *LC, - SVal V) const; - /// Create a new state by binding the value 'V' to the statement 'S' in the /// state's environment. ProgramStateRef BindExpr(const Stmt *S, const LocationContext *LCtx, @@ -240,12 +232,22 @@ 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. - ProgramStateRef invalidateRegions(ArrayRef<const MemRegion *> Regions, - const Expr *E, unsigned BlockCount, - const LocationContext *LCtx, - bool CausesPointerEscape, - InvalidatedSymbols *IS = 0, - const CallEvent *Call = 0) const; + /// \param ConstRegions the set of regions whose contents are accessible, + /// even though the regions themselves should not be invalidated. + 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; + + 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; /// enterStackFrame - Returns the state for entry to the given stack frame, /// preserving the current state. @@ -415,14 +417,17 @@ public: private: friend void ProgramStateRetain(const ProgramState *state); friend void ProgramStateRelease(const ProgramState *state); - - ProgramStateRef - invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions, + + /// \sa invalidateValues() + /// \sa invalidateRegions() + ProgramStateRef + invalidateRegionsImpl(ArrayRef<SVal> Values, const Expr *E, unsigned BlockCount, const LocationContext *LCtx, bool ResultsInSymbolEscape, InvalidatedSymbols &IS, - const CallEvent *Call) const; + const CallEvent *Call, + ArrayRef<SVal> ConstValues) const; }; //===----------------------------------------------------------------------===// @@ -698,7 +703,8 @@ ProgramState::getSValAsScalarOrLoc(const Stmt *S, const LocationContext *LCtx) const { if (const Expr *Ex = dyn_cast<Expr>(S)) { QualType T = Ex->getType(); - if (Ex->isGLValue() || Loc::isLocType(T) || T->isIntegerType()) + if (Ex->isGLValue() || Loc::isLocType(T) || + T->isIntegralOrEnumerationType()) return getSVal(S, LCtx); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index f7e49a3c75..bbb56885af 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -78,7 +78,8 @@ public: // FIXME: Remove the second disjunct when we support symbolic // truncation/extension. return (Context.getCanonicalType(Ty1) == Context.getCanonicalType(Ty2) || - (Ty1->isIntegerType() && Ty2->isIntegerType())); + (Ty1->isIntegralOrEnumerationType() && + Ty2->isIntegralOrEnumerationType())); } SVal evalCast(SVal val, QualType castTy, QualType originalType); @@ -201,6 +202,12 @@ public: DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy, const LocationContext *locContext); + /// Returns the value of \p E, if it can be determined in a non-path-sensitive + /// manner. + /// + /// If \p E is not a constant or cannot be modeled, returns \c None. + Optional<SVal> getConstantVal(const Expr *E); + NonLoc makeCompoundVal(QualType type, llvm::ImmutableList<SVal> vals) { return nonloc::CompoundVal(BasicVals.getCompoundValData(type, vals)); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index 8182f2e565..326e784e83 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -144,16 +144,24 @@ public: /// Otherwise return 0. const FunctionDecl *getAsFunctionDecl() const; - /// If this SVal is a location (subclasses Loc) and - /// wraps a symbol, return that SymbolRef. Otherwise return 0. - SymbolRef getAsLocSymbol() const; + /// \brief If this SVal is a location and wraps a symbol, return that + /// SymbolRef. Otherwise return 0. + /// + /// Casts are ignored during lookup. + /// \param IncludeBaseRegions The boolean that controls whether the search + /// should continue to the base regions if the region is not symbolic. + SymbolRef getAsLocSymbol(bool IncludeBaseRegions = false) const; /// Get the symbol in the SVal or its base region. SymbolRef getLocSymbolInBase() const; - /// If this SVal wraps a symbol return that SymbolRef. + /// \brief If this SVal wraps a symbol return that SymbolRef. /// Otherwise, return 0. - SymbolRef getAsSymbol() const; + /// + /// Casts are ignored during lookup. + /// \param IncludeBaseRegions The boolean that controls whether the search + /// should continue to the base regions if the region is not symbolic. + SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const; /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then /// return that expression. Otherwise return NULL. @@ -544,7 +552,8 @@ private: }; } // end ento::loc namespace -} // end GR namespace + +} // end ento namespace } // end clang namespace diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index 066cd20e18..b219495d5f 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -76,21 +76,6 @@ public: /// \param L the location whose binding should be removed. virtual StoreRef killBinding(Store ST, Loc L) = 0; - /// \brief Create a new store that binds a value to a compound literal. - /// - /// \param ST The original store whose bindings are the basis for the new - /// store. - /// - /// \param CL The compound literal to bind (the binding key). - /// - /// \param LC The LocationContext for the binding. - /// - /// \param V The value to bind to the compound literal. - virtual StoreRef bindCompoundLiteral(Store ST, - const CompoundLiteralExpr *CL, - const LocationContext *LC, - SVal V) = 0; - /// getInitialStore - Returns the initial "empty" store representing the /// value bindings upon entry to an analyzed function. virtual StoreRef getInitialStore(const LocationContext *InitLoc) = 0; @@ -178,26 +163,40 @@ public: /// invalidate additional regions that may have changed based on accessing /// the given regions. Optionally, invalidates non-static globals as well. /// \param[in] store The initial store - /// \param[in] Regions The regions to invalidate. + /// \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 /// symbols to mark the values of invalidated regions. - /// \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] Call The call expression which will be used to determine which /// 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,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 + /// 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 /// even if they do not currently have bindings. Pass \c NULL if this /// information will not be used. virtual StoreRef invalidateRegions(Store store, - ArrayRef<const MemRegion *> Regions, - const Expr *E, unsigned Count, - const LocationContext *LCtx, - InvalidatedSymbols &IS, - const CallEvent *Call, - InvalidatedRegions *Invalidated) = 0; + ArrayRef<SVal> Values, + ArrayRef<SVal> ConstValues, + const Expr *E, unsigned Count, + const LocationContext *LCtx, + const CallEvent *Call, + InvalidatedSymbols &IS, + InvalidatedSymbols &ConstIS, + InvalidatedRegions *InvalidatedTopLevel, + InvalidatedRegions *InvalidatedTopLevelConst, + InvalidatedRegions *Invalidated) = 0; /// enterStackFrame - Let the StoreManager to do something when execution /// engine is about to execute into a callee. diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h index 0e9f25375d..d4100634a7 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -72,6 +72,15 @@ public: const CFGBlock *DstT, const CFGBlock *DstF) = 0; + /// Called by CoreEngine. Used to processing branching behavior + /// at static initalizers. + virtual void processStaticInitializer(const DeclStmt *DS, + NodeBuilderContext& BuilderCtx, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF) = 0; + /// Called by CoreEngine. Used to generate successor /// nodes by processing the 'effects' of a computed goto jump. virtual void processIndirectGoto(IndirectGotoNodeBuilder& builder) = 0; @@ -120,11 +129,12 @@ public: processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, SVal Val) = 0; virtual ProgramStateRef - processPointerEscapedOnInvalidateRegions(ProgramStateRef State, + notifyCheckersOfPointerEscape(ProgramStateRef State, const InvalidatedSymbols *Invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, - const CallEvent *Call) = 0; + const CallEvent *Call, + bool IsConst = false) = 0; /// printState - Called by ProgramStateManager to print checker-specific data. virtual void printState(raw_ostream &Out, ProgramStateRef State, diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index 56afca24f6..914b2bea2d 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -49,7 +49,10 @@ public: MetadataKind, BEGIN_SYMBOLS = RegionValueKind, END_SYMBOLS = MetadataKind, - SymIntKind, IntSymKind, SymSymKind, CastSymbolKind }; + SymIntKind, IntSymKind, SymSymKind, + BEGIN_BINARYSYMEXPRS = SymIntKind, + END_BINARYSYMEXPRS = SymSymKind, + CastSymbolKind }; private: Kind K; @@ -341,24 +344,39 @@ public: } }; -/// SymIntExpr - Represents symbolic expression like 'x' + 3. -class SymIntExpr : public SymExpr { - const SymExpr *LHS; +/// \brief Represents a symbolic expression involving a binary operator +class BinarySymExpr : public SymExpr { BinaryOperator::Opcode Op; - const llvm::APSInt& RHS; QualType T; -public: - SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, - const llvm::APSInt& rhs, QualType t) - : SymExpr(SymIntKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} +protected: + BinarySymExpr(Kind k, BinaryOperator::Opcode op, QualType t) + : SymExpr(k), Op(op), T(t) {} +public: // FIXME: We probably need to make this out-of-line to avoid redundant // generation of virtual functions. QualType getType() const { return T; } BinaryOperator::Opcode getOpcode() const { return Op; } + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + Kind k = SE->getKind(); + return k >= BEGIN_BINARYSYMEXPRS && k <= END_BINARYSYMEXPRS; + } +}; + +/// \brief Represents a symbolic expression like 'x' + 3. +class SymIntExpr : public BinarySymExpr { + const SymExpr *LHS; + const llvm::APSInt& RHS; + +public: + SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t) + : BinarySymExpr(SymIntKind, op, t), LHS(lhs), RHS(rhs) {} + virtual void dumpToStream(raw_ostream &os) const; const SymExpr *getLHS() const { return LHS; } @@ -375,7 +393,7 @@ public: } void Profile(llvm::FoldingSetNodeID& ID) { - Profile(ID, LHS, Op, RHS, T); + Profile(ID, LHS, getOpcode(), RHS, getType()); } // Implement isa<T> support. @@ -384,21 +402,15 @@ public: } }; -/// IntSymExpr - Represents symbolic expression like 3 - 'x'. -class IntSymExpr : public SymExpr { +/// \brief Represents a symbolic expression like 3 - 'x'. +class IntSymExpr : public BinarySymExpr { const llvm::APSInt& LHS; - BinaryOperator::Opcode Op; const SymExpr *RHS; - QualType T; public: IntSymExpr(const llvm::APSInt& lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) - : SymExpr(IntSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} - - QualType getType() const { return T; } - - BinaryOperator::Opcode getOpcode() const { return Op; } + : BinarySymExpr(IntSymKind, op, t), LHS(lhs), RHS(rhs) {} virtual void dumpToStream(raw_ostream &os) const; @@ -416,7 +428,7 @@ public: } void Profile(llvm::FoldingSetNodeID& ID) { - Profile(ID, LHS, Op, RHS, T); + Profile(ID, LHS, getOpcode(), RHS, getType()); } // Implement isa<T> support. @@ -425,26 +437,19 @@ public: } }; -/// SymSymExpr - Represents symbolic expression like 'x' + 'y'. -class SymSymExpr : public SymExpr { +/// \brief Represents a symbolic expression like 'x' + 'y'. +class SymSymExpr : public BinarySymExpr { const SymExpr *LHS; - BinaryOperator::Opcode Op; const SymExpr *RHS; - QualType T; public: SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) - : SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} + : BinarySymExpr(SymSymKind, op, t), LHS(lhs), RHS(rhs) {} - BinaryOperator::Opcode getOpcode() const { return Op; } const SymExpr *getLHS() const { return LHS; } const SymExpr *getRHS() const { return RHS; } - // FIXME: We probably need to make this out-of-line to avoid redundant - // generation of virtual functions. - QualType getType() const { return T; } - virtual void dumpToStream(raw_ostream &os) const; static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, @@ -457,7 +462,7 @@ public: } void Profile(llvm::FoldingSetNodeID& ID) { - Profile(ID, LHS, Op, RHS, T); + Profile(ID, LHS, getOpcode(), RHS, getType()); } // Implement isa<T> support. |