aboutsummaryrefslogtreecommitdiff
path: root/include/clang/StaticAnalyzer
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2012-12-02 13:20:44 +0000
committerDimitry Andric <dim@FreeBSD.org>2012-12-02 13:20:44 +0000
commit13cc256e404620c1de0cbcc4e43ce1e2dbbc4898 (patch)
tree2732d02d7d51218d6eed98ac7fcfc5b8794896b5 /include/clang/StaticAnalyzer
parent657bc3d9848e3be92029b2416031340988cd0111 (diff)
downloadsrc-13cc256e404620c1de0cbcc4e43ce1e2dbbc4898.tar.gz
src-13cc256e404620c1de0cbcc4e43ce1e2dbbc4898.zip
Vendor import of clang release_32 branch r168974 (effectively, 3.2 RC2):vendor/clang/clang-release_32-r168974
Notes
Notes: svn path=/vendor/clang/dist/; revision=243791 svn path=/vendor/clang/clang-release_32-r168974/; revision=243792; tag=vendor/clang/clang-release_32-r168974
Diffstat (limited to 'include/clang/StaticAnalyzer')
-rw-r--r--include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h35
-rw-r--r--include/clang/StaticAnalyzer/Core/Analyses.def67
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h308
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h89
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h58
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h129
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h17
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h12
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h80
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h5
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h167
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h130
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h111
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h70
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h52
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h11
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h74
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h76
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h43
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h95
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h31
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h57
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h5
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h45
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h52
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h2
28 files changed, 1293 insertions, 538 deletions
diff --git a/include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h b/include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h
deleted file mode 100644
index f9cce9ca9c62..000000000000
--- a/include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//== NullDerefChecker.h - Null dereference checker --------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines NullDerefChecker and UndefDerefChecker, two builtin checks
-// in ExprEngine that check for null and undefined pointers at loads
-// and stores.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_DEREFCHECKER
-#define LLVM_CLANG_GR_DEREFCHECKER
-
-#include <utility>
-
-namespace clang {
-
-namespace ento {
-
-class ExprEngine;
-class ExplodedNode;
-
-std::pair<ExplodedNode * const *, ExplodedNode * const *>
-GetImplicitNullDereferences(ExprEngine &Eng);
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
diff --git a/include/clang/StaticAnalyzer/Core/Analyses.def b/include/clang/StaticAnalyzer/Core/Analyses.def
new file mode 100644
index 000000000000..01a6ffd7142c
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/Analyses.def
@@ -0,0 +1,67 @@
+//===-- Analyses.def - Metadata about Static Analyses -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the set of static analyses used by AnalysisConsumer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ANALYSIS_STORE
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN)
+#endif
+
+ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateRegionStoreManager)
+
+#ifndef ANALYSIS_CONSTRAINTS
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN)
+#endif
+
+ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager)
+
+#ifndef ANALYSIS_DIAGNOSTICS
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)
+#endif
+
+ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer, false)
+ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer, true)
+ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for mult-file bugs)", createPlistMultiFileDiagnosticConsumer, true)
+ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer, true)
+ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer, true)
+
+#ifndef ANALYSIS_PURGE
+#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC)
+#endif
+
+ANALYSIS_PURGE(PurgeStmt, "statement", "Purge symbols, bindings, and constraints before every statement")
+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")
+
+#undef ANALYSIS_STORE
+#undef ANALYSIS_CONSTRAINTS
+#undef ANALYSIS_DIAGNOSTICS
+#undef ANALYSIS_PURGE
+#undef ANALYSIS_INLINING_MODE
+#undef ANALYSIS_IPA
+
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
new file mode 100644
index 000000000000..fa0754acb150
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -0,0 +1,308 @@
+//===--- AnalyzerOptions.h - Analysis Engine Options ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines various options for the static analyzer that are set
+// by the frontend and are consulted throughout the analyzer.
+//
+//===----------------------------------------------------------------------===//
+
+#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/StringMap.h"
+
+namespace clang {
+class ASTConsumer;
+class DiagnosticsEngine;
+class Preprocessor;
+class LangOptions;
+
+/// Analysis - Set of available source code analyses.
+enum Analyses {
+#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) NAME,
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+NumAnalyses
+};
+
+/// AnalysisStores - Set of available analysis store models.
+enum AnalysisStores {
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) NAME##Model,
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+NumStores
+};
+
+/// AnalysisConstraints - Set of available constraint models.
+enum AnalysisConstraints {
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) NAME##Model,
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+NumConstraints
+};
+
+/// AnalysisDiagClients - Set of available diagnostic clients for rendering
+/// analysis results.
+enum AnalysisDiagClients {
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) PD_##NAME,
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+NUM_ANALYSIS_DIAG_CLIENTS
+};
+
+/// AnalysisPurgeModes - Set of available strategies for dead symbol removal.
+enum AnalysisPurgeMode {
+#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) NAME,
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+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,
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+NumInliningModes
+};
+
+/// \brief Describes the different kinds of C++ member functions which can be
+/// considered for inlining by the analyzer.
+///
+/// These options are cumulative; enabling one kind of member function will
+/// enable all kinds with lower enum values.
+enum CXXInlineableMemberKind {
+ // Uninitialized = 0,
+
+ /// A dummy mode in which no C++ inlining is enabled.
+ CIMK_None = 1,
+
+ /// Refers to regular member function and operator calls.
+ CIMK_MemberFunctions,
+
+ /// Refers to constructors (implicit or explicit).
+ ///
+ /// Note that a constructor will not be inlined if the corresponding
+ /// destructor is non-trivial.
+ CIMK_Constructors,
+
+ /// Refers to destructors (implicit or explicit).
+ CIMK_Destructors
+};
+
+
+class AnalyzerOptions : public llvm::RefCountedBase<AnalyzerOptions> {
+public:
+ typedef llvm::StringMap<std::string> ConfigTable;
+
+ /// \brief Pair of checker name and enable/disable.
+ std::vector<std::pair<std::string, bool> > CheckersControlList;
+
+ /// \brief A key-value table of use-specified configuration values.
+ ConfigTable Config;
+ AnalysisStores AnalysisStoreOpt;
+ AnalysisConstraints AnalysisConstraintsOpt;
+ 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;
+
+
+ unsigned ShowCheckerHelp : 1;
+ unsigned AnalyzeAll : 1;
+ unsigned AnalyzerDisplayProgress : 1;
+ unsigned AnalyzeNestedBlocks : 1;
+
+ /// \brief The flag regulates if we should eagerly assume evaluations of
+ /// conditionals, thus, bifurcating the path.
+ ///
+ /// This flag indicates how the engine should handle expressions such as: 'x =
+ /// (y != 0)'. When this flag is true then the subexpression 'y != 0' will be
+ /// eagerly assumed to be true or false, thus evaluating it to the integers 0
+ /// or 1 respectively. The upside is that this can increase analysis
+ /// precision until we have a better way to lazily evaluate such logic. The
+ /// downside is that it eagerly bifurcates paths.
+ unsigned eagerlyAssumeBinOpBifurcation : 1;
+
+ unsigned TrimGraph : 1;
+ unsigned visualizeExplodedGraphWithGraphViz : 1;
+ unsigned visualizeExplodedGraphWithUbiGraph : 1;
+ unsigned UnoptimizedCFG : 1;
+ unsigned PrintStats : 1;
+
+ /// \brief Do not re-analyze paths leading to exhausted nodes with a different
+ /// strategy. We get better code coverage when retry is enabled.
+ unsigned NoRetryExhausted : 1;
+
+ /// \brief The inlining stack depth limit.
+ 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:
+ /// Controls which C++ member functions will be considered for inlining.
+ CXXInlineableMemberKind CXXMemberInliningMode;
+
+ /// \sa includeTemporaryDtorsInCFG
+ llvm::Optional<bool> IncludeTemporaryDtorsInCFG;
+
+ /// \sa mayInlineCXXStandardLibrary
+ llvm::Optional<bool> InlineCXXStandardLibrary;
+
+ /// \sa mayInlineTemplateFunctions
+ llvm::Optional<bool> InlineTemplateFunctions;
+
+ /// \sa mayInlineObjCMethod
+ llvm::Optional<bool> ObjCInliningMode;
+
+ // Cache of the "ipa-always-inline-size" setting.
+ // \sa getAlwaysInlineSize
+ llvm::Optional<unsigned> AlwaysInlineSize;
+
+ /// \sa shouldPruneNullReturnPaths
+ llvm::Optional<bool> PruneNullReturnPaths;
+
+ /// \sa shouldAvoidSuppressingNullArgumentPaths
+ llvm::Optional<bool> AvoidSuppressingNullArgumentPaths;
+
+ /// \sa getGraphTrimInterval
+ llvm::Optional<unsigned> GraphTrimInterval;
+
+ /// Interprets an option's string value as a boolean.
+ ///
+ /// Accepts the strings "true" and "false".
+ /// If an option value is not provided, returns the given \p DefaultVal.
+ 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);
+
+ /// Interprets an option's string value as an integer value.
+ int getOptionAsInteger(llvm::StringRef Name, int DefaultVal);
+
+public:
+ /// Returns the option controlling which C++ member functions will be
+ /// considered for inlining.
+ ///
+ /// This is controlled by the 'c++-inlining' config option.
+ ///
+ /// \sa CXXMemberInliningMode
+ bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K);
+
+ /// Returns true if ObjectiveC inlining is enabled, false otherwise.
+ bool mayInlineObjCMethod();
+
+ /// Returns whether or not the destructors for C++ temporary objects should
+ /// be included in the CFG.
+ ///
+ /// This is controlled by the 'cfg-temporary-dtors' config option, which
+ /// accepts the values "true" and "false".
+ bool includeTemporaryDtorsInCFG();
+
+ /// Returns whether or not C++ standard library functions may be considered
+ /// for inlining.
+ ///
+ /// This is controlled by the 'c++-stdlib-inlining' config option, which
+ /// accepts the values "true" and "false".
+ bool mayInlineCXXStandardLibrary();
+
+ /// Returns whether or not templated functions may be considered for inlining.
+ ///
+ /// This is controlled by the 'c++-template-inlining' config option, which
+ /// accepts the values "true" and "false".
+ bool mayInlineTemplateFunctions();
+
+ /// Returns whether or not paths that go through null returns should be
+ /// suppressed.
+ ///
+ /// This is a heuristic for avoiding bug reports with paths that go through
+ /// inlined functions that are more defensive than their callers.
+ ///
+ /// This is controlled by the 'suppress-null-return-paths' config option,
+ /// which accepts the values "true" and "false".
+ bool shouldPruneNullReturnPaths();
+
+ /// 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 is a counter-heuristic to avoid false negatives.
+ ///
+ /// This is controlled by the 'avoid-suppressing-null-argument-paths' config
+ /// option, which accepts the values "true" and "false".
+ bool shouldAvoidSuppressingNullArgumentPaths();
+
+ // 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 true if the analyzer engine should synthesize fake bodies
+ /// for well-known functions.
+ bool shouldSynthesizeBodies();
+
+ /// Returns how often nodes in the ExplodedGraph should be recycled to save
+ /// memory.
+ ///
+ /// This is controlled by the 'graph-trim-interval' config option. To disable
+ /// node reclamation, set the option to "0".
+ unsigned getGraphTrimInterval();
+
+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;
+ // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls).
+ InlineMaxStackDepth = 5;
+ InlineMaxFunctionSize = 200;
+ InliningMode = NoRedundancy;
+ }
+};
+
+typedef llvm::IntrusiveRefCntPtr<AnalyzerOptions> AnalyzerOptionsRef;
+
+}
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 48393a379b39..b5a88ba9f6c6 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -24,6 +24,7 @@
#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/ImmutableSet.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallSet.h"
namespace clang {
@@ -95,6 +96,10 @@ protected:
/// for multiple PathDiagnosticConsumers.
llvm::SmallVector<Regions *, 2> interestingRegions;
+ /// A set of location contexts that correspoind to call sites which should be
+ /// considered "interesting".
+ llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts;
+
/// A set of custom visitors which generate "event" diagnostics at
/// interesting points in the path.
VisitorList Callbacks;
@@ -111,6 +116,19 @@ protected:
/// when reporting an issue.
bool DoNotPrunePath;
+ /// Used to track unique reasons why a bug report might be invalid.
+ ///
+ /// \sa markInvalid
+ /// \sa removeInvalidation
+ typedef std::pair<const void *, const void *> InvalidationRecord;
+
+ /// If non-empty, this bug report is likely a false positive and should not be
+ /// shown to the user.
+ ///
+ /// \sa markInvalid
+ /// \sa removeInvalidation
+ llvm::SmallSet<InvalidationRecord, 4> Invalidations;
+
private:
// Used internally by BugReporter.
Symbols &getInterestingSymbols();
@@ -147,7 +165,8 @@ public:
PathDiagnosticLocation LocationToUnique)
: BT(bt), DeclWithIssue(0), Description(desc),
UniqueingLocation(LocationToUnique),
- ErrorNode(errornode), ConfigurationChangeToken(0) {}
+ ErrorNode(errornode), ConfigurationChangeToken(0),
+ DoNotPrunePath(false) {}
virtual ~BugReport();
@@ -158,8 +177,10 @@ public:
const StringRef getDescription() const { return Description; }
- const StringRef getShortDescription() const {
- return ShortDescription.empty() ? Description : ShortDescription;
+ const StringRef getShortDescription(bool UseFallback = true) const {
+ if (ShortDescription.empty() && UseFallback)
+ return Description;
+ return ShortDescription;
}
/// Indicates whether or not any path pruning should take place
@@ -172,14 +193,44 @@ public:
void markInteresting(SymbolRef sym);
void markInteresting(const MemRegion *R);
void markInteresting(SVal V);
+ void markInteresting(const LocationContext *LC);
bool isInteresting(SymbolRef sym);
bool isInteresting(const MemRegion *R);
bool isInteresting(SVal V);
+ bool isInteresting(const LocationContext *LC);
unsigned getConfigurationChangeToken() const {
return ConfigurationChangeToken;
}
+
+ /// Returns whether or not this report should be considered valid.
+ ///
+ /// Invalid reports are those that have been classified as likely false
+ /// positives after the fact.
+ bool isValid() const {
+ return Invalidations.empty();
+ }
+
+ /// Marks the current report as invalid, meaning that it is probably a false
+ /// positive and should not be reported to the user.
+ ///
+ /// The \p Tag and \p Data arguments are intended to be opaque identifiers for
+ /// this particular invalidation, where \p Tag represents the visitor
+ /// responsible for invalidation, and \p Data represents the reason this
+ /// visitor decided to invalidate the bug report.
+ ///
+ /// \sa removeInvalidation
+ void markInvalid(const void *Tag, const void *Data) {
+ Invalidations.insert(std::make_pair(Tag, Data));
+ }
+
+ /// Reverses the effects of a previous invalidation.
+ ///
+ /// \sa markInvalid
+ void removeInvalidation(const void *Tag, const void *Data) {
+ Invalidations.erase(std::make_pair(Tag, Data));
+ }
/// Return the canonical declaration, be it a method or class, where
/// this issue semantically occurred.
@@ -342,6 +393,11 @@ private:
/// A vector of BugReports for tracking the allocated pointers and cleanup.
std::vector<BugReportEquivClass *> EQClassesVector;
+ /// A map from PathDiagnosticPiece to the LocationContext of the inlined
+ /// function call it represents.
+ llvm::DenseMap<const PathDiagnosticCallPiece*,
+ const LocationContext*> LocationContextMap;
+
protected:
BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
D(d) {}
@@ -378,9 +434,14 @@ public:
SourceManager& getSourceManager() { return D.getSourceManager(); }
- virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
+ virtual bool generatePathDiagnostic(PathDiagnostic& pathDiagnostic,
PathDiagnosticConsumer &PC,
- ArrayRef<BugReport *> &bugReports) {}
+ ArrayRef<BugReport *> &bugReports) {
+ return true;
+ }
+
+ bool RemoveUneededCalls(PathPieces &pieces, BugReport *R,
+ PathDiagnosticCallPiece *CallWithLoc = 0);
void Register(BugType *BT);
@@ -389,7 +450,7 @@ public:
/// The reports are usually generated by the checkers. Further, they are
/// folded based on the profile value, which is done to coalesce similar
/// reports.
- void EmitReport(BugReport *R);
+ void emitReport(BugReport *R);
void EmitBasicReport(const Decl *DeclWithIssue,
StringRef BugName, StringRef BugCategory,
@@ -409,8 +470,10 @@ public:
EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1);
}
- static bool classof(const BugReporter* R) { return true; }
-
+ void addCallPieceLocationContextPair(const PathDiagnosticCallPiece *C,
+ const LocationContext *LC) {
+ LocationContextMap[C] = LC;
+ }
private:
llvm::StringMap<BugType *> StrBugTypes;
@@ -440,7 +503,15 @@ public:
/// engine.
ProgramStateManager &getStateManager();
- virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
+ /// Generates a path corresponding to one of the given bug reports.
+ ///
+ /// Which report is used for path generation is not specified. The
+ /// bug reporter will try to pick the shortest path, but this is not
+ /// guaranteed.
+ ///
+ /// \return True if the report was valid and a path was generated,
+ /// false if the reports should be considered invalid.
+ virtual bool generatePathDiagnostic(PathDiagnostic &PD,
PathDiagnosticConsumer &PC,
ArrayRef<BugReport*> &bugReports);
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
index f53c15f117c9..78e35ca82b89 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -100,7 +100,6 @@ class FindLastStoreBRVisitor
const MemRegion *R;
SVal V;
bool satisfied;
- const ExplodedNode *StoreSite;
public:
/// \brief Convenience method to create a visitor given only the MemRegion.
@@ -114,7 +113,7 @@ public:
static void registerStatementVarDecls(BugReport &BR, const Stmt *S);
FindLastStoreBRVisitor(SVal v, const MemRegion *r)
- : R(r), V(v), satisfied(false), StoreSite(0) {
+ : R(r), V(v), satisfied(false) {
assert (!V.isUnknown() && "Cannot track unknown value.");
// TODO: Does it make sense to allow undef values here?
@@ -142,6 +141,10 @@ public:
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 *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
@@ -171,6 +174,9 @@ public:
ID.AddPointer(&x);
}
+ /// Return the tag associated with this visitor. This tag will be used
+ /// to make all PathDiagnosticPieces created by this visitor.
+ static const char *getTag();
virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
const ExplodedNode *Prev,
@@ -223,15 +229,57 @@ public:
const ExplodedNode *N,
llvm::Optional<bool> &prunable);
};
-
+
+/// \brief When a region containing undefined value or '0' value is passed
+/// as an argument in a call, marks the call as interesting.
+///
+/// As a result, BugReporter will not prune the path through the function even
+/// if the region's contents are not modified/accessed by the call.
+class UndefOrNullArgVisitor
+ : public BugReporterVisitorImpl<UndefOrNullArgVisitor> {
+
+ /// The interesting memory region this visitor is tracking.
+ const MemRegion *R;
+
+public:
+ UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const {
+ static int Tag = 0;
+ ID.AddPointer(&Tag);
+ ID.AddPointer(R);
+ }
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR);
+};
+
namespace bugreporter {
-void addTrackNullOrUndefValueVisitor(const ExplodedNode *N, const Stmt *S,
- BugReport *R);
+/// Attempts to add visitors to trace a null or undefined value back to its
+/// point of origin, whether it is a symbol constrained to null or an explicit
+/// assignment.
+///
+/// \param N A node "downstream" from the evaluation of the statement.
+/// \param S The statement whose value is null or undefined.
+/// \param R The bug report to which visitors should be attached.
+/// \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.
+///
+/// \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);
const Stmt *GetDerefExpr(const ExplodedNode *N);
const Stmt *GetDenomExpr(const ExplodedNode *N);
const Stmt *GetRetValExpr(const ExplodedNode *N);
+bool isDeclRefExprToReference(const Expr *E);
+
} // end namespace clang
} // end namespace ento
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 973cfb109c05..6dc26e670344 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -52,7 +52,31 @@ class PathDiagnostic;
class PathDiagnosticConsumer {
public:
- typedef std::vector<std::pair<StringRef, std::string> > FilesMade;
+ class PDFileEntry : public llvm::FoldingSetNode {
+ public:
+ PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {}
+
+ typedef std::vector<std::pair<StringRef, StringRef> > ConsumerFiles;
+
+ /// \brief A vector of <consumer,file> pairs.
+ ConsumerFiles files;
+
+ /// \brief A precomputed hash tag used for uniquing PDFileEntry objects.
+ const llvm::FoldingSetNodeID NodeID;
+
+ /// \brief Used for profiling in the FoldingSet.
+ void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; }
+ };
+
+ struct FilesMade : public llvm::FoldingSet<PDFileEntry> {
+ llvm::BumpPtrAllocator Alloc;
+
+ void addDiagnostic(const PathDiagnostic &PD,
+ StringRef ConsumerName,
+ StringRef fileName);
+
+ PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD);
+ };
private:
virtual void anchor();
@@ -73,7 +97,6 @@ public:
virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
virtual bool supportsLogicalOpControlFlow() const { return false; }
virtual bool supportsAllBlockEdges() const { return false; }
- virtual bool useVerboseDescription() const { return true; }
/// Return true if the PathDiagnosticConsumer supports individual
/// PathDiagnostics that span multiple files.
@@ -114,8 +137,6 @@ private:
Kind kind)
: K(kind), S(0), D(0), SM(&sm),
Loc(genLocation(L)), Range(genRange()) {
- assert(Loc.isValid());
- assert(Range.isValid());
}
FullSourceLoc
@@ -134,12 +155,14 @@ public:
PathDiagnosticLocation(const Stmt *s,
const SourceManager &sm,
LocationOrAnalysisDeclContext lac)
- : K(StmtK), S(s), D(0), SM(&sm),
+ : K(s->getLocStart().isValid() ? StmtK : SingleLocK),
+ S(K == StmtK ? s : 0),
+ D(0), SM(&sm),
Loc(genLocation(SourceLocation(), lac)),
Range(genRange(lac)) {
- assert(S);
- assert(Loc.isValid());
- assert(Range.isValid());
+ assert(K == SingleLocK || S);
+ assert(K == SingleLocK || Loc.isValid());
+ assert(K == SingleLocK || Range.isValid());
}
/// Create a location corresponding to the given declaration.
@@ -297,12 +320,18 @@ private:
const std::string str;
const Kind kind;
const DisplayHint Hint;
+
+ /// A constant string that can be used to tag the PathDiagnosticPiece,
+ /// typically with the identification of the creator. The actual pointer
+ /// value is meant to be an identifier; the string itself is useful for
+ /// debugging.
+ StringRef Tag;
+
std::vector<SourceRange> ranges;
- // Do not implement:
- PathDiagnosticPiece();
- PathDiagnosticPiece(const PathDiagnosticPiece &P);
- PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
+ PathDiagnosticPiece() LLVM_DELETED_FUNCTION;
+ PathDiagnosticPiece(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION;
+ void operator=(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION;
protected:
PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
@@ -312,8 +341,18 @@ protected:
public:
virtual ~PathDiagnosticPiece();
- const std::string& getString() const { return str; }
+ llvm::StringRef getString() const { return str; }
+ /// Tag this PathDiagnosticPiece with the given C-string.
+ void setTag(const char *tag) { Tag = tag; }
+
+ /// Return the opaque tag (if any) on the PathDiagnosticPiece.
+ const void *getTag() const { return Tag.data(); }
+
+ /// Return the string representation of the tag. This is useful
+ /// for debugging.
+ StringRef getTagStr() const { return Tag; }
+
/// getDisplayHint - Return a hint indicating where the diagnostic should
/// be displayed by the PathDiagnosticConsumer.
DisplayHint getDisplayHint() const { return Hint; }
@@ -338,10 +377,6 @@ public:
/// Return the SourceRanges associated with this PathDiagnosticPiece.
ArrayRef<SourceRange> getRanges() const { return ranges; }
- static inline bool classof(const PathDiagnosticPiece *P) {
- return true;
- }
-
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
};
@@ -377,6 +412,10 @@ public:
virtual void flattenLocations() { Pos.flatten(); }
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ static bool classof(const PathDiagnosticPiece *P) {
+ return P->getKind() == Event || P->getKind() == Macro;
+ }
};
/// \brief Interface for classes constructing Stack hints.
@@ -410,10 +449,6 @@ public:
/// 'getMessageForX()' methods to construct a specific message.
virtual std::string getMessage(const ExplodedNode *N);
- /// Prints the ordinal form of the given integer,
- /// only valid for ValNo : ValNo > 0.
- void printOrdinal(unsigned ValNo, llvm::raw_svector_ostream &Out);
-
/// Produces the message of the following form:
/// 'Msg via Nth parameter'
virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
@@ -629,14 +664,22 @@ public:
class PathDiagnostic : public llvm::FoldingSetNode {
const Decl *DeclWithIssue;
std::string BugType;
- std::string Desc;
+ std::string VerboseDesc;
+ std::string ShortDesc;
std::string Category;
std::deque<std::string> OtherDesc;
+ PathDiagnosticLocation Loc;
PathPieces pathImpl;
llvm::SmallVector<PathPieces *, 3> pathStack;
PathDiagnostic(); // Do not implement.
public:
+ PathDiagnostic(const Decl *DeclWithIssue, StringRef bugtype,
+ StringRef verboseDesc, StringRef shortDesc,
+ StringRef category);
+
+ ~PathDiagnostic();
+
const PathPieces &path;
/// Return the path currently used by builders for constructing the
@@ -659,16 +702,24 @@ public:
void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
bool isWithinCall() const { return !pathStack.empty(); }
-
- // PathDiagnostic();
- PathDiagnostic(const Decl *DeclWithIssue,
- StringRef bugtype,
- StringRef desc,
- StringRef category);
- ~PathDiagnostic();
+ void setEndOfPath(PathDiagnosticPiece *EndPiece) {
+ assert(!Loc.isValid() && "End location already set!");
+ Loc = EndPiece->getLocation();
+ assert(Loc.isValid() && "Invalid location for end-of-path piece");
+ getActivePath().push_back(EndPiece);
+ }
- StringRef getDescription() const { return Desc; }
+ void resetPath() {
+ pathStack.clear();
+ pathImpl.clear();
+ Loc = PathDiagnosticLocation();
+ }
+
+ StringRef getVerboseDescription() const { return VerboseDesc; }
+ StringRef getShortDescription() const {
+ return ShortDesc.empty() ? VerboseDesc : ShortDesc;
+ }
StringRef getBugType() const { return BugType; }
StringRef getCategory() const { return Category; }
@@ -682,15 +733,27 @@ public:
meta_iterator meta_end() const { return OtherDesc.end(); }
void addMeta(StringRef s) { OtherDesc.push_back(s); }
- PathDiagnosticLocation getLocation() const;
+ PathDiagnosticLocation getLocation() const {
+ assert(Loc.isValid() && "No end-of-path location set yet!");
+ return Loc;
+ }
void flattenLocations() {
+ Loc.flatten();
for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end();
I != E; ++I) (*I)->flattenLocations();
}
-
+
+ /// Profiles the diagnostic, independent of the path it references.
+ ///
+ /// This can be used to merge diagnostics that refer to the same issue
+ /// along different paths.
void Profile(llvm::FoldingSetNodeID &ID) const;
-
+
+ /// Profiles the diagnostic, including its path.
+ ///
+ /// Two diagnostics with the same issue along different paths will generate
+ /// different profiles.
void FullProfile(llvm::FoldingSetNodeID &ID) const;
};
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index 3214d96c5398..9eb1248f6a71 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -366,23 +366,6 @@ public:
}
};
-class InlineCall {
- template <typename CHECKER>
- static bool _inlineCall(void *checker, const CallExpr *CE,
- ExprEngine &Eng,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- return ((const CHECKER *)checker)->inlineCall(CE, Eng, Pred, Dst);
- }
-
-public:
- template <typename CHECKER>
- static void _register(CHECKER *checker, CheckerManager &mgr) {
- mgr._registerForInlineCall(
- CheckerManager::InlineCallFunc(checker, _inlineCall<CHECKER>));
- }
-};
-
} // end eval namespace
class CheckerBase : public ProgramPointTag {
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index e11b6d518a4e..7ae8e53784bf 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -258,7 +258,7 @@ public:
const ExplodedNodeSet &Src,
SVal location, SVal val,
const Stmt *S, ExprEngine &Eng,
- ProgramPoint::Kind PointKind);
+ const ProgramPoint &PP);
/// \brief Run checkers for end of analysis.
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
@@ -267,6 +267,7 @@ public:
/// \brief Run checkers for end of path.
void runCheckersForEndPath(NodeBuilderContext &BC,
ExplodedNodeSet &Dst,
+ ExplodedNode *Pred,
ExprEngine &Eng);
/// \brief Run checkers for branch condition.
@@ -407,11 +408,6 @@ public:
typedef CheckerFn<bool (const CallExpr *, CheckerContext &)>
EvalCallFunc;
- typedef CheckerFn<bool (const CallExpr *, ExprEngine &Eng,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst)>
- InlineCallFunc;
-
typedef CheckerFn<void (const TranslationUnitDecl *,
AnalysisManager&, BugReporter &)>
CheckEndOfTranslationUnit;
@@ -449,8 +445,6 @@ public:
void _registerForEvalCall(EvalCallFunc checkfn);
- void _registerForInlineCall(InlineCallFunc checkfn);
-
void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn);
//===----------------------------------------------------------------------===//
@@ -576,8 +570,6 @@ private:
std::vector<EvalCallFunc> EvalCallCheckers;
- std::vector<InlineCallFunc> InlineCallCheckers;
-
std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers;
struct EventInfo {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
index e1ff17b361aa..27f3677bba22 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
@@ -66,6 +66,10 @@ public:
return llvm::APSInt::getMaxValue(BitWidth, IsUnsigned);
}
+ llvm::APSInt getValue(uint64_t RawValue) const LLVM_READONLY {
+ return (llvm::APSInt(BitWidth, IsUnsigned) = RawValue);
+ }
+
/// Used to classify whether a value is representable using this type.
///
/// \see testInRange
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index 876196ba4f7f..9038ae5276a7 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -16,7 +16,7 @@
#define LLVM_CLANG_GR_ANALYSISMANAGER_H
#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Frontend/AnalyzerOptions.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
@@ -41,64 +41,16 @@ class AnalysisManager : public BugReporterData {
CheckerManager *CheckerMgr;
- /// \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 MaxVisit;
-
- bool VisualizeEGDot;
- bool VisualizeEGUbi;
- AnalysisPurgeMode PurgeDead;
-
- /// \brief The flag regulates if we should eagerly assume evaluations of
- /// conditionals, thus, bifurcating the path.
- ///
- /// EagerlyAssume - A flag indicating how the engine should handle
- /// expressions such as: 'x = (y != 0)'. When this flag is true then
- /// the subexpression 'y != 0' will be eagerly assumed to be true or false,
- /// thus evaluating it to the integers 0 or 1 respectively. The upside
- /// is that this can increase analysis precision until we have a better way
- /// to lazily evaluate such logic. The downside is that it eagerly
- /// bifurcates paths.
- bool EagerlyAssume;
- bool TrimGraph;
- bool EagerlyTrimEGraph;
-
-public:
- // \brief inter-procedural analysis mode.
- AnalysisIPAMode IPAMode;
-
- // Settings for inlining tuning.
- /// \brief The inlining stack depth limit.
- unsigned InlineMaxStackDepth;
- /// \brief The max number of basic blocks in a function being inlined.
- unsigned InlineMaxFunctionSize;
- /// \brief The mode of function selection used during inlining.
- AnalysisInliningMode InliningMode;
-
- /// \brief Do not re-analyze paths leading to exhausted nodes with a different
- /// strategy. We get better code coverage when retry is enabled.
- bool NoRetryExhausted;
-
public:
+ AnalyzerOptions &options;
+
AnalysisManager(ASTContext &ctx,DiagnosticsEngine &diags,
const LangOptions &lang,
const PathDiagnosticConsumers &Consumers,
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
CheckerManager *checkerMgr,
- unsigned maxnodes, unsigned maxvisit,
- bool vizdot, bool vizubi, AnalysisPurgeMode purge,
- bool eager, bool trim,
- bool useUnoptimizedCFG,
- bool addImplicitDtors,
- bool eagerlyTrimEGraph,
- AnalysisIPAMode ipa,
- unsigned inlineMaxStack,
- unsigned inlineMaxFunctionSize,
- AnalysisInliningMode inliningMode,
- bool NoRetry);
+ AnalyzerOptions &Options);
~AnalysisManager();
@@ -142,27 +94,14 @@ public:
void FlushDiagnostics();
- unsigned getMaxNodes() const { return MaxNodes; }
-
- unsigned getMaxVisit() const { return MaxVisit; }
-
- bool shouldVisualizeGraphviz() const { return VisualizeEGDot; }
-
- bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; }
-
bool shouldVisualize() const {
- return VisualizeEGDot || VisualizeEGUbi;
+ return options.visualizeExplodedGraphWithGraphViz ||
+ options.visualizeExplodedGraphWithUbiGraph;
}
- bool shouldEagerlyTrimExplodedGraph() const { return EagerlyTrimEGraph; }
-
- bool shouldTrimGraph() const { return TrimGraph; }
-
- AnalysisPurgeMode getPurgeMode() const { return PurgeDead; }
-
- bool shouldEagerlyAssume() const { return EagerlyAssume; }
-
- bool shouldInlineCall() const { return (IPAMode != None); }
+ bool shouldInlineCall() const {
+ return options.IPAMode != None;
+ }
CFG *getCFG(Decl const *D) {
return AnaCtxMgr.getContext(D)->getCFG();
@@ -180,7 +119,6 @@ public:
AnalysisDeclContext *getAnalysisDeclContext(const Decl *D) {
return AnaCtxMgr.getContext(D);
}
-
};
} // enAnaCtxMgrspace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index b4a9de76f4d1..fb393548b1af 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -73,6 +73,10 @@ class BasicValueFactory {
llvm::FoldingSet<CompoundValData> CompoundValDataSet;
llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
+ // This is private because external clients should use the factory
+ // method that takes a QualType.
+ const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
+
public:
BasicValueFactory(ASTContext &ctx, llvm::BumpPtrAllocator& Alloc)
: Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0),
@@ -84,7 +88,6 @@ public:
const llvm::APSInt& getValue(const llvm::APSInt& X);
const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned);
- const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
const llvm::APSInt& getValue(uint64_t X, QualType T);
/// Returns the type of the APSInt used to store values of the given QualType.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index f6c5830c2955..a6a91e2b66df 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -20,6 +20,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/PointerIntPair.h"
@@ -68,15 +69,22 @@ public:
}
};
+/// \class RuntimeDefinition
/// \brief Defines the runtime definition of the called function.
+///
+/// Encapsulates the information we have about which Decl will be used
+/// when the call is executed on the given path. When dealing with dynamic
+/// dispatch, the information is based on DynamicTypeInfo and might not be
+/// precise.
class RuntimeDefinition {
- /// The Declaration of the function which will be called at runtime.
- /// 0 if not available.
+ /// The Declaration of the function which could be called at runtime.
+ /// NULL if not available.
const Decl *D;
/// The region representing an object (ObjC/C++) on which the method is
/// called. With dynamic dispatch, the method definition depends on the
- /// runtime type of this object. 0 when there is no dynamic dispatch.
+ /// runtime type of this object. NULL when the DynamicTypeInfo is
+ /// precise.
const MemRegion *R;
public:
@@ -84,8 +92,15 @@ public:
RuntimeDefinition(const Decl *InD): D(InD), R(0) {}
RuntimeDefinition(const Decl *InD, const MemRegion *InR): D(InD), R(InR) {}
const Decl *getDecl() { return D; }
- const MemRegion *getDispatchRegion() { return R; }
+
+ /// \brief Check if the definition we have is precise.
+ /// If not, it is possible that the call dispatches to another definition at
+ /// execution time.
bool mayHaveOtherDefinitions() { return R != 0; }
+
+ /// When other definitions are possible, returns the region whose runtime type
+ /// determines the method definition.
+ const MemRegion *getDispatchRegion() { return R; }
};
/// \brief Represents an abstract call to a function or method along a
@@ -106,8 +121,7 @@ private:
const LocationContext *LCtx;
llvm::PointerUnion<const Expr *, const Decl *> Origin;
- // DO NOT IMPLEMENT
- CallEvent &operator=(const CallEvent &);
+ void operator=(const CallEvent &) LLVM_DELETED_FUNCTION;
protected:
// This is user data for subclasses.
@@ -139,16 +153,6 @@ protected:
: State(Original.State), LCtx(Original.LCtx), Origin(Original.Origin),
Data(Original.Data), Location(Original.Location), RefCount(0) {}
-
- ProgramStateRef getState() const {
- return State;
- }
-
- const LocationContext *getLocationContext() const {
- return LCtx;
- }
-
-
/// Copies this CallEvent, with vtable intact, into a new block of memory.
virtual void cloneTo(void *Dest) const = 0;
@@ -164,8 +168,6 @@ protected:
/// result of this call.
virtual void getExtraInvalidatedRegions(RegionList &Regions) const {}
- virtual QualType getDeclaredResultType() const = 0;
-
public:
virtual ~CallEvent() {}
@@ -178,6 +180,16 @@ public:
return Origin.dyn_cast<const Decl *>();
}
+ /// \brief The state in which the call is being evaluated.
+ ProgramStateRef getState() const {
+ return State;
+ }
+
+ /// \brief The context in which the call is being evaluated.
+ const LocationContext *getLocationContext() const {
+ return LCtx;
+ }
+
/// \brief Returns the definition of the function or method that will be
/// called.
virtual RuntimeDefinition getRuntimeDefinition() const = 0;
@@ -237,6 +249,12 @@ public:
/// \brief Returns the result type, adjusted for references.
QualType getResultType() const;
+ /// \brief Returns the return value of the call.
+ ///
+ /// This should only be called if the CallEvent was created using a state in
+ /// which the return value has already been bound to the origin expression.
+ SVal getReturnValue() const;
+
/// \brief Returns true if any of the arguments appear to represent callbacks.
bool hasNonZeroCallbackArg() const;
@@ -249,6 +267,38 @@ public:
return hasNonZeroCallbackArg();
}
+ /// \brief Returns true if the callee is an externally-visible function in the
+ /// top-level namespace, such as \c malloc.
+ ///
+ /// You can use this call to determine that a particular function really is
+ /// a library function and not, say, a C++ member function with the same name.
+ ///
+ /// If a name is provided, the function must additionally match the given
+ /// name.
+ ///
+ /// Note that this deliberately excludes C++ library functions in the \c std
+ /// namespace, but will include C library functions accessed through the
+ /// \c std namespace. This also does not check if the function is declared
+ /// as 'extern "C"', or if it uses C++ name mangling.
+ // FIXME: Add a helper for checking namespaces.
+ // FIXME: Move this down to AnyFunctionCall once checkers have more
+ // precise callbacks.
+ bool isGlobalCFunction(StringRef SpecificName = StringRef()) const;
+
+ /// \brief Returns the name of the callee, if its name is a simple identifier.
+ ///
+ /// Note that this will fail for Objective-C methods, blocks, and C++
+ /// overloaded operators. The former is named by a Selector rather than a
+ /// simple identifier, and the latter two do not have names.
+ // FIXME: Move this down to AnyFunctionCall once checkers have more
+ // precise callbacks.
+ const IdentifierInfo *getCalleeIdentifier() const {
+ const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getDecl());
+ if (!ND)
+ return 0;
+ return ND->getIdentifier();
+ }
+
/// \brief Returns an appropriate ProgramPoint for this call.
ProgramPoint getProgramPoint(bool IsPreVisit = false,
const ProgramPointTag *Tag = 0) const;
@@ -277,12 +327,12 @@ public:
return cloneWithState<CallEvent>(NewState);
}
- /// \brief Returns true if this is a statement that can be considered for
- /// inlining.
- ///
- /// FIXME: This should go away once CallEvents are cheap and easy to
- /// construct from ExplodedNodes.
- static bool mayBeInlined(const Stmt *S);
+ /// \brief Returns true if this is a statement is a function or method call
+ /// of some kind.
+ static bool isCallStmt(const Stmt *S);
+
+ /// \brief Returns the result type of a function, method declaration.
+ static QualType getDeclaredResultType(const Decl *D);
// Iterator access to formal parameters and their types.
private:
@@ -329,8 +379,6 @@ public:
// For debugging purposes only
void dump(raw_ostream &Out) const;
LLVM_ATTRIBUTE_USED void dump() const;
-
- static bool classof(const CallEvent *) { return true; }
};
@@ -346,8 +394,6 @@ protected:
: CallEvent(D, St, LCtx) {}
AnyFunctionCall(const AnyFunctionCall &Other) : CallEvent(Other) {}
- virtual QualType getDeclaredResultType() const;
-
public:
// This function is overridden by subclasses, but they must return
// a FunctionDecl.
@@ -357,9 +403,16 @@ public:
virtual RuntimeDefinition getRuntimeDefinition() const {
const FunctionDecl *FD = getDecl();
- // Note that hasBody() will fill FD with the definition FunctionDecl.
- if (FD && FD->hasBody(FD))
- return RuntimeDefinition(FD);
+ // Note that the AnalysisDeclContext will have the FunctionDecl with
+ // the definition (if one exists).
+ if (FD) {
+ AnalysisDeclContext *AD =
+ getLocationContext()->getAnalysisDeclContext()->
+ getManager()->getContext(FD);
+ if (AD->getBody())
+ return RuntimeDefinition(AD->getDecl());
+ }
+
return RuntimeDefinition();
}
@@ -442,8 +495,6 @@ protected:
virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
- virtual QualType getDeclaredResultType() const;
-
public:
/// \brief Returns the region associated with this instance of the block.
///
@@ -499,13 +550,7 @@ public:
virtual const Expr *getCXXThisExpr() const { return 0; }
/// \brief Returns the value of the implicit 'this' object.
- virtual SVal getCXXThisVal() const {
- const Expr *Base = getCXXThisExpr();
- // FIXME: This doesn't handle an overloaded ->* operator.
- if (!Base)
- return UnknownVal();
- return getSVal(Base);
- }
+ virtual SVal getCXXThisVal() const;
virtual const FunctionDecl *getDecl() const;
@@ -550,6 +595,8 @@ public:
}
virtual const Expr *getCXXThisExpr() const;
+
+ virtual RuntimeDefinition getRuntimeDefinition() const;
virtual Kind getKind() const { return CE_CXXMember; }
@@ -605,6 +652,8 @@ class CXXDestructorCall : public CXXInstanceCall {
friend class CallEventManager;
protected:
+ typedef llvm::PointerIntPair<const MemRegion *, 1, bool> DtorDataTy;
+
/// Creates an implicit destructor.
///
/// \param DD The destructor that will be called.
@@ -613,10 +662,10 @@ protected:
/// \param St The path-sensitive state at this point in the program.
/// \param LCtx The location context at this point in the program.
CXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
- const MemRegion *Target, ProgramStateRef St,
- const LocationContext *LCtx)
+ const MemRegion *Target, bool IsBaseDestructor,
+ ProgramStateRef St, const LocationContext *LCtx)
: CXXInstanceCall(DD, St, LCtx) {
- Data = Target;
+ Data = DtorDataTy(Target, IsBaseDestructor).getOpaqueValue();
Location = Trigger->getLocEnd();
}
@@ -627,9 +676,16 @@ public:
virtual SourceRange getSourceRange() const { return Location; }
virtual unsigned getNumArgs() const { return 0; }
+ virtual RuntimeDefinition getRuntimeDefinition() const;
+
/// \brief Returns the value of the implicit 'this' object.
virtual SVal getCXXThisVal() const;
+ /// Returns true if this is a call to a base class destructor.
+ bool isBaseDestructor() const {
+ return DtorDataTy::getFromOpaqueValue(Data).getInt();
+ }
+
virtual Kind getKind() const { return CE_CXXDestructor; }
static bool classof(const CallEvent *CA) {
@@ -651,10 +707,10 @@ protected:
/// a new symbolic region will be used.
/// \param St The path-sensitive state at this point in the program.
/// \param LCtx The location context at this point in the program.
- CXXConstructorCall(const CXXConstructExpr *CE, const MemRegion *target,
+ CXXConstructorCall(const CXXConstructExpr *CE, const MemRegion *Target,
ProgramStateRef St, const LocationContext *LCtx)
: AnyFunctionCall(CE, St, LCtx) {
- Data = target;
+ Data = Target;
}
CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){}
@@ -761,8 +817,6 @@ protected:
virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
- virtual QualType getDeclaredResultType() const;
-
/// Check if the selector may have multiple definitions (may have overrides).
virtual bool canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
Selector Sel) const;
@@ -796,6 +850,9 @@ public:
/// \brief Returns the value of the receiver at the time of this call.
SVal getReceiverSVal() const;
+ /// \brief Return the value of 'self' if available.
+ SVal getSelfSVal() const;
+
/// \brief Get the interface for the receiver.
///
/// This works whether this is an instance message or a class message.
@@ -804,6 +861,9 @@ public:
return getOriginExpr()->getReceiverInterface();
}
+ /// \brief Checks if the receiver refers to 'self' or 'super'.
+ bool isReceiverSelfOrSuper() const;
+
/// Returns how the message was written in the source (property access,
/// subscript, or explicit message send).
ObjCMessageKind getMessageKind() const;
@@ -879,6 +939,13 @@ class CallEventManager {
return new (allocate()) T(A1, A2, A3, St, LCtx);
}
+ template <typename T, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4>
+ T *create(Arg1 A1, Arg2 A2, Arg3 A3, Arg4 A4, ProgramStateRef St,
+ const LocationContext *LCtx) {
+ return new (allocate()) T(A1, A2, A3, A4, St, LCtx);
+ }
+
public:
CallEventManager(llvm::BumpPtrAllocator &alloc) : Alloc(alloc) {}
@@ -905,9 +972,9 @@ public:
CallEventRef<CXXDestructorCall>
getCXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
- const MemRegion *Target, ProgramStateRef State,
- const LocationContext *LCtx) {
- return create<CXXDestructorCall>(DD, Trigger, Target, State, LCtx);
+ const MemRegion *Target, bool IsBase,
+ ProgramStateRef State, const LocationContext *LCtx) {
+ return create<CXXDestructorCall>(DD, Trigger, Target, IsBase, State, LCtx);
}
CallEventRef<CXXAllocatorCall>
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 8c8e82ce20dd..4558cd9c9480 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -16,10 +16,57 @@
#define LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
namespace clang {
namespace ento {
+ /// Declares an immutable map of type \p NameTy, suitable for placement into
+ /// the ProgramState. This is implementing using llvm::ImmutableMap.
+ ///
+ /// \code
+ /// State = State->set<Name>(K, V);
+ /// const Value *V = State->get<Name>(K); // Returns NULL if not in the map.
+ /// State = State->remove<Name>(K);
+ /// NameTy Map = State->get<Name>();
+ /// \endcode
+ ///
+ /// The macro should not be used inside namespaces, or for traits that must
+ /// be accessible from more than one translation unit.
+ #define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value) \
+ REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, \
+ CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value))
+
+ /// Declares an immutable set of type \p NameTy, suitable for placement into
+ /// the ProgramState. This is implementing using llvm::ImmutableSet.
+ ///
+ /// \code
+ /// State = State->add<Name>(E);
+ /// State = State->remove<Name>(E);
+ /// bool Present = State->contains<Name>(E);
+ /// NameTy Set = State->get<Name>();
+ /// \endcode
+ ///
+ /// The macro should not be used inside namespaces, or for traits that must
+ /// be accessible from more than one translation unit.
+ #define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem) \
+ REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableSet<Elem>)
+
+ /// Declares an immutable list of type \p NameTy, suitable for placement into
+ /// the ProgramState. This is implementing using llvm::ImmutableList.
+ ///
+ /// \code
+ /// State = State->add<Name>(E); // Adds to the /end/ of the list.
+ /// bool Present = State->contains<Name>(E);
+ /// NameTy List = State->get<Name>();
+ /// \endcode
+ ///
+ /// The macro should not be used inside namespaces, or for traits that must
+ /// be accessible from more than one translation unit.
+ #define REGISTER_LIST_WITH_PROGRAMSTATE(Name, Elem) \
+ REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableList<Elem>)
+
+
class CheckerContext {
ExprEngine &Eng;
/// The current exploded(symbolic execution) graph node.
@@ -64,6 +111,10 @@ public:
return Eng.getStoreManager();
}
+ const AnalyzerOptions::ConfigTable &getConfig() const {
+ return Eng.getAnalysisManager().options.Config;
+ }
+
/// \brief Returns the previous node in the exploded graph, which includes
/// the state of the program before the checker ran. Note, checkers should
/// not retain the node in their state since the nodes might get invalidated.
@@ -76,8 +127,8 @@ public:
/// \brief Returns the number of times the current block has been visited
/// along the analyzed path.
- unsigned getCurrentBlockCount() const {
- return NB.getContext().getCurrentBlockCount();
+ unsigned blockCount() const {
+ return NB.getContext().blockCount();
}
ASTContext &getASTContext() {
@@ -96,6 +147,9 @@ public:
return Pred->getStackFrame();
}
+ /// Return true if the current LocationContext has no caller context.
+ bool inTopFrame() const { return getLocationContext()->inTopFrame(); }
+
BugReporter &getBugReporter() {
return Eng.getBugReporter();
}
@@ -144,20 +198,15 @@ public:
/// \brief Generates a new transition in the program state graph
/// (ExplodedGraph). Uses the default CheckerContext predecessor node.
///
- /// @param State The state of the generated node.
+ /// @param State The state of the generated node. If not specified, the state
+ /// will not be changed, but the new node will have the checker's tag.
/// @param Tag The tag is used to uniquely identify the creation site. If no
/// tag is specified, a default tag, unique to the given checker,
/// will be used. Tags are used to prevent states generated at
/// different sites from caching out.
- ExplodedNode *addTransition(ProgramStateRef State,
+ ExplodedNode *addTransition(ProgramStateRef State = 0,
const ProgramPointTag *Tag = 0) {
- return addTransitionImpl(State, false, 0, Tag);
- }
-
- /// \brief Generates a default transition (containing checker tag but no
- /// checker state changes).
- ExplodedNode *addTransition() {
- return addTransition(getState());
+ return addTransitionImpl(State ? State : getState(), false, 0, Tag);
}
/// \brief Generates a new transition with the given predecessor.
@@ -167,25 +216,24 @@ public:
/// @param Pred The transition will be generated from the specified Pred node
/// to the newly generated node.
/// @param Tag The tag to uniquely identify the creation site.
- /// @param IsSink Mark the new node as sink, which will stop exploration of
- /// the given path.
ExplodedNode *addTransition(ProgramStateRef State,
- ExplodedNode *Pred,
- const ProgramPointTag *Tag = 0,
- bool IsSink = false) {
- return addTransitionImpl(State, IsSink, Pred, Tag);
+ ExplodedNode *Pred,
+ const ProgramPointTag *Tag = 0) {
+ return addTransitionImpl(State, false, Pred, Tag);
}
- /// \brief Generate a sink node. Generating sink stops exploration of the
+ /// \brief Generate a sink node. Generating a sink stops exploration of the
/// given path.
- ExplodedNode *generateSink(ProgramStateRef state = 0) {
- return addTransitionImpl(state ? state : getState(), true);
+ ExplodedNode *generateSink(ProgramStateRef State = 0,
+ ExplodedNode *Pred = 0,
+ const ProgramPointTag *Tag = 0) {
+ return addTransitionImpl(State ? State : getState(), true, Pred, Tag);
}
/// \brief Emit the diagnostics report.
- void EmitReport(BugReport *R) {
+ void emitReport(BugReport *R) {
Changed = true;
- Eng.getBugReporter().EmitReport(R);
+ Eng.getBugReporter().emitReport(R);
}
/// \brief Get the declaration of the called function (path-sensitive).
@@ -194,17 +242,33 @@ public:
/// \brief Get the name of the called function (path-sensitive).
StringRef getCalleeName(const FunctionDecl *FunDecl) const;
+ /// \brief Get the identifier of the called function (path-sensitive).
+ const IdentifierInfo *getCalleeIdentifier(const CallExpr *CE) const {
+ const FunctionDecl *FunDecl = getCalleeDecl(CE);
+ if (FunDecl)
+ return FunDecl->getIdentifier();
+ else
+ return 0;
+ }
+
/// \brief Get the name of the called function (path-sensitive).
StringRef getCalleeName(const CallExpr *CE) const {
const FunctionDecl *FunDecl = getCalleeDecl(CE);
return getCalleeName(FunDecl);
}
- /// Given a function declaration and a name checks if this is a C lib
- /// function with the given name.
- bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name);
- static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name,
- ASTContext &Context);
+ /// \brief Returns true if the callee is an externally-visible function in the
+ /// top-level namespace, such as \c malloc.
+ ///
+ /// If a name is provided, the function must additionally match the given
+ /// name.
+ ///
+ /// Note that this deliberately excludes C++ library functions in the \c std
+ /// namespace, but will include C library functions accessed through the
+ /// \c std namespace. This also does not check if the function is declared
+ /// as 'extern "C"', or if it uses C++ name mangling.
+ static bool isCLibraryFunction(const FunctionDecl *FD,
+ StringRef Name = StringRef());
/// \brief Depending on wither the location corresponds to a macro, return
/// either the macro name or the token spelling.
@@ -226,9 +290,15 @@ private:
return Pred;
Changed = true;
- ExplodedNode *node = NB.generateNode(Tag ? Location.withTag(Tag) : Location,
- State,
- P ? P : Pred, MarkAsSink);
+ const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
+ if (!P)
+ P = Pred;
+
+ ExplodedNode *node;
+ if (MarkAsSink)
+ node = NB.generateSink(LocalLoc, State, P);
+ else
+ node = NB.generateNode(LocalLoc, State, P);
return node;
}
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index 631858dd7c5b..4a78849024ae 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -16,6 +16,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/Support/SaveAndRestore.h"
namespace llvm {
class APSInt;
@@ -26,29 +27,83 @@ namespace ento {
class SubEngine;
+class ConditionTruthVal {
+ llvm::Optional<bool> Val;
+public:
+ /// Construct a ConditionTruthVal indicating the constraint is constrained
+ /// to either true or false, depending on the boolean value provided.
+ ConditionTruthVal(bool constraint) : Val(constraint) {}
+
+ /// Construct a ConstraintVal indicating the constraint is underconstrained.
+ ConditionTruthVal() {}
+
+ /// Return true if the constraint is perfectly constrained to 'true'.
+ bool isConstrainedTrue() const {
+ return Val.hasValue() && Val.getValue();
+ }
+
+ /// Return true if the constraint is perfectly constrained to 'false'.
+ bool isConstrainedFalse() const {
+ return Val.hasValue() && !Val.getValue();
+ }
+
+ /// Return true if the constrained is perfectly constrained.
+ bool isConstrained() const {
+ return Val.hasValue();
+ }
+
+ /// Return true if the constrained is underconstrained and we do not know
+ /// if the constraint is true of value.
+ bool isUnderconstrained() const {
+ return !Val.hasValue();
+ }
+};
+
class ConstraintManager {
public:
+ ConstraintManager() : NotifyAssumeClients(true) {}
+
virtual ~ConstraintManager();
virtual ProgramStateRef assume(ProgramStateRef state,
- DefinedSVal Cond,
- bool Assumption) = 0;
-
- std::pair<ProgramStateRef, ProgramStateRef >
- assumeDual(ProgramStateRef state, DefinedSVal Cond)
- {
- std::pair<ProgramStateRef, ProgramStateRef > res =
- std::make_pair(assume(state, Cond, true), assume(state, Cond, false));
-
- assert(!(!res.first && !res.second) && "System is over constrained.");
- return res;
+ DefinedSVal Cond,
+ bool Assumption) = 0;
+
+ typedef std::pair<ProgramStateRef, ProgramStateRef> ProgramStatePair;
+
+ /// Returns a pair of states (StTrue, StFalse) where the given condition is
+ /// assumed to be true or false, respectively.
+ ProgramStatePair assumeDual(ProgramStateRef State, DefinedSVal Cond) {
+ ProgramStateRef StTrue = assume(State, Cond, true);
+
+ // 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.
+ assert(assume(State, Cond, false) && "System is over constrained.");
+ return ProgramStatePair((ProgramStateRef)NULL, State);
+ }
+
+ ProgramStateRef StFalse = assume(State, Cond, false);
+ if (!StFalse) {
+ // We are careful to return the original state, /not/ StTrue,
+ // because we want to avoid having callers generate a new node
+ // in the ExplodedGraph.
+ return ProgramStatePair(State, (ProgramStateRef)NULL);
+ }
+
+ return ProgramStatePair(StTrue, StFalse);
}
+ /// \brief If a symbol is perfectly constrained to a constant, attempt
+ /// to return the concrete value.
+ ///
+ /// Note that a ConstraintManager is not obligated to return a concretized
+ /// value for a symbol, even if it is perfectly constrained.
virtual const llvm::APSInt* getSymVal(ProgramStateRef state,
- SymbolRef sym) const = 0;
-
- virtual bool isEqual(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) const = 0;
+ SymbolRef sym) const {
+ return 0;
+ }
virtual ProgramStateRef removeDeadBindings(ProgramStateRef state,
SymbolReaper& SymReaper) = 0;
@@ -59,20 +114,38 @@ public:
const char *sep) = 0;
virtual void EndPath(ProgramStateRef state) {}
+
+ /// 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);
+
+ return checkNull(State, Sym);
+ }
protected:
+ /// A flag to indicate that clients should be notified of assumptions.
+ /// By default this is the case, but sometimes this needs to be restricted
+ /// to avoid infinite recursions within the ConstraintManager.
+ ///
+ /// Note that this flag allows the ConstraintManager to be re-entrant,
+ /// but not thread-safe.
+ bool NotifyAssumeClients;
+
/// canReasonAbout - Not all ConstraintManagers can accurately reason about
/// all SVal values. This method returns true if the ConstraintManager can
/// reasonably handle a given SVal value. This is typically queried by
/// ExprEngine to determine if the value should be replaced with a
/// conjured symbolic value in order to recover some precision.
virtual bool canReasonAbout(SVal X) const = 0;
+
+ /// Returns whether or not a symbol is known to be null ("true"), known to be
+ /// non-null ("false"), or may be either ("underconstrained").
+ virtual ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym);
};
-ConstraintManager* CreateBasicConstraintManager(ProgramStateManager& statemgr,
- SubEngine &subengine);
ConstraintManager* CreateRangeConstraintManager(ProgramStateManager& statemgr,
- SubEngine &subengine);
+ SubEngine *subengine);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index e75cdd87596b..b6686409e5aa 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -80,10 +80,6 @@ private:
/// usually because it could not reason about something.
BlocksAborted blocksAborted;
- /// The functions which have been analyzed through inlining. This is owned by
- /// AnalysisConsumer. It can be null.
- SetOfConstDecls *AnalyzedCallees;
-
/// The information about functions shared by the whole translation unit.
/// (This data is owned by AnalysisConsumer.)
FunctionSummariesTy *FunctionSummaries;
@@ -101,19 +97,18 @@ private:
ExplodedNode *Pred);
private:
- CoreEngine(const CoreEngine&); // Do not implement.
- CoreEngine& operator=(const CoreEngine&);
+ CoreEngine(const CoreEngine &) LLVM_DELETED_FUNCTION;
+ void operator=(const CoreEngine &) LLVM_DELETED_FUNCTION;
ExplodedNode *generateCallExitBeginNode(ExplodedNode *N);
public:
/// Construct a CoreEngine object to analyze the provided CFG.
- CoreEngine(SubEngine& subengine, SetOfConstDecls *VisitedCallees,
+ CoreEngine(SubEngine& subengine,
FunctionSummariesTy *FS)
: SubEng(subengine), G(new ExplodedGraph()),
WList(WorkList::makeDFS()),
BCounterFactory(G->getAllocator()),
- AnalyzedCallees(VisitedCallees),
FunctionSummaries(FS){}
/// getGraph - Returns the exploded graph.
@@ -185,20 +180,18 @@ public:
struct NodeBuilderContext {
const CoreEngine &Eng;
const CFGBlock *Block;
- ExplodedNode *Pred;
+ const LocationContext *LC;
NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
- : Eng(E), Block(B), Pred(N) { assert(B); assert(!N->isSink()); }
-
- ExplodedNode *getPred() const { return Pred; }
+ : Eng(E), Block(B), LC(N->getLocationContext()) { assert(B); }
/// \brief Return the CFGBlock associated with this builder.
const CFGBlock *getBlock() const { return Block; }
/// \brief Returns the number of times the current basic block has been
/// visited on the exploded graph path.
- unsigned getCurrentBlockCount() const {
+ unsigned blockCount() const {
return Eng.WList->getBlockCounter().getNumVisited(
- Pred->getLocationContext()->getCurrentStackFrame(),
+ LC->getCurrentStackFrame(),
Block->getBlockID());
}
};
@@ -265,14 +258,21 @@ public:
virtual ~NodeBuilder() {}
/// \brief Generates a node in the ExplodedGraph.
+ ExplodedNode *generateNode(const ProgramPoint &PP,
+ ProgramStateRef State,
+ ExplodedNode *Pred) {
+ return generateNodeImpl(PP, State, Pred, false);
+ }
+
+ /// \brief Generates a sink in the ExplodedGraph.
///
/// When a node is marked as sink, the exploration from the node is stopped -
- /// the node becomes the last node on the path.
- ExplodedNode *generateNode(const ProgramPoint &PP,
+ /// the node becomes the last node on the path and certain kinds of bugs are
+ /// suppressed.
+ ExplodedNode *generateSink(const ProgramPoint &PP,
ProgramStateRef State,
- ExplodedNode *Pred,
- bool MarkAsSink = false) {
- return generateNodeImpl(PP, State, Pred, MarkAsSink);
+ ExplodedNode *Pred) {
+ return generateNodeImpl(PP, State, Pred, true);
}
const ExplodedNodeSet &getResults() {
@@ -317,13 +317,18 @@ public:
NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet,
const NodeBuilderContext &Ctx, ProgramPoint &L)
: NodeBuilder(Pred, DstSet, Ctx), Location(L) {}
+
ExplodedNode *generateNode(ProgramStateRef State,
ExplodedNode *Pred,
- const ProgramPointTag *Tag = 0,
- bool MarkAsSink = false) {
- ProgramPoint LocalLoc = (Tag ? Location.withTag(Tag): Location);
+ const ProgramPointTag *Tag = 0) {
+ const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
+ return NodeBuilder::generateNode(LocalLoc, State, Pred);
+ }
- ExplodedNode *N = generateNodeImpl(LocalLoc, State, Pred, MarkAsSink);
+ ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred,
+ const ProgramPointTag *Tag = 0) {
+ const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
+ ExplodedNode *N = NodeBuilder::generateSink(LocalLoc, State, Pred);
if (N && N->isSink())
sinksGenerated.push_back(N);
return N;
@@ -336,7 +341,7 @@ public:
/// \class StmtNodeBuilder
/// \brief This builder class is useful for generating nodes that resulted from
-/// visiting a statement. The main difference from it's parent NodeBuilder is
+/// visiting a statement. The main difference from its parent NodeBuilder is
/// that it creates a statement specific ProgramPoint.
class StmtNodeBuilder: public NodeBuilder {
NodeBuilder *EnclosingBldr;
@@ -363,22 +368,27 @@ public:
virtual ~StmtNodeBuilder();
+ using NodeBuilder::generateNode;
+ using NodeBuilder::generateSink;
+
ExplodedNode *generateNode(const Stmt *S,
ExplodedNode *Pred,
ProgramStateRef St,
- bool MarkAsSink = false,
const ProgramPointTag *tag = 0,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
Pred->getLocationContext(), tag);
- return generateNodeImpl(L, St, Pred, MarkAsSink);
+ return NodeBuilder::generateNode(L, St, Pred);
}
- ExplodedNode *generateNode(const ProgramPoint &PP,
+ ExplodedNode *generateSink(const Stmt *S,
ExplodedNode *Pred,
- ProgramStateRef State,
- bool MarkAsSink = false) {
- return generateNodeImpl(PP, State, Pred, MarkAsSink);
+ ProgramStateRef St,
+ const ProgramPointTag *tag = 0,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
+ Pred->getLocationContext(), tag);
+ return NodeBuilder::generateSink(L, St, Pred);
}
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
new file mode 100644
index 000000000000..5ac97dbc3145
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
@@ -0,0 +1,52 @@
+//== DynamicTypeInfo.h - Runtime type information ----------------*- C++ -*--=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SA_CORE_DYNAMICTYPEINFO_H
+#define LLVM_CLANG_SA_CORE_DYNAMICTYPEINFO_H
+
+#include "clang/AST/Type.h"
+
+namespace clang {
+namespace ento {
+
+/// \brief Stores the currently inferred strictest bound on the runtime type
+/// of a region in a given state along the analysis path.
+class DynamicTypeInfo {
+private:
+ QualType T;
+ bool CanBeASubClass;
+
+public:
+
+ DynamicTypeInfo() : T(QualType()) {}
+ DynamicTypeInfo(QualType WithType, bool CanBeSub = true)
+ : T(WithType), CanBeASubClass(CanBeSub) {}
+
+ /// \brief Return false if no dynamic type info is available.
+ bool isValid() const { return !T.isNull(); }
+
+ /// \brief Returns the currently inferred upper bound on the runtime type.
+ QualType getType() const { return T; }
+
+ /// \brief Returns false if the type information is precise (the type T is
+ /// the only type in the lattice), true otherwise.
+ bool canBeASubClass() const { return CanBeASubClass; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.Add(T);
+ ID.AddInteger((unsigned)CanBeASubClass);
+ }
+ bool operator==(const DynamicTypeInfo &X) const {
+ return T == X.T && CanBeASubClass == X.CanBeASubClass;
+ }
+};
+
+} // end ento
+} // end clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index b80213e249a2..eb9bd85fe64d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -33,10 +33,11 @@ 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)
- : std::pair<const Stmt*,
- const StackFrameContext*>(s, L ? L->getCurrentStackFrame():0) {}
+ EnvironmentEntry(const Stmt *s, const LocationContext *L);
const Stmt *getStmt() const { return first; }
const LocationContext *getLocationContext() const { return second; }
@@ -76,9 +77,7 @@ public:
/// Fetches the current binding of the expression in the
/// Environment.
- SVal getSVal(const EnvironmentEntry &E,
- SValBuilder &svalBuilder,
- bool useOnlyDirectBindings = false) const;
+ SVal getSVal(const EnvironmentEntry &E, SValBuilder &svalBuilder) const;
/// Profile - Profile the contents of an Environment object for use
/// in a FoldingSet.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index 1052d9491a96..b112e66d30d3 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -60,45 +60,50 @@ class ExplodedNode : public llvm::FoldingSetNode {
friend class SwitchNodeBuilder;
friend class EndOfFunctionNodeBuilder;
+ /// Efficiently stores a list of ExplodedNodes, or an optional flag.
+ ///
+ /// NodeGroup provides opaque storage for a list of ExplodedNodes, optimizing
+ /// for the case when there is only one node in the group. This is a fairly
+ /// common case in an ExplodedGraph, where most nodes have only one
+ /// predecessor and many have only one successor. It can also be used to
+ /// store a flag rather than a node list, which ExplodedNode uses to mark
+ /// whether a node is a sink. If the flag is set, the group is implicitly
+ /// empty and no nodes may be added.
class NodeGroup {
- enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 };
+ // Conceptually a discriminated union. If the low bit is set, the node is
+ // a sink. If the low bit is not set, the pointer refers to the storage
+ // for the nodes in the group.
+ // This is not a PointerIntPair in order to keep the storage type opaque.
uintptr_t P;
-
- unsigned getKind() const {
- return P & 0x1;
- }
-
- void *getPtr() const {
- assert (!getFlag());
- return reinterpret_cast<void*>(P & ~Mask);
- }
-
- ExplodedNode *getNode() const {
- return reinterpret_cast<ExplodedNode*>(getPtr());
- }
public:
- NodeGroup() : P(0) {}
+ NodeGroup(bool Flag = false) : P(Flag) {
+ assert(getFlag() == Flag);
+ }
- ExplodedNode **begin() const;
+ ExplodedNode * const *begin() const;
- ExplodedNode **end() const;
+ ExplodedNode * const *end() const;
unsigned size() const;
- bool empty() const { return (P & ~Mask) == 0; }
+ bool empty() const { return P == 0 || getFlag() != 0; }
+ /// Adds a node to the list.
+ ///
+ /// The group must not have been created with its flag set.
void addNode(ExplodedNode *N, ExplodedGraph &G);
+ /// Replaces the single node in this group with a new node.
+ ///
+ /// Note that this should only be used when you know the group was not
+ /// created with its flag set, and that the group is empty or contains
+ /// only a single node.
void replaceNode(ExplodedNode *node);
- void setFlag() {
- assert(P == 0);
- P = AuxFlag;
- }
-
+ /// Returns whether this group was created with its flag set.
bool getFlag() const {
- return P & AuxFlag ? true : false;
+ return (P & 1);
}
};
@@ -119,9 +124,8 @@ public:
explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state,
bool IsSink)
- : Location(loc), State(state) {
- if (IsSink)
- Succs.setFlag();
+ : Location(loc), State(state), Succs(IsSink) {
+ assert(isSink() == IsSink);
}
~ExplodedNode() {}
@@ -190,9 +194,9 @@ public:
}
// Iterators over successor and predecessor vertices.
- typedef ExplodedNode** succ_iterator;
+ typedef ExplodedNode* const * succ_iterator;
typedef const ExplodedNode* const * const_succ_iterator;
- typedef ExplodedNode** pred_iterator;
+ typedef ExplodedNode* const * pred_iterator;
typedef const ExplodedNode* const * const_pred_iterator;
pred_iterator pred_begin() { return Preds.begin(); }
@@ -278,11 +282,13 @@ protected:
/// A list of nodes that can be reused.
NodeVector FreeNodes;
- /// A flag that indicates whether nodes should be recycled.
- bool reclaimNodes;
+ /// Determines how often nodes are reclaimed.
+ ///
+ /// If this is 0, nodes will never be reclaimed.
+ unsigned ReclaimNodeInterval;
/// Counter to determine when to reclaim nodes.
- unsigned reclaimCounter;
+ unsigned ReclaimCounter;
public:
@@ -370,7 +376,9 @@ public:
/// Enable tracking of recently allocated nodes for potential reclamation
/// when calling reclaimRecentlyAllocatedNodes().
- void enableNodeReclamation() { reclaimNodes = true; }
+ void enableNodeReclamation(unsigned Interval) {
+ ReclaimCounter = ReclaimNodeInterval = Interval;
+ }
/// Reclaim "uninteresting" nodes created since the last time this method
/// was called.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 4addb9d4ec49..78b254222e9e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -16,6 +16,7 @@
#ifndef LLVM_CLANG_GR_EXPRENGINE
#define LLVM_CLANG_GR_EXPRENGINE
+#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
@@ -70,17 +71,14 @@ class ExprEngine : public SubEngine {
/// variables and symbols (as determined by a liveness analysis).
ProgramStateRef CleanedState;
- /// currentStmt - The current block-level statement.
- const Stmt *currentStmt;
- unsigned int currentStmtIdx;
- const NodeBuilderContext *currentBuilderContext;
-
- /// Obj-C Class Identifiers.
- IdentifierInfo* NSExceptionII;
-
- /// Obj-C Selectors.
- Selector* NSExceptionInstanceRaiseSelectors;
- Selector RaiseSel;
+ /// currStmt - The current block-level statement.
+ const Stmt *currStmt;
+ unsigned int currStmtIdx;
+ const NodeBuilderContext *currBldrCtx;
+
+ /// Helper object to determine if an Objective-C message expression
+ /// implicitly never returns.
+ ObjCNoReturn ObjCNoRet;
/// Whether or not GC is enabled in this analysis.
bool ObjCGCEnabled;
@@ -90,9 +88,13 @@ class ExprEngine : public SubEngine {
/// destructor is called before the rest of the ExprEngine is destroyed.
GRBugReporter BR;
+ /// The functions which have been analyzed through inlining. This is owned by
+ /// AnalysisConsumer. It can be null.
+ SetOfConstDecls *VisitedCallees;
+
public:
ExprEngine(AnalysisManager &mgr, bool gcEnabled,
- SetOfConstDecls *VisitedCallees,
+ SetOfConstDecls *VisitedCalleesIn,
FunctionSummariesTy *FS);
~ExprEngine();
@@ -126,8 +128,8 @@ public:
BugReporter& getBugReporter() { return BR; }
const NodeBuilderContext &getBuilderContext() {
- assert(currentBuilderContext);
- return *currentBuilderContext;
+ assert(currBldrCtx);
+ return *currBldrCtx;
}
bool isObjCGCEnabled() { return ObjCGCEnabled; }
@@ -165,8 +167,12 @@ public:
/// 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.
void removeDead(ExplodedNode *Node, ExplodedNodeSet &Out,
- const Stmt *ReferenceStmt, const LocationContext *LC,
+ const Stmt *ReferenceStmt, const StackFrameContext *LC,
const Stmt *DiagnosticStmt,
ProgramPoint::Kind K = ProgramPoint::PreStmtPurgeDeadSymbolsKind);
@@ -192,7 +198,8 @@ public:
/// Called by CoreEngine when processing the entrance of a CFGBlock.
virtual void processCFGBlockEntrance(const BlockEdge &L,
- NodeBuilderWithSinks &nodeBuilder);
+ NodeBuilderWithSinks &nodeBuilder,
+ ExplodedNode *Pred);
/// ProcessBranch - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
@@ -213,7 +220,13 @@ public:
/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
- void processEndOfFunction(NodeBuilderContext& BC);
+ void processEndOfFunction(NodeBuilderContext& BC,
+ ExplodedNode *Pred);
+
+ /// Remove dead bindings/symbols before exiting a function.
+ void removeDeadOnEndOfFunction(NodeBuilderContext& BC,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// Generate the entry node of the callee.
void processCallEnter(CallEnter CE, ExplodedNode *Pred);
@@ -258,9 +271,6 @@ public:
BasicValueFactory& getBasicVals() {
return StateMgr.getBasicVals();
}
- const BasicValueFactory& getBasicVals() const {
- return StateMgr.getBasicVals();
- }
// FIXME: Remove when we migrate over to just using ValueManager.
SymbolManager& getSymbolManager() { return SymMgr; }
@@ -283,13 +293,14 @@ public:
ExplodedNode *Pred,
ExplodedNodeSet &Dst);
- /// VisitAsmStmt - Transfer function logic for inline asm.
- void VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred, ExplodedNodeSet &Dst);
+ /// VisitGCCAsmStmt - Transfer function logic for inline asm.
+ void VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitMSAsmStmt - Transfer function logic for MS inline asm.
void VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
-
+
/// VisitBlockExpr - Transfer function logic for BlockExprs.
void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
@@ -380,8 +391,8 @@ public:
void VisitCXXConstructExpr(const CXXConstructExpr *E, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
- void VisitCXXDestructor(QualType ObjectType,
- const MemRegion *Dest, const Stmt *S,
+ void VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest,
+ const Stmt *S, bool IsBaseDtor,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
void VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
@@ -395,14 +406,14 @@ public:
ExplodedNode *Pred,
ExplodedNodeSet &Dst);
- /// evalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
+ /// evalEagerlyAssumeBinOpBifurcation - Given the nodes in 'Src', eagerly assume symbolic
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
/// with those assumptions.
- void evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
+ void evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
const Expr *Ex);
std::pair<const ProgramPointTag *, const ProgramPointTag*>
- getEagerlyAssumeTags();
+ geteagerlyAssumeBinOpBifurcationTags();
SVal evalMinus(SVal X) {
return X.isValid() ? svalBuilder.evalMinus(cast<NonLoc>(X)) : X;
@@ -433,7 +444,8 @@ protected:
/// evalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by evalStore, VisitDeclStmt, and others.
void evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred,
- SVal location, SVal Val, bool atDeclInit = false);
+ SVal location, SVal Val, bool atDeclInit = false,
+ const ProgramPoint *PP = 0);
public:
// FIXME: 'tag' should be removed, and a LocationContext should be used
@@ -490,6 +502,10 @@ private:
ProgramStateRef St, SVal location,
const ProgramPointTag *tag, bool isLoad);
+ /// Count the stack depth and determine if the call is recursive.
+ void examineStackFrames(const Decl *D, const LocationContext *LCtx,
+ bool &IsRecursive, unsigned &StackDepth);
+
bool shouldInlineDecl(const Decl *D, ExplodedNode *Pred);
bool inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr,
ExplodedNode *Pred, ProgramStateRef State);
@@ -510,6 +526,8 @@ private:
/// Traits for storing the call processing policy inside GDM.
/// The GDM stores the corresponding CallExpr pointer.
+// FIXME: This does not use the nice trait macros because it must be accessible
+// from multiple translation units.
struct ReplayWithoutInlining{};
template <>
struct ProgramStateTrait<ReplayWithoutInlining> :
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 8044ed839a75..34fbc3ca9e83 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -99,11 +99,11 @@ public:
// Untyped regions.
SymbolicRegionKind,
AllocaRegionKind,
- BlockDataRegionKind,
// Typed regions.
BEG_TYPED_REGIONS,
FunctionTextRegionKind = BEG_TYPED_REGIONS,
BlockTextRegionKind,
+ BlockDataRegionKind,
BEG_TYPED_VALUE_REGIONS,
CompoundLiteralRegionKind = BEG_TYPED_VALUE_REGIONS,
CXXThisRegionKind,
@@ -140,6 +140,9 @@ public:
const MemRegion *getBaseRegion() const;
+ /// Check if the region is a subregion of the given region.
+ virtual bool isSubRegionOf(const MemRegion *R) const;
+
const MemRegion *StripCasts(bool StripBaseCasts = true) const;
bool hasGlobalsOrParametersStorage() const;
@@ -171,8 +174,6 @@ public:
template<typename RegionTy> const RegionTy* getAs() const;
virtual bool isBoundable() const { return false; }
-
- static bool classof(const MemRegion*) { return true; }
};
/// MemSpaceRegion - A memory region that represents a "memory space";
@@ -416,7 +417,7 @@ public:
MemRegionManager* getMemRegionManager() const;
- bool isSubRegionOf(const MemRegion* R) const;
+ virtual bool isSubRegionOf(const MemRegion* R) const;
static bool classof(const MemRegion* R) {
return R->getKind() > END_MEMSPACES;
@@ -530,16 +531,28 @@ public:
/// FunctionTextRegion - A region that represents code texts of function.
class FunctionTextRegion : public CodeTextRegion {
- const FunctionDecl *FD;
+ const NamedDecl *FD;
public:
- FunctionTextRegion(const FunctionDecl *fd, const MemRegion* sreg)
- : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {}
+ FunctionTextRegion(const NamedDecl *fd, const MemRegion* sreg)
+ : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {
+ assert(isa<ObjCMethodDecl>(fd) || isa<FunctionDecl>(fd));
+ }
QualType getLocationType() const {
- return getContext().getPointerType(FD->getType());
+ const ASTContext &Ctx = getContext();
+ if (const FunctionDecl *D = dyn_cast<FunctionDecl>(FD)) {
+ return Ctx.getPointerType(D->getType());
+ }
+
+ assert(isa<ObjCMethodDecl>(FD));
+ assert(false && "Getting the type of ObjCMethod is not supported yet");
+
+ // TODO: We might want to return a different type here (ex: id (*ty)(...))
+ // depending on how it is used.
+ return QualType();
}
-
- const FunctionDecl *getDecl() const {
+
+ const NamedDecl *getDecl() const {
return FD;
}
@@ -547,7 +560,7 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD,
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD,
const MemRegion*);
static bool classof(const MemRegion* R) {
@@ -603,7 +616,7 @@ public:
/// which correspond to "code+data". The distinction is important, because
/// like a closure a block captures the values of externally referenced
/// variables.
-class BlockDataRegion : public SubRegion {
+class BlockDataRegion : public TypedRegion {
friend class MemRegionManager;
const BlockTextRegion *BC;
const LocationContext *LC; // Can be null */
@@ -612,13 +625,15 @@ class BlockDataRegion : public SubRegion {
BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc,
const MemRegion *sreg)
- : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
+ : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
ReferencedVars(0), OriginalVars(0) {}
public:
const BlockTextRegion *getCodeRegion() const { return BC; }
const BlockDecl *getDecl() const { return BC->getDecl(); }
+
+ QualType getLocationType() const { return BC->getLocationType(); }
class referenced_vars_iterator {
const MemRegion * const *R;
@@ -1212,7 +1227,7 @@ public:
return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion);
}
- const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD);
+ const FunctionTextRegion *getFunctionTextRegion(const NamedDecl *FD);
const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD,
CanQualType locTy,
AnalysisDeclContext *AC);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index b0c51dd5b928..86c94deab5e8 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines SymbolRef, ExprBindKey, and ProgramState*.
+// This file defines the state of the program along the analysisa path.
//
//===----------------------------------------------------------------------===//
@@ -16,6 +16,7 @@
#include "clang/Basic/LLVM.h"
#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"
@@ -39,7 +40,7 @@ class CallEvent;
class CallEventManager;
typedef ConstraintManager* (*ConstraintManagerCreator)(ProgramStateManager&,
- SubEngine&);
+ SubEngine*);
typedef StoreManager* (*StoreManagerCreator)(ProgramStateManager&);
//===----------------------------------------------------------------------===//
@@ -56,32 +57,6 @@ template <typename T> struct ProgramStateTrait {
}
};
-/// \class Stores the dynamic type information.
-/// Information about type of an object at runtime. This is used by dynamic
-/// dispatch implementation.
-class DynamicTypeInfo {
- QualType T;
- bool CanBeASubClass;
-
-public:
- DynamicTypeInfo() : T(QualType()) {}
- DynamicTypeInfo(QualType WithType, bool CanBeSub = true)
- : T(WithType), CanBeASubClass(CanBeSub) {}
-
- bool isValid() const { return !T.isNull(); }
-
- QualType getType() const { return T; }
- bool canBeASubClass() const { return CanBeASubClass; }
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- T.Profile(ID);
- ID.AddInteger((unsigned)CanBeASubClass);
- }
- bool operator==(const DynamicTypeInfo &X) const {
- return T == X.T && CanBeASubClass == X.CanBeASubClass;
- }
-};
-
/// \class ProgramState
/// ProgramState - This class encapsulates:
///
@@ -100,7 +75,7 @@ public:
typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
private:
- void operator=(const ProgramState& R) const; // Do not implement.
+ void operator=(const ProgramState& R) LLVM_DELETED_FUNCTION;
friend class ProgramStateManager;
friend class ExplodedGraph;
@@ -130,7 +105,12 @@ public:
~ProgramState();
/// Return the ProgramStateManager associated with this state.
- ProgramStateManager &getStateManager() const { return *stateMgr; }
+ ProgramStateManager &getStateManager() const {
+ return *stateMgr;
+ }
+
+ /// Return the ConstraintManager.
+ ConstraintManager &getConstraintManager() const;
/// getEnvironment - Return the environment associated with this state.
/// The environment is the mapping from expressions to values.
@@ -210,11 +190,13 @@ public:
// Binding and retrieving values to/from the environment and symbolic store.
//==---------------------------------------------------------------------==//
- /// BindCompoundLiteral - Return the state that has the bindings currently
- /// in this state plus the bindings for the CompoundLiteral.
+ /// \brief Create a new state with the specified CompoundLiteral binding.
+ /// \param CL the compound literal expression (the binding key)
+ /// \param LC the LocationContext of the binding
+ /// \param V the value to bind.
ProgramStateRef bindCompoundLiteral(const CompoundLiteralExpr *CL,
- const LocationContext *LC,
- SVal V) const;
+ const LocationContext *LC,
+ SVal V) const;
/// Create a new state by binding the value 'V' to the statement 'S' in the
/// state's environment.
@@ -226,18 +208,16 @@ public:
ProgramStateRef bindExprAndLocation(const Stmt *S,
const LocationContext *LCtx,
SVal location, SVal V) const;
-
- ProgramStateRef bindDecl(const VarRegion *VR, SVal V) const;
- ProgramStateRef bindDeclWithNoInit(const VarRegion *VR) const;
-
- ProgramStateRef bindLoc(Loc location, SVal V) const;
+ ProgramStateRef bindLoc(Loc location,
+ SVal V,
+ bool notifyChanges = true) const;
ProgramStateRef bindLoc(SVal location, SVal V) const;
ProgramStateRef bindDefault(SVal loc, SVal V) const;
- ProgramStateRef unbindLoc(Loc LV) const;
+ 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
@@ -271,11 +251,8 @@ public:
/// Get the lvalue for an array index.
SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const;
- const llvm::APSInt *getSymVal(SymbolRef sym) const;
-
/// Returns the SVal bound to the statement 'S' in the state's environment.
- SVal getSVal(const Stmt *S, const LocationContext *LCtx,
- bool useOnlyDirectBindings = false) const;
+ SVal getSVal(const Stmt *S, const LocationContext *LCtx) const;
SVal getSValAsScalarOrLoc(const Stmt *Ex, const LocationContext *LCtx) const;
@@ -469,7 +446,7 @@ public:
StoreManagerCreator CreateStoreManager,
ConstraintManagerCreator CreateConstraintManager,
llvm::BumpPtrAllocator& alloc,
- SubEngine &subeng);
+ SubEngine *subeng);
~ProgramStateManager();
@@ -481,9 +458,6 @@ public:
BasicValueFactory &getBasicVals() {
return svalBuilder->getBasicValueFactory();
}
- const BasicValueFactory& getBasicVals() const {
- return svalBuilder->getBasicValueFactory();
- }
SValBuilder &getSValBuilder() {
return *svalBuilder;
@@ -515,10 +489,6 @@ public:
const StackFrameContext *LCtx,
SymbolReaper& SymReaper);
- /// Marshal a new state for the callee in another translation unit.
- /// 'state' is owned by the caller's engine.
- ProgramStateRef MarshalState(ProgramStateRef state, const StackFrameContext *L);
-
public:
SVal ArrayToPointer(Loc Array) {
@@ -617,10 +587,6 @@ public:
return ProgramStateTrait<T>::MakeContext(p);
}
- const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) {
- return ConstraintMgr->getSymVal(St, sym);
- }
-
void EndPath(ProgramStateRef St) {
ConstraintMgr->EndPath(St);
}
@@ -631,6 +597,10 @@ public:
// Out-of-line method definitions for ProgramState.
//===----------------------------------------------------------------------===//
+inline ConstraintManager &ProgramState::getConstraintManager() const {
+ return stateMgr->getConstraintManager();
+}
+
inline const VarRegion* ProgramState::getRegion(const VarDecl *D,
const LocationContext *LC) const
{
@@ -695,15 +665,10 @@ inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) c
return UnknownVal();
}
-inline const llvm::APSInt *ProgramState::getSymVal(SymbolRef sym) const {
- return getStateManager().getSymVal(this, sym);
-}
-
-inline SVal ProgramState::getSVal(const Stmt *Ex, const LocationContext *LCtx,
- bool useOnlyDirectBindings) const{
+inline SVal ProgramState::getSVal(const Stmt *Ex,
+ const LocationContext *LCtx) const{
return Env.getSVal(EnvironmentEntry(Ex, LCtx),
- *getStateManager().svalBuilder,
- useOnlyDirectBindings);
+ *getStateManager().svalBuilder);
}
inline SVal
@@ -821,7 +786,7 @@ public:
bool scan(const SymExpr *sym);
};
-} // end GR namespace
+} // end ento namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
index 1c7bedb82f24..ea2a8525ba47 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
@@ -31,6 +31,26 @@ namespace clang {
namespace ento {
template <typename T> struct ProgramStatePartialTrait;
+ /// Declares a program state trait for type \p Type called \p Name, and
+ /// introduce a typedef named \c NameTy.
+ /// The macro should not be used inside namespaces, or for traits that must
+ /// be accessible from more than one translation unit.
+ #define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type) \
+ namespace { \
+ class Name {}; \
+ typedef Type Name ## Ty; \
+ } \
+ namespace clang { \
+ namespace ento { \
+ template <> \
+ struct ProgramStateTrait<Name> \
+ : public ProgramStatePartialTrait<Name ## Ty> { \
+ static void *GDMIndex() { static int Index; return &Index; } \
+ }; \
+ } \
+ }
+
+
// Partial-specialization for ImmutableMap.
template <typename Key, typename Data, typename Info>
@@ -71,6 +91,15 @@ namespace ento {
}
};
+ /// Helper for registering a map trait.
+ ///
+ /// If the map type were written directly in the invocation of
+ /// REGISTER_TRAIT_WITH_PROGRAMSTATE, the comma in the template arguments
+ /// would be treated as a macro argument separator, which is wrong.
+ /// This allows the user to specify a map type in a way that the preprocessor
+ /// can deal with.
+ #define CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value) llvm::ImmutableMap<Key, Value>
+
// Partial-specialization for ImmutableSet.
@@ -113,6 +142,7 @@ namespace ento {
}
};
+
// Partial-specialization for ImmutableList.
template <typename T>
@@ -150,6 +180,7 @@ namespace ento {
delete (typename data_type::Factory*) Ctx;
}
};
+
// Partial specialization for bool.
template <> struct ProgramStatePartialTrait<bool> {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 83c3a5634586..5d72e73a3d94 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -72,7 +72,7 @@ public:
virtual ~SValBuilder() {}
bool haveSameType(const SymExpr *Sym1, const SymExpr *Sym2) {
- return haveSameType(Sym1->getType(Context), Sym2->getType(Context));
+ return haveSameType(Sym1->getType(), Sym2->getType());
}
bool haveSameType(QualType Ty1, QualType Ty2) {
@@ -142,19 +142,19 @@ public:
// Forwarding methods to SymbolManager.
- const SymbolConjured* getConjuredSymbol(const Stmt *stmt,
- const LocationContext *LCtx,
- QualType type,
- unsigned visitCount,
- const void *symbolTag = 0) {
- return SymMgr.getConjuredSymbol(stmt, LCtx, type, visitCount, symbolTag);
+ const SymbolConjured* conjureSymbol(const Stmt *stmt,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned visitCount,
+ const void *symbolTag = 0) {
+ return SymMgr.conjureSymbol(stmt, LCtx, type, visitCount, symbolTag);
}
- const SymbolConjured* getConjuredSymbol(const Expr *expr,
- const LocationContext *LCtx,
- unsigned visitCount,
- const void *symbolTag = 0) {
- return SymMgr.getConjuredSymbol(expr, LCtx, visitCount, symbolTag);
+ const SymbolConjured* conjureSymbol(const Expr *expr,
+ const LocationContext *LCtx,
+ unsigned visitCount,
+ const void *symbolTag = 0) {
+ return SymMgr.conjureSymbol(expr, LCtx, visitCount, symbolTag);
}
/// Construct an SVal representing '0' for the specified type.
@@ -169,20 +169,20 @@ public:
/// The advantage of symbols derived/built from other symbols is that we
/// preserve the relation between related(or even equivalent) expressions, so
/// conjured symbols should be used sparingly.
- DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag,
- const Expr *expr,
- const LocationContext *LCtx,
- unsigned count);
- DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag,
- const Expr *expr,
- const LocationContext *LCtx,
- QualType type,
- unsigned count);
+ DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag,
+ const Expr *expr,
+ const LocationContext *LCtx,
+ unsigned count);
+ DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag,
+ const Expr *expr,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned count);
- DefinedOrUnknownSVal getConjuredSymbolVal(const Stmt *stmt,
- const LocationContext *LCtx,
- QualType type,
- unsigned visitCount);
+ DefinedOrUnknownSVal conjureSymbolVal(const Stmt *stmt,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned visitCount);
/// \brief Conjure a symbol representing heap allocated memory region.
///
/// Note, the expression should represent a location.
@@ -227,7 +227,7 @@ public:
BasicVals.getValue(integer->getValue(),
integer->getType()->isUnsignedIntegerOrEnumerationType()));
}
-
+
nonloc::ConcreteInt makeBoolVal(const ObjCBoolLiteralExpr *boolean) {
return makeTruthVal(boolean->getValue(), boolean->getType());
}
@@ -262,11 +262,6 @@ public:
BasicVals.getIntWithPtrWidth(integer, isUnsigned));
}
- NonLoc makeIntVal(uint64_t integer, unsigned bitWidth, bool isUnsigned) {
- return nonloc::ConcreteInt(
- BasicVals.getValue(integer, bitWidth, isUnsigned));
- }
-
NonLoc makeLocAsInteger(Loc loc, unsigned bits) {
return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(loc, bits));
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index e0b5f64b900b..c2134cf04826 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -154,9 +154,6 @@ public:
SymExpr::symbol_iterator symbol_end() const {
return SymExpr::symbol_end();
}
-
- // Implement isa<T> support.
- static inline bool classof(const SVal*) { return true; }
};
@@ -257,7 +254,7 @@ public:
namespace nonloc {
-enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind,
+enum Kind { ConcreteIntKind, SymbolValKind,
LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
/// \brief Represents symbolic expression.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index 138a590b1b24..979546b6ed47 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -25,6 +25,7 @@ namespace clang {
class Stmt;
class Expr;
class ObjCIvarDecl;
+class CXXBasePath;
class StackFrameContext;
namespace ento {
@@ -67,15 +68,26 @@ public:
virtual StoreRef Bind(Store store, Loc loc, SVal val) = 0;
virtual StoreRef BindDefault(Store store, const MemRegion *R, SVal V);
- virtual StoreRef Remove(Store St, Loc L) = 0;
- /// BindCompoundLiteral - Return the store that has the bindings currently
- /// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region
- /// for the compound literal and 'BegInit' and 'EndInit' represent an
- /// array of initializer values.
- virtual StoreRef BindCompoundLiteral(Store store,
- const CompoundLiteralExpr *cl,
- const LocationContext *LC, SVal v) = 0;
+ /// \brief Create a new store with the specified binding removed.
+ /// \param ST the original store, that is the basis for the new store.
+ /// \param L the location whose binding should be removed.
+ virtual StoreRef killBinding(Store ST, Loc L) = 0;
+
+ /// \brief Create a new store that binds a value to a compound literal.
+ ///
+ /// \param ST The original store whose bindings are the basis for the new
+ /// store.
+ ///
+ /// \param CL The compound literal to bind (the binding key).
+ ///
+ /// \param LC The LocationContext for the binding.
+ ///
+ /// \param V The value to bind to the compound literal.
+ virtual StoreRef bindCompoundLiteral(Store ST,
+ const CompoundLiteralExpr *CL,
+ const LocationContext *LC,
+ SVal V) = 0;
/// getInitialStore - Returns the initial "empty" store representing the
/// value bindings upon entry to an analyzed function.
@@ -114,11 +126,15 @@ public:
/// conversions between arrays and pointers.
virtual SVal ArrayToPointer(Loc Array) = 0;
- /// Evaluates DerivedToBase casts.
- SVal evalDerivedToBase(SVal derived, const CastExpr *Cast);
+ /// Evaluates a chain of derived-to-base casts through the path specified in
+ /// \p Cast.
+ SVal evalDerivedToBase(SVal Derived, const CastExpr *Cast);
+
+ /// Evaluates a chain of derived-to-base casts through the specified path.
+ SVal evalDerivedToBase(SVal Derived, const CXXBasePath &CastPath);
/// Evaluates a derived-to-base cast through a single level of derivation.
- virtual SVal evalDerivedToBase(SVal derived, QualType derivedPtrType) = 0;
+ SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType);
/// \brief Evaluates C++ dynamic_cast cast.
/// The callback may result in the following 3 scenarios:
@@ -128,8 +144,7 @@ public:
/// enough info to determine if the cast will succeed at run time).
/// The function returns an SVal representing the derived class; it's
/// valid only if Failed flag is set to false.
- virtual SVal evalDynamicCast(SVal base, QualType derivedPtrType,
- bool &Failed) = 0;
+ SVal evalDynamicCast(SVal Base, QualType DerivedPtrType, bool &Failed);
const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
@@ -141,10 +156,6 @@ public:
virtual StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx,
SymbolReaper& SymReaper) = 0;
- virtual StoreRef BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0;
-
- virtual StoreRef BindDeclWithNoInit(Store store, const VarRegion *VR) = 0;
-
virtual bool includedInBindings(Store store,
const MemRegion *region) const = 0;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index 68b81f19a4fd..1e710778d9be 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -60,7 +60,8 @@ public:
/// SubEngine is expected to populate dstNodes with new nodes representing
/// updated analysis state, or generate no nodes at all if it doesn't.
virtual void processCFGBlockEntrance(const BlockEdge &L,
- NodeBuilderWithSinks &nodeBuilder) = 0;
+ NodeBuilderWithSinks &nodeBuilder,
+ ExplodedNode *Pred) = 0;
/// Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
@@ -81,7 +82,8 @@ public:
/// Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
- virtual void processEndOfFunction(NodeBuilderContext& BC) = 0;
+ virtual void processEndOfFunction(NodeBuilderContext& BC,
+ ExplodedNode *Pred) = 0;
// Generate the entry node of the callee.
virtual void processCallEnter(CallEnter CE, ExplodedNode *Pred) = 0;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 5d27f8654eb0..873f773b459d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -65,12 +65,9 @@ public:
virtual void dumpToStream(raw_ostream &os) const {}
- virtual QualType getType(ASTContext&) const = 0;
+ virtual QualType getType() const = 0;
virtual void Profile(llvm::FoldingSetNodeID& profile) = 0;
- // Implement isa<T> support.
- static inline bool classof(const SymExpr*) { return true; }
-
/// \brief Iterator over symbols that the current symbol depends on.
///
/// For SymbolData, it's the symbol itself; for expressions, it's the
@@ -144,7 +141,7 @@ public:
virtual void dumpToStream(raw_ostream &os) const;
- QualType getType(ASTContext&) const;
+ QualType getType() const;
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
@@ -173,7 +170,7 @@ public:
unsigned getCount() const { return Count; }
const void *getTag() const { return SymbolTag; }
- QualType getType(ASTContext&) const;
+ QualType getType() const;
virtual void dumpToStream(raw_ostream &os) const;
@@ -211,7 +208,7 @@ public:
SymbolRef getParentSymbol() const { return parentSymbol; }
const TypedValueRegion *getRegion() const { return R; }
- QualType getType(ASTContext&) const;
+ QualType getType() const;
virtual void dumpToStream(raw_ostream &os) const;
@@ -244,7 +241,7 @@ public:
const SubRegion *getRegion() const { return R; }
- QualType getType(ASTContext&) const;
+ QualType getType() const;
virtual void dumpToStream(raw_ostream &os) const;
@@ -283,7 +280,7 @@ public:
unsigned getCount() const { return Count; }
const void *getTag() const { return Tag; }
- QualType getType(ASTContext&) const;
+ QualType getType() const;
virtual void dumpToStream(raw_ostream &os) const;
@@ -320,7 +317,7 @@ public:
SymbolCast(const SymExpr *In, QualType From, QualType To) :
SymExpr(CastSymbolKind), Operand(In), FromTy(From), ToTy(To) { }
- QualType getType(ASTContext &C) const { return ToTy; }
+ QualType getType() const { return ToTy; }
const SymExpr *getOperand() const { return Operand; }
@@ -358,7 +355,7 @@ public:
// FIXME: We probably need to make this out-of-line to avoid redundant
// generation of virtual functions.
- QualType getType(ASTContext &C) const { return T; }
+ QualType getType() const { return T; }
BinaryOperator::Opcode getOpcode() const { return Op; }
@@ -399,7 +396,7 @@ public:
const SymExpr *rhs, QualType t)
: SymExpr(IntSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
- QualType getType(ASTContext &C) const { return T; }
+ QualType getType() const { return T; }
BinaryOperator::Opcode getOpcode() const { return Op; }
@@ -446,7 +443,7 @@ public:
// FIXME: We probably need to make this out-of-line to avoid redundant
// generation of virtual functions.
- QualType getType(ASTContext &C) const { return T; }
+ QualType getType() const { return T; }
virtual void dumpToStream(raw_ostream &os) const;
@@ -495,18 +492,17 @@ public:
/// \brief Make a unique symbol for MemRegion R according to its kind.
const SymbolRegionValue* getRegionValueSymbol(const TypedValueRegion* R);
- const SymbolConjured* getConjuredSymbol(const Stmt *E,
- const LocationContext *LCtx,
- QualType T,
- unsigned VisitCount,
- const void *SymbolTag = 0);
+ const SymbolConjured* conjureSymbol(const Stmt *E,
+ const LocationContext *LCtx,
+ QualType T,
+ unsigned VisitCount,
+ const void *SymbolTag = 0);
- const SymbolConjured* getConjuredSymbol(const Expr *E,
- const LocationContext *LCtx,
- unsigned VisitCount,
- const void *SymbolTag = 0) {
- return getConjuredSymbol(E, LCtx, E->getType(),
- VisitCount, SymbolTag);
+ const SymbolConjured* conjureSymbol(const Expr *E,
+ const LocationContext *LCtx,
+ unsigned VisitCount,
+ const void *SymbolTag = 0) {
+ return conjureSymbol(E, LCtx, E->getType(), VisitCount, SymbolTag);
}
const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol,
@@ -541,7 +537,7 @@ public:
const SymExpr *rhs, QualType t);
QualType getType(const SymExpr *SE) const {
- return SE->getType(Ctx);
+ return SE->getType();
}
/// \brief Add artificial symbol dependency.
@@ -584,9 +580,11 @@ public:
///
/// If the statement is NULL, everything is this and parent contexts is
/// considered live.
- SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr,
+ /// If the stack frame context is NULL, everything on stack is considered
+ /// dead.
+ SymbolReaper(const StackFrameContext *Ctx, const Stmt *s, SymbolManager& symmgr,
StoreManager &storeMgr)
- : LCtx(ctx->getCurrentStackFrame()), Loc(s), SymMgr(symmgr),
+ : LCtx(Ctx), Loc(s), SymMgr(symmgr),
reapedStore(0, storeMgr) {}
~SymbolReaper() {}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
index 53205d3b720c..c274cea8413e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
@@ -22,6 +22,8 @@ namespace ento {
/// The GDM component containing the tainted root symbols. We lazily infer the
/// taint of the dependent symbols. Currently, this is a map from a symbol to
/// tag kind. TODO: Should support multiple tag kinds.
+// FIXME: This does not use the nice trait macros because it must be accessible
+// from multiple translation units.
struct TaintMap {};
typedef llvm::ImmutableMap<SymbolRef, TaintTagType> TaintMapImpl;
template<> struct ProgramStateTrait<TaintMap>