aboutsummaryrefslogtreecommitdiff
path: root/include/clang/StaticAnalyzer
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2013-04-08 18:45:10 +0000
committerDimitry Andric <dim@FreeBSD.org>2013-04-08 18:45:10 +0000
commit809500fc2c13c8173a16b052304d983864e4a1e1 (patch)
tree4fc2f184c499d106f29a386c452b49e5197bf63d /include/clang/StaticAnalyzer
parentbe7c9ec198dcdb5bf73a35bfbb00b3333cb87909 (diff)
downloadsrc-809500fc2c13c8173a16b052304d983864e4a1e1.tar.gz
src-809500fc2c13c8173a16b052304d983864e4a1e1.zip
Vendor import of clang trunk r178860:vendor/clang/clang-trunk-r178860
Notes
Notes: svn path=/vendor/clang/dist/; revision=249261 svn path=/vendor/clang/clang-trunk-r178860/; revision=249262; tag=vendor/clang/clang-trunk-r178860
Diffstat (limited to 'include/clang/StaticAnalyzer')
-rw-r--r--include/clang/StaticAnalyzer/Core/Analyses.def14
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h215
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h28
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h125
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugType.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h32
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h87
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h81
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerOptInfo.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerRegistry.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h24
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h3
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h38
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h12
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h14
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h12
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h64
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h143
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h96
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h61
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h105
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h19
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h5
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h242
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h40
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h22
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h8
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h6
32 files changed, 1049 insertions, 476 deletions
diff --git a/include/clang/StaticAnalyzer/Core/Analyses.def b/include/clang/StaticAnalyzer/Core/Analyses.def
index 01a6ffd7142c..dc7945016b1a 100644
--- a/include/clang/StaticAnalyzer/Core/Analyses.def
+++ b/include/clang/StaticAnalyzer/Core/Analyses.def
@@ -41,22 +41,12 @@ ANALYSIS_PURGE(PurgeStmt, "statement", "Purge symbols, bindings, and constraint
ANALYSIS_PURGE(PurgeBlock, "block", "Purge symbols, bindings, and constraints before every basic block")
ANALYSIS_PURGE(PurgeNone, "none", "Do not purge symbols, bindings, or constraints")
-#ifndef ANALYSIS_IPA
-#define ANALYSIS_IPA(NAME, CMDFLAG, DESC)
-#endif
-
-ANALYSIS_IPA(None, "none", "Perform only intra-procedural analysis")
-ANALYSIS_IPA(BasicInlining, "basic-inlining", "Inline C functions and blocks when their definitions are available")
-ANALYSIS_IPA(Inlining, "inlining", "Inline callees when their definitions are available")
-ANALYSIS_IPA(DynamicDispatch, "dynamic", "Experimental: Enable inlining of dynamically dispatched methods")
-ANALYSIS_IPA(DynamicDispatchBifurcate, "dynamic-bifurcate", "Experimental: Enable inlining of dynamically dispatched methods, bifurcate paths when exact type info is unavailable")
-
#ifndef ANALYSIS_INLINING_MODE
#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC)
#endif
-ANALYSIS_INLINING_MODE(All, "all", "Analyze all functions in the order defined in the TU")
-ANALYSIS_INLINING_MODE(NoRedundancy, "noredundancy", "Do not analyze a function which has been previously inlined, use call graph to order")
+ANALYSIS_INLINING_MODE(All, "all", "Analyze all functions as top level")
+ANALYSIS_INLINING_MODE(NoRedundancy, "noredundancy", "Do not analyze a function which has been previously inlined")
#undef ANALYSIS_STORE
#undef ANALYSIS_CONSTRAINTS
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index fa0754acb150..6dbdbbf89b96 100644
--- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -15,12 +15,12 @@
#ifndef LLVM_CLANG_ANALYZEROPTIONS_H
#define LLVM_CLANG_ANALYZEROPTIONS_H
-#include <string>
-#include <vector>
#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringMap.h"
+#include <string>
+#include <vector>
namespace clang {
class ASTConsumer;
@@ -64,13 +64,6 @@ enum AnalysisPurgeMode {
NumPurgeModes
};
-/// AnalysisIPAMode - Set of inter-procedural modes.
-enum AnalysisIPAMode {
-#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) NAME,
-#include "clang/StaticAnalyzer/Core/Analyses.def"
-NumIPAModes
-};
-
/// AnalysisInlineFunctionSelection - Set of inlining function selection heuristics.
enum AnalysisInliningMode {
#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) NAME,
@@ -102,8 +95,28 @@ enum CXXInlineableMemberKind {
CIMK_Destructors
};
+/// \brief Describes the different modes of inter-procedural analysis.
+enum IPAKind {
+ IPAK_NotSet = 0,
+
+ /// Perform only intra-procedural analysis.
+ IPAK_None = 1,
+
+ /// Inline C functions and blocks when their definitions are available.
+ IPAK_BasicInlining = 2,
-class AnalyzerOptions : public llvm::RefCountedBase<AnalyzerOptions> {
+ /// Inline callees(C, C++, ObjC) when their definitions are available.
+ IPAK_Inlining = 3,
+
+ /// Enable inlining of dynamically dispatched methods.
+ IPAK_DynamicDispatch = 4,
+
+ /// Enable inlining of dynamically dispatched methods, bifurcate paths when
+ /// exact type info is unavailable.
+ IPAK_DynamicDispatchBifurcate = 5
+};
+
+class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
public:
typedef llvm::StringMap<std::string> ConfigTable;
@@ -117,14 +130,8 @@ public:
AnalysisDiagClients AnalysisDiagOpt;
AnalysisPurgeMode AnalysisPurgeOpt;
- // \brief The interprocedural analysis mode.
- AnalysisIPAMode IPAMode;
-
std::string AnalyzeSpecificFunction;
- /// \brief The maximum number of exploded nodes the analyzer will generate.
- unsigned MaxNodes;
-
/// \brief The maximum number of times the analyzer visits a block.
unsigned maxBlockVisitOnPath;
@@ -159,39 +166,71 @@ public:
unsigned InlineMaxStackDepth;
/// \brief The mode of function selection used during inlining.
- unsigned InlineMaxFunctionSize;
-
- /// \brief The mode of function selection used during inlining.
AnalysisInliningMode InliningMode;
private:
+ /// \brief Describes the kinds for high-level analyzer mode.
+ enum UserModeKind {
+ UMK_NotSet = 0,
+ /// Perform shallow but fast analyzes.
+ UMK_Shallow = 1,
+ /// Perform deep analyzes.
+ UMK_Deep = 2
+ };
+
+ /// Controls the high-level analyzer mode, which influences the default
+ /// settings for some of the lower-level config options (such as IPAMode).
+ /// \sa getUserMode
+ UserModeKind UserMode;
+
+ /// Controls the mode of inter-procedural analysis.
+ IPAKind IPAMode;
+
/// Controls which C++ member functions will be considered for inlining.
CXXInlineableMemberKind CXXMemberInliningMode;
/// \sa includeTemporaryDtorsInCFG
- llvm::Optional<bool> IncludeTemporaryDtorsInCFG;
+ Optional<bool> IncludeTemporaryDtorsInCFG;
/// \sa mayInlineCXXStandardLibrary
- llvm::Optional<bool> InlineCXXStandardLibrary;
+ Optional<bool> InlineCXXStandardLibrary;
/// \sa mayInlineTemplateFunctions
- llvm::Optional<bool> InlineTemplateFunctions;
+ Optional<bool> InlineTemplateFunctions;
+
+ /// \sa mayInlineCXXContainerCtorsAndDtors
+ Optional<bool> InlineCXXContainerCtorsAndDtors;
/// \sa mayInlineObjCMethod
- llvm::Optional<bool> ObjCInliningMode;
+ Optional<bool> ObjCInliningMode;
// Cache of the "ipa-always-inline-size" setting.
// \sa getAlwaysInlineSize
- llvm::Optional<unsigned> AlwaysInlineSize;
+ Optional<unsigned> AlwaysInlineSize;
- /// \sa shouldPruneNullReturnPaths
- llvm::Optional<bool> PruneNullReturnPaths;
+ /// \sa shouldSuppressNullReturnPaths
+ Optional<bool> SuppressNullReturnPaths;
+
+ // \sa getMaxInlinableSize
+ Optional<unsigned> MaxInlinableSize;
/// \sa shouldAvoidSuppressingNullArgumentPaths
- llvm::Optional<bool> AvoidSuppressingNullArgumentPaths;
-
+ Optional<bool> AvoidSuppressingNullArgumentPaths;
+
+ /// \sa shouldSuppressInlinedDefensiveChecks
+ Optional<bool> SuppressInlinedDefensiveChecks;
+
+ /// \sa shouldSuppressFromCXXStandardLibrary
+ Optional<bool> SuppressFromCXXStandardLibrary;
+
/// \sa getGraphTrimInterval
- llvm::Optional<unsigned> GraphTrimInterval;
+ Optional<unsigned> GraphTrimInterval;
+
+ /// \sa getMaxTimesInlineLarge
+ Optional<unsigned> MaxTimesInlineLarge;
+
+ /// \sa getMaxNodesPerTopLevelFunction
+ Optional<unsigned> MaxNodesPerTopLevelFunction;
/// Interprets an option's string value as a boolean.
///
@@ -200,13 +239,20 @@ private:
bool getBooleanOption(StringRef Name, bool DefaultVal);
/// Variant that accepts a Optional value to cache the result.
- bool getBooleanOption(llvm::Optional<bool> &V, StringRef Name,
- bool DefaultVal);
-
+ bool getBooleanOption(Optional<bool> &V, StringRef Name, bool DefaultVal);
+
/// Interprets an option's string value as an integer value.
- int getOptionAsInteger(llvm::StringRef Name, int DefaultVal);
+ 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.
+ UserModeKind getUserMode();
+
+ /// \brief Returns the inter-procedural analysis mode.
+ IPAKind getIPAMode();
+
/// Returns the option controlling which C++ member functions will be
/// considered for inlining.
///
@@ -238,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.
///
@@ -246,12 +299,12 @@ public:
///
/// This is controlled by the 'suppress-null-return-paths' config option,
/// which accepts the values "true" and "false".
- bool shouldPruneNullReturnPaths();
+ bool shouldSuppressNullReturnPaths();
/// Returns whether a bug report should \em not be suppressed if its path
/// includes a call with a null argument, even if that call has a null return.
///
- /// This option has no effect when #shouldPruneNullReturnPaths() is false.
+ /// This option has no effect when #shouldSuppressNullReturnPaths() is false.
///
/// This is a counter-heuristic to avoid false negatives.
///
@@ -259,12 +312,43 @@ public:
/// option, which accepts the values "true" and "false".
bool shouldAvoidSuppressingNullArgumentPaths();
+ /// Returns whether or not diagnostics containing inlined defensive NULL
+ /// checks should be suppressed.
+ ///
+ /// This is controlled by the 'suppress-inlined-defensive-checks' config
+ /// 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.
+ ///
+ /// This is controlled by the 'prune-paths' config option, which accepts the
+ /// 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.
//
// This is controlled by "ipa-always-inline-size" analyzer-config option.
unsigned getAlwaysInlineSize();
-
+
+ // Returns the bound on the number of basic blocks in an inlined function
+ // (50 by default).
+ //
+ // This is controlled by "-analyzer-config max-inlinable-size" option.
+ unsigned getMaxInlinableSize();
+
/// Returns true if the analyzer engine should synthesize fake bodies
/// for well-known functions.
bool shouldSynthesizeBodies();
@@ -276,32 +360,45 @@ public:
/// node reclamation, set the option to "0".
unsigned getGraphTrimInterval();
+ /// Returns the maximum times a large function could be inlined.
+ ///
+ /// This is controlled by the 'max-times-inline-large' config option.
+ unsigned getMaxTimesInlineLarge();
+
+ /// Returns the maximum number of nodes the analyzer can generate while
+ /// exploring a top level function (for each exploded graph).
+ /// 150000 is default; 0 means no limit.
+ ///
+ /// This is controlled by the 'max-nodes' config option.
+ unsigned getMaxNodesPerTopLevelFunction();
+
public:
- AnalyzerOptions() : CXXMemberInliningMode() {
- AnalysisStoreOpt = RegionStoreModel;
- AnalysisConstraintsOpt = RangeConstraintsModel;
- AnalysisDiagOpt = PD_HTML;
- AnalysisPurgeOpt = PurgeStmt;
- IPAMode = DynamicDispatchBifurcate;
- ShowCheckerHelp = 0;
- AnalyzeAll = 0;
- AnalyzerDisplayProgress = 0;
- AnalyzeNestedBlocks = 0;
- eagerlyAssumeBinOpBifurcation = 0;
- TrimGraph = 0;
- visualizeExplodedGraphWithGraphViz = 0;
- visualizeExplodedGraphWithUbiGraph = 0;
- UnoptimizedCFG = 0;
- PrintStats = 0;
- NoRetryExhausted = 0;
+ AnalyzerOptions() :
+ AnalysisStoreOpt(RegionStoreModel),
+ AnalysisConstraintsOpt(RangeConstraintsModel),
+ AnalysisDiagOpt(PD_HTML),
+ AnalysisPurgeOpt(PurgeStmt),
+ ShowCheckerHelp(0),
+ AnalyzeAll(0),
+ AnalyzerDisplayProgress(0),
+ AnalyzeNestedBlocks(0),
+ eagerlyAssumeBinOpBifurcation(0),
+ TrimGraph(0),
+ visualizeExplodedGraphWithGraphViz(0),
+ visualizeExplodedGraphWithUbiGraph(0),
+ UnoptimizedCFG(0),
+ PrintStats(0),
+ NoRetryExhausted(0),
// Cap the stack depth at 4 calls (5 stack frames, base + 4 calls).
- InlineMaxStackDepth = 5;
- InlineMaxFunctionSize = 200;
- InliningMode = NoRedundancy;
- }
+ InlineMaxStackDepth(5),
+ InliningMode(NoRedundancy),
+ UserMode(UMK_NotSet),
+ IPAMode(IPAK_NotSet),
+ CXXMemberInliningMode() {}
+
};
-typedef llvm::IntrusiveRefCntPtr<AnalyzerOptions> AnalyzerOptionsRef;
+typedef IntrusiveRefCntPtr<AnalyzerOptions> AnalyzerOptionsRef;
}
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index b5a88ba9f6c6..7a87e47f74ce 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -19,12 +19,12 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/ilist.h"
-#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/ImmutableSet.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
namespace clang {
@@ -75,6 +75,8 @@ protected:
std::string Description;
PathDiagnosticLocation Location;
PathDiagnosticLocation UniqueingLocation;
+ const Decl *UniqueingDecl;
+
const ExplodedNode *ErrorNode;
SmallVector<SourceRange, 4> Ranges;
ExtraTextList ExtraText;
@@ -87,14 +89,14 @@ protected:
/// diagnostics to include when constructing the final path diagnostic.
/// The stack is largely used by BugReporter when generating PathDiagnostics
/// for multiple PathDiagnosticConsumers.
- llvm::SmallVector<Symbols *, 2> interestingSymbols;
+ SmallVector<Symbols *, 2> interestingSymbols;
/// A (stack of) set of regions that are registered with this report as being
/// "interesting", and thus used to help decide which diagnostics
/// to include when constructing the final path diagnostic.
/// The stack is largely used by BugReporter when generating PathDiagnostics
/// for multiple PathDiagnosticConsumers.
- llvm::SmallVector<Regions *, 2> interestingRegions;
+ SmallVector<Regions *, 2> interestingRegions;
/// A set of location contexts that correspoind to call sites which should be
/// considered "interesting".
@@ -162,9 +164,10 @@ public:
/// for uniquing reports. For example, memory leaks checker, could set this to
/// the allocation site, rather then the location where the bug is reported.
BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode,
- PathDiagnosticLocation LocationToUnique)
+ PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique)
: BT(bt), DeclWithIssue(0), Description(desc),
UniqueingLocation(LocationToUnique),
+ UniqueingDecl(DeclToUnique),
ErrorNode(errornode), ConfigurationChangeToken(0),
DoNotPrunePath(false) {}
@@ -260,6 +263,16 @@ public:
/// This location is used by clients rendering diagnostics.
virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const;
+ /// \brief Get the location on which the report should be uniqued.
+ PathDiagnosticLocation getUniqueingLocation() const {
+ return UniqueingLocation;
+ }
+
+ /// \brief Get the declaration containing the uniqueing location.
+ const Decl *getUniqueingDecl() const {
+ return UniqueingDecl;
+ }
+
const Stmt *getStmt() const;
/// \brief Add a range to a bug report.
@@ -440,8 +453,7 @@ public:
return true;
}
- bool RemoveUneededCalls(PathPieces &pieces, BugReport *R,
- PathDiagnosticCallPiece *CallWithLoc = 0);
+ bool RemoveUnneededCalls(PathPieces &pieces, BugReport *R);
void Register(BugType *BT);
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
index 78e35ca82b89..2e5f207f4b4c 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -55,8 +55,8 @@ public:
///
/// The last parameter can be used to register a new visitor with the given
/// BugReport while processing a node.
- virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
- const ExplodedNode *PrevN,
+ virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
BugReporterContext &BRC,
BugReport &BR) = 0;
@@ -99,26 +99,24 @@ class FindLastStoreBRVisitor
{
const MemRegion *R;
SVal V;
- bool satisfied;
+ 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(SVal v, const MemRegion *r)
- : R(r), V(v), satisfied(false) {
- assert (!V.isUnknown() && "Cannot track unknown value.");
-
- // TODO: Does it make sense to allow undef values here?
- // (If not, also see UndefCapturedBlockVarChecker)?
- }
+ FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R,
+ bool InEnableNullFPSuppression)
+ : R(R),
+ V(V),
+ Satisfied(false),
+ EnableNullFPSuppression(InEnableNullFPSuppression) {}
void Profile(llvm::FoldingSetNodeID &ID) const;
@@ -132,12 +130,14 @@ class TrackConstraintBRVisitor
: public BugReporterVisitorImpl<TrackConstraintBRVisitor>
{
DefinedSVal Constraint;
- const bool Assumption;
- bool isSatisfied;
+ bool Assumption;
+ bool IsSatisfied;
+ bool IsZeroCheck;
public:
TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
- : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
+ : Constraint(constraint), Assumption(assumption), IsSatisfied(false),
+ IsZeroCheck(!Assumption && Constraint.getAs<Loc>()) {}
void Profile(llvm::FoldingSetNodeID &ID) const;
@@ -149,12 +149,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);
@@ -164,6 +171,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.
@@ -223,11 +234,38 @@ public:
const ExplodedNode *N);
bool patternMatch(const Expr *Ex,
- llvm::raw_ostream &Out,
+ raw_ostream &Out,
BugReporterContext &BRC,
BugReport &R,
const ExplodedNode *N,
- llvm::Optional<bool> &prunable);
+ Optional<bool> &prunable);
+};
+
+/// \brief Suppress reports that might lead to known false positives.
+///
+/// Currently this suppresses reports based on locations of bugs.
+class LikelyFalsePositiveSuppressionBRVisitor
+ : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> {
+public:
+ static void *getTag() {
+ static int Tag = 0;
+ return static_cast<void *>(&Tag);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(getTag());
+ }
+
+ virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *Prev,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ return 0;
+ }
+
+ virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR);
};
/// \brief When a region containing undefined value or '0' value is passed
@@ -256,6 +294,38 @@ public:
BugReport &BR);
};
+class SuppressInlineDefensiveChecksVisitor
+: public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor>
+{
+ /// The symbolic value for which we are tracking constraints.
+ /// This value is constrained to null in the end of path.
+ DefinedSVal V;
+
+ /// Track if we found the node where the constraint was first added.
+ bool IsSatisfied;
+
+ /// 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. 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);
+
+ void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ /// Return the tag associated with this visitor. This tag will be used
+ /// to make all PathDiagnosticPieces created by this visitor.
+ static const char *getTag();
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
+ BugReporterContext &BRC,
+ BugReport &BR);
+};
+
namespace bugreporter {
/// Attempts to add visitors to trace a null or undefined value back to its
@@ -268,14 +338,17 @@ 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 Stmt *GetDerefExpr(const ExplodedNode *N);
+const Expr *getDerefExpr(const Stmt *S);
const Stmt *GetDenomExpr(const ExplodedNode *N);
const Stmt *GetRetValExpr(const ExplodedNode *N);
bool isDeclRefExprToReference(const Expr *E);
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
index cb49122e4a53..644aa3159301 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
#define LLVM_CLANG_ANALYSIS_BUGTYPE
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/FoldingSet.h"
#include <string>
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 6dc26e670344..3f0a1b1bc144 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -14,12 +14,12 @@
#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
#define LLVM_CLANG_PATH_DIAGNOSTIC_H
-#include "clang/Basic/SourceLocation.h"
#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PointerUnion.h"
#include <deque>
#include <iterator>
#include <string>
@@ -341,7 +341,7 @@ protected:
public:
virtual ~PathDiagnosticPiece();
- llvm::StringRef getString() const { return str; }
+ StringRef getString() const { return str; }
/// Tag this PathDiagnosticPiece with the given C-string.
void setTag(const char *tag) { Tag = tag; }
@@ -461,13 +461,13 @@ public:
};
class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
- llvm::Optional<bool> IsPrunable;
+ Optional<bool> IsPrunable;
/// If the event occurs in a different frame than the final diagnostic,
/// supply a message that will be used to construct an extra hint on the
/// returns from all the calls on the stack from this event to the final
/// diagnostic.
- llvm::OwningPtr<StackHintGenerator> CallStackHint;
+ OwningPtr<StackHintGenerator> CallStackHint;
public:
PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
@@ -670,13 +670,19 @@ class PathDiagnostic : public llvm::FoldingSetNode {
std::deque<std::string> OtherDesc;
PathDiagnosticLocation Loc;
PathPieces pathImpl;
- llvm::SmallVector<PathPieces *, 3> pathStack;
+ SmallVector<PathPieces *, 3> pathStack;
- PathDiagnostic(); // Do not implement.
+ /// \brief Important bug uniqueing location.
+ /// The location info is useful to differentiate between bugs.
+ PathDiagnosticLocation UniqueingLoc;
+ const Decl *UniqueingDecl;
+
+ PathDiagnostic() LLVM_DELETED_FUNCTION;
public:
PathDiagnostic(const Decl *DeclWithIssue, StringRef bugtype,
StringRef verboseDesc, StringRef shortDesc,
- StringRef category);
+ StringRef category, PathDiagnosticLocation LocationToUnique,
+ const Decl *DeclToUnique);
~PathDiagnostic();
@@ -738,6 +744,16 @@ public:
return Loc;
}
+ /// \brief Get the location on which the report should be uniqued.
+ PathDiagnosticLocation getUniqueingLoc() const {
+ return UniqueingLoc;
+ }
+
+ /// \brief Get the declaration containing the uniqueing location.
+ const Decl *getUniqueingDecl() const {
+ return UniqueingDecl;
+ }
+
void flattenLocations() {
Loc.flatten();
for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end();
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index 9eb1248f6a71..0dbaab033d2d 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -34,11 +34,11 @@ class ASTDecl {
template <typename CHECKER>
static void _checkDecl(void *checker, const Decl *D, AnalysisManager& mgr,
BugReporter &BR) {
- ((const CHECKER *)checker)->checkASTDecl(llvm::cast<DECL>(D), mgr, BR);
+ ((const CHECKER *)checker)->checkASTDecl(cast<DECL>(D), mgr, BR);
}
static bool _handlesDecl(const Decl *D) {
- return llvm::isa<DECL>(D);
+ return isa<DECL>(D);
}
public:
template <typename CHECKER>
@@ -86,11 +86,11 @@ template <typename STMT>
class PreStmt {
template <typename CHECKER>
static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) {
- ((const CHECKER *)checker)->checkPreStmt(llvm::cast<STMT>(S), C);
+ ((const CHECKER *)checker)->checkPreStmt(cast<STMT>(S), C);
}
static bool _handlesStmt(const Stmt *S) {
- return llvm::isa<STMT>(S);
+ return isa<STMT>(S);
}
public:
template <typename CHECKER>
@@ -105,11 +105,11 @@ template <typename STMT>
class PostStmt {
template <typename CHECKER>
static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) {
- ((const CHECKER *)checker)->checkPostStmt(llvm::cast<STMT>(S), C);
+ ((const CHECKER *)checker)->checkPostStmt(cast<STMT>(S), C);
}
static bool _handlesStmt(const Stmt *S) {
- return llvm::isa<STMT>(S);
+ return isa<STMT>(S);
}
public:
template <typename CHECKER>
@@ -227,18 +227,18 @@ public:
}
};
-class EndPath {
+class EndFunction {
template <typename CHECKER>
- static void _checkEndPath(void *checker,
- CheckerContext &C) {
- ((const CHECKER *)checker)->checkEndPath(C);
+ static void _checkEndFunction(void *checker,
+ CheckerContext &C) {
+ ((const CHECKER *)checker)->checkEndFunction(C);
}
public:
template <typename CHECKER>
static void _register(CHECKER *checker, CheckerManager &mgr) {
- mgr._registerForEndPath(
- CheckerManager::CheckEndPathFunc(checker, _checkEndPath<CHECKER>));
+ mgr._registerForEndFunction(
+ CheckerManager::CheckEndFunctionFunc(checker, _checkEndFunction<CHECKER>));
}
};
@@ -293,7 +293,7 @@ class RegionChanges {
static ProgramStateRef
_checkRegionChanges(void *checker,
ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> Explicits,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) {
@@ -317,6 +317,59 @@ public:
}
};
+class PointerEscape {
+ template <typename CHECKER>
+ static ProgramStateRef
+ _checkPointerEscape(void *checker,
+ ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ bool IsConst) {
+ if (!IsConst)
+ return ((const CHECKER *)checker)->checkPointerEscape(State,
+ Escaped,
+ Call,
+ Kind);
+ return State;
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForPointerEscape(
+ CheckerManager::CheckPointerEscapeFunc(checker,
+ _checkPointerEscape<CHECKER>));
+ }
+};
+
+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>
@@ -448,6 +501,14 @@ struct ImplicitNullDerefEvent {
BugReporter *BR;
};
+/// \brief A helper class which wraps a boolean value set to false by default.
+struct DefaultBool {
+ bool val;
+ DefaultBool() : val(false) {}
+ operator bool() const { return val; }
+ DefaultBool &operator=(bool b) { val = b; return *this; }
+};
+
} // end ento namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 7ae8e53784bf..6f99fc14577a 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -14,12 +14,12 @@
#ifndef LLVM_CLANG_SA_CORE_CHECKERMANAGER_H
#define LLVM_CLANG_SA_CORE_CHECKERMANAGER_H
+#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/LangOptions.h"
-#include "llvm/ADT/SmallVector.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
-#include "clang/Analysis/ProgramPoint.h"
+#include "llvm/ADT/SmallVector.h"
#include <vector>
namespace clang {
@@ -112,6 +112,26 @@ public:
RET operator()() const { return Fn(Checker); }
};
+/// \brief Describes the different reasons a pointer escapes
+/// during analysis.
+enum PointerEscapeKind {
+ /// A pointer escapes due to binding its value to a location
+ /// that the analyzer cannot track.
+ PSK_EscapeOnBind,
+
+ /// The pointer has been passed to a function call directly.
+ PSK_DirectEscapeOnCall,
+
+ /// The pointer has been passed to a function indirectly.
+ /// For example, the pointer is accessible through an
+ /// argument to a function.
+ PSK_IndirectEscapeOnCall,
+
+ /// The reason for pointer escape is unknown. For example,
+ /// a region containing this pointer is invalidated.
+ PSK_EscapeOther
+};
+
class CheckerManager {
const LangOptions LangOpts;
@@ -264,11 +284,11 @@ public:
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng);
- /// \brief Run checkers for end of path.
- void runCheckersForEndPath(NodeBuilderContext &BC,
- ExplodedNodeSet &Dst,
- ExplodedNode *Pred,
- ExprEngine &Eng);
+ /// \brief Run checkers on end of function.
+ void runCheckersForEndFunction(NodeBuilderContext &BC,
+ ExplodedNodeSet &Dst,
+ ExplodedNode *Pred,
+ ExprEngine &Eng);
/// \brief Run checkers for branch condition.
void runCheckersForBranchCondition(const Stmt *condition,
@@ -310,14 +330,34 @@ public:
/// by a call.
ProgramStateRef
runCheckersForRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call);
+ /// \brief Run checkers when pointers escape.
+ ///
+ /// This notifies the checkers about pointer escape, which occurs whenever
+ /// the analyzer cannot track the symbol any more. For example, as a
+ /// result of assigning a pointer into a global or when it's passed to a
+ /// function call the analyzer cannot model.
+ ///
+ /// \param State The state at the point of escape.
+ /// \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,
+ bool IsConst = false);
+
/// \brief Run checkers for handling assumptions on symbolic values.
ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state,
- SVal Cond, bool Assumption);
+ SVal Cond, bool Assumption);
/// \brief Run checkers for evaluating a call.
///
@@ -382,7 +422,7 @@ public:
CheckEndAnalysisFunc;
typedef CheckerFn<void (CheckerContext &)>
- CheckEndPathFunc;
+ CheckEndFunctionFunc;
typedef CheckerFn<void (const Stmt *, CheckerContext &)>
CheckBranchConditionFunc;
@@ -393,13 +433,20 @@ public:
typedef CheckerFn<void (ProgramStateRef,SymbolReaper &)> CheckLiveSymbolsFunc;
typedef CheckerFn<ProgramStateRef (ProgramStateRef,
- const StoreManager::InvalidatedSymbols *symbols,
+ const InvalidatedSymbols *symbols,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call)>
CheckRegionChangesFunc;
typedef CheckerFn<bool (ProgramStateRef)> WantsRegionChangeUpdateFunc;
+
+ typedef CheckerFn<ProgramStateRef (ProgramStateRef,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ bool IsConst)>
+ CheckPointerEscapeFunc;
typedef CheckerFn<ProgramStateRef (ProgramStateRef,
const SVal &cond, bool assumption)>
@@ -430,7 +477,7 @@ public:
void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn);
- void _registerForEndPath(CheckEndPathFunc checkfn);
+ void _registerForEndFunction(CheckEndFunctionFunc checkfn);
void _registerForBranchCondition(CheckBranchConditionFunc checkfn);
@@ -441,6 +488,10 @@ public:
void _registerForRegionChanges(CheckRegionChangesFunc checkfn,
WantsRegionChangeUpdateFunc wantUpdateFn);
+ void _registerForPointerEscape(CheckPointerEscapeFunc checkfn);
+
+ void _registerForConstPointerEscape(CheckPointerEscapeFunc checkfn);
+
void _registerForEvalAssume(EvalAssumeFunc checkfn);
void _registerForEvalCall(EvalCallFunc checkfn);
@@ -552,7 +603,7 @@ private:
std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers;
- std::vector<CheckEndPathFunc> EndPathCheckers;
+ std::vector<CheckEndFunctionFunc> EndFunctionCheckers;
std::vector<CheckBranchConditionFunc> BranchConditionCheckers;
@@ -566,6 +617,8 @@ private:
};
std::vector<RegionChangesCheckerInfo> RegionChangesCheckers;
+ std::vector<CheckPointerEscapeFunc> PointerEscapeCheckers;
+
std::vector<EvalAssumeFunc> EvalAssumeCheckers;
std::vector<EvalCallFunc> EvalCallCheckers;
diff --git a/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h b/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h
index 6ce5b3c5095e..e981871ae4e0 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
namespace clang {
namespace ento {
diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
index 1452d45073aa..4557aa40ea80 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
@@ -10,8 +10,8 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include <vector>
// FIXME: move this information to an HTML file in docs/.
diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
index 3aab648dc574..b856de7dc612 100644
--- a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
+++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
@@ -19,6 +19,7 @@
namespace clang {
+class AnalyzerOptions;
class Preprocessor;
namespace ento {
@@ -26,21 +27,18 @@ namespace ento {
class PathDiagnosticConsumer;
typedef std::vector<PathDiagnosticConsumer*> PathDiagnosticConsumers;
-void createHTMLDiagnosticConsumer(PathDiagnosticConsumers &C,
- const std::string& prefix,
- const Preprocessor &PP);
+#define CREATE_CONSUMER(NAME)\
+void create ## NAME ## DiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,\
+ PathDiagnosticConsumers &C,\
+ const std::string& prefix,\
+ const Preprocessor &PP);
-void createPlistDiagnosticConsumer(PathDiagnosticConsumers &C,
- const std::string& prefix,
- const Preprocessor &PP);
+CREATE_CONSUMER(HTML)
+CREATE_CONSUMER(Plist)
+CREATE_CONSUMER(PlistMultiFile)
+CREATE_CONSUMER(TextPath)
-void createPlistMultiFileDiagnosticConsumer(PathDiagnosticConsumers &C,
- const std::string& prefix,
- const Preprocessor &PP);
-
-void createTextPathDiagnosticConsumer(PathDiagnosticConsumers &C,
- const std::string& prefix,
- const Preprocessor &PP);
+#undef CREATE_CONSUMER
} // end 'ento' namespace
} // end 'clang' namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
index 27f3677bba22..9502900f7e35 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/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index 9038ae5276a7..458c8966e79e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -100,7 +100,7 @@ public:
}
bool shouldInlineCall() const {
- return options.IPAMode != None;
+ return options.getIPAMode() != IPAK_None;
}
CFG *getCFG(Decl const *D) {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index fb393548b1af..1135b511441d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -16,9 +16,10 @@
#ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H
#define LLVM_CLANG_GR_BASICVALUEFACTORY_H
+#include "clang/AST/ASTContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
namespace clang {
namespace ento {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index a6a91e2b66df..f990b8dcd0ec 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -16,11 +16,11 @@
#ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL
#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL
-#include "clang/Basic/SourceManager.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/PointerIntPair.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() {}
@@ -181,7 +181,7 @@ public:
}
/// \brief The state in which the call is being evaluated.
- ProgramStateRef getState() const {
+ const ProgramStateRef &getState() const {
return State;
}
@@ -228,6 +228,11 @@ public:
return false;
}
+ /// \brief Returns true if this is a call to a variadic function or method.
+ virtual bool isVariadic() const {
+ return false;
+ }
+
/// \brief Returns a source range for the entire call, suitable for
/// outputting in diagnostics.
virtual SourceRange getSourceRange() const {
@@ -331,7 +336,9 @@ public:
/// of some kind.
static bool isCallStmt(const Stmt *S);
- /// \brief Returns the result type of a function, method declaration.
+ /// \brief Returns the result type of a function or method declaration.
+ ///
+ /// This will return a null QualType if the result type cannot be determined.
static QualType getDeclaredResultType(const Decl *D);
// Iterator access to formal parameters and their types.
@@ -416,6 +423,10 @@ public:
return RuntimeDefinition();
}
+ virtual bool isVariadic() const {
+ return getDecl()->isVariadic();
+ }
+
virtual bool argumentsMayEscape() const;
virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
@@ -493,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.
@@ -516,6 +527,10 @@ public:
return RuntimeDefinition(getBlockDecl());
}
+ virtual bool isVariadic() const {
+ return getBlockDecl()->isVariadic();
+ }
+
virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
BindingsTy &Bindings) const;
@@ -533,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)
@@ -716,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 {
@@ -815,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,
@@ -834,6 +849,9 @@ public:
virtual const Expr *getArgExpr(unsigned Index) const {
return getOriginExpr()->getArg(Index);
}
+ virtual bool isVariadic() const {
+ return getDecl()->isVariadic();
+ }
bool isInstanceMessage() const {
return getOriginExpr()->isInstanceMessage();
@@ -1024,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 4558cd9c9480..cda1366a4399 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -119,7 +119,7 @@ public:
/// the state of the program before the checker ran. Note, checkers should
/// not retain the node in their state since the nodes might get invalidated.
ExplodedNode *getPredecessor() { return Pred; }
- ProgramStateRef getState() const { return Pred->getState(); }
+ const ProgramStateRef &getState() const { return Pred->getState(); }
/// \brief Check if the checker changed the state of the execution; ex: added
/// a new transition or a bug report.
@@ -185,7 +185,7 @@ public:
/// example, for finding variables that the given symbol was assigned to.
static const MemRegion *getLocationRegionIfPostStore(const ExplodedNode *N) {
ProgramPoint L = N->getLocation();
- if (const PostStore *PSL = dyn_cast<PostStore>(&L))
+ if (Optional<PostStore> PSL = L.getAs<PostStore>())
return reinterpret_cast<const MemRegion*>(PSL->getLocationValue());
return 0;
}
@@ -303,14 +303,6 @@ private:
}
};
-/// \brief A helper class which wraps a boolean value set to false by default.
-struct DefaultBool {
- bool Val;
- DefaultBool() : Val(false) {}
- operator bool() const { return Val; }
- DefaultBool &operator=(bool b) { Val = b; return *this; }
-};
-
} // end GR namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index 4a78849024ae..1e76ea6ed647 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -14,8 +14,8 @@
#ifndef LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
#define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
-#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/Support/SaveAndRestore.h"
namespace llvm {
@@ -28,7 +28,7 @@ namespace ento {
class SubEngine;
class ConditionTruthVal {
- llvm::Optional<bool> Val;
+ Optional<bool> Val;
public:
/// Construct a ConditionTruthVal indicating the constraint is constrained
/// to either true or false, depending on the boolean value provided.
@@ -78,9 +78,13 @@ public:
// If StTrue is infeasible, asserting the falseness of Cond is unnecessary
// because the existing constraints already establish this.
if (!StTrue) {
- // FIXME: This is fairly expensive and should be disabled even in
- // Release+Asserts builds.
+#ifndef __OPTIMIZE__
+ // This check is expensive and should be disabled even in Release+Asserts
+ // builds.
+ // FIXME: __OPTIMIZE__ is a GNU extension that Clang implements but MSVC
+ // does not. Is there a good equivalent there?
assert(assume(State, Cond, false) && "System is over constrained.");
+#endif
return ProgramStatePair((ProgramStateRef)NULL, State);
}
@@ -118,7 +122,7 @@ public:
/// Convenience method to query the state to see if a symbol is null or
/// not null, or if neither assumption can be made.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym) {
- llvm::SaveAndRestore<bool> DisableNotify(NotifyAssumeClients, false);
+ SaveAndRestore<bool> DisableNotify(NotifyAssumeClients, false);
return checkNull(State, Sym);
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index b6686409e5aa..a2e211edea8b 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -17,10 +17,10 @@
#include "clang/AST/Expr.h"
#include "clang/Analysis/AnalysisContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
#include "llvm/ADT/OwningPtr.h"
namespace clang {
@@ -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;
@@ -463,7 +467,7 @@ public:
bool operator!=(const iterator &X) const { return I != X.I; }
const LabelDecl *getLabel() const {
- return llvm::cast<LabelStmt>((*I)->getLabel())->getDecl();
+ return cast<LabelStmt>((*I)->getLabel())->getDecl();
}
const CFGBlock *getBlock() const {
@@ -510,7 +514,7 @@ public:
bool operator==(const iterator &X) const { return I == X.I; }
const CaseStmt *getCase() const {
- return llvm::cast<CaseStmt>((*I)->getLabel());
+ return cast<CaseStmt>((*I)->getLabel());
}
const CFGBlock *getBlock() const {
@@ -522,7 +526,7 @@ public:
iterator end() { return iterator(Src->succ_rend()); }
const SwitchStmt *getSwitch() const {
- return llvm::cast<SwitchStmt>(Src->getTerminator());
+ return cast<SwitchStmt>(Src->getTerminator());
}
ExplodedNode *generateCaseStmtNode(const iterator &I,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index eb9bd85fe64d..f3a582da040f 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -33,9 +33,6 @@ class SValBuilder;
/// other things.
class EnvironmentEntry : public std::pair<const Stmt*,
const StackFrameContext *> {
- friend class EnvironmentManager;
- EnvironmentEntry makeLocation() const;
-
public:
EnvironmentEntry(const Stmt *s, const LocationContext *L);
@@ -118,13 +115,6 @@ public:
/// Bind a symbolic value to the given environment entry.
Environment bindExpr(Environment Env, const EnvironmentEntry &E, SVal V,
bool Invalidate);
-
- /// Bind the location 'location' and value 'V' to the specified
- /// environment entry.
- Environment bindExprAndLocation(Environment Env,
- const EnvironmentEntry &E,
- SVal location,
- SVal V);
Environment removeDeadBindings(Environment Env,
SymbolReaper &SymReaper,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index b112e66d30d3..5211916407c8 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -19,19 +19,19 @@
#ifndef LLVM_CLANG_GR_EXPLODEDGRAPH
#define LLVM_CLANG_GR_EXPLODEDGRAPH
-#include "clang/Analysis/ProgramPoint.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/Decl.h"
-#include "llvm/ADT/SmallVector.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
-#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/GraphTraits.h"
-#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/Support/Casting.h"
-#include "clang/Analysis/Support/BumpVector.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include <vector>
namespace clang {
@@ -152,10 +152,12 @@ public:
return *getLocationContext()->getAnalysis<T>();
}
- ProgramStateRef getState() const { return State; }
+ const ProgramStateRef &getState() const { return State; }
template <typename T>
- const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); }
+ Optional<T> getLocationAs() const LLVM_LVALUE_FUNCTION {
+ return Location.getAs<T>();
+ }
static void Profile(llvm::FoldingSetNodeID &ID,
const ProgramPoint &Loc,
@@ -167,7 +169,8 @@ public:
}
void Profile(llvm::FoldingSetNodeID& ID) const {
- Profile(ID, getLocation(), getState(), isSink());
+ // We avoid copy constructors by not using accessors.
+ Profile(ID, Location, State, isSink());
}
/// addPredeccessor - Adds a predecessor to the current node, and
@@ -236,18 +239,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:
@@ -365,14 +358,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().
@@ -384,6 +382,10 @@ public:
/// was called.
void reclaimRecentlyAllocatedNodes();
+ /// \brief Returns true if nodes for the given expression kind are always
+ /// kept around.
+ static bool isInterestingLValueExpr(const Expr *Ex);
+
private:
bool shouldCollect(const ExplodedNode *node);
void collectNode(ExplodedNode *node);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 78b254222e9e..33e4431eb4be 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -16,15 +16,15 @@
#ifndef LLVM_CLANG_GR_EXPRENGINE
#define LLVM_CLANG_GR_EXPRENGINE
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/Type.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
namespace clang {
@@ -44,8 +44,19 @@ namespace ento {
class AnalysisManager;
class CallEvent;
class SimpleCall;
+class CXXConstructorCall;
class ExprEngine : public SubEngine {
+public:
+ /// The modes of inlining, which override the default analysis-wide settings.
+ enum InliningModes {
+ /// Follow the default settings for inlining callees.
+ Inline_Regular = 0,
+ /// Do minimal inlining of callees.
+ Inline_Minimal = 0x1
+ };
+
+private:
AnalysisManager &AMgr;
AnalysisDeclContextManager &AnalysisDeclContexts;
@@ -64,15 +75,6 @@ class ExprEngine : public SubEngine {
/// svalBuilder - SValBuilder object that creates SVals from expressions.
SValBuilder &svalBuilder;
- /// EntryNode - The immediate predecessor node.
- ExplodedNode *EntryNode;
-
- /// CleanedState - The state for EntryNode "cleaned" of all dead
- /// variables and symbols (as determined by a liveness analysis).
- ProgramStateRef CleanedState;
-
- /// currStmt - The current block-level statement.
- const Stmt *currStmt;
unsigned int currStmtIdx;
const NodeBuilderContext *currBldrCtx;
@@ -92,10 +94,14 @@ class ExprEngine : public SubEngine {
/// AnalysisConsumer. It can be null.
SetOfConstDecls *VisitedCallees;
+ /// The flag, which specifies the mode of inlining for the engine.
+ InliningModes HowToInline;
+
public:
ExprEngine(AnalysisManager &mgr, bool gcEnabled,
SetOfConstDecls *VisitedCalleesIn,
- FunctionSummariesTy *FS);
+ FunctionSummariesTy *FS,
+ InliningModes HowToInlineIn);
~ExprEngine();
@@ -140,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.
@@ -154,26 +161,33 @@ public:
const ExplodedGraph& getGraph() const { return G; }
/// \brief Run the analyzer's garbage collection - remove dead symbols and
- /// bindings.
+ /// bindings from the state.
///
- /// \param Node - The predecessor node, from which the processing should
- /// start.
- /// \param Out - The returned set of output nodes.
- /// \param ReferenceStmt - Run garbage collection using the symbols,
- /// which are live before the given statement.
- /// \param LC - The location context of the ReferenceStmt.
- /// \param DiagnosticStmt - the statement used to associate the diagnostic
- /// message, if any warnings should occur while removing the dead (leaks
- /// are usually reported here).
- /// \param K - In some cases it is possible to use PreStmt kind. (Do
- /// not use it unless you know what you are doing.)
- /// If the ReferenceStmt is NULL, everything is this and parent contexts is
- /// considered live.
- /// If the stack frame context is NULL, everything on stack is considered
- /// dead.
+ /// Checkers can participate in this process with two callbacks:
+ /// \c checkLiveSymbols and \c checkDeadSymbols. See the CheckerDocumentation
+ /// class for more information.
+ ///
+ /// \param Node The predecessor node, from which the processing should start.
+ /// \param Out The returned set of output nodes.
+ /// \param ReferenceStmt The statement which is about to be processed.
+ /// Everything needed for this statement should be considered live.
+ /// A null statement means that everything in child LocationContexts
+ /// is dead.
+ /// \param LC The location context of the \p ReferenceStmt. A null location
+ /// context means that we have reached the end of analysis and that
+ /// all statements and local variables should be considered dead.
+ /// \param DiagnosticStmt Used as a location for any warnings that should
+ /// occur while removing the dead (e.g. leaks). By default, the
+ /// \p ReferenceStmt is used.
+ /// \param K Denotes whether this is a pre- or post-statement purge. This
+ /// must only be ProgramPoint::PostStmtPurgeDeadSymbolsKind if an
+ /// entire location context is being cleared, in which case the
+ /// \p ReferenceStmt must either be a ReturnStmt or \c NULL. Otherwise,
+ /// it must be ProgramPoint::PreStmtPurgeDeadSymbolsKind (the default)
+ /// and \p ReferenceStmt must be valid (non-null).
void removeDead(ExplodedNode *Node, ExplodedNodeSet &Out,
- const Stmt *ReferenceStmt, const StackFrameContext *LC,
- const Stmt *DiagnosticStmt,
+ const Stmt *ReferenceStmt, const LocationContext *LC,
+ const Stmt *DiagnosticStmt = 0,
ProgramPoint::Kind K = ProgramPoint::PreStmtPurgeDeadSymbolsKind);
/// processCFGElement - Called by CoreEngine. Used to generate new successor
@@ -210,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);
@@ -218,8 +241,8 @@ public:
/// nodes by processing the 'effects' of a switch statement.
void processSwitch(SwitchNodeBuilder& builder);
- /// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
- /// nodes when the control reaches the end of a function.
+ /// Called by CoreEngine. Used to generate end-of-path
+ /// nodes when the control reaches the end of a function.
void processEndOfFunction(NodeBuilderContext& BC,
ExplodedNode *Pred);
@@ -250,7 +273,7 @@ public:
/// to the store. Used to update checkers that track region values.
ProgramStateRef
processRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call);
@@ -416,11 +439,11 @@ public:
geteagerlyAssumeBinOpBifurcationTags();
SVal evalMinus(SVal X) {
- return X.isValid() ? svalBuilder.evalMinus(cast<NonLoc>(X)) : X;
+ return X.isValid() ? svalBuilder.evalMinus(X.castAs<NonLoc>()) : X;
}
SVal evalComplement(SVal X) {
- return X.isValid() ? svalBuilder.evalComplement(cast<NonLoc>(X)) : X;
+ return X.isValid() ? svalBuilder.evalComplement(X.castAs<NonLoc>()) : X;
}
public:
@@ -432,7 +455,8 @@ public:
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
NonLoc L, SVal R, QualType T) {
- return R.isValid() ? svalBuilder.evalBinOpNN(state,op,L, cast<NonLoc>(R), T) : R;
+ return R.isValid() ? svalBuilder.evalBinOpNN(state, op, L,
+ R.castAs<NonLoc>(), T) : R;
}
SVal evalBinOp(ProgramStateRef ST, BinaryOperator::Opcode Op,
@@ -447,6 +471,20 @@ protected:
SVal location, SVal Val, bool atDeclInit = false,
const ProgramPoint *PP = 0);
+ /// Call PointerEscape callback when a value escapes as a result of bind.
+ ProgramStateRef processPointerEscapedOnBind(ProgramStateRef State,
+ SVal Loc, SVal Val);
+ /// Call PointerEscape callback when a value escapes as a result of
+ /// region invalidation.
+ /// \param[in] IsConst Specifies that the pointer is const.
+ ProgramStateRef notifyCheckersOfPointerEscape(
+ ProgramStateRef State,
+ const InvalidatedSymbols *Invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const CallEvent *Call,
+ bool IsConst);
+
public:
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
@@ -506,7 +544,10 @@ private:
void examineStackFrames(const Decl *D, const LocationContext *LCtx,
bool &IsRecursive, unsigned &StackDepth);
- bool shouldInlineDecl(const Decl *D, ExplodedNode *Pred);
+ /// Checks our policies and decides weither the given call should be inlined.
+ bool shouldInlineCall(const CallEvent &Call, const Decl *D,
+ const ExplodedNode *Pred);
+
bool inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr,
ExplodedNode *Pred, ProgramStateRef State);
@@ -522,6 +563,22 @@ private:
ExplodedNode *Pred);
bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC);
+
+ /// Models a trivial copy or move constructor or trivial assignment operator
+ /// call with a simple bind.
+ void performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
+ 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
+ /// that.
+ ///
+ /// If \p ResultE is provided, the new region will be bound to this expression
+ /// instead of \p E.
+ ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State,
+ const LocationContext *LC,
+ const Expr *E,
+ const Expr *ResultE = 0);
};
/// Traits for storing the call processing policy inside GDM.
@@ -531,7 +588,7 @@ private:
struct ReplayWithoutInlining{};
template <>
struct ProgramStateTrait<ReplayWithoutInlining> :
- public ProgramStatePartialTrait<void*> {
+ public ProgramStatePartialTrait<const void*> {
static void *GDMIndex() { static int index = 0; return &index; }
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
index cf4a6929a3aa..169af939f08e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
@@ -7,94 +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 <deque>
-#include "clang/AST/Decl.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/BitVector.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 : 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();
+ if (I != Map.end())
+ 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 0;
+ }
+
+ void bumpNumTimesInlined(const Decl* D) {
+ MapTy::iterator I = findOrInsertSummary(D);
+ 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 34fbc3ca9e83..af2f365ead96 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -22,8 +22,8 @@
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "llvm/Support/ErrorHandling.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/ErrorHandling.h"
#include <string>
namespace llvm {
@@ -642,26 +642,20 @@ public:
explicit referenced_vars_iterator(const MemRegion * const *r,
const MemRegion * const *originalR)
: R(r), OriginalR(originalR) {}
-
- operator const MemRegion * const *() const {
- return R;
- }
-
- const MemRegion *getCapturedRegion() const {
- return *R;
- }
- const MemRegion *getOriginalRegion() const {
- return *OriginalR;
- }
- const VarRegion* operator*() const {
+ const VarRegion *getCapturedRegion() const {
return cast<VarRegion>(*R);
}
-
+ const VarRegion *getOriginalRegion() const {
+ return cast<VarRegion>(*OriginalR);
+ }
+
bool operator==(const referenced_vars_iterator &I) const {
+ assert((R == 0) == (I.R == 0));
return I.R == R;
}
bool operator!=(const referenced_vars_iterator &I) const {
+ assert((R == 0) == (I.R == 0));
return I.R != R;
}
referenced_vars_iterator &operator++() {
@@ -670,6 +664,10 @@ public:
return *this;
}
};
+
+ /// Return the original region for a captured region, if
+ /// one exists.
+ const VarRegion *getOriginalRegion(const VarRegion *VR) const;
referenced_vars_iterator referenced_vars_begin() const;
referenced_vars_iterator referenced_vars_end() const;
@@ -686,6 +684,8 @@ public:
}
private:
void LazyInitializeReferencedVars();
+ std::pair<const VarRegion *, const VarRegion *>
+ getCaptureRegions(const VarDecl *VD);
};
/// SymbolicRegion - A special, "non-concrete" region. Unlike other region
@@ -952,6 +952,9 @@ public:
const ObjCIvarDecl *getDecl() const;
QualType getValueType() const;
+ bool canPrintPretty() const;
+ void printPretty(raw_ostream &os) const;
+
void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
@@ -993,8 +996,8 @@ class ElementRegion : public TypedValueRegion {
ElementRegion(QualType elementType, NonLoc Idx, const MemRegion* sReg)
: TypedValueRegion(sReg, ElementRegionKind),
ElementType(elementType), Index(Idx) {
- assert((!isa<nonloc::ConcreteInt>(&Idx) ||
- cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) &&
+ assert((!Idx.getAs<nonloc::ConcreteInt>() ||
+ Idx.castAs<nonloc::ConcreteInt>().getValue().isSigned()) &&
"The index must be signed");
}
@@ -1057,16 +1060,18 @@ public:
class CXXBaseObjectRegion : public TypedValueRegion {
friend class MemRegionManager;
- const CXXRecordDecl *decl;
+ llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Data;
- CXXBaseObjectRegion(const CXXRecordDecl *d, const MemRegion *sReg)
- : TypedValueRegion(sReg, CXXBaseObjectRegionKind), decl(d) {}
+ CXXBaseObjectRegion(const CXXRecordDecl *RD, bool IsVirtual,
+ const MemRegion *SReg)
+ : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {}
- static void ProfileRegion(llvm::FoldingSetNodeID &ID,
- const CXXRecordDecl *decl, const MemRegion *sReg);
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD,
+ bool IsVirtual, const MemRegion *SReg);
public:
- const CXXRecordDecl *getDecl() const { return decl; }
+ const CXXRecordDecl *getDecl() const { return Data.getPointer(); }
+ bool isVirtual() const { return Data.getInt(); }
QualType getValueType() const;
@@ -1216,15 +1221,21 @@ public:
const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex,
LocationContext const *LC);
- const CXXBaseObjectRegion *getCXXBaseObjectRegion(const CXXRecordDecl *decl,
- const MemRegion *superRegion);
+ /// Create a CXXBaseObjectRegion with the given base class for region
+ /// \p Super.
+ ///
+ /// The type of \p Super is assumed be a class deriving from \p BaseClass.
+ const CXXBaseObjectRegion *
+ getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const MemRegion *Super,
+ bool IsVirtual);
/// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different
/// super region.
const CXXBaseObjectRegion *
getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg,
const MemRegion *superRegion) {
- return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion);
+ return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion,
+ baseReg->isVirtual());
}
const FunctionTextRegion *getFunctionTextRegion(const NamedDecl *FD);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 86c94deab5e8..6ea7211090ba 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -18,13 +18,13 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h"
-#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/PointerIntPair.h"
namespace llvm {
class APSInt;
@@ -170,19 +170,30 @@ public:
// If no new state is feasible, NULL is returned.
//
+ /// Assumes that the value of \p cond is zero (if \p assumption is "false")
+ /// or non-zero (if \p assumption is "true").
+ ///
+ /// This returns a new state with the added constraint on \p cond.
+ /// If no new state is feasible, NULL is returned.
ProgramStateRef assume(DefinedOrUnknownSVal cond, bool assumption) const;
- /// This method assumes both "true" and "false" for 'cond', and
- /// returns both corresponding states. It's shorthand for doing
- /// 'assume' twice.
- std::pair<ProgramStateRef , ProgramStateRef >
+ /// Assumes both "true" and "false" for \p cond, and returns both
+ /// corresponding states (respectively).
+ ///
+ /// This is more efficient than calling assume() twice. Note that one (but not
+ /// both) of the returned states may be NULL.
+ std::pair<ProgramStateRef, ProgramStateRef>
assume(DefinedOrUnknownSVal cond) const;
ProgramStateRef assumeInBound(DefinedOrUnknownSVal idx,
DefinedOrUnknownSVal upperBound,
bool assumption,
QualType IndexType = QualType()) const;
-
+
+ /// \brief Check if the given SVal is constrained to zero or is a zero
+ /// constant.
+ ConditionTruthVal isNull(SVal V) const;
+
/// Utility method for getting regions.
const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
@@ -203,12 +214,6 @@ public:
ProgramStateRef BindExpr(const Stmt *S, const LocationContext *LCtx,
SVal V, bool Invalidate = true) const;
- /// Create a new state by binding the value 'V' and location 'locaton' to the
- /// statement 'S' in the state's environment.
- ProgramStateRef bindExprAndLocation(const Stmt *S,
- const LocationContext *LCtx,
- SVal location, SVal V) const;
-
ProgramStateRef bindLoc(Loc location,
SVal V,
bool notifyChanges = true) const;
@@ -219,14 +224,38 @@ public:
ProgramStateRef killBinding(Loc LV) const;
- /// invalidateRegions - Returns the state with bindings for the given regions
- /// cleared from the store. The regions are provided as a continuous array
- /// from Begin to End. Optionally invalidates global regions as well.
- ProgramStateRef invalidateRegions(ArrayRef<const MemRegion *> Regions,
- const Expr *E, unsigned BlockCount,
- const LocationContext *LCtx,
- StoreManager::InvalidatedSymbols *IS = 0,
- const CallEvent *Call = 0) const;
+ /// \brief Returns the state with bindings for the given regions
+ /// cleared from the store.
+ ///
+ /// Optionally invalidates global regions as well.
+ ///
+ /// \param Regions the set of regions to be invalidated.
+ /// \param E the expression that caused the invalidation.
+ /// \param BlockCount The number of times the current basic block has been
+ // visited.
+ /// \param CausesPointerEscape the flag is set to true when
+ /// the invalidation entails escape of a symbol (representing a
+ /// pointer). For example, due to it being passed as an argument in a
+ /// call.
+ /// \param IS the set of invalidated symbols.
+ /// \param Call if non-null, the invalidated regions represent parameters to
+ /// the call and should be considered directly invalidated.
+ /// \param ConstRegions the set of regions whose contents are accessible,
+ /// even though the regions themselves should not be invalidated.
+ 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.
@@ -396,13 +425,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,
- StoreManager::InvalidatedSymbols &IS,
- const CallEvent *Call) const;
+ bool ResultsInSymbolEscape,
+ InvalidatedSymbols &IS,
+ const CallEvent *Call,
+ ArrayRef<SVal> ConstValues) const;
};
//===----------------------------------------------------------------------===//
@@ -611,22 +644,24 @@ inline ProgramStateRef ProgramState::assume(DefinedOrUnknownSVal Cond,
bool Assumption) const {
if (Cond.isUnknown())
return this;
-
- return getStateManager().ConstraintMgr->assume(this, cast<DefinedSVal>(Cond),
- Assumption);
+
+ return getStateManager().ConstraintMgr
+ ->assume(this, Cond.castAs<DefinedSVal>(), Assumption);
}
inline std::pair<ProgramStateRef , ProgramStateRef >
ProgramState::assume(DefinedOrUnknownSVal Cond) const {
if (Cond.isUnknown())
return std::make_pair(this, this);
-
- return getStateManager().ConstraintMgr->assumeDual(this,
- cast<DefinedSVal>(Cond));
+
+ return getStateManager().ConstraintMgr
+ ->assumeDual(this, Cond.castAs<DefinedSVal>());
}
inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V) const {
- return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V);
+ if (Optional<Loc> L = LV.getAs<Loc>())
+ return bindLoc(*L, V);
+ return this;
}
inline Loc ProgramState::getLValue(const VarDecl *VD,
@@ -660,7 +695,7 @@ inline SVal ProgramState::getLValue(const IndirectFieldDecl *D,
}
inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{
- if (NonLoc *N = dyn_cast<NonLoc>(&Idx))
+ if (Optional<NonLoc> N = Idx.getAs<NonLoc>())
return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base);
return UnknownVal();
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
index ea2a8525ba47..eb52ae47bdf2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
@@ -18,6 +18,8 @@
#ifndef LLVM_CLANG_GR_PROGRAMSTATETRAIT_H
#define LLVM_CLANG_GR_PROGRAMSTATETRAIT_H
+#include "llvm/Support/DataTypes.h"
+
namespace llvm {
class BumpPtrAllocator;
template <typename K, typename D, typename I> class ImmutableMap;
@@ -165,7 +167,7 @@ namespace ento {
}
static inline void *MakeVoidPtr(data_type D) {
- return (void*) D.getInternalPointer();
+ return const_cast<llvm::ImmutableListImpl<T> *>(D.getInternalPointer());
}
static inline context_type MakeContext(void *p) {
@@ -221,7 +223,20 @@ namespace ento {
}
};
-} // end GR namespace
+ // Partial specialization for const void *.
+ template <> struct ProgramStatePartialTrait<const void *> {
+ typedef const void *data_type;
+
+ static inline data_type MakeData(void * const *p) {
+ return p ? *p : data_type();
+ }
+
+ static inline void *MakeVoidPtr(data_type d) {
+ return const_cast<void *>(d);
+ }
+ };
+
+} // end ento namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 5d72e73a3d94..f7e49a3c7539 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -17,11 +17,10 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
namespace clang {
@@ -124,7 +123,7 @@ public:
ProgramStateManager &getStateManager() { return StateMgr; }
QualType getConditionType() const {
- return getContext().IntTy;
+ return Context.getLangOpts().CPlusPlus ? Context.BoolTy : Context.IntTy;
}
QualType getArrayIndexType() const {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index c2134cf04826..1c5519e9e785 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -16,8 +16,8 @@
#define LLVM_CLANG_GR_RVALUE_H
#include "clang/Basic/LLVM.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/ADT/ImmutableList.h"
//==------------------------------------------------------------------------==//
@@ -33,7 +33,7 @@ class LazyCompoundValData;
class ProgramState;
class BasicValueFactory;
class MemRegion;
-class TypedRegion;
+class TypedValueRegion;
class MemRegionManager;
class ProgramStateManager;
class SValBuilder;
@@ -69,6 +69,29 @@ protected:
public:
explicit SVal() : Data(0), Kind(0) {}
+ /// \brief Convert to the specified SVal type, asserting that this SVal is of
+ /// the desired type.
+ template<typename T>
+ T castAs() const {
+ assert(T::isKind(*this));
+ T t;
+ SVal& sv = t;
+ sv = *this;
+ return t;
+ }
+
+ /// \brief Convert to the specified SVal type, returning None if this SVal is
+ /// not of the desired type.
+ template<typename T>
+ Optional<T> getAs() const {
+ if (!T::isKind(*this))
+ return None;
+ T t;
+ SVal& sv = t;
+ sv = *this;
+ return t;
+ }
+
/// BufferTy - A temporary buffer to hold a set of SVals.
typedef SmallVector<SVal,5> BufferTy;
@@ -161,29 +184,32 @@ class UndefinedVal : public SVal {
public:
UndefinedVal() : SVal(UndefinedKind) {}
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == UndefinedKind;
+private:
+ friend class SVal;
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == UndefinedKind;
}
};
class DefinedOrUnknownSVal : public SVal {
private:
- // Do not implement. We want calling these methods to be a compiler
- // error since they are tautologically false.
- bool isUndef() const;
- bool isValid() const;
+ // We want calling these methods to be a compiler error since they are
+ // tautologically false.
+ bool isUndef() const LLVM_DELETED_FUNCTION;
+ bool isValid() const LLVM_DELETED_FUNCTION;
protected:
+ DefinedOrUnknownSVal() {}
explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind)
: SVal(d, isLoc, ValKind) {}
explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL)
: SVal(k, D) {}
-public:
- // Implement isa<T> support.
- static inline bool classof(const SVal *V) {
- return !V->isUndef();
+private:
+ friend class SVal;
+ static bool isKind(const SVal& V) {
+ return !V.isUndef();
}
};
@@ -191,61 +217,79 @@ class UnknownVal : public DefinedOrUnknownSVal {
public:
explicit UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {}
- static inline bool classof(const SVal *V) {
- return V->getBaseKind() == UnknownKind;
+private:
+ friend class SVal;
+ static bool isKind(const SVal &V) {
+ return V.getBaseKind() == UnknownKind;
}
};
class DefinedSVal : public DefinedOrUnknownSVal {
private:
- // Do not implement. We want calling these methods to be a compiler
- // error since they are tautologically true/false.
- bool isUnknown() const;
- bool isUnknownOrUndef() const;
- bool isValid() const;
+ // We want calling these methods to be a compiler error since they are
+ // tautologically true/false.
+ bool isUnknown() const LLVM_DELETED_FUNCTION;
+ bool isUnknownOrUndef() const LLVM_DELETED_FUNCTION;
+ bool isValid() const LLVM_DELETED_FUNCTION;
protected:
+ DefinedSVal() {}
explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind)
: DefinedOrUnknownSVal(d, isLoc, ValKind) {}
-public:
- // Implement isa<T> support.
- static inline bool classof(const SVal *V) {
- return !V->isUnknownOrUndef();
+private:
+ friend class SVal;
+ static bool isKind(const SVal& V) {
+ return !V.isUnknownOrUndef();
+ }
+};
+
+
+/// \brief Represents an SVal that is guaranteed to not be UnknownVal.
+class KnownSVal : public SVal {
+ KnownSVal() {}
+ friend class SVal;
+ static bool isKind(const SVal &V) {
+ return !V.isUnknown();
}
+public:
+ KnownSVal(const DefinedSVal &V) : SVal(V) {}
+ KnownSVal(const UndefinedVal &V) : SVal(V) {}
};
class NonLoc : public DefinedSVal {
protected:
+ NonLoc() {}
explicit NonLoc(unsigned SubKind, const void *d)
: DefinedSVal(d, false, SubKind) {}
public:
void dumpToStream(raw_ostream &Out) const;
- // Implement isa<T> support.
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == NonLocKind;
+private:
+ friend class SVal;
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind;
}
};
class Loc : public DefinedSVal {
protected:
+ Loc() {}
explicit Loc(unsigned SubKind, const void *D)
: DefinedSVal(const_cast<void*>(D), true, SubKind) {}
public:
void dumpToStream(raw_ostream &Out) const;
- Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {}
-
- // Implement isa<T> support.
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == LocKind;
- }
-
static inline bool isLocType(QualType T) {
return T->isAnyPointerType() || T->isBlockPointerType() ||
T->isReferenceType();
}
+
+private:
+ friend class SVal;
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind;
+ }
};
//==------------------------------------------------------------------------==//
@@ -266,17 +310,20 @@ public:
return (const SymExpr*) Data;
}
- bool isExpression() {
+ bool isExpression() const {
return !isa<SymbolData>(getSymbol());
}
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == NonLocKind &&
- V->getSubKind() == SymbolValKind;
+private:
+ friend class SVal;
+ SymbolVal() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == SymbolValKind;
}
- static inline bool classof(const NonLoc* V) {
- return V->getSubKind() == SymbolValKind;
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == SymbolValKind;
}
};
@@ -297,38 +344,40 @@ public:
ConcreteInt evalMinus(SValBuilder &svalBuilder) const;
- // Implement isa<T> support.
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == NonLocKind &&
- V->getSubKind() == ConcreteIntKind;
+private:
+ friend class SVal;
+ ConcreteInt() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == ConcreteIntKind;
}
- static inline bool classof(const NonLoc* V) {
- return V->getSubKind() == ConcreteIntKind;
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == ConcreteIntKind;
}
};
class LocAsInteger : public NonLoc {
friend class ento::SValBuilder;
- explicit LocAsInteger(const std::pair<SVal, uintptr_t>& data) :
- NonLoc(LocAsIntegerKind, &data) {
- assert (isa<Loc>(data.first));
- }
+ explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data)
+ : NonLoc(LocAsIntegerKind, &data) {
+ assert (data.first.getAs<Loc>());
+ }
public:
Loc getLoc() const {
const std::pair<SVal, uintptr_t> *D =
static_cast<const std::pair<SVal, uintptr_t> *>(Data);
- return cast<Loc>(D->first);
+ return D->first.castAs<Loc>();
}
- const Loc& getPersistentLoc() const {
+ Loc getPersistentLoc() const {
const std::pair<SVal, uintptr_t> *D =
static_cast<const std::pair<SVal, uintptr_t> *>(Data);
const SVal& V = D->first;
- return cast<Loc>(V);
+ return V.castAs<Loc>();
}
unsigned getNumBits() const {
@@ -337,14 +386,16 @@ public:
return D->second;
}
- // Implement isa<T> support.
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == NonLocKind &&
- V->getSubKind() == LocAsIntegerKind;
+private:
+ friend class SVal;
+ LocAsInteger() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == LocAsIntegerKind;
}
- static inline bool classof(const NonLoc* V) {
- return V->getSubKind() == LocAsIntegerKind;
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == LocAsIntegerKind;
}
};
@@ -362,12 +413,15 @@ public:
iterator begin() const;
iterator end() const;
- static bool classof(const SVal* V) {
- return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind;
+private:
+ friend class SVal;
+ CompoundVal() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind && V.getSubKind() == CompoundValKind;
}
- static bool classof(const NonLoc* V) {
- return V->getSubKind() == CompoundValKind;
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == CompoundValKind;
}
};
@@ -381,14 +435,17 @@ public:
return static_cast<const LazyCompoundValData*>(Data);
}
const void *getStore() const;
- const TypedRegion *getRegion() const;
+ const TypedValueRegion *getRegion() const;
- static bool classof(const SVal *V) {
- return V->getBaseKind() == NonLocKind &&
- V->getSubKind() == LazyCompoundValKind;
+private:
+ friend class SVal;
+ LazyCompoundVal() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == LazyCompoundValKind;
}
- static bool classof(const NonLoc *V) {
- return V->getSubKind() == LazyCompoundValKind;
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == LazyCompoundValKind;
}
};
@@ -410,12 +467,15 @@ public:
return static_cast<const LabelDecl*>(Data);
}
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == LocKind && V->getSubKind() == GotoLabelKind;
+private:
+ friend class SVal;
+ GotoLabel() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind && V.getSubKind() == GotoLabelKind;
}
- static inline bool classof(const Loc* V) {
- return V->getSubKind() == GotoLabelKind;
+ static bool isKind(const Loc& V) {
+ return V.getSubKind() == GotoLabelKind;
}
};
@@ -434,7 +494,7 @@ public:
template <typename REGION>
const REGION* getRegionAs() const {
- return llvm::dyn_cast<REGION>(getRegion());
+ return dyn_cast<REGION>(getRegion());
}
inline bool operator==(const MemRegionVal& R) const {
@@ -445,14 +505,16 @@ public:
return getRegion() != R.getRegion();
}
- // Implement isa<T> support.
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == LocKind &&
- V->getSubKind() == MemRegionKind;
+private:
+ friend class SVal;
+ MemRegionVal() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind &&
+ V.getSubKind() == MemRegionKind;
}
- static inline bool classof(const Loc* V) {
- return V->getSubKind() == MemRegionKind;
+ static bool isKind(const Loc& V) {
+ return V.getSubKind() == MemRegionKind;
}
};
@@ -468,19 +530,22 @@ public:
SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
const ConcreteInt& R) const;
- // Implement isa<T> support.
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == LocKind &&
- V->getSubKind() == ConcreteIntKind;
+private:
+ friend class SVal;
+ ConcreteInt() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind &&
+ V.getSubKind() == ConcreteIntKind;
}
- static inline bool classof(const Loc* V) {
- return V->getSubKind() == ConcreteIntKind;
+ static bool isKind(const Loc& V) {
+ return V.getSubKind() == ConcreteIntKind;
}
};
} // end ento::loc namespace
-} // end GR namespace
+
+} // end ento namespace
} // end clang namespace
@@ -491,6 +556,11 @@ static inline raw_ostream &operator<<(raw_ostream &os,
return os;
}
+template <typename T> struct isPodLike;
+template <> struct isPodLike<clang::ento::SVal> {
+ static const bool value = true;
+};
+
} // end llvm namespace
#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index 979546b6ed47..bbfd5797fff0 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -14,9 +14,9 @@
#ifndef LLVM_CLANG_GR_STORE_H
#define LLVM_CLANG_GR_STORE_H
-#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Optional.h"
@@ -35,6 +35,8 @@ class ProgramState;
class ProgramStateManager;
class ScanReachableSymbols;
+typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
+
class StoreManager {
protected:
SValBuilder &svalBuilder;
@@ -134,7 +136,8 @@ public:
SVal evalDerivedToBase(SVal Derived, const CXXBasePath &CastPath);
/// Evaluates a derived-to-base cast through a single level of derivation.
- SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType);
+ SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType,
+ bool IsVirtual);
/// \brief Evaluates C++ dynamic_cast cast.
/// The callback may result in the following 3 scenarios:
@@ -168,7 +171,6 @@ public:
/// associated with the object is recycled.
virtual void decrementReferenceCount(Store store) {}
- typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
typedef SmallVector<const MemRegion *, 8> InvalidatedRegions;
/// invalidateRegions - Clears out the specified regions from the store,
@@ -176,26 +178,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 1e710778d9be..d4100634a785 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;
@@ -104,7 +113,7 @@ public:
/// made to the store. Used to update checkers that track region values.
virtual ProgramStateRef
processRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) = 0;
@@ -116,6 +125,17 @@ public:
return processRegionChanges(state, 0, MR, MR, 0);
}
+ virtual ProgramStateRef
+ processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, SVal Val) = 0;
+
+ virtual ProgramStateRef
+ notifyCheckersOfPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols *Invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const CallEvent *Call,
+ bool IsConst = false) = 0;
+
/// printState - Called by ProgramStateManager to print checker-specific data.
virtual void printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) = 0;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 873f773b459d..56afca24f6b4 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -20,10 +20,10 @@
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
-#include "llvm/Support/DataTypes.h"
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/DataTypes.h"
namespace llvm {
class BumpPtrAllocator;
@@ -96,7 +96,7 @@ public:
};
typedef const SymExpr* SymbolRef;
-typedef llvm::SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
+typedef SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
typedef unsigned SymbolID;
/// \brief A symbol representing data which can be stored in a memory location
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
index c274cea8413e..4c58d4b1d261 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
@@ -14,7 +14,11 @@
#ifndef LLVM_CLANG_TAINTMANAGER_H
#define LLVM_CLANG_TAINTMANAGER_H
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h"
+#include "llvm/ADT/ImmutableMap.h"
namespace clang {
namespace ento {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
index 51aa753f11e9..d12a1514898f 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
@@ -16,7 +16,8 @@
#define LLVM_CLANG_GR_WORKLIST
#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
-#include <cstddef>
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include <cassert>
namespace clang {
@@ -24,9 +25,6 @@ class CFGBlock;
namespace ento {
-class ExplodedNode;
-class ExplodedNodeImpl;
-
class WorkListUnit {
ExplodedNode *node;
BlockCounter counter;