• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //== SVals.h - Abstract Values for Static Analysis ---------*- C++ -*--==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file defines SVal, Loc, and NonLoc, classes that represent
11 //  abstract r-values for use with path-sensitive value tracking.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_GR_RVALUE_H
16 #define LLVM_CLANG_GR_RVALUE_H
17 
18 #include "clang/Basic/LLVM.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
21 #include "llvm/ADT/ImmutableList.h"
22 
23 //==------------------------------------------------------------------------==//
24 //  Base SVal types.
25 //==------------------------------------------------------------------------==//
26 
27 namespace clang {
28 
29 namespace ento {
30 
31 class CompoundValData;
32 class LazyCompoundValData;
33 class ProgramState;
34 class BasicValueFactory;
35 class MemRegion;
36 class TypedRegion;
37 class MemRegionManager;
38 class ProgramStateManager;
39 class SValBuilder;
40 
41 /// SVal - This represents a symbolic expression, which can be either
42 ///  an L-value or an R-value.
43 ///
44 class SVal {
45 public:
46   enum BaseKind {
47     // The enumerators must be representable using 2 bits.
48     UndefinedKind = 0,  // for subclass UndefinedVal (an uninitialized value)
49     UnknownKind = 1,    // for subclass UnknownVal (a void value)
50     LocKind = 2,        // for subclass Loc (an L-value)
51     NonLocKind = 3      // for subclass NonLoc (an R-value that's not
52                         //   an L-value)
53   };
54   enum { BaseBits = 2, BaseMask = 0x3 };
55 
56 protected:
57   const void *Data;
58 
59   /// The lowest 2 bits are a BaseKind (0 -- 3).
60   ///  The higher bits are an unsigned "kind" value.
61   unsigned Kind;
62 
SVal(const void * d,bool isLoc,unsigned ValKind)63   explicit SVal(const void *d, bool isLoc, unsigned ValKind)
64   : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
65 
66   explicit SVal(BaseKind k, const void *D = NULL)
Data(D)67     : Data(D), Kind(k) {}
68 
69 public:
SVal()70   explicit SVal() : Data(0), Kind(0) {}
71 
72   /// BufferTy - A temporary buffer to hold a set of SVals.
73   typedef SmallVector<SVal,5> BufferTy;
74 
getRawKind()75   inline unsigned getRawKind() const { return Kind; }
getBaseKind()76   inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
getSubKind()77   inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
78 
79   // This method is required for using SVal in a FoldingSetNode.  It
80   // extracts a unique signature for this SVal object.
Profile(llvm::FoldingSetNodeID & ID)81   inline void Profile(llvm::FoldingSetNodeID& ID) const {
82     ID.AddInteger((unsigned) getRawKind());
83     ID.AddPointer(Data);
84   }
85 
86   inline bool operator==(const SVal& R) const {
87     return getRawKind() == R.getRawKind() && Data == R.Data;
88   }
89 
90   inline bool operator!=(const SVal& R) const {
91     return !(*this == R);
92   }
93 
isUnknown()94   inline bool isUnknown() const {
95     return getRawKind() == UnknownKind;
96   }
97 
isUndef()98   inline bool isUndef() const {
99     return getRawKind() == UndefinedKind;
100   }
101 
isUnknownOrUndef()102   inline bool isUnknownOrUndef() const {
103     return getRawKind() <= UnknownKind;
104   }
105 
isValid()106   inline bool isValid() const {
107     return getRawKind() > UnknownKind;
108   }
109 
110   bool isConstant() const;
111 
112   bool isConstant(int I) const;
113 
114   bool isZeroConstant() const;
115 
116   /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true;
117   bool hasConjuredSymbol() const;
118 
119   /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a
120   /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl.
121   /// Otherwise return 0.
122   const FunctionDecl *getAsFunctionDecl() const;
123 
124   /// If this SVal is a location (subclasses Loc) and
125   /// wraps a symbol, return that SymbolRef.  Otherwise return 0.
126   SymbolRef getAsLocSymbol() const;
127 
128   /// Get the symbol in the SVal or its base region.
129   SymbolRef getLocSymbolInBase() const;
130 
131   /// If this SVal wraps a symbol return that SymbolRef.
132   /// Otherwise, return 0.
133   SymbolRef getAsSymbol() const;
134 
135   /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
136   ///  return that expression.  Otherwise return NULL.
137   const SymExpr *getAsSymbolicExpression() const;
138 
139   const SymExpr* getAsSymExpr() const;
140 
141   const MemRegion *getAsRegion() const;
142 
143   void dumpToStream(raw_ostream &OS) const;
144   void dump() const;
145 
symbol_begin()146   SymExpr::symbol_iterator symbol_begin() const {
147     const SymExpr *SE = getAsSymbolicExpression();
148     if (SE)
149       return SE->symbol_begin();
150     else
151       return SymExpr::symbol_iterator();
152   }
153 
symbol_end()154   SymExpr::symbol_iterator symbol_end() const {
155     return SymExpr::symbol_end();
156   }
157 
158   // Implement isa<T> support.
classof(const SVal *)159   static inline bool classof(const SVal*) { return true; }
160 };
161 
162 
163 class UndefinedVal : public SVal {
164 public:
UndefinedVal()165   UndefinedVal() : SVal(UndefinedKind) {}
166 
classof(const SVal * V)167   static inline bool classof(const SVal* V) {
168     return V->getBaseKind() == UndefinedKind;
169   }
170 };
171 
172 class DefinedOrUnknownSVal : public SVal {
173 private:
174   // Do not implement.  We want calling these methods to be a compiler
175   // error since they are tautologically false.
176   bool isUndef() const;
177   bool isValid() const;
178 
179 protected:
DefinedOrUnknownSVal(const void * d,bool isLoc,unsigned ValKind)180   explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind)
181     : SVal(d, isLoc, ValKind) {}
182 
183   explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL)
SVal(k,D)184     : SVal(k, D) {}
185 
186 public:
187     // Implement isa<T> support.
classof(const SVal * V)188   static inline bool classof(const SVal *V) {
189     return !V->isUndef();
190   }
191 };
192 
193 class UnknownVal : public DefinedOrUnknownSVal {
194 public:
UnknownVal()195   explicit UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {}
196 
classof(const SVal * V)197   static inline bool classof(const SVal *V) {
198     return V->getBaseKind() == UnknownKind;
199   }
200 };
201 
202 class DefinedSVal : public DefinedOrUnknownSVal {
203 private:
204   // Do not implement.  We want calling these methods to be a compiler
205   // error since they are tautologically true/false.
206   bool isUnknown() const;
207   bool isUnknownOrUndef() const;
208   bool isValid() const;
209 protected:
DefinedSVal(const void * d,bool isLoc,unsigned ValKind)210   explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind)
211     : DefinedOrUnknownSVal(d, isLoc, ValKind) {}
212 public:
213   // Implement isa<T> support.
classof(const SVal * V)214   static inline bool classof(const SVal *V) {
215     return !V->isUnknownOrUndef();
216   }
217 };
218 
219 class NonLoc : public DefinedSVal {
220 protected:
NonLoc(unsigned SubKind,const void * d)221   explicit NonLoc(unsigned SubKind, const void *d)
222     : DefinedSVal(d, false, SubKind) {}
223 
224 public:
225   void dumpToStream(raw_ostream &Out) const;
226 
227   // Implement isa<T> support.
classof(const SVal * V)228   static inline bool classof(const SVal* V) {
229     return V->getBaseKind() == NonLocKind;
230   }
231 };
232 
233 class Loc : public DefinedSVal {
234 protected:
Loc(unsigned SubKind,const void * D)235   explicit Loc(unsigned SubKind, const void *D)
236   : DefinedSVal(const_cast<void*>(D), true, SubKind) {}
237 
238 public:
239   void dumpToStream(raw_ostream &Out) const;
240 
Loc(const Loc & X)241   Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {}
242 
243   // Implement isa<T> support.
classof(const SVal * V)244   static inline bool classof(const SVal* V) {
245     return V->getBaseKind() == LocKind;
246   }
247 
isLocType(QualType T)248   static inline bool isLocType(QualType T) {
249     return T->isAnyPointerType() || T->isBlockPointerType() ||
250            T->isReferenceType();
251   }
252 };
253 
254 //==------------------------------------------------------------------------==//
255 //  Subclasses of NonLoc.
256 //==------------------------------------------------------------------------==//
257 
258 namespace nonloc {
259 
260 enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind,
261             LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
262 
263 /// \brief Represents symbolic expression.
264 class SymbolVal : public NonLoc {
265 public:
SymbolVal(SymbolRef sym)266   SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {}
267 
getSymbol()268   SymbolRef getSymbol() const {
269     return (const SymExpr*) Data;
270   }
271 
isExpression()272   bool isExpression() {
273     return !isa<SymbolData>(getSymbol());
274   }
275 
classof(const SVal * V)276   static inline bool classof(const SVal* V) {
277     return V->getBaseKind() == NonLocKind &&
278            V->getSubKind() == SymbolValKind;
279   }
280 
classof(const NonLoc * V)281   static inline bool classof(const NonLoc* V) {
282     return V->getSubKind() == SymbolValKind;
283   }
284 };
285 
286 /// \brief Value representing integer constant.
287 class ConcreteInt : public NonLoc {
288 public:
ConcreteInt(const llvm::APSInt & V)289   explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
290 
getValue()291   const llvm::APSInt& getValue() const {
292     return *static_cast<const llvm::APSInt*>(Data);
293   }
294 
295   // Transfer functions for binary/unary operations on ConcreteInts.
296   SVal evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op,
297                  const ConcreteInt& R) const;
298 
299   ConcreteInt evalComplement(SValBuilder &svalBuilder) const;
300 
301   ConcreteInt evalMinus(SValBuilder &svalBuilder) const;
302 
303   // Implement isa<T> support.
classof(const SVal * V)304   static inline bool classof(const SVal* V) {
305     return V->getBaseKind() == NonLocKind &&
306            V->getSubKind() == ConcreteIntKind;
307   }
308 
classof(const NonLoc * V)309   static inline bool classof(const NonLoc* V) {
310     return V->getSubKind() == ConcreteIntKind;
311   }
312 };
313 
314 class LocAsInteger : public NonLoc {
315   friend class ento::SValBuilder;
316 
LocAsInteger(const std::pair<SVal,uintptr_t> & data)317   explicit LocAsInteger(const std::pair<SVal, uintptr_t>& data) :
318     NonLoc(LocAsIntegerKind, &data) {
319       assert (isa<Loc>(data.first));
320     }
321 
322 public:
323 
getLoc()324   Loc getLoc() const {
325     const std::pair<SVal, uintptr_t> *D =
326       static_cast<const std::pair<SVal, uintptr_t> *>(Data);
327     return cast<Loc>(D->first);
328   }
329 
getPersistentLoc()330   const Loc& getPersistentLoc() const {
331     const std::pair<SVal, uintptr_t> *D =
332       static_cast<const std::pair<SVal, uintptr_t> *>(Data);
333     const SVal& V = D->first;
334     return cast<Loc>(V);
335   }
336 
getNumBits()337   unsigned getNumBits() const {
338     const std::pair<SVal, uintptr_t> *D =
339       static_cast<const std::pair<SVal, uintptr_t> *>(Data);
340     return D->second;
341   }
342 
343   // Implement isa<T> support.
classof(const SVal * V)344   static inline bool classof(const SVal* V) {
345     return V->getBaseKind() == NonLocKind &&
346            V->getSubKind() == LocAsIntegerKind;
347   }
348 
classof(const NonLoc * V)349   static inline bool classof(const NonLoc* V) {
350     return V->getSubKind() == LocAsIntegerKind;
351   }
352 };
353 
354 class CompoundVal : public NonLoc {
355   friend class ento::SValBuilder;
356 
CompoundVal(const CompoundValData * D)357   explicit CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {}
358 
359 public:
getValue()360   const CompoundValData* getValue() const {
361     return static_cast<const CompoundValData*>(Data);
362   }
363 
364   typedef llvm::ImmutableList<SVal>::iterator iterator;
365   iterator begin() const;
366   iterator end() const;
367 
classof(const SVal * V)368   static bool classof(const SVal* V) {
369     return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind;
370   }
371 
classof(const NonLoc * V)372   static bool classof(const NonLoc* V) {
373     return V->getSubKind() == CompoundValKind;
374   }
375 };
376 
377 class LazyCompoundVal : public NonLoc {
378   friend class ento::SValBuilder;
379 
LazyCompoundVal(const LazyCompoundValData * D)380   explicit LazyCompoundVal(const LazyCompoundValData *D)
381     : NonLoc(LazyCompoundValKind, D) {}
382 public:
getCVData()383   const LazyCompoundValData *getCVData() const {
384     return static_cast<const LazyCompoundValData*>(Data);
385   }
386   const void *getStore() const;
387   const TypedRegion *getRegion() const;
388 
classof(const SVal * V)389   static bool classof(const SVal *V) {
390     return V->getBaseKind() == NonLocKind &&
391            V->getSubKind() == LazyCompoundValKind;
392   }
classof(const NonLoc * V)393   static bool classof(const NonLoc *V) {
394     return V->getSubKind() == LazyCompoundValKind;
395   }
396 };
397 
398 } // end namespace ento::nonloc
399 
400 //==------------------------------------------------------------------------==//
401 //  Subclasses of Loc.
402 //==------------------------------------------------------------------------==//
403 
404 namespace loc {
405 
406 enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind };
407 
408 class GotoLabel : public Loc {
409 public:
GotoLabel(LabelDecl * Label)410   explicit GotoLabel(LabelDecl *Label) : Loc(GotoLabelKind, Label) {}
411 
getLabel()412   const LabelDecl *getLabel() const {
413     return static_cast<const LabelDecl*>(Data);
414   }
415 
classof(const SVal * V)416   static inline bool classof(const SVal* V) {
417     return V->getBaseKind() == LocKind && V->getSubKind() == GotoLabelKind;
418   }
419 
classof(const Loc * V)420   static inline bool classof(const Loc* V) {
421     return V->getSubKind() == GotoLabelKind;
422   }
423 };
424 
425 
426 class MemRegionVal : public Loc {
427 public:
MemRegionVal(const MemRegion * r)428   explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {}
429 
430   /// \brief Get the underlining region.
getRegion()431   const MemRegion* getRegion() const {
432     return static_cast<const MemRegion*>(Data);
433   }
434 
435   /// \brief Get the underlining region and strip casts.
436   const MemRegion* stripCasts(bool StripBaseCasts = true) const;
437 
438   template <typename REGION>
getRegionAs()439   const REGION* getRegionAs() const {
440     return llvm::dyn_cast<REGION>(getRegion());
441   }
442 
443   inline bool operator==(const MemRegionVal& R) const {
444     return getRegion() == R.getRegion();
445   }
446 
447   inline bool operator!=(const MemRegionVal& R) const {
448     return getRegion() != R.getRegion();
449   }
450 
451   // Implement isa<T> support.
classof(const SVal * V)452   static inline bool classof(const SVal* V) {
453     return V->getBaseKind() == LocKind &&
454            V->getSubKind() == MemRegionKind;
455   }
456 
classof(const Loc * V)457   static inline bool classof(const Loc* V) {
458     return V->getSubKind() == MemRegionKind;
459   }
460 };
461 
462 class ConcreteInt : public Loc {
463 public:
ConcreteInt(const llvm::APSInt & V)464   explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {}
465 
getValue()466   const llvm::APSInt& getValue() const {
467     return *static_cast<const llvm::APSInt*>(Data);
468   }
469 
470   // Transfer functions for binary/unary operations on ConcreteInts.
471   SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
472                  const ConcreteInt& R) const;
473 
474   // Implement isa<T> support.
classof(const SVal * V)475   static inline bool classof(const SVal* V) {
476     return V->getBaseKind() == LocKind &&
477            V->getSubKind() == ConcreteIntKind;
478   }
479 
classof(const Loc * V)480   static inline bool classof(const Loc* V) {
481     return V->getSubKind() == ConcreteIntKind;
482   }
483 };
484 
485 } // end ento::loc namespace
486 } // end GR namespace
487 
488 } // end clang namespace
489 
490 namespace llvm {
491 static inline raw_ostream &operator<<(raw_ostream &os,
492                                             clang::ento::SVal V) {
493   V.dumpToStream(os);
494   return os;
495 }
496 
497 } // end llvm namespace
498 
499 #endif
500