summaryrefslogtreecommitdiff
path: root/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive
diff options
context:
space:
mode:
authorRalf Luther <luther.ralf@gmail.com>2019-03-27 20:23:17 +0000
committerGerrit Code Review <gerrit2@aicp-server-3>2019-03-27 20:23:17 +0000
commit1ce3a9d272e564b22a1333a1e36a3d3ab7cfab01 (patch)
tree391382eadd4fec5bb480f2e8934fa352770221d1 /clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive
parentd1d48b140bafaa8a50107292f5fce95562575765 (diff)
parent4f56932d3416ac03f646bc1a611b3135fec2fe08 (diff)
Merge "Update prebuilt Clang to r353983." into p9.0HEADp9.0-backupp9.0
Diffstat (limited to 'clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive')
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h108
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h161
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h270
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h59
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h1229
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h309
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h69
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h208
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h574
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h51
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h63
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h125
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h504
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h848
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h142
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h49
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h35
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h1488
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h909
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h328
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h42
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h215
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def89
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SMTAPI.h405
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h337
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h752
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h395
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h150
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def74
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h670
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h92
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h338
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h53
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h175
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SummaryManager.h57
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h145
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h650
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def54
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h58
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h29
-rw-r--r--clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h94
41 files changed, 12403 insertions, 0 deletions
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
new file mode 100644
index 00000000..4b7d6054
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
@@ -0,0 +1,108 @@
+//== APSIntType.h - Simple record of the type of APSInts --------*- C++ -*--==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_APSINTTYPE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_APSINTTYPE_H
+
+#include "llvm/ADT/APSInt.h"
+#include <tuple>
+
+namespace clang {
+namespace ento {
+
+/// A record of the "type" of an APSInt, used for conversions.
+class APSIntType {
+ uint32_t BitWidth;
+ bool IsUnsigned;
+
+public:
+ APSIntType(uint32_t Width, bool Unsigned)
+ : BitWidth(Width), IsUnsigned(Unsigned) {}
+
+ /* implicit */ APSIntType(const llvm::APSInt &Value)
+ : BitWidth(Value.getBitWidth()), IsUnsigned(Value.isUnsigned()) {}
+
+ uint32_t getBitWidth() const { return BitWidth; }
+ bool isUnsigned() const { return IsUnsigned; }
+
+ /// Convert a given APSInt, in place, to match this type.
+ ///
+ /// This behaves like a C cast: converting 255u8 (0xFF) to s16 gives
+ /// 255 (0x00FF), and converting -1s8 (0xFF) to u16 gives 65535 (0xFFFF).
+ void apply(llvm::APSInt &Value) const {
+ // Note the order here. We extend first to preserve the sign, if this value
+ // is signed, /then/ match the signedness of the result type.
+ Value = Value.extOrTrunc(BitWidth);
+ Value.setIsUnsigned(IsUnsigned);
+ }
+
+ /// Convert and return a new APSInt with the given value, but this
+ /// type's bit width and signedness.
+ ///
+ /// \see apply
+ llvm::APSInt convert(const llvm::APSInt &Value) const LLVM_READONLY {
+ llvm::APSInt Result(Value, Value.isUnsigned());
+ apply(Result);
+ return Result;
+ }
+
+ /// Returns an all-zero value for this type.
+ llvm::APSInt getZeroValue() const LLVM_READONLY {
+ return llvm::APSInt(BitWidth, IsUnsigned);
+ }
+
+ /// Returns the minimum value for this type.
+ llvm::APSInt getMinValue() const LLVM_READONLY {
+ return llvm::APSInt::getMinValue(BitWidth, IsUnsigned);
+ }
+
+ /// Returns the maximum value for this type.
+ llvm::APSInt getMaxValue() const LLVM_READONLY {
+ 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
+ enum RangeTestResultKind {
+ RTR_Below = -1, ///< Value is less than the minimum representable value.
+ RTR_Within = 0, ///< Value is representable using this type.
+ RTR_Above = 1 ///< Value is greater than the maximum representable value.
+ };
+
+ /// Tests whether a given value is losslessly representable using this type.
+ ///
+ /// \param Val The value to test.
+ /// \param AllowMixedSign Whether or not to allow signedness conversions.
+ /// This determines whether -1s8 is considered in range
+ /// for 'unsigned char' (u8).
+ RangeTestResultKind testInRange(const llvm::APSInt &Val,
+ bool AllowMixedSign) const LLVM_READONLY;
+
+ bool operator==(const APSIntType &Other) const {
+ return BitWidth == Other.BitWidth && IsUnsigned == Other.IsUnsigned;
+ }
+
+ /// Provide an ordering for finding a common conversion type.
+ ///
+ /// Unsigned integers are considered to be better conversion types than
+ /// signed integers of the same width.
+ bool operator<(const APSIntType &Other) const {
+ return std::tie(BitWidth, IsUnsigned) <
+ std::tie(Other.BitWidth, Other.IsUnsigned);
+ }
+};
+
+} // end ento namespace
+} // end clang namespace
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
new file mode 100644
index 00000000..b0dda78a
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -0,0 +1,161 @@
+//== AnalysisManager.h - Path sensitive analysis data manager ------*- C++ -*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the AnalysisManager class that manages the data and policy
+// for path sensitive analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H
+
+#include "clang/Analysis/AnalysisDeclContext.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"
+
+namespace clang {
+
+class CodeInjector;
+
+namespace ento {
+ class CheckerManager;
+
+class AnalysisManager : public BugReporterData {
+ virtual void anchor();
+ AnalysisDeclContextManager AnaCtxMgr;
+
+ ASTContext &Ctx;
+ DiagnosticsEngine &Diags;
+ const LangOptions &LangOpts;
+ PathDiagnosticConsumers PathConsumers;
+
+ // Configurable components creators.
+ StoreManagerCreator CreateStoreMgr;
+ ConstraintManagerCreator CreateConstraintMgr;
+
+ CheckerManager *CheckerMgr;
+
+public:
+ AnalyzerOptions &options;
+
+ AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
+ const PathDiagnosticConsumers &Consumers,
+ StoreManagerCreator storemgr,
+ ConstraintManagerCreator constraintmgr,
+ CheckerManager *checkerMgr, AnalyzerOptions &Options,
+ CodeInjector *injector = nullptr);
+
+ ~AnalysisManager() override;
+
+ void ClearContexts() {
+ AnaCtxMgr.clear();
+ }
+
+ AnalysisDeclContextManager& getAnalysisDeclContextManager() {
+ return AnaCtxMgr;
+ }
+
+ StoreManagerCreator getStoreManagerCreator() {
+ return CreateStoreMgr;
+ }
+
+ AnalyzerOptions& getAnalyzerOptions() override {
+ return options;
+ }
+
+ ConstraintManagerCreator getConstraintManagerCreator() {
+ return CreateConstraintMgr;
+ }
+
+ CheckerManager *getCheckerManager() const { return CheckerMgr; }
+
+ ASTContext &getASTContext() override {
+ return Ctx;
+ }
+
+ SourceManager &getSourceManager() override {
+ return getASTContext().getSourceManager();
+ }
+
+ DiagnosticsEngine &getDiagnostic() override {
+ return Diags;
+ }
+
+ const LangOptions &getLangOpts() const {
+ return LangOpts;
+ }
+
+ ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() override {
+ return PathConsumers;
+ }
+
+ void FlushDiagnostics();
+
+ bool shouldVisualize() const {
+ return options.visualizeExplodedGraphWithGraphViz;
+ }
+
+ bool shouldInlineCall() const {
+ return options.getIPAMode() != IPAK_None;
+ }
+
+ CFG *getCFG(Decl const *D) {
+ return AnaCtxMgr.getContext(D)->getCFG();
+ }
+
+ template <typename T>
+ T *getAnalysis(Decl const *D) {
+ return AnaCtxMgr.getContext(D)->getAnalysis<T>();
+ }
+
+ ParentMap &getParentMap(Decl const *D) {
+ return AnaCtxMgr.getContext(D)->getParentMap();
+ }
+
+ AnalysisDeclContext *getAnalysisDeclContext(const Decl *D) {
+ return AnaCtxMgr.getContext(D);
+ }
+
+ static bool isInCodeFile(SourceLocation SL, const SourceManager &SM) {
+ if (SM.isInMainFile(SL))
+ return true;
+
+ // Support the "unified sources" compilation method (eg. WebKit) that
+ // involves producing non-header files that include other non-header files.
+ // We should be included directly from a UnifiedSource* file
+ // and we shouldn't be a header - which is a very safe defensive check.
+ SourceLocation IL = SM.getIncludeLoc(SM.getFileID(SL));
+ if (!IL.isValid() || !SM.isInMainFile(IL))
+ return false;
+ // Should rather be "file name starts with", but the current .getFilename
+ // includes the full path.
+ if (SM.getFilename(IL).contains("UnifiedSource")) {
+ // It might be great to reuse FrontendOptions::getInputKindForExtension()
+ // but for now it doesn't discriminate between code and header files.
+ return llvm::StringSwitch<bool>(SM.getFilename(SL).rsplit('.').second)
+ .Cases("c", "m", "mm", "C", "cc", "cp", true)
+ .Cases("cpp", "CPP", "c++", "cxx", "cppm", true)
+ .Default(false);
+ }
+
+ return false;
+ }
+
+ bool isInCodeFile(SourceLocation SL) {
+ const SourceManager &SM = getASTContext().getSourceManager();
+ return isInCodeFile(SL, SM);
+ }
+};
+
+} // enAnaCtxMgrspace
+
+} // end clang namespace
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
new file mode 100644
index 00000000..ac218bc0
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -0,0 +1,270 @@
+//==- BasicValueFactory.h - Basic values for Path Sens analysis --*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines BasicValueFactory, a class that manages the lifetime
+// of APSInt objects and symbolic constraints used by ExprEngine
+// and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Allocator.h"
+#include <cassert>
+#include <cstdint>
+#include <utility>
+
+namespace clang {
+
+class CXXBaseSpecifier;
+class DeclaratorDecl;
+
+namespace ento {
+
+class CompoundValData : public llvm::FoldingSetNode {
+ QualType T;
+ llvm::ImmutableList<SVal> L;
+
+public:
+ CompoundValData(QualType t, llvm::ImmutableList<SVal> l) : T(t), L(l) {
+ assert(NonLoc::isCompoundType(t));
+ }
+
+ using iterator = llvm::ImmutableList<SVal>::iterator;
+
+ iterator begin() const { return L.begin(); }
+ iterator end() const { return L.end(); }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, QualType T,
+ llvm::ImmutableList<SVal> L);
+
+ void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); }
+};
+
+class LazyCompoundValData : public llvm::FoldingSetNode {
+ StoreRef store;
+ const TypedValueRegion *region;
+
+public:
+ LazyCompoundValData(const StoreRef &st, const TypedValueRegion *r)
+ : store(st), region(r) {
+ assert(NonLoc::isCompoundType(r->getValueType()));
+ }
+
+ const void *getStore() const { return store.getStore(); }
+ const TypedValueRegion *getRegion() const { return region; }
+
+ static void Profile(llvm::FoldingSetNodeID& ID,
+ const StoreRef &store,
+ const TypedValueRegion *region);
+
+ void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); }
+};
+
+class PointerToMemberData : public llvm::FoldingSetNode {
+ const DeclaratorDecl *D;
+ llvm::ImmutableList<const CXXBaseSpecifier *> L;
+
+public:
+ PointerToMemberData(const DeclaratorDecl *D,
+ llvm::ImmutableList<const CXXBaseSpecifier *> L)
+ : D(D), L(L) {}
+
+ using iterator = llvm::ImmutableList<const CXXBaseSpecifier *>::iterator;
+
+ iterator begin() const { return L.begin(); }
+ iterator end() const { return L.end(); }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, const DeclaratorDecl *D,
+ llvm::ImmutableList<const CXXBaseSpecifier *> L);
+
+ void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, D, L); }
+ const DeclaratorDecl *getDeclaratorDecl() const {return D;}
+
+ llvm::ImmutableList<const CXXBaseSpecifier *> getCXXBaseList() const {
+ return L;
+ }
+};
+
+class BasicValueFactory {
+ using APSIntSetTy =
+ llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt>>;
+
+ ASTContext &Ctx;
+ llvm::BumpPtrAllocator& BPAlloc;
+
+ APSIntSetTy APSIntSet;
+ void *PersistentSVals = nullptr;
+ void *PersistentSValPairs = nullptr;
+
+ llvm::ImmutableList<SVal>::Factory SValListFactory;
+ llvm::ImmutableList<const CXXBaseSpecifier *>::Factory CXXBaseListFactory;
+ llvm::FoldingSet<CompoundValData> CompoundValDataSet;
+ llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
+ llvm::FoldingSet<PointerToMemberData> PointerToMemberDataSet;
+
+ // 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), SValListFactory(Alloc),
+ CXXBaseListFactory(Alloc) {}
+
+ ~BasicValueFactory();
+
+ ASTContext &getContext() const { return Ctx; }
+
+ 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, QualType T);
+
+ /// Returns the type of the APSInt used to store values of the given QualType.
+ APSIntType getAPSIntType(QualType T) const {
+ assert(T->isIntegralOrEnumerationType() || Loc::isLocType(T));
+ return APSIntType(Ctx.getIntWidth(T),
+ !T->isSignedIntegerOrEnumerationType());
+ }
+
+ /// Convert - Create a new persistent APSInt with the same value as 'From'
+ /// but with the bitwidth and signedness of 'To'.
+ const llvm::APSInt &Convert(const llvm::APSInt& To,
+ const llvm::APSInt& From) {
+ APSIntType TargetType(To);
+ if (TargetType == APSIntType(From))
+ return From;
+
+ return getValue(TargetType.convert(From));
+ }
+
+ const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) {
+ APSIntType TargetType = getAPSIntType(T);
+ if (TargetType == APSIntType(From))
+ return From;
+
+ return getValue(TargetType.convert(From));
+ }
+
+ const llvm::APSInt &getIntValue(uint64_t X, bool isUnsigned) {
+ QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy;
+ return getValue(X, T);
+ }
+
+ const llvm::APSInt &getMaxValue(const llvm::APSInt &v) {
+ return getValue(APSIntType(v).getMaxValue());
+ }
+
+ const llvm::APSInt &getMinValue(const llvm::APSInt &v) {
+ return getValue(APSIntType(v).getMinValue());
+ }
+
+ const llvm::APSInt &getMaxValue(QualType T) {
+ return getValue(getAPSIntType(T).getMaxValue());
+ }
+
+ const llvm::APSInt &getMinValue(QualType T) {
+ return getValue(getAPSIntType(T).getMinValue());
+ }
+
+ const llvm::APSInt &Add1(const llvm::APSInt &V) {
+ llvm::APSInt X = V;
+ ++X;
+ return getValue(X);
+ }
+
+ const llvm::APSInt &Sub1(const llvm::APSInt &V) {
+ llvm::APSInt X = V;
+ --X;
+ return getValue(X);
+ }
+
+ const llvm::APSInt &getZeroWithTypeSize(QualType T) {
+ assert(T->isScalarType());
+ return getValue(0, Ctx.getTypeSize(T), true);
+ }
+
+ const llvm::APSInt &getZeroWithPtrWidth(bool isUnsigned = true) {
+ return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
+ }
+
+ const llvm::APSInt &getIntWithPtrWidth(uint64_t X, bool isUnsigned) {
+ return getValue(X, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
+ }
+
+ const llvm::APSInt &getTruthValue(bool b, QualType T) {
+ return getValue(b ? 1 : 0, Ctx.getIntWidth(T),
+ T->isUnsignedIntegerOrEnumerationType());
+ }
+
+ const llvm::APSInt &getTruthValue(bool b) {
+ return getTruthValue(b, Ctx.getLogicalOperationType());
+ }
+
+ const CompoundValData *getCompoundValData(QualType T,
+ llvm::ImmutableList<SVal> Vals);
+
+ const LazyCompoundValData *getLazyCompoundValData(const StoreRef &store,
+ const TypedValueRegion *region);
+
+ const PointerToMemberData *getPointerToMemberData(
+ const DeclaratorDecl *DD,
+ llvm::ImmutableList<const CXXBaseSpecifier *> L);
+
+ llvm::ImmutableList<SVal> getEmptySValList() {
+ return SValListFactory.getEmptyList();
+ }
+
+ llvm::ImmutableList<SVal> prependSVal(SVal X, llvm::ImmutableList<SVal> L) {
+ return SValListFactory.add(X, L);
+ }
+
+ llvm::ImmutableList<const CXXBaseSpecifier *> getEmptyCXXBaseList() {
+ return CXXBaseListFactory.getEmptyList();
+ }
+
+ llvm::ImmutableList<const CXXBaseSpecifier *> prependCXXBase(
+ const CXXBaseSpecifier *CBS,
+ llvm::ImmutableList<const CXXBaseSpecifier *> L) {
+ return CXXBaseListFactory.add(CBS, L);
+ }
+
+ const PointerToMemberData *accumCXXBase(
+ llvm::iterator_range<CastExpr::path_const_iterator> PathRange,
+ const nonloc::PointerToMember &PTM);
+
+ const llvm::APSInt* evalAPSInt(BinaryOperator::Opcode Op,
+ const llvm::APSInt& V1,
+ const llvm::APSInt& V2);
+
+ const std::pair<SVal, uintptr_t>&
+ getPersistentSValWithData(const SVal& V, uintptr_t Data);
+
+ const std::pair<SVal, SVal>&
+ getPersistentSValPair(const SVal& V1, const SVal& V2);
+
+ const SVal* getPersistentSVal(SVal X);
+};
+
+} // namespace ento
+
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
new file mode 100644
index 00000000..46ff69e0
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
@@ -0,0 +1,59 @@
+//==- BlockCounter.h - ADT for counting block visits ---------------*- C++ -*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines BlockCounter, an abstract data type used to count
+// the number of times a given block has been visited along a path
+// analyzed by CoreEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BLOCKCOUNTER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BLOCKCOUNTER_H
+
+#include "llvm/Support/Allocator.h"
+
+namespace clang {
+
+class StackFrameContext;
+
+namespace ento {
+
+/// \class BlockCounter
+/// An abstract data type used to count the number of times a given
+/// block has been visited along a path analyzed by CoreEngine.
+class BlockCounter {
+ void *Data;
+
+ BlockCounter(void *D) : Data(D) {}
+
+public:
+ BlockCounter() : Data(nullptr) {}
+
+ unsigned getNumVisited(const StackFrameContext *CallSite,
+ unsigned BlockID) const;
+
+ class Factory {
+ void *F;
+ public:
+ Factory(llvm::BumpPtrAllocator& Alloc);
+ ~Factory();
+
+ BlockCounter GetEmptyCounter();
+ BlockCounter IncrementCount(BlockCounter BC,
+ const StackFrameContext *CallSite,
+ unsigned BlockID);
+ };
+
+ friend class Factory;
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
new file mode 100644
index 00000000..19996cf9
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -0,0 +1,1229 @@
+//===- CallEvent.h - Wrapper for all function and method calls --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file This file defines CallEvent and its subclasses, which represent path-
+/// sensitive instances of different kinds of function and method calls
+/// (C, C++, and Objective-C).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLEVENT_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLEVENT_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cassert>
+#include <limits>
+#include <utility>
+
+namespace clang {
+
+class LocationContext;
+class ProgramPoint;
+class ProgramPointTag;
+class StackFrameContext;
+
+namespace ento {
+
+enum CallEventKind {
+ CE_Function,
+ CE_CXXMember,
+ CE_CXXMemberOperator,
+ CE_CXXDestructor,
+ CE_BEG_CXX_INSTANCE_CALLS = CE_CXXMember,
+ CE_END_CXX_INSTANCE_CALLS = CE_CXXDestructor,
+ CE_CXXConstructor,
+ CE_CXXAllocator,
+ CE_BEG_FUNCTION_CALLS = CE_Function,
+ CE_END_FUNCTION_CALLS = CE_CXXAllocator,
+ CE_Block,
+ CE_ObjCMessage
+};
+
+class CallEvent;
+
+/// This class represents a description of a function call using the number of
+/// arguments and the name of the function.
+class CallDescription {
+ friend CallEvent;
+
+ mutable IdentifierInfo *II = nullptr;
+ mutable bool IsLookupDone = false;
+ // The list of the qualified names used to identify the specified CallEvent,
+ // e.g. "{a, b}" represent the qualified names, like "a::b".
+ std::vector<const char *> QualifiedName;
+ unsigned RequiredArgs;
+
+public:
+ const static unsigned NoArgRequirement = std::numeric_limits<unsigned>::max();
+
+ /// Constructs a CallDescription object.
+ ///
+ /// @param QualifiedName The list of the name qualifiers of the function that
+ /// will be matched. The user is allowed to skip any of the qualifiers.
+ /// For example, {"std", "basic_string", "c_str"} would match both
+ /// std::basic_string<...>::c_str() and std::__1::basic_string<...>::c_str().
+ ///
+ /// @param RequiredArgs The number of arguments that is expected to match a
+ /// call. Omit this parameter to match every occurrence of call with a given
+ /// name regardless the number of arguments.
+ CallDescription(ArrayRef<const char *> QualifiedName,
+ unsigned RequiredArgs = NoArgRequirement)
+ : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs) {}
+
+ /// Get the name of the function that this object matches.
+ StringRef getFunctionName() const { return QualifiedName.back(); }
+};
+
+template<typename T = CallEvent>
+class CallEventRef : public IntrusiveRefCntPtr<const T> {
+public:
+ CallEventRef(const T *Call) : IntrusiveRefCntPtr<const T>(Call) {}
+ CallEventRef(const CallEventRef &Orig) : IntrusiveRefCntPtr<const T>(Orig) {}
+
+ CallEventRef<T> cloneWithState(ProgramStateRef State) const {
+ return this->get()->template cloneWithState<T>(State);
+ }
+
+ // Allow implicit conversions to a superclass type, since CallEventRef
+ // behaves like a pointer-to-const.
+ template <typename SuperT>
+ operator CallEventRef<SuperT> () const {
+ return this->get();
+ }
+};
+
+/// \class RuntimeDefinition
+/// 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 could be called at runtime.
+ /// NULL if not available.
+ const Decl *D = nullptr;
+
+ /// 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. NULL when the DynamicTypeInfo is
+ /// precise.
+ const MemRegion *R = nullptr;
+
+public:
+ RuntimeDefinition() = default;
+ RuntimeDefinition(const Decl *InD): D(InD) {}
+ RuntimeDefinition(const Decl *InD, const MemRegion *InR): D(InD), R(InR) {}
+
+ const Decl *getDecl() { return D; }
+
+ /// 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 != nullptr; }
+
+ /// When other definitions are possible, returns the region whose runtime type
+ /// determines the method definition.
+ const MemRegion *getDispatchRegion() { return R; }
+};
+
+/// Represents an abstract call to a function or method along a
+/// particular path.
+///
+/// CallEvents are created through the factory methods of CallEventManager.
+///
+/// CallEvents should always be cheap to create and destroy. In order for
+/// CallEventManager to be able to re-use CallEvent-sized memory blocks,
+/// subclasses of CallEvent may not add any data members to the base class.
+/// Use the "Data" and "Location" fields instead.
+class CallEvent {
+public:
+ using Kind = CallEventKind;
+
+private:
+ ProgramStateRef State;
+ const LocationContext *LCtx;
+ llvm::PointerUnion<const Expr *, const Decl *> Origin;
+
+protected:
+ // This is user data for subclasses.
+ const void *Data;
+
+ // This is user data for subclasses.
+ // This should come right before RefCount, so that the two fields can be
+ // packed together on LP64 platforms.
+ SourceLocation Location;
+
+private:
+ template <typename T> friend struct llvm::IntrusiveRefCntPtrInfo;
+
+ mutable unsigned RefCount = 0;
+
+ void Retain() const { ++RefCount; }
+ void Release() const;
+
+protected:
+ friend class CallEventManager;
+
+ CallEvent(const Expr *E, ProgramStateRef state, const LocationContext *lctx)
+ : State(std::move(state)), LCtx(lctx), Origin(E) {}
+
+ CallEvent(const Decl *D, ProgramStateRef state, const LocationContext *lctx)
+ : State(std::move(state)), LCtx(lctx), Origin(D) {}
+
+ // DO NOT MAKE PUBLIC
+ CallEvent(const CallEvent &Original)
+ : State(Original.State), LCtx(Original.LCtx), Origin(Original.Origin),
+ Data(Original.Data), Location(Original.Location) {}
+
+ /// Copies this CallEvent, with vtable intact, into a new block of memory.
+ virtual void cloneTo(void *Dest) const = 0;
+
+ /// Get the value of arbitrary expressions at this point in the path.
+ SVal getSVal(const Stmt *S) const {
+ return getState()->getSVal(S, getLocationContext());
+ }
+
+ using ValueList = SmallVectorImpl<SVal>;
+
+ /// Used to specify non-argument regions that will be invalidated as a
+ /// result of this call.
+ virtual void getExtraInvalidatedValues(ValueList &Values,
+ RegionAndSymbolInvalidationTraits *ETraits) const {}
+
+public:
+ CallEvent &operator=(const CallEvent &) = delete;
+ virtual ~CallEvent() = default;
+
+ /// Returns the kind of call this is.
+ virtual Kind getKind() const = 0;
+
+ /// Returns the declaration of the function or method that will be
+ /// called. May be null.
+ virtual const Decl *getDecl() const {
+ return Origin.dyn_cast<const Decl *>();
+ }
+
+ /// The state in which the call is being evaluated.
+ const ProgramStateRef &getState() const {
+ return State;
+ }
+
+ /// The context in which the call is being evaluated.
+ const LocationContext *getLocationContext() const {
+ return LCtx;
+ }
+
+ /// Returns the definition of the function or method that will be
+ /// called.
+ virtual RuntimeDefinition getRuntimeDefinition() const = 0;
+
+ /// Returns the expression whose value will be the result of this call.
+ /// May be null.
+ const Expr *getOriginExpr() const {
+ return Origin.dyn_cast<const Expr *>();
+ }
+
+ /// Returns the number of arguments (explicit and implicit).
+ ///
+ /// Note that this may be greater than the number of parameters in the
+ /// callee's declaration, and that it may include arguments not written in
+ /// the source.
+ virtual unsigned getNumArgs() const = 0;
+
+ /// Returns true if the callee is known to be from a system header.
+ bool isInSystemHeader() const {
+ const Decl *D = getDecl();
+ if (!D)
+ return false;
+
+ SourceLocation Loc = D->getLocation();
+ if (Loc.isValid()) {
+ const SourceManager &SM =
+ getState()->getStateManager().getContext().getSourceManager();
+ return SM.isInSystemHeader(D->getLocation());
+ }
+
+ // Special case for implicitly-declared global operator new/delete.
+ // These should be considered system functions.
+ if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ return FD->isOverloadedOperator() && FD->isImplicit() && FD->isGlobal();
+
+ return false;
+ }
+
+ /// Returns true if the CallEvent is a call to a function that matches
+ /// the CallDescription.
+ ///
+ /// Note that this function is not intended to be used to match Obj-C method
+ /// calls.
+ bool isCalled(const CallDescription &CD) const;
+
+ /// Returns a source range for the entire call, suitable for
+ /// outputting in diagnostics.
+ virtual SourceRange getSourceRange() const {
+ return getOriginExpr()->getSourceRange();
+ }
+
+ /// Returns the value of a given argument at the time of the call.
+ virtual SVal getArgSVal(unsigned Index) const;
+
+ /// Returns the expression associated with a given argument.
+ /// May be null if this expression does not appear in the source.
+ virtual const Expr *getArgExpr(unsigned Index) const { return nullptr; }
+
+ /// Returns the source range for errors associated with this argument.
+ ///
+ /// May be invalid if the argument is not written in the source.
+ virtual SourceRange getArgSourceRange(unsigned Index) const;
+
+ /// Returns the result type, adjusted for references.
+ QualType getResultType() const;
+
+ /// 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;
+
+ /// Returns true if the type of any of the non-null arguments satisfies
+ /// the condition.
+ bool hasNonNullArgumentsWithType(bool (*Condition)(QualType)) const;
+
+ /// Returns true if any of the arguments appear to represent callbacks.
+ bool hasNonZeroCallbackArg() const;
+
+ /// Returns true if any of the arguments is void*.
+ bool hasVoidPointerToNonConstArg() const;
+
+ /// 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!
+ // We don't really want a list of hardcoded exceptions in the long run,
+ // but we don't want duplicated lists of known APIs in the short term either.
+ virtual bool argumentsMayEscape() const {
+ return hasNonZeroCallbackArg();
+ }
+
+ /// 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;
+
+ /// 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 auto *ND = dyn_cast_or_null<NamedDecl>(getDecl());
+ if (!ND)
+ return nullptr;
+ return ND->getIdentifier();
+ }
+
+ /// Returns an appropriate ProgramPoint for this call.
+ ProgramPoint getProgramPoint(bool IsPreVisit = false,
+ const ProgramPointTag *Tag = nullptr) const;
+
+ /// Returns a new state with all argument regions invalidated.
+ ///
+ /// This accepts an alternate state in case some processing has already
+ /// occurred.
+ ProgramStateRef invalidateRegions(unsigned BlockCount,
+ ProgramStateRef Orig = nullptr) const;
+
+ using FrameBindingTy = std::pair<Loc, SVal>;
+ using BindingsTy = SmallVectorImpl<FrameBindingTy>;
+
+ /// Populates the given SmallVector with the bindings in the callee's stack
+ /// frame at the start of this call.
+ virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const = 0;
+
+ /// Returns a copy of this CallEvent, but using the given state.
+ template <typename T>
+ CallEventRef<T> cloneWithState(ProgramStateRef NewState) const;
+
+ /// Returns a copy of this CallEvent, but using the given state.
+ CallEventRef<> cloneWithState(ProgramStateRef NewState) const {
+ return cloneWithState<CallEvent>(NewState);
+ }
+
+ /// Returns true if this is a statement is a function or method call
+ /// of some kind.
+ static bool isCallStmt(const Stmt *S);
+
+ /// Returns the result type of a function or method declaration.
+ ///
+ /// This will return a null QualType if the result type cannot be determined.
+ static QualType getDeclaredResultType(const Decl *D);
+
+ /// Returns true if the given decl is known to be variadic.
+ ///
+ /// \p D must not be null.
+ static bool isVariadic(const Decl *D);
+
+ /// Returns AnalysisDeclContext for the callee stack frame.
+ /// Currently may fail; returns null on failure.
+ AnalysisDeclContext *getCalleeAnalysisDeclContext() const;
+
+ /// Returns the callee stack frame. That stack frame will only be entered
+ /// during analysis if the call is inlined, but it may still be useful
+ /// in intermediate calculations even if the call isn't inlined.
+ /// May fail; returns null on failure.
+ const StackFrameContext *getCalleeStackFrame() const;
+
+ /// Returns memory location for a parameter variable within the callee stack
+ /// frame. May fail; returns null on failure.
+ const VarRegion *getParameterLocation(unsigned Index) const;
+
+ /// Returns true if on the current path, the argument was constructed by
+ /// calling a C++ constructor over it. This is an internal detail of the
+ /// analysis which doesn't necessarily represent the program semantics:
+ /// if we are supposed to construct an argument directly, we may still
+ /// not do that because we don't know how (i.e., construction context is
+ /// unavailable in the CFG or not supported by the analyzer).
+ bool isArgumentConstructedDirectly(unsigned Index) const {
+ // This assumes that the object was not yet removed from the state.
+ return ExprEngine::getObjectUnderConstruction(
+ getState(), {getOriginExpr(), Index}, getLocationContext()).hasValue();
+ }
+
+ /// Some calls have parameter numbering mismatched from argument numbering.
+ /// This function converts an argument index to the corresponding
+ /// parameter index. Returns None is the argument doesn't correspond
+ /// to any parameter variable.
+ virtual Optional<unsigned>
+ getAdjustedParameterIndex(unsigned ASTArgumentIndex) const {
+ return ASTArgumentIndex;
+ }
+
+ /// Some call event sub-classes conveniently adjust mismatching AST indices
+ /// to match parameter indices. This function converts an argument index
+ /// as understood by CallEvent to the argument index as understood by the AST.
+ virtual unsigned getASTArgumentIndex(unsigned CallArgumentIndex) const {
+ return CallArgumentIndex;
+ }
+
+ // Iterator access to formal parameters and their types.
+private:
+ struct GetTypeFn {
+ QualType operator()(ParmVarDecl *PD) const { return PD->getType(); }
+ };
+
+public:
+ /// Return call's formal parameters.
+ ///
+ /// Remember that the number of formal parameters may not match the number
+ /// of arguments for all calls. However, the first parameter will always
+ /// correspond with the argument value returned by \c getArgSVal(0).
+ virtual ArrayRef<ParmVarDecl *> parameters() const = 0;
+
+ using param_type_iterator =
+ llvm::mapped_iterator<ArrayRef<ParmVarDecl *>::iterator, GetTypeFn>;
+
+ /// Returns an iterator over the types of the call's formal parameters.
+ ///
+ /// This uses the callee decl found by default name lookup rather than the
+ /// definition because it represents a public interface, and probably has
+ /// more annotations.
+ param_type_iterator param_type_begin() const {
+ return llvm::map_iterator(parameters().begin(), GetTypeFn());
+ }
+ /// \sa param_type_begin()
+ param_type_iterator param_type_end() const {
+ return llvm::map_iterator(parameters().end(), GetTypeFn());
+ }
+
+ // For debugging purposes only
+ void dump(raw_ostream &Out) const;
+ void dump() const;
+};
+
+/// Represents a call to any sort of function that might have a
+/// FunctionDecl.
+class AnyFunctionCall : public CallEvent {
+protected:
+ AnyFunctionCall(const Expr *E, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CallEvent(E, St, LCtx) {}
+ AnyFunctionCall(const Decl *D, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CallEvent(D, St, LCtx) {}
+ AnyFunctionCall(const AnyFunctionCall &Other) = default;
+
+public:
+ // This function is overridden by subclasses, but they must return
+ // a FunctionDecl.
+ const FunctionDecl *getDecl() const override {
+ return cast<FunctionDecl>(CallEvent::getDecl());
+ }
+
+ RuntimeDefinition getRuntimeDefinition() const override;
+
+ bool argumentsMayEscape() const override;
+
+ void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const override;
+
+ ArrayRef<ParmVarDecl *> parameters() const override;
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() >= CE_BEG_FUNCTION_CALLS &&
+ CA->getKind() <= CE_END_FUNCTION_CALLS;
+ }
+};
+
+/// Represents a C function or static C++ member function call.
+///
+/// Example: \c fun()
+class SimpleFunctionCall : public AnyFunctionCall {
+ friend class CallEventManager;
+
+protected:
+ SimpleFunctionCall(const CallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : AnyFunctionCall(CE, St, LCtx) {}
+ SimpleFunctionCall(const SimpleFunctionCall &Other) = default;
+
+ void cloneTo(void *Dest) const override {
+ new (Dest) SimpleFunctionCall(*this);
+ }
+
+public:
+ virtual const CallExpr *getOriginExpr() const {
+ return cast<CallExpr>(AnyFunctionCall::getOriginExpr());
+ }
+
+ const FunctionDecl *getDecl() const override;
+
+ unsigned getNumArgs() const override { return getOriginExpr()->getNumArgs(); }
+
+ const Expr *getArgExpr(unsigned Index) const override {
+ return getOriginExpr()->getArg(Index);
+ }
+
+ Kind getKind() const override { return CE_Function; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_Function;
+ }
+};
+
+/// Represents a call to a block.
+///
+/// Example: <tt>^{ /* ... */ }()</tt>
+class BlockCall : public CallEvent {
+ friend class CallEventManager;
+
+protected:
+ BlockCall(const CallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CallEvent(CE, St, LCtx) {}
+ BlockCall(const BlockCall &Other) = default;
+
+ void cloneTo(void *Dest) const override { new (Dest) BlockCall(*this); }
+
+ void getExtraInvalidatedValues(ValueList &Values,
+ RegionAndSymbolInvalidationTraits *ETraits) const override;
+
+public:
+ virtual const CallExpr *getOriginExpr() const {
+ return cast<CallExpr>(CallEvent::getOriginExpr());
+ }
+
+ unsigned getNumArgs() const override { return getOriginExpr()->getNumArgs(); }
+
+ const Expr *getArgExpr(unsigned Index) const override {
+ return getOriginExpr()->getArg(Index);
+ }
+
+ /// Returns the region associated with this instance of the block.
+ ///
+ /// This may be NULL if the block's origin is unknown.
+ const BlockDataRegion *getBlockRegion() const;
+
+ const BlockDecl *getDecl() const override {
+ const BlockDataRegion *BR = getBlockRegion();
+ if (!BR)
+ return nullptr;
+ return BR->getDecl();
+ }
+
+ bool isConversionFromLambda() const {
+ const BlockDecl *BD = getDecl();
+ if (!BD)
+ return false;
+
+ return BD->isConversionFromLambda();
+ }
+
+ /// 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 {
+ 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 {
+ return true;
+ }
+
+ void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const override;
+
+ ArrayRef<ParmVarDecl*> parameters() const override;
+
+ Kind getKind() const override { return CE_Block; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_Block;
+ }
+};
+
+/// Represents a non-static C++ member function call, no matter how
+/// it is written.
+class CXXInstanceCall : public AnyFunctionCall {
+protected:
+ CXXInstanceCall(const CallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : AnyFunctionCall(CE, St, LCtx) {}
+ CXXInstanceCall(const FunctionDecl *D, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : AnyFunctionCall(D, St, LCtx) {}
+ CXXInstanceCall(const CXXInstanceCall &Other) = default;
+
+ void getExtraInvalidatedValues(ValueList &Values,
+ RegionAndSymbolInvalidationTraits *ETraits) const override;
+
+public:
+ /// Returns the expression representing the implicit 'this' object.
+ virtual const Expr *getCXXThisExpr() const { return nullptr; }
+
+ /// Returns the value of the implicit 'this' object.
+ virtual SVal getCXXThisVal() const;
+
+ const FunctionDecl *getDecl() const override;
+
+ RuntimeDefinition getRuntimeDefinition() const override;
+
+ void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const override;
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() >= CE_BEG_CXX_INSTANCE_CALLS &&
+ CA->getKind() <= CE_END_CXX_INSTANCE_CALLS;
+ }
+};
+
+/// Represents a non-static C++ member function call.
+///
+/// Example: \c obj.fun()
+class CXXMemberCall : public CXXInstanceCall {
+ friend class CallEventManager;
+
+protected:
+ CXXMemberCall(const CXXMemberCallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CXXInstanceCall(CE, St, LCtx) {}
+ CXXMemberCall(const CXXMemberCall &Other) = default;
+
+ void cloneTo(void *Dest) const override { new (Dest) CXXMemberCall(*this); }
+
+public:
+ virtual const CXXMemberCallExpr *getOriginExpr() const {
+ return cast<CXXMemberCallExpr>(CXXInstanceCall::getOriginExpr());
+ }
+
+ unsigned getNumArgs() const override {
+ if (const CallExpr *CE = getOriginExpr())
+ return CE->getNumArgs();
+ return 0;
+ }
+
+ const Expr *getArgExpr(unsigned Index) const override {
+ return getOriginExpr()->getArg(Index);
+ }
+
+ const Expr *getCXXThisExpr() const override;
+
+ RuntimeDefinition getRuntimeDefinition() const override;
+
+ Kind getKind() const override { return CE_CXXMember; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_CXXMember;
+ }
+};
+
+/// Represents a C++ overloaded operator call where the operator is
+/// implemented as a non-static member function.
+///
+/// Example: <tt>iter + 1</tt>
+class CXXMemberOperatorCall : public CXXInstanceCall {
+ friend class CallEventManager;
+
+protected:
+ CXXMemberOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CXXInstanceCall(CE, St, LCtx) {}
+ CXXMemberOperatorCall(const CXXMemberOperatorCall &Other) = default;
+
+ void cloneTo(void *Dest) const override {
+ new (Dest) CXXMemberOperatorCall(*this);
+ }
+
+public:
+ virtual const CXXOperatorCallExpr *getOriginExpr() const {
+ return cast<CXXOperatorCallExpr>(CXXInstanceCall::getOriginExpr());
+ }
+
+ unsigned getNumArgs() const override {
+ return getOriginExpr()->getNumArgs() - 1;
+ }
+
+ const Expr *getArgExpr(unsigned Index) const override {
+ return getOriginExpr()->getArg(Index + 1);
+ }
+
+ const Expr *getCXXThisExpr() const override;
+
+ Kind getKind() const override { return CE_CXXMemberOperator; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_CXXMemberOperator;
+ }
+
+ Optional<unsigned>
+ getAdjustedParameterIndex(unsigned ASTArgumentIndex) const override {
+ // For member operator calls argument 0 on the expression corresponds
+ // to implicit this-parameter on the declaration.
+ return (ASTArgumentIndex > 0) ? Optional<unsigned>(ASTArgumentIndex - 1)
+ : None;
+ }
+
+ unsigned getASTArgumentIndex(unsigned CallArgumentIndex) const override {
+ // For member operator calls argument 0 on the expression corresponds
+ // to implicit this-parameter on the declaration.
+ return CallArgumentIndex + 1;
+ }
+};
+
+/// Represents an implicit call to a C++ destructor.
+///
+/// This can occur at the end of a scope (for automatic objects), at the end
+/// of a full-expression (for temporaries), or as part of a delete.
+class CXXDestructorCall : public CXXInstanceCall {
+ friend class CallEventManager;
+
+protected:
+ using DtorDataTy = llvm::PointerIntPair<const MemRegion *, 1, bool>;
+
+ /// Creates an implicit destructor.
+ ///
+ /// \param DD The destructor that will be called.
+ /// \param Trigger The statement whose completion causes this destructor call.
+ /// \param Target The object region to be destructed.
+ /// \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, bool IsBaseDestructor,
+ ProgramStateRef St, const LocationContext *LCtx)
+ : CXXInstanceCall(DD, St, LCtx) {
+ Data = DtorDataTy(Target, IsBaseDestructor).getOpaqueValue();
+ Location = Trigger->getEndLoc();
+ }
+
+ CXXDestructorCall(const CXXDestructorCall &Other) = default;
+
+ void cloneTo(void *Dest) const override {new (Dest) CXXDestructorCall(*this);}
+
+public:
+ SourceRange getSourceRange() const override { return Location; }
+ unsigned getNumArgs() const override { return 0; }
+
+ RuntimeDefinition getRuntimeDefinition() const override;
+
+ /// Returns the value of the implicit 'this' object.
+ SVal getCXXThisVal() const override;
+
+ /// Returns true if this is a call to a base class destructor.
+ bool isBaseDestructor() const {
+ return DtorDataTy::getFromOpaqueValue(Data).getInt();
+ }
+
+ Kind getKind() const override { return CE_CXXDestructor; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_CXXDestructor;
+ }
+};
+
+/// Represents a call to a C++ constructor.
+///
+/// Example: \c T(1)
+class CXXConstructorCall : public AnyFunctionCall {
+ friend class CallEventManager;
+
+protected:
+ /// Creates a constructor call.
+ ///
+ /// \param CE The constructor expression as written in the source.
+ /// \param Target The region where the object should be constructed. If NULL,
+ /// 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,
+ ProgramStateRef St, const LocationContext *LCtx)
+ : AnyFunctionCall(CE, St, LCtx) {
+ Data = Target;
+ }
+
+ CXXConstructorCall(const CXXConstructorCall &Other) = default;
+
+ void cloneTo(void *Dest) const override { new (Dest) CXXConstructorCall(*this); }
+
+ void getExtraInvalidatedValues(ValueList &Values,
+ RegionAndSymbolInvalidationTraits *ETraits) const override;
+
+public:
+ virtual const CXXConstructExpr *getOriginExpr() const {
+ return cast<CXXConstructExpr>(AnyFunctionCall::getOriginExpr());
+ }
+
+ const CXXConstructorDecl *getDecl() const override {
+ return getOriginExpr()->getConstructor();
+ }
+
+ unsigned getNumArgs() const override { return getOriginExpr()->getNumArgs(); }
+
+ const Expr *getArgExpr(unsigned Index) const override {
+ return getOriginExpr()->getArg(Index);
+ }
+
+ /// Returns the value of the implicit 'this' object.
+ SVal getCXXThisVal() const;
+
+ void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const override;
+
+ Kind getKind() const override { return CE_CXXConstructor; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_CXXConstructor;
+ }
+};
+
+/// Represents the memory allocation call in a C++ new-expression.
+///
+/// This is a call to "operator new".
+class CXXAllocatorCall : public AnyFunctionCall {
+ friend class CallEventManager;
+
+protected:
+ CXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : AnyFunctionCall(E, St, LCtx) {}
+ CXXAllocatorCall(const CXXAllocatorCall &Other) = default;
+
+ void cloneTo(void *Dest) const override { new (Dest) CXXAllocatorCall(*this); }
+
+public:
+ virtual const CXXNewExpr *getOriginExpr() const {
+ return cast<CXXNewExpr>(AnyFunctionCall::getOriginExpr());
+ }
+
+ const FunctionDecl *getDecl() const override {
+ return getOriginExpr()->getOperatorNew();
+ }
+
+ /// Number of non-placement arguments to the call. It is equal to 2 for
+ /// C++17 aligned operator new() calls that have alignment implicitly
+ /// passed as the second argument, and to 1 for other operator new() calls.
+ unsigned getNumImplicitArgs() const {
+ return getOriginExpr()->passAlignment() ? 2 : 1;
+ }
+
+ unsigned getNumArgs() const override {
+ return getOriginExpr()->getNumPlacementArgs() + getNumImplicitArgs();
+ }
+
+ const Expr *getArgExpr(unsigned Index) const override {
+ // The first argument of an allocator call is the size of the allocation.
+ if (Index < getNumImplicitArgs())
+ return nullptr;
+ return getOriginExpr()->getPlacementArg(Index - getNumImplicitArgs());
+ }
+
+ /// Number of placement arguments to the operator new() call. For example,
+ /// standard std::nothrow operator new and standard placement new both have
+ /// 1 implicit argument (size) and 1 placement argument, while regular
+ /// operator new() has 1 implicit argument and 0 placement arguments.
+ const Expr *getPlacementArgExpr(unsigned Index) const {
+ return getOriginExpr()->getPlacementArg(Index);
+ }
+
+ Kind getKind() const override { return CE_CXXAllocator; }
+
+ static bool classof(const CallEvent *CE) {
+ return CE->getKind() == CE_CXXAllocator;
+ }
+};
+
+/// Represents the ways an Objective-C message send can occur.
+//
+// Note to maintainers: OCM_Message should always be last, since it does not
+// need to fit in the Data field's low bits.
+enum ObjCMessageKind {
+ OCM_PropertyAccess,
+ OCM_Subscript,
+ OCM_Message
+};
+
+/// Represents any expression that calls an Objective-C method.
+///
+/// This includes all of the kinds listed in ObjCMessageKind.
+class ObjCMethodCall : public CallEvent {
+ friend class CallEventManager;
+
+ const PseudoObjectExpr *getContainingPseudoObjectExpr() const;
+
+protected:
+ ObjCMethodCall(const ObjCMessageExpr *Msg, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CallEvent(Msg, St, LCtx) {
+ Data = nullptr;
+ }
+
+ ObjCMethodCall(const ObjCMethodCall &Other) = default;
+
+ void cloneTo(void *Dest) const override { new (Dest) ObjCMethodCall(*this); }
+
+ void getExtraInvalidatedValues(ValueList &Values,
+ RegionAndSymbolInvalidationTraits *ETraits) const override;
+
+ /// Check if the selector may have multiple definitions (may have overrides).
+ virtual bool canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
+ Selector Sel) const;
+
+public:
+ virtual const ObjCMessageExpr *getOriginExpr() const {
+ return cast<ObjCMessageExpr>(CallEvent::getOriginExpr());
+ }
+
+ const ObjCMethodDecl *getDecl() const override {
+ return getOriginExpr()->getMethodDecl();
+ }
+
+ unsigned getNumArgs() const override {
+ return getOriginExpr()->getNumArgs();
+ }
+
+ const Expr *getArgExpr(unsigned Index) const override {
+ return getOriginExpr()->getArg(Index);
+ }
+
+ bool isInstanceMessage() const {
+ return getOriginExpr()->isInstanceMessage();
+ }
+
+ ObjCMethodFamily getMethodFamily() const {
+ return getOriginExpr()->getMethodFamily();
+ }
+
+ Selector getSelector() const {
+ return getOriginExpr()->getSelector();
+ }
+
+ SourceRange getSourceRange() const override;
+
+ /// Returns the value of the receiver at the time of this call.
+ SVal getReceiverSVal() const;
+
+ /// Return the value of 'self' if available.
+ SVal getSelfSVal() const;
+
+ /// Get the interface for the receiver.
+ ///
+ /// This works whether this is an instance message or a class message.
+ /// However, it currently just uses the static type of the receiver.
+ const ObjCInterfaceDecl *getReceiverInterface() const {
+ return getOriginExpr()->getReceiverInterface();
+ }
+
+ /// 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;
+
+ /// Returns true if this property access or subscript is a setter (has the
+ /// form of an assignment).
+ bool isSetter() const {
+ switch (getMessageKind()) {
+ case OCM_Message:
+ llvm_unreachable("This is not a pseudo-object access!");
+ case OCM_PropertyAccess:
+ return getNumArgs() > 0;
+ case OCM_Subscript:
+ return getNumArgs() > 1;
+ }
+ llvm_unreachable("Unknown message kind");
+ }
+
+ // Returns the property accessed by this method, either explicitly via
+ // property syntax or implicitly via a getter or setter method. Returns
+ // nullptr if the call is not a prooperty access.
+ const ObjCPropertyDecl *getAccessedProperty() const;
+
+ RuntimeDefinition getRuntimeDefinition() const override;
+
+ bool argumentsMayEscape() const override;
+
+ void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const override;
+
+ ArrayRef<ParmVarDecl*> parameters() const override;
+
+ Kind getKind() const override { return CE_ObjCMessage; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_ObjCMessage;
+ }
+};
+
+/// Manages the lifetime of CallEvent objects.
+///
+/// CallEventManager provides a way to create arbitrary CallEvents "on the
+/// stack" as if they were value objects by keeping a cache of CallEvent-sized
+/// memory blocks. The CallEvents created by CallEventManager are only valid
+/// for the lifetime of the OwnedCallEvent that holds them; right now these
+/// objects cannot be copied and ownership cannot be transferred.
+class CallEventManager {
+ friend class CallEvent;
+
+ llvm::BumpPtrAllocator &Alloc;
+ SmallVector<void *, 8> Cache;
+
+ using CallEventTemplateTy = SimpleFunctionCall;
+
+ void reclaim(const void *Memory) {
+ Cache.push_back(const_cast<void *>(Memory));
+ }
+
+ /// Returns memory that can be initialized as a CallEvent.
+ void *allocate() {
+ if (Cache.empty())
+ return Alloc.Allocate<CallEventTemplateTy>();
+ else
+ return Cache.pop_back_val();
+ }
+
+ template <typename T, typename Arg>
+ T *create(Arg A, ProgramStateRef St, const LocationContext *LCtx) {
+ static_assert(sizeof(T) == sizeof(CallEventTemplateTy),
+ "CallEvent subclasses are not all the same size");
+ return new (allocate()) T(A, St, LCtx);
+ }
+
+ template <typename T, typename Arg1, typename Arg2>
+ T *create(Arg1 A1, Arg2 A2, ProgramStateRef St, const LocationContext *LCtx) {
+ static_assert(sizeof(T) == sizeof(CallEventTemplateTy),
+ "CallEvent subclasses are not all the same size");
+ return new (allocate()) T(A1, A2, St, LCtx);
+ }
+
+ template <typename T, typename Arg1, typename Arg2, typename Arg3>
+ T *create(Arg1 A1, Arg2 A2, Arg3 A3, ProgramStateRef St,
+ const LocationContext *LCtx) {
+ static_assert(sizeof(T) == sizeof(CallEventTemplateTy),
+ "CallEvent subclasses are not all the same size");
+ 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) {
+ static_assert(sizeof(T) == sizeof(CallEventTemplateTy),
+ "CallEvent subclasses are not all the same size");
+ return new (allocate()) T(A1, A2, A3, A4, St, LCtx);
+ }
+
+public:
+ CallEventManager(llvm::BumpPtrAllocator &alloc) : Alloc(alloc) {}
+
+ /// Gets an outside caller given a callee context.
+ CallEventRef<>
+ getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State);
+
+ /// Gets a call event for a function call, Objective-C method call,
+ /// or a 'new' call.
+ CallEventRef<>
+ getCall(const Stmt *S, ProgramStateRef State,
+ const LocationContext *LC);
+
+ CallEventRef<>
+ getSimpleCall(const CallExpr *E, ProgramStateRef State,
+ const LocationContext *LCtx);
+
+ CallEventRef<ObjCMethodCall>
+ getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State,
+ const LocationContext *LCtx) {
+ return create<ObjCMethodCall>(E, State, LCtx);
+ }
+
+ CallEventRef<CXXConstructorCall>
+ getCXXConstructorCall(const CXXConstructExpr *E, const MemRegion *Target,
+ ProgramStateRef State, const LocationContext *LCtx) {
+ return create<CXXConstructorCall>(E, Target, State, LCtx);
+ }
+
+ CallEventRef<CXXDestructorCall>
+ getCXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
+ const MemRegion *Target, bool IsBase,
+ ProgramStateRef State, const LocationContext *LCtx) {
+ return create<CXXDestructorCall>(DD, Trigger, Target, IsBase, State, LCtx);
+ }
+
+ CallEventRef<CXXAllocatorCall>
+ getCXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef State,
+ const LocationContext *LCtx) {
+ return create<CXXAllocatorCall>(E, State, LCtx);
+ }
+};
+
+template <typename T>
+CallEventRef<T> CallEvent::cloneWithState(ProgramStateRef NewState) const {
+ assert(isa<T>(*this) && "Cloning to unrelated type");
+ static_assert(sizeof(T) == sizeof(CallEvent),
+ "Subclasses may not add fields");
+
+ if (NewState == State)
+ return cast<T>(this);
+
+ CallEventManager &Mgr = State->getStateManager().getCallEventManager();
+ T *Copy = static_cast<T *>(Mgr.allocate());
+ cloneTo(Copy);
+ assert(Copy->getKind() == this->getKind() && "Bad copy");
+
+ Copy->State = NewState;
+ return Copy;
+}
+
+inline void CallEvent::Release() const {
+ assert(RefCount > 0 && "Reference count is already zero.");
+ --RefCount;
+
+ if (RefCount > 0)
+ return;
+
+ CallEventManager &Mgr = State->getStateManager().getCallEventManager();
+ Mgr.reclaim(this);
+
+ this->~CallEvent();
+}
+
+} // namespace ento
+
+} // namespace clang
+
+namespace llvm {
+
+// Support isa<>, cast<>, and dyn_cast<> for CallEventRef.
+template<class T> struct simplify_type< clang::ento::CallEventRef<T>> {
+ using SimpleType = const T *;
+
+ static SimpleType
+ getSimplifiedValue(clang::ento::CallEventRef<T> Val) {
+ return Val.get();
+ }
+};
+
+} // namespace llvm
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLEVENT_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
new file mode 100644
index 00000000..5710ee79
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -0,0 +1,309 @@
+//== CheckerContext.h - Context info for path-sensitive checkers--*- C++ -*--=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines CheckerContext that provides contextual info for
+// path-sensitive checkers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+
+namespace clang {
+namespace ento {
+
+class CheckerContext {
+ ExprEngine &Eng;
+ /// The current exploded(symbolic execution) graph node.
+ ExplodedNode *Pred;
+ /// The flag is true if the (state of the execution) has been modified
+ /// by the checker using this context. For example, a new transition has been
+ /// added or a bug report issued.
+ bool Changed;
+ /// The tagged location, which is used to generate all new nodes.
+ const ProgramPoint Location;
+ NodeBuilder &NB;
+
+public:
+ /// If we are post visiting a call, this flag will be set if the
+ /// call was inlined. In all other cases it will be false.
+ const bool wasInlined;
+
+ CheckerContext(NodeBuilder &builder,
+ ExprEngine &eng,
+ ExplodedNode *pred,
+ const ProgramPoint &loc,
+ bool wasInlined = false)
+ : Eng(eng),
+ Pred(pred),
+ Changed(false),
+ Location(loc),
+ NB(builder),
+ wasInlined(wasInlined) {
+ assert(Pred->getState() &&
+ "We should not call the checkers on an empty state.");
+ }
+
+ AnalysisManager &getAnalysisManager() {
+ return Eng.getAnalysisManager();
+ }
+
+ ConstraintManager &getConstraintManager() {
+ return Eng.getConstraintManager();
+ }
+
+ StoreManager &getStoreManager() {
+ return Eng.getStoreManager();
+ }
+
+ /// 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.
+ ExplodedNode *getPredecessor() { return Pred; }
+ const ProgramStateRef &getState() const { return Pred->getState(); }
+
+ /// Check if the checker changed the state of the execution; ex: added
+ /// a new transition or a bug report.
+ bool isDifferent() { return Changed; }
+
+ /// Returns the number of times the current block has been visited
+ /// along the analyzed path.
+ unsigned blockCount() const {
+ return NB.getContext().blockCount();
+ }
+
+ ASTContext &getASTContext() {
+ return Eng.getContext();
+ }
+
+ const LangOptions &getLangOpts() const {
+ return Eng.getContext().getLangOpts();
+ }
+
+ const LocationContext *getLocationContext() const {
+ return Pred->getLocationContext();
+ }
+
+ const StackFrameContext *getStackFrame() const {
+ return Pred->getStackFrame();
+ }
+
+ /// Return true if the current LocationContext has no caller context.
+ bool inTopFrame() const { return getLocationContext()->inTopFrame(); }
+
+ BugReporter &getBugReporter() {
+ return Eng.getBugReporter();
+ }
+
+ SourceManager &getSourceManager() {
+ return getBugReporter().getSourceManager();
+ }
+
+ SValBuilder &getSValBuilder() {
+ return Eng.getSValBuilder();
+ }
+
+ SymbolManager &getSymbolManager() {
+ return getSValBuilder().getSymbolManager();
+ }
+
+ ProgramStateManager &getStateManager() {
+ return Eng.getStateManager();
+ }
+
+ AnalysisDeclContext *getCurrentAnalysisDeclContext() const {
+ return Pred->getLocationContext()->getAnalysisDeclContext();
+ }
+
+ /// Get the blockID.
+ unsigned getBlockID() const {
+ return NB.getContext().getBlock()->getBlockID();
+ }
+
+ /// If the given node corresponds to a PostStore program point,
+ /// retrieve the location region as it was uttered in the code.
+ ///
+ /// This utility can be useful for generating extensive diagnostics, for
+ /// example, for finding variables that the given symbol was assigned to.
+ static const MemRegion *getLocationRegionIfPostStore(const ExplodedNode *N) {
+ ProgramPoint L = N->getLocation();
+ if (Optional<PostStore> PSL = L.getAs<PostStore>())
+ return reinterpret_cast<const MemRegion*>(PSL->getLocationValue());
+ return nullptr;
+ }
+
+ /// Get the value of arbitrary expressions at this point in the path.
+ SVal getSVal(const Stmt *S) const {
+ return Pred->getSVal(S);
+ }
+
+ /// Returns true if the value of \p E is greater than or equal to \p
+ /// Val under unsigned comparison
+ bool isGreaterOrEqual(const Expr *E, unsigned long long Val);
+
+ /// Returns true if the value of \p E is negative.
+ bool isNegative(const Expr *E);
+
+ /// Generates a new transition in the program state graph
+ /// (ExplodedGraph). Uses the default CheckerContext predecessor 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 = nullptr,
+ const ProgramPointTag *Tag = nullptr) {
+ return addTransitionImpl(State ? State : getState(), false, nullptr, Tag);
+ }
+
+ /// Generates a new transition with the given predecessor.
+ /// Allows checkers to generate a chain of nodes.
+ ///
+ /// @param State The state of the generated node.
+ /// @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.
+ ExplodedNode *addTransition(ProgramStateRef State,
+ ExplodedNode *Pred,
+ const ProgramPointTag *Tag = nullptr) {
+ return addTransitionImpl(State, false, Pred, Tag);
+ }
+
+ /// Generate a sink node. Generating a sink stops exploration of the
+ /// 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);
+ }
+
+ /// 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()));
+ }
+
+ /// 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()));
+ }
+
+ /// Emit the diagnostics report.
+ void emitReport(std::unique_ptr<BugReport> R) {
+ Changed = true;
+ Eng.getBugReporter().emitReport(std::move(R));
+ }
+
+ /// Returns the word that should be used to refer to the declaration
+ /// in the report.
+ StringRef getDeclDescription(const Decl *D);
+
+ /// Get the declaration of the called function (path-sensitive).
+ const FunctionDecl *getCalleeDecl(const CallExpr *CE) const;
+
+ /// Get the name of the called function (path-sensitive).
+ StringRef getCalleeName(const FunctionDecl *FunDecl) const;
+
+ /// 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 nullptr;
+ }
+
+ /// Get the name of the called function (path-sensitive).
+ StringRef getCalleeName(const CallExpr *CE) const {
+ const FunctionDecl *FunDecl = getCalleeDecl(CE);
+ return getCalleeName(FunDecl);
+ }
+
+ /// 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());
+
+ /// Depending on wither the location corresponds to a macro, return
+ /// either the macro name or the token spelling.
+ ///
+ /// This could be useful when checkers' logic depends on whether a function
+ /// is called with a given macro argument. For example:
+ /// s = socket(AF_INET,..)
+ /// If AF_INET is a macro, the result should be treated as a source of taint.
+ ///
+ /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName().
+ StringRef getMacroNameOrSpelling(SourceLocation &Loc);
+
+private:
+ ExplodedNode *addTransitionImpl(ProgramStateRef State,
+ 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;
+
+ Changed = true;
+ 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;
+ }
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
new file mode 100644
index 00000000..b53c042a
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
@@ -0,0 +1,69 @@
+//== CheckerHelpers.h - Helper functions for checkers ------------*- C++ -*--=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines CheckerVisitor.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H
+
+#include "clang/AST/Stmt.h"
+#include <tuple>
+
+namespace clang {
+
+class Expr;
+class VarDecl;
+class QualType;
+class AttributedType;
+
+namespace ento {
+
+bool containsMacro(const Stmt *S);
+bool containsEnum(const Stmt *S);
+bool containsStaticLocal(const Stmt *S);
+bool containsBuiltinOffsetOf(const Stmt *S);
+template <class T> bool containsStmt(const Stmt *S) {
+ if (isa<T>(S))
+ return true;
+
+ for (const Stmt *Child : S->children())
+ if (Child && containsStmt<T>(Child))
+ return true;
+
+ return false;
+}
+
+std::pair<const clang::VarDecl *, const clang::Expr *>
+parseAssignment(const Stmt *S);
+
+// Do not reorder! The getMostNullable method relies on the order.
+// Optimization: Most pointers expected to be unspecified. When a symbol has an
+// unspecified or nonnull type non of the rules would indicate any problem for
+// that symbol. For this reason only nullable and contradicted nullability are
+// stored for a symbol. When a symbol is already contradicted, it can not be
+// casted back to nullable.
+enum class Nullability : char {
+ Contradicted, // Tracked nullability is contradicted by an explicit cast. Do
+ // not report any nullability related issue for this symbol.
+ // This nullability is propagated aggressively to avoid false
+ // positive results. See the comment on getMostNullable method.
+ Nullable,
+ Unspecified,
+ Nonnull
+};
+
+/// Get nullability annotation for a given type.
+Nullability getNullabilityAnnotation(QualType Type);
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
new file mode 100644
index 00000000..0a8712ea
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -0,0 +1,208 @@
+//===- ConstraintManager.h - Constraints on symbolic values. ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defined the interface to manage constraints on symbolic values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/SaveAndRestore.h"
+#include <memory>
+#include <utility>
+
+namespace llvm {
+
+class APSInt;
+
+} // namespace llvm
+
+namespace clang {
+namespace ento {
+
+class ProgramStateManager;
+class SubEngine;
+class SymbolReaper;
+
+class ConditionTruthVal {
+ 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() = default;
+
+ /// \return Stored value, assuming that the value is known.
+ /// Crashes otherwise.
+ bool getValue() const {
+ return *Val;
+ }
+
+ /// 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() = default;
+ virtual ~ConstraintManager();
+
+ virtual ProgramStateRef assume(ProgramStateRef state,
+ DefinedSVal Cond,
+ bool Assumption) = 0;
+
+ using ProgramStatePair = std::pair<ProgramStateRef, ProgramStateRef>;
+
+ /// 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) {
+#ifndef __OPTIMIZE__
+ // This check is expensive and should be disabled even in Release+Asserts
+ // builds.
+ // FIXME: __OPTIMIZE__ is a GNU extension that Clang implements but MSVC
+ // does not. Is there a good equivalent there?
+ assert(assume(State, Cond, false) && "System is over constrained.");
+#endif
+ return ProgramStatePair((ProgramStateRef)nullptr, 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)nullptr);
+ }
+
+ return ProgramStatePair(StTrue, StFalse);
+ }
+
+ virtual ProgramStateRef assumeInclusiveRange(ProgramStateRef State,
+ NonLoc Value,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InBound) = 0;
+
+ virtual ProgramStatePair assumeInclusiveRangeDual(ProgramStateRef State,
+ NonLoc Value,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To) {
+ ProgramStateRef StInRange =
+ assumeInclusiveRange(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 =
+ assumeInclusiveRange(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);
+ }
+
+ /// 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 {
+ return nullptr;
+ }
+
+ /// Scan all symbols referenced by the constraints. If the symbol is not
+ /// alive, remove it.
+ virtual ProgramStateRef removeDeadBindings(ProgramStateRef state,
+ SymbolReaper& SymReaper) = 0;
+
+ virtual void print(ProgramStateRef state,
+ raw_ostream &Out,
+ const char* nl,
+ 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) {
+ 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 = true;
+
+ /// 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);
+};
+
+std::unique_ptr<ConstraintManager>
+CreateRangeConstraintManager(ProgramStateManager &statemgr,
+ SubEngine *subengine);
+
+std::unique_ptr<ConstraintManager>
+CreateZ3ConstraintManager(ProgramStateManager &statemgr, SubEngine *subengine);
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
new file mode 100644
index 00000000..a01678ef
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -0,0 +1,574 @@
+//===- CoreEngine.h - Path-Sensitive Dataflow Engine ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a generic engine for intraprocedural, path-sensitive,
+// dataflow analysis via graph reachability.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
+
+#include "clang/AST/Stmt.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Casting.h"
+#include <cassert>
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace clang {
+
+class AnalyzerOptions;
+class CXXBindTemporaryExpr;
+class Expr;
+class LabelDecl;
+
+namespace ento {
+
+class FunctionSummariesTy;
+class SubEngine;
+
+//===----------------------------------------------------------------------===//
+/// CoreEngine - Implements the core logic of the graph-reachability
+/// analysis. It traverses the CFG and generates the ExplodedGraph.
+/// Program "states" are treated as opaque void pointers.
+/// The template class CoreEngine (which subclasses CoreEngine)
+/// provides the matching component to the engine that knows the actual types
+/// for states. Note that this engine only dispatches to transfer functions
+/// at the statement and block-level. The analyses themselves must implement
+/// any transfer function logic and the sub-expression level (if any).
+class CoreEngine {
+ friend class CommonNodeBuilder;
+ friend class EndOfFunctionNodeBuilder;
+ friend class ExprEngine;
+ friend class IndirectGotoNodeBuilder;
+ friend class NodeBuilder;
+ friend struct NodeBuilderContext;
+ friend class SwitchNodeBuilder;
+
+public:
+ using BlocksExhausted =
+ std::vector<std::pair<BlockEdge, const ExplodedNode *>>;
+
+ using BlocksAborted =
+ std::vector<std::pair<const CFGBlock *, const ExplodedNode *>>;
+
+private:
+ SubEngine &SubEng;
+
+ /// G - The simulation graph. Each node is a (location,state) pair.
+ mutable ExplodedGraph G;
+
+ /// WList - A set of queued nodes that need to be processed by the
+ /// worklist algorithm. It is up to the implementation of WList to decide
+ /// the order that nodes are processed.
+ std::unique_ptr<WorkList> WList;
+
+ /// BCounterFactory - A factory object for created BlockCounter objects.
+ /// These are used to record for key nodes in the ExplodedGraph the
+ /// number of times different CFGBlocks have been visited along a path.
+ BlockCounter::Factory BCounterFactory;
+
+ /// The locations where we stopped doing work because we visited a location
+ /// too many times.
+ BlocksExhausted blocksExhausted;
+
+ /// The locations where we stopped because the engine aborted analysis,
+ /// usually because it could not reason about something.
+ BlocksAborted blocksAborted;
+
+ /// The information about functions shared by the whole translation unit.
+ /// (This data is owned by AnalysisConsumer.)
+ FunctionSummariesTy *FunctionSummaries;
+
+ void generateNode(const ProgramPoint &Loc,
+ ProgramStateRef State,
+ ExplodedNode *Pred);
+
+ void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred);
+ void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred);
+ void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred);
+
+ void HandleCallEnter(const CallEnter &CE, ExplodedNode *Pred);
+
+ void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred);
+
+ void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B,
+ ExplodedNode *Pred);
+ void HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
+ const CFGBlock *B, ExplodedNode *Pred);
+
+ /// Handle conditional logic for running static initializers.
+ void HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
+ ExplodedNode *Pred);
+
+private:
+ ExplodedNode *generateCallExitBeginNode(ExplodedNode *N,
+ const ReturnStmt *RS);
+
+public:
+ /// Construct a CoreEngine object to analyze the provided CFG.
+ CoreEngine(SubEngine &subengine,
+ FunctionSummariesTy *FS,
+ AnalyzerOptions &Opts);
+
+ CoreEngine(const CoreEngine &) = delete;
+ CoreEngine &operator=(const CoreEngine &) = delete;
+
+ /// getGraph - Returns the exploded graph.
+ ExplodedGraph &getGraph() { return G; }
+
+ /// ExecuteWorkList - Run the worklist algorithm for a maximum number of
+ /// steps. Returns true if there is still simulation state on the worklist.
+ bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
+ ProgramStateRef InitState);
+
+ /// Returns true if there is still simulation state on the worklist.
+ bool ExecuteWorkListWithInitialState(const LocationContext *L,
+ unsigned Steps,
+ ProgramStateRef InitState,
+ ExplodedNodeSet &Dst);
+
+ /// Dispatch the work list item based on the given location information.
+ /// Use Pred parameter as the predecessor state.
+ void dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
+ const WorkListUnit& WU);
+
+ // Functions for external checking of whether we have unfinished work
+ bool wasBlockAborted() const { return !blocksAborted.empty(); }
+ bool wasBlocksExhausted() const { return !blocksExhausted.empty(); }
+ bool hasWorkRemaining() const { return wasBlocksExhausted() ||
+ WList->hasWork() ||
+ wasBlockAborted(); }
+
+ /// Inform the CoreEngine that a basic block was aborted because
+ /// it could not be completely analyzed.
+ void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) {
+ blocksAborted.push_back(std::make_pair(block, node));
+ }
+
+ WorkList *getWorkList() const { return WList.get(); }
+
+ BlocksExhausted::const_iterator blocks_exhausted_begin() const {
+ return blocksExhausted.begin();
+ }
+
+ BlocksExhausted::const_iterator blocks_exhausted_end() const {
+ return blocksExhausted.end();
+ }
+
+ BlocksAborted::const_iterator blocks_aborted_begin() const {
+ return blocksAborted.begin();
+ }
+
+ BlocksAborted::const_iterator blocks_aborted_end() const {
+ return blocksAborted.end();
+ }
+
+ /// Enqueue the given set of nodes onto the work list.
+ void enqueue(ExplodedNodeSet &Set);
+
+ /// Enqueue nodes that were created as a result of processing
+ /// a statement onto the work list.
+ void enqueue(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx);
+
+ /// enqueue the nodes corresponding to the end of function onto the
+ /// end of path / work list.
+ void enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS);
+
+ /// Enqueue a single node created as a result of statement processing.
+ void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx);
+};
+
+// TODO: Turn into a calss.
+struct NodeBuilderContext {
+ const CoreEngine &Eng;
+ const CFGBlock *Block;
+ const LocationContext *LC;
+
+ NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
+ : Eng(E), Block(B), LC(N->getLocationContext()) { assert(B); }
+
+ /// Return the CFGBlock associated with this builder.
+ const CFGBlock *getBlock() const { return Block; }
+
+ /// Returns the number of times the current basic block has been
+ /// visited on the exploded graph path.
+ unsigned blockCount() const {
+ return Eng.WList->getBlockCounter().getNumVisited(
+ LC->getStackFrame(),
+ Block->getBlockID());
+ }
+};
+
+/// \class NodeBuilder
+/// This is the simplest builder which generates nodes in the
+/// ExplodedGraph.
+///
+/// The main benefit of the builder is that it automatically tracks the
+/// frontier nodes (or destination set). This is the set of nodes which should
+/// be propagated to the next step / builder. They are the nodes which have been
+/// added to the builder (either as the input node set or as the newly
+/// constructed nodes) but did not have any outgoing transitions added.
+class NodeBuilder {
+ virtual void anchor();
+
+protected:
+ const NodeBuilderContext &C;
+
+ /// Specifies if the builder results have been finalized. For example, if it
+ /// is set to false, autotransitions are yet to be generated.
+ bool Finalized;
+
+ bool HasGeneratedNodes = false;
+
+ /// The frontier set - a set of nodes which need to be propagated after
+ /// the builder dies.
+ ExplodedNodeSet &Frontier;
+
+ /// Checks if the results are ready.
+ virtual bool checkResults() {
+ return Finalized;
+ }
+
+ bool hasNoSinksInFrontier() {
+ for (const auto I : Frontier)
+ if (I->isSink())
+ return false;
+ return true;
+ }
+
+ /// Allow subclasses to finalize results before result_begin() is executed.
+ virtual void finalizeResults() {}
+
+ ExplodedNode *generateNodeImpl(const ProgramPoint &PP,
+ ProgramStateRef State,
+ ExplodedNode *Pred,
+ bool MarkAsSink = false);
+
+public:
+ NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &Ctx, bool F = true)
+ : C(Ctx), Finalized(F), Frontier(DstSet) {
+ Frontier.Add(SrcNode);
+ }
+
+ NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &Ctx, bool F = true)
+ : C(Ctx), Finalized(F), Frontier(DstSet) {
+ Frontier.insert(SrcSet);
+ assert(hasNoSinksInFrontier());
+ }
+
+ virtual ~NodeBuilder() = default;
+
+ /// Generates a node in the ExplodedGraph.
+ ExplodedNode *generateNode(const ProgramPoint &PP,
+ ProgramStateRef State,
+ ExplodedNode *Pred) {
+ return generateNodeImpl(PP, State, Pred, false);
+ }
+
+ /// 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 and certain kinds of bugs are
+ /// suppressed.
+ ExplodedNode *generateSink(const ProgramPoint &PP,
+ ProgramStateRef State,
+ ExplodedNode *Pred) {
+ return generateNodeImpl(PP, State, Pred, true);
+ }
+
+ const ExplodedNodeSet &getResults() {
+ finalizeResults();
+ assert(checkResults());
+ return Frontier;
+ }
+
+ using iterator = ExplodedNodeSet::iterator;
+
+ /// Iterators through the results frontier.
+ iterator begin() {
+ finalizeResults();
+ assert(checkResults());
+ return Frontier.begin();
+ }
+
+ iterator end() {
+ finalizeResults();
+ return Frontier.end();
+ }
+
+ const NodeBuilderContext &getContext() { return C; }
+ bool hasGeneratedNodes() { return HasGeneratedNodes; }
+
+ void takeNodes(const ExplodedNodeSet &S) {
+ for (const auto I : S)
+ Frontier.erase(I);
+ }
+
+ void takeNodes(ExplodedNode *N) { Frontier.erase(N); }
+ void addNodes(const ExplodedNodeSet &S) { Frontier.insert(S); }
+ void addNodes(ExplodedNode *N) { Frontier.Add(N); }
+};
+
+/// \class NodeBuilderWithSinks
+/// This node builder keeps track of the generated sink nodes.
+class NodeBuilderWithSinks: public NodeBuilder {
+ void anchor() override;
+
+protected:
+ SmallVector<ExplodedNode*, 2> sinksGenerated;
+ ProgramPoint &Location;
+
+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 = nullptr) {
+ const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
+ return NodeBuilder::generateNode(LocalLoc, State, Pred);
+ }
+
+ ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred,
+ const ProgramPointTag *Tag = nullptr) {
+ 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;
+ }
+
+ const SmallVectorImpl<ExplodedNode*> &getSinks() const {
+ return sinksGenerated;
+ }
+};
+
+/// \class StmtNodeBuilder
+/// This builder class is useful for generating nodes that resulted from
+/// visiting a statement. The main difference from its parent NodeBuilder is
+/// that it creates a statement specific ProgramPoint.
+class StmtNodeBuilder: public NodeBuilder {
+ NodeBuilder *EnclosingBldr;
+
+public:
+ /// Constructs a StmtNodeBuilder. If the builder is going to process
+ /// nodes currently owned by another builder(with larger scope), use
+ /// Enclosing builder to transfer ownership.
+ StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &Ctx,
+ NodeBuilder *Enclosing = nullptr)
+ : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) {
+ if (EnclosingBldr)
+ EnclosingBldr->takeNodes(SrcNode);
+ }
+
+ StmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &Ctx,
+ NodeBuilder *Enclosing = nullptr)
+ : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) {
+ if (EnclosingBldr)
+ for (const auto I : SrcSet)
+ EnclosingBldr->takeNodes(I);
+ }
+
+ ~StmtNodeBuilder() override;
+
+ using NodeBuilder::generateNode;
+ using NodeBuilder::generateSink;
+
+ ExplodedNode *generateNode(const Stmt *S,
+ ExplodedNode *Pred,
+ ProgramStateRef St,
+ const ProgramPointTag *tag = nullptr,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
+ Pred->getLocationContext(), tag);
+ return NodeBuilder::generateNode(L, St, Pred);
+ }
+
+ ExplodedNode *generateSink(const Stmt *S,
+ ExplodedNode *Pred,
+ ProgramStateRef St,
+ const ProgramPointTag *tag = nullptr,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
+ Pred->getLocationContext(), tag);
+ return NodeBuilder::generateSink(L, St, Pred);
+ }
+};
+
+/// BranchNodeBuilder is responsible for constructing the nodes
+/// corresponding to the two branches of the if statement - true and false.
+class BranchNodeBuilder: public NodeBuilder {
+ const CFGBlock *DstT;
+ const CFGBlock *DstF;
+
+ bool InFeasibleTrue;
+ bool InFeasibleFalse;
+
+ void anchor() override;
+
+public:
+ BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &C,
+ const CFGBlock *dstT, const CFGBlock *dstF)
+ : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF),
+ InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
+ // The branch node builder does not generate autotransitions.
+ // If there are no successors it means that both branches are infeasible.
+ takeNodes(SrcNode);
+ }
+
+ BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &C,
+ const CFGBlock *dstT, const CFGBlock *dstF)
+ : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF),
+ InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
+ takeNodes(SrcSet);
+ }
+
+ ExplodedNode *generateNode(ProgramStateRef State, bool branch,
+ ExplodedNode *Pred);
+
+ const CFGBlock *getTargetBlock(bool branch) const {
+ return branch ? DstT : DstF;
+ }
+
+ void markInfeasible(bool branch) {
+ if (branch)
+ InFeasibleTrue = true;
+ else
+ InFeasibleFalse = true;
+ }
+
+ bool isFeasible(bool branch) {
+ return branch ? !InFeasibleTrue : !InFeasibleFalse;
+ }
+};
+
+class IndirectGotoNodeBuilder {
+ CoreEngine& Eng;
+ const CFGBlock *Src;
+ const CFGBlock &DispatchBlock;
+ const Expr *E;
+ ExplodedNode *Pred;
+
+public:
+ IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
+ const Expr *e, const CFGBlock *dispatch, CoreEngine* eng)
+ : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
+
+ class iterator {
+ friend class IndirectGotoNodeBuilder;
+
+ CFGBlock::const_succ_iterator I;
+
+ iterator(CFGBlock::const_succ_iterator i) : I(i) {}
+
+ public:
+ iterator &operator++() { ++I; return *this; }
+ bool operator!=(const iterator &X) const { return I != X.I; }
+
+ const LabelDecl *getLabel() const {
+ return cast<LabelStmt>((*I)->getLabel())->getDecl();
+ }
+
+ const CFGBlock *getBlock() const {
+ return *I;
+ }
+ };
+
+ iterator begin() { return iterator(DispatchBlock.succ_begin()); }
+ iterator end() { return iterator(DispatchBlock.succ_end()); }
+
+ ExplodedNode *generateNode(const iterator &I,
+ ProgramStateRef State,
+ bool isSink = false);
+
+ const Expr *getTarget() const { return E; }
+
+ ProgramStateRef getState() const { return Pred->State; }
+
+ const LocationContext *getLocationContext() const {
+ return Pred->getLocationContext();
+ }
+};
+
+class SwitchNodeBuilder {
+ CoreEngine& Eng;
+ const CFGBlock *Src;
+ const Expr *Condition;
+ ExplodedNode *Pred;
+
+public:
+ SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
+ const Expr *condition, CoreEngine* eng)
+ : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
+
+ class iterator {
+ friend class SwitchNodeBuilder;
+
+ CFGBlock::const_succ_reverse_iterator I;
+
+ iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {}
+
+ public:
+ iterator &operator++() { ++I; return *this; }
+ bool operator!=(const iterator &X) const { return I != X.I; }
+ bool operator==(const iterator &X) const { return I == X.I; }
+
+ const CaseStmt *getCase() const {
+ return cast<CaseStmt>((*I)->getLabel());
+ }
+
+ const CFGBlock *getBlock() const {
+ return *I;
+ }
+ };
+
+ iterator begin() { return iterator(Src->succ_rbegin()+1); }
+ iterator end() { return iterator(Src->succ_rend()); }
+
+ const SwitchStmt *getSwitch() const {
+ return cast<SwitchStmt>(Src->getTerminator());
+ }
+
+ ExplodedNode *generateCaseStmtNode(const iterator &I,
+ ProgramStateRef State);
+
+ ExplodedNode *generateDefaultCaseNode(ProgramStateRef State,
+ bool isSink = false);
+
+ const Expr *getCondition() const { return Condition; }
+
+ ProgramStateRef getState() const { return Pred->State; }
+
+ const LocationContext *getLocationContext() const {
+ return Pred->getLocationContext();
+ }
+};
+
+} // namespace ento
+
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
new file mode 100644
index 00000000..9bb1e213
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
@@ -0,0 +1,51 @@
+//== DynamicTypeInfo.h - Runtime type information ----------------*- C++ -*--=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEINFO_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEINFO_H
+
+#include "clang/AST/Type.h"
+
+namespace clang {
+namespace ento {
+
+/// 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) {}
+
+ /// Return false if no dynamic type info is available.
+ bool isValid() const { return !T.isNull(); }
+
+ /// Returns the currently inferred upper bound on the runtime type.
+ QualType getType() const { return T; }
+
+ /// 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/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h
new file mode 100644
index 00000000..6608f26b
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h
@@ -0,0 +1,63 @@
+//===- DynamicTypeMap.h - Dynamic type map ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// 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/PathSensitive/DynamicTypeInfo.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "clang/AST/Type.h"
+
+namespace clang {
+namespace ento {
+
+class MemRegion;
+
+/// The GDM component containing the dynamic type info. This is a map from a
+/// symbol to its most likely type.
+struct DynamicTypeMap {};
+
+using DynamicTypeMapImpl =
+ llvm::ImmutableMap<const MemRegion *, DynamicTypeInfo>;
+
+template <>
+struct ProgramStateTrait<DynamicTypeMap>
+ : public ProgramStatePartialTrait<DynamicTypeMapImpl> {
+ static void *GDMIndex();
+};
+
+/// Get dynamic type information for a region.
+DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State,
+ const MemRegion *Reg);
+
+/// Set dynamic type information of the region; return the new state.
+ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg,
+ DynamicTypeInfo NewTy);
+
+/// 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));
+}
+
+void printDynamicTypeInfo(ProgramStateRef State, raw_ostream &Out,
+ const char *NL, const char *Sep);
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
new file mode 100644
index 00000000..6fc589b8
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -0,0 +1,125 @@
+//===- Environment.h - Map from Stmt* to Locations/Values -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defined the Environment and EnvironmentManager classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H
+
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include <utility>
+
+namespace clang {
+
+class Stmt;
+
+namespace ento {
+
+class SValBuilder;
+class SymbolReaper;
+
+/// An entry in the environment consists of a Stmt and an LocationContext.
+/// This allows the environment to manage context-sensitive bindings,
+/// which is essentially for modeling recursive function analysis, among
+/// other things.
+class EnvironmentEntry : public std::pair<const Stmt *,
+ const StackFrameContext *> {
+public:
+ EnvironmentEntry(const Stmt *s, const LocationContext *L);
+
+ const Stmt *getStmt() const { return first; }
+ const LocationContext *getLocationContext() const { return second; }
+
+ /// Profile an EnvironmentEntry for inclusion in a FoldingSet.
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const EnvironmentEntry &E) {
+ ID.AddPointer(E.getStmt());
+ ID.AddPointer(E.getLocationContext());
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, *this);
+ }
+};
+
+/// An immutable map from EnvironemntEntries to SVals.
+class Environment {
+private:
+ friend class EnvironmentManager;
+
+ using BindingsTy = llvm::ImmutableMap<EnvironmentEntry, SVal>;
+
+ BindingsTy ExprBindings;
+
+ Environment(BindingsTy eb) : ExprBindings(eb) {}
+
+ SVal lookupExpr(const EnvironmentEntry &E) const;
+
+public:
+ using iterator = BindingsTy::iterator;
+
+ iterator begin() const { return ExprBindings.begin(); }
+ iterator end() const { return ExprBindings.end(); }
+
+ /// Fetches the current binding of the expression in the
+ /// Environment.
+ SVal getSVal(const EnvironmentEntry &E, SValBuilder &svalBuilder) const;
+
+ /// Profile - Profile the contents of an Environment object for use
+ /// in a FoldingSet.
+ static void Profile(llvm::FoldingSetNodeID& ID, const Environment* env) {
+ env->ExprBindings.Profile(ID);
+ }
+
+ /// Profile - Used to profile the contents of this object for inclusion
+ /// in a FoldingSet.
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ Profile(ID, this);
+ }
+
+ bool operator==(const Environment& RHS) const {
+ return ExprBindings == RHS.ExprBindings;
+ }
+
+ void print(raw_ostream &Out, const char *NL, const char *Sep,
+ const ASTContext &Context,
+ const LocationContext *WithLC = nullptr) const;
+};
+
+class EnvironmentManager {
+private:
+ using FactoryTy = Environment::BindingsTy::Factory;
+
+ FactoryTy F;
+
+public:
+ EnvironmentManager(llvm::BumpPtrAllocator &Allocator) : F(Allocator) {}
+
+ Environment getInitialEnvironment() {
+ return Environment(F.getEmptyMap());
+ }
+
+ /// Bind a symbolic value to the given environment entry.
+ Environment bindExpr(Environment Env, const EnvironmentEntry &E, SVal V,
+ bool Invalidate);
+
+ Environment removeDeadBindings(Environment Env,
+ SymbolReaper &SymReaper,
+ ProgramStateRef state);
+};
+
+} // namespace ento
+
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
new file mode 100644
index 00000000..727d04cb
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -0,0 +1,504 @@
+//===- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the template classes ExplodedNode and ExplodedGraph,
+// which represent a path-sensitive, intra-procedural "exploded graph."
+// See "Precise interprocedural dataflow analysis via graph reachability"
+// by Reps, Horwitz, and Sagiv
+// (http://portal.acm.org/citation.cfm?id=199462) for the definition of an
+// exploded graph.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H
+
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Compiler.h"
+#include <cassert>
+#include <cstdint>
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace clang {
+
+class CFG;
+class Decl;
+class Expr;
+class ParentMap;
+class Stmt;
+
+namespace ento {
+
+class ExplodedGraph;
+
+//===----------------------------------------------------------------------===//
+// ExplodedGraph "implementation" classes. These classes are not typed to
+// contain a specific kind of state. Typed-specialized versions are defined
+// on top of these classes.
+//===----------------------------------------------------------------------===//
+
+// ExplodedNode is not constified all over the engine because we need to add
+// successors to it at any time after creating it.
+
+class ExplodedNode : public llvm::FoldingSetNode {
+ friend class BranchNodeBuilder;
+ friend class CoreEngine;
+ friend class EndOfFunctionNodeBuilder;
+ friend class ExplodedGraph;
+ friend class IndirectGotoNodeBuilder;
+ friend class NodeBuilder;
+ friend class SwitchNodeBuilder;
+
+ /// 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 {
+ // 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;
+
+ public:
+ NodeGroup(bool Flag = false) : P(Flag) {
+ assert(getFlag() == Flag);
+ }
+
+ ExplodedNode * const *begin() const;
+
+ ExplodedNode * const *end() const;
+
+ unsigned size() const;
+
+ 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);
+
+ /// Returns whether this group was created with its flag set.
+ bool getFlag() const {
+ return (P & 1);
+ }
+ };
+
+ /// Location - The program location (within a function body) associated
+ /// with this node.
+ const ProgramPoint Location;
+
+ /// State - The state associated with this node.
+ ProgramStateRef State;
+
+ /// Preds - The predecessors of this node.
+ NodeGroup Preds;
+
+ /// Succs - The successors of this node.
+ NodeGroup Succs;
+
+public:
+ explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state,
+ bool IsSink)
+ : Location(loc), State(std::move(state)), Succs(IsSink) {
+ assert(isSink() == IsSink);
+ }
+
+ /// getLocation - Returns the edge associated with the given node.
+ ProgramPoint getLocation() const { return Location; }
+
+ const LocationContext *getLocationContext() const {
+ return getLocation().getLocationContext();
+ }
+
+ const StackFrameContext *getStackFrame() const {
+ return getLocation().getStackFrame();
+ }
+
+ const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); }
+
+ CFG &getCFG() const { return *getLocationContext()->getCFG(); }
+
+ ParentMap &getParentMap() const {return getLocationContext()->getParentMap();}
+
+ template <typename T>
+ T &getAnalysis() const {
+ return *getLocationContext()->getAnalysis<T>();
+ }
+
+ const ProgramStateRef &getState() const { return State; }
+
+ template <typename T>
+ Optional<T> getLocationAs() const LLVM_LVALUE_FUNCTION {
+ return Location.getAs<T>();
+ }
+
+ /// Get the value of an arbitrary expression at this node.
+ SVal getSVal(const Stmt *S) const {
+ return getState()->getSVal(S, getLocationContext());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const ProgramPoint &Loc,
+ const ProgramStateRef &state,
+ bool IsSink) {
+ ID.Add(Loc);
+ ID.AddPointer(state.get());
+ ID.AddBoolean(IsSink);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ // We avoid copy constructors by not using accessors.
+ Profile(ID, Location, State, isSink());
+ }
+
+ /// addPredeccessor - Adds a predecessor to the current node, and
+ /// in tandem add this node as a successor of the other node.
+ void addPredecessor(ExplodedNode *V, ExplodedGraph &G);
+
+ unsigned succ_size() const { return Succs.size(); }
+ unsigned pred_size() const { return Preds.size(); }
+ bool succ_empty() const { return Succs.empty(); }
+ bool pred_empty() const { return Preds.empty(); }
+
+ bool isSink() const { return Succs.getFlag(); }
+
+ bool hasSinglePred() const {
+ return (pred_size() == 1);
+ }
+
+ ExplodedNode *getFirstPred() {
+ return pred_empty() ? nullptr : *(pred_begin());
+ }
+
+ const ExplodedNode *getFirstPred() const {
+ return const_cast<ExplodedNode*>(this)->getFirstPred();
+ }
+
+ ExplodedNode *getFirstSucc() {
+ return succ_empty() ? nullptr : *(succ_begin());
+ }
+
+ const ExplodedNode *getFirstSucc() const {
+ return const_cast<ExplodedNode*>(this)->getFirstSucc();
+ }
+
+ // Iterators over successor and predecessor vertices.
+ using succ_iterator = ExplodedNode * const *;
+ using const_succ_iterator = const ExplodedNode * const *;
+ using pred_iterator = ExplodedNode * const *;
+ using const_pred_iterator = const ExplodedNode * const *;
+
+ pred_iterator pred_begin() { return Preds.begin(); }
+ pred_iterator pred_end() { return Preds.end(); }
+
+ const_pred_iterator pred_begin() const {
+ return const_cast<ExplodedNode*>(this)->pred_begin();
+ }
+ const_pred_iterator pred_end() const {
+ return const_cast<ExplodedNode*>(this)->pred_end();
+ }
+
+ succ_iterator succ_begin() { return Succs.begin(); }
+ succ_iterator succ_end() { return Succs.end(); }
+
+ const_succ_iterator succ_begin() const {
+ return const_cast<ExplodedNode*>(this)->succ_begin();
+ }
+ const_succ_iterator succ_end() const {
+ return const_cast<ExplodedNode*>(this)->succ_end();
+ }
+
+ int64_t getID(ExplodedGraph *G) const;
+
+ /// The node is trivial if it has only one successor, only one predecessor,
+ /// it's predecessor has only one successor,
+ /// and its program state is the same as the program state of the previous
+ /// node.
+ /// Trivial nodes may be skipped while printing exploded graph.
+ bool isTrivial() const;
+
+private:
+ void replaceSuccessor(ExplodedNode *node) { Succs.replaceNode(node); }
+ void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); }
+};
+
+using InterExplodedGraphMap =
+ llvm::DenseMap<const ExplodedNode *, const ExplodedNode *>;
+
+class ExplodedGraph {
+protected:
+ friend class CoreEngine;
+
+ // Type definitions.
+ using NodeVector = std::vector<ExplodedNode *>;
+
+ /// The roots of the simulation graph. Usually there will be only
+ /// one, but clients are free to establish multiple subgraphs within a single
+ /// SimulGraph. Moreover, these subgraphs can often merge when paths from
+ /// different roots reach the same state at the same program location.
+ NodeVector Roots;
+
+ /// The nodes in the simulation graph which have been
+ /// specially marked as the endpoint of an abstract simulation path.
+ NodeVector EndNodes;
+
+ /// Nodes - The nodes in the graph.
+ llvm::FoldingSet<ExplodedNode> Nodes;
+
+ /// BVC - Allocator and context for allocating nodes and their predecessor
+ /// and successor groups.
+ BumpVectorContext BVC;
+
+ /// NumNodes - The number of nodes in the graph.
+ unsigned NumNodes = 0;
+
+ /// A list of recently allocated nodes that can potentially be recycled.
+ NodeVector ChangedNodes;
+
+ /// A list of nodes that can be reused.
+ NodeVector FreeNodes;
+
+ /// Determines how often nodes are reclaimed.
+ ///
+ /// If this is 0, nodes will never be reclaimed.
+ unsigned ReclaimNodeInterval = 0;
+
+ /// Counter to determine when to reclaim nodes.
+ unsigned ReclaimCounter;
+
+public:
+ ExplodedGraph();
+ ~ExplodedGraph();
+
+ /// Retrieve the node associated with a (Location,State) pair,
+ /// where the 'Location' is a ProgramPoint in the CFG. If no node for
+ /// this pair exists, it is created. IsNew is set to true if
+ /// the node was freshly created.
+ ExplodedNode *getNode(const ProgramPoint &L, ProgramStateRef State,
+ bool IsSink = false,
+ bool* IsNew = nullptr);
+
+ /// Create a node for a (Location, State) pair,
+ /// but don't store it for deduplication later. This
+ /// is useful when copying an already completed
+ /// ExplodedGraph for further processing.
+ ExplodedNode *createUncachedNode(const ProgramPoint &L,
+ ProgramStateRef State,
+ bool IsSink = false);
+
+ std::unique_ptr<ExplodedGraph> MakeEmptyGraph() const {
+ return llvm::make_unique<ExplodedGraph>();
+ }
+
+ /// addRoot - Add an untyped node to the set of roots.
+ ExplodedNode *addRoot(ExplodedNode *V) {
+ Roots.push_back(V);
+ return V;
+ }
+
+ /// addEndOfPath - Add an untyped node to the set of EOP nodes.
+ ExplodedNode *addEndOfPath(ExplodedNode *V) {
+ EndNodes.push_back(V);
+ return V;
+ }
+
+ unsigned num_roots() const { return Roots.size(); }
+ unsigned num_eops() const { return EndNodes.size(); }
+
+ bool empty() const { return NumNodes == 0; }
+ unsigned size() const { return NumNodes; }
+
+ void reserve(unsigned NodeCount) { Nodes.reserve(NodeCount); }
+
+ // Iterators.
+ using NodeTy = ExplodedNode;
+ using AllNodesTy = llvm::FoldingSet<ExplodedNode>;
+ using roots_iterator = NodeVector::iterator;
+ using const_roots_iterator = NodeVector::const_iterator;
+ using eop_iterator = NodeVector::iterator;
+ using const_eop_iterator = NodeVector::const_iterator;
+ using node_iterator = AllNodesTy::iterator;
+ using const_node_iterator = AllNodesTy::const_iterator;
+
+ node_iterator nodes_begin() { return Nodes.begin(); }
+
+ node_iterator nodes_end() { return Nodes.end(); }
+
+ const_node_iterator nodes_begin() const { return Nodes.begin(); }
+
+ const_node_iterator nodes_end() const { return Nodes.end(); }
+
+ roots_iterator roots_begin() { return Roots.begin(); }
+
+ roots_iterator roots_end() { return Roots.end(); }
+
+ const_roots_iterator roots_begin() const { return Roots.begin(); }
+
+ const_roots_iterator roots_end() const { return Roots.end(); }
+
+ eop_iterator eop_begin() { return EndNodes.begin(); }
+
+ eop_iterator eop_end() { return EndNodes.end(); }
+
+ const_eop_iterator eop_begin() const { return EndNodes.begin(); }
+
+ const_eop_iterator eop_end() const { return EndNodes.end(); }
+
+ llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); }
+ BumpVectorContext &getNodeAllocator() { return BVC; }
+
+ using NodeMap = llvm::DenseMap<const ExplodedNode *, ExplodedNode *>;
+
+ /// Creates a trimmed version of the graph that only contains paths leading
+ /// to the given nodes.
+ ///
+ /// \param Nodes The nodes which must appear in the final graph. Presumably
+ /// these are end-of-path nodes (i.e. they have no successors).
+ /// \param[out] ForwardMap A optional map from nodes in this graph to nodes in
+ /// the returned graph.
+ /// \param[out] InverseMap An optional map from nodes in the returned graph to
+ /// nodes in this graph.
+ /// \returns The trimmed graph
+ std::unique_ptr<ExplodedGraph>
+ trim(ArrayRef<const NodeTy *> Nodes,
+ InterExplodedGraphMap *ForwardMap = nullptr,
+ InterExplodedGraphMap *InverseMap = nullptr) const;
+
+ /// Enable tracking of recently allocated nodes for potential reclamation
+ /// when calling reclaimRecentlyAllocatedNodes().
+ void enableNodeReclamation(unsigned Interval) {
+ ReclaimCounter = ReclaimNodeInterval = Interval;
+ }
+
+ /// Reclaim "uninteresting" nodes created since the last time this method
+ /// was called.
+ void reclaimRecentlyAllocatedNodes();
+
+ /// Returns true if nodes for the given expression kind are always
+ /// kept around.
+ static bool isInterestingLValueExpr(const Expr *Ex);
+
+private:
+ bool shouldCollect(const ExplodedNode *node);
+ void collectNode(ExplodedNode *node);
+};
+
+class ExplodedNodeSet {
+ using ImplTy = llvm::SmallSetVector<ExplodedNode *, 4>;
+ ImplTy Impl;
+
+public:
+ ExplodedNodeSet(ExplodedNode *N) {
+ assert(N && !static_cast<ExplodedNode*>(N)->isSink());
+ Impl.insert(N);
+ }
+
+ ExplodedNodeSet() = default;
+
+ void Add(ExplodedNode *N) {
+ if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N);
+ }
+
+ using iterator = ImplTy::iterator;
+ using const_iterator = ImplTy::const_iterator;
+
+ unsigned size() const { return Impl.size(); }
+ bool empty() const { return Impl.empty(); }
+ bool erase(ExplodedNode *N) { return Impl.remove(N); }
+
+ void clear() { Impl.clear(); }
+
+ void insert(const ExplodedNodeSet &S) {
+ assert(&S != this);
+ if (empty())
+ Impl = S.Impl;
+ else
+ Impl.insert(S.begin(), S.end());
+ }
+
+ iterator begin() { return Impl.begin(); }
+ iterator end() { return Impl.end(); }
+
+ const_iterator begin() const { return Impl.begin(); }
+ const_iterator end() const { return Impl.end(); }
+};
+
+} // namespace ento
+
+} // namespace clang
+
+// GraphTraits
+
+namespace llvm {
+ template <> struct GraphTraits<clang::ento::ExplodedGraph *> {
+ using GraphTy = clang::ento::ExplodedGraph *;
+ using NodeRef = clang::ento::ExplodedNode *;
+ using ChildIteratorType = clang::ento::ExplodedNode::succ_iterator;
+ using nodes_iterator = llvm::df_iterator<GraphTy>;
+
+ static NodeRef getEntryNode(const GraphTy G) {
+ return *G->roots_begin();
+ }
+
+ static bool predecessorOfTrivial(NodeRef N) {
+ return N->succ_size() == 1 && N->getFirstSucc()->isTrivial();
+ }
+
+ static ChildIteratorType child_begin(NodeRef N) {
+ if (predecessorOfTrivial(N))
+ return child_begin(*N->succ_begin());
+ return N->succ_begin();
+ }
+
+ static ChildIteratorType child_end(NodeRef N) {
+ if (predecessorOfTrivial(N))
+ return child_end(N->getFirstSucc());
+ return N->succ_end();
+ }
+
+ static nodes_iterator nodes_begin(const GraphTy G) {
+ return df_begin(G);
+ }
+
+ static nodes_iterator nodes_end(const GraphTy G) {
+ return df_end(G);
+ }
+ };
+} // namespace llvm
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
new file mode 100644
index 00000000..605e1c78
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -0,0 +1,848 @@
+//===- ExprEngine.h - Path-Sensitive Expression-Level Dataflow --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a meta-engine for path-sensitive dataflow analysis that
+// is built on CoreEngine, but provides the boilerplate to execute transfer
+// functions and build the ExplodedGraph at the expression level.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPRENGINE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPRENGINE_H
+
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
+#include "llvm/ADT/ArrayRef.h"
+#include <cassert>
+#include <utility>
+
+namespace clang {
+
+class AnalysisDeclContextManager;
+class AnalyzerOptions;
+class ASTContext;
+class ConstructionContext;
+class CXXBindTemporaryExpr;
+class CXXCatchStmt;
+class CXXConstructExpr;
+class CXXDeleteExpr;
+class CXXNewExpr;
+class CXXThisExpr;
+class Decl;
+class DeclStmt;
+class GCCAsmStmt;
+class LambdaExpr;
+class LocationContext;
+class MaterializeTemporaryExpr;
+class MSAsmStmt;
+class NamedDecl;
+class ObjCAtSynchronizedStmt;
+class ObjCForCollectionStmt;
+class ObjCIvarRefExpr;
+class ObjCMessageExpr;
+class ReturnStmt;
+class Stmt;
+
+namespace cross_tu {
+
+class CrossTranslationUnitContext;
+
+} // namespace cross_tu
+
+namespace ento {
+
+class BasicValueFactory;
+class CallEvent;
+class CheckerManager;
+class ConstraintManager;
+class CXXTempObjectRegion;
+class MemRegion;
+class RegionAndSymbolInvalidationTraits;
+class SymbolManager;
+
+class ExprEngine : public SubEngine {
+public:
+ /// The modes of inlining, which override the default analysis-wide settings.
+ enum InliningModes {
+ /// Follow the default settings for inlining callees.
+ Inline_Regular = 0,
+
+ /// Do minimal inlining of callees.
+ Inline_Minimal = 0x1
+ };
+
+ /// Hints for figuring out of a call should be inlined during evalCall().
+ struct EvalCallOptions {
+ /// This call is a constructor or a destructor for which we do not currently
+ /// compute the this-region correctly.
+ bool IsCtorOrDtorWithImproperlyModeledTargetRegion = false;
+
+ /// This call is a constructor or a destructor for a single element within
+ /// an array, a part of array construction or destruction.
+ bool IsArrayCtorOrDtor = false;
+
+ /// This call is a constructor or a destructor of a temporary value.
+ bool IsTemporaryCtorOrDtor = false;
+
+ /// This call is a constructor for a temporary that is lifetime-extended
+ /// by binding it to a reference-type field within an aggregate,
+ /// for example 'A { const C &c; }; A a = { C() };'
+ bool IsTemporaryLifetimeExtendedViaAggregate = false;
+
+ EvalCallOptions() {}
+ };
+
+private:
+ cross_tu::CrossTranslationUnitContext &CTU;
+
+ AnalysisManager &AMgr;
+
+ AnalysisDeclContextManager &AnalysisDeclContexts;
+
+ CoreEngine Engine;
+
+ /// G - the simulation graph.
+ ExplodedGraph &G;
+
+ /// StateMgr - Object that manages the data for all created states.
+ ProgramStateManager StateMgr;
+
+ /// SymMgr - Object that manages the symbol information.
+ SymbolManager &SymMgr;
+
+ /// MRMgr - MemRegionManager object that creates memory regions.
+ MemRegionManager &MRMgr;
+
+ /// svalBuilder - SValBuilder object that creates SVals from expressions.
+ SValBuilder &svalBuilder;
+
+ unsigned int currStmtIdx = 0;
+ const NodeBuilderContext *currBldrCtx = nullptr;
+
+ /// Helper object to determine if an Objective-C message expression
+ /// implicitly never returns.
+ ObjCNoReturn ObjCNoRet;
+
+ /// The BugReporter associated with this engine. It is important that
+ /// this object be placed at the very end of member variables so that its
+ /// 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;
+
+ /// The flag, which specifies the mode of inlining for the engine.
+ InliningModes HowToInline;
+
+public:
+ ExprEngine(cross_tu::CrossTranslationUnitContext &CTU, AnalysisManager &mgr,
+ SetOfConstDecls *VisitedCalleesIn,
+ FunctionSummariesTy *FS, InliningModes HowToInlineIn);
+
+ ~ExprEngine() override;
+
+ /// Returns true if there is still simulation state on the worklist.
+ bool ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
+ return Engine.ExecuteWorkList(L, Steps, nullptr);
+ }
+
+ /// Execute the work list with an initial state. Nodes that reaches the exit
+ /// of the function are added into the Dst set, which represent the exit
+ /// state of the function call. Returns true if there is still simulation
+ /// state on the worklist.
+ bool ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
+ ProgramStateRef InitState,
+ ExplodedNodeSet &Dst) {
+ return Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst);
+ }
+
+ /// getContext - Return the ASTContext associated with this analysis.
+ ASTContext &getContext() const { return AMgr.getASTContext(); }
+
+ AnalysisManager &getAnalysisManager() override { return AMgr; }
+
+ AnalysisDeclContextManager &getAnalysisDeclContextManager() {
+ return AMgr.getAnalysisDeclContextManager();
+ }
+
+ CheckerManager &getCheckerManager() const {
+ return *AMgr.getCheckerManager();
+ }
+
+ SValBuilder &getSValBuilder() { return svalBuilder; }
+
+ BugReporter &getBugReporter() { return BR; }
+
+ cross_tu::CrossTranslationUnitContext *
+ getCrossTranslationUnitContext() override {
+ return &CTU;
+ }
+
+ const NodeBuilderContext &getBuilderContext() {
+ assert(currBldrCtx);
+ return *currBldrCtx;
+ }
+
+ const Stmt *getStmt() const;
+
+ void GenerateAutoTransition(ExplodedNode *N);
+ void enqueueEndOfPath(ExplodedNodeSet &S);
+ void GenerateCallExitNode(ExplodedNode *N);
+
+
+ /// Dump graph to the specified filename.
+ /// If filename is empty, generate a temporary one.
+ /// \return The filename the graph is written into.
+ std::string DumpGraph(bool trim = false, StringRef Filename="");
+
+ /// Dump the graph consisting of the given nodes to a specified filename.
+ /// Generate a temporary filename if it's not provided.
+ /// \return The filename the graph is written into.
+ std::string DumpGraph(ArrayRef<const ExplodedNode *> Nodes,
+ StringRef Filename = "");
+
+ /// Visualize the ExplodedGraph created by executing the simulation.
+ void ViewGraph(bool trim = false);
+
+ /// Visualize a trimmed ExplodedGraph that only contains paths to the given
+ /// nodes.
+ void ViewGraph(ArrayRef<const ExplodedNode *> Nodes);
+
+ /// getInitialState - Return the initial state used for the root vertex
+ /// in the ExplodedGraph.
+ ProgramStateRef getInitialState(const LocationContext *InitLoc) override;
+
+ ExplodedGraph &getGraph() { return G; }
+ const ExplodedGraph &getGraph() const { return G; }
+
+ /// Run the analyzer's garbage collection - remove dead symbols and
+ /// bindings from the state.
+ ///
+ /// Checkers can participate in this process with two callbacks:
+ /// \c checkLiveSymbols and \c checkDeadSymbols. See the CheckerDocumentation
+ /// class for more information.
+ ///
+ /// \param Node The predecessor node, from which the processing should start.
+ /// \param Out The returned set of output nodes.
+ /// \param ReferenceStmt The statement which is about to be processed.
+ /// Everything needed for this statement should be considered live.
+ /// A null statement means that everything in child LocationContexts
+ /// is dead.
+ /// \param LC The location context of the \p ReferenceStmt. A null location
+ /// context means that we have reached the end of analysis and that
+ /// all statements and local variables should be considered dead.
+ /// \param DiagnosticStmt Used as a location for any warnings that should
+ /// occur while removing the dead (e.g. leaks). By default, the
+ /// \p ReferenceStmt is used.
+ /// \param K Denotes whether this is a pre- or post-statement purge. This
+ /// must only be ProgramPoint::PostStmtPurgeDeadSymbolsKind if an
+ /// entire location context is being cleared, in which case the
+ /// \p ReferenceStmt must either be a ReturnStmt or \c NULL. Otherwise,
+ /// it must be ProgramPoint::PreStmtPurgeDeadSymbolsKind (the default)
+ /// and \p ReferenceStmt must be valid (non-null).
+ void removeDead(ExplodedNode *Node, ExplodedNodeSet &Out,
+ const Stmt *ReferenceStmt, const LocationContext *LC,
+ const Stmt *DiagnosticStmt = nullptr,
+ ProgramPoint::Kind K = ProgramPoint::PreStmtPurgeDeadSymbolsKind);
+
+ /// processCFGElement - Called by CoreEngine. Used to generate new successor
+ /// nodes by processing the 'effects' of a CFG element.
+ void processCFGElement(const CFGElement E, ExplodedNode *Pred,
+ unsigned StmtIdx, NodeBuilderContext *Ctx) override;
+
+ void ProcessStmt(const Stmt *S, ExplodedNode *Pred);
+
+ void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred);
+
+ void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred);
+
+ void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred);
+
+ void ProcessNewAllocator(const CXXNewExpr *NE, ExplodedNode *Pred);
+
+ void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+ void ProcessDeleteDtor(const CFGDeleteDtor D,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+ void ProcessBaseDtor(const CFGBaseDtor D,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+ void ProcessMemberDtor(const CFGMemberDtor D,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+ void ProcessTemporaryDtor(const CFGTemporaryDtor D,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+ /// Called by CoreEngine when processing the entrance of a CFGBlock.
+ void processCFGBlockEntrance(const BlockEdge &L,
+ NodeBuilderWithSinks &nodeBuilder,
+ ExplodedNode *Pred) override;
+
+ /// ProcessBranch - Called by CoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a branch condition.
+ void processBranch(const Stmt *Condition,
+ NodeBuilderContext& BuilderCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) override;
+
+ /// Called by CoreEngine.
+ /// Used to generate successor nodes for temporary destructors depending
+ /// on whether the corresponding constructor was visited.
+ void processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
+ NodeBuilderContext &BldCtx,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) override;
+
+ /// Called by CoreEngine. Used to processing branching behavior
+ /// at static initializers.
+ void processStaticInitializer(const DeclStmt *DS,
+ NodeBuilderContext& BuilderCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) override;
+
+ /// processIndirectGoto - Called by CoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a computed goto jump.
+ void processIndirectGoto(IndirectGotoNodeBuilder& builder) override;
+
+ /// ProcessSwitch - Called by CoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a switch statement.
+ void processSwitch(SwitchNodeBuilder& builder) override;
+
+ /// Called by CoreEngine. Used to notify checkers that processing a
+ /// function has begun. Called for both inlined and and top-level functions.
+ void processBeginOfFunction(NodeBuilderContext &BC,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst,
+ const BlockEdge &L) override;
+
+ /// Called by CoreEngine. Used to notify checkers that processing a
+ /// function has ended. Called for both inlined and and top-level functions.
+ void processEndOfFunction(NodeBuilderContext& BC,
+ ExplodedNode *Pred,
+ const ReturnStmt *RS = nullptr) override;
+
+ /// 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(NodeBuilderContext& BC, CallEnter CE,
+ ExplodedNode *Pred) override;
+
+ /// Generate the sequence of nodes that simulate the call exit and the post
+ /// visit for CallExpr.
+ void processCallExit(ExplodedNode *Pred) override;
+
+ /// Called by CoreEngine when the analysis worklist has terminated.
+ void processEndWorklist() override;
+
+ /// evalAssume - Callback function invoked by the ConstraintManager when
+ /// making assumptions about state values.
+ ProgramStateRef processAssume(ProgramStateRef state, SVal cond,
+ bool assumption) override;
+
+ /// processRegionChanges - Called by ProgramStateManager whenever a change is made
+ /// to the store. Used to update checkers that track region values.
+ ProgramStateRef
+ processRegionChanges(ProgramStateRef state,
+ const InvalidatedSymbols *invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
+ const CallEvent *Call) override;
+
+ /// printState - Called by ProgramStateManager to print checker-specific data.
+ void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
+ const char *Sep,
+ const LocationContext *LCtx = nullptr) override;
+
+ ProgramStateManager &getStateManager() override { return StateMgr; }
+
+ StoreManager &getStoreManager() { return StateMgr.getStoreManager(); }
+
+ ConstraintManager &getConstraintManager() {
+ return StateMgr.getConstraintManager();
+ }
+
+ // FIXME: Remove when we migrate over to just using SValBuilder.
+ BasicValueFactory &getBasicVals() {
+ return StateMgr.getBasicVals();
+ }
+
+ SymbolManager &getSymbolManager() { return SymMgr; }
+ MemRegionManager &getRegionManager() { return MRMgr; }
+
+
+ // Functions for external checking of whether we have unfinished work
+ bool wasBlocksExhausted() const { return Engine.wasBlocksExhausted(); }
+ bool hasEmptyWorkList() const { return !Engine.getWorkList()->hasWork(); }
+ bool hasWorkRemaining() const { return Engine.hasWorkRemaining(); }
+
+ const CoreEngine &getCoreEngine() const { return Engine; }
+
+public:
+ /// Visit - Transfer function logic for all statements. Dispatches to
+ /// other functions that handle specific kinds of statements.
+ void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+ /// VisitArraySubscriptExpr - Transfer function for array accesses.
+ void VisitArraySubscriptExpr(const ArraySubscriptExpr *Ex,
+ 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);
+
+ /// 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);
+
+
+ /// VisitCall - Transfer function for function calls.
+ void VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// VisitCast - Transfer function logic for all casts (implicit and explicit).
+ void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// VisitCompoundLiteralExpr - Transfer function logic for compound literals.
+ void VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+ /// Transfer function logic for DeclRefExprs and BlockDeclRefExprs.
+ void VisitCommonDeclRefExpr(const Expr *DR, const NamedDecl *D,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+ /// VisitDeclStmt - Transfer function logic for DeclStmts.
+ void VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
+ void VisitGuardedExpr(const Expr *Ex, const Expr *L, const Expr *R,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+ void VisitInitListExpr(const InitListExpr *E, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// VisitLogicalExpr - Transfer function logic for '&&', '||'
+ void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// VisitMemberExpr - Transfer function for member expressions.
+ void VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// VisitAtomicExpr - Transfer function for builtin atomic expressions
+ void VisitAtomicExpr(const AtomicExpr *E, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// Transfer function logic for ObjCAtSynchronizedStmts.
+ void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+ /// Transfer function logic for computing the lvalue of an Objective-C ivar.
+ void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *DR, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// VisitObjCForCollectionStmt - Transfer function logic for
+ /// ObjCForCollectionStmt.
+ void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+ void VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// VisitReturnStmt - Transfer function logic for return statements.
+ void VisitReturnStmt(const ReturnStmt *R, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// VisitOffsetOfExpr - Transfer function for offsetof.
+ void VisitOffsetOfExpr(const OffsetOfExpr *Ex, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof.
+ void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+ /// VisitUnaryOperator - Transfer function logic for unary operators.
+ void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// Handle ++ and -- (both pre- and post-increment).
+ void VisitIncrementDecrementOperator(const UnaryOperator* U,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
+ ExplodedNodeSet &PreVisit,
+ ExplodedNodeSet &Dst);
+
+ void VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ void VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
+ ExplodedNodeSet & Dst);
+
+ void VisitCXXConstructExpr(const CXXConstructExpr *E, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ void VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest,
+ const Stmt *S, bool IsBaseDtor,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst,
+ const EvalCallOptions &Options);
+
+ void VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ void VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ void VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// Create a C++ temporary object for an rvalue.
+ void CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// 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 evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
+ const Expr *Ex);
+
+ static std::pair<const ProgramPointTag *, const ProgramPointTag *>
+ geteagerlyAssumeBinOpBifurcationTags();
+
+ SVal evalMinus(SVal X) {
+ return X.isValid() ? svalBuilder.evalMinus(X.castAs<NonLoc>()) : X;
+ }
+
+ SVal evalComplement(SVal X) {
+ return X.isValid() ? svalBuilder.evalComplement(X.castAs<NonLoc>()) : X;
+ }
+
+ ProgramStateRef handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
+ const LocationContext *LCtx, QualType T,
+ QualType ExTy, const CastExpr *CastE,
+ StmtNodeBuilder &Bldr,
+ ExplodedNode *Pred);
+
+ ProgramStateRef handleLVectorSplat(ProgramStateRef state,
+ const LocationContext *LCtx,
+ const CastExpr *CastE,
+ StmtNodeBuilder &Bldr,
+ ExplodedNode *Pred);
+
+ void handleUOExtension(ExplodedNodeSet::iterator I,
+ const UnaryOperator* U,
+ StmtNodeBuilder &Bldr);
+
+public:
+ SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
+ NonLoc L, NonLoc R, QualType T) {
+ return svalBuilder.evalBinOpNN(state, op, L, R, T);
+ }
+
+ SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
+ NonLoc L, SVal R, QualType T) {
+ return R.isValid() ? svalBuilder.evalBinOpNN(state, op, L,
+ R.castAs<NonLoc>(), T) : R;
+ }
+
+ SVal evalBinOp(ProgramStateRef ST, BinaryOperator::Opcode Op,
+ SVal LHS, SVal RHS, QualType T) {
+ return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T);
+ }
+
+ /// By looking at a certain item that may be potentially part of an object's
+ /// ConstructionContext, retrieve such object's location. A particular
+ /// statement can be transparently passed as \p Item in most cases.
+ static Optional<SVal>
+ getObjectUnderConstruction(ProgramStateRef State,
+ const ConstructionContextItem &Item,
+ const LocationContext *LC);
+
+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,
+ const ProgramPoint *PP = nullptr);
+
+ /// Call PointerEscape callback when a value escapes as a result of bind.
+ ProgramStateRef processPointerEscapedOnBind(ProgramStateRef State,
+ SVal Loc,
+ SVal Val,
+ const LocationContext *LCtx) override;
+ /// Call PointerEscape callback when a value escapes as a result of
+ /// region invalidation.
+ /// \param[in] ITraits Specifies invalidation traits for regions/symbols.
+ ProgramStateRef notifyCheckersOfPointerEscape(
+ ProgramStateRef State,
+ const InvalidatedSymbols *Invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ const CallEvent *Call,
+ RegionAndSymbolInvalidationTraits &ITraits) override;
+
+ /// A simple wrapper when you only need to notify checkers of pointer-escape
+ /// of a single value.
+ ProgramStateRef escapeValue(ProgramStateRef State, SVal V,
+ PointerEscapeKind K) const;
+
+public:
+ // FIXME: 'tag' should be removed, and a LocationContext should be used
+ // instead.
+ // FIXME: Comment on the meaning of the arguments, when 'St' may not
+ // be the same as Pred->state, and when 'location' may not be the
+ // same as state->getLValue(Ex).
+ /// Simulate a read of the result of Ex.
+ void evalLoad(ExplodedNodeSet &Dst,
+ const Expr *NodeEx, /* Eventually will be a CFGStmt */
+ const Expr *BoundExpr,
+ ExplodedNode *Pred,
+ ProgramStateRef St,
+ SVal location,
+ const ProgramPointTag *tag = nullptr,
+ QualType LoadTy = QualType());
+
+ // FIXME: 'tag' should be removed, and a LocationContext should be used
+ // instead.
+ void evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, const Expr *StoreE,
+ ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val,
+ const ProgramPointTag *tag = nullptr);
+
+ /// Return the CFG element corresponding to the worklist element
+ /// that is currently being processed by ExprEngine.
+ CFGElement getCurrentCFGElement() {
+ return (*currBldrCtx->getBlock())[currStmtIdx];
+ }
+
+ /// Create a new state in which the call return value is binded to the
+ /// call origin expression.
+ ProgramStateRef bindReturnValue(const CallEvent &Call,
+ const LocationContext *LCtx,
+ ProgramStateRef State);
+
+ /// Evaluate a call, running pre- and post-call checks and allowing checkers
+ /// to be responsible for handling the evaluation of the call itself.
+ void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+ const CallEvent &Call);
+
+ /// Default implementation of call evaluation.
+ void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred,
+ const CallEvent &Call,
+ const EvalCallOptions &CallOpts = {});
+
+private:
+ ProgramStateRef finishArgumentConstruction(ProgramStateRef State,
+ const CallEvent &Call);
+ void finishArgumentConstruction(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+ const CallEvent &Call);
+
+ void evalLoadCommon(ExplodedNodeSet &Dst,
+ const Expr *NodeEx, /* Eventually will be a CFGStmt */
+ const Expr *BoundEx,
+ ExplodedNode *Pred,
+ ProgramStateRef St,
+ SVal location,
+ const ProgramPointTag *tag,
+ QualType LoadTy);
+
+ void evalLocation(ExplodedNodeSet &Dst,
+ const Stmt *NodeEx, /* This will eventually be a CFGStmt */
+ const Stmt *BoundEx,
+ ExplodedNode *Pred,
+ ProgramStateRef St,
+ SVal location,
+ 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);
+
+ enum CallInlinePolicy {
+ CIP_Allowed,
+ CIP_DisallowedOnce,
+ CIP_DisallowedAlways
+ };
+
+ /// See if a particular call should be inlined, by only looking
+ /// at the call event and the current state of analysis.
+ CallInlinePolicy mayInlineCallKind(const CallEvent &Call,
+ const ExplodedNode *Pred,
+ AnalyzerOptions &Opts,
+ const EvalCallOptions &CallOpts);
+
+ /// Checks our policies and decides weither the given call should be inlined.
+ bool shouldInlineCall(const CallEvent &Call, const Decl *D,
+ const ExplodedNode *Pred,
+ const EvalCallOptions &CallOpts = {});
+
+ bool inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr,
+ ExplodedNode *Pred, ProgramStateRef State);
+
+ /// Conservatively evaluate call by invalidating regions and binding
+ /// a conjured return value.
+ void conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
+ ExplodedNode *Pred, ProgramStateRef State);
+
+ /// Either inline or process the call conservatively (or both), based
+ /// on DynamicDispatchBifurcation data.
+ void BifurcateCall(const MemRegion *BifurReg,
+ const CallEvent &Call, const Decl *D, NodeBuilder &Bldr,
+ ExplodedNode *Pred);
+
+ bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC);
+
+ /// Models a trivial copy or move constructor or trivial assignment operator
+ /// call with a simple bind.
+ void performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
+ const CallEvent &Call);
+
+ /// If the value of the given expression \p InitWithAdjustments is a NonLoc,
+ /// copy it into a new temporary object region, and replace the value of the
+ /// expression with that.
+ ///
+ /// If \p Result is provided, the new region will be bound to this expression
+ /// instead of \p InitWithAdjustments.
+ ///
+ /// Returns the temporary region with adjustments into the optional
+ /// OutRegionWithAdjustments out-parameter if a new region was indeed needed,
+ /// otherwise sets it to nullptr.
+ ProgramStateRef createTemporaryRegionIfNeeded(
+ ProgramStateRef State, const LocationContext *LC,
+ const Expr *InitWithAdjustments, const Expr *Result = nullptr,
+ const SubRegion **OutRegionWithAdjustments = nullptr);
+
+ /// Returns a region representing the first element of a (possibly
+ /// multi-dimensional) array, for the purposes of element construction or
+ /// destruction.
+ ///
+ /// On return, \p Ty will be set to the base type of the array.
+ ///
+ /// If the type is not an array type at all, the original value is returned.
+ /// Otherwise the "IsArray" flag is set.
+ static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue,
+ QualType &Ty, bool &IsArray);
+
+ /// 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();
+
+ /// Update the program state with all the path-sensitive information
+ /// that's necessary to perform construction of an object with a given
+ /// syntactic construction context. If the construction context is unavailable
+ /// or unusable for any reason, a dummy temporary region is returned, and the
+ /// IsConstructorWithImproperlyModeledTargetRegion flag is set in \p CallOpts.
+ /// Returns the updated program state and the new object's this-region.
+ std::pair<ProgramStateRef, SVal> prepareForObjectConstruction(
+ const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
+ const ConstructionContext *CC, EvalCallOptions &CallOpts);
+
+ /// Store the location of a C++ object corresponding to a statement
+ /// until the statement is actually encountered. For example, if a DeclStmt
+ /// has CXXConstructExpr as its initializer, the object would be considered
+ /// to be "under construction" between CXXConstructExpr and DeclStmt.
+ /// This allows, among other things, to keep bindings to variable's fields
+ /// made within the constructor alive until its declaration actually
+ /// goes into scope.
+ static ProgramStateRef
+ addObjectUnderConstruction(ProgramStateRef State,
+ const ConstructionContextItem &Item,
+ const LocationContext *LC, SVal V);
+
+ /// Mark the object sa fully constructed, cleaning up the state trait
+ /// that tracks objects under construction.
+ static ProgramStateRef
+ finishObjectConstruction(ProgramStateRef State,
+ const ConstructionContextItem &Item,
+ const LocationContext *LC);
+
+ /// If the given expression corresponds to a temporary that was used for
+ /// passing into an elidable copy/move constructor and that constructor
+ /// was actually elided, track that we also need to elide the destructor.
+ static ProgramStateRef elideDestructor(ProgramStateRef State,
+ const CXXBindTemporaryExpr *BTE,
+ const LocationContext *LC);
+
+ /// Stop tracking the destructor that corresponds to an elided constructor.
+ static ProgramStateRef
+ cleanupElidedDestructor(ProgramStateRef State,
+ const CXXBindTemporaryExpr *BTE,
+ const LocationContext *LC);
+
+ /// Returns true if the given expression corresponds to a temporary that
+ /// was constructed for passing into an elidable copy/move constructor
+ /// and that constructor was actually elided.
+ static bool isDestructorElided(ProgramStateRef State,
+ const CXXBindTemporaryExpr *BTE,
+ const LocationContext *LC);
+
+ /// Check if all objects under construction have been fully constructed
+ /// for the given context range (including FromLC, not including ToLC).
+ /// This is useful for assertions. Also checks if elided destructors
+ /// were cleaned up.
+ static bool areAllObjectsFullyConstructed(ProgramStateRef State,
+ const LocationContext *FromLC,
+ const LocationContext *ToLC);
+};
+
+/// 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> :
+ public ProgramStatePartialTrait<const void*> {
+ static void *GDMIndex();
+};
+
+} // namespace ento
+
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPRENGINE_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
new file mode 100644
index 00000000..53b4bf60
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
@@ -0,0 +1,142 @@
+//===- FunctionSummary.h - Stores summaries of functions. -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a summary of a function gathered/used by static analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#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"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallBitVector.h"
+#include <cassert>
+#include <deque>
+#include <utility>
+
+namespace clang {
+namespace ento {
+
+using SetOfDecls = std::deque<Decl *>;
+using SetOfConstDecls = llvm::DenseSet<const Decl *>;
+
+class FunctionSummariesTy {
+ class FunctionSummary {
+ public:
+ /// Marks the IDs of the basic blocks visited during the analyzes.
+ llvm::SmallBitVector VisitedBasicBlocks;
+
+ /// Total number of blocks in the function.
+ unsigned TotalBasicBlocks : 30;
+
+ /// True if this function has been checked against the rules for which
+ /// functions may be inlined.
+ unsigned InlineChecked : 1;
+
+ /// True if this function may be inlined.
+ unsigned MayInline : 1;
+
+ /// The number of times the function has been inlined.
+ unsigned TimesInlined : 32;
+
+ FunctionSummary()
+ : TotalBasicBlocks(0), InlineChecked(0), MayInline(0),
+ TimesInlined(0) {}
+ };
+
+ using MapTy = llvm::DenseMap<const Decl *, FunctionSummary>;
+ MapTy Map;
+
+public:
+ MapTy::iterator findOrInsertSummary(const Decl *D) {
+ MapTy::iterator I = Map.find(D);
+ if (I != Map.end())
+ return I;
+
+ using KVPair = std::pair<const Decl *, FunctionSummary>;
+
+ I = Map.insert(KVPair(D, FunctionSummary())).first;
+ assert(I != Map.end());
+ return I;
+ }
+
+ void markMayInline(const Decl *D) {
+ MapTy::iterator I = findOrInsertSummary(D);
+ I->second.InlineChecked = 1;
+ I->second.MayInline = 1;
+ }
+
+ void markShouldNotInline(const Decl *D) {
+ MapTy::iterator I = findOrInsertSummary(D);
+ I->second.InlineChecked = 1;
+ I->second.MayInline = 0;
+ }
+
+ void markReachedMaxBlockCount(const Decl *D) {
+ markShouldNotInline(D);
+ }
+
+ Optional<bool> mayInline(const Decl *D) {
+ MapTy::const_iterator I = Map.find(D);
+ if (I != Map.end() && I->second.InlineChecked)
+ return I->second.MayInline;
+ return None;
+ }
+
+ void markVisitedBasicBlock(unsigned ID, const Decl* D, unsigned TotalIDs) {
+ MapTy::iterator I = findOrInsertSummary(D);
+ llvm::SmallBitVector &Blocks = I->second.VisitedBasicBlocks;
+ assert(ID < TotalIDs);
+ if (TotalIDs > Blocks.size()) {
+ Blocks.resize(TotalIDs);
+ I->second.TotalBasicBlocks = TotalIDs;
+ }
+ Blocks.set(ID);
+ }
+
+ unsigned getNumVisitedBasicBlocks(const Decl* D) {
+ MapTy::const_iterator I = Map.find(D);
+ if (I != Map.end())
+ return I->second.VisitedBasicBlocks.count();
+ return 0;
+ }
+
+ unsigned getNumTimesInlined(const Decl* D) {
+ MapTy::const_iterator I = Map.find(D);
+ if (I != Map.end())
+ return I->second.TimesInlined;
+ return 0;
+ }
+
+ void bumpNumTimesInlined(const Decl* D) {
+ MapTy::iterator I = findOrInsertSummary(D);
+ I->second.TimesInlined++;
+ }
+
+ /// Get the percentage of the reachable blocks.
+ unsigned getPercentBlocksReachable(const Decl *D) {
+ MapTy::const_iterator I = Map.find(D);
+ if (I != Map.end())
+ return ((I->second.VisitedBasicBlocks.count() * 100) /
+ I->second.TotalBasicBlocks);
+ return 0;
+ }
+
+ unsigned getTotalNumBasicBlocks();
+ unsigned getTotalNumVisitedBasicBlocks();
+};
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
new file mode 100644
index 00000000..d25d2643
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
@@ -0,0 +1,49 @@
+//===--- LoopUnrolling.h - Unroll loops -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This header contains the declarations of functions which are used to decide
+/// which loops should be completely unrolled and mark their corresponding
+/// CFGBlocks. It is done by tracking a stack of loops in the ProgramState. This
+/// way specific loops can be marked as completely unrolled. For considering a
+/// loop to be completely unrolled it has to fulfill the following requirements:
+/// - Currently only forStmts can be considered.
+/// - The bound has to be known.
+/// - The counter variable has not escaped before/in the body of the loop and
+/// changed only in the increment statement corresponding to the loop. It also
+/// has to be initialized by a literal in the corresponding initStmt.
+/// - Does not contain goto, switch and returnStmt.
+///
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPUNROLLING_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPUNROLLING_H
+
+#include "clang/Analysis/CFG.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+namespace clang {
+namespace ento {
+class AnalysisManager;
+
+/// Returns if the given State indicates that is inside a completely unrolled
+/// loop.
+bool isUnrolledState(ProgramStateRef State);
+
+/// Updates the stack of loops contained by the ProgramState.
+ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx,
+ ExplodedNode* Pred, unsigned maxVisitOnPath);
+
+/// Updates the given ProgramState. In current implementation it removes the top
+/// element of the stack of loops.
+ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State);
+
+} // end namespace ento
+} // end namespace clang
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
new file mode 100644
index 00000000..7484a51b
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
@@ -0,0 +1,35 @@
+//===--- LoopWidening.h - Widen loops ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// 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 {
+
+/// 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/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
new file mode 100644
index 00000000..071e3508
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -0,0 +1,1488 @@
+//==- MemRegion.h - Abstract memory regions for static analysis -*- C++ -*--==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines MemRegion and its subclasses. MemRegion defines a
+// partially-typed abstraction of memory useful for path-sensitive dataflow
+// analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Type.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include <cassert>
+#include <cstdint>
+#include <limits>
+#include <string>
+#include <utility>
+
+namespace clang {
+
+class AnalysisDeclContext;
+class CXXRecordDecl;
+class Decl;
+class LocationContext;
+class StackFrameContext;
+
+namespace ento {
+
+class CodeTextRegion;
+class MemRegion;
+class MemRegionManager;
+class MemSpaceRegion;
+class SValBuilder;
+class SymbolicRegion;
+class VarRegion;
+
+/// Represent a region's offset within the top level base region.
+class RegionOffset {
+ /// The base region.
+ const MemRegion *R = nullptr;
+
+ /// The bit offset within the base region. Can be negative.
+ int64_t Offset;
+
+public:
+ // We're using a const instead of an enumeration due to the size required;
+ // Visual Studio will only create enumerations of size int, not long long.
+ static const int64_t Symbolic = std::numeric_limits<int64_t>::max();
+
+ RegionOffset() = default;
+ RegionOffset(const MemRegion *r, int64_t off) : R(r), Offset(off) {}
+
+ const MemRegion *getRegion() const { return R; }
+
+ bool hasSymbolicOffset() const { return Offset == Symbolic; }
+
+ int64_t getOffset() const {
+ assert(!hasSymbolicOffset());
+ return Offset;
+ }
+
+ bool isValid() const { return R; }
+};
+
+//===----------------------------------------------------------------------===//
+// Base region classes.
+//===----------------------------------------------------------------------===//
+
+/// MemRegion - The root abstract class for all memory regions.
+class MemRegion : public llvm::FoldingSetNode {
+public:
+ enum Kind {
+#define REGION(Id, Parent) Id ## Kind,
+#define REGION_RANGE(Id, First, Last) BEGIN_##Id = First, END_##Id = Last,
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
+ };
+
+private:
+ const Kind kind;
+ mutable Optional<RegionOffset> cachedOffset;
+
+protected:
+ MemRegion(Kind k) : kind(k) {}
+ virtual ~MemRegion();
+
+public:
+ ASTContext &getContext() const;
+
+ virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0;
+
+ virtual MemRegionManager* getMemRegionManager() const = 0;
+
+ const MemSpaceRegion *getMemorySpace() const;
+
+ const MemRegion *getBaseRegion() const;
+
+ /// Recursively retrieve the region of the most derived class instance of
+ /// regions of C++ base class instances.
+ const MemRegion *getMostDerivedObjectRegion() const;
+
+ /// Check if the region is a subregion of the given region.
+ /// Each region is a subregion of itself.
+ virtual bool isSubRegionOf(const MemRegion *R) const;
+
+ const MemRegion *StripCasts(bool StripBaseAndDerivedCasts = true) const;
+
+ /// If this is a symbolic region, returns the region. Otherwise,
+ /// goes up the base chain looking for the first symbolic base region.
+ const SymbolicRegion *getSymbolicBase() const;
+
+ bool hasGlobalsOrParametersStorage() const;
+
+ bool hasStackStorage() const;
+
+ bool hasStackNonParametersStorage() const;
+
+ bool hasStackParametersStorage() const;
+
+ /// Compute the offset within the top level memory object.
+ RegionOffset getAsOffset() const;
+
+ /// Get a string representation of a region for debug use.
+ std::string getString() const;
+
+ virtual void dumpToStream(raw_ostream &os) const;
+
+ void dump() const;
+
+ /// Returns true if this region can be printed in a user-friendly way.
+ virtual bool canPrintPretty() const;
+
+ /// Print the region for use in diagnostics.
+ virtual void printPretty(raw_ostream &os) const;
+
+ /// Returns true if this region's textual representation can be used
+ /// as part of a larger expression.
+ virtual bool canPrintPrettyAsExpr() const;
+
+ /// Print the region as expression.
+ ///
+ /// When this region represents a subexpression, the method is for printing
+ /// an expression containing it.
+ virtual void printPrettyAsExpr(raw_ostream &os) const;
+
+ Kind getKind() const { return kind; }
+
+ template<typename RegionTy> const RegionTy* getAs() const;
+
+ virtual bool isBoundable() const { return false; }
+
+ /// Get descriptive name for memory region. The name is obtained from
+ /// the variable/field declaration retrieved from the memory region.
+ /// Regions that point to an element of an array are returned as: "arr[0]".
+ /// Regions that point to a struct are returned as: "st.var".
+ //
+ /// \param UseQuotes Set if the name should be quoted.
+ ///
+ /// \returns variable name for memory region
+ std::string getDescriptiveName(bool UseQuotes = true) const;
+
+ /// Retrieve source range from memory region. The range retrieval
+ /// is based on the decl obtained from the memory region.
+ /// For a VarRegion the range of the base region is returned.
+ /// For a FieldRegion the range of the field is returned.
+ /// If no declaration is found, an empty source range is returned.
+ /// The client is responsible for checking if the returned range is valid.
+ ///
+ /// \returns source range for declaration retrieved from memory region
+ SourceRange sourceRange() const;
+};
+
+/// MemSpaceRegion - A memory region that represents a "memory space";
+/// for example, the set of global variables, the stack frame, etc.
+class MemSpaceRegion : public MemRegion {
+protected:
+ MemRegionManager *Mgr;
+
+ MemSpaceRegion(MemRegionManager *mgr, Kind k) : MemRegion(k), Mgr(mgr) {
+ assert(classof(this));
+ assert(mgr);
+ }
+
+ MemRegionManager* getMemRegionManager() const override { return Mgr; }
+
+public:
+ bool isBoundable() const override { return false; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override;
+
+ static bool classof(const MemRegion *R) {
+ Kind k = R->getKind();
+ return k >= BEGIN_MEMSPACES && k <= END_MEMSPACES;
+ }
+};
+
+/// CodeSpaceRegion - The memory space that holds the executable code of
+/// functions and blocks.
+class CodeSpaceRegion : public MemSpaceRegion {
+ friend class MemRegionManager;
+
+ CodeSpaceRegion(MemRegionManager *mgr)
+ : MemSpaceRegion(mgr, CodeSpaceRegionKind) {}
+
+public:
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == CodeSpaceRegionKind;
+ }
+};
+
+class GlobalsSpaceRegion : public MemSpaceRegion {
+ virtual void anchor();
+
+protected:
+ GlobalsSpaceRegion(MemRegionManager *mgr, Kind k) : MemSpaceRegion(mgr, k) {
+ assert(classof(this));
+ }
+
+public:
+ static bool classof(const MemRegion *R) {
+ Kind k = R->getKind();
+ return k >= BEGIN_GLOBAL_MEMSPACES && k <= END_GLOBAL_MEMSPACES;
+ }
+};
+
+/// The region of the static variables within the current CodeTextRegion
+/// scope.
+///
+/// Currently, only the static locals are placed there, so we know that these
+/// variables do not get invalidated by calls to other functions.
+class StaticGlobalSpaceRegion : public GlobalsSpaceRegion {
+ friend class MemRegionManager;
+
+ const CodeTextRegion *CR;
+
+ StaticGlobalSpaceRegion(MemRegionManager *mgr, const CodeTextRegion *cr)
+ : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {
+ assert(cr);
+ }
+
+public:
+ void Profile(llvm::FoldingSetNodeID &ID) const override;
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ const CodeTextRegion *getCodeRegion() const { return CR; }
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == StaticGlobalSpaceRegionKind;
+ }
+};
+
+/// The region for all the non-static global variables.
+///
+/// This class is further split into subclasses for efficient implementation of
+/// invalidating a set of related global values as is done in
+/// RegionStoreManager::invalidateRegions (instead of finding all the dependent
+/// globals, we invalidate the whole parent region).
+class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion {
+ void anchor() override;
+
+protected:
+ NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k)
+ : GlobalsSpaceRegion(mgr, k) {
+ assert(classof(this));
+ }
+
+public:
+ static bool classof(const MemRegion *R) {
+ Kind k = R->getKind();
+ return k >= BEGIN_NON_STATIC_GLOBAL_MEMSPACES &&
+ k <= END_NON_STATIC_GLOBAL_MEMSPACES;
+ }
+};
+
+/// The region containing globals which are defined in system/external
+/// headers and are considered modifiable by system calls (ex: errno).
+class GlobalSystemSpaceRegion : public NonStaticGlobalSpaceRegion {
+ friend class MemRegionManager;
+
+ GlobalSystemSpaceRegion(MemRegionManager *mgr)
+ : NonStaticGlobalSpaceRegion(mgr, GlobalSystemSpaceRegionKind) {}
+
+public:
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == GlobalSystemSpaceRegionKind;
+ }
+};
+
+/// The region containing globals which are considered not to be modified
+/// or point to data which could be modified as a result of a function call
+/// (system or internal). Ex: Const global scalars would be modeled as part of
+/// this region. This region also includes most system globals since they have
+/// low chance of being modified.
+class GlobalImmutableSpaceRegion : public NonStaticGlobalSpaceRegion {
+ friend class MemRegionManager;
+
+ GlobalImmutableSpaceRegion(MemRegionManager *mgr)
+ : NonStaticGlobalSpaceRegion(mgr, GlobalImmutableSpaceRegionKind) {}
+
+public:
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == GlobalImmutableSpaceRegionKind;
+ }
+};
+
+/// The region containing globals which can be modified by calls to
+/// "internally" defined functions - (for now just) functions other then system
+/// calls.
+class GlobalInternalSpaceRegion : public NonStaticGlobalSpaceRegion {
+ friend class MemRegionManager;
+
+ GlobalInternalSpaceRegion(MemRegionManager *mgr)
+ : NonStaticGlobalSpaceRegion(mgr, GlobalInternalSpaceRegionKind) {}
+
+public:
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == GlobalInternalSpaceRegionKind;
+ }
+};
+
+class HeapSpaceRegion : public MemSpaceRegion {
+ friend class MemRegionManager;
+
+ HeapSpaceRegion(MemRegionManager *mgr)
+ : MemSpaceRegion(mgr, HeapSpaceRegionKind) {}
+
+public:
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == HeapSpaceRegionKind;
+ }
+};
+
+class UnknownSpaceRegion : public MemSpaceRegion {
+ friend class MemRegionManager;
+
+ UnknownSpaceRegion(MemRegionManager *mgr)
+ : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {}
+
+public:
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == UnknownSpaceRegionKind;
+ }
+};
+
+class StackSpaceRegion : public MemSpaceRegion {
+ virtual void anchor();
+
+ const StackFrameContext *SFC;
+
+protected:
+ StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc)
+ : MemSpaceRegion(mgr, k), SFC(sfc) {
+ assert(classof(this));
+ assert(sfc);
+ }
+
+public:
+ const StackFrameContext *getStackFrame() const { return SFC; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override;
+
+ static bool classof(const MemRegion *R) {
+ Kind k = R->getKind();
+ return k >= BEGIN_STACK_MEMSPACES && k <= END_STACK_MEMSPACES;
+ }
+};
+
+class StackLocalsSpaceRegion : public StackSpaceRegion {
+ friend class MemRegionManager;
+
+ StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
+ : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {}
+
+public:
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == StackLocalsSpaceRegionKind;
+ }
+};
+
+class StackArgumentsSpaceRegion : public StackSpaceRegion {
+private:
+ friend class MemRegionManager;
+
+ StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
+ : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {}
+
+public:
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == StackArgumentsSpaceRegionKind;
+ }
+};
+
+/// SubRegion - A region that subsets another larger region. Most regions
+/// are subclasses of SubRegion.
+class SubRegion : public MemRegion {
+ virtual void anchor();
+
+protected:
+ const MemRegion* superRegion;
+
+ SubRegion(const MemRegion *sReg, Kind k) : MemRegion(k), superRegion(sReg) {
+ assert(classof(this));
+ assert(sReg);
+ }
+
+public:
+ const MemRegion* getSuperRegion() const {
+ return superRegion;
+ }
+
+ /// getExtent - Returns the size of the region in bytes.
+ virtual DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const {
+ return UnknownVal();
+ }
+
+ MemRegionManager* getMemRegionManager() const override;
+
+ bool isSubRegionOf(const MemRegion* R) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() > END_MEMSPACES;
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// MemRegion subclasses.
+//===----------------------------------------------------------------------===//
+
+/// AllocaRegion - A region that represents an untyped blob of bytes created
+/// by a call to 'alloca'.
+class AllocaRegion : public SubRegion {
+ friend class MemRegionManager;
+
+ // Block counter. Used to distinguish different pieces of memory allocated by
+ // alloca at the same call site.
+ unsigned Cnt;
+
+ const Expr *Ex;
+
+ AllocaRegion(const Expr *ex, unsigned cnt, const MemSpaceRegion *superRegion)
+ : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {
+ assert(Ex);
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex,
+ unsigned Cnt, const MemRegion *superRegion);
+
+public:
+ const Expr *getExpr() const { return Ex; }
+
+ bool isBoundable() const override { return true; }
+
+ DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
+
+ void Profile(llvm::FoldingSetNodeID& ID) const override;
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == AllocaRegionKind;
+ }
+};
+
+/// TypedRegion - An abstract class representing regions that are typed.
+class TypedRegion : public SubRegion {
+ void anchor() override;
+
+protected:
+ TypedRegion(const MemRegion *sReg, Kind k) : SubRegion(sReg, k) {
+ assert(classof(this));
+ }
+
+public:
+ virtual QualType getLocationType() const = 0;
+
+ QualType getDesugaredLocationType(ASTContext &Context) const {
+ return getLocationType().getDesugaredType(Context);
+ }
+
+ bool isBoundable() const override { return true; }
+
+ static bool classof(const MemRegion* R) {
+ unsigned k = R->getKind();
+ return k >= BEGIN_TYPED_REGIONS && k <= END_TYPED_REGIONS;
+ }
+};
+
+/// TypedValueRegion - An abstract class representing regions having a typed value.
+class TypedValueRegion : public TypedRegion {
+ void anchor() override;
+
+protected:
+ TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {
+ assert(classof(this));
+ }
+
+public:
+ virtual QualType getValueType() const = 0;
+
+ QualType getLocationType() const override {
+ // FIXME: We can possibly optimize this later to cache this value.
+ QualType T = getValueType();
+ ASTContext &ctx = getContext();
+ if (T->getAs<ObjCObjectType>())
+ return ctx.getObjCObjectPointerType(T);
+ return ctx.getPointerType(getValueType());
+ }
+
+ QualType getDesugaredValueType(ASTContext &Context) const {
+ QualType T = getValueType();
+ return T.getTypePtrOrNull() ? T.getDesugaredType(Context) : T;
+ }
+
+ DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
+
+ static bool classof(const MemRegion* R) {
+ unsigned k = R->getKind();
+ return k >= BEGIN_TYPED_VALUE_REGIONS && k <= END_TYPED_VALUE_REGIONS;
+ }
+};
+
+class CodeTextRegion : public TypedRegion {
+ void anchor() override;
+
+protected:
+ CodeTextRegion(const MemSpaceRegion *sreg, Kind k) : TypedRegion(sreg, k) {
+ assert(classof(this));
+ }
+
+public:
+ bool isBoundable() const override { return false; }
+
+ static bool classof(const MemRegion* R) {
+ Kind k = R->getKind();
+ return k >= BEGIN_CODE_TEXT_REGIONS && k <= END_CODE_TEXT_REGIONS;
+ }
+};
+
+/// FunctionCodeRegion - A region that represents code texts of function.
+class FunctionCodeRegion : public CodeTextRegion {
+ friend class MemRegionManager;
+
+ const NamedDecl *FD;
+
+ FunctionCodeRegion(const NamedDecl *fd, const CodeSpaceRegion* sreg)
+ : CodeTextRegion(sreg, FunctionCodeRegionKind), FD(fd) {
+ assert(isa<ObjCMethodDecl>(fd) || isa<FunctionDecl>(fd));
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD,
+ const MemRegion*);
+
+public:
+ QualType getLocationType() const override {
+ const ASTContext &Ctx = getContext();
+ if (const auto *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 {};
+ }
+
+ const NamedDecl *getDecl() const {
+ return FD;
+ }
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ void Profile(llvm::FoldingSetNodeID& ID) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == FunctionCodeRegionKind;
+ }
+};
+
+/// BlockCodeRegion - A region that represents code texts of blocks (closures).
+/// Blocks are represented with two kinds of regions. BlockCodeRegions
+/// represent the "code", while BlockDataRegions represent instances of blocks,
+/// which correspond to "code+data". The distinction is important, because
+/// like a closure a block captures the values of externally referenced
+/// variables.
+class BlockCodeRegion : public CodeTextRegion {
+ friend class MemRegionManager;
+
+ const BlockDecl *BD;
+ AnalysisDeclContext *AC;
+ CanQualType locTy;
+
+ BlockCodeRegion(const BlockDecl *bd, CanQualType lTy,
+ AnalysisDeclContext *ac, const CodeSpaceRegion* sreg)
+ : CodeTextRegion(sreg, BlockCodeRegionKind), BD(bd), AC(ac), locTy(lTy) {
+ assert(bd);
+ assert(ac);
+ assert(lTy->getTypePtr()->isBlockPointerType());
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD,
+ CanQualType, const AnalysisDeclContext*,
+ const MemRegion*);
+
+public:
+ QualType getLocationType() const override {
+ return locTy;
+ }
+
+ const BlockDecl *getDecl() const {
+ return BD;
+ }
+
+ AnalysisDeclContext *getAnalysisDeclContext() const { return AC; }
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ void Profile(llvm::FoldingSetNodeID& ID) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == BlockCodeRegionKind;
+ }
+};
+
+/// BlockDataRegion - A region that represents a block instance.
+/// Blocks are represented with two kinds of regions. BlockCodeRegions
+/// represent the "code", while BlockDataRegions represent instances of blocks,
+/// 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 TypedRegion {
+ friend class MemRegionManager;
+
+ const BlockCodeRegion *BC;
+ const LocationContext *LC; // Can be null
+ unsigned BlockCount;
+ void *ReferencedVars = nullptr;
+ void *OriginalVars = nullptr;
+
+ BlockDataRegion(const BlockCodeRegion *bc, const LocationContext *lc,
+ unsigned count, const MemSpaceRegion *sreg)
+ : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
+ BlockCount(count) {
+ assert(bc);
+ assert(lc);
+ assert(isa<GlobalImmutableSpaceRegion>(sreg) ||
+ isa<StackLocalsSpaceRegion>(sreg) ||
+ isa<UnknownSpaceRegion>(sreg));
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *,
+ const LocationContext *, unsigned,
+ const MemRegion *);
+
+public:
+ const BlockCodeRegion *getCodeRegion() const { return BC; }
+
+ const BlockDecl *getDecl() const { return BC->getDecl(); }
+
+ QualType getLocationType() const override { return BC->getLocationType(); }
+
+ class referenced_vars_iterator {
+ const MemRegion * const *R;
+ const MemRegion * const *OriginalR;
+
+ public:
+ explicit referenced_vars_iterator(const MemRegion * const *r,
+ const MemRegion * const *originalR)
+ : R(r), OriginalR(originalR) {}
+
+ const VarRegion *getCapturedRegion() const {
+ return cast<VarRegion>(*R);
+ }
+
+ const VarRegion *getOriginalRegion() const {
+ return cast<VarRegion>(*OriginalR);
+ }
+
+ bool operator==(const referenced_vars_iterator &I) const {
+ assert((R == nullptr) == (I.R == nullptr));
+ return I.R == R;
+ }
+
+ bool operator!=(const referenced_vars_iterator &I) const {
+ assert((R == nullptr) == (I.R == nullptr));
+ return I.R != R;
+ }
+
+ referenced_vars_iterator &operator++() {
+ ++R;
+ ++OriginalR;
+ return *this;
+ }
+ };
+
+ /// Return the original region for a captured region, if
+ /// one exists.
+ const VarRegion *getOriginalRegion(const VarRegion *VR) const;
+
+ referenced_vars_iterator referenced_vars_begin() const;
+ referenced_vars_iterator referenced_vars_end() const;
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ void Profile(llvm::FoldingSetNodeID& ID) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == BlockDataRegionKind;
+ }
+
+private:
+ void LazyInitializeReferencedVars();
+ std::pair<const VarRegion *, const VarRegion *>
+ getCaptureRegions(const VarDecl *VD);
+};
+
+/// SymbolicRegion - A special, "non-concrete" region. Unlike other region
+/// classes, SymbolicRegion represents a region that serves as an alias for
+/// either a real region, a NULL pointer, etc. It essentially is used to
+/// map the concept of symbolic values into the domain of regions. Symbolic
+/// regions do not need to be typed.
+class SymbolicRegion : public SubRegion {
+ friend class MemRegionManager;
+
+ const SymbolRef sym;
+
+ SymbolicRegion(const SymbolRef s, const MemSpaceRegion *sreg)
+ : SubRegion(sreg, SymbolicRegionKind), sym(s) {
+ // Because pointer arithmetic is represented by ElementRegion layers,
+ // the base symbol here should not contain any arithmetic.
+ assert(s && isa<SymbolData>(s));
+ assert(s->getType()->isAnyPointerType() ||
+ s->getType()->isReferenceType() ||
+ s->getType()->isBlockPointerType());
+ assert(isa<UnknownSpaceRegion>(sreg) || isa<HeapSpaceRegion>(sreg));
+ }
+
+public:
+ SymbolRef getSymbol() const { return sym; }
+
+ bool isBoundable() const override { return true; }
+
+ DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
+
+ void Profile(llvm::FoldingSetNodeID& ID) const override;
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID,
+ SymbolRef sym,
+ const MemRegion* superRegion);
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == SymbolicRegionKind;
+ }
+};
+
+/// StringRegion - Region associated with a StringLiteral.
+class StringRegion : public TypedValueRegion {
+ friend class MemRegionManager;
+
+ const StringLiteral *Str;
+
+ StringRegion(const StringLiteral *str, const GlobalInternalSpaceRegion *sreg)
+ : TypedValueRegion(sreg, StringRegionKind), Str(str) {
+ assert(str);
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const StringLiteral *Str,
+ const MemRegion *superRegion);
+
+public:
+ const StringLiteral *getStringLiteral() const { return Str; }
+
+ QualType getValueType() const override { return Str->getType(); }
+
+ DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
+
+ bool isBoundable() const override { return false; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const override {
+ ProfileRegion(ID, Str, superRegion);
+ }
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == StringRegionKind;
+ }
+};
+
+/// The region associated with an ObjCStringLiteral.
+class ObjCStringRegion : public TypedValueRegion {
+ friend class MemRegionManager;
+
+ const ObjCStringLiteral *Str;
+
+ ObjCStringRegion(const ObjCStringLiteral *str,
+ const GlobalInternalSpaceRegion *sreg)
+ : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) {
+ assert(str);
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const ObjCStringLiteral *Str,
+ const MemRegion *superRegion);
+
+public:
+ const ObjCStringLiteral *getObjCStringLiteral() const { return Str; }
+
+ QualType getValueType() const override { return Str->getType(); }
+
+ bool isBoundable() const override { return false; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const override {
+ ProfileRegion(ID, Str, superRegion);
+ }
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == ObjCStringRegionKind;
+ }
+};
+
+/// CompoundLiteralRegion - A memory region representing a compound literal.
+/// Compound literals are essentially temporaries that are stack allocated
+/// or in the global constant pool.
+class CompoundLiteralRegion : public TypedValueRegion {
+ friend class MemRegionManager;
+
+ const CompoundLiteralExpr *CL;
+
+ CompoundLiteralRegion(const CompoundLiteralExpr *cl,
+ const MemSpaceRegion *sReg)
+ : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) {
+ assert(cl);
+ assert(isa<GlobalInternalSpaceRegion>(sReg) ||
+ isa<StackLocalsSpaceRegion>(sReg));
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const CompoundLiteralExpr *CL,
+ const MemRegion* superRegion);
+
+public:
+ QualType getValueType() const override { return CL->getType(); }
+
+ bool isBoundable() const override { return !CL->isFileScope(); }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const override;
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ const CompoundLiteralExpr *getLiteralExpr() const { return CL; }
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == CompoundLiteralRegionKind;
+ }
+};
+
+class DeclRegion : public TypedValueRegion {
+protected:
+ const ValueDecl *D;
+
+ DeclRegion(const ValueDecl *d, const MemRegion *sReg, Kind k)
+ : TypedValueRegion(sReg, k), D(d) {
+ assert(classof(this));
+ assert(d && d->isCanonicalDecl());
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D,
+ const MemRegion* superRegion, Kind k);
+
+public:
+ const ValueDecl *getDecl() const { return D; }
+ void Profile(llvm::FoldingSetNodeID& ID) const override;
+
+ static bool classof(const MemRegion* R) {
+ unsigned k = R->getKind();
+ return k >= BEGIN_DECL_REGIONS && k <= END_DECL_REGIONS;
+ }
+};
+
+class VarRegion : public DeclRegion {
+ friend class MemRegionManager;
+
+ // Constructors and private methods.
+ VarRegion(const VarDecl *vd, const MemRegion *sReg)
+ : DeclRegion(vd, sReg, VarRegionKind) {
+ // VarRegion appears in unknown space when it's a block variable as seen
+ // from a block using it, when this block is analyzed at top-level.
+ // Other block variables appear within block data regions,
+ // which, unlike everything else on this list, are not memory spaces.
+ assert(isa<GlobalsSpaceRegion>(sReg) || isa<StackSpaceRegion>(sReg) ||
+ isa<BlockDataRegion>(sReg) || isa<UnknownSpaceRegion>(sReg));
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD,
+ const MemRegion *superRegion) {
+ DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
+ }
+
+public:
+ void Profile(llvm::FoldingSetNodeID& ID) const override;
+
+ const VarDecl *getDecl() const { return cast<VarDecl>(D); }
+
+ const StackFrameContext *getStackFrame() const;
+
+ QualType getValueType() const override {
+ // FIXME: We can cache this if needed.
+ return getDecl()->getType();
+ }
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ bool canPrintPrettyAsExpr() const override;
+
+ void printPrettyAsExpr(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == VarRegionKind;
+ }
+};
+
+/// CXXThisRegion - Represents the region for the implicit 'this' parameter
+/// in a call to a C++ method. This region doesn't represent the object
+/// referred to by 'this', but rather 'this' itself.
+class CXXThisRegion : public TypedValueRegion {
+ friend class MemRegionManager;
+
+ CXXThisRegion(const PointerType *thisPointerTy,
+ const StackArgumentsSpaceRegion *sReg)
+ : TypedValueRegion(sReg, CXXThisRegionKind),
+ ThisPointerTy(thisPointerTy) {
+ assert(ThisPointerTy->getPointeeType()->getAsCXXRecordDecl() &&
+ "Invalid region type!");
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const PointerType *PT,
+ const MemRegion *sReg);
+
+public:
+ void Profile(llvm::FoldingSetNodeID &ID) const override;
+
+ QualType getValueType() const override {
+ return QualType(ThisPointerTy, 0);
+ }
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == CXXThisRegionKind;
+ }
+
+private:
+ const PointerType *ThisPointerTy;
+};
+
+class FieldRegion : public DeclRegion {
+ friend class MemRegionManager;
+
+ FieldRegion(const FieldDecl *fd, const SubRegion* sReg)
+ : DeclRegion(fd, sReg, FieldRegionKind) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD,
+ const MemRegion* superRegion) {
+ DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
+ }
+
+public:
+ const FieldDecl *getDecl() const { return cast<FieldDecl>(D); }
+
+ QualType getValueType() const override {
+ // FIXME: We can cache this if needed.
+ return getDecl()->getType();
+ }
+
+ DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ bool canPrintPretty() const override;
+ void printPretty(raw_ostream &os) const override;
+ bool canPrintPrettyAsExpr() const override;
+ void printPrettyAsExpr(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == FieldRegionKind;
+ }
+};
+
+class ObjCIvarRegion : public DeclRegion {
+ friend class MemRegionManager;
+
+ ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg);
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd,
+ const MemRegion* superRegion);
+
+public:
+ const ObjCIvarDecl *getDecl() const;
+ QualType getValueType() const override;
+
+ bool canPrintPrettyAsExpr() const override;
+ void printPrettyAsExpr(raw_ostream &os) const override;
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == ObjCIvarRegionKind;
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Auxiliary data classes for use with MemRegions.
+//===----------------------------------------------------------------------===//
+
+class RegionRawOffset {
+ friend class ElementRegion;
+
+ const MemRegion *Region;
+ CharUnits Offset;
+
+ RegionRawOffset(const MemRegion* reg, CharUnits offset = CharUnits::Zero())
+ : Region(reg), Offset(offset) {}
+
+public:
+ // FIXME: Eventually support symbolic offsets.
+ CharUnits getOffset() const { return Offset; }
+ const MemRegion *getRegion() const { return Region; }
+
+ void dumpToStream(raw_ostream &os) const;
+ void dump() const;
+};
+
+/// ElementRegion is used to represent both array elements and casts.
+class ElementRegion : public TypedValueRegion {
+ friend class MemRegionManager;
+
+ QualType ElementType;
+ NonLoc Index;
+
+ ElementRegion(QualType elementType, NonLoc Idx, const SubRegion *sReg)
+ : TypedValueRegion(sReg, ElementRegionKind), ElementType(elementType),
+ Index(Idx) {
+ assert((!Idx.getAs<nonloc::ConcreteInt>() ||
+ Idx.castAs<nonloc::ConcreteInt>().getValue().isSigned()) &&
+ "The index must be signed");
+ assert(!elementType.isNull() && !elementType->isVoidType() &&
+ "Invalid region type!");
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType,
+ SVal Idx, const MemRegion* superRegion);
+
+public:
+ NonLoc getIndex() const { return Index; }
+
+ QualType getValueType() const override { return ElementType; }
+
+ QualType getElementType() const { return ElementType; }
+
+ /// Compute the offset within the array. The array might also be a subobject.
+ RegionRawOffset getAsArrayOffset() const;
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ void Profile(llvm::FoldingSetNodeID& ID) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == ElementRegionKind;
+ }
+};
+
+// C++ temporary object associated with an expression.
+class CXXTempObjectRegion : public TypedValueRegion {
+ friend class MemRegionManager;
+
+ Expr const *Ex;
+
+ CXXTempObjectRegion(Expr const *E, MemSpaceRegion const *sReg)
+ : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) {
+ assert(E);
+ assert(isa<StackLocalsSpaceRegion>(sReg) ||
+ isa<GlobalInternalSpaceRegion>(sReg));
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID,
+ Expr const *E, const MemRegion *sReg);
+
+public:
+ const Expr *getExpr() const { return Ex; }
+
+ QualType getValueType() const override { return Ex->getType(); }
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == CXXTempObjectRegionKind;
+ }
+};
+
+// CXXBaseObjectRegion represents a base object within a C++ object. It is
+// identified by the base class declaration and the region of its parent object.
+class CXXBaseObjectRegion : public TypedValueRegion {
+ friend class MemRegionManager;
+
+ llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Data;
+
+ CXXBaseObjectRegion(const CXXRecordDecl *RD, bool IsVirtual,
+ const SubRegion *SReg)
+ : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {
+ assert(RD);
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD,
+ bool IsVirtual, const MemRegion *SReg);
+
+public:
+ const CXXRecordDecl *getDecl() const { return Data.getPointer(); }
+ bool isVirtual() const { return Data.getInt(); }
+
+ QualType getValueType() const override;
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override;
+
+ bool canPrintPrettyAsExpr() const override;
+
+ void printPrettyAsExpr(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *region) {
+ return region->getKind() == CXXBaseObjectRegionKind;
+ }
+};
+
+// CXXDerivedObjectRegion represents a derived-class object that surrounds
+// a C++ object. It is identified by the derived class declaration and the
+// region of its parent object. It is a bit counter-intuitive (but not otherwise
+// unseen) that this region represents a larger segment of memory that its
+// super-region.
+class CXXDerivedObjectRegion : public TypedValueRegion {
+ friend class MemRegionManager;
+
+ const CXXRecordDecl *DerivedD;
+
+ CXXDerivedObjectRegion(const CXXRecordDecl *DerivedD, const SubRegion *SReg)
+ : TypedValueRegion(SReg, CXXDerivedObjectRegionKind), DerivedD(DerivedD) {
+ assert(DerivedD);
+ // In case of a concrete region, it should always be possible to model
+ // the base-to-derived cast by undoing a previous derived-to-base cast,
+ // otherwise the cast is most likely ill-formed.
+ assert(SReg->getSymbolicBase() &&
+ "Should have unwrapped a base region instead!");
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD,
+ const MemRegion *SReg);
+
+public:
+ const CXXRecordDecl *getDecl() const { return DerivedD; }
+
+ QualType getValueType() const override;
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override;
+
+ bool canPrintPrettyAsExpr() const override;
+
+ void printPrettyAsExpr(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *region) {
+ return region->getKind() == CXXDerivedObjectRegionKind;
+ }
+};
+
+template<typename RegionTy>
+const RegionTy* MemRegion::getAs() const {
+ if (const auto *RT = dyn_cast<RegionTy>(this))
+ return RT;
+
+ return nullptr;
+}
+
+//===----------------------------------------------------------------------===//
+// MemRegionManager - Factory object for creating regions.
+//===----------------------------------------------------------------------===//
+
+class MemRegionManager {
+ ASTContext &C;
+ llvm::BumpPtrAllocator& A;
+ llvm::FoldingSet<MemRegion> Regions;
+
+ GlobalInternalSpaceRegion *InternalGlobals = nullptr;
+ GlobalSystemSpaceRegion *SystemGlobals = nullptr;
+ GlobalImmutableSpaceRegion *ImmutableGlobals = nullptr;
+
+ llvm::DenseMap<const StackFrameContext *, StackLocalsSpaceRegion *>
+ StackLocalsSpaceRegions;
+ llvm::DenseMap<const StackFrameContext *, StackArgumentsSpaceRegion *>
+ StackArgumentsSpaceRegions;
+ llvm::DenseMap<const CodeTextRegion *, StaticGlobalSpaceRegion *>
+ StaticsGlobalSpaceRegions;
+
+ HeapSpaceRegion *heap = nullptr;
+ UnknownSpaceRegion *unknown = nullptr;
+ CodeSpaceRegion *code = nullptr;
+
+public:
+ MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator &a) : C(c), A(a) {}
+ ~MemRegionManager();
+
+ ASTContext &getContext() { return C; }
+
+ llvm::BumpPtrAllocator &getAllocator() { return A; }
+
+ /// getStackLocalsRegion - Retrieve the memory region associated with the
+ /// specified stack frame.
+ const StackLocalsSpaceRegion *
+ getStackLocalsRegion(const StackFrameContext *STC);
+
+ /// getStackArgumentsRegion - Retrieve the memory region associated with
+ /// function/method arguments of the specified stack frame.
+ const StackArgumentsSpaceRegion *
+ getStackArgumentsRegion(const StackFrameContext *STC);
+
+ /// getGlobalsRegion - Retrieve the memory region associated with
+ /// global variables.
+ const GlobalsSpaceRegion *getGlobalsRegion(
+ MemRegion::Kind K = MemRegion::GlobalInternalSpaceRegionKind,
+ const CodeTextRegion *R = nullptr);
+
+ /// getHeapRegion - Retrieve the memory region associated with the
+ /// generic "heap".
+ const HeapSpaceRegion *getHeapRegion();
+
+ /// getUnknownRegion - Retrieve the memory region associated with unknown
+ /// memory space.
+ const UnknownSpaceRegion *getUnknownRegion();
+
+ const CodeSpaceRegion *getCodeRegion();
+
+ /// getAllocaRegion - Retrieve a region associated with a call to alloca().
+ const AllocaRegion *getAllocaRegion(const Expr *Ex, unsigned Cnt,
+ const LocationContext *LC);
+
+ /// getCompoundLiteralRegion - Retrieve the region associated with a
+ /// given CompoundLiteral.
+ const CompoundLiteralRegion*
+ getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
+ const LocationContext *LC);
+
+ /// getCXXThisRegion - Retrieve the [artificial] region associated with the
+ /// parameter 'this'.
+ const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy,
+ const LocationContext *LC);
+
+ /// Retrieve or create a "symbolic" memory region.
+ const SymbolicRegion* getSymbolicRegion(SymbolRef Sym);
+
+ /// Return a unique symbolic region belonging to heap memory space.
+ const SymbolicRegion *getSymbolicHeapRegion(SymbolRef sym);
+
+ const StringRegion *getStringRegion(const StringLiteral *Str);
+
+ const ObjCStringRegion *getObjCStringRegion(const ObjCStringLiteral *Str);
+
+ /// getVarRegion - Retrieve or create the memory region associated with
+ /// a specified VarDecl and LocationContext.
+ const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC);
+
+ /// getVarRegion - Retrieve or create the memory region associated with
+ /// a specified VarDecl and super region.
+ const VarRegion *getVarRegion(const VarDecl *D, const MemRegion *superR);
+
+ /// getElementRegion - Retrieve the memory region associated with the
+ /// associated element type, index, and super region.
+ const ElementRegion *getElementRegion(QualType elementType, NonLoc Idx,
+ const SubRegion *superRegion,
+ ASTContext &Ctx);
+
+ const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER,
+ const SubRegion *superRegion) {
+ return getElementRegion(ER->getElementType(), ER->getIndex(),
+ superRegion, ER->getContext());
+ }
+
+ /// getFieldRegion - Retrieve or create the memory region associated with
+ /// a specified FieldDecl. 'superRegion' corresponds to the containing
+ /// memory region (which typically represents the memory representing
+ /// a structure or class).
+ const FieldRegion *getFieldRegion(const FieldDecl *fd,
+ const SubRegion* superRegion);
+
+ const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR,
+ const SubRegion *superRegion) {
+ return getFieldRegion(FR->getDecl(), superRegion);
+ }
+
+ /// getObjCIvarRegion - Retrieve or create the memory region associated with
+ /// a specified Objective-c instance variable. 'superRegion' corresponds
+ /// to the containing region (which typically represents the Objective-C
+ /// object).
+ const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl *ivd,
+ const SubRegion* superRegion);
+
+ const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex,
+ LocationContext const *LC);
+
+ /// Create a CXXBaseObjectRegion with the given base class for region
+ /// \p Super.
+ ///
+ /// The type of \p Super is assumed be a class deriving from \p BaseClass.
+ const CXXBaseObjectRegion *
+ getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const SubRegion *Super,
+ bool IsVirtual);
+
+ /// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different
+ /// super region.
+ const CXXBaseObjectRegion *
+ getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg,
+ const SubRegion *superRegion) {
+ return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion,
+ baseReg->isVirtual());
+ }
+
+ /// Create a CXXDerivedObjectRegion with the given derived class for region
+ /// \p Super. This should not be used for casting an existing
+ /// CXXBaseObjectRegion back to the derived type; instead, CXXBaseObjectRegion
+ /// should be removed.
+ const CXXDerivedObjectRegion *
+ getCXXDerivedObjectRegion(const CXXRecordDecl *BaseClass,
+ const SubRegion *Super);
+
+ const FunctionCodeRegion *getFunctionCodeRegion(const NamedDecl *FD);
+ const BlockCodeRegion *getBlockCodeRegion(const BlockDecl *BD,
+ CanQualType locTy,
+ AnalysisDeclContext *AC);
+
+ /// getBlockDataRegion - Get the memory region associated with an instance
+ /// of a block. Unlike many other MemRegions, the LocationContext*
+ /// argument is allowed to be NULL for cases where we have no known
+ /// context.
+ const BlockDataRegion *getBlockDataRegion(const BlockCodeRegion *bc,
+ const LocationContext *lc,
+ unsigned blockCount);
+
+ /// Create a CXXTempObjectRegion for temporaries which are lifetime-extended
+ /// by static references. This differs from getCXXTempObjectRegion in the
+ /// super-region used.
+ const CXXTempObjectRegion *getCXXStaticTempObjectRegion(const Expr *Ex);
+
+private:
+ template <typename RegionTy, typename SuperTy,
+ typename Arg1Ty>
+ RegionTy* getSubRegion(const Arg1Ty arg1,
+ const SuperTy* superRegion);
+
+ template <typename RegionTy, typename SuperTy,
+ typename Arg1Ty, typename Arg2Ty>
+ RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+ const SuperTy* superRegion);
+
+ template <typename RegionTy, typename SuperTy,
+ typename Arg1Ty, typename Arg2Ty, typename Arg3Ty>
+ RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+ const Arg3Ty arg3,
+ const SuperTy* superRegion);
+
+ template <typename REG>
+ const REG* LazyAllocate(REG*& region);
+
+ template <typename REG, typename ARG>
+ const REG* LazyAllocate(REG*& region, ARG a);
+};
+
+//===----------------------------------------------------------------------===//
+// Out-of-line member definitions.
+//===----------------------------------------------------------------------===//
+
+inline ASTContext &MemRegion::getContext() const {
+ return getMemRegionManager()->getContext();
+}
+
+//===----------------------------------------------------------------------===//
+// Means for storing region/symbol handling traits.
+//===----------------------------------------------------------------------===//
+
+/// Information about invalidation for a particular region/symbol.
+class RegionAndSymbolInvalidationTraits {
+ using StorageTypeForKinds = unsigned char;
+
+ llvm::DenseMap<const MemRegion *, StorageTypeForKinds> MRTraitsMap;
+ llvm::DenseMap<SymbolRef, StorageTypeForKinds> SymTraitsMap;
+
+ using const_region_iterator =
+ llvm::DenseMap<const MemRegion *, StorageTypeForKinds>::const_iterator;
+ using const_symbol_iterator =
+ llvm::DenseMap<SymbolRef, StorageTypeForKinds>::const_iterator;
+
+public:
+ /// Describes different invalidation traits.
+ enum InvalidationKinds {
+ /// Tells that a region's contents is not changed.
+ TK_PreserveContents = 0x1,
+
+ /// Suppress pointer-escaping of a region.
+ 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.
+ };
+
+ void setTrait(SymbolRef Sym, InvalidationKinds IK);
+ void setTrait(const MemRegion *MR, InvalidationKinds IK);
+ bool hasTrait(SymbolRef Sym, InvalidationKinds IK) const;
+ bool hasTrait(const MemRegion *MR, InvalidationKinds IK) const;
+};
+
+//===----------------------------------------------------------------------===//
+// Pretty-printing regions.
+//===----------------------------------------------------------------------===//
+inline raw_ostream &operator<<(raw_ostream &os, const MemRegion *R) {
+ R->dumpToStream(os);
+ return os;
+}
+
+} // namespace ento
+
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
new file mode 100644
index 00000000..3b1c638f
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -0,0 +1,909 @@
+//== ProgramState.h - Path-sensitive "State" for tracking values -*- C++ -*--=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the state of the program along the analysisa path.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H
+
+#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/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/Support/Allocator.h"
+#include <utility>
+
+namespace llvm {
+class APSInt;
+}
+
+namespace clang {
+class ASTContext;
+
+namespace ento {
+
+class AnalysisManager;
+class CallEvent;
+class CallEventManager;
+
+typedef std::unique_ptr<ConstraintManager>(*ConstraintManagerCreator)(
+ ProgramStateManager &, SubEngine *);
+typedef std::unique_ptr<StoreManager>(*StoreManagerCreator)(
+ ProgramStateManager &);
+typedef llvm::ImmutableMap<const SubRegion*, TaintTagType> TaintedSubRegions;
+
+//===----------------------------------------------------------------------===//
+// ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState.
+//===----------------------------------------------------------------------===//
+
+template <typename T> struct ProgramStatePartialTrait;
+
+template <typename T> struct ProgramStateTrait {
+ typedef typename T::data_type data_type;
+ static inline void *MakeVoidPtr(data_type D) { return (void*) D; }
+ static inline data_type MakeData(void *const* P) {
+ return P ? (data_type) *P : (data_type) 0;
+ }
+};
+
+/// \class ProgramState
+/// ProgramState - This class encapsulates:
+///
+/// 1. A mapping from expressions to values (Environment)
+/// 2. A mapping from locations to values (Store)
+/// 3. Constraints on symbolic values (GenericDataMap)
+///
+/// Together these represent the "abstract state" of a program.
+///
+/// ProgramState is intended to be used as a functional object; that is,
+/// once it is created and made "persistent" in a FoldingSet, its
+/// values will never change.
+class ProgramState : public llvm::FoldingSetNode {
+public:
+ typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy;
+ typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
+
+private:
+ void operator=(const ProgramState& R) = delete;
+
+ friend class ProgramStateManager;
+ friend class ExplodedGraph;
+ friend class ExplodedNode;
+
+ ProgramStateManager *stateMgr;
+ Environment Env; // Maps a Stmt to its current SVal.
+ Store store; // Maps a location to its current value.
+ GenericDataMap GDM; // Custom data stored by a client of this class.
+ unsigned refCount;
+
+ /// makeWithStore - Return a ProgramState with the same values as the current
+ /// state with the exception of using the specified Store.
+ ProgramStateRef makeWithStore(const StoreRef &store) const;
+
+ void setStore(const StoreRef &storeRef);
+
+public:
+ /// This ctor is used when creating the first ProgramState object.
+ ProgramState(ProgramStateManager *mgr, const Environment& env,
+ StoreRef st, GenericDataMap gdm);
+
+ /// Copy ctor - We must explicitly define this or else the "Next" ptr
+ /// in FoldingSetNode will also get copied.
+ ProgramState(const ProgramState &RHS);
+
+ ~ProgramState();
+
+ int64_t getID() const;
+
+ /// Return the ProgramStateManager associated with this state.
+ ProgramStateManager &getStateManager() const {
+ return *stateMgr;
+ }
+
+ AnalysisManager &getAnalysisManager() const;
+
+ /// Return the ConstraintManager.
+ ConstraintManager &getConstraintManager() const;
+
+ /// getEnvironment - Return the environment associated with this state.
+ /// The environment is the mapping from expressions to values.
+ const Environment& getEnvironment() const { return Env; }
+
+ /// Return the store associated with this state. The store
+ /// is a mapping from locations to values.
+ Store getStore() const { return store; }
+
+
+ /// getGDM - Return the generic data map associated with this state.
+ GenericDataMap getGDM() const { return GDM; }
+
+ void setGDM(GenericDataMap gdm) { GDM = gdm; }
+
+ /// Profile - Profile the contents of a ProgramState object for use in a
+ /// FoldingSet. Two ProgramState objects are considered equal if they
+ /// have the same Environment, Store, and GenericDataMap.
+ static void Profile(llvm::FoldingSetNodeID& ID, const ProgramState *V) {
+ V->Env.Profile(ID);
+ ID.AddPointer(V->store);
+ V->GDM.Profile(ID);
+ }
+
+ /// Profile - Used to profile the contents of this object for inclusion
+ /// in a FoldingSet.
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ Profile(ID, this);
+ }
+
+ BasicValueFactory &getBasicVals() const;
+ SymbolManager &getSymbolManager() const;
+
+ //==---------------------------------------------------------------------==//
+ // Constraints on values.
+ //==---------------------------------------------------------------------==//
+ //
+ // Each ProgramState records constraints on symbolic values. These constraints
+ // are managed using the ConstraintManager associated with a ProgramStateManager.
+ // As constraints gradually accrue on symbolic values, added constraints
+ // may conflict and indicate that a state is infeasible (as no real values
+ // could satisfy all the constraints). This is the principal mechanism
+ // for modeling path-sensitivity in ExprEngine/ProgramState.
+ //
+ // Various "assume" methods form the interface for adding constraints to
+ // symbolic values. A call to 'assume' indicates an assumption being placed
+ // on one or symbolic values. 'assume' methods take the following inputs:
+ //
+ // (1) A ProgramState object representing the current state.
+ //
+ // (2) The assumed constraint (which is specific to a given "assume" method).
+ //
+ // (3) A binary value "Assumption" that indicates whether the constraint is
+ // assumed to be true or false.
+ //
+ // The output of "assume*" is a new ProgramState object with the added constraints.
+ // If no new state is feasible, NULL is returned.
+ //
+
+ /// Assumes that the value of \p cond is zero (if \p assumption is "false")
+ /// or non-zero (if \p assumption is "true").
+ ///
+ /// This returns a new state with the added constraint on \p cond.
+ /// If no new state is feasible, NULL is returned.
+ LLVM_NODISCARD ProgramStateRef assume(DefinedOrUnknownSVal cond,
+ bool assumption) const;
+
+ /// Assumes both "true" and "false" for \p cond, and returns both
+ /// corresponding states (respectively).
+ ///
+ /// This is more efficient than calling assume() twice. Note that one (but not
+ /// both) of the returned states may be NULL.
+ LLVM_NODISCARD std::pair<ProgramStateRef, ProgramStateRef>
+ assume(DefinedOrUnknownSVal cond) const;
+
+ LLVM_NODISCARD ProgramStateRef
+ assumeInBound(DefinedOrUnknownSVal idx, 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.
+ LLVM_NODISCARD ProgramStateRef assumeInclusiveRange(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.
+ LLVM_NODISCARD std::pair<ProgramStateRef, ProgramStateRef>
+ assumeInclusiveRange(DefinedOrUnknownSVal Val, const llvm::APSInt &From,
+ const llvm::APSInt &To) const;
+
+ /// Check if the given SVal is not constrained to zero and is not
+ /// a zero constant.
+ ConditionTruthVal isNonNull(SVal V) const;
+
+ /// Check if the given SVal is constrained to zero or is a zero
+ /// constant.
+ ConditionTruthVal isNull(SVal V) const;
+
+ /// \return Whether values \p Lhs and \p Rhs are equal.
+ ConditionTruthVal areEqual(SVal Lhs, SVal Rhs) const;
+
+ /// Utility method for getting regions.
+ const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
+
+ //==---------------------------------------------------------------------==//
+ // Binding and retrieving values to/from the environment and symbolic store.
+ //==---------------------------------------------------------------------==//
+
+ /// Create a new state by binding the value 'V' to the statement 'S' in the
+ /// state's environment.
+ LLVM_NODISCARD ProgramStateRef BindExpr(const Stmt *S,
+ const LocationContext *LCtx, SVal V,
+ bool Invalidate = true) const;
+
+ LLVM_NODISCARD ProgramStateRef bindLoc(Loc location, SVal V,
+ const LocationContext *LCtx,
+ bool notifyChanges = true) const;
+
+ LLVM_NODISCARD ProgramStateRef bindLoc(SVal location, SVal V,
+ const LocationContext *LCtx) const;
+
+ /// Initializes the region of memory represented by \p loc with an initial
+ /// value. Once initialized, all values loaded from any sub-regions of that
+ /// region will be equal to \p V, unless overwritten later by the program.
+ /// This method should not be used on regions that are already initialized.
+ /// If you need to indicate that memory contents have suddenly become unknown
+ /// within a certain region of memory, consider invalidateRegions().
+ LLVM_NODISCARD ProgramStateRef
+ bindDefaultInitial(SVal loc, SVal V, const LocationContext *LCtx) const;
+
+ /// Performs C++ zero-initialization procedure on the region of memory
+ /// represented by \p loc.
+ LLVM_NODISCARD ProgramStateRef
+ bindDefaultZero(SVal loc, const LocationContext *LCtx) const;
+
+ LLVM_NODISCARD ProgramStateRef killBinding(Loc LV) const;
+
+ /// Returns the state with bindings for the given regions
+ /// cleared from the store.
+ ///
+ /// Optionally invalidates global regions as well.
+ ///
+ /// \param Regions the set of regions to be invalidated.
+ /// \param E the expression that caused the invalidation.
+ /// \param BlockCount The number of times the current basic block has been
+ // visited.
+ /// \param CausesPointerEscape the flag is set to true when
+ /// the invalidation entails escape of a symbol (representing a
+ /// pointer). For example, due to it being passed as an argument in a
+ /// call.
+ /// \param IS the set of invalidated symbols.
+ /// \param Call if non-null, the invalidated regions represent parameters to
+ /// the call and should be considered directly invalidated.
+ /// \param ITraits information about special handling for a particular
+ /// region/symbol.
+ LLVM_NODISCARD ProgramStateRef
+ invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E,
+ unsigned BlockCount, const LocationContext *LCtx,
+ bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr,
+ const CallEvent *Call = nullptr,
+ RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
+
+ LLVM_NODISCARD ProgramStateRef
+ invalidateRegions(ArrayRef<SVal> Regions, const Expr *E,
+ unsigned BlockCount, const LocationContext *LCtx,
+ bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr,
+ const CallEvent *Call = nullptr,
+ RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
+
+ /// enterStackFrame - Returns the state for entry to the given stack frame,
+ /// preserving the current state.
+ LLVM_NODISCARD ProgramStateRef enterStackFrame(
+ const CallEvent &Call, const StackFrameContext *CalleeCtx) const;
+
+ /// Get the lvalue for a base class object reference.
+ Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const;
+
+ /// Get the lvalue for a base class object reference.
+ Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super,
+ bool IsVirtual) const;
+
+ /// Get the lvalue for a variable reference.
+ Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
+
+ Loc getLValue(const CompoundLiteralExpr *literal,
+ const LocationContext *LC) const;
+
+ /// Get the lvalue for an ivar reference.
+ SVal getLValue(const ObjCIvarDecl *decl, SVal base) const;
+
+ /// Get the lvalue for a field reference.
+ SVal getLValue(const FieldDecl *decl, SVal Base) const;
+
+ /// Get the lvalue for an indirect field reference.
+ SVal getLValue(const IndirectFieldDecl *decl, SVal Base) const;
+
+ /// Get the lvalue for an array index.
+ SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const;
+
+ /// Returns the SVal bound to the statement 'S' in the state's environment.
+ SVal getSVal(const Stmt *S, const LocationContext *LCtx) const;
+
+ SVal getSValAsScalarOrLoc(const Stmt *Ex, const LocationContext *LCtx) const;
+
+ /// Return the value bound to the specified location.
+ /// Returns UnknownVal() if none found.
+ SVal getSVal(Loc LV, QualType T = QualType()) const;
+
+ /// Returns the "raw" SVal bound to LV before any value simplfication.
+ SVal getRawSVal(Loc LV, QualType T= QualType()) const;
+
+ /// Return the value bound to the specified location.
+ /// Returns UnknownVal() if none found.
+ SVal getSVal(const MemRegion* R, QualType T = QualType()) const;
+
+ /// Return the value bound to the specified location, assuming
+ /// that the value is a scalar integer or an enumeration or a pointer.
+ /// Returns UnknownVal() if none found or the region is not known to hold
+ /// a value of such type.
+ SVal getSValAsScalarOrLoc(const MemRegion *R) const;
+
+ using region_iterator = const MemRegion **;
+
+ /// Visits the symbols reachable from the given SVal using the provided
+ /// SymbolVisitor.
+ ///
+ /// This is a convenience API. Consider using ScanReachableSymbols class
+ /// directly when making multiple scans on the same state with the same
+ /// visitor to avoid repeated initialization cost.
+ /// \sa ScanReachableSymbols
+ bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const;
+
+ /// Visits the symbols reachable from the regions in the given
+ /// MemRegions range using the provided SymbolVisitor.
+ bool scanReachableSymbols(llvm::iterator_range<region_iterator> Reachable,
+ SymbolVisitor &visitor) const;
+
+ template <typename CB> CB scanReachableSymbols(SVal val) const;
+ template <typename CB> CB
+ scanReachableSymbols(llvm::iterator_range<region_iterator> Reachable) const;
+
+ /// Create a new state in which the statement is marked as tainted.
+ LLVM_NODISCARD ProgramStateRef
+ addTaint(const Stmt *S, const LocationContext *LCtx,
+ TaintTagType Kind = TaintTagGeneric) const;
+
+ /// Create a new state in which the value is marked as tainted.
+ LLVM_NODISCARD ProgramStateRef
+ addTaint(SVal V, TaintTagType Kind = TaintTagGeneric) const;
+
+ /// Create a new state in which the symbol is marked as tainted.
+ LLVM_NODISCARD ProgramStateRef addTaint(SymbolRef S,
+ TaintTagType Kind = TaintTagGeneric) const;
+
+ /// Create a new state in which the region symbol is marked as tainted.
+ LLVM_NODISCARD ProgramStateRef
+ addTaint(const MemRegion *R, TaintTagType Kind = TaintTagGeneric) const;
+
+ /// Create a new state in a which a sub-region of a given symbol is tainted.
+ /// This might be necessary when referring to regions that can not have an
+ /// individual symbol, e.g. if they are represented by the default binding of
+ /// a LazyCompoundVal.
+ LLVM_NODISCARD ProgramStateRef
+ addPartialTaint(SymbolRef ParentSym, const SubRegion *SubRegion,
+ TaintTagType Kind = TaintTagGeneric) const;
+
+ /// Check if the statement is tainted in the current state.
+ bool isTainted(const Stmt *S, const LocationContext *LCtx,
+ TaintTagType Kind = TaintTagGeneric) const;
+ bool isTainted(SVal V, TaintTagType Kind = TaintTagGeneric) const;
+ bool isTainted(SymbolRef Sym, TaintTagType Kind = TaintTagGeneric) const;
+ bool isTainted(const MemRegion *Reg, TaintTagType Kind=TaintTagGeneric) const;
+
+ //==---------------------------------------------------------------------==//
+ // Accessing the Generic Data Map (GDM).
+ //==---------------------------------------------------------------------==//
+
+ void *const* FindGDM(void *K) const;
+
+ template <typename T>
+ LLVM_NODISCARD ProgramStateRef
+ add(typename ProgramStateTrait<T>::key_type K) const;
+
+ template <typename T>
+ typename ProgramStateTrait<T>::data_type
+ get() const {
+ return ProgramStateTrait<T>::MakeData(FindGDM(ProgramStateTrait<T>::GDMIndex()));
+ }
+
+ template<typename T>
+ typename ProgramStateTrait<T>::lookup_type
+ get(typename ProgramStateTrait<T>::key_type key) const {
+ void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex());
+ return ProgramStateTrait<T>::Lookup(ProgramStateTrait<T>::MakeData(d), key);
+ }
+
+ template <typename T>
+ typename ProgramStateTrait<T>::context_type get_context() const;
+
+ template <typename T>
+ LLVM_NODISCARD ProgramStateRef
+ remove(typename ProgramStateTrait<T>::key_type K) const;
+
+ template <typename T>
+ LLVM_NODISCARD ProgramStateRef
+ remove(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::context_type C) const;
+
+ template <typename T> LLVM_NODISCARD ProgramStateRef remove() const;
+
+ template <typename T>
+ LLVM_NODISCARD ProgramStateRef
+ set(typename ProgramStateTrait<T>::data_type D) const;
+
+ template <typename T>
+ LLVM_NODISCARD ProgramStateRef
+ set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E) const;
+
+ template <typename T>
+ LLVM_NODISCARD ProgramStateRef
+ set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E,
+ typename ProgramStateTrait<T>::context_type C) const;
+
+ template<typename T>
+ bool contains(typename ProgramStateTrait<T>::key_type key) const {
+ void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex());
+ return ProgramStateTrait<T>::Contains(ProgramStateTrait<T>::MakeData(d), key);
+ }
+
+ // Pretty-printing.
+ void print(raw_ostream &Out, const char *nl = "\n", const char *sep = "",
+ const LocationContext *CurrentLC = nullptr) const;
+ void printDOT(raw_ostream &Out,
+ const LocationContext *CurrentLC = nullptr) const;
+ void printTaint(raw_ostream &Out, const char *nl = "\n") const;
+
+ void dump() const;
+ void dumpTaint() const;
+
+private:
+ friend void ProgramStateRetain(const ProgramState *state);
+ friend void ProgramStateRelease(const ProgramState *state);
+
+ /// \sa invalidateValues()
+ /// \sa invalidateRegions()
+ ProgramStateRef
+ invalidateRegionsImpl(ArrayRef<SVal> Values,
+ const Expr *E, unsigned BlockCount,
+ const LocationContext *LCtx,
+ bool ResultsInSymbolEscape,
+ InvalidatedSymbols *IS,
+ RegionAndSymbolInvalidationTraits *HTraits,
+ const CallEvent *Call) const;
+};
+
+//===----------------------------------------------------------------------===//
+// ProgramStateManager - Factory object for ProgramStates.
+//===----------------------------------------------------------------------===//
+
+class ProgramStateManager {
+ friend class ProgramState;
+ friend void ProgramStateRelease(const ProgramState *state);
+private:
+ /// Eng - The SubEngine that owns this state manager.
+ SubEngine *Eng; /* Can be null. */
+
+ EnvironmentManager EnvMgr;
+ std::unique_ptr<StoreManager> StoreMgr;
+ std::unique_ptr<ConstraintManager> ConstraintMgr;
+
+ ProgramState::GenericDataMap::Factory GDMFactory;
+ TaintedSubRegions::Factory TSRFactory;
+
+ typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy;
+ GDMContextsTy GDMContexts;
+
+ /// StateSet - FoldingSet containing all the states created for analyzing
+ /// a particular function. This is used to unique states.
+ llvm::FoldingSet<ProgramState> StateSet;
+
+ /// Object that manages the data for all created SVals.
+ std::unique_ptr<SValBuilder> svalBuilder;
+
+ /// Manages memory for created CallEvents.
+ std::unique_ptr<CallEventManager> CallEventMgr;
+
+ /// A BumpPtrAllocator to allocate states.
+ llvm::BumpPtrAllocator &Alloc;
+
+ /// A vector of ProgramStates that we can reuse.
+ std::vector<ProgramState *> freeStates;
+
+public:
+ ProgramStateManager(ASTContext &Ctx,
+ StoreManagerCreator CreateStoreManager,
+ ConstraintManagerCreator CreateConstraintManager,
+ llvm::BumpPtrAllocator& alloc,
+ SubEngine *subeng);
+
+ ~ProgramStateManager();
+
+ ProgramStateRef getInitialState(const LocationContext *InitLoc);
+
+ ASTContext &getContext() { return svalBuilder->getContext(); }
+ const ASTContext &getContext() const { return svalBuilder->getContext(); }
+
+ BasicValueFactory &getBasicVals() {
+ return svalBuilder->getBasicValueFactory();
+ }
+
+ SValBuilder &getSValBuilder() {
+ return *svalBuilder;
+ }
+
+ SymbolManager &getSymbolManager() {
+ return svalBuilder->getSymbolManager();
+ }
+ const SymbolManager &getSymbolManager() const {
+ return svalBuilder->getSymbolManager();
+ }
+
+ llvm::BumpPtrAllocator& getAllocator() { return Alloc; }
+
+ MemRegionManager& getRegionManager() {
+ return svalBuilder->getRegionManager();
+ }
+ const MemRegionManager &getRegionManager() const {
+ return svalBuilder->getRegionManager();
+ }
+
+ CallEventManager &getCallEventManager() { return *CallEventMgr; }
+
+ StoreManager &getStoreManager() { return *StoreMgr; }
+ ConstraintManager &getConstraintManager() { return *ConstraintMgr; }
+ SubEngine &getOwningEngine() { return *Eng; }
+
+ ProgramStateRef removeDeadBindings(ProgramStateRef St,
+ const StackFrameContext *LCtx,
+ SymbolReaper& SymReaper);
+
+public:
+
+ SVal ArrayToPointer(Loc Array, QualType ElementTy) {
+ return StoreMgr->ArrayToPointer(Array, ElementTy);
+ }
+
+ // Methods that manipulate the GDM.
+ ProgramStateRef addGDM(ProgramStateRef St, void *Key, void *Data);
+ ProgramStateRef removeGDM(ProgramStateRef state, void *Key);
+
+ // Methods that query & manipulate the Store.
+
+ void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler& F) {
+ StoreMgr->iterBindings(state->getStore(), F);
+ }
+
+ ProgramStateRef getPersistentState(ProgramState &Impl);
+ ProgramStateRef getPersistentStateWithGDM(ProgramStateRef FromState,
+ ProgramStateRef GDMState);
+
+ bool haveEqualEnvironments(ProgramStateRef S1, ProgramStateRef S2) {
+ return S1->Env == S2->Env;
+ }
+
+ bool haveEqualStores(ProgramStateRef S1, ProgramStateRef S2) {
+ return S1->store == S2->store;
+ }
+
+ //==---------------------------------------------------------------------==//
+ // Generic Data Map methods.
+ //==---------------------------------------------------------------------==//
+ //
+ // ProgramStateManager and ProgramState support a "generic data map" that allows
+ // different clients of ProgramState objects to embed arbitrary data within a
+ // ProgramState object. The generic data map is essentially an immutable map
+ // from a "tag" (that acts as the "key" for a client) and opaque values.
+ // Tags/keys and values are simply void* values. The typical way that clients
+ // generate unique tags are by taking the address of a static variable.
+ // Clients are responsible for ensuring that data values referred to by a
+ // the data pointer are immutable (and thus are essentially purely functional
+ // data).
+ //
+ // The templated methods below use the ProgramStateTrait<T> class
+ // to resolve keys into the GDM and to return data values to clients.
+ //
+
+ // Trait based GDM dispatch.
+ template <typename T>
+ ProgramStateRef set(ProgramStateRef st, typename ProgramStateTrait<T>::data_type D) {
+ return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::MakeVoidPtr(D));
+ }
+
+ template<typename T>
+ ProgramStateRef set(ProgramStateRef st,
+ typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type V,
+ typename ProgramStateTrait<T>::context_type C) {
+
+ return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Set(st->get<T>(), K, V, C)));
+ }
+
+ template <typename T>
+ ProgramStateRef add(ProgramStateRef st,
+ typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::context_type C) {
+ return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Add(st->get<T>(), K, C)));
+ }
+
+ template <typename T>
+ ProgramStateRef remove(ProgramStateRef st,
+ typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::context_type C) {
+
+ return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Remove(st->get<T>(), K, C)));
+ }
+
+ template <typename T>
+ ProgramStateRef remove(ProgramStateRef st) {
+ return removeGDM(st, ProgramStateTrait<T>::GDMIndex());
+ }
+
+ void *FindGDMContext(void *index,
+ void *(*CreateContext)(llvm::BumpPtrAllocator&),
+ void (*DeleteContext)(void*));
+
+ template <typename T>
+ typename ProgramStateTrait<T>::context_type get_context() {
+ void *p = FindGDMContext(ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::CreateContext,
+ ProgramStateTrait<T>::DeleteContext);
+
+ return ProgramStateTrait<T>::MakeContext(p);
+ }
+
+ void EndPath(ProgramStateRef St) {
+ ConstraintMgr->EndPath(St);
+ }
+};
+
+
+//===----------------------------------------------------------------------===//
+// 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
+{
+ return getStateManager().getRegionManager().getVarRegion(D, LC);
+}
+
+inline ProgramStateRef ProgramState::assume(DefinedOrUnknownSVal Cond,
+ bool Assumption) const {
+ if (Cond.isUnknown())
+ return this;
+
+ return getStateManager().ConstraintMgr
+ ->assume(this, Cond.castAs<DefinedSVal>(), Assumption);
+}
+
+inline std::pair<ProgramStateRef , ProgramStateRef >
+ProgramState::assume(DefinedOrUnknownSVal Cond) const {
+ if (Cond.isUnknown())
+ return std::make_pair(this, this);
+
+ return getStateManager().ConstraintMgr
+ ->assumeDual(this, Cond.castAs<DefinedSVal>());
+}
+
+inline ProgramStateRef ProgramState::assumeInclusiveRange(
+ 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->assumeInclusiveRange(
+ this, Val.castAs<NonLoc>(), From, To, Assumption);
+}
+
+inline std::pair<ProgramStateRef, ProgramStateRef>
+ProgramState::assumeInclusiveRange(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->assumeInclusiveRangeDual(
+ this, Val.castAs<NonLoc>(), From, To);
+}
+
+inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V, const LocationContext *LCtx) const {
+ if (Optional<Loc> L = LV.getAs<Loc>())
+ return bindLoc(*L, V, LCtx);
+ return this;
+}
+
+inline Loc ProgramState::getLValue(const CXXBaseSpecifier &BaseSpec,
+ const SubRegion *Super) const {
+ const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl();
+ return loc::MemRegionVal(
+ getStateManager().getRegionManager().getCXXBaseObjectRegion(
+ Base, Super, BaseSpec.isVirtual()));
+}
+
+inline Loc ProgramState::getLValue(const CXXRecordDecl *BaseClass,
+ const SubRegion *Super,
+ bool IsVirtual) const {
+ return loc::MemRegionVal(
+ getStateManager().getRegionManager().getCXXBaseObjectRegion(
+ BaseClass, Super, IsVirtual));
+}
+
+inline Loc ProgramState::getLValue(const VarDecl *VD,
+ const LocationContext *LC) const {
+ return getStateManager().StoreMgr->getLValueVar(VD, LC);
+}
+
+inline Loc ProgramState::getLValue(const CompoundLiteralExpr *literal,
+ const LocationContext *LC) const {
+ return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC);
+}
+
+inline SVal ProgramState::getLValue(const ObjCIvarDecl *D, SVal Base) const {
+ return getStateManager().StoreMgr->getLValueIvar(D, Base);
+}
+
+inline SVal ProgramState::getLValue(const FieldDecl *D, SVal Base) const {
+ return getStateManager().StoreMgr->getLValueField(D, Base);
+}
+
+inline SVal ProgramState::getLValue(const IndirectFieldDecl *D,
+ SVal Base) const {
+ StoreManager &SM = *getStateManager().StoreMgr;
+ for (const auto *I : D->chain()) {
+ Base = SM.getLValueField(cast<FieldDecl>(I), Base);
+ }
+
+ return Base;
+}
+
+inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{
+ if (Optional<NonLoc> N = Idx.getAs<NonLoc>())
+ return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base);
+ return UnknownVal();
+}
+
+inline SVal ProgramState::getSVal(const Stmt *Ex,
+ const LocationContext *LCtx) const{
+ return Env.getSVal(EnvironmentEntry(Ex, LCtx),
+ *getStateManager().svalBuilder);
+}
+
+inline SVal
+ProgramState::getSValAsScalarOrLoc(const Stmt *S,
+ const LocationContext *LCtx) const {
+ if (const Expr *Ex = dyn_cast<Expr>(S)) {
+ QualType T = Ex->getType();
+ if (Ex->isGLValue() || Loc::isLocType(T) ||
+ T->isIntegralOrEnumerationType())
+ return getSVal(S, LCtx);
+ }
+
+ return UnknownVal();
+}
+
+inline SVal ProgramState::getRawSVal(Loc LV, QualType T) const {
+ return getStateManager().StoreMgr->getBinding(getStore(), LV, T);
+}
+
+inline SVal ProgramState::getSVal(const MemRegion* R, QualType T) const {
+ return getStateManager().StoreMgr->getBinding(getStore(),
+ loc::MemRegionVal(R),
+ T);
+}
+
+inline BasicValueFactory &ProgramState::getBasicVals() const {
+ return getStateManager().getBasicVals();
+}
+
+inline SymbolManager &ProgramState::getSymbolManager() const {
+ return getStateManager().getSymbolManager();
+}
+
+template<typename T>
+ProgramStateRef ProgramState::add(typename ProgramStateTrait<T>::key_type K) const {
+ return getStateManager().add<T>(this, K, get_context<T>());
+}
+
+template <typename T>
+typename ProgramStateTrait<T>::context_type ProgramState::get_context() const {
+ return getStateManager().get_context<T>();
+}
+
+template<typename T>
+ProgramStateRef ProgramState::remove(typename ProgramStateTrait<T>::key_type K) const {
+ return getStateManager().remove<T>(this, K, get_context<T>());
+}
+
+template<typename T>
+ProgramStateRef ProgramState::remove(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::context_type C) const {
+ return getStateManager().remove<T>(this, K, C);
+}
+
+template <typename T>
+ProgramStateRef ProgramState::remove() const {
+ return getStateManager().remove<T>(this);
+}
+
+template<typename T>
+ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::data_type D) const {
+ return getStateManager().set<T>(this, D);
+}
+
+template<typename T>
+ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E) const {
+ return getStateManager().set<T>(this, K, E, get_context<T>());
+}
+
+template<typename T>
+ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E,
+ typename ProgramStateTrait<T>::context_type C) const {
+ return getStateManager().set<T>(this, K, E, C);
+}
+
+template <typename CB>
+CB ProgramState::scanReachableSymbols(SVal val) const {
+ CB cb(this);
+ scanReachableSymbols(val, cb);
+ return cb;
+}
+
+template <typename CB>
+CB ProgramState::scanReachableSymbols(
+ llvm::iterator_range<region_iterator> Reachable) const {
+ CB cb(this);
+ scanReachableSymbols(Reachable, cb);
+ return cb;
+}
+
+/// \class ScanReachableSymbols
+/// A utility class that visits the reachable symbols using a custom
+/// SymbolVisitor. Terminates recursive traversal when the visitor function
+/// returns false.
+class ScanReachableSymbols {
+ typedef llvm::DenseSet<const void*> VisitedItems;
+
+ VisitedItems visited;
+ ProgramStateRef state;
+ SymbolVisitor &visitor;
+public:
+ ScanReachableSymbols(ProgramStateRef st, SymbolVisitor &v)
+ : state(std::move(st)), visitor(v) {}
+
+ bool scan(nonloc::LazyCompoundVal val);
+ bool scan(nonloc::CompoundVal val);
+ bool scan(SVal val);
+ bool scan(const MemRegion *R);
+ bool scan(const SymExpr *sym);
+};
+
+} // end ento namespace
+
+} // end clang namespace
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
new file mode 100644
index 00000000..da82a55e
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
@@ -0,0 +1,328 @@
+//ProgramStateTrait.h - Partial implementations of ProgramStateTrait -*- C++ -*-
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines partial implementations of template specializations of
+// the class ProgramStateTrait<>. ProgramStateTrait<> is used by ProgramState
+// to implement set/get methods for manipulating a ProgramState's
+// generic data map.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H
+
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/ImmutableSet.h"
+#include "llvm/Support/Allocator.h"
+#include <cstdint>
+
+namespace clang {
+namespace ento {
+
+ template <typename T> struct ProgramStatePartialTrait;
+
+ /// Declares a program state trait for type \p Type called \p Name, and
+ /// introduce a type named \c NameTy.
+ /// The macro should not be used inside namespaces.
+ #define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type) \
+ namespace { \
+ class Name {}; \
+ using Name ## Ty = Type; \
+ } \
+ namespace clang { \
+ namespace ento { \
+ template <> \
+ struct ProgramStateTrait<Name> \
+ : public ProgramStatePartialTrait<Name ## Ty> { \
+ static void *GDMIndex() { static int Index; return &Index; } \
+ }; \
+ } \
+ }
+
+ /// Declares a factory for objects of type \p Type in the program state
+ /// manager. The type must provide a ::Factory sub-class. Commonly used for
+ /// ImmutableMap, ImmutableSet, ImmutableList. The macro should not be used
+ /// inside namespaces.
+ #define REGISTER_FACTORY_WITH_PROGRAMSTATE(Type) \
+ namespace clang { \
+ namespace ento { \
+ template <> \
+ struct ProgramStateTrait<Type> \
+ : public ProgramStatePartialTrait<Type> { \
+ static void *GDMIndex() { static int Index; return &Index; } \
+ }; \
+ } \
+ }
+
+ /// 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>
+
+ /// 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 map type \p Name and registers the factory
+ /// for such maps in the program state, but does not add the map itself
+ /// to the program state. Useful for managing lifetime of maps that are used
+ /// as elements of other program state data structures.
+ #define REGISTER_MAP_FACTORY_WITH_PROGRAMSTATE(Name, Key, Value) \
+ using Name = llvm::ImmutableMap<Key, Value>; \
+ REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)
+
+
+ /// 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 set type \p Name and registers the factory
+ /// for such sets in the program state, but does not add the set itself
+ /// to the program state. Useful for managing lifetime of sets that are used
+ /// as elements of other program state data structures.
+ #define REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(Name, Elem) \
+ using Name = llvm::ImmutableSet<Elem>; \
+ REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)
+
+
+ /// Declares an immutable list 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>)
+
+ /// Declares an immutable list of type \p Name and registers the factory
+ /// for such lists in the program state, but does not add the list itself
+ /// to the program state. Useful for managing lifetime of lists that are used
+ /// as elements of other program state data structures.
+ #define REGISTER_LIST_FACTORY_WITH_PROGRAMSTATE(Name, Elem) \
+ using Name = llvm::ImmutableList<Elem>; \
+ REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)
+
+
+ // Partial-specialization for ImmutableMap.
+ template <typename Key, typename Data, typename Info>
+ struct ProgramStatePartialTrait<llvm::ImmutableMap<Key, Data, Info>> {
+ using data_type = llvm::ImmutableMap<Key, Data, Info>;
+ using context_type = typename data_type::Factory &;
+ using key_type = Key;
+ using value_type = Data;
+ using lookup_type = const value_type *;
+
+ static data_type MakeData(void *const *p) {
+ return p ? data_type((typename data_type::TreeTy *) *p)
+ : data_type(nullptr);
+ }
+
+ static void *MakeVoidPtr(data_type B) {
+ return B.getRoot();
+ }
+
+ static lookup_type Lookup(data_type B, key_type K) {
+ return B.lookup(K);
+ }
+
+ static data_type Set(data_type B, key_type K, value_type E,
+ context_type F) {
+ return F.add(B, K, E);
+ }
+
+ static data_type Remove(data_type B, key_type K, context_type F) {
+ return F.remove(B, K);
+ }
+
+ static bool Contains(data_type B, key_type K) {
+ return B.contains(K);
+ }
+
+ static context_type MakeContext(void *p) {
+ return *((typename data_type::Factory *) p);
+ }
+
+ static void *CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ return new typename data_type::Factory(Alloc);
+ }
+
+ static void DeleteContext(void *Ctx) {
+ delete (typename data_type::Factory *) Ctx;
+ }
+ };
+
+ // Partial-specialization for ImmutableSet.
+ template <typename Key, typename Info>
+ struct ProgramStatePartialTrait<llvm::ImmutableSet<Key, Info>> {
+ using data_type = llvm::ImmutableSet<Key, Info>;
+ using context_type = typename data_type::Factory &;
+ using key_type = Key;
+
+ static data_type MakeData(void *const *p) {
+ return p ? data_type((typename data_type::TreeTy *) *p)
+ : data_type(nullptr);
+ }
+
+ static void *MakeVoidPtr(data_type B) {
+ return B.getRoot();
+ }
+
+ static data_type Add(data_type B, key_type K, context_type F) {
+ return F.add(B, K);
+ }
+
+ static data_type Remove(data_type B, key_type K, context_type F) {
+ return F.remove(B, K);
+ }
+
+ static bool Contains(data_type B, key_type K) {
+ return B.contains(K);
+ }
+
+ static context_type MakeContext(void *p) {
+ return *((typename data_type::Factory *) p);
+ }
+
+ static void *CreateContext(llvm::BumpPtrAllocator &Alloc) {
+ return new typename data_type::Factory(Alloc);
+ }
+
+ static void DeleteContext(void *Ctx) {
+ delete (typename data_type::Factory *) Ctx;
+ }
+ };
+
+ // Partial-specialization for ImmutableList.
+ template <typename T>
+ struct ProgramStatePartialTrait<llvm::ImmutableList<T>> {
+ using data_type = llvm::ImmutableList<T>;
+ using key_type = T;
+ using context_type = typename data_type::Factory &;
+
+ static data_type Add(data_type L, key_type K, context_type F) {
+ return F.add(K, L);
+ }
+
+ static bool Contains(data_type L, key_type K) {
+ return L.contains(K);
+ }
+
+ static data_type MakeData(void *const *p) {
+ return p ? data_type((const llvm::ImmutableListImpl<T> *) *p)
+ : data_type(nullptr);
+ }
+
+ static void *MakeVoidPtr(data_type D) {
+ return const_cast<llvm::ImmutableListImpl<T> *>(D.getInternalPointer());
+ }
+
+ static context_type MakeContext(void *p) {
+ return *((typename data_type::Factory *) p);
+ }
+
+ static void *CreateContext(llvm::BumpPtrAllocator &Alloc) {
+ return new typename data_type::Factory(Alloc);
+ }
+
+ static void DeleteContext(void *Ctx) {
+ delete (typename data_type::Factory *) Ctx;
+ }
+ };
+
+ // Partial specialization for bool.
+ template <> struct ProgramStatePartialTrait<bool> {
+ using data_type = bool;
+
+ static data_type MakeData(void *const *p) {
+ return p ? (data_type) (uintptr_t) *p
+ : data_type();
+ }
+
+ static void *MakeVoidPtr(data_type d) {
+ return (void *) (uintptr_t) d;
+ }
+ };
+
+ // Partial specialization for unsigned.
+ template <> struct ProgramStatePartialTrait<unsigned> {
+ using data_type = unsigned;
+
+ static data_type MakeData(void *const *p) {
+ return p ? (data_type) (uintptr_t) *p
+ : data_type();
+ }
+
+ static void *MakeVoidPtr(data_type d) {
+ return (void *) (uintptr_t) d;
+ }
+ };
+
+ // Partial specialization for void*.
+ template <> struct ProgramStatePartialTrait<void *> {
+ using data_type = void *;
+
+ static data_type MakeData(void *const *p) {
+ return p ? *p
+ : data_type();
+ }
+
+ static void *MakeVoidPtr(data_type d) {
+ return d;
+ }
+ };
+
+ // Partial specialization for const void *.
+ template <> struct ProgramStatePartialTrait<const void *> {
+ using data_type = const void *;
+
+ static data_type MakeData(void *const *p) {
+ return p ? *p : data_type();
+ }
+
+ static void *MakeVoidPtr(data_type d) {
+ return const_cast<void *>(d);
+ }
+ };
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h
new file mode 100644
index 00000000..0ea26bf2
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h
@@ -0,0 +1,42 @@
+//== ProgramState_Fwd.h - Incomplete declarations of ProgramState -*- C++ -*--=/
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_FWD_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_FWD_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+
+namespace clang {
+namespace ento {
+ class ProgramState;
+ class ProgramStateManager;
+ void ProgramStateRetain(const ProgramState *state);
+ void ProgramStateRelease(const ProgramState *state);
+}
+}
+
+namespace llvm {
+ template <> struct IntrusiveRefCntPtrInfo<const clang::ento::ProgramState> {
+ static void retain(const clang::ento::ProgramState *state) {
+ clang::ento::ProgramStateRetain(state);
+ }
+ static void release(const clang::ento::ProgramState *state) {
+ clang::ento::ProgramStateRelease(state);
+ }
+ };
+}
+
+namespace clang {
+namespace ento {
+ typedef IntrusiveRefCntPtr<const ProgramState> ProgramStateRef;
+}
+}
+
+#endif
+
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
new file mode 100644
index 00000000..16c30ec1
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -0,0 +1,215 @@
+//== RangedConstraintManager.h ----------------------------------*- C++ -*--==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Ranged constraint manager, built on SimpleConstraintManager.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CORE_RANGEDCONSTRAINTMANAGER_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CORE_RANGEDCONSTRAINTMANAGER_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h"
+
+namespace clang {
+
+namespace ento {
+
+/// A Range represents the closed range [from, to]. The caller must
+/// guarantee that from <= to. Note that Range is immutable, so as not
+/// to subvert RangeSet's immutability.
+class Range : public std::pair<const llvm::APSInt *, const llvm::APSInt *> {
+public:
+ Range(const llvm::APSInt &from, const llvm::APSInt &to)
+ : std::pair<const llvm::APSInt *, const llvm::APSInt *>(&from, &to) {
+ assert(from <= to);
+ }
+ bool Includes(const llvm::APSInt &v) const {
+ return *first <= v && v <= *second;
+ }
+ const llvm::APSInt &From() const { return *first; }
+ const llvm::APSInt &To() const { return *second; }
+ const llvm::APSInt *getConcreteValue() const {
+ return &From() == &To() ? &From() : nullptr;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(&From());
+ ID.AddPointer(&To());
+ }
+};
+
+class RangeTrait : public llvm::ImutContainerInfo<Range> {
+public:
+ // When comparing if one Range is less than another, we should compare
+ // the actual APSInt values instead of their pointers. This keeps the order
+ // consistent (instead of comparing by pointer values) and can potentially
+ // be used to speed up some of the operations in RangeSet.
+ static inline bool isLess(key_type_ref lhs, key_type_ref rhs) {
+ return *lhs.first < *rhs.first ||
+ (!(*rhs.first < *lhs.first) && *lhs.second < *rhs.second);
+ }
+};
+
+/// RangeSet contains a set of ranges. If the set is empty, then
+/// there the value of a symbol is overly constrained and there are no
+/// possible values for that symbol.
+class RangeSet {
+ typedef llvm::ImmutableSet<Range, RangeTrait> PrimRangeSet;
+ PrimRangeSet ranges; // no need to make const, since it is an
+ // ImmutableSet - this allows default operator=
+ // to work.
+public:
+ typedef PrimRangeSet::Factory Factory;
+ typedef PrimRangeSet::iterator iterator;
+
+ RangeSet(PrimRangeSet RS) : ranges(RS) {}
+
+ /// Create a new set with all ranges of this set and RS.
+ /// Possible intersections are not checked here.
+ RangeSet addRange(Factory &F, const RangeSet &RS) {
+ PrimRangeSet Ranges(RS.ranges);
+ for (const auto &range : ranges)
+ Ranges = F.add(Ranges, range);
+ return RangeSet(Ranges);
+ }
+
+ iterator begin() const { return ranges.begin(); }
+ iterator end() const { return ranges.end(); }
+
+ bool isEmpty() const { return ranges.isEmpty(); }
+
+ /// Construct a new RangeSet representing '{ [from, to] }'.
+ RangeSet(Factory &F, const llvm::APSInt &from, const llvm::APSInt &to)
+ : ranges(F.add(F.getEmptySet(), Range(from, to))) {}
+
+ /// Profile - Generates a hash profile of this RangeSet for use
+ /// by FoldingSet.
+ void Profile(llvm::FoldingSetNodeID &ID) const { ranges.Profile(ID); }
+
+ /// getConcreteValue - If a symbol is contrained to equal a specific integer
+ /// constant then this method returns that value. Otherwise, it returns
+ /// NULL.
+ const llvm::APSInt *getConcreteValue() const {
+ return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : nullptr;
+ }
+
+private:
+ void IntersectInRange(BasicValueFactory &BV, Factory &F,
+ const llvm::APSInt &Lower, const llvm::APSInt &Upper,
+ PrimRangeSet &newRanges, PrimRangeSet::iterator &i,
+ PrimRangeSet::iterator &e) const;
+
+ const llvm::APSInt &getMinValue() const;
+
+ bool pin(llvm::APSInt &Lower, llvm::APSInt &Upper) const;
+
+public:
+ RangeSet Intersect(BasicValueFactory &BV, Factory &F, llvm::APSInt Lower,
+ llvm::APSInt Upper) const;
+
+ RangeSet Negate(BasicValueFactory &BV, Factory &F) const;
+
+ void print(raw_ostream &os) const;
+
+ bool operator==(const RangeSet &other) const {
+ return ranges == other.ranges;
+ }
+};
+
+
+class ConstraintRange {};
+using ConstraintRangeTy = llvm::ImmutableMap<SymbolRef, RangeSet>;
+
+template <>
+struct ProgramStateTrait<ConstraintRange>
+ : public ProgramStatePartialTrait<ConstraintRangeTy> {
+ static void *GDMIndex();
+};
+
+
+class RangedConstraintManager : public SimpleConstraintManager {
+public:
+ RangedConstraintManager(SubEngine *SE, SValBuilder &SB)
+ : SimpleConstraintManager(SE, SB) {}
+
+ ~RangedConstraintManager() override;
+
+ //===------------------------------------------------------------------===//
+ // Implementation for interface from SimpleConstraintManager.
+ //===------------------------------------------------------------------===//
+
+ ProgramStateRef assumeSym(ProgramStateRef State, SymbolRef Sym,
+ bool Assumption) override;
+
+ ProgramStateRef assumeSymInclusiveRange(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InRange) override;
+
+ ProgramStateRef assumeSymUnsupported(ProgramStateRef State, SymbolRef Sym,
+ bool Assumption) override;
+
+protected:
+ /// Assume a constraint between a symbolic expression and a concrete integer.
+ virtual ProgramStateRef assumeSymRel(ProgramStateRef State, SymbolRef Sym,
+ BinaryOperator::Opcode op,
+ const llvm::APSInt &Int);
+
+ //===------------------------------------------------------------------===//
+ // Interface that subclasses must implement.
+ //===------------------------------------------------------------------===//
+
+ // Each of these is of the form "$Sym+Adj <> V", where "<>" is the comparison
+ // operation for the method being invoked.
+
+ virtual ProgramStateRef assumeSymNE(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymEQ(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymLT(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymGT(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymLE(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymGE(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymWithinInclusiveRange(
+ ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
+ const llvm::APSInt &To, const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymOutsideInclusiveRange(
+ ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
+ const llvm::APSInt &To, const llvm::APSInt &Adjustment) = 0;
+
+ //===------------------------------------------------------------------===//
+ // Internal implementation.
+ //===------------------------------------------------------------------===//
+private:
+ static void computeAdjustment(SymbolRef &Sym, llvm::APSInt &Adjustment);
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
new file mode 100644
index 00000000..3c52c2bc
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
@@ -0,0 +1,89 @@
+//===-- Regions.def - Metadata about MemRegion kinds ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// The list of regions (MemRegion sub-classes) used in the Static Analyzer.
+// In order to use this information, users of this file must define one or more
+// of the three macros:
+//
+// REGION(Id, Parent) - for specific MemRegion sub-classes, reserving
+// enum value IdKind for their kind.
+//
+// ABSTRACT_REGION(Id, Parent) - for abstract region classes,
+//
+// REGION_RANGE(Id, First, Last) - for ranges of kind-enums,
+// allowing to determine abstract class of a region
+// based on the kind-enum value.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef REGION
+#define REGION(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_REGION
+#define ABSTRACT_REGION(Id, Parent)
+#endif
+
+#ifndef REGION_RANGE
+#define REGION_RANGE(Id, First, Last)
+#endif
+
+ABSTRACT_REGION(MemSpaceRegion, MemRegion)
+ REGION(CodeSpaceRegion, MemSpaceRegion)
+ ABSTRACT_REGION(GlobalsSpaceRegion, MemSpaceRegion)
+ ABSTRACT_REGION(NonStaticGlobalSpaceRegion, GlobalsSpaceRegion)
+ REGION(GlobalImmutableSpaceRegion, NonStaticGlobalSpaceRegion)
+ REGION(GlobalInternalSpaceRegion, NonStaticGlobalSpaceRegion)
+ REGION(GlobalSystemSpaceRegion, NonStaticGlobalSpaceRegion)
+ REGION_RANGE(NON_STATIC_GLOBAL_MEMSPACES, GlobalImmutableSpaceRegionKind,
+ GlobalSystemSpaceRegionKind)
+ REGION(StaticGlobalSpaceRegion, MemSpaceRegion)
+ REGION_RANGE(GLOBAL_MEMSPACES, GlobalImmutableSpaceRegionKind,
+ StaticGlobalSpaceRegionKind)
+ REGION(HeapSpaceRegion, MemSpaceRegion)
+ ABSTRACT_REGION(StackSpaceRegion, MemSpaceRegion)
+ REGION(StackArgumentsSpaceRegion, StackSpaceRegion)
+ REGION(StackLocalsSpaceRegion, StackSpaceRegion)
+ REGION_RANGE(STACK_MEMSPACES, StackArgumentsSpaceRegionKind,
+ StackLocalsSpaceRegionKind)
+ REGION(UnknownSpaceRegion, MemSpaceRegion)
+ REGION_RANGE(MEMSPACES, CodeSpaceRegionKind,
+ UnknownSpaceRegionKind)
+ABSTRACT_REGION(SubRegion, MemRegion)
+ REGION(AllocaRegion, SubRegion)
+ REGION(SymbolicRegion, SubRegion)
+ ABSTRACT_REGION(TypedRegion, SubRegion)
+ REGION(BlockDataRegion, TypedRegion)
+ ABSTRACT_REGION(CodeTextRegion, TypedRegion)
+ REGION(BlockCodeRegion, CodeTextRegion)
+ REGION(FunctionCodeRegion, CodeTextRegion)
+ REGION_RANGE(CODE_TEXT_REGIONS, BlockCodeRegionKind,
+ FunctionCodeRegionKind)
+ ABSTRACT_REGION(TypedValueRegion, TypedRegion)
+ REGION(CompoundLiteralRegion, TypedValueRegion)
+ REGION(CXXBaseObjectRegion, TypedValueRegion)
+ REGION(CXXDerivedObjectRegion, TypedValueRegion)
+ REGION(CXXTempObjectRegion, TypedValueRegion)
+ REGION(CXXThisRegion, TypedValueRegion)
+ ABSTRACT_REGION(DeclRegion, TypedValueRegion)
+ REGION(FieldRegion, DeclRegion)
+ REGION(ObjCIvarRegion, DeclRegion)
+ REGION(VarRegion, DeclRegion)
+ REGION_RANGE(DECL_REGIONS, FieldRegionKind,
+ VarRegionKind)
+ REGION(ElementRegion, TypedValueRegion)
+ REGION(ObjCStringRegion, TypedValueRegion)
+ REGION(StringRegion, TypedValueRegion)
+ REGION_RANGE(TYPED_VALUE_REGIONS, CompoundLiteralRegionKind,
+ StringRegionKind)
+ REGION_RANGE(TYPED_REGIONS, BlockDataRegionKind,
+ StringRegionKind)
+
+#undef REGION_RANGE
+#undef ABSTRACT_REGION
+#undef REGION
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SMTAPI.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SMTAPI.h
new file mode 100644
index 00000000..51648921
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SMTAPI.h
@@ -0,0 +1,405 @@
+//===- SMTAPI.h -------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a SMT generic Solver API, which will be the base class
+// for every SMT solver specific class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTSOLVER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTSOLVER_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/FoldingSet.h"
+
+namespace clang {
+namespace ento {
+
+/// Generic base class for SMT sorts
+class SMTSort {
+public:
+ SMTSort() = default;
+ virtual ~SMTSort() = default;
+
+ /// Returns true if the sort is a bitvector, calls isBitvectorSortImpl().
+ virtual bool isBitvectorSort() const { return isBitvectorSortImpl(); }
+
+ /// Returns true if the sort is a floating-point, calls isFloatSortImpl().
+ virtual bool isFloatSort() const { return isFloatSortImpl(); }
+
+ /// Returns true if the sort is a boolean, calls isBooleanSortImpl().
+ virtual bool isBooleanSort() const { return isBooleanSortImpl(); }
+
+ /// Returns the bitvector size, fails if the sort is not a bitvector
+ /// Calls getBitvectorSortSizeImpl().
+ virtual unsigned getBitvectorSortSize() const {
+ assert(isBitvectorSort() && "Not a bitvector sort!");
+ unsigned Size = getBitvectorSortSizeImpl();
+ assert(Size && "Size is zero!");
+ return Size;
+ };
+
+ /// Returns the floating-point size, fails if the sort is not a floating-point
+ /// Calls getFloatSortSizeImpl().
+ virtual unsigned getFloatSortSize() const {
+ assert(isFloatSort() && "Not a floating-point sort!");
+ unsigned Size = getFloatSortSizeImpl();
+ assert(Size && "Size is zero!");
+ return Size;
+ };
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
+
+ bool operator<(const SMTSort &Other) const {
+ llvm::FoldingSetNodeID ID1, ID2;
+ Profile(ID1);
+ Other.Profile(ID2);
+ return ID1 < ID2;
+ }
+
+ friend bool operator==(SMTSort const &LHS, SMTSort const &RHS) {
+ return LHS.equal_to(RHS);
+ }
+
+ virtual void print(raw_ostream &OS) const = 0;
+
+ LLVM_DUMP_METHOD void dump() const { print(llvm::errs()); }
+
+protected:
+ /// Query the SMT solver and returns true if two sorts are equal (same kind
+ /// and bit width). This does not check if the two sorts are the same objects.
+ virtual bool equal_to(SMTSort const &other) const = 0;
+
+ /// Query the SMT solver and checks if a sort is bitvector.
+ virtual bool isBitvectorSortImpl() const = 0;
+
+ /// Query the SMT solver and checks if a sort is floating-point.
+ virtual bool isFloatSortImpl() const = 0;
+
+ /// Query the SMT solver and checks if a sort is boolean.
+ virtual bool isBooleanSortImpl() const = 0;
+
+ /// Query the SMT solver and returns the sort bit width.
+ virtual unsigned getBitvectorSortSizeImpl() const = 0;
+
+ /// Query the SMT solver and returns the sort bit width.
+ virtual unsigned getFloatSortSizeImpl() const = 0;
+};
+
+/// Shared pointer for SMTSorts, used by SMTSolver API.
+using SMTSortRef = const SMTSort *;
+
+/// Generic base class for SMT exprs
+class SMTExpr {
+public:
+ SMTExpr() = default;
+ virtual ~SMTExpr() = default;
+
+ bool operator<(const SMTExpr &Other) const {
+ llvm::FoldingSetNodeID ID1, ID2;
+ Profile(ID1);
+ Other.Profile(ID2);
+ return ID1 < ID2;
+ }
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
+
+ friend bool operator==(SMTExpr const &LHS, SMTExpr const &RHS) {
+ return LHS.equal_to(RHS);
+ }
+
+ virtual void print(raw_ostream &OS) const = 0;
+
+ LLVM_DUMP_METHOD void dump() const { print(llvm::errs()); }
+
+protected:
+ /// Query the SMT solver and returns true if two sorts are equal (same kind
+ /// and bit width). This does not check if the two sorts are the same objects.
+ virtual bool equal_to(SMTExpr const &other) const = 0;
+};
+
+/// Shared pointer for SMTExprs, used by SMTSolver API.
+using SMTExprRef = const SMTExpr *;
+
+/// Generic base class for SMT Solvers
+///
+/// This class is responsible for wrapping all sorts and expression generation,
+/// through the mk* methods. It also provides methods to create SMT expressions
+/// straight from clang's AST, through the from* methods.
+class SMTSolver {
+public:
+ SMTSolver() = default;
+ virtual ~SMTSolver() = default;
+
+ LLVM_DUMP_METHOD void dump() const { print(llvm::errs()); }
+
+ // Returns an appropriate floating-point sort for the given bitwidth.
+ SMTSortRef getFloatSort(unsigned BitWidth) {
+ switch (BitWidth) {
+ case 16:
+ return getFloat16Sort();
+ case 32:
+ return getFloat32Sort();
+ case 64:
+ return getFloat64Sort();
+ case 128:
+ return getFloat128Sort();
+ default:;
+ }
+ llvm_unreachable("Unsupported floating-point bitwidth!");
+ }
+
+ // Returns a boolean sort.
+ virtual SMTSortRef getBoolSort() = 0;
+
+ // Returns an appropriate bitvector sort for the given bitwidth.
+ virtual SMTSortRef getBitvectorSort(const unsigned BitWidth) = 0;
+
+ // Returns a floating-point sort of width 16
+ virtual SMTSortRef getFloat16Sort() = 0;
+
+ // Returns a floating-point sort of width 32
+ virtual SMTSortRef getFloat32Sort() = 0;
+
+ // Returns a floating-point sort of width 64
+ virtual SMTSortRef getFloat64Sort() = 0;
+
+ // Returns a floating-point sort of width 128
+ virtual SMTSortRef getFloat128Sort() = 0;
+
+ // Returns an appropriate sort for the given AST.
+ virtual SMTSortRef getSort(const SMTExprRef &AST) = 0;
+
+ /// Given a constraint, adds it to the solver
+ virtual void addConstraint(const SMTExprRef &Exp) const = 0;
+
+ /// Creates a bitvector addition operation
+ virtual SMTExprRef mkBVAdd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector subtraction operation
+ virtual SMTExprRef mkBVSub(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector multiplication operation
+ virtual SMTExprRef mkBVMul(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed modulus operation
+ virtual SMTExprRef mkBVSRem(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned modulus operation
+ virtual SMTExprRef mkBVURem(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed division operation
+ virtual SMTExprRef mkBVSDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned division operation
+ virtual SMTExprRef mkBVUDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector logical shift left operation
+ virtual SMTExprRef mkBVShl(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector arithmetic shift right operation
+ virtual SMTExprRef mkBVAshr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector logical shift right operation
+ virtual SMTExprRef mkBVLshr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector negation operation
+ virtual SMTExprRef mkBVNeg(const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector not operation
+ virtual SMTExprRef mkBVNot(const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector xor operation
+ virtual SMTExprRef mkBVXor(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector or operation
+ virtual SMTExprRef mkBVOr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector and operation
+ virtual SMTExprRef mkBVAnd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned less-than operation
+ virtual SMTExprRef mkBVUlt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed less-than operation
+ virtual SMTExprRef mkBVSlt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned greater-than operation
+ virtual SMTExprRef mkBVUgt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed greater-than operation
+ virtual SMTExprRef mkBVSgt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned less-equal-than operation
+ virtual SMTExprRef mkBVUle(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed less-equal-than operation
+ virtual SMTExprRef mkBVSle(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned greater-equal-than operation
+ virtual SMTExprRef mkBVUge(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed greater-equal-than operation
+ virtual SMTExprRef mkBVSge(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a boolean not operation
+ virtual SMTExprRef mkNot(const SMTExprRef &Exp) = 0;
+
+ /// Creates a boolean equality operation
+ virtual SMTExprRef mkEqual(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a boolean and operation
+ virtual SMTExprRef mkAnd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a boolean or operation
+ virtual SMTExprRef mkOr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a boolean ite operation
+ virtual SMTExprRef mkIte(const SMTExprRef &Cond, const SMTExprRef &T,
+ const SMTExprRef &F) = 0;
+
+ /// Creates a bitvector sign extension operation
+ virtual SMTExprRef mkBVSignExt(unsigned i, const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector zero extension operation
+ virtual SMTExprRef mkBVZeroExt(unsigned i, const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector extract operation
+ virtual SMTExprRef mkBVExtract(unsigned High, unsigned Low,
+ const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector concat operation
+ virtual SMTExprRef mkBVConcat(const SMTExprRef &LHS,
+ const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point negation operation
+ virtual SMTExprRef mkFPNeg(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point isInfinite operation
+ virtual SMTExprRef mkFPIsInfinite(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point isNaN operation
+ virtual SMTExprRef mkFPIsNaN(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point isNormal operation
+ virtual SMTExprRef mkFPIsNormal(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point isZero operation
+ virtual SMTExprRef mkFPIsZero(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point multiplication operation
+ virtual SMTExprRef mkFPMul(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point division operation
+ virtual SMTExprRef mkFPDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point remainder operation
+ virtual SMTExprRef mkFPRem(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point addition operation
+ virtual SMTExprRef mkFPAdd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point subtraction operation
+ virtual SMTExprRef mkFPSub(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point less-than operation
+ virtual SMTExprRef mkFPLt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point greater-than operation
+ virtual SMTExprRef mkFPGt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point less-than-or-equal operation
+ virtual SMTExprRef mkFPLe(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point greater-than-or-equal operation
+ virtual SMTExprRef mkFPGe(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point equality operation
+ virtual SMTExprRef mkFPEqual(const SMTExprRef &LHS,
+ const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point conversion from floatint-point to floating-point
+ /// operation
+ virtual SMTExprRef mkFPtoFP(const SMTExprRef &From, const SMTSortRef &To) = 0;
+
+ /// Creates a floating-point conversion from signed bitvector to
+ /// floatint-point operation
+ virtual SMTExprRef mkSBVtoFP(const SMTExprRef &From,
+ const SMTSortRef &To) = 0;
+
+ /// Creates a floating-point conversion from unsigned bitvector to
+ /// floatint-point operation
+ virtual SMTExprRef mkUBVtoFP(const SMTExprRef &From,
+ const SMTSortRef &To) = 0;
+
+ /// Creates a floating-point conversion from floatint-point to signed
+ /// bitvector operation
+ virtual SMTExprRef mkFPtoSBV(const SMTExprRef &From, unsigned ToWidth) = 0;
+
+ /// Creates a floating-point conversion from floatint-point to unsigned
+ /// bitvector operation
+ virtual SMTExprRef mkFPtoUBV(const SMTExprRef &From, unsigned ToWidth) = 0;
+
+ /// Creates a new symbol, given a name and a sort
+ virtual SMTExprRef mkSymbol(const char *Name, SMTSortRef Sort) = 0;
+
+ // Returns an appropriate floating-point rounding mode.
+ virtual SMTExprRef getFloatRoundingMode() = 0;
+
+ // If the a model is available, returns the value of a given bitvector symbol
+ virtual llvm::APSInt getBitvector(const SMTExprRef &Exp, unsigned BitWidth,
+ bool isUnsigned) = 0;
+
+ // If the a model is available, returns the value of a given boolean symbol
+ virtual bool getBoolean(const SMTExprRef &Exp) = 0;
+
+ /// Constructs an SMTExprRef from a boolean.
+ virtual SMTExprRef mkBoolean(const bool b) = 0;
+
+ /// Constructs an SMTExprRef from a finite APFloat.
+ virtual SMTExprRef mkFloat(const llvm::APFloat Float) = 0;
+
+ /// Constructs an SMTExprRef from an APSInt and its bit width
+ virtual SMTExprRef mkBitvector(const llvm::APSInt Int, unsigned BitWidth) = 0;
+
+ /// Given an expression, extract the value of this operand in the model.
+ virtual bool getInterpretation(const SMTExprRef &Exp, llvm::APSInt &Int) = 0;
+
+ /// Given an expression extract the value of this operand in the model.
+ virtual bool getInterpretation(const SMTExprRef &Exp,
+ llvm::APFloat &Float) = 0;
+
+ /// Check if the constraints are satisfiable
+ virtual Optional<bool> check() const = 0;
+
+ /// Push the current solver state
+ virtual void push() = 0;
+
+ /// Pop the previous solver state
+ virtual void pop(unsigned NumStates = 1) = 0;
+
+ /// Reset the solver and remove all constraints.
+ virtual void reset() = 0;
+
+ /// Checks if the solver supports floating-points.
+ virtual bool isFPSupported() = 0;
+
+ virtual void print(raw_ostream &OS) const = 0;
+};
+
+/// Shared pointer for SMTSolvers.
+using SMTSolverRef = std::shared_ptr<SMTSolver>;
+
+/// Convenience method to create and Z3Solver object
+SMTSolverRef CreateZ3Solver();
+
+} // namespace ento
+} // namespace clang
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h
new file mode 100644
index 00000000..72f36014
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h
@@ -0,0 +1,337 @@
+//== SMTConstraintManager.h -------------------------------------*- C++ -*--==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a SMT generic API, which will be the base class for
+// every SMT solver specific class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONSTRAINTMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONSTRAINTMANAGER_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h"
+
+typedef llvm::ImmutableSet<
+ std::pair<clang::ento::SymbolRef, const clang::ento::SMTExpr *>>
+ ConstraintSMTType;
+REGISTER_TRAIT_WITH_PROGRAMSTATE(ConstraintSMT, ConstraintSMTType)
+
+namespace clang {
+namespace ento {
+
+class SMTConstraintManager : public clang::ento::SimpleConstraintManager {
+ mutable SMTSolverRef Solver = CreateZ3Solver();
+
+public:
+ SMTConstraintManager(clang::ento::SubEngine *SE, clang::ento::SValBuilder &SB)
+ : SimpleConstraintManager(SE, SB) {}
+ virtual ~SMTConstraintManager() = default;
+
+ //===------------------------------------------------------------------===//
+ // Implementation for interface from SimpleConstraintManager.
+ //===------------------------------------------------------------------===//
+
+ ProgramStateRef assumeSym(ProgramStateRef State, SymbolRef Sym,
+ bool Assumption) override {
+ ASTContext &Ctx = getBasicVals().getContext();
+
+ QualType RetTy;
+ bool hasComparison;
+
+ SMTExprRef Exp = SMTConv::getExpr(Solver, Ctx, Sym, &RetTy, &hasComparison);
+
+ // Create zero comparison for implicit boolean cast, with reversed
+ // assumption
+ if (!hasComparison && !RetTy->isBooleanType())
+ return assumeExpr(
+ State, Sym,
+ SMTConv::getZeroExpr(Solver, Ctx, Exp, RetTy, !Assumption));
+
+ return assumeExpr(State, Sym, Assumption ? Exp : Solver->mkNot(Exp));
+ }
+
+ ProgramStateRef assumeSymInclusiveRange(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InRange) override {
+ ASTContext &Ctx = getBasicVals().getContext();
+ return assumeExpr(
+ State, Sym, SMTConv::getRangeExpr(Solver, Ctx, Sym, From, To, InRange));
+ }
+
+ ProgramStateRef assumeSymUnsupported(ProgramStateRef State, SymbolRef Sym,
+ bool Assumption) override {
+ // Skip anything that is unsupported
+ return State;
+ }
+
+ //===------------------------------------------------------------------===//
+ // Implementation for interface from ConstraintManager.
+ //===------------------------------------------------------------------===//
+
+ ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override {
+ ASTContext &Ctx = getBasicVals().getContext();
+
+ QualType RetTy;
+ // The expression may be casted, so we cannot call getZ3DataExpr() directly
+ SMTExprRef VarExp = SMTConv::getExpr(Solver, Ctx, Sym, &RetTy);
+ SMTExprRef Exp =
+ SMTConv::getZeroExpr(Solver, Ctx, VarExp, RetTy, /*Assumption=*/true);
+
+ // Negate the constraint
+ SMTExprRef NotExp =
+ SMTConv::getZeroExpr(Solver, Ctx, VarExp, RetTy, /*Assumption=*/false);
+
+ ConditionTruthVal isSat = checkModel(State, Sym, Exp);
+ ConditionTruthVal isNotSat = checkModel(State, Sym, NotExp);
+
+ // Zero is the only possible solution
+ if (isSat.isConstrainedTrue() && isNotSat.isConstrainedFalse())
+ return true;
+
+ // Zero is not a solution
+ if (isSat.isConstrainedFalse() && isNotSat.isConstrainedTrue())
+ return false;
+
+ // Zero may be a solution
+ return ConditionTruthVal();
+ }
+
+ const llvm::APSInt *getSymVal(ProgramStateRef State,
+ SymbolRef Sym) const override {
+ BasicValueFactory &BVF = getBasicVals();
+ ASTContext &Ctx = BVF.getContext();
+
+ if (const SymbolData *SD = dyn_cast<SymbolData>(Sym)) {
+ QualType Ty = Sym->getType();
+ assert(!Ty->isRealFloatingType());
+ llvm::APSInt Value(Ctx.getTypeSize(Ty),
+ !Ty->isSignedIntegerOrEnumerationType());
+
+ // TODO: this should call checkModel so we can use the cache, however,
+ // this method tries to get the interpretation (the actual value) from
+ // the solver, which is currently not cached.
+
+ SMTExprRef Exp =
+ SMTConv::fromData(Solver, SD->getSymbolID(), Ty, Ctx.getTypeSize(Ty));
+
+ Solver->reset();
+ addStateConstraints(State);
+
+ // Constraints are unsatisfiable
+ Optional<bool> isSat = Solver->check();
+ if (!isSat.hasValue() || !isSat.getValue())
+ return nullptr;
+
+ // Model does not assign interpretation
+ if (!Solver->getInterpretation(Exp, Value))
+ return nullptr;
+
+ // A value has been obtained, check if it is the only value
+ SMTExprRef NotExp = SMTConv::fromBinOp(
+ Solver, Exp, BO_NE,
+ Ty->isBooleanType() ? Solver->mkBoolean(Value.getBoolValue())
+ : Solver->mkBitvector(Value, Value.getBitWidth()),
+ /*isSigned=*/false);
+
+ Solver->addConstraint(NotExp);
+
+ Optional<bool> isNotSat = Solver->check();
+ if (!isSat.hasValue() || isNotSat.getValue())
+ return nullptr;
+
+ // This is the only solution, store it
+ return &BVF.getValue(Value);
+ }
+
+ if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) {
+ SymbolRef CastSym = SC->getOperand();
+ QualType CastTy = SC->getType();
+ // Skip the void type
+ if (CastTy->isVoidType())
+ return nullptr;
+
+ const llvm::APSInt *Value;
+ if (!(Value = getSymVal(State, CastSym)))
+ return nullptr;
+ return &BVF.Convert(SC->getType(), *Value);
+ }
+
+ if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
+ const llvm::APSInt *LHS, *RHS;
+ if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE)) {
+ LHS = getSymVal(State, SIE->getLHS());
+ RHS = &SIE->getRHS();
+ } else if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE)) {
+ LHS = &ISE->getLHS();
+ RHS = getSymVal(State, ISE->getRHS());
+ } else if (const SymSymExpr *SSM = dyn_cast<SymSymExpr>(BSE)) {
+ // Early termination to avoid expensive call
+ LHS = getSymVal(State, SSM->getLHS());
+ RHS = LHS ? getSymVal(State, SSM->getRHS()) : nullptr;
+ } else {
+ llvm_unreachable("Unsupported binary expression to get symbol value!");
+ }
+
+ if (!LHS || !RHS)
+ return nullptr;
+
+ llvm::APSInt ConvertedLHS, ConvertedRHS;
+ QualType LTy, RTy;
+ std::tie(ConvertedLHS, LTy) = SMTConv::fixAPSInt(Ctx, *LHS);
+ std::tie(ConvertedRHS, RTy) = SMTConv::fixAPSInt(Ctx, *RHS);
+ SMTConv::doIntTypeConversion<llvm::APSInt, &SMTConv::castAPSInt>(
+ Solver, Ctx, ConvertedLHS, LTy, ConvertedRHS, RTy);
+ return BVF.evalAPSInt(BSE->getOpcode(), ConvertedLHS, ConvertedRHS);
+ }
+
+ llvm_unreachable("Unsupported expression to get symbol value!");
+ }
+
+ ProgramStateRef removeDeadBindings(ProgramStateRef State,
+ SymbolReaper &SymReaper) override {
+ auto CZ = State->get<ConstraintSMT>();
+ auto &CZFactory = State->get_context<ConstraintSMT>();
+
+ for (auto I = CZ.begin(), E = CZ.end(); I != E; ++I) {
+ if (SymReaper.isDead(I->first))
+ CZ = CZFactory.remove(CZ, *I);
+ }
+
+ return State->set<ConstraintSMT>(CZ);
+ }
+
+ void print(ProgramStateRef St, raw_ostream &OS, const char *nl,
+ const char *sep) override {
+
+ auto CZ = St->get<ConstraintSMT>();
+
+ OS << nl << sep << "Constraints:";
+ for (auto I = CZ.begin(), E = CZ.end(); I != E; ++I) {
+ OS << nl << ' ' << I->first << " : ";
+ I->second->print(OS);
+ }
+ OS << nl;
+ }
+
+ bool canReasonAbout(SVal X) const override {
+ const TargetInfo &TI = getBasicVals().getContext().getTargetInfo();
+
+ Optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>();
+ if (!SymVal)
+ return true;
+
+ const SymExpr *Sym = SymVal->getSymbol();
+ QualType Ty = Sym->getType();
+
+ // Complex types are not modeled
+ if (Ty->isComplexType() || Ty->isComplexIntegerType())
+ return false;
+
+ // Non-IEEE 754 floating-point types are not modeled
+ if ((Ty->isSpecificBuiltinType(BuiltinType::LongDouble) &&
+ (&TI.getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended() ||
+ &TI.getLongDoubleFormat() == &llvm::APFloat::PPCDoubleDouble())))
+ return false;
+
+ if (Ty->isRealFloatingType())
+ return Solver->isFPSupported();
+
+ if (isa<SymbolData>(Sym))
+ return true;
+
+ SValBuilder &SVB = getSValBuilder();
+
+ if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
+ return canReasonAbout(SVB.makeSymbolVal(SC->getOperand()));
+
+ if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
+ if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE))
+ return canReasonAbout(SVB.makeSymbolVal(SIE->getLHS()));
+
+ if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE))
+ return canReasonAbout(SVB.makeSymbolVal(ISE->getRHS()));
+
+ if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(BSE))
+ return canReasonAbout(SVB.makeSymbolVal(SSE->getLHS())) &&
+ canReasonAbout(SVB.makeSymbolVal(SSE->getRHS()));
+ }
+
+ llvm_unreachable("Unsupported expression to reason about!");
+ }
+
+ /// Dumps SMT formula
+ LLVM_DUMP_METHOD void dump() const { Solver->dump(); }
+
+protected:
+ // Check whether a new model is satisfiable, and update the program state.
+ virtual ProgramStateRef assumeExpr(ProgramStateRef State, SymbolRef Sym,
+ const SMTExprRef &Exp) {
+ // Check the model, avoid simplifying AST to save time
+ if (checkModel(State, Sym, Exp).isConstrainedTrue())
+ return State->add<ConstraintSMT>(std::make_pair(Sym, Exp));
+
+ return nullptr;
+ }
+
+ /// Given a program state, construct the logical conjunction and add it to
+ /// the solver
+ virtual void addStateConstraints(ProgramStateRef State) const {
+ // TODO: Don't add all the constraints, only the relevant ones
+ auto CZ = State->get<ConstraintSMT>();
+ auto I = CZ.begin(), IE = CZ.end();
+
+ // Construct the logical AND of all the constraints
+ if (I != IE) {
+ std::vector<SMTExprRef> ASTs;
+
+ SMTExprRef Constraint = I++->second;
+ while (I != IE) {
+ Constraint = Solver->mkAnd(Constraint, I++->second);
+ }
+
+ Solver->addConstraint(Constraint);
+ }
+ }
+
+ // Generate and check a Z3 model, using the given constraint.
+ ConditionTruthVal checkModel(ProgramStateRef State, SymbolRef Sym,
+ const SMTExprRef &Exp) const {
+ ProgramStateRef NewState =
+ State->add<ConstraintSMT>(std::make_pair(Sym, Exp));
+
+ llvm::FoldingSetNodeID ID;
+ NewState->get<ConstraintSMT>().Profile(ID);
+
+ unsigned hash = ID.ComputeHash();
+ auto I = Cached.find(hash);
+ if (I != Cached.end())
+ return I->second;
+
+ Solver->reset();
+ addStateConstraints(NewState);
+
+ Optional<bool> res = Solver->check();
+ if (!res.hasValue())
+ Cached[hash] = ConditionTruthVal();
+ else
+ Cached[hash] = ConditionTruthVal(res.getValue());
+
+ return Cached[hash];
+ }
+
+ // Cache the result of an SMT query (true, false, unknown). The key is the
+ // hash of the constraints in a state
+ mutable llvm::DenseMap<unsigned, ConditionTruthVal> Cached;
+}; // end class SMTConstraintManager
+
+} // namespace ento
+} // namespace clang
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
new file mode 100644
index 00000000..f5145699
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
@@ -0,0 +1,752 @@
+//== SMTConv.h --------------------------------------------------*- C++ -*--==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a set of functions to create SMT expressions
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONV_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONV_H
+
+#include "clang/AST/Expr.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SMTAPI.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+
+namespace clang {
+namespace ento {
+
+class SMTConv {
+public:
+ // Returns an appropriate sort, given a QualType and it's bit width.
+ static inline SMTSortRef mkSort(SMTSolverRef &Solver, const QualType &Ty,
+ unsigned BitWidth) {
+ if (Ty->isBooleanType())
+ return Solver->getBoolSort();
+
+ if (Ty->isRealFloatingType())
+ return Solver->getFloatSort(BitWidth);
+
+ return Solver->getBitvectorSort(BitWidth);
+ }
+
+ /// Constructs an SMTExprRef from an unary operator.
+ static inline SMTExprRef fromUnOp(SMTSolverRef &Solver,
+ const UnaryOperator::Opcode Op,
+ const SMTExprRef &Exp) {
+ switch (Op) {
+ case UO_Minus:
+ return Solver->mkBVNeg(Exp);
+
+ case UO_Not:
+ return Solver->mkBVNot(Exp);
+
+ case UO_LNot:
+ return Solver->mkNot(Exp);
+
+ default:;
+ }
+ llvm_unreachable("Unimplemented opcode");
+ }
+
+ /// Constructs an SMTExprRef from a floating-point unary operator.
+ static inline SMTExprRef fromFloatUnOp(SMTSolverRef &Solver,
+ const UnaryOperator::Opcode Op,
+ const SMTExprRef &Exp) {
+ switch (Op) {
+ case UO_Minus:
+ return Solver->mkFPNeg(Exp);
+
+ case UO_LNot:
+ return fromUnOp(Solver, Op, Exp);
+
+ default:;
+ }
+ llvm_unreachable("Unimplemented opcode");
+ }
+
+ /// Construct an SMTExprRef from a n-ary binary operator.
+ static inline SMTExprRef fromNBinOp(SMTSolverRef &Solver,
+ const BinaryOperator::Opcode Op,
+ const std::vector<SMTExprRef> &ASTs) {
+ assert(!ASTs.empty());
+
+ if (Op != BO_LAnd && Op != BO_LOr)
+ llvm_unreachable("Unimplemented opcode");
+
+ SMTExprRef res = ASTs.front();
+ for (std::size_t i = 1; i < ASTs.size(); ++i)
+ res = (Op == BO_LAnd) ? Solver->mkAnd(res, ASTs[i])
+ : Solver->mkOr(res, ASTs[i]);
+ return res;
+ }
+
+ /// Construct an SMTExprRef from a binary operator.
+ static inline SMTExprRef fromBinOp(SMTSolverRef &Solver,
+ const SMTExprRef &LHS,
+ const BinaryOperator::Opcode Op,
+ const SMTExprRef &RHS, bool isSigned) {
+ assert(*Solver->getSort(LHS) == *Solver->getSort(RHS) &&
+ "AST's must have the same sort!");
+
+ switch (Op) {
+ // Multiplicative operators
+ case BO_Mul:
+ return Solver->mkBVMul(LHS, RHS);
+
+ case BO_Div:
+ return isSigned ? Solver->mkBVSDiv(LHS, RHS) : Solver->mkBVUDiv(LHS, RHS);
+
+ case BO_Rem:
+ return isSigned ? Solver->mkBVSRem(LHS, RHS) : Solver->mkBVURem(LHS, RHS);
+
+ // Additive operators
+ case BO_Add:
+ return Solver->mkBVAdd(LHS, RHS);
+
+ case BO_Sub:
+ return Solver->mkBVSub(LHS, RHS);
+
+ // Bitwise shift operators
+ case BO_Shl:
+ return Solver->mkBVShl(LHS, RHS);
+
+ case BO_Shr:
+ return isSigned ? Solver->mkBVAshr(LHS, RHS) : Solver->mkBVLshr(LHS, RHS);
+
+ // Relational operators
+ case BO_LT:
+ return isSigned ? Solver->mkBVSlt(LHS, RHS) : Solver->mkBVUlt(LHS, RHS);
+
+ case BO_GT:
+ return isSigned ? Solver->mkBVSgt(LHS, RHS) : Solver->mkBVUgt(LHS, RHS);
+
+ case BO_LE:
+ return isSigned ? Solver->mkBVSle(LHS, RHS) : Solver->mkBVUle(LHS, RHS);
+
+ case BO_GE:
+ return isSigned ? Solver->mkBVSge(LHS, RHS) : Solver->mkBVUge(LHS, RHS);
+
+ // Equality operators
+ case BO_EQ:
+ return Solver->mkEqual(LHS, RHS);
+
+ case BO_NE:
+ return fromUnOp(Solver, UO_LNot,
+ fromBinOp(Solver, LHS, BO_EQ, RHS, isSigned));
+
+ // Bitwise operators
+ case BO_And:
+ return Solver->mkBVAnd(LHS, RHS);
+
+ case BO_Xor:
+ return Solver->mkBVXor(LHS, RHS);
+
+ case BO_Or:
+ return Solver->mkBVOr(LHS, RHS);
+
+ // Logical operators
+ case BO_LAnd:
+ return Solver->mkAnd(LHS, RHS);
+
+ case BO_LOr:
+ return Solver->mkOr(LHS, RHS);
+
+ default:;
+ }
+ llvm_unreachable("Unimplemented opcode");
+ }
+
+ /// Construct an SMTExprRef from a special floating-point binary operator.
+ static inline SMTExprRef
+ fromFloatSpecialBinOp(SMTSolverRef &Solver, const SMTExprRef &LHS,
+ const BinaryOperator::Opcode Op,
+ const llvm::APFloat::fltCategory &RHS) {
+ switch (Op) {
+ // Equality operators
+ case BO_EQ:
+ switch (RHS) {
+ case llvm::APFloat::fcInfinity:
+ return Solver->mkFPIsInfinite(LHS);
+
+ case llvm::APFloat::fcNaN:
+ return Solver->mkFPIsNaN(LHS);
+
+ case llvm::APFloat::fcNormal:
+ return Solver->mkFPIsNormal(LHS);
+
+ case llvm::APFloat::fcZero:
+ return Solver->mkFPIsZero(LHS);
+ }
+ break;
+
+ case BO_NE:
+ return fromFloatUnOp(Solver, UO_LNot,
+ fromFloatSpecialBinOp(Solver, LHS, BO_EQ, RHS));
+
+ default:;
+ }
+
+ llvm_unreachable("Unimplemented opcode");
+ }
+
+ /// Construct an SMTExprRef from a floating-point binary operator.
+ static inline SMTExprRef fromFloatBinOp(SMTSolverRef &Solver,
+ const SMTExprRef &LHS,
+ const BinaryOperator::Opcode Op,
+ const SMTExprRef &RHS) {
+ assert(*Solver->getSort(LHS) == *Solver->getSort(RHS) &&
+ "AST's must have the same sort!");
+
+ switch (Op) {
+ // Multiplicative operators
+ case BO_Mul:
+ return Solver->mkFPMul(LHS, RHS);
+
+ case BO_Div:
+ return Solver->mkFPDiv(LHS, RHS);
+
+ case BO_Rem:
+ return Solver->mkFPRem(LHS, RHS);
+
+ // Additive operators
+ case BO_Add:
+ return Solver->mkFPAdd(LHS, RHS);
+
+ case BO_Sub:
+ return Solver->mkFPSub(LHS, RHS);
+
+ // Relational operators
+ case BO_LT:
+ return Solver->mkFPLt(LHS, RHS);
+
+ case BO_GT:
+ return Solver->mkFPGt(LHS, RHS);
+
+ case BO_LE:
+ return Solver->mkFPLe(LHS, RHS);
+
+ case BO_GE:
+ return Solver->mkFPGe(LHS, RHS);
+
+ // Equality operators
+ case BO_EQ:
+ return Solver->mkFPEqual(LHS, RHS);
+
+ case BO_NE:
+ return fromFloatUnOp(Solver, UO_LNot,
+ fromFloatBinOp(Solver, LHS, BO_EQ, RHS));
+
+ // Logical operators
+ case BO_LAnd:
+ case BO_LOr:
+ return fromBinOp(Solver, LHS, Op, RHS, /*isSigned=*/false);
+
+ default:;
+ }
+
+ llvm_unreachable("Unimplemented opcode");
+ }
+
+ /// Construct an SMTExprRef from a QualType FromTy to a QualType ToTy, and
+ /// their bit widths.
+ static inline SMTExprRef fromCast(SMTSolverRef &Solver, const SMTExprRef &Exp,
+ QualType ToTy, uint64_t ToBitWidth,
+ QualType FromTy, uint64_t FromBitWidth) {
+ if ((FromTy->isIntegralOrEnumerationType() &&
+ ToTy->isIntegralOrEnumerationType()) ||
+ (FromTy->isAnyPointerType() ^ ToTy->isAnyPointerType()) ||
+ (FromTy->isBlockPointerType() ^ ToTy->isBlockPointerType()) ||
+ (FromTy->isReferenceType() ^ ToTy->isReferenceType())) {
+
+ if (FromTy->isBooleanType()) {
+ assert(ToBitWidth > 0 && "BitWidth must be positive!");
+ return Solver->mkIte(
+ Exp, Solver->mkBitvector(llvm::APSInt("1"), ToBitWidth),
+ Solver->mkBitvector(llvm::APSInt("0"), ToBitWidth));
+ }
+
+ if (ToBitWidth > FromBitWidth)
+ return FromTy->isSignedIntegerOrEnumerationType()
+ ? Solver->mkBVSignExt(ToBitWidth - FromBitWidth, Exp)
+ : Solver->mkBVZeroExt(ToBitWidth - FromBitWidth, Exp);
+
+ if (ToBitWidth < FromBitWidth)
+ return Solver->mkBVExtract(ToBitWidth - 1, 0, Exp);
+
+ // Both are bitvectors with the same width, ignore the type cast
+ return Exp;
+ }
+
+ if (FromTy->isRealFloatingType() && ToTy->isRealFloatingType()) {
+ if (ToBitWidth != FromBitWidth)
+ return Solver->mkFPtoFP(Exp, Solver->getFloatSort(ToBitWidth));
+
+ return Exp;
+ }
+
+ if (FromTy->isIntegralOrEnumerationType() && ToTy->isRealFloatingType()) {
+ SMTSortRef Sort = Solver->getFloatSort(ToBitWidth);
+ return FromTy->isSignedIntegerOrEnumerationType()
+ ? Solver->mkSBVtoFP(Exp, Sort)
+ : Solver->mkUBVtoFP(Exp, Sort);
+ }
+
+ if (FromTy->isRealFloatingType() && ToTy->isIntegralOrEnumerationType())
+ return ToTy->isSignedIntegerOrEnumerationType()
+ ? Solver->mkFPtoSBV(Exp, ToBitWidth)
+ : Solver->mkFPtoUBV(Exp, ToBitWidth);
+
+ llvm_unreachable("Unsupported explicit type cast!");
+ }
+
+ // Callback function for doCast parameter on APSInt type.
+ static inline llvm::APSInt castAPSInt(SMTSolverRef &Solver,
+ const llvm::APSInt &V, QualType ToTy,
+ uint64_t ToWidth, QualType FromTy,
+ uint64_t FromWidth) {
+ APSIntType TargetType(ToWidth, !ToTy->isSignedIntegerOrEnumerationType());
+ return TargetType.convert(V);
+ }
+
+ /// Construct an SMTExprRef from a SymbolData.
+ static inline SMTExprRef fromData(SMTSolverRef &Solver, const SymbolID ID,
+ const QualType &Ty, uint64_t BitWidth) {
+ llvm::Twine Name = "$" + llvm::Twine(ID);
+ return Solver->mkSymbol(Name.str().c_str(), mkSort(Solver, Ty, BitWidth));
+ }
+
+ // Wrapper to generate SMTExprRef from SymbolCast data.
+ static inline SMTExprRef getCastExpr(SMTSolverRef &Solver, ASTContext &Ctx,
+ const SMTExprRef &Exp, QualType FromTy,
+ QualType ToTy) {
+ return fromCast(Solver, Exp, ToTy, Ctx.getTypeSize(ToTy), FromTy,
+ Ctx.getTypeSize(FromTy));
+ }
+
+ // Wrapper to generate SMTExprRef from unpacked binary symbolic expression.
+ // Sets the RetTy parameter. See getSMTExprRef().
+ static inline SMTExprRef getBinExpr(SMTSolverRef &Solver, ASTContext &Ctx,
+ const SMTExprRef &LHS, QualType LTy,
+ BinaryOperator::Opcode Op,
+ const SMTExprRef &RHS, QualType RTy,
+ QualType *RetTy) {
+ SMTExprRef NewLHS = LHS;
+ SMTExprRef NewRHS = RHS;
+ doTypeConversion(Solver, Ctx, NewLHS, NewRHS, LTy, RTy);
+
+ // Update the return type parameter if the output type has changed.
+ if (RetTy) {
+ // A boolean result can be represented as an integer type in C/C++, but at
+ // this point we only care about the SMT sorts. Set it as a boolean type
+ // to avoid subsequent SMT errors.
+ if (BinaryOperator::isComparisonOp(Op) ||
+ BinaryOperator::isLogicalOp(Op)) {
+ *RetTy = Ctx.BoolTy;
+ } else {
+ *RetTy = LTy;
+ }
+
+ // If the two operands are pointers and the operation is a subtraction,
+ // the result is of type ptrdiff_t, which is signed
+ if (LTy->isAnyPointerType() && RTy->isAnyPointerType() && Op == BO_Sub) {
+ *RetTy = Ctx.getPointerDiffType();
+ }
+ }
+
+ return LTy->isRealFloatingType()
+ ? fromFloatBinOp(Solver, NewLHS, Op, NewRHS)
+ : fromBinOp(Solver, NewLHS, Op, NewRHS,
+ LTy->isSignedIntegerOrEnumerationType());
+ }
+
+ // Wrapper to generate SMTExprRef from BinarySymExpr.
+ // Sets the hasComparison and RetTy parameters. See getSMTExprRef().
+ static inline SMTExprRef getSymBinExpr(SMTSolverRef &Solver, ASTContext &Ctx,
+ const BinarySymExpr *BSE,
+ bool *hasComparison, QualType *RetTy) {
+ QualType LTy, RTy;
+ BinaryOperator::Opcode Op = BSE->getOpcode();
+
+ if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE)) {
+ SMTExprRef LHS =
+ getSymExpr(Solver, Ctx, SIE->getLHS(), &LTy, hasComparison);
+ llvm::APSInt NewRInt;
+ std::tie(NewRInt, RTy) = fixAPSInt(Ctx, SIE->getRHS());
+ SMTExprRef RHS = Solver->mkBitvector(NewRInt, NewRInt.getBitWidth());
+ return getBinExpr(Solver, Ctx, LHS, LTy, Op, RHS, RTy, RetTy);
+ }
+
+ if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE)) {
+ llvm::APSInt NewLInt;
+ std::tie(NewLInt, LTy) = fixAPSInt(Ctx, ISE->getLHS());
+ SMTExprRef LHS = Solver->mkBitvector(NewLInt, NewLInt.getBitWidth());
+ SMTExprRef RHS =
+ getSymExpr(Solver, Ctx, ISE->getRHS(), &RTy, hasComparison);
+ return getBinExpr(Solver, Ctx, LHS, LTy, Op, RHS, RTy, RetTy);
+ }
+
+ if (const SymSymExpr *SSM = dyn_cast<SymSymExpr>(BSE)) {
+ SMTExprRef LHS =
+ getSymExpr(Solver, Ctx, SSM->getLHS(), &LTy, hasComparison);
+ SMTExprRef RHS =
+ getSymExpr(Solver, Ctx, SSM->getRHS(), &RTy, hasComparison);
+ return getBinExpr(Solver, Ctx, LHS, LTy, Op, RHS, RTy, RetTy);
+ }
+
+ llvm_unreachable("Unsupported BinarySymExpr type!");
+ }
+
+ // Recursive implementation to unpack and generate symbolic expression.
+ // Sets the hasComparison and RetTy parameters. See getExpr().
+ static inline SMTExprRef getSymExpr(SMTSolverRef &Solver, ASTContext &Ctx,
+ SymbolRef Sym, QualType *RetTy,
+ bool *hasComparison) {
+ if (const SymbolData *SD = dyn_cast<SymbolData>(Sym)) {
+ if (RetTy)
+ *RetTy = Sym->getType();
+
+ return fromData(Solver, SD->getSymbolID(), Sym->getType(),
+ Ctx.getTypeSize(Sym->getType()));
+ }
+
+ if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) {
+ if (RetTy)
+ *RetTy = Sym->getType();
+
+ QualType FromTy;
+ SMTExprRef Exp =
+ getSymExpr(Solver, Ctx, SC->getOperand(), &FromTy, hasComparison);
+
+ // Casting an expression with a comparison invalidates it. Note that this
+ // must occur after the recursive call above.
+ // e.g. (signed char) (x > 0)
+ if (hasComparison)
+ *hasComparison = false;
+ return getCastExpr(Solver, Ctx, Exp, FromTy, Sym->getType());
+ }
+
+ if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
+ SMTExprRef Exp = getSymBinExpr(Solver, Ctx, BSE, hasComparison, RetTy);
+ // Set the hasComparison parameter, in post-order traversal order.
+ if (hasComparison)
+ *hasComparison = BinaryOperator::isComparisonOp(BSE->getOpcode());
+ return Exp;
+ }
+
+ llvm_unreachable("Unsupported SymbolRef type!");
+ }
+
+ // Generate an SMTExprRef that represents the given symbolic expression.
+ // Sets the hasComparison parameter if the expression has a comparison
+ // operator. Sets the RetTy parameter to the final return type after
+ // promotions and casts.
+ static inline SMTExprRef getExpr(SMTSolverRef &Solver, ASTContext &Ctx,
+ SymbolRef Sym, QualType *RetTy = nullptr,
+ bool *hasComparison = nullptr) {
+ if (hasComparison) {
+ *hasComparison = false;
+ }
+
+ return getSymExpr(Solver, Ctx, Sym, RetTy, hasComparison);
+ }
+
+ // Generate an SMTExprRef that compares the expression to zero.
+ static inline SMTExprRef getZeroExpr(SMTSolverRef &Solver, ASTContext &Ctx,
+ const SMTExprRef &Exp, QualType Ty,
+ bool Assumption) {
+
+ if (Ty->isRealFloatingType()) {
+ llvm::APFloat Zero =
+ llvm::APFloat::getZero(Ctx.getFloatTypeSemantics(Ty));
+ return fromFloatBinOp(Solver, Exp, Assumption ? BO_EQ : BO_NE,
+ Solver->mkFloat(Zero));
+ }
+
+ if (Ty->isIntegralOrEnumerationType() || Ty->isAnyPointerType() ||
+ Ty->isBlockPointerType() || Ty->isReferenceType()) {
+
+ // Skip explicit comparison for boolean types
+ bool isSigned = Ty->isSignedIntegerOrEnumerationType();
+ if (Ty->isBooleanType())
+ return Assumption ? fromUnOp(Solver, UO_LNot, Exp) : Exp;
+
+ return fromBinOp(
+ Solver, Exp, Assumption ? BO_EQ : BO_NE,
+ Solver->mkBitvector(llvm::APSInt("0"), Ctx.getTypeSize(Ty)),
+ isSigned);
+ }
+
+ llvm_unreachable("Unsupported type for zero value!");
+ }
+
+ // Wrapper to generate SMTExprRef from a range. If From == To, an equality
+ // will be created instead.
+ static inline SMTExprRef getRangeExpr(SMTSolverRef &Solver, ASTContext &Ctx,
+ SymbolRef Sym, const llvm::APSInt &From,
+ const llvm::APSInt &To, bool InRange) {
+ // Convert lower bound
+ QualType FromTy;
+ llvm::APSInt NewFromInt;
+ std::tie(NewFromInt, FromTy) = fixAPSInt(Ctx, From);
+ SMTExprRef FromExp =
+ Solver->mkBitvector(NewFromInt, NewFromInt.getBitWidth());
+
+ // Convert symbol
+ QualType SymTy;
+ SMTExprRef Exp = getExpr(Solver, Ctx, Sym, &SymTy);
+
+ // Construct single (in)equality
+ if (From == To)
+ return getBinExpr(Solver, Ctx, Exp, SymTy, InRange ? BO_EQ : BO_NE,
+ FromExp, FromTy, /*RetTy=*/nullptr);
+
+ QualType ToTy;
+ llvm::APSInt NewToInt;
+ std::tie(NewToInt, ToTy) = fixAPSInt(Ctx, To);
+ SMTExprRef ToExp = Solver->mkBitvector(NewToInt, NewToInt.getBitWidth());
+ assert(FromTy == ToTy && "Range values have different types!");
+
+ // Construct two (in)equalities, and a logical and/or
+ SMTExprRef LHS =
+ getBinExpr(Solver, Ctx, Exp, SymTy, InRange ? BO_GE : BO_LT, FromExp,
+ FromTy, /*RetTy=*/nullptr);
+ SMTExprRef RHS = getBinExpr(Solver, Ctx, Exp, SymTy,
+ InRange ? BO_LE : BO_GT, ToExp, ToTy,
+ /*RetTy=*/nullptr);
+
+ return fromBinOp(Solver, LHS, InRange ? BO_LAnd : BO_LOr, RHS,
+ SymTy->isSignedIntegerOrEnumerationType());
+ }
+
+ // Recover the QualType of an APSInt.
+ // TODO: Refactor to put elsewhere
+ static inline QualType getAPSIntType(ASTContext &Ctx,
+ const llvm::APSInt &Int) {
+ return Ctx.getIntTypeForBitwidth(Int.getBitWidth(), Int.isSigned());
+ }
+
+ // Get the QualTy for the input APSInt, and fix it if it has a bitwidth of 1.
+ static inline std::pair<llvm::APSInt, QualType>
+ fixAPSInt(ASTContext &Ctx, const llvm::APSInt &Int) {
+ llvm::APSInt NewInt;
+
+ // FIXME: This should be a cast from a 1-bit integer type to a boolean type,
+ // but the former is not available in Clang. Instead, extend the APSInt
+ // directly.
+ if (Int.getBitWidth() == 1 && getAPSIntType(Ctx, Int).isNull()) {
+ NewInt = Int.extend(Ctx.getTypeSize(Ctx.BoolTy));
+ } else
+ NewInt = Int;
+
+ return std::make_pair(NewInt, getAPSIntType(Ctx, NewInt));
+ }
+
+ // Perform implicit type conversion on binary symbolic expressions.
+ // May modify all input parameters.
+ // TODO: Refactor to use built-in conversion functions
+ static inline void doTypeConversion(SMTSolverRef &Solver, ASTContext &Ctx,
+ SMTExprRef &LHS, SMTExprRef &RHS,
+ QualType &LTy, QualType &RTy) {
+ assert(!LTy.isNull() && !RTy.isNull() && "Input type is null!");
+
+ // Perform type conversion
+ if ((LTy->isIntegralOrEnumerationType() &&
+ RTy->isIntegralOrEnumerationType()) &&
+ (LTy->isArithmeticType() && RTy->isArithmeticType())) {
+ SMTConv::doIntTypeConversion<SMTExprRef, &fromCast>(Solver, Ctx, LHS, LTy,
+ RHS, RTy);
+ return;
+ }
+
+ if (LTy->isRealFloatingType() || RTy->isRealFloatingType()) {
+ SMTConv::doFloatTypeConversion<SMTExprRef, &fromCast>(Solver, Ctx, LHS,
+ LTy, RHS, RTy);
+ return;
+ }
+
+ if ((LTy->isAnyPointerType() || RTy->isAnyPointerType()) ||
+ (LTy->isBlockPointerType() || RTy->isBlockPointerType()) ||
+ (LTy->isReferenceType() || RTy->isReferenceType())) {
+ // TODO: Refactor to Sema::FindCompositePointerType(), and
+ // Sema::CheckCompareOperands().
+
+ uint64_t LBitWidth = Ctx.getTypeSize(LTy);
+ uint64_t RBitWidth = Ctx.getTypeSize(RTy);
+
+ // Cast the non-pointer type to the pointer type.
+ // TODO: Be more strict about this.
+ if ((LTy->isAnyPointerType() ^ RTy->isAnyPointerType()) ||
+ (LTy->isBlockPointerType() ^ RTy->isBlockPointerType()) ||
+ (LTy->isReferenceType() ^ RTy->isReferenceType())) {
+ if (LTy->isNullPtrType() || LTy->isBlockPointerType() ||
+ LTy->isReferenceType()) {
+ LHS = fromCast(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ } else {
+ RHS = fromCast(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ }
+ }
+
+ // Cast the void pointer type to the non-void pointer type.
+ // For void types, this assumes that the casted value is equal to the
+ // value of the original pointer, and does not account for alignment
+ // requirements.
+ if (LTy->isVoidPointerType() ^ RTy->isVoidPointerType()) {
+ assert((Ctx.getTypeSize(LTy) == Ctx.getTypeSize(RTy)) &&
+ "Pointer types have different bitwidths!");
+ if (RTy->isVoidPointerType())
+ RTy = LTy;
+ else
+ LTy = RTy;
+ }
+
+ if (LTy == RTy)
+ return;
+ }
+
+ // Fallback: for the solver, assume that these types don't really matter
+ if ((LTy.getCanonicalType() == RTy.getCanonicalType()) ||
+ (LTy->isObjCObjectPointerType() && RTy->isObjCObjectPointerType())) {
+ LTy = RTy;
+ return;
+ }
+
+ // TODO: Refine behavior for invalid type casts
+ }
+
+ // Perform implicit integer type conversion.
+ // May modify all input parameters.
+ // TODO: Refactor to use Sema::handleIntegerConversion()
+ template <typename T, T (*doCast)(SMTSolverRef &Solver, const T &, QualType,
+ uint64_t, QualType, uint64_t)>
+ static inline void doIntTypeConversion(SMTSolverRef &Solver, ASTContext &Ctx,
+ T &LHS, QualType &LTy, T &RHS,
+ QualType &RTy) {
+
+ uint64_t LBitWidth = Ctx.getTypeSize(LTy);
+ uint64_t RBitWidth = Ctx.getTypeSize(RTy);
+
+ assert(!LTy.isNull() && !RTy.isNull() && "Input type is null!");
+ // Always perform integer promotion before checking type equality.
+ // Otherwise, e.g. (bool) a + (bool) b could trigger a backend assertion
+ if (LTy->isPromotableIntegerType()) {
+ QualType NewTy = Ctx.getPromotedIntegerType(LTy);
+ uint64_t NewBitWidth = Ctx.getTypeSize(NewTy);
+ LHS = (*doCast)(Solver, LHS, NewTy, NewBitWidth, LTy, LBitWidth);
+ LTy = NewTy;
+ LBitWidth = NewBitWidth;
+ }
+ if (RTy->isPromotableIntegerType()) {
+ QualType NewTy = Ctx.getPromotedIntegerType(RTy);
+ uint64_t NewBitWidth = Ctx.getTypeSize(NewTy);
+ RHS = (*doCast)(Solver, RHS, NewTy, NewBitWidth, RTy, RBitWidth);
+ RTy = NewTy;
+ RBitWidth = NewBitWidth;
+ }
+
+ if (LTy == RTy)
+ return;
+
+ // Perform integer type conversion
+ // Note: Safe to skip updating bitwidth because this must terminate
+ bool isLSignedTy = LTy->isSignedIntegerOrEnumerationType();
+ bool isRSignedTy = RTy->isSignedIntegerOrEnumerationType();
+
+ int order = Ctx.getIntegerTypeOrder(LTy, RTy);
+ if (isLSignedTy == isRSignedTy) {
+ // Same signedness; use the higher-ranked type
+ if (order == 1) {
+ RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ } else {
+ LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ }
+ } else if (order != (isLSignedTy ? 1 : -1)) {
+ // The unsigned type has greater than or equal rank to the
+ // signed type, so use the unsigned type
+ if (isRSignedTy) {
+ RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ } else {
+ LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ }
+ } else if (LBitWidth != RBitWidth) {
+ // The two types are different widths; if we are here, that
+ // means the signed type is larger than the unsigned type, so
+ // use the signed type.
+ if (isLSignedTy) {
+ RHS = (doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ } else {
+ LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ }
+ } else {
+ // The signed type is higher-ranked than the unsigned type,
+ // but isn't actually any bigger (like unsigned int and long
+ // on most 32-bit systems). Use the unsigned type corresponding
+ // to the signed type.
+ QualType NewTy =
+ Ctx.getCorrespondingUnsignedType(isLSignedTy ? LTy : RTy);
+ RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = NewTy;
+ LHS = (doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = NewTy;
+ }
+ }
+
+ // Perform implicit floating-point type conversion.
+ // May modify all input parameters.
+ // TODO: Refactor to use Sema::handleFloatConversion()
+ template <typename T, T (*doCast)(SMTSolverRef &Solver, const T &, QualType,
+ uint64_t, QualType, uint64_t)>
+ static inline void
+ doFloatTypeConversion(SMTSolverRef &Solver, ASTContext &Ctx, T &LHS,
+ QualType &LTy, T &RHS, QualType &RTy) {
+
+ uint64_t LBitWidth = Ctx.getTypeSize(LTy);
+ uint64_t RBitWidth = Ctx.getTypeSize(RTy);
+
+ // Perform float-point type promotion
+ if (!LTy->isRealFloatingType()) {
+ LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ LBitWidth = RBitWidth;
+ }
+ if (!RTy->isRealFloatingType()) {
+ RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ RBitWidth = LBitWidth;
+ }
+
+ if (LTy == RTy)
+ return;
+
+ // If we have two real floating types, convert the smaller operand to the
+ // bigger result
+ // Note: Safe to skip updating bitwidth because this must terminate
+ int order = Ctx.getFloatingTypeOrder(LTy, RTy);
+ if (order > 0) {
+ RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ } else if (order == 0) {
+ LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ } else {
+ llvm_unreachable("Unsupported floating-point type cast!");
+ }
+ }
+};
+} // namespace ento
+} // namespace clang
+
+#endif \ No newline at end of file
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
new file mode 100644
index 00000000..35ebefdc
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -0,0 +1,395 @@
+// SValBuilder.h - Construction of SVals from evaluating expressions -*- C++ -*-
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SValBuilder, a class that defines the interface for
+// "symbolical evaluators" which construct an SVal from an expression.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALBUILDER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALBUILDER_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/Optional.h"
+#include <cstdint>
+
+namespace clang {
+
+class BlockDecl;
+class CXXBoolLiteralExpr;
+class CXXMethodDecl;
+class CXXRecordDecl;
+class DeclaratorDecl;
+class FunctionDecl;
+class LocationContext;
+class StackFrameContext;
+class Stmt;
+
+namespace ento {
+
+class ConditionTruthVal;
+class ProgramStateManager;
+class StoreRef;
+
+class SValBuilder {
+ virtual void anchor();
+
+protected:
+ ASTContext &Context;
+
+ /// Manager of APSInt values.
+ BasicValueFactory BasicVals;
+
+ /// Manages the creation of symbols.
+ SymbolManager SymMgr;
+
+ /// Manages the creation of memory regions.
+ MemRegionManager MemMgr;
+
+ ProgramStateManager &StateMgr;
+
+ /// The scalar type to use for array indices.
+ const QualType ArrayIndexTy;
+
+ /// The width of the scalar type used for array indices.
+ const unsigned ArrayIndexWidth;
+
+ virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy) = 0;
+ virtual SVal evalCastFromLoc(Loc val, QualType castTy) = 0;
+
+public:
+ // FIXME: Make these protected again once RegionStoreManager correctly
+ // handles loads from different bound value types.
+ virtual SVal dispatchCast(SVal val, QualType castTy) = 0;
+
+public:
+ SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
+ ProgramStateManager &stateMgr)
+ : Context(context), BasicVals(context, alloc),
+ SymMgr(context, BasicVals, alloc), MemMgr(context, alloc),
+ StateMgr(stateMgr), ArrayIndexTy(context.LongLongTy),
+ ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {}
+
+ virtual ~SValBuilder() = default;
+
+ bool haveSameType(const SymExpr *Sym1, const SymExpr *Sym2) {
+ return haveSameType(Sym1->getType(), Sym2->getType());
+ }
+
+ bool haveSameType(QualType Ty1, QualType Ty2) {
+ // FIXME: Remove the second disjunct when we support symbolic
+ // truncation/extension.
+ return (Context.getCanonicalType(Ty1) == Context.getCanonicalType(Ty2) ||
+ (Ty1->isIntegralOrEnumerationType() &&
+ Ty2->isIntegralOrEnumerationType()));
+ }
+
+ SVal evalCast(SVal val, QualType castTy, QualType originalType);
+
+ // Handles casts of type CK_IntegralCast.
+ SVal evalIntegralCast(ProgramStateRef state, SVal val, QualType castTy,
+ QualType originalType);
+
+ virtual SVal evalMinus(NonLoc val) = 0;
+
+ virtual SVal evalComplement(NonLoc val) = 0;
+
+ /// Create a new value which represents a binary expression with two non-
+ /// location operands.
+ virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op,
+ NonLoc lhs, NonLoc rhs, QualType resultTy) = 0;
+
+ /// Create a new value which represents a binary expression with two memory
+ /// location operands.
+ virtual SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op,
+ Loc lhs, Loc rhs, QualType resultTy) = 0;
+
+ /// Create a new value which represents a binary expression with a memory
+ /// location and non-location operands. For example, this would be used to
+ /// evaluate a pointer arithmetic operation.
+ virtual SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op,
+ Loc lhs, NonLoc rhs, QualType resultTy) = 0;
+
+ /// Evaluates a given SVal. If the SVal has only one possible (integer) value,
+ /// that value is returned. Otherwise, returns NULL.
+ virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal val) = 0;
+
+ /// Simplify symbolic expressions within a given SVal. Return an SVal
+ /// that represents the same value, but is hopefully easier to work with
+ /// than the original SVal.
+ virtual SVal simplifySVal(ProgramStateRef State, SVal Val) = 0;
+
+ /// Constructs a symbolic expression for two non-location values.
+ SVal makeSymExprValNN(BinaryOperator::Opcode op,
+ NonLoc lhs, NonLoc rhs, QualType resultTy);
+
+ SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
+ SVal lhs, SVal rhs, QualType type);
+
+ /// \return Whether values in \p lhs and \p rhs are equal at \p state.
+ ConditionTruthVal areEqual(ProgramStateRef state, SVal lhs, SVal rhs);
+
+ SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs);
+
+ DefinedOrUnknownSVal evalEQ(ProgramStateRef state, DefinedOrUnknownSVal lhs,
+ DefinedOrUnknownSVal rhs);
+
+ ASTContext &getContext() { return Context; }
+ const ASTContext &getContext() const { return Context; }
+
+ ProgramStateManager &getStateManager() { return StateMgr; }
+
+ QualType getConditionType() const {
+ return Context.getLangOpts().CPlusPlus ? Context.BoolTy : Context.IntTy;
+ }
+
+ QualType getArrayIndexType() const {
+ return ArrayIndexTy;
+ }
+
+ BasicValueFactory &getBasicValueFactory() { return BasicVals; }
+ const BasicValueFactory &getBasicValueFactory() const { return BasicVals; }
+
+ SymbolManager &getSymbolManager() { return SymMgr; }
+ const SymbolManager &getSymbolManager() const { return SymMgr; }
+
+ MemRegionManager &getRegionManager() { return MemMgr; }
+ const MemRegionManager &getRegionManager() const { return MemMgr; }
+
+ // Forwarding methods to SymbolManager.
+
+ const SymbolConjured* conjureSymbol(const Stmt *stmt,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned visitCount,
+ const void *symbolTag = nullptr) {
+ return SymMgr.conjureSymbol(stmt, LCtx, type, visitCount, symbolTag);
+ }
+
+ const SymbolConjured* conjureSymbol(const Expr *expr,
+ const LocationContext *LCtx,
+ unsigned visitCount,
+ const void *symbolTag = nullptr) {
+ return SymMgr.conjureSymbol(expr, LCtx, visitCount, symbolTag);
+ }
+
+ /// Construct an SVal representing '0' for the specified type.
+ DefinedOrUnknownSVal makeZeroVal(QualType type);
+
+ /// Make a unique symbol for value of region.
+ DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedValueRegion *region);
+
+ /// Create a new symbol with a unique 'name'.
+ ///
+ /// We resort to conjured symbols when we cannot construct a derived symbol.
+ /// 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 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 conjureSymbolVal(const Stmt *stmt,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned visitCount);
+
+ /// Conjure a symbol representing heap allocated memory region.
+ ///
+ /// Note, the expression should represent a location.
+ DefinedOrUnknownSVal getConjuredHeapSymbolVal(const Expr *E,
+ const LocationContext *LCtx,
+ unsigned Count);
+
+ DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(
+ SymbolRef parentSymbol, const TypedValueRegion *region);
+
+ DefinedSVal getMetadataSymbolVal(const void *symbolTag,
+ const MemRegion *region,
+ const Expr *expr, QualType type,
+ const LocationContext *LCtx,
+ unsigned count);
+
+ DefinedSVal getMemberPointer(const DeclaratorDecl *DD);
+
+ DefinedSVal getFunctionPointer(const FunctionDecl *func);
+
+ DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy,
+ const LocationContext *locContext,
+ unsigned blockCount);
+
+ /// Returns the value of \p E, if it can be determined in a non-path-sensitive
+ /// manner.
+ ///
+ /// If \p E is not a constant or cannot be modeled, returns \c None.
+ Optional<SVal> getConstantVal(const Expr *E);
+
+ NonLoc makeCompoundVal(QualType type, llvm::ImmutableList<SVal> vals) {
+ return nonloc::CompoundVal(BasicVals.getCompoundValData(type, vals));
+ }
+
+ NonLoc makeLazyCompoundVal(const StoreRef &store,
+ const TypedValueRegion *region) {
+ return nonloc::LazyCompoundVal(
+ BasicVals.getLazyCompoundValData(store, region));
+ }
+
+ NonLoc makePointerToMember(const DeclaratorDecl *DD) {
+ return nonloc::PointerToMember(DD);
+ }
+
+ NonLoc makePointerToMember(const PointerToMemberData *PTMD) {
+ return nonloc::PointerToMember(PTMD);
+ }
+
+ NonLoc makeZeroArrayIndex() {
+ return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy));
+ }
+
+ NonLoc makeArrayIndex(uint64_t idx) {
+ return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy));
+ }
+
+ SVal convertToArrayIndex(SVal val);
+
+ nonloc::ConcreteInt makeIntVal(const IntegerLiteral* integer) {
+ return nonloc::ConcreteInt(
+ BasicVals.getValue(integer->getValue(),
+ integer->getType()->isUnsignedIntegerOrEnumerationType()));
+ }
+
+ nonloc::ConcreteInt makeBoolVal(const ObjCBoolLiteralExpr *boolean) {
+ return makeTruthVal(boolean->getValue(), boolean->getType());
+ }
+
+ nonloc::ConcreteInt makeBoolVal(const CXXBoolLiteralExpr *boolean);
+
+ nonloc::ConcreteInt makeIntVal(const llvm::APSInt& integer) {
+ return nonloc::ConcreteInt(BasicVals.getValue(integer));
+ }
+
+ loc::ConcreteInt makeIntLocVal(const llvm::APSInt &integer) {
+ return loc::ConcreteInt(BasicVals.getValue(integer));
+ }
+
+ NonLoc makeIntVal(const llvm::APInt& integer, bool isUnsigned) {
+ return nonloc::ConcreteInt(BasicVals.getValue(integer, isUnsigned));
+ }
+
+ DefinedSVal makeIntVal(uint64_t integer, QualType type) {
+ if (Loc::isLocType(type))
+ return loc::ConcreteInt(BasicVals.getValue(integer, type));
+
+ return nonloc::ConcreteInt(BasicVals.getValue(integer, type));
+ }
+
+ NonLoc makeIntVal(uint64_t integer, bool isUnsigned) {
+ return nonloc::ConcreteInt(BasicVals.getIntValue(integer, isUnsigned));
+ }
+
+ NonLoc makeIntValWithPtrWidth(uint64_t integer, bool isUnsigned) {
+ return nonloc::ConcreteInt(
+ BasicVals.getIntWithPtrWidth(integer, isUnsigned));
+ }
+
+ NonLoc makeLocAsInteger(Loc loc, unsigned bits) {
+ return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(loc, bits));
+ }
+
+ NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const llvm::APSInt& rhs, QualType type);
+
+ NonLoc makeNonLoc(const llvm::APSInt& rhs, BinaryOperator::Opcode op,
+ const SymExpr *lhs, QualType type);
+
+ NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const SymExpr *rhs, QualType type);
+
+ /// Create a NonLoc value for cast.
+ NonLoc makeNonLoc(const SymExpr *operand, QualType fromTy, QualType toTy);
+
+ nonloc::ConcreteInt makeTruthVal(bool b, QualType type) {
+ return nonloc::ConcreteInt(BasicVals.getTruthValue(b, type));
+ }
+
+ nonloc::ConcreteInt makeTruthVal(bool b) {
+ return nonloc::ConcreteInt(BasicVals.getTruthValue(b));
+ }
+
+ /// Create NULL pointer, with proper pointer bit-width for given address
+ /// space.
+ /// \param type pointer type.
+ Loc makeNullWithType(QualType type) {
+ return loc::ConcreteInt(BasicVals.getZeroWithTypeSize(type));
+ }
+
+ Loc makeNull() {
+ return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth());
+ }
+
+ Loc makeLoc(SymbolRef sym) {
+ return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
+ }
+
+ Loc makeLoc(const MemRegion* region) {
+ return loc::MemRegionVal(region);
+ }
+
+ Loc makeLoc(const AddrLabelExpr *expr) {
+ return loc::GotoLabel(expr->getLabel());
+ }
+
+ Loc makeLoc(const llvm::APSInt& integer) {
+ return loc::ConcreteInt(BasicVals.getValue(integer));
+ }
+
+ /// Make an SVal that represents the given symbol. This follows the convention
+ /// of representing Loc-type symbols (symbolic pointers and references)
+ /// as Loc values wrapping the symbol rather than as plain symbol values.
+ SVal makeSymbolVal(SymbolRef Sym) {
+ if (Loc::isLocType(Sym->getType()))
+ return makeLoc(Sym);
+ return nonloc::SymbolVal(Sym);
+ }
+
+ /// Return a memory region for the 'this' object reference.
+ loc::MemRegionVal getCXXThis(const CXXMethodDecl *D,
+ const StackFrameContext *SFC);
+
+ /// Return a memory region for the 'this' object reference.
+ loc::MemRegionVal getCXXThis(const CXXRecordDecl *D,
+ const StackFrameContext *SFC);
+};
+
+SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
+ ASTContext &context,
+ ProgramStateManager &stateMgr);
+
+} // namespace ento
+
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALBUILDER_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h
new file mode 100644
index 00000000..fc83e261
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h
@@ -0,0 +1,150 @@
+//===--- SValVisitor.h - Visitor for SVal subclasses ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the SValVisitor, SymExprVisitor, and MemRegionVisitor
+// interfaces, and also FullSValVisitor, which visits all three hierarchies.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+
+namespace clang {
+
+namespace ento {
+
+/// SValVisitor - this class implements a simple visitor for SVal
+/// subclasses.
+template <typename ImplClass, typename RetTy = void> class SValVisitor {
+public:
+
+#define DISPATCH(NAME, CLASS) \
+ return static_cast<ImplClass *>(this)->Visit ## NAME(V.castAs<CLASS>())
+
+ RetTy Visit(SVal V) {
+ // Dispatch to VisitFooVal for each FooVal.
+ // Take namespaces (loc:: and nonloc::) into account.
+ switch (V.getBaseKind()) {
+#define BASIC_SVAL(Id, Parent) case SVal::Id ## Kind: DISPATCH(Id, Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+ case SVal::LocKind:
+ switch (V.getSubKind()) {
+#define LOC_SVAL(Id, Parent) \
+ case loc::Id ## Kind: DISPATCH(Loc ## Id, loc :: Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+ }
+ llvm_unreachable("Unknown Loc sub-kind!");
+ case SVal::NonLocKind:
+ switch (V.getSubKind()) {
+#define NONLOC_SVAL(Id, Parent) \
+ case nonloc::Id ## Kind: DISPATCH(NonLoc ## Id, nonloc :: Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+ }
+ llvm_unreachable("Unknown NonLoc sub-kind!");
+ }
+ llvm_unreachable("Unknown SVal kind!");
+ }
+
+#define BASIC_SVAL(Id, Parent) \
+ RetTy Visit ## Id(Id V) { DISPATCH(Parent, Id); }
+#define ABSTRACT_SVAL(Id, Parent) \
+ BASIC_SVAL(Id, Parent)
+#define LOC_SVAL(Id, Parent) \
+ RetTy VisitLoc ## Id(loc::Id V) { DISPATCH(Parent, Parent); }
+#define NONLOC_SVAL(Id, Parent) \
+ RetTy VisitNonLoc ## Id(nonloc::Id V) { DISPATCH(Parent, Parent); }
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+
+ // Base case, ignore it. :)
+ RetTy VisitSVal(SVal V) { return RetTy(); }
+
+#undef DISPATCH
+};
+
+/// SymExprVisitor - this class implements a simple visitor for SymExpr
+/// subclasses.
+template <typename ImplClass, typename RetTy = void> class SymExprVisitor {
+public:
+
+#define DISPATCH(CLASS) \
+ return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(S))
+
+ RetTy Visit(SymbolRef S) {
+ // Dispatch to VisitSymbolFoo for each SymbolFoo.
+ switch (S->getKind()) {
+#define SYMBOL(Id, Parent) \
+ case SymExpr::Id ## Kind: DISPATCH(Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
+ }
+ llvm_unreachable("Unknown SymExpr kind!");
+ }
+
+ // If the implementation chooses not to implement a certain visit method, fall
+ // back on visiting the superclass.
+#define SYMBOL(Id, Parent) RetTy Visit ## Id(const Id *S) { DISPATCH(Parent); }
+#define ABSTRACT_SYMBOL(Id, Parent) SYMBOL(Id, Parent)
+#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
+
+ // Base case, ignore it. :)
+ RetTy VisitSymExpr(SymbolRef S) { return RetTy(); }
+
+#undef DISPATCH
+};
+
+/// MemRegionVisitor - this class implements a simple visitor for MemRegion
+/// subclasses.
+template <typename ImplClass, typename RetTy = void> class MemRegionVisitor {
+public:
+
+#define DISPATCH(CLASS) \
+ return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(R))
+
+ RetTy Visit(const MemRegion *R) {
+ // Dispatch to VisitFooRegion for each FooRegion.
+ switch (R->getKind()) {
+#define REGION(Id, Parent) case MemRegion::Id ## Kind: DISPATCH(Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
+ }
+ llvm_unreachable("Unknown MemRegion kind!");
+ }
+
+ // If the implementation chooses not to implement a certain visit method, fall
+ // back on visiting the superclass.
+#define REGION(Id, Parent) \
+ RetTy Visit ## Id(const Id *R) { DISPATCH(Parent); }
+#define ABSTRACT_REGION(Id, Parent) \
+ REGION(Id, Parent)
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
+
+ // Base case, ignore it. :)
+ RetTy VisitMemRegion(const MemRegion *R) { return RetTy(); }
+
+#undef DISPATCH
+};
+
+/// FullSValVisitor - a convenient mixed visitor for all three:
+/// SVal, SymExpr and MemRegion subclasses.
+template <typename ImplClass, typename RetTy = void>
+class FullSValVisitor : public SValVisitor<ImplClass, RetTy>,
+ public SymExprVisitor<ImplClass, RetTy>,
+ public MemRegionVisitor<ImplClass, RetTy> {
+public:
+ using SValVisitor<ImplClass, RetTy>::Visit;
+ using SymExprVisitor<ImplClass, RetTy>::Visit;
+ using MemRegionVisitor<ImplClass, RetTy>::Visit;
+};
+
+} // end namespace ento
+
+} // end namespace clang
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
new file mode 100644
index 00000000..eb05de6d
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
@@ -0,0 +1,74 @@
+//===-- SVals.def - Metadata about SVal kinds -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// The list of symbolic values (SVal kinds and sub-kinds) used in the Static
+// Analyzer. The distinction between loc:: and nonloc:: SVal namespaces is
+// currently hardcoded, because it is too peculiar and explicit to be handled
+// uniformly. In order to use this information, users of this file must define
+// one or more of the following macros:
+//
+// BASIC_SVAL(Id, Parent) - for specific SVal sub-kinds, which are
+// neither in loc:: nor in nonloc:: namespace; these classes occupy
+// their own base kind IdKind.
+//
+// ABSTRACT_SVAL(Id, Parent) - for abstract SVal classes which are
+// neither in loc:: nor in nonloc:: namespace,
+//
+// ABSTRACT_SVAL_WITH_KIND(Id, Parent) - for SVal classes which are also
+// neither in loc:: nor in nonloc:: namespace, but occupy a whole base kind
+// identifier IdKind, much like BASIC_SVALs.
+//
+// LOC_SVAL(Id, Parent) - for values in loc:: namespace, which occupy a sub-kind
+// loc::IdKind.
+//
+// NONLOC_SVAL(Id, Parent) - for values in nonloc:: namespace, which occupy a
+// sub-kind nonloc::IdKind.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BASIC_SVAL
+#define BASIC_SVAL(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_SVAL
+#define ABSTRACT_SVAL(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_SVAL_WITH_KIND
+#define ABSTRACT_SVAL_WITH_KIND(Id, Parent) ABSTRACT_SVAL(Id, Parent)
+#endif
+
+#ifndef LOC_SVAL
+#define LOC_SVAL(Id, Parent)
+#endif
+
+#ifndef NONLOC_SVAL
+#define NONLOC_SVAL(Id, Parent)
+#endif
+
+BASIC_SVAL(UndefinedVal, SVal)
+ABSTRACT_SVAL(DefinedOrUnknownSVal, SVal)
+ BASIC_SVAL(UnknownVal, DefinedOrUnknownSVal)
+ ABSTRACT_SVAL(DefinedSVal, DefinedOrUnknownSVal)
+ ABSTRACT_SVAL_WITH_KIND(Loc, DefinedSVal)
+ LOC_SVAL(ConcreteInt, Loc)
+ LOC_SVAL(GotoLabel, Loc)
+ LOC_SVAL(MemRegionVal, Loc)
+ ABSTRACT_SVAL_WITH_KIND(NonLoc, DefinedSVal)
+ NONLOC_SVAL(CompoundVal, NonLoc)
+ NONLOC_SVAL(ConcreteInt, NonLoc)
+ NONLOC_SVAL(LazyCompoundVal, NonLoc)
+ NONLOC_SVAL(LocAsInteger, NonLoc)
+ NONLOC_SVAL(SymbolVal, NonLoc)
+ NONLOC_SVAL(PointerToMember, NonLoc)
+
+#undef NONLOC_SVAL
+#undef LOC_SVAL
+#undef ABSTRACT_SVAL_WITH_KIND
+#undef ABSTRACT_SVAL
+#undef BASIC_SVAL
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
new file mode 100644
index 00000000..e8599366
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -0,0 +1,670 @@
+//===- SVals.h - Abstract Values for Static Analysis ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SVal, Loc, and NonLoc, classes that represent
+// abstract r-values for use with path-sensitive value tracking.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
+
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/Support/Casting.h"
+#include <cassert>
+#include <cstdint>
+#include <utility>
+
+//==------------------------------------------------------------------------==//
+// Base SVal types.
+//==------------------------------------------------------------------------==//
+
+namespace clang {
+
+class CXXBaseSpecifier;
+class DeclaratorDecl;
+class FunctionDecl;
+class LabelDecl;
+
+namespace ento {
+
+class BasicValueFactory;
+class CompoundValData;
+class LazyCompoundValData;
+class MemRegion;
+class PointerToMemberData;
+class SValBuilder;
+class TypedValueRegion;
+
+namespace nonloc {
+
+/// Sub-kinds for NonLoc values.
+enum Kind {
+#define NONLOC_SVAL(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+};
+
+} // namespace nonloc
+
+namespace loc {
+
+/// Sub-kinds for Loc values.
+enum Kind {
+#define LOC_SVAL(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+};
+
+} // namespace loc
+
+/// SVal - This represents a symbolic expression, which can be either
+/// an L-value or an R-value.
+///
+class SVal {
+public:
+ enum BaseKind {
+ // The enumerators must be representable using 2 bits.
+#define BASIC_SVAL(Id, Parent) Id ## Kind,
+#define ABSTRACT_SVAL_WITH_KIND(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+ };
+ enum { BaseBits = 2, BaseMask = 0x3 };
+
+protected:
+ const void *Data = nullptr;
+
+ /// The lowest 2 bits are a BaseKind (0 -- 3).
+ /// The higher bits are an unsigned "kind" value.
+ unsigned Kind = 0;
+
+ explicit SVal(const void *d, bool isLoc, unsigned ValKind)
+ : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
+
+ explicit SVal(BaseKind k, const void *D = nullptr) : Data(D), Kind(k) {}
+
+public:
+ explicit SVal() = default;
+
+ /// Convert to the specified SVal type, asserting that this SVal is of
+ /// the desired type.
+ template<typename T>
+ T castAs() const {
+ assert(T::isKind(*this));
+ return *static_cast<const T *>(this);
+ }
+
+ /// Convert to the specified SVal type, returning None if this SVal is
+ /// not of the desired type.
+ template<typename T>
+ Optional<T> getAs() const {
+ if (!T::isKind(*this))
+ return None;
+ return *static_cast<const T *>(this);
+ }
+
+ unsigned getRawKind() const { return Kind; }
+ BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
+ unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
+
+ // This method is required for using SVal in a FoldingSetNode. It
+ // extracts a unique signature for this SVal object.
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger((unsigned) getRawKind());
+ ID.AddPointer(Data);
+ }
+
+ bool operator==(const SVal &R) const {
+ return getRawKind() == R.getRawKind() && Data == R.Data;
+ }
+
+ bool operator!=(const SVal &R) const {
+ return !(*this == R);
+ }
+
+ bool isUnknown() const {
+ return getRawKind() == UnknownValKind;
+ }
+
+ bool isUndef() const {
+ return getRawKind() == UndefinedValKind;
+ }
+
+ bool isUnknownOrUndef() const {
+ return getRawKind() <= UnknownValKind;
+ }
+
+ bool isValid() const {
+ return getRawKind() > UnknownValKind;
+ }
+
+ bool isConstant() const;
+
+ bool isConstant(int I) const;
+
+ bool isZeroConstant() const;
+
+ /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true;
+ bool hasConjuredSymbol() const;
+
+ /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a
+ /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl.
+ /// Otherwise return 0.
+ const FunctionDecl *getAsFunctionDecl() const;
+
+ /// If this SVal is a location and wraps a symbol, return that
+ /// SymbolRef. Otherwise return 0.
+ ///
+ /// Casts are ignored during lookup.
+ /// \param IncludeBaseRegions The boolean that controls whether the search
+ /// should continue to the base regions if the region is not symbolic.
+ SymbolRef getAsLocSymbol(bool IncludeBaseRegions = false) const;
+
+ /// Get the symbol in the SVal or its base region.
+ SymbolRef getLocSymbolInBase() const;
+
+ /// If this SVal wraps a symbol return that SymbolRef.
+ /// Otherwise, return 0.
+ ///
+ /// Casts are ignored during lookup.
+ /// \param IncludeBaseRegions The boolean that controls whether the search
+ /// should continue to the base regions if the region is not symbolic.
+ SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const;
+
+ /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
+ /// return that expression. Otherwise return NULL.
+ const SymExpr *getAsSymbolicExpression() const;
+
+ const SymExpr *getAsSymExpr() const;
+
+ const MemRegion *getAsRegion() const;
+
+ void dumpToStream(raw_ostream &OS) const;
+ void dump() const;
+
+ SymExpr::symbol_iterator symbol_begin() const {
+ const SymExpr *SE = getAsSymbol(/*IncludeBaseRegions=*/true);
+ if (SE)
+ return SE->symbol_begin();
+ else
+ return SymExpr::symbol_iterator();
+ }
+
+ SymExpr::symbol_iterator symbol_end() const {
+ return SymExpr::symbol_end();
+ }
+};
+
+inline raw_ostream &operator<<(raw_ostream &os, clang::ento::SVal V) {
+ V.dumpToStream(os);
+ return os;
+}
+
+class UndefinedVal : public SVal {
+public:
+ UndefinedVal() : SVal(UndefinedValKind) {}
+
+private:
+ friend class SVal;
+
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == UndefinedValKind;
+ }
+};
+
+class DefinedOrUnknownSVal : public SVal {
+public:
+ // We want calling these methods to be a compiler error since they are
+ // tautologically false.
+ bool isUndef() const = delete;
+ bool isValid() const = delete;
+
+protected:
+ DefinedOrUnknownSVal() = default;
+ explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind)
+ : SVal(d, isLoc, ValKind) {}
+ explicit DefinedOrUnknownSVal(BaseKind k, void *D = nullptr) : SVal(k, D) {}
+
+private:
+ friend class SVal;
+
+ static bool isKind(const SVal& V) {
+ return !V.isUndef();
+ }
+};
+
+class UnknownVal : public DefinedOrUnknownSVal {
+public:
+ explicit UnknownVal() : DefinedOrUnknownSVal(UnknownValKind) {}
+
+private:
+ friend class SVal;
+
+ static bool isKind(const SVal &V) {
+ return V.getBaseKind() == UnknownValKind;
+ }
+};
+
+class DefinedSVal : public DefinedOrUnknownSVal {
+public:
+ // We want calling these methods to be a compiler error since they are
+ // tautologically true/false.
+ bool isUnknown() const = delete;
+ bool isUnknownOrUndef() const = delete;
+ bool isValid() const = delete;
+
+protected:
+ DefinedSVal() = default;
+ explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind)
+ : DefinedOrUnknownSVal(d, isLoc, ValKind) {}
+
+private:
+ friend class SVal;
+
+ static bool isKind(const SVal& V) {
+ return !V.isUnknownOrUndef();
+ }
+};
+
+/// Represents an SVal that is guaranteed to not be UnknownVal.
+class KnownSVal : public SVal {
+ friend class SVal;
+
+ KnownSVal() = default;
+
+ static bool isKind(const SVal &V) {
+ return !V.isUnknown();
+ }
+
+public:
+ KnownSVal(const DefinedSVal &V) : SVal(V) {}
+ KnownSVal(const UndefinedVal &V) : SVal(V) {}
+};
+
+class NonLoc : public DefinedSVal {
+protected:
+ NonLoc() = default;
+ explicit NonLoc(unsigned SubKind, const void *d)
+ : DefinedSVal(d, false, SubKind) {}
+
+public:
+ void dumpToStream(raw_ostream &Out) const;
+
+ static bool isCompoundType(QualType T) {
+ return T->isArrayType() || T->isRecordType() ||
+ T->isComplexType() || T->isVectorType();
+ }
+
+private:
+ friend class SVal;
+
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind;
+ }
+};
+
+class Loc : public DefinedSVal {
+protected:
+ Loc() = default;
+ explicit Loc(unsigned SubKind, const void *D)
+ : DefinedSVal(const_cast<void *>(D), true, SubKind) {}
+
+public:
+ void dumpToStream(raw_ostream &Out) const;
+
+ static bool isLocType(QualType T) {
+ return T->isAnyPointerType() || T->isBlockPointerType() ||
+ T->isReferenceType() || T->isNullPtrType();
+ }
+
+private:
+ friend class SVal;
+
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind;
+ }
+};
+
+//==------------------------------------------------------------------------==//
+// Subclasses of NonLoc.
+//==------------------------------------------------------------------------==//
+
+namespace nonloc {
+
+/// Represents symbolic expression that isn't a location.
+class SymbolVal : public NonLoc {
+public:
+ SymbolVal() = delete;
+ SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {
+ assert(sym);
+ assert(!Loc::isLocType(sym->getType()));
+ }
+
+ SymbolRef getSymbol() const {
+ return (const SymExpr *) Data;
+ }
+
+ bool isExpression() const {
+ return !isa<SymbolData>(getSymbol());
+ }
+
+private:
+ friend class SVal;
+
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == SymbolValKind;
+ }
+
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == SymbolValKind;
+ }
+};
+
+/// Value representing integer constant.
+class ConcreteInt : public NonLoc {
+public:
+ explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
+
+ const llvm::APSInt& getValue() const {
+ return *static_cast<const llvm::APSInt *>(Data);
+ }
+
+ // Transfer functions for binary/unary operations on ConcreteInts.
+ SVal evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op,
+ const ConcreteInt& R) const;
+
+ ConcreteInt evalComplement(SValBuilder &svalBuilder) const;
+
+ ConcreteInt evalMinus(SValBuilder &svalBuilder) const;
+
+private:
+ friend class SVal;
+
+ ConcreteInt() = default;
+
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == ConcreteIntKind;
+ }
+
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == ConcreteIntKind;
+ }
+};
+
+class LocAsInteger : public NonLoc {
+ friend class ento::SValBuilder;
+
+ explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data)
+ : NonLoc(LocAsIntegerKind, &data) {
+ // We do not need to represent loc::ConcreteInt as LocAsInteger,
+ // as it'd collapse into a nonloc::ConcreteInt instead.
+ assert(data.first.getBaseKind() == LocKind &&
+ (data.first.getSubKind() == loc::MemRegionValKind ||
+ data.first.getSubKind() == loc::GotoLabelKind));
+ }
+
+public:
+ Loc getLoc() const {
+ const std::pair<SVal, uintptr_t> *D =
+ static_cast<const std::pair<SVal, uintptr_t> *>(Data);
+ return D->first.castAs<Loc>();
+ }
+
+ Loc getPersistentLoc() const {
+ const std::pair<SVal, uintptr_t> *D =
+ static_cast<const std::pair<SVal, uintptr_t> *>(Data);
+ const SVal& V = D->first;
+ return V.castAs<Loc>();
+ }
+
+ unsigned getNumBits() const {
+ const std::pair<SVal, uintptr_t> *D =
+ static_cast<const std::pair<SVal, uintptr_t> *>(Data);
+ return D->second;
+ }
+
+private:
+ friend class SVal;
+
+ LocAsInteger() = default;
+
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == LocAsIntegerKind;
+ }
+
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == LocAsIntegerKind;
+ }
+};
+
+class CompoundVal : public NonLoc {
+ friend class ento::SValBuilder;
+
+ explicit CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {}
+
+public:
+ const CompoundValData* getValue() const {
+ return static_cast<const CompoundValData *>(Data);
+ }
+
+ using iterator = llvm::ImmutableList<SVal>::iterator;
+
+ iterator begin() const;
+ iterator end() const;
+
+private:
+ friend class SVal;
+
+ CompoundVal() = default;
+
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind && V.getSubKind() == CompoundValKind;
+ }
+
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == CompoundValKind;
+ }
+};
+
+class LazyCompoundVal : public NonLoc {
+ friend class ento::SValBuilder;
+
+ explicit LazyCompoundVal(const LazyCompoundValData *D)
+ : NonLoc(LazyCompoundValKind, D) {}
+
+public:
+ const LazyCompoundValData *getCVData() const {
+ return static_cast<const LazyCompoundValData *>(Data);
+ }
+
+ const void *getStore() const;
+ const TypedValueRegion *getRegion() const;
+
+private:
+ friend class SVal;
+
+ LazyCompoundVal() = default;
+
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == LazyCompoundValKind;
+ }
+
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == LazyCompoundValKind;
+ }
+};
+
+/// Value representing pointer-to-member.
+///
+/// This value is qualified as NonLoc because neither loading nor storing
+/// operations are applied to it. Instead, the analyzer uses the L-value coming
+/// from pointer-to-member applied to an object.
+/// This SVal is represented by a DeclaratorDecl which can be a member function
+/// pointer or a member data pointer and a list of CXXBaseSpecifiers. This list
+/// is required to accumulate the pointer-to-member cast history to figure out
+/// the correct subobject field.
+class PointerToMember : public NonLoc {
+ friend class ento::SValBuilder;
+
+public:
+ using PTMDataType =
+ llvm::PointerUnion<const DeclaratorDecl *, const PointerToMemberData *>;
+
+ const PTMDataType getPTMData() const {
+ return PTMDataType::getFromOpaqueValue(const_cast<void *>(Data));
+ }
+
+ bool isNullMemberPointer() const;
+
+ const DeclaratorDecl *getDecl() const;
+
+ template<typename AdjustedDecl>
+ const AdjustedDecl *getDeclAs() const {
+ return dyn_cast_or_null<AdjustedDecl>(getDecl());
+ }
+
+ using iterator = llvm::ImmutableList<const CXXBaseSpecifier *>::iterator;
+
+ iterator begin() const;
+ iterator end() const;
+
+private:
+ friend class SVal;
+
+ PointerToMember() = default;
+ explicit PointerToMember(const PTMDataType D)
+ : NonLoc(PointerToMemberKind, D.getOpaqueValue()) {}
+
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == PointerToMemberKind;
+ }
+
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == PointerToMemberKind;
+ }
+};
+
+} // namespace nonloc
+
+//==------------------------------------------------------------------------==//
+// Subclasses of Loc.
+//==------------------------------------------------------------------------==//
+
+namespace loc {
+
+class GotoLabel : public Loc {
+public:
+ explicit GotoLabel(const LabelDecl *Label) : Loc(GotoLabelKind, Label) {
+ assert(Label);
+ }
+
+ const LabelDecl *getLabel() const {
+ return static_cast<const LabelDecl *>(Data);
+ }
+
+private:
+ friend class SVal;
+
+ GotoLabel() = default;
+
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind && V.getSubKind() == GotoLabelKind;
+ }
+
+ static bool isKind(const Loc& V) {
+ return V.getSubKind() == GotoLabelKind;
+ }
+};
+
+class MemRegionVal : public Loc {
+public:
+ explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) {
+ assert(r);
+ }
+
+ /// Get the underlining region.
+ const MemRegion *getRegion() const {
+ return static_cast<const MemRegion *>(Data);
+ }
+
+ /// Get the underlining region and strip casts.
+ const MemRegion* stripCasts(bool StripBaseCasts = true) const;
+
+ template <typename REGION>
+ const REGION* getRegionAs() const {
+ return dyn_cast<REGION>(getRegion());
+ }
+
+ bool operator==(const MemRegionVal &R) const {
+ return getRegion() == R.getRegion();
+ }
+
+ bool operator!=(const MemRegionVal &R) const {
+ return getRegion() != R.getRegion();
+ }
+
+private:
+ friend class SVal;
+
+ MemRegionVal() = default;
+
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind &&
+ V.getSubKind() == MemRegionValKind;
+ }
+
+ static bool isKind(const Loc& V) {
+ return V.getSubKind() == MemRegionValKind;
+ }
+};
+
+class ConcreteInt : public Loc {
+public:
+ explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {}
+
+ const llvm::APSInt &getValue() const {
+ return *static_cast<const llvm::APSInt *>(Data);
+ }
+
+ // Transfer functions for binary/unary operations on ConcreteInts.
+ SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
+ const ConcreteInt& R) const;
+
+private:
+ friend class SVal;
+
+ ConcreteInt() = default;
+
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind &&
+ V.getSubKind() == ConcreteIntKind;
+ }
+
+ static bool isKind(const Loc& V) {
+ return V.getSubKind() == ConcreteIntKind;
+ }
+};
+
+} // namespace loc
+
+} // namespace ento
+
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h
new file mode 100644
index 00000000..6bf5e94a
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h
@@ -0,0 +1,92 @@
+//== SimpleConstraintManager.h ----------------------------------*- C++ -*--==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Simplified constraint manager backend.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SIMPLECONSTRAINTMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SIMPLECONSTRAINTMANAGER_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+
+namespace clang {
+
+namespace ento {
+
+class SimpleConstraintManager : public ConstraintManager {
+ SubEngine *SU;
+ SValBuilder &SVB;
+
+public:
+ SimpleConstraintManager(SubEngine *subengine, SValBuilder &SB)
+ : SU(subengine), SVB(SB) {}
+
+ ~SimpleConstraintManager() override;
+
+ //===------------------------------------------------------------------===//
+ // Implementation for interface from ConstraintManager.
+ //===------------------------------------------------------------------===//
+
+ /// Ensures that the DefinedSVal conditional is expressed as a NonLoc by
+ /// creating boolean casts to handle Loc's.
+ ProgramStateRef assume(ProgramStateRef State, DefinedSVal Cond,
+ bool Assumption) override;
+
+ ProgramStateRef assumeInclusiveRange(ProgramStateRef State, NonLoc Value,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InRange) override;
+
+protected:
+ //===------------------------------------------------------------------===//
+ // Interface that subclasses must implement.
+ //===------------------------------------------------------------------===//
+
+ /// Given a symbolic expression that can be reasoned about, assume that it is
+ /// true/false and generate the new program state.
+ virtual ProgramStateRef assumeSym(ProgramStateRef State, SymbolRef Sym,
+ bool Assumption) = 0;
+
+ /// Given a symbolic expression within the range [From, To], assume that it is
+ /// true/false and generate the new program state.
+ /// This function is used to handle case ranges produced by a language
+ /// extension for switch case statements.
+ virtual ProgramStateRef assumeSymInclusiveRange(ProgramStateRef State,
+ SymbolRef Sym,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InRange) = 0;
+
+ /// Given a symbolic expression that cannot be reasoned about, assume that
+ /// it is zero/nonzero and add it directly to the solver state.
+ virtual ProgramStateRef assumeSymUnsupported(ProgramStateRef State,
+ SymbolRef Sym,
+ bool Assumption) = 0;
+
+ //===------------------------------------------------------------------===//
+ // Internal implementation.
+ //===------------------------------------------------------------------===//
+
+ SValBuilder &getSValBuilder() const { return SVB; }
+ BasicValueFactory &getBasicVals() const { return SVB.getBasicValueFactory(); }
+ SymbolManager &getSymbolManager() const { return SVB.getSymbolManager(); }
+
+private:
+ ProgramStateRef assume(ProgramStateRef State, NonLoc Cond, bool Assumption);
+
+ ProgramStateRef assumeAux(ProgramStateRef State, NonLoc Cond,
+ bool Assumption);
+};
+
+} // end namespace ento
+
+} // end namespace clang
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
new file mode 100644
index 00000000..17736833
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -0,0 +1,338 @@
+//===- Store.h - Interface for maps from Locations to Values ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defined the types Store and StoreManager.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H
+
+#include "clang/AST/Type.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include <cassert>
+#include <cstdint>
+#include <memory>
+
+namespace clang {
+
+class ASTContext;
+class CastExpr;
+class CompoundLiteralExpr;
+class CXXBasePath;
+class Decl;
+class Expr;
+class LocationContext;
+class ObjCIvarDecl;
+class StackFrameContext;
+
+namespace ento {
+
+class CallEvent;
+class ProgramStateManager;
+class ScanReachableSymbols;
+class SymbolReaper;
+
+using InvalidatedSymbols = llvm::DenseSet<SymbolRef>;
+
+class StoreManager {
+protected:
+ SValBuilder &svalBuilder;
+ ProgramStateManager &StateMgr;
+
+ /// MRMgr - Manages region objects associated with this StoreManager.
+ MemRegionManager &MRMgr;
+ ASTContext &Ctx;
+
+ StoreManager(ProgramStateManager &stateMgr);
+
+public:
+ virtual ~StoreManager() = default;
+
+ /// Return the value bound to specified location in a given state.
+ /// \param[in] store The store in which to make the lookup.
+ /// \param[in] loc The symbolic memory location.
+ /// \param[in] T An optional type that provides a hint indicating the
+ /// expected type of the returned value. This is used if the value is
+ /// lazily computed.
+ /// \return The value bound to the location \c loc.
+ virtual SVal getBinding(Store store, Loc loc, QualType T = QualType()) = 0;
+
+ /// Return the default value bound to a region in a given store. The default
+ /// binding is the value of sub-regions that were not initialized separately
+ /// from their base region. For example, if the structure is zero-initialized
+ /// upon construction, this method retrieves the concrete zero value, even if
+ /// some or all fields were later overwritten manually. Default binding may be
+ /// an unknown, undefined, concrete, or symbolic value.
+ /// \param[in] store The store in which to make the lookup.
+ /// \param[in] R The region to find the default binding for.
+ /// \return The default value bound to the region in the store, if a default
+ /// binding exists.
+ virtual Optional<SVal> getDefaultBinding(Store store, const MemRegion *R) = 0;
+
+ /// Return the default value bound to a LazyCompoundVal. The default binding
+ /// is used to represent the value of any fields or elements within the
+ /// structure represented by the LazyCompoundVal which were not initialized
+ /// explicitly separately from the whole structure. Default binding may be an
+ /// unknown, undefined, concrete, or symbolic value.
+ /// \param[in] lcv The lazy compound value.
+ /// \return The default value bound to the LazyCompoundVal \c lcv, if a
+ /// default binding exists.
+ Optional<SVal> getDefaultBinding(nonloc::LazyCompoundVal lcv) {
+ return getDefaultBinding(lcv.getStore(), lcv.getRegion());
+ }
+
+ /// Return a store with the specified value bound to the given location.
+ /// \param[in] store The store in which to make the binding.
+ /// \param[in] loc The symbolic memory location.
+ /// \param[in] val The value to bind to location \c loc.
+ /// \return A StoreRef object that contains the same
+ /// bindings as \c store with the addition of having the value specified
+ /// by \c val bound to the location given for \c loc.
+ virtual StoreRef Bind(Store store, Loc loc, SVal val) = 0;
+
+ /// Return a store with the specified value bound to all sub-regions of the
+ /// region. The region must not have previous bindings. If you need to
+ /// invalidate existing bindings, consider invalidateRegions().
+ virtual StoreRef BindDefaultInitial(Store store, const MemRegion *R,
+ SVal V) = 0;
+
+ /// Return a store with in which all values within the given region are
+ /// reset to zero. This method is allowed to overwrite previous bindings.
+ virtual StoreRef BindDefaultZero(Store store, const MemRegion *R) = 0;
+
+ /// 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;
+
+ /// getInitialStore - Returns the initial "empty" store representing the
+ /// value bindings upon entry to an analyzed function.
+ virtual StoreRef getInitialStore(const LocationContext *InitLoc) = 0;
+
+ /// getRegionManager - Returns the internal RegionManager object that is
+ /// used to query and manipulate MemRegion objects.
+ MemRegionManager& getRegionManager() { return MRMgr; }
+
+ SValBuilder& getSValBuilder() { return svalBuilder; }
+
+ virtual Loc getLValueVar(const VarDecl *VD, const LocationContext *LC) {
+ return svalBuilder.makeLoc(MRMgr.getVarRegion(VD, LC));
+ }
+
+ Loc getLValueCompoundLiteral(const CompoundLiteralExpr *CL,
+ const LocationContext *LC) {
+ return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
+ }
+
+ virtual SVal getLValueIvar(const ObjCIvarDecl *decl, SVal base);
+
+ virtual SVal getLValueField(const FieldDecl *D, SVal Base) {
+ return getLValueFieldOrIvar(D, Base);
+ }
+
+ virtual SVal getLValueElement(QualType elementType, NonLoc offset, SVal Base);
+
+ // FIXME: This should soon be eliminated altogether; clients should deal with
+ // region extents directly.
+ virtual DefinedOrUnknownSVal getSizeInElements(ProgramStateRef state,
+ const MemRegion *region,
+ QualType EleTy) {
+ return UnknownVal();
+ }
+
+ /// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit
+ /// conversions between arrays and pointers.
+ virtual SVal ArrayToPointer(Loc Array, QualType ElementTy) = 0;
+
+ /// 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.
+ SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType,
+ bool IsVirtual);
+
+ /// Attempts to do a down cast. Used to model BaseToDerived and C++
+ /// dynamic_cast.
+ /// The callback may result in the following 3 scenarios:
+ /// - Successful cast (ex: derived is subclass of base).
+ /// - Failed cast (ex: derived is definitely not a subclass of base).
+ /// The distinction of this case from the next one is necessary to model
+ /// dynamic_cast.
+ /// - We don't know (base is a symbolic region and we don't have
+ /// 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.
+ SVal attemptDownCast(SVal Base, QualType DerivedPtrType, bool &Failed);
+
+ const ElementRegion *GetElementZeroRegion(const SubRegion *R, QualType T);
+
+ /// castRegion - Used by ExprEngine::VisitCast to handle casts from
+ /// a MemRegion* to a specific location type. 'R' is the region being
+ /// casted and 'CastToTy' the result type of the cast.
+ const MemRegion *castRegion(const MemRegion *region, QualType CastToTy);
+
+ virtual StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx,
+ SymbolReaper &SymReaper) = 0;
+
+ virtual bool includedInBindings(Store store,
+ const MemRegion *region) const = 0;
+
+ /// If the StoreManager supports it, increment the reference count of
+ /// the specified Store object.
+ virtual void incrementReferenceCount(Store store) {}
+
+ /// If the StoreManager supports it, decrement the reference count of
+ /// the specified Store object. If the reference count hits 0, the memory
+ /// associated with the object is recycled.
+ virtual void decrementReferenceCount(Store store) {}
+
+ using InvalidatedRegions = SmallVector<const MemRegion *, 8>;
+
+ /// invalidateRegions - Clears out the specified regions from the store,
+ /// marking their values as unknown. Depending on the store, this may also
+ /// invalidate additional regions that may have changed based on accessing
+ /// the given regions. Optionally, invalidates non-static globals as well.
+ /// \param[in] store The initial store
+ /// \param[in] Values The values to invalidate.
+ /// \param[in] E The current statement being evaluated. Used to conjure
+ /// symbols to mark the values of invalidated regions.
+ /// \param[in] Count The current block count. Used to conjure
+ /// symbols to mark the values of invalidated regions.
+ /// \param[in] Call The call expression which will be used to determine which
+ /// globals should get invalidated.
+ /// \param[in,out] IS A set to fill with any symbols that are no longer
+ /// accessible. Pass \c NULL if this information will not be used.
+ /// \param[in] ITraits Information about invalidation for a particular
+ /// region/symbol.
+ /// \param[in,out] InvalidatedTopLevel A vector to fill with regions
+ //// explicitly being invalidated. Pass \c NULL if this
+ /// information will not be used.
+ /// \param[in,out] Invalidated A vector to fill with any regions being
+ /// invalidated. This should include any regions explicitly invalidated
+ /// even if they do not currently have bindings. Pass \c NULL if this
+ /// information will not be used.
+ virtual StoreRef invalidateRegions(Store store,
+ ArrayRef<SVal> Values,
+ const Expr *E, unsigned Count,
+ const LocationContext *LCtx,
+ const CallEvent *Call,
+ InvalidatedSymbols &IS,
+ RegionAndSymbolInvalidationTraits &ITraits,
+ InvalidatedRegions *InvalidatedTopLevel,
+ InvalidatedRegions *Invalidated) = 0;
+
+ /// enterStackFrame - Let the StoreManager to do something when execution
+ /// engine is about to execute into a callee.
+ StoreRef enterStackFrame(Store store,
+ const CallEvent &Call,
+ const StackFrameContext *CalleeCtx);
+
+ /// Finds the transitive closure of symbols within the given region.
+ ///
+ /// Returns false if the visitor aborted the scan.
+ virtual bool scanReachableSymbols(Store S, const MemRegion *R,
+ ScanReachableSymbols &Visitor) = 0;
+
+ virtual void print(Store store, raw_ostream &Out, const char* nl) = 0;
+
+ class BindingsHandler {
+ public:
+ virtual ~BindingsHandler();
+
+ /// \return whether the iteration should continue.
+ virtual bool HandleBinding(StoreManager& SMgr, Store store,
+ const MemRegion *region, SVal val) = 0;
+ };
+
+ class FindUniqueBinding : public BindingsHandler {
+ SymbolRef Sym;
+ const MemRegion* Binding = nullptr;
+ bool First = true;
+
+ public:
+ FindUniqueBinding(SymbolRef sym) : Sym(sym) {}
+
+ explicit operator bool() { return First && Binding; }
+
+ bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
+ SVal val) override;
+ const MemRegion *getRegion() { return Binding; }
+ };
+
+ /// iterBindings - Iterate over the bindings in the Store.
+ virtual void iterBindings(Store store, BindingsHandler& f) = 0;
+
+protected:
+ const ElementRegion *MakeElementRegion(const SubRegion *baseRegion,
+ QualType pointeeTy,
+ uint64_t index = 0);
+
+ /// CastRetrievedVal - Used by subclasses of StoreManager to implement
+ /// implicit casts that arise from loads from regions that are reinterpreted
+ /// as another region.
+ SVal CastRetrievedVal(SVal val, const TypedValueRegion *region,
+ QualType castTy);
+
+private:
+ SVal getLValueFieldOrIvar(const Decl *decl, SVal base);
+};
+
+inline StoreRef::StoreRef(Store store, StoreManager & smgr)
+ : store(store), mgr(smgr) {
+ if (store)
+ mgr.incrementReferenceCount(store);
+}
+
+inline StoreRef::StoreRef(const StoreRef &sr)
+ : store(sr.store), mgr(sr.mgr)
+{
+ if (store)
+ mgr.incrementReferenceCount(store);
+}
+
+inline StoreRef::~StoreRef() {
+ if (store)
+ mgr.decrementReferenceCount(store);
+}
+
+inline StoreRef &StoreRef::operator=(StoreRef const &newStore) {
+ assert(&newStore.mgr == &mgr);
+ if (store != newStore.store) {
+ mgr.incrementReferenceCount(newStore.store);
+ mgr.decrementReferenceCount(store);
+ store = newStore.getStore();
+ }
+ return *this;
+}
+
+// FIXME: Do we need to pass ProgramStateManager anymore?
+std::unique_ptr<StoreManager>
+CreateRegionStoreManager(ProgramStateManager &StMgr);
+std::unique_ptr<StoreManager>
+CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr);
+
+} // namespace ento
+
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
new file mode 100644
index 00000000..a2dd05cf
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
@@ -0,0 +1,53 @@
+//===- StoreRef.h - Smart pointer for store objects -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defined the type StoreRef.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STOREREF_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STOREREF_H
+
+#include <cassert>
+
+namespace clang {
+namespace ento {
+
+class StoreManager;
+
+/// Store - This opaque type encapsulates an immutable mapping from
+/// locations to values. At a high-level, it represents the symbolic
+/// memory model. Different subclasses of StoreManager may choose
+/// different types to represent the locations and values.
+using Store = const void *;
+
+class StoreRef {
+ Store store;
+ StoreManager &mgr;
+
+public:
+ StoreRef(Store store, StoreManager &smgr);
+ StoreRef(const StoreRef &sr);
+ StoreRef &operator=(StoreRef const &newStore);
+ ~StoreRef();
+
+ bool operator==(const StoreRef &x) const {
+ assert(&mgr == &x.mgr);
+ return x.store == store;
+ }
+
+ bool operator!=(const StoreRef &x) const { return !operator==(x); }
+
+ Store getStore() const { return store; }
+ const StoreManager &getStoreManager() const { return mgr; }
+};
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STOREREF_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
new file mode 100644
index 00000000..9296e17c
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -0,0 +1,175 @@
+//== SubEngine.h - Interface of the subengine of CoreEngine --------*- C++ -*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the interface of a subengine of the CoreEngine.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SUBENGINE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SUBENGINE_H
+
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
+
+namespace clang {
+
+class CFGBlock;
+class CFGElement;
+class LocationContext;
+class Stmt;
+
+namespace cross_tu {
+class CrossTranslationUnitContext;
+}
+
+namespace ento {
+
+struct NodeBuilderContext;
+class AnalysisManager;
+class ExplodedNodeSet;
+class ExplodedNode;
+class ProgramState;
+class ProgramStateManager;
+class BlockCounter;
+class BranchNodeBuilder;
+class IndirectGotoNodeBuilder;
+class SwitchNodeBuilder;
+class EndOfFunctionNodeBuilder;
+class NodeBuilderWithSinks;
+class MemRegion;
+
+class SubEngine {
+ virtual void anchor();
+public:
+ virtual ~SubEngine() {}
+
+ virtual ProgramStateRef getInitialState(const LocationContext *InitLoc) = 0;
+
+ virtual AnalysisManager &getAnalysisManager() = 0;
+
+ virtual cross_tu::CrossTranslationUnitContext *
+ getCrossTranslationUnitContext() = 0;
+
+ virtual ProgramStateManager &getStateManager() = 0;
+
+ /// Called by CoreEngine. Used to generate new successor
+ /// nodes by processing the 'effects' of a block-level statement.
+ virtual void processCFGElement(const CFGElement E, ExplodedNode* Pred,
+ unsigned StmtIdx, NodeBuilderContext *Ctx)=0;
+
+ /// Called by CoreEngine when it starts processing a CFGBlock. The
+ /// 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,
+ ExplodedNode *Pred) = 0;
+
+ /// Called by CoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a branch condition.
+ virtual void processBranch(const Stmt *Condition,
+ NodeBuilderContext& BuilderCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) = 0;
+
+ /// Called by CoreEngine.
+ /// Used to generate successor nodes for temporary destructors depending
+ /// on whether the corresponding constructor was visited.
+ virtual void processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
+ NodeBuilderContext &BldCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) = 0;
+
+ /// Called by CoreEngine. Used to processing branching behavior
+ /// at static initializers.
+ virtual void processStaticInitializer(const DeclStmt *DS,
+ NodeBuilderContext& BuilderCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) = 0;
+
+ /// Called by CoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a computed goto jump.
+ virtual void processIndirectGoto(IndirectGotoNodeBuilder& builder) = 0;
+
+ /// Called by CoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a switch statement.
+ virtual void processSwitch(SwitchNodeBuilder& builder) = 0;
+
+ /// Called by CoreEngine. Used to notify checkers that processing a
+ /// function has begun. Called for both inlined and and top-level functions.
+ virtual void processBeginOfFunction(NodeBuilderContext &BC,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const BlockEdge &L) = 0;
+
+ /// Called by CoreEngine. Used to notify checkers that processing a
+ /// function has ended. Called for both inlined and and top-level functions.
+ virtual void processEndOfFunction(NodeBuilderContext& BC,
+ ExplodedNode *Pred,
+ const ReturnStmt *RS = nullptr) = 0;
+
+ // Generate the entry node of the callee.
+ virtual void processCallEnter(NodeBuilderContext& BC, CallEnter CE,
+ ExplodedNode *Pred) = 0;
+
+ // Generate the first post callsite node.
+ virtual void processCallExit(ExplodedNode *Pred) = 0;
+
+ /// Called by ConstraintManager. Used to call checker-specific
+ /// logic for handling assumptions on symbolic values.
+ virtual ProgramStateRef processAssume(ProgramStateRef state,
+ SVal cond, bool assumption) = 0;
+
+ /// processRegionChanges - Called by ProgramStateManager whenever a change is
+ /// made to the store. Used to update checkers that track region values.
+ virtual ProgramStateRef
+ processRegionChanges(ProgramStateRef state,
+ const InvalidatedSymbols *invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
+ const CallEvent *Call) = 0;
+
+
+ inline ProgramStateRef
+ processRegionChange(ProgramStateRef state,
+ const MemRegion* MR,
+ const LocationContext *LCtx) {
+ return processRegionChanges(state, nullptr, MR, MR, LCtx, nullptr);
+ }
+
+ virtual ProgramStateRef
+ processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, SVal Val, const LocationContext *LCtx) = 0;
+
+ virtual ProgramStateRef
+ notifyCheckersOfPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols *Invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ const CallEvent *Call,
+ RegionAndSymbolInvalidationTraits &HTraits) = 0;
+
+ /// printState - Called by ProgramStateManager to print checker-specific data.
+ virtual void printState(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const char *Sep,
+ const LocationContext *LCtx = nullptr) = 0;
+
+ /// Called by CoreEngine when the analysis worklist is either empty or the
+ // maximum number of analysis steps have been reached.
+ virtual void processEndWorklist() = 0;
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SummaryManager.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SummaryManager.h
new file mode 100644
index 00000000..1a56153d
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SummaryManager.h
@@ -0,0 +1,57 @@
+//== SummaryManager.h - Generic handling of function summaries --*- C++ -*--==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SummaryManager and related classes, which provides
+// a generic mechanism for managing function summaries.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_SUMMARY
+#define LLVM_CLANG_GR_SUMMARY
+
+namespace clang {
+
+namespace ento {
+
+namespace summMgr {
+
+
+/* Key kinds:
+
+ - C functions
+ - C++ functions (name + parameter types)
+ - ObjC methods:
+ - Class, selector (class method)
+ - Class, selector (instance method)
+ - Category, selector (instance method)
+ - Protocol, selector (instance method)
+ - C++ methods
+ - Class, function name + parameter types + const
+ */
+
+class SummaryKey {
+
+};
+
+} // end namespace clang::summMgr
+
+class SummaryManagerImpl {
+
+};
+
+
+template <typename T>
+class SummaryManager : SummaryManagerImpl {
+
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
new file mode 100644
index 00000000..abfcd1d8
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
@@ -0,0 +1,145 @@
+//===- SymExpr.h - Management of Symbolic Values ----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SymExpr and SymbolData.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMEXPR_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMEXPR_H
+
+#include "clang/AST/Type.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include <cassert>
+
+namespace clang {
+namespace ento {
+
+class MemRegion;
+
+/// Symbolic value. These values used to capture symbolic execution of
+/// the program.
+class SymExpr : public llvm::FoldingSetNode {
+ virtual void anchor();
+
+public:
+ enum Kind {
+#define SYMBOL(Id, Parent) Id##Kind,
+#define SYMBOL_RANGE(Id, First, Last) BEGIN_##Id = First, END_##Id = Last,
+#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
+ };
+
+private:
+ Kind K;
+
+protected:
+ SymExpr(Kind k) : K(k) {}
+
+ static bool isValidTypeForSymbol(QualType T) {
+ // FIXME: Depending on whether we choose to deprecate structural symbols,
+ // this may become much stricter.
+ return !T.isNull() && !T->isVoidType();
+ }
+
+ mutable unsigned Complexity = 0;
+
+public:
+ virtual ~SymExpr() = default;
+
+ Kind getKind() const { return K; }
+
+ virtual void dump() const;
+
+ virtual void dumpToStream(raw_ostream &os) const {}
+
+ virtual QualType getType() const = 0;
+ virtual void Profile(llvm::FoldingSetNodeID &profile) = 0;
+
+ /// Iterator over symbols that the current symbol depends on.
+ ///
+ /// For SymbolData, it's the symbol itself; for expressions, it's the
+ /// expression symbol and all the operands in it. Note, SymbolDerived is
+ /// treated as SymbolData - the iterator will NOT visit the parent region.
+ class symbol_iterator {
+ SmallVector<const SymExpr *, 5> itr;
+
+ void expand();
+
+ public:
+ symbol_iterator() = default;
+ symbol_iterator(const SymExpr *SE);
+
+ symbol_iterator &operator++();
+ const SymExpr *operator*();
+
+ bool operator==(const symbol_iterator &X) const;
+ bool operator!=(const symbol_iterator &X) const;
+ };
+
+ symbol_iterator symbol_begin() const { return symbol_iterator(this); }
+ static symbol_iterator symbol_end() { return symbol_iterator(); }
+
+ virtual unsigned computeComplexity() const = 0;
+
+ /// Find the region from which this symbol originates.
+ ///
+ /// Whenever the symbol was constructed to denote an unknown value of
+ /// a certain memory region, return this region. This method
+ /// allows checkers to make decisions depending on the origin of the symbol.
+ /// Symbol classes for which the origin region is known include
+ /// SymbolRegionValue which denotes the value of the region before
+ /// the beginning of the analysis, and SymbolDerived which denotes the value
+ /// of a certain memory region after its super region (a memory space or
+ /// a larger record region) is default-bound with a certain symbol.
+ virtual const MemRegion *getOriginRegion() const { return nullptr; }
+};
+
+inline raw_ostream &operator<<(raw_ostream &os,
+ const clang::ento::SymExpr *SE) {
+ SE->dumpToStream(os);
+ return os;
+}
+
+using SymbolRef = const SymExpr *;
+using SymbolRefSmallVectorTy = SmallVector<SymbolRef, 2>;
+using SymbolID = unsigned;
+
+/// A symbol representing data which can be stored in a memory location
+/// (region).
+class SymbolData : public SymExpr {
+ const SymbolID Sym;
+
+ void anchor() override;
+
+protected:
+ SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {
+ assert(classof(this));
+ }
+
+public:
+ ~SymbolData() override = default;
+
+ SymbolID getSymbolID() const { return Sym; }
+
+ unsigned computeComplexity() const override {
+ return 1;
+ };
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr *SE) {
+ Kind k = SE->getKind();
+ return k >= BEGIN_SYMBOLS && k <= END_SYMBOLS;
+ }
+};
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMEXPR_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
new file mode 100644
index 00000000..d212e23d
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -0,0 +1,650 @@
+//===- SymbolManager.h - Management of Symbolic Values ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SymbolManager, a class that manages symbolic values
+// created for use by ExprEngine and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H
+
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/Allocator.h"
+#include <cassert>
+
+namespace clang {
+
+class ASTContext;
+class Stmt;
+
+namespace ento {
+
+class BasicValueFactory;
+class StoreManager;
+
+///A symbol representing the value stored at a MemRegion.
+class SymbolRegionValue : public SymbolData {
+ const TypedValueRegion *R;
+
+public:
+ SymbolRegionValue(SymbolID sym, const TypedValueRegion *r)
+ : SymbolData(SymbolRegionValueKind, sym), R(r) {
+ assert(r);
+ assert(isValidTypeForSymbol(r->getValueType()));
+ }
+
+ const TypedValueRegion* getRegion() const { return R; }
+
+ static void Profile(llvm::FoldingSetNodeID& profile, const TypedValueRegion* R) {
+ profile.AddInteger((unsigned) SymbolRegionValueKind);
+ profile.AddPointer(R);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& profile) override {
+ Profile(profile, R);
+ }
+
+ void dumpToStream(raw_ostream &os) const override;
+ const MemRegion *getOriginRegion() const override { return getRegion(); }
+
+ QualType getType() const override;
+
+ // Implement isa<T> support.
+ static bool classof(const SymExpr *SE) {
+ return SE->getKind() == SymbolRegionValueKind;
+ }
+};
+
+/// A symbol representing the result of an expression in the case when we do
+/// not know anything about what the expression is.
+class SymbolConjured : public SymbolData {
+ const Stmt *S;
+ QualType T;
+ unsigned Count;
+ const LocationContext *LCtx;
+ const void *SymbolTag;
+
+public:
+ SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx,
+ QualType t, unsigned count, const void *symbolTag)
+ : SymbolData(SymbolConjuredKind, sym), S(s), T(t), Count(count),
+ LCtx(lctx), SymbolTag(symbolTag) {
+ // FIXME: 's' might be a nullptr if we're conducting invalidation
+ // that was caused by a destructor call on a temporary object,
+ // which has no statement associated with it.
+ // Due to this, we might be creating the same invalidation symbol for
+ // two different invalidation passes (for two different temporaries).
+ assert(lctx);
+ assert(isValidTypeForSymbol(t));
+ }
+
+ const Stmt *getStmt() const { return S; }
+ unsigned getCount() const { return Count; }
+ const void *getTag() const { return SymbolTag; }
+
+ QualType getType() const override;
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ static void Profile(llvm::FoldingSetNodeID& profile, const Stmt *S,
+ QualType T, unsigned Count, const LocationContext *LCtx,
+ const void *SymbolTag) {
+ profile.AddInteger((unsigned) SymbolConjuredKind);
+ profile.AddPointer(S);
+ profile.AddPointer(LCtx);
+ profile.Add(T);
+ profile.AddInteger(Count);
+ profile.AddPointer(SymbolTag);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& profile) override {
+ Profile(profile, S, T, Count, LCtx, SymbolTag);
+ }
+
+ // Implement isa<T> support.
+ static bool classof(const SymExpr *SE) {
+ return SE->getKind() == SymbolConjuredKind;
+ }
+};
+
+/// A symbol representing the value of a MemRegion whose parent region has
+/// symbolic value.
+class SymbolDerived : public SymbolData {
+ SymbolRef parentSymbol;
+ const TypedValueRegion *R;
+
+public:
+ SymbolDerived(SymbolID sym, SymbolRef parent, const TypedValueRegion *r)
+ : SymbolData(SymbolDerivedKind, sym), parentSymbol(parent), R(r) {
+ assert(parent);
+ assert(r);
+ assert(isValidTypeForSymbol(r->getValueType()));
+ }
+
+ SymbolRef getParentSymbol() const { return parentSymbol; }
+ const TypedValueRegion *getRegion() const { return R; }
+
+ QualType getType() const override;
+
+ void dumpToStream(raw_ostream &os) const override;
+ const MemRegion *getOriginRegion() const override { return getRegion(); }
+
+ static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent,
+ const TypedValueRegion *r) {
+ profile.AddInteger((unsigned) SymbolDerivedKind);
+ profile.AddPointer(r);
+ profile.AddPointer(parent);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& profile) override {
+ Profile(profile, parentSymbol, R);
+ }
+
+ // Implement isa<T> support.
+ static bool classof(const SymExpr *SE) {
+ return SE->getKind() == SymbolDerivedKind;
+ }
+};
+
+/// SymbolExtent - Represents the extent (size in bytes) of a bounded region.
+/// Clients should not ask the SymbolManager for a region's extent. Always use
+/// SubRegion::getExtent instead -- the value returned may not be a symbol.
+class SymbolExtent : public SymbolData {
+ const SubRegion *R;
+
+public:
+ SymbolExtent(SymbolID sym, const SubRegion *r)
+ : SymbolData(SymbolExtentKind, sym), R(r) {
+ assert(r);
+ }
+
+ const SubRegion *getRegion() const { return R; }
+
+ QualType getType() const override;
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) {
+ profile.AddInteger((unsigned) SymbolExtentKind);
+ profile.AddPointer(R);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& profile) override {
+ Profile(profile, R);
+ }
+
+ // Implement isa<T> support.
+ static bool classof(const SymExpr *SE) {
+ return SE->getKind() == SymbolExtentKind;
+ }
+};
+
+/// SymbolMetadata - Represents path-dependent metadata about a specific region.
+/// Metadata symbols remain live as long as they are marked as in use before
+/// dead-symbol sweeping AND their associated regions are still alive.
+/// Intended for use by checkers.
+class SymbolMetadata : public SymbolData {
+ const MemRegion* R;
+ const Stmt *S;
+ QualType T;
+ const LocationContext *LCtx;
+ unsigned Count;
+ const void *Tag;
+
+public:
+ SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt *s, QualType t,
+ const LocationContext *LCtx, unsigned count, const void *tag)
+ : SymbolData(SymbolMetadataKind, sym), R(r), S(s), T(t), LCtx(LCtx),
+ Count(count), Tag(tag) {
+ assert(r);
+ assert(s);
+ assert(isValidTypeForSymbol(t));
+ assert(LCtx);
+ assert(tag);
+ }
+
+ const MemRegion *getRegion() const { return R; }
+ const Stmt *getStmt() const { return S; }
+ const LocationContext *getLocationContext() const { return LCtx; }
+ unsigned getCount() const { return Count; }
+ const void *getTag() const { return Tag; }
+
+ QualType getType() const override;
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion *R,
+ const Stmt *S, QualType T, const LocationContext *LCtx,
+ unsigned Count, const void *Tag) {
+ profile.AddInteger((unsigned) SymbolMetadataKind);
+ profile.AddPointer(R);
+ profile.AddPointer(S);
+ profile.Add(T);
+ profile.AddPointer(LCtx);
+ profile.AddInteger(Count);
+ profile.AddPointer(Tag);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& profile) override {
+ Profile(profile, R, S, T, LCtx, Count, Tag);
+ }
+
+ // Implement isa<T> support.
+ static bool classof(const SymExpr *SE) {
+ return SE->getKind() == SymbolMetadataKind;
+ }
+};
+
+/// Represents a cast expression.
+class SymbolCast : public SymExpr {
+ const SymExpr *Operand;
+
+ /// Type of the operand.
+ QualType FromTy;
+
+ /// The type of the result.
+ QualType ToTy;
+
+public:
+ SymbolCast(const SymExpr *In, QualType From, QualType To)
+ : SymExpr(SymbolCastKind), Operand(In), FromTy(From), ToTy(To) {
+ assert(In);
+ assert(isValidTypeForSymbol(From));
+ // FIXME: GenericTaintChecker creates symbols of void type.
+ // Otherwise, 'To' should also be a valid type.
+ }
+
+ unsigned computeComplexity() const override {
+ if (Complexity == 0)
+ Complexity = 1 + Operand->computeComplexity();
+ return Complexity;
+ }
+
+ QualType getType() const override { return ToTy; }
+
+ const SymExpr *getOperand() const { return Operand; }
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ static void Profile(llvm::FoldingSetNodeID& ID,
+ const SymExpr *In, QualType From, QualType To) {
+ ID.AddInteger((unsigned) SymbolCastKind);
+ ID.AddPointer(In);
+ ID.Add(From);
+ ID.Add(To);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) override {
+ Profile(ID, Operand, FromTy, ToTy);
+ }
+
+ // Implement isa<T> support.
+ static bool classof(const SymExpr *SE) {
+ return SE->getKind() == SymbolCastKind;
+ }
+};
+
+/// Represents a symbolic expression involving a binary operator
+class BinarySymExpr : public SymExpr {
+ BinaryOperator::Opcode Op;
+ QualType T;
+
+protected:
+ BinarySymExpr(Kind k, BinaryOperator::Opcode op, QualType t)
+ : SymExpr(k), Op(op), T(t) {
+ assert(classof(this));
+ // Binary expressions are results of arithmetic. Pointer arithmetic is not
+ // handled by binary expressions, but it is instead handled by applying
+ // sub-regions to regions.
+ assert(isValidTypeForSymbol(t) && !Loc::isLocType(t));
+ }
+
+public:
+ // FIXME: We probably need to make this out-of-line to avoid redundant
+ // generation of virtual functions.
+ QualType getType() const override { return T; }
+
+ BinaryOperator::Opcode getOpcode() const { return Op; }
+
+ // Implement isa<T> support.
+ static bool classof(const SymExpr *SE) {
+ Kind k = SE->getKind();
+ return k >= BEGIN_BINARYSYMEXPRS && k <= END_BINARYSYMEXPRS;
+ }
+};
+
+/// Represents a symbolic expression like 'x' + 3.
+class SymIntExpr : public BinarySymExpr {
+ const SymExpr *LHS;
+ const llvm::APSInt& RHS;
+
+public:
+ SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const llvm::APSInt &rhs, QualType t)
+ : BinarySymExpr(SymIntExprKind, op, t), LHS(lhs), RHS(rhs) {
+ assert(lhs);
+ }
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ const SymExpr *getLHS() const { return LHS; }
+ const llvm::APSInt &getRHS() const { return RHS; }
+
+ unsigned computeComplexity() const override {
+ if (Complexity == 0)
+ Complexity = 1 + LHS->computeComplexity();
+ return Complexity;
+ }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
+ BinaryOperator::Opcode op, const llvm::APSInt& rhs,
+ QualType t) {
+ ID.AddInteger((unsigned) SymIntExprKind);
+ ID.AddPointer(lhs);
+ ID.AddInteger(op);
+ ID.AddPointer(&rhs);
+ ID.Add(t);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) override {
+ Profile(ID, LHS, getOpcode(), RHS, getType());
+ }
+
+ // Implement isa<T> support.
+ static bool classof(const SymExpr *SE) {
+ return SE->getKind() == SymIntExprKind;
+ }
+};
+
+/// Represents a symbolic expression like 3 - 'x'.
+class IntSymExpr : public BinarySymExpr {
+ const llvm::APSInt& LHS;
+ const SymExpr *RHS;
+
+public:
+ IntSymExpr(const llvm::APSInt &lhs, BinaryOperator::Opcode op,
+ const SymExpr *rhs, QualType t)
+ : BinarySymExpr(IntSymExprKind, op, t), LHS(lhs), RHS(rhs) {
+ assert(rhs);
+ }
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ const SymExpr *getRHS() const { return RHS; }
+ const llvm::APSInt &getLHS() const { return LHS; }
+
+ unsigned computeComplexity() const override {
+ if (Complexity == 0)
+ Complexity = 1 + RHS->computeComplexity();
+ return Complexity;
+ }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, const llvm::APSInt& lhs,
+ BinaryOperator::Opcode op, const SymExpr *rhs,
+ QualType t) {
+ ID.AddInteger((unsigned) IntSymExprKind);
+ ID.AddPointer(&lhs);
+ ID.AddInteger(op);
+ ID.AddPointer(rhs);
+ ID.Add(t);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) override {
+ Profile(ID, LHS, getOpcode(), RHS, getType());
+ }
+
+ // Implement isa<T> support.
+ static bool classof(const SymExpr *SE) {
+ return SE->getKind() == IntSymExprKind;
+ }
+};
+
+/// Represents a symbolic expression like 'x' + 'y'.
+class SymSymExpr : public BinarySymExpr {
+ const SymExpr *LHS;
+ const SymExpr *RHS;
+
+public:
+ SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs,
+ QualType t)
+ : BinarySymExpr(SymSymExprKind, op, t), LHS(lhs), RHS(rhs) {
+ assert(lhs);
+ assert(rhs);
+ }
+
+ const SymExpr *getLHS() const { return LHS; }
+ const SymExpr *getRHS() const { return RHS; }
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ unsigned computeComplexity() const override {
+ if (Complexity == 0)
+ Complexity = RHS->computeComplexity() + LHS->computeComplexity();
+ return Complexity;
+ }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
+ BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) {
+ ID.AddInteger((unsigned) SymSymExprKind);
+ ID.AddPointer(lhs);
+ ID.AddInteger(op);
+ ID.AddPointer(rhs);
+ ID.Add(t);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) override {
+ Profile(ID, LHS, getOpcode(), RHS, getType());
+ }
+
+ // Implement isa<T> support.
+ static bool classof(const SymExpr *SE) {
+ return SE->getKind() == SymSymExprKind;
+ }
+};
+
+class SymbolManager {
+ using DataSetTy = llvm::FoldingSet<SymExpr>;
+ using SymbolDependTy = llvm::DenseMap<SymbolRef, SymbolRefSmallVectorTy *>;
+
+ DataSetTy DataSet;
+
+ /// Stores the extra dependencies between symbols: the data should be kept
+ /// alive as long as the key is live.
+ SymbolDependTy SymbolDependencies;
+
+ unsigned SymbolCounter = 0;
+ llvm::BumpPtrAllocator& BPAlloc;
+ BasicValueFactory &BV;
+ ASTContext &Ctx;
+
+public:
+ SymbolManager(ASTContext &ctx, BasicValueFactory &bv,
+ llvm::BumpPtrAllocator& bpalloc)
+ : SymbolDependencies(16), BPAlloc(bpalloc), BV(bv), Ctx(ctx) {}
+ ~SymbolManager();
+
+ static bool canSymbolicate(QualType T);
+
+ /// Make a unique symbol for MemRegion R according to its kind.
+ const SymbolRegionValue* getRegionValueSymbol(const TypedValueRegion* R);
+
+ const SymbolConjured* conjureSymbol(const Stmt *E,
+ const LocationContext *LCtx,
+ QualType T,
+ unsigned VisitCount,
+ const void *SymbolTag = nullptr);
+
+ const SymbolConjured* conjureSymbol(const Expr *E,
+ const LocationContext *LCtx,
+ unsigned VisitCount,
+ const void *SymbolTag = nullptr) {
+ return conjureSymbol(E, LCtx, E->getType(), VisitCount, SymbolTag);
+ }
+
+ const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol,
+ const TypedValueRegion *R);
+
+ const SymbolExtent *getExtentSymbol(const SubRegion *R);
+
+ /// Creates a metadata symbol associated with a specific region.
+ ///
+ /// VisitCount can be used to differentiate regions corresponding to
+ /// different loop iterations, thus, making the symbol path-dependent.
+ const SymbolMetadata *getMetadataSymbol(const MemRegion *R, const Stmt *S,
+ QualType T,
+ const LocationContext *LCtx,
+ unsigned VisitCount,
+ const void *SymbolTag = nullptr);
+
+ const SymbolCast* getCastSymbol(const SymExpr *Operand,
+ QualType From, QualType To);
+
+ const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const llvm::APSInt& rhs, QualType t);
+
+ const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op,
+ const llvm::APSInt& rhs, QualType t) {
+ return getSymIntExpr(&lhs, op, rhs, t);
+ }
+
+ const IntSymExpr *getIntSymExpr(const llvm::APSInt& lhs,
+ BinaryOperator::Opcode op,
+ const SymExpr *rhs, QualType t);
+
+ const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const SymExpr *rhs, QualType t);
+
+ QualType getType(const SymExpr *SE) const {
+ return SE->getType();
+ }
+
+ /// Add artificial symbol dependency.
+ ///
+ /// The dependent symbol should stay alive as long as the primary is alive.
+ void addSymbolDependency(const SymbolRef Primary, const SymbolRef Dependent);
+
+ const SymbolRefSmallVectorTy *getDependentSymbols(const SymbolRef Primary);
+
+ ASTContext &getContext() { return Ctx; }
+ BasicValueFactory &getBasicVals() { return BV; }
+};
+
+/// A class responsible for cleaning up unused symbols.
+class SymbolReaper {
+ enum SymbolStatus {
+ NotProcessed,
+ HaveMarkedDependents
+ };
+
+ using SymbolSetTy = llvm::DenseSet<SymbolRef>;
+ using SymbolMapTy = llvm::DenseMap<SymbolRef, SymbolStatus>;
+ using RegionSetTy = llvm::DenseSet<const MemRegion *>;
+
+ SymbolMapTy TheLiving;
+ SymbolSetTy MetadataInUse;
+
+ RegionSetTy RegionRoots;
+
+ const StackFrameContext *LCtx;
+ const Stmt *Loc;
+ SymbolManager& SymMgr;
+ StoreRef reapedStore;
+ llvm::DenseMap<const MemRegion *, unsigned> includedRegionCache;
+
+public:
+ /// Construct a reaper object, which removes everything which is not
+ /// live before we execute statement s in the given location context.
+ ///
+ /// If the statement is NULL, everything is this and parent contexts is
+ /// considered live.
+ /// 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), Loc(s), SymMgr(symmgr), reapedStore(nullptr, storeMgr) {}
+
+ const LocationContext *getLocationContext() const { return LCtx; }
+
+ bool isLive(SymbolRef sym);
+ bool isLiveRegion(const MemRegion *region);
+ bool isLive(const Stmt *ExprVal, const LocationContext *LCtx) const;
+ bool isLive(const VarRegion *VR, bool includeStoreBindings = false) const;
+
+ /// Unconditionally marks a symbol as live.
+ ///
+ /// This should never be
+ /// used by checkers, only by the state infrastructure such as the store and
+ /// environment. Checkers should instead use metadata symbols and markInUse.
+ void markLive(SymbolRef sym);
+
+ /// Marks a symbol as important to a checker.
+ ///
+ /// For metadata symbols,
+ /// this will keep the symbol alive as long as its associated region is also
+ /// live. For other symbols, this has no effect; checkers are not permitted
+ /// to influence the life of other symbols. This should be used before any
+ /// symbol marking has occurred, i.e. in the MarkLiveSymbols callback.
+ void markInUse(SymbolRef sym);
+
+ using region_iterator = RegionSetTy::const_iterator;
+
+ region_iterator region_begin() const { return RegionRoots.begin(); }
+ region_iterator region_end() const { return RegionRoots.end(); }
+
+ /// Returns whether or not a symbol has been confirmed dead.
+ ///
+ /// This should only be called once all marking of dead symbols has completed.
+ /// (For checkers, this means only in the checkDeadSymbols callback.)
+ bool isDead(SymbolRef sym) {
+ return !isLive(sym);
+ }
+
+ void markLive(const MemRegion *region);
+ void markElementIndicesLive(const MemRegion *region);
+
+ /// Set to the value of the symbolic store after
+ /// StoreManager::removeDeadBindings has been called.
+ void setReapedStore(StoreRef st) { reapedStore = st; }
+
+private:
+ /// Mark the symbols dependent on the input symbol as live.
+ void markDependentsLive(SymbolRef sym);
+};
+
+class SymbolVisitor {
+protected:
+ ~SymbolVisitor() = default;
+
+public:
+ SymbolVisitor() = default;
+ SymbolVisitor(const SymbolVisitor &) = default;
+ SymbolVisitor(SymbolVisitor &&) {}
+
+ /// 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 *) { return true; }
+};
+
+} // namespace ento
+
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def
new file mode 100644
index 00000000..7163a162
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def
@@ -0,0 +1,54 @@
+//===-- Symbols.def - Metadata about SymExpr kinds --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// The list of symbols (SymExpr sub-classes) used in the Static Analyzer.
+// In order to use this information, users of this file must define
+// one or more of the three macros:
+//
+// SYMBOL(Id, Parent) - for specific SymExpr sub-classes, reserving the
+// IdKind identifier for its kind enumeration value.
+//
+// ABSTRACT_SYMBOL(Id, Parent) - for abstract symbol classes,
+//
+// SYMBOL_RANGE(Id, First, Last) - for ranges of kind-enums,
+// allowing to determine abstract class of a symbol
+// based on the kind enumeration value.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SYMBOL
+#define SYMBOL(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_SYMBOL
+#define ABSTRACT_SYMBOL(Id, Parent)
+#endif
+
+#ifndef SYMBOL_RANGE
+#define SYMBOL_RANGE(Id, First, Last)
+#endif
+
+ABSTRACT_SYMBOL(BinarySymExpr, SymExpr)
+ SYMBOL(IntSymExpr, BinarySymExpr)
+ SYMBOL(SymIntExpr, BinarySymExpr)
+ SYMBOL(SymSymExpr, BinarySymExpr)
+SYMBOL_RANGE(BINARYSYMEXPRS, IntSymExprKind, SymSymExprKind)
+
+SYMBOL(SymbolCast, SymExpr)
+
+ABSTRACT_SYMBOL(SymbolData, SymExpr)
+ SYMBOL(SymbolConjured, SymbolData)
+ SYMBOL(SymbolDerived, SymbolData)
+ SYMBOL(SymbolExtent, SymbolData)
+ SYMBOL(SymbolMetadata, SymbolData)
+ SYMBOL(SymbolRegionValue, SymbolData)
+SYMBOL_RANGE(SYMBOLS, SymbolConjuredKind, SymbolRegionValueKind)
+
+#undef SYMBOL
+#undef ABSTRACT_SYMBOL
+#undef SYMBOL_RANGE
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
new file mode 100644
index 00000000..9424392c
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
@@ -0,0 +1,58 @@
+//===- TaintManager.h - Managing taint --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides APIs for adding, removing, querying symbol taint.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTMANAGER_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h"
+#include "llvm/ADT/ImmutableMap.h"
+
+namespace clang {
+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 {};
+
+using TaintMapImpl = llvm::ImmutableMap<SymbolRef, TaintTagType>;
+
+template<> struct ProgramStateTrait<TaintMap>
+ : public ProgramStatePartialTrait<TaintMapImpl> {
+ static void *GDMIndex();
+};
+
+/// The GDM component mapping derived symbols' parent symbols to their
+/// underlying regions. This is used to efficiently check whether a symbol is
+/// tainted when it represents a sub-region of a tainted symbol.
+struct DerivedSymTaint {};
+
+using DerivedSymTaintImpl = llvm::ImmutableMap<SymbolRef, TaintedSubRegions>;
+
+template<> struct ProgramStateTrait<DerivedSymTaint>
+ : public ProgramStatePartialTrait<DerivedSymTaintImpl> {
+ static void *GDMIndex();
+};
+
+class TaintManager {
+ TaintManager() = default;
+};
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTMANAGER_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
new file mode 100644
index 00000000..d1018f9d
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
@@ -0,0 +1,29 @@
+//===- TaintTag.h - Path-sensitive "State" for tracking values --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a set of taint tags. Several tags are used to differentiate kinds
+// of taint.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTTAG_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTTAG_H
+
+namespace clang {
+namespace ento {
+
+/// The type of taint, which helps to differentiate between different types of
+/// taint.
+using TaintTagType = unsigned;
+
+static const TaintTagType TaintTagGeneric = 0;
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTTAG_H
diff --git a/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
new file mode 100644
index 00000000..7beb7ddf
--- /dev/null
+++ b/clang-r353983/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
@@ -0,0 +1,94 @@
+//==- WorkList.h - Worklist class used by CoreEngine ---------------*- C++ -*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines WorkList, a pure virtual class that represents an opaque
+// worklist used by CoreEngine to explore the reachability state space.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_WORKLIST_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_WORKLIST_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include <cassert>
+
+namespace clang {
+
+class CFGBlock;
+
+namespace ento {
+
+class WorkListUnit {
+ ExplodedNode *node;
+ BlockCounter counter;
+ const CFGBlock *block;
+ unsigned blockIdx; // This is the index of the next statement.
+
+public:
+ WorkListUnit(ExplodedNode *N, BlockCounter C,
+ const CFGBlock *B, unsigned idx)
+ : node(N),
+ counter(C),
+ block(B),
+ blockIdx(idx) {}
+
+ explicit WorkListUnit(ExplodedNode *N, BlockCounter C)
+ : node(N),
+ counter(C),
+ block(nullptr),
+ blockIdx(0) {}
+
+ /// Returns the node associated with the worklist unit.
+ ExplodedNode *getNode() const { return node; }
+
+ /// Returns the block counter map associated with the worklist unit.
+ BlockCounter getBlockCounter() const { return counter; }
+
+ /// Returns the CFGblock associated with the worklist unit.
+ const CFGBlock *getBlock() const { return block; }
+
+ /// Return the index within the CFGBlock for the worklist unit.
+ unsigned getIndex() const { return blockIdx; }
+};
+
+class WorkList {
+ BlockCounter CurrentCounter;
+public:
+ virtual ~WorkList();
+ virtual bool hasWork() const = 0;
+
+ virtual void enqueue(const WorkListUnit& U) = 0;
+
+ void enqueue(ExplodedNode *N, const CFGBlock *B, unsigned idx) {
+ enqueue(WorkListUnit(N, CurrentCounter, B, idx));
+ }
+
+ void enqueue(ExplodedNode *N) {
+ assert(N->getLocation().getKind() != ProgramPoint::PostStmtKind);
+ enqueue(WorkListUnit(N, CurrentCounter));
+ }
+
+ virtual WorkListUnit dequeue() = 0;
+
+ void setBlockCounter(BlockCounter C) { CurrentCounter = C; }
+ BlockCounter getBlockCounter() const { return CurrentCounter; }
+
+ static std::unique_ptr<WorkList> makeDFS();
+ static std::unique_ptr<WorkList> makeBFS();
+ static std::unique_ptr<WorkList> makeBFSBlockDFSContents();
+ static std::unique_ptr<WorkList> makeUnexploredFirst();
+ static std::unique_ptr<WorkList> makeUnexploredFirstPriorityQueue();
+ static std::unique_ptr<WorkList> makeUnexploredFirstPriorityLocationQueue();
+};
+
+} // end ento namespace
+
+} // end clang namespace
+
+#endif