summaryrefslogtreecommitdiff
path: root/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h')
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h574
1 files changed, 574 insertions, 0 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
new file mode 100644
index 0000000..d50c3be
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -0,0 +1,574 @@
+//== SVals.h - Abstract Values for Static Analysis ---------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SVal, Loc, and NonLoc, classes that represent
+// abstract r-values for use with path-sensitive value tracking.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_RVALUE_H
+#define LLVM_CLANG_GR_RVALUE_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/ImmutableList.h"
+
+//==------------------------------------------------------------------------==//
+// Base SVal types.
+//==------------------------------------------------------------------------==//
+
+namespace clang {
+
+namespace ento {
+
+class CompoundValData;
+class LazyCompoundValData;
+class ProgramState;
+class BasicValueFactory;
+class MemRegion;
+class TypedValueRegion;
+class MemRegionManager;
+class ProgramStateManager;
+class SValBuilder;
+
+/// 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.
+ UndefinedKind = 0, // for subclass UndefinedVal (an uninitialized value)
+ UnknownKind = 1, // for subclass UnknownVal (a void value)
+ LocKind = 2, // for subclass Loc (an L-value)
+ NonLocKind = 3 // for subclass NonLoc (an R-value that's not
+ // an L-value)
+ };
+ enum { BaseBits = 2, BaseMask = 0x3 };
+
+protected:
+ const void *Data;
+
+ /// The lowest 2 bits are a BaseKind (0 -- 3).
+ /// The higher bits are an unsigned "kind" value.
+ unsigned Kind;
+
+ 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() : Data(nullptr), Kind(0) {}
+
+ /// \brief Convert to the specified SVal type, asserting that this SVal is of
+ /// the desired type.
+ template<typename T>
+ T castAs() const {
+ assert(T::isKind(*this));
+ T t;
+ SVal& sv = t;
+ sv = *this;
+ return t;
+ }
+
+ /// \brief Convert to the specified SVal type, returning None if this SVal is
+ /// not of the desired type.
+ template<typename T>
+ Optional<T> getAs() const {
+ if (!T::isKind(*this))
+ return None;
+ T t;
+ SVal& sv = t;
+ sv = *this;
+ return t;
+ }
+
+ /// BufferTy - A temporary buffer to hold a set of SVals.
+ typedef SmallVector<SVal,5> BufferTy;
+
+ inline unsigned getRawKind() const { return Kind; }
+ inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
+ inline 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.
+ inline void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddInteger((unsigned) getRawKind());
+ ID.AddPointer(Data);
+ }
+
+ inline bool operator==(const SVal& R) const {
+ return getRawKind() == R.getRawKind() && Data == R.Data;
+ }
+
+ inline bool operator!=(const SVal& R) const {
+ return !(*this == R);
+ }
+
+ inline bool isUnknown() const {
+ return getRawKind() == UnknownKind;
+ }
+
+ inline bool isUndef() const {
+ return getRawKind() == UndefinedKind;
+ }
+
+ inline bool isUnknownOrUndef() const {
+ return getRawKind() <= UnknownKind;
+ }
+
+ inline bool isValid() const {
+ return getRawKind() > UnknownKind;
+ }
+
+ 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;
+
+ /// \brief If this SVal is a location and wraps a symbol, return that
+ /// SymbolRef. Otherwise return 0.
+ ///
+ /// Casts are ignored during lookup.
+ /// \param IncludeBaseRegions The boolean that controls whether the search
+ /// should continue to the base regions if the region is not symbolic.
+ SymbolRef getAsLocSymbol(bool IncludeBaseRegions = false) const;
+
+ /// Get the symbol in the SVal or its base region.
+ SymbolRef getLocSymbolInBase() const;
+
+ /// \brief 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 = getAsSymbolicExpression();
+ if (SE)
+ return SE->symbol_begin();
+ else
+ return SymExpr::symbol_iterator();
+ }
+
+ SymExpr::symbol_iterator symbol_end() const {
+ return SymExpr::symbol_end();
+ }
+};
+
+
+class UndefinedVal : public SVal {
+public:
+ UndefinedVal() : SVal(UndefinedKind) {}
+
+private:
+ friend class SVal;
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == UndefinedKind;
+ }
+};
+
+class DefinedOrUnknownSVal : public SVal {
+private:
+ // We want calling these methods to be a compiler error since they are
+ // tautologically false.
+ bool isUndef() const LLVM_DELETED_FUNCTION;
+ bool isValid() const LLVM_DELETED_FUNCTION;
+
+protected:
+ DefinedOrUnknownSVal() {}
+ explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind)
+ : SVal(d, isLoc, ValKind) {}
+
+ explicit DefinedOrUnknownSVal(BaseKind k, void *D = 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(UnknownKind) {}
+
+private:
+ friend class SVal;
+ static bool isKind(const SVal &V) {
+ return V.getBaseKind() == UnknownKind;
+ }
+};
+
+class DefinedSVal : public DefinedOrUnknownSVal {
+private:
+ // We want calling these methods to be a compiler error since they are
+ // tautologically true/false.
+ bool isUnknown() const LLVM_DELETED_FUNCTION;
+ bool isUnknownOrUndef() const LLVM_DELETED_FUNCTION;
+ bool isValid() const LLVM_DELETED_FUNCTION;
+protected:
+ DefinedSVal() {}
+ explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind)
+ : DefinedOrUnknownSVal(d, isLoc, ValKind) {}
+private:
+ friend class SVal;
+ static bool isKind(const SVal& V) {
+ return !V.isUnknownOrUndef();
+ }
+};
+
+
+/// \brief Represents an SVal that is guaranteed to not be UnknownVal.
+class KnownSVal : public SVal {
+ KnownSVal() {}
+ friend class SVal;
+ static bool isKind(const SVal &V) {
+ return !V.isUnknown();
+ }
+public:
+ KnownSVal(const DefinedSVal &V) : SVal(V) {}
+ KnownSVal(const UndefinedVal &V) : SVal(V) {}
+};
+
+class NonLoc : public DefinedSVal {
+protected:
+ NonLoc() {}
+ explicit NonLoc(unsigned SubKind, const void *d)
+ : DefinedSVal(d, false, SubKind) {}
+
+public:
+ void dumpToStream(raw_ostream &Out) const;
+
+private:
+ friend class SVal;
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind;
+ }
+};
+
+class Loc : public DefinedSVal {
+protected:
+ Loc() {}
+ explicit Loc(unsigned SubKind, const void *D)
+ : DefinedSVal(const_cast<void*>(D), true, SubKind) {}
+
+public:
+ void dumpToStream(raw_ostream &Out) const;
+
+ static inline 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 {
+
+enum Kind { ConcreteIntKind, SymbolValKind,
+ LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
+
+/// \brief Represents symbolic expression.
+class SymbolVal : public NonLoc {
+public:
+ SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {}
+
+ SymbolRef getSymbol() const {
+ return (const SymExpr*) Data;
+ }
+
+ bool isExpression() const {
+ return !isa<SymbolData>(getSymbol());
+ }
+
+private:
+ friend class SVal;
+ SymbolVal() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == SymbolValKind;
+ }
+
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == SymbolValKind;
+ }
+};
+
+/// \brief 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() {}
+ 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) {
+ assert (data.first.getAs<Loc>());
+ }
+
+public:
+
+ Loc getLoc() const {
+ const std::pair<SVal, uintptr_t> *D =
+ static_cast<const std::pair<SVal, uintptr_t> *>(Data);
+ return 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() {}
+ 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);
+ }
+
+ typedef llvm::ImmutableList<SVal>::iterator iterator;
+ iterator begin() const;
+ iterator end() const;
+
+private:
+ friend class SVal;
+ CompoundVal() {}
+ 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() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == LazyCompoundValKind;
+ }
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == LazyCompoundValKind;
+ }
+};
+
+} // end namespace ento::nonloc
+
+//==------------------------------------------------------------------------==//
+// Subclasses of Loc.
+//==------------------------------------------------------------------------==//
+
+namespace loc {
+
+enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind };
+
+class GotoLabel : public Loc {
+public:
+ explicit GotoLabel(LabelDecl *Label) : Loc(GotoLabelKind, Label) {}
+
+ const LabelDecl *getLabel() const {
+ return static_cast<const LabelDecl*>(Data);
+ }
+
+private:
+ friend class SVal;
+ GotoLabel() {}
+ 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(MemRegionKind, r) {}
+
+ /// \brief Get the underlining region.
+ const MemRegion* getRegion() const {
+ return static_cast<const MemRegion*>(Data);
+ }
+
+ /// \brief 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());
+ }
+
+ inline bool operator==(const MemRegionVal& R) const {
+ return getRegion() == R.getRegion();
+ }
+
+ inline bool operator!=(const MemRegionVal& R) const {
+ return getRegion() != R.getRegion();
+ }
+
+private:
+ friend class SVal;
+ MemRegionVal() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind &&
+ V.getSubKind() == MemRegionKind;
+ }
+
+ static bool isKind(const Loc& V) {
+ return V.getSubKind() == MemRegionKind;
+ }
+};
+
+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() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind &&
+ V.getSubKind() == ConcreteIntKind;
+ }
+
+ static bool isKind(const Loc& V) {
+ return V.getSubKind() == ConcreteIntKind;
+ }
+};
+
+} // end ento::loc namespace
+
+} // end ento namespace
+
+} // end clang namespace
+
+namespace llvm {
+static inline raw_ostream &operator<<(raw_ostream &os,
+ clang::ento::SVal V) {
+ V.dumpToStream(os);
+ return os;
+}
+
+template <typename T> struct isPodLike;
+template <> struct isPodLike<clang::ento::SVal> {
+ static const bool value = true;
+};
+
+} // end llvm namespace
+
+#endif