1 //== SVals.h - Abstract Values for Static Analysis ---------*- C++ -*--==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines SVal, Loc, and NonLoc, classes that represent
11 // abstract r-values for use with path-sensitive value tracking.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
16 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
18 #include "clang/AST/Expr.h"
19 #include "clang/Basic/LLVM.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
22 #include "llvm/ADT/FoldingSet.h"
23 #include "llvm/ADT/ImmutableList.h"
25 //==------------------------------------------------------------------------==//
27 //==------------------------------------------------------------------------==//
33 class CompoundValData;
34 class LazyCompoundValData;
35 class PointerToMemberData;
37 class BasicValueFactory;
39 class TypedValueRegion;
40 class MemRegionManager;
41 class ProgramStateManager;
45 /// Sub-kinds for NonLoc values.
47 #define NONLOC_SVAL(Id, Parent) Id ## Kind,
48 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
53 /// Sub-kinds for Loc values.
55 #define LOC_SVAL(Id, Parent) Id ## Kind,
56 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
60 /// SVal - This represents a symbolic expression, which can be either
61 /// an L-value or an R-value.
66 // The enumerators must be representable using 2 bits.
67 #define BASIC_SVAL(Id, Parent) Id ## Kind,
68 #define ABSTRACT_SVAL_WITH_KIND(Id, Parent) Id ## Kind,
69 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
71 enum { BaseBits = 2, BaseMask = 0x3 };
76 /// The lowest 2 bits are a BaseKind (0 -- 3).
77 /// The higher bits are an unsigned "kind" value.
80 explicit SVal(const void *d, bool isLoc, unsigned ValKind)
81 : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
83 explicit SVal(BaseKind k, const void *D = nullptr)
87 explicit SVal() : Data(nullptr), Kind(0) {}
89 /// \brief Convert to the specified SVal type, asserting that this SVal is of
93 assert(T::isKind(*this));
94 return *static_cast<const T *>(this);
97 /// \brief Convert to the specified SVal type, returning None if this SVal is
98 /// not of the desired type.
100 Optional<T> getAs() const {
101 if (!T::isKind(*this))
103 return *static_cast<const T *>(this);
106 inline unsigned getRawKind() const { return Kind; }
107 inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
108 inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
110 // This method is required for using SVal in a FoldingSetNode. It
111 // extracts a unique signature for this SVal object.
112 inline void Profile(llvm::FoldingSetNodeID& ID) const {
113 ID.AddInteger((unsigned) getRawKind());
117 inline bool operator==(const SVal& R) const {
118 return getRawKind() == R.getRawKind() && Data == R.Data;
121 inline bool operator!=(const SVal& R) const {
122 return !(*this == R);
125 inline bool isUnknown() const {
126 return getRawKind() == UnknownValKind;
129 inline bool isUndef() const {
130 return getRawKind() == UndefinedValKind;
133 inline bool isUnknownOrUndef() const {
134 return getRawKind() <= UnknownValKind;
137 inline bool isValid() const {
138 return getRawKind() > UnknownValKind;
141 bool isConstant() const;
143 bool isConstant(int I) const;
145 bool isZeroConstant() const;
147 /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true;
148 bool hasConjuredSymbol() const;
150 /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a
151 /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl.
152 /// Otherwise return 0.
153 const FunctionDecl *getAsFunctionDecl() const;
155 /// \brief If this SVal is a location and wraps a symbol, return that
156 /// SymbolRef. Otherwise return 0.
158 /// Casts are ignored during lookup.
159 /// \param IncludeBaseRegions The boolean that controls whether the search
160 /// should continue to the base regions if the region is not symbolic.
161 SymbolRef getAsLocSymbol(bool IncludeBaseRegions = false) const;
163 /// Get the symbol in the SVal or its base region.
164 SymbolRef getLocSymbolInBase() const;
166 /// \brief If this SVal wraps a symbol return that SymbolRef.
167 /// Otherwise, return 0.
169 /// Casts are ignored during lookup.
170 /// \param IncludeBaseRegions The boolean that controls whether the search
171 /// should continue to the base regions if the region is not symbolic.
172 SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const;
174 /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
175 /// return that expression. Otherwise return NULL.
176 const SymExpr *getAsSymbolicExpression() const;
178 const SymExpr* getAsSymExpr() const;
180 const MemRegion *getAsRegion() const;
182 void dumpToStream(raw_ostream &OS) const;
185 SymExpr::symbol_iterator symbol_begin() const {
186 const SymExpr *SE = getAsSymbolicExpression();
188 return SE->symbol_begin();
190 return SymExpr::symbol_iterator();
193 SymExpr::symbol_iterator symbol_end() const {
194 return SymExpr::symbol_end();
198 inline raw_ostream &operator<<(raw_ostream &os, clang::ento::SVal V) {
203 class UndefinedVal : public SVal {
205 UndefinedVal() : SVal(UndefinedValKind) {}
209 static bool isKind(const SVal& V) {
210 return V.getBaseKind() == UndefinedValKind;
214 class DefinedOrUnknownSVal : public SVal {
216 // We want calling these methods to be a compiler error since they are
217 // tautologically false.
218 bool isUndef() const = delete;
219 bool isValid() const = delete;
222 DefinedOrUnknownSVal() {}
223 explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind)
224 : SVal(d, isLoc, ValKind) {}
226 explicit DefinedOrUnknownSVal(BaseKind k, void *D = nullptr)
231 static bool isKind(const SVal& V) {
236 class UnknownVal : public DefinedOrUnknownSVal {
238 explicit UnknownVal() : DefinedOrUnknownSVal(UnknownValKind) {}
242 static bool isKind(const SVal &V) {
243 return V.getBaseKind() == UnknownValKind;
247 class DefinedSVal : public DefinedOrUnknownSVal {
249 // We want calling these methods to be a compiler error since they are
250 // tautologically true/false.
251 bool isUnknown() const = delete;
252 bool isUnknownOrUndef() const = delete;
253 bool isValid() const = delete;
256 explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind)
257 : DefinedOrUnknownSVal(d, isLoc, ValKind) {}
260 static bool isKind(const SVal& V) {
261 return !V.isUnknownOrUndef();
266 /// \brief Represents an SVal that is guaranteed to not be UnknownVal.
267 class KnownSVal : public SVal {
270 static bool isKind(const SVal &V) {
271 return !V.isUnknown();
274 KnownSVal(const DefinedSVal &V) : SVal(V) {}
275 KnownSVal(const UndefinedVal &V) : SVal(V) {}
278 class NonLoc : public DefinedSVal {
281 explicit NonLoc(unsigned SubKind, const void *d)
282 : DefinedSVal(d, false, SubKind) {}
285 void dumpToStream(raw_ostream &Out) const;
287 static inline bool isCompoundType(QualType T) {
288 return T->isArrayType() || T->isRecordType() ||
289 T->isComplexType() || T->isVectorType();
294 static bool isKind(const SVal& V) {
295 return V.getBaseKind() == NonLocKind;
299 class Loc : public DefinedSVal {
302 explicit Loc(unsigned SubKind, const void *D)
303 : DefinedSVal(const_cast<void*>(D), true, SubKind) {}
306 void dumpToStream(raw_ostream &Out) const;
308 static inline bool isLocType(QualType T) {
309 return T->isAnyPointerType() || T->isBlockPointerType() ||
310 T->isReferenceType() || T->isNullPtrType();
315 static bool isKind(const SVal& V) {
316 return V.getBaseKind() == LocKind;
320 //==------------------------------------------------------------------------==//
321 // Subclasses of NonLoc.
322 //==------------------------------------------------------------------------==//
326 /// \brief Represents symbolic expression.
327 class SymbolVal : public NonLoc {
329 SymbolVal() = delete;
330 SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) { assert(sym); }
332 SymbolRef getSymbol() const {
333 return (const SymExpr*) Data;
336 bool isExpression() const {
337 return !isa<SymbolData>(getSymbol());
342 static bool isKind(const SVal& V) {
343 return V.getBaseKind() == NonLocKind &&
344 V.getSubKind() == SymbolValKind;
347 static bool isKind(const NonLoc& V) {
348 return V.getSubKind() == SymbolValKind;
352 /// \brief Value representing integer constant.
353 class ConcreteInt : public NonLoc {
355 explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
357 const llvm::APSInt& getValue() const {
358 return *static_cast<const llvm::APSInt*>(Data);
361 // Transfer functions for binary/unary operations on ConcreteInts.
362 SVal evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op,
363 const ConcreteInt& R) const;
365 ConcreteInt evalComplement(SValBuilder &svalBuilder) const;
367 ConcreteInt evalMinus(SValBuilder &svalBuilder) const;
372 static bool isKind(const SVal& V) {
373 return V.getBaseKind() == NonLocKind &&
374 V.getSubKind() == ConcreteIntKind;
377 static bool isKind(const NonLoc& V) {
378 return V.getSubKind() == ConcreteIntKind;
382 class LocAsInteger : public NonLoc {
383 friend class ento::SValBuilder;
385 explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data)
386 : NonLoc(LocAsIntegerKind, &data) {
387 // We do not need to represent loc::ConcreteInt as LocAsInteger,
388 // as it'd collapse into a nonloc::ConcreteInt instead.
389 assert(data.first.getBaseKind() == LocKind &&
390 (data.first.getSubKind() == loc::MemRegionValKind ||
391 data.first.getSubKind() == loc::GotoLabelKind));
397 const std::pair<SVal, uintptr_t> *D =
398 static_cast<const std::pair<SVal, uintptr_t> *>(Data);
399 return D->first.castAs<Loc>();
402 Loc getPersistentLoc() const {
403 const std::pair<SVal, uintptr_t> *D =
404 static_cast<const std::pair<SVal, uintptr_t> *>(Data);
405 const SVal& V = D->first;
406 return V.castAs<Loc>();
409 unsigned getNumBits() const {
410 const std::pair<SVal, uintptr_t> *D =
411 static_cast<const std::pair<SVal, uintptr_t> *>(Data);
418 static bool isKind(const SVal& V) {
419 return V.getBaseKind() == NonLocKind &&
420 V.getSubKind() == LocAsIntegerKind;
423 static bool isKind(const NonLoc& V) {
424 return V.getSubKind() == LocAsIntegerKind;
428 class CompoundVal : public NonLoc {
429 friend class ento::SValBuilder;
431 explicit CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {}
434 const CompoundValData* getValue() const {
435 return static_cast<const CompoundValData*>(Data);
438 typedef llvm::ImmutableList<SVal>::iterator iterator;
439 iterator begin() const;
440 iterator end() const;
445 static bool isKind(const SVal& V) {
446 return V.getBaseKind() == NonLocKind && V.getSubKind() == CompoundValKind;
449 static bool isKind(const NonLoc& V) {
450 return V.getSubKind() == CompoundValKind;
454 class LazyCompoundVal : public NonLoc {
455 friend class ento::SValBuilder;
457 explicit LazyCompoundVal(const LazyCompoundValData *D)
458 : NonLoc(LazyCompoundValKind, D) {}
460 const LazyCompoundValData *getCVData() const {
461 return static_cast<const LazyCompoundValData*>(Data);
463 const void *getStore() const;
464 const TypedValueRegion *getRegion() const;
469 static bool isKind(const SVal& V) {
470 return V.getBaseKind() == NonLocKind &&
471 V.getSubKind() == LazyCompoundValKind;
473 static bool isKind(const NonLoc& V) {
474 return V.getSubKind() == LazyCompoundValKind;
478 /// \brief Value representing pointer-to-member.
480 /// This value is qualified as NonLoc because neither loading nor storing
481 /// operations are aplied to it. Instead, the analyzer uses the L-value coming
482 /// from pointer-to-member applied to an object.
483 /// This SVal is represented by a DeclaratorDecl which can be a member function
484 /// pointer or a member data pointer and a list of CXXBaseSpecifiers. This list
485 /// is required to accumulate the pointer-to-member cast history to figure out
486 /// the correct subobject field.
487 class PointerToMember : public NonLoc {
488 friend class ento::SValBuilder;
491 typedef llvm::PointerUnion<const DeclaratorDecl *,
492 const PointerToMemberData *> PTMDataType;
493 const PTMDataType getPTMData() const {
494 return PTMDataType::getFromOpaqueValue(const_cast<void *>(Data));
496 bool isNullMemberPointer() const {
497 return getPTMData().isNull();
499 const DeclaratorDecl *getDecl() const;
500 template<typename AdjustedDecl>
501 const AdjustedDecl* getDeclAs() const {
502 return dyn_cast_or_null<AdjustedDecl>(getDecl());
504 typedef llvm::ImmutableList<const CXXBaseSpecifier *>::iterator iterator;
505 iterator begin() const;
506 iterator end() const;
509 explicit PointerToMember(const PTMDataType D)
510 : NonLoc(PointerToMemberKind, D.getOpaqueValue()) {}
513 static bool isKind(const SVal& V) {
514 return V.getBaseKind() == NonLocKind &&
515 V.getSubKind() == PointerToMemberKind;
518 static bool isKind(const NonLoc& V) {
519 return V.getSubKind() == PointerToMemberKind;
523 } // end namespace ento::nonloc
525 //==------------------------------------------------------------------------==//
526 // Subclasses of Loc.
527 //==------------------------------------------------------------------------==//
531 class GotoLabel : public Loc {
533 explicit GotoLabel(const LabelDecl *Label) : Loc(GotoLabelKind, Label) {
537 const LabelDecl *getLabel() const {
538 return static_cast<const LabelDecl*>(Data);
544 static bool isKind(const SVal& V) {
545 return V.getBaseKind() == LocKind && V.getSubKind() == GotoLabelKind;
548 static bool isKind(const Loc& V) {
549 return V.getSubKind() == GotoLabelKind;
554 class MemRegionVal : public Loc {
556 explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) {
560 /// \brief Get the underlining region.
561 const MemRegion* getRegion() const {
562 return static_cast<const MemRegion*>(Data);
565 /// \brief Get the underlining region and strip casts.
566 const MemRegion* stripCasts(bool StripBaseCasts = true) const;
568 template <typename REGION>
569 const REGION* getRegionAs() const {
570 return dyn_cast<REGION>(getRegion());
573 inline bool operator==(const MemRegionVal& R) const {
574 return getRegion() == R.getRegion();
577 inline bool operator!=(const MemRegionVal& R) const {
578 return getRegion() != R.getRegion();
584 static bool isKind(const SVal& V) {
585 return V.getBaseKind() == LocKind &&
586 V.getSubKind() == MemRegionValKind;
589 static bool isKind(const Loc& V) {
590 return V.getSubKind() == MemRegionValKind;
594 class ConcreteInt : public Loc {
596 explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {}
598 const llvm::APSInt& getValue() const {
599 return *static_cast<const llvm::APSInt*>(Data);
602 // Transfer functions for binary/unary operations on ConcreteInts.
603 SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
604 const ConcreteInt& R) const;
609 static bool isKind(const SVal& V) {
610 return V.getBaseKind() == LocKind &&
611 V.getSubKind() == ConcreteIntKind;
614 static bool isKind(const Loc& V) {
615 return V.getSubKind() == ConcreteIntKind;
619 } // end ento::loc namespace
621 } // end ento namespace
623 } // end clang namespace
627 template <typename T> struct isPodLike;
628 template <> struct isPodLike<clang::ento::SVal> {
629 static const bool value = true;
632 } // end llvm namespace