summaryrefslogtreecommitdiffstats
path: root/include/clang/StaticAnalyzer/Core
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/StaticAnalyzer/Core')
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h24
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h33
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h3
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h19
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h33
-rw-r--r--include/clang/StaticAnalyzer/Core/IssueHash.h51
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h71
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h44
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h7
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h29
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h57
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h26
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h36
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h62
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h9
17 files changed, 466 insertions, 50 deletions
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index f02e48a4..3959de2 100644
--- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -253,9 +253,18 @@ private:
/// \sa getMaxTimesInlineLarge
Optional<unsigned> MaxTimesInlineLarge;
+ /// \sa getMinCFGSizeTreatFunctionsAsLarge
+ Optional<unsigned> MinCFGSizeTreatFunctionsAsLarge;
+
/// \sa getMaxNodesPerTopLevelFunction
Optional<unsigned> MaxNodesPerTopLevelFunction;
+ /// \sa shouldInlineLambdas
+ Optional<bool> InlineLambdas;
+
+ /// \sa shouldWidenLoops
+ Optional<bool> WidenLoops;
+
/// A helper function that retrieves option for a given full-qualified
/// checker name.
/// Options for checkers can be specified via 'analyzer-config' command-line
@@ -502,6 +511,13 @@ public:
/// This is controlled by the 'max-times-inline-large' config option.
unsigned getMaxTimesInlineLarge();
+ /// Returns the number of basic blocks a function needs to have to be
+ /// considered large for the 'max-times-inline-large' config option.
+ ///
+ /// This is controlled by the 'min-cfg-size-treat-functions-as-large' config
+ /// option.
+ unsigned getMinCFGSizeTreatFunctionsAsLarge();
+
/// Returns the maximum number of nodes the analyzer can generate while
/// exploring a top level function (for each exploded graph).
/// 150000 is default; 0 means no limit.
@@ -509,6 +525,14 @@ public:
/// This is controlled by the 'max-nodes' config option.
unsigned getMaxNodesPerTopLevelFunction();
+ /// Returns true if lambdas should be inlined. Otherwise a sink node will be
+ /// generated each time a LambdaExpr is visited.
+ bool shouldInlineLambdas();
+
+ /// Returns true if the analysis should try to widen loops.
+ /// This is controlled by the 'widen-loops' config option.
+ bool shouldWidenLoops();
+
public:
AnalyzerOptions() :
AnalysisStoreOpt(RegionStoreModel),
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
index 83b05ec..197d27a 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -37,6 +37,9 @@ class PathDiagnosticPiece;
/// will have to provide your own implementation.)
class BugReporterVisitor : public llvm::FoldingSetNode {
public:
+ BugReporterVisitor() = default;
+ BugReporterVisitor(const BugReporterVisitor &) = default;
+ BugReporterVisitor(BugReporterVisitor &&) {}
virtual ~BugReporterVisitor();
/// \brief Returns a copy of this BugReporter.
@@ -92,9 +95,8 @@ class BugReporterVisitorImpl : public BugReporterVisitor {
}
};
-class FindLastStoreBRVisitor
- : public BugReporterVisitorImpl<FindLastStoreBRVisitor>
-{
+class FindLastStoreBRVisitor final
+ : public BugReporterVisitorImpl<FindLastStoreBRVisitor> {
const MemRegion *R;
SVal V;
bool Satisfied;
@@ -124,9 +126,8 @@ public:
BugReport &BR) override;
};
-class TrackConstraintBRVisitor
- : public BugReporterVisitorImpl<TrackConstraintBRVisitor>
-{
+class TrackConstraintBRVisitor final
+ : public BugReporterVisitorImpl<TrackConstraintBRVisitor> {
DefinedSVal Constraint;
bool Assumption;
bool IsSatisfied;
@@ -161,8 +162,8 @@ private:
/// \class NilReceiverBRVisitor
/// \brief Prints path notes when a message is sent to a nil receiver.
-class NilReceiverBRVisitor
- : public BugReporterVisitorImpl<NilReceiverBRVisitor> {
+class NilReceiverBRVisitor final
+ : public BugReporterVisitorImpl<NilReceiverBRVisitor> {
public:
void Profile(llvm::FoldingSetNodeID &ID) const override {
@@ -181,7 +182,8 @@ public:
};
/// Visitor that tries to report interesting diagnostics from conditions.
-class ConditionBRVisitor : public BugReporterVisitorImpl<ConditionBRVisitor> {
+class ConditionBRVisitor final
+ : public BugReporterVisitorImpl<ConditionBRVisitor> {
public:
void Profile(llvm::FoldingSetNodeID &ID) const override {
static int x = 0;
@@ -247,8 +249,8 @@ public:
/// \brief Suppress reports that might lead to known false positives.
///
/// Currently this suppresses reports based on locations of bugs.
-class LikelyFalsePositiveSuppressionBRVisitor
- : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> {
+class LikelyFalsePositiveSuppressionBRVisitor final
+ : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> {
public:
static void *getTag() {
static int Tag = 0;
@@ -276,8 +278,8 @@ public:
///
/// 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> {
+class UndefOrNullArgVisitor final
+ : public BugReporterVisitorImpl<UndefOrNullArgVisitor> {
/// The interesting memory region this visitor is tracking.
const MemRegion *R;
@@ -297,9 +299,8 @@ public:
BugReport &BR) override;
};
-class SuppressInlineDefensiveChecksVisitor
-: public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor>
-{
+class SuppressInlineDefensiveChecksVisitor final
+ : public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor> {
/// The symbolic value for which we are tracking constraints.
/// This value is constrained to null in the end of path.
DefinedSVal V;
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 941d5240..35421f9 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -122,7 +122,7 @@ class PathDiagnosticRange : public SourceRange {
public:
bool isPoint;
- PathDiagnosticRange(const SourceRange &R, bool isP = false)
+ PathDiagnosticRange(SourceRange R, bool isP = false)
: SourceRange(R), isPoint(isP) {}
PathDiagnosticRange() : isPoint(false) {}
@@ -422,7 +422,6 @@ class PathPieces : public std::list<IntrusiveRefCntPtr<PathDiagnosticPiece> > {
void flattenTo(PathPieces &Primary, PathPieces &Current,
bool ShouldFlattenMacros) const;
public:
- ~PathPieces();
PathPieces flatten(bool ShouldFlattenMacros) const {
PathPieces Result;
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index 099d763..1410af1 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -131,6 +131,21 @@ public:
}
};
+class ObjCMessageNil {
+ template <typename CHECKER>
+ static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg,
+ CheckerContext &C) {
+ ((const CHECKER *)checker)->checkObjCMessageNil(msg, C);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForObjCMessageNil(
+ CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>));
+ }
+};
+
class PostObjCMessage {
template <typename CHECKER>
static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg,
@@ -514,6 +529,10 @@ struct ImplicitNullDerefEvent {
bool IsLoad;
ExplodedNode *SinkNode;
BugReporter *BR;
+ // When true, the dereference is in the source code directly. When false, the
+ // dereference might happen later (for example pointer passed to a parameter
+ // that is marked with nonnull attribute.)
+ bool IsDirectDereference;
};
/// \brief A helper class which wraps a boolean value set to false by default.
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 8a1a82b..bc9af49 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -89,11 +89,16 @@ class CheckName {
explicit CheckName(StringRef Name) : Name(Name) {}
public:
- CheckName() {}
- CheckName(const CheckName &Other) : Name(Other.Name) {}
+ CheckName() = default;
StringRef getName() const { return Name; }
};
+enum class ObjCMessageVisitKind {
+ Pre,
+ Post,
+ MessageNil
+};
+
class CheckerManager {
const LangOptions LangOpts;
AnalyzerOptionsRef AOptions;
@@ -212,7 +217,7 @@ public:
const ExplodedNodeSet &Src,
const ObjCMethodCall &msg,
ExprEngine &Eng) {
- runCheckersForObjCMessage(/*isPreVisit=*/true, Dst, Src, msg, Eng);
+ runCheckersForObjCMessage(ObjCMessageVisitKind::Pre, Dst, Src, msg, Eng);
}
/// \brief Run checkers for post-visiting obj-c messages.
@@ -221,12 +226,22 @@ public:
const ObjCMethodCall &msg,
ExprEngine &Eng,
bool wasInlined = false) {
- runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng,
+ runCheckersForObjCMessage(ObjCMessageVisitKind::Post, Dst, Src, msg, Eng,
wasInlined);
}
+ /// \brief Run checkers for visiting an obj-c message to nil.
+ void runCheckersForObjCMessageNil(ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ const ObjCMethodCall &msg,
+ ExprEngine &Eng) {
+ runCheckersForObjCMessage(ObjCMessageVisitKind::MessageNil, Dst, Src, msg,
+ Eng);
+ }
+
+
/// \brief Run checkers for visiting obj-c messages.
- void runCheckersForObjCMessage(bool isPreVisit,
+ void runCheckersForObjCMessage(ObjCMessageVisitKind visitKind,
ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const ObjCMethodCall &msg, ExprEngine &Eng,
@@ -458,6 +473,8 @@ public:
void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn);
void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn);
+ void _registerForObjCMessageNil(CheckObjCMessageFunc checkfn);
+
void _registerForPreCall(CheckCallFunc checkfn);
void _registerForPostCall(CheckCallFunc checkfn);
@@ -558,8 +575,14 @@ private:
const CachedStmtCheckers &getCachedStmtCheckersFor(const Stmt *S,
bool isPreVisit);
+ /// Returns the checkers that have registered for callbacks of the
+ /// given \p Kind.
+ const std::vector<CheckObjCMessageFunc> &
+ getObjCMessageCheckers(ObjCMessageVisitKind Kind);
+
std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers;
std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers;
+ std::vector<CheckObjCMessageFunc> ObjCMessageNilCheckers;
std::vector<CheckCallFunc> PreCallCheckers;
std::vector<CheckCallFunc> PostCallCheckers;
diff --git a/include/clang/StaticAnalyzer/Core/IssueHash.h b/include/clang/StaticAnalyzer/Core/IssueHash.h
new file mode 100644
index 0000000..b3c4f14
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/IssueHash.h
@@ -0,0 +1,51 @@
+//===---------- IssueHash.h - Generate identification hashes ----*- 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_STATICANALYZER_CORE_ISSUE_HASH_H
+#define LLVM_CLANG_STATICANALYZER_CORE_ISSUE_HASH_H
+
+#include "llvm/ADT/SmallString.h"
+
+namespace clang {
+class Decl;
+class SourceManager;
+class FullSourceLoc;
+class LangOptions;
+
+/// \brief Get an MD5 hash to help identify bugs.
+///
+/// This function returns a hash that helps identify bugs within a source file.
+/// This identification can be utilized to diff diagnostic results on different
+/// snapshots of a projects, or maintain a database of suppressed diagnotics.
+///
+/// The hash contains the normalized text of the location associated with the
+/// diagnostic. Normalization means removing the whitespaces. The associated
+/// location is the either the last location of a diagnostic path or a uniqueing
+/// location. The bugtype and the name of the checker is also part of the hash.
+/// The last component is the string representation of the enclosing declaration
+/// of the associated location.
+///
+/// In case a new hash is introduced, the old one should still be maintained for
+/// a while. One should not introduce a new hash for every change, it is
+/// possible to introduce experimental hashes that may change in the future.
+/// Such hashes should be marked as experimental using a comment in the plist
+/// files.
+llvm::SmallString<32> GetIssueHash(const SourceManager &SM,
+ FullSourceLoc &IssueLoc,
+ llvm::StringRef CheckerName,
+ llvm::StringRef BugType, const Decl *D,
+ const LangOptions &LangOpts);
+
+/// \brief Get the string representation of issue hash. See GetIssueHash() for
+/// more information.
+std::string GetIssueString(const SourceManager &SM, FullSourceLoc &IssueLoc,
+ llvm::StringRef CheckerName, llvm::StringRef BugType,
+ const Decl *D, const LangOptions &LangOpts);
+} // namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 63b8631..b09dffa 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -164,7 +164,8 @@ protected:
/// \brief Used to specify non-argument regions that will be invalidated as a
/// result of this call.
- virtual void getExtraInvalidatedValues(ValueList &Values) const {}
+ virtual void getExtraInvalidatedValues(ValueList &Values,
+ RegionAndSymbolInvalidationTraits *ETraits) const {}
public:
virtual ~CallEvent() {}
@@ -253,9 +254,16 @@ public:
/// which the return value has already been bound to the origin expression.
SVal getReturnValue() const;
+ /// \brief Returns true if the type of any of the non-null arguments satisfies
+ /// the condition.
+ bool hasNonNullArgumentsWithType(bool (*Condition)(QualType)) const;
+
/// \brief Returns true if any of the arguments appear to represent callbacks.
bool hasNonZeroCallbackArg() const;
+ /// \brief Returns true if any of the arguments is void*.
+ bool hasVoidPointerToNonConstArg() const;
+
/// \brief Returns true if any of the arguments are known to escape to long-
/// term storage, even if this method will not modify them.
// NOTE: The exact semantics of this are still being defined!
@@ -472,7 +480,8 @@ protected:
BlockCall(const BlockCall &Other) : CallEvent(Other) {}
void cloneTo(void *Dest) const override { new (Dest) BlockCall(*this); }
- void getExtraInvalidatedValues(ValueList &Values) const override;
+ void getExtraInvalidatedValues(ValueList &Values,
+ RegionAndSymbolInvalidationTraits *ETraits) const override;
public:
virtual const CallExpr *getOriginExpr() const {
@@ -497,8 +506,55 @@ public:
return BR->getDecl();
}
+ bool isConversionFromLambda() const {
+ const BlockDecl *BD = getDecl();
+ if (!BD)
+ return false;
+
+ return BD->isConversionFromLambda();
+ }
+
+ /// \brief For a block converted from a C++ lambda, returns the block
+ /// VarRegion for the variable holding the captured C++ lambda record.
+ const VarRegion *getRegionStoringCapturedLambda() const {
+ assert(isConversionFromLambda());
+ const BlockDataRegion *BR = getBlockRegion();
+ assert(BR && "Block converted from lambda must have a block region");
+
+ auto I = BR->referenced_vars_begin();
+ assert(I != BR->referenced_vars_end());
+
+ return I.getCapturedRegion();
+ }
+
RuntimeDefinition getRuntimeDefinition() const override {
- return RuntimeDefinition(getDecl());
+ if (!isConversionFromLambda())
+ return RuntimeDefinition(getDecl());
+
+ // Clang converts lambdas to blocks with an implicit user-defined
+ // conversion operator method on the lambda record that looks (roughly)
+ // like:
+ //
+ // typedef R(^block_type)(P1, P2, ...);
+ // operator block_type() const {
+ // auto Lambda = *this;
+ // return ^(P1 p1, P2 p2, ...){
+ // /* return Lambda(p1, p2, ...); */
+ // };
+ // }
+ //
+ // Here R is the return type of the lambda and P1, P2, ... are
+ // its parameter types. 'Lambda' is a fake VarDecl captured by the block
+ // that is initialized to a copy of the lambda.
+ //
+ // Sema leaves the body of a lambda-converted block empty (it is
+ // produced by CodeGen), so we can't analyze it directly. Instead, we skip
+ // the block body and analyze the operator() method on the captured lambda.
+ const VarDecl *LambdaVD = getRegionStoringCapturedLambda()->getDecl();
+ const CXXRecordDecl *LambdaDecl = LambdaVD->getType()->getAsCXXRecordDecl();
+ CXXMethodDecl* LambdaCallOperator = LambdaDecl->getLambdaCallOperator();
+
+ return RuntimeDefinition(LambdaCallOperator);
}
bool argumentsMayEscape() const override {
@@ -521,7 +577,8 @@ public:
/// it is written.
class CXXInstanceCall : public AnyFunctionCall {
protected:
- void getExtraInvalidatedValues(ValueList &Values) const override;
+ void getExtraInvalidatedValues(ValueList &Values,
+ RegionAndSymbolInvalidationTraits *ETraits) const override;
CXXInstanceCall(const CallExpr *CE, ProgramStateRef St,
const LocationContext *LCtx)
@@ -704,7 +761,8 @@ protected:
CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){}
void cloneTo(void *Dest) const override { new (Dest) CXXConstructorCall(*this); }
- void getExtraInvalidatedValues(ValueList &Values) const override;
+ void getExtraInvalidatedValues(ValueList &Values,
+ RegionAndSymbolInvalidationTraits *ETraits) const override;
public:
virtual const CXXConstructExpr *getOriginExpr() const {
@@ -803,7 +861,8 @@ protected:
ObjCMethodCall(const ObjCMethodCall &Other) : CallEvent(Other) {}
void cloneTo(void *Dest) const override { new (Dest) ObjCMethodCall(*this); }
- void getExtraInvalidatedValues(ValueList &Values) const override;
+ void getExtraInvalidatedValues(ValueList &Values,
+ RegionAndSymbolInvalidationTraits *ETraits) const override;
/// Check if the selector may have multiple definitions (may have overrides).
virtual bool canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index a4ff133..d4f014d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -224,13 +224,39 @@ public:
}
/// \brief Generate a sink node. Generating a sink stops exploration of the
- /// given path.
- ExplodedNode *generateSink(ProgramStateRef State = nullptr,
- ExplodedNode *Pred = nullptr,
+ /// given path. To create a sink node for the purpose of reporting an error,
+ /// checkers should use generateErrorNode() instead.
+ ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred,
const ProgramPointTag *Tag = nullptr) {
return addTransitionImpl(State ? State : getState(), true, Pred, Tag);
}
+ /// \brief Generate a transition to a node that will be used to report
+ /// an error. This node will be a sink. That is, it will stop exploration of
+ /// the given path.
+ ///
+ /// @param State The state of the generated node.
+ /// @param Tag The tag to uniquely identify the creation site. If null,
+ /// the default tag for the checker will be used.
+ ExplodedNode *generateErrorNode(ProgramStateRef State = nullptr,
+ const ProgramPointTag *Tag = nullptr) {
+ return generateSink(State, Pred,
+ (Tag ? Tag : Location.getTag()));
+ }
+
+ /// \brief Generate a transition to a node that will be used to report
+ /// an error. This node will not be a sink. That is, exploration will
+ /// continue along this path.
+ ///
+ /// @param State The state of the generated node.
+ /// @param Tag The tag to uniquely identify the creation site. If null,
+ /// the default tag for the checker will be used.
+ ExplodedNode *
+ generateNonFatalErrorNode(ProgramStateRef State = nullptr,
+ const ProgramPointTag *Tag = nullptr) {
+ return addTransition(State, (Tag ? Tag : Location.getTag()));
+ }
+
/// \brief Emit the diagnostics report.
void emitReport(std::unique_ptr<BugReport> R) {
Changed = true;
@@ -287,6 +313,18 @@ private:
bool MarkAsSink,
ExplodedNode *P = nullptr,
const ProgramPointTag *Tag = nullptr) {
+ // The analyzer may stop exploring if it sees a state it has previously
+ // visited ("cache out"). The early return here is a defensive check to
+ // prevent accidental caching out by checker API clients. Unless there is a
+ // tag or the client checker has requested that the generated node be
+ // marked as a sink, we assume that a client requesting a transition to a
+ // state that is the same as the predecessor state has made a mistake. We
+ // return the predecessor rather than cache out.
+ //
+ // TODO: We could potentially change the return to an assertion to alert
+ // clients to their mistake, but several checkers (including
+ // DereferenceChecker, CallAndMessageChecker, and DynamicTypePropagation)
+ // rely upon the defensive behavior and would need to be updated.
if (!State || (State == Pred->getState() && !Tag && !MarkAsSink))
return Pred;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
index e7ec1f4..8dda636 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
@@ -15,9 +15,13 @@
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H
#include "clang/AST/Stmt.h"
+#include <tuple>
namespace clang {
+class Expr;
+class VarDecl;
+
namespace ento {
bool containsMacro(const Stmt *S);
@@ -35,6 +39,9 @@ template <class T> bool containsStmt(const Stmt *S) {
return false;
}
+std::pair<const clang::VarDecl *, const clang::Expr *>
+parseAssignment(const Stmt *S);
+
} // end GR namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index f876096..9a858c2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -99,6 +99,35 @@ public:
return ProgramStatePair(StTrue, StFalse);
}
+ virtual ProgramStateRef assumeWithinInclusiveRange(ProgramStateRef State,
+ NonLoc Value,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InBound) = 0;
+
+ virtual ProgramStatePair assumeWithinInclusiveRangeDual(
+ ProgramStateRef State, NonLoc Value, const llvm::APSInt &From,
+ const llvm::APSInt &To) {
+ ProgramStateRef StInRange = assumeWithinInclusiveRange(State, Value, From,
+ To, true);
+
+ // If StTrue is infeasible, asserting the falseness of Cond is unnecessary
+ // because the existing constraints already establish this.
+ if (!StInRange)
+ return ProgramStatePair((ProgramStateRef)nullptr, State);
+
+ ProgramStateRef StOutOfRange = assumeWithinInclusiveRange(State, Value,
+ From, To, false);
+ if (!StOutOfRange) {
+ // 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)nullptr);
+ }
+
+ return ProgramStatePair(StInRange, StOutOfRange);
+ }
+
/// \brief If a symbol is perfectly constrained to a constant, attempt
/// to return the concrete value.
///
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h
new file mode 100644
index 0000000..555191d
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h
@@ -0,0 +1,57 @@
+//== DynamicTypeMap.h - Dynamic type map ----------------------- -*- C++ -*--=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides APIs for tracking dynamic type information.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "llvm/ADT/ImmutableMap.h"
+
+namespace clang {
+namespace ento {
+
+/// The GDM component containing the dynamic type info. This is a map from a
+/// symbol to its most likely type.
+struct DynamicTypeMap {};
+typedef llvm::ImmutableMap<const MemRegion *, DynamicTypeInfo>
+ DynamicTypeMapImpl;
+template <>
+struct ProgramStateTrait<DynamicTypeMap>
+ : public ProgramStatePartialTrait<DynamicTypeMapImpl> {
+ static void *GDMIndex() {
+ static int index = 0;
+ return &index;
+ }
+};
+
+/// \brief Get dynamic type information for a region.
+DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State,
+ const MemRegion *Reg);
+
+/// \brief Set dynamic type information of the region; return the new state.
+ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg,
+ DynamicTypeInfo NewTy);
+
+/// \brief Set dynamic type information of the region; return the new state.
+inline ProgramStateRef setDynamicTypeInfo(ProgramStateRef State,
+ const MemRegion *Reg, QualType NewTy,
+ bool CanBeSubClassed = true) {
+ return setDynamicTypeInfo(State, Reg,
+ DynamicTypeInfo(NewTy, CanBeSubClassed));
+}
+
+} // ento
+} // clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index d8f1c34..99083c9 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -341,6 +341,10 @@ public:
void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
+ /// VisitLambdaExpr - Transfer function logic for LambdaExprs.
+ void VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
/// VisitBinaryOperator - Transfer function logic for binary operators.
void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
@@ -600,6 +604,28 @@ private:
const LocationContext *LC,
const Expr *E,
const Expr *ResultE = nullptr);
+
+ /// For a DeclStmt or CXXInitCtorInitializer, walk backward in the current CFG
+ /// block to find the constructor expression that directly constructed into
+ /// the storage for this statement. Returns null if the constructor for this
+ /// statement created a temporary object region rather than directly
+ /// constructing into an existing region.
+ const CXXConstructExpr *findDirectConstructorForCurrentCFGElement();
+
+ /// For a CXXConstructExpr, walk forward in the current CFG block to find the
+ /// CFGElement for the DeclStmt or CXXInitCtorInitializer for which is
+ /// directly constructed by this constructor. Returns None if the current
+ /// constructor expression did not directly construct into an existing
+ /// region.
+ Optional<CFGElement> findElementDirectlyInitializedByCurrentConstructor();
+
+ /// For a given constructor, look forward in the current CFG block to
+ /// determine the region into which an object will be constructed by \p CE.
+ /// Returns either a field or local variable region if the object will be
+ /// directly constructed in an existing region or a temporary object region
+ /// if not.
+ const MemRegion *getRegionForConstructedObject(const CXXConstructExpr *CE,
+ ExplodedNode *Pred);
};
/// Traits for storing the call processing policy inside GDM.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
index faa3500..ce81c98 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H
+#include "clang/AST/Decl.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
@@ -22,7 +23,6 @@
#include <deque>
namespace clang {
-class Decl;
namespace ento {
typedef std::deque<Decl*> SetOfDecls;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
new file mode 100644
index 0000000..3168733
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
@@ -0,0 +1,36 @@
+//===--- LoopWidening.h - Widen loops ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// This header contains the declarations of functions which are used to widen
+/// loops which do not otherwise exit. The widening is done by invalidating
+/// anything which might be modified by the body of the loop.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPWIDENING_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPWIDENING_H
+
+#include "clang/Analysis/CFG.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+
+namespace clang {
+namespace ento {
+
+/// \brief Get the states that result from widening the loop.
+///
+/// Widen the loop by invalidating anything that might be modified
+/// by the loop body in any iteration.
+ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
+ const LocationContext *LCtx,
+ unsigned BlockCount, const Stmt *LoopStmt);
+
+} // end namespace ento
+} // end namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 4f07129..bb835c4 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -19,6 +19,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
@@ -46,7 +47,7 @@ class RegionOffset {
/// The base region.
const MemRegion *R;
- /// The bit offset within the base region. It shouldn't be negative.
+ /// The bit offset within the base region. Can be negative.
int64_t Offset;
public:
@@ -1333,7 +1334,12 @@ public:
/// Tells that a region's contents is not changed.
TK_PreserveContents = 0x1,
/// Suppress pointer-escaping of a region.
- TK_SuppressEscape = 0x2
+ TK_SuppressEscape = 0x2,
+ // Do not invalidate super region.
+ TK_DoNotInvalidateSuperRegion = 0x4,
+ /// When applied to a MemSpaceRegion, indicates the entire memory space
+ /// should be invalidated.
+ TK_EntireMemSpace = 0x8
// Do not forget to extend StorageTypeForKinds if number of traits exceed
// the number of bits StorageTypeForKinds can store.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index ac4e452..c4a62ec 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -190,6 +190,27 @@ public:
DefinedOrUnknownSVal upperBound,
bool assumption,
QualType IndexType = QualType()) const;
+
+ /// Assumes that the value of \p Val is bounded with [\p From; \p To]
+ /// (if \p assumption is "true") or it is fully out of this range
+ /// (if \p assumption is "false").
+ ///
+ /// This returns a new state with the added constraint on \p cond.
+ /// If no new state is feasible, NULL is returned.
+ ProgramStateRef assumeWithinInclusiveRange(DefinedOrUnknownSVal Val,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool assumption) const;
+
+ /// Assumes given range both "true" and "false" for \p Val, and returns both
+ /// corresponding states (respectively).
+ ///
+ /// This is more efficient than calling assume() twice. Note that one (but not
+ /// both) of the returned states may be NULL.
+ std::pair<ProgramStateRef, ProgramStateRef>
+ assumeWithinInclusiveRange(DefinedOrUnknownSVal Val, const llvm::APSInt &From,
+ const llvm::APSInt &To) const;
+
/// \brief Check if the given SVal is constrained to zero or is a zero
/// constant.
@@ -337,20 +358,6 @@ public:
bool isTainted(SymbolRef Sym, TaintTagType Kind = TaintTagGeneric) const;
bool isTainted(const MemRegion *Reg, TaintTagType Kind=TaintTagGeneric) const;
- /// \brief Get dynamic type information for a region.
- DynamicTypeInfo getDynamicTypeInfo(const MemRegion *Reg) const;
-
- /// \brief Set dynamic type information of the region; return the new state.
- ProgramStateRef setDynamicTypeInfo(const MemRegion *Reg,
- DynamicTypeInfo NewTy) const;
-
- /// \brief Set dynamic type information of the region; return the new state.
- ProgramStateRef setDynamicTypeInfo(const MemRegion *Reg,
- QualType NewTy,
- bool CanBeSubClassed = true) const {
- return setDynamicTypeInfo(Reg, DynamicTypeInfo(NewTy, CanBeSubClassed));
- }
-
//==---------------------------------------------------------------------==//
// Accessing the Generic Data Map (GDM).
//==---------------------------------------------------------------------==//
@@ -650,6 +657,33 @@ ProgramState::assume(DefinedOrUnknownSVal Cond) const {
->assumeDual(this, Cond.castAs<DefinedSVal>());
}
+inline ProgramStateRef
+ProgramState::assumeWithinInclusiveRange(DefinedOrUnknownSVal Val,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool Assumption) const {
+ if (Val.isUnknown())
+ return this;
+
+ assert(Val.getAs<NonLoc>() && "Only NonLocs are supported!");
+
+ return getStateManager().ConstraintMgr->assumeWithinInclusiveRange(
+ this, Val.castAs<NonLoc>(), From, To, Assumption);
+}
+
+inline std::pair<ProgramStateRef, ProgramStateRef>
+ProgramState::assumeWithinInclusiveRange(DefinedOrUnknownSVal Val,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To) const {
+ if (Val.isUnknown())
+ return std::make_pair(this, this);
+
+ assert(Val.getAs<NonLoc>() && "Only NonLocs are supported!");
+
+ return getStateManager().ConstraintMgr
+ ->assumeWithinInclusiveRangeDual(this, Val.castAs<NonLoc>(), From, To);
+}
+
inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V) const {
if (Optional<Loc> L = LV.getAs<Loc>())
return bindLoc(*L, V);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 1ca96a2..9dbfab2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -639,6 +639,7 @@ public:
}
void markLive(const MemRegion *region);
+ void markElementIndicesLive(const MemRegion *region);
/// \brief Set to the value of the symbolic store after
/// StoreManager::removeDeadBindings has been called.
@@ -650,14 +651,20 @@ private:
};
class SymbolVisitor {
+protected:
+ ~SymbolVisitor() = default;
+
public:
+ SymbolVisitor() = default;
+ SymbolVisitor(const SymbolVisitor &) = default;
+ SymbolVisitor(SymbolVisitor &&) {}
+
/// \brief A visitor method invoked by ProgramStateManager::scanReachableSymbols.
///
/// The method returns \c true if symbols should continue be scanned and \c
/// false otherwise.
virtual bool VisitSymbol(SymbolRef sym) = 0;
virtual bool VisitMemRegion(const MemRegion *region) { return true; }
- virtual ~SymbolVisitor();
};
} // end GR namespace
OpenPOWER on IntegriCloud