aboutsummaryrefslogtreecommitdiff
path: root/include/clang/StaticAnalyzer/Core
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/StaticAnalyzer/Core')
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h26
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h64
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h23
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h40
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h33
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h14
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h39
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h39
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h82
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h32
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h44
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h21
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h47
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h14
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h67
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.