• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //= RValues.cpp - Abstract RValues for Path-Sens. Value Tracking -*- 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 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
16 #include "clang/AST/ExprObjC.h"
17 #include "clang/Basic/IdentifierTable.h"
18 #include "llvm/Support/raw_ostream.h"
19 using namespace clang;
20 using namespace ento;
21 using llvm::APSInt;
22 
23 //===----------------------------------------------------------------------===//
24 // Symbol iteration within an SVal.
25 //===----------------------------------------------------------------------===//
26 
27 
28 //===----------------------------------------------------------------------===//
29 // Utility methods.
30 //===----------------------------------------------------------------------===//
31 
hasConjuredSymbol() const32 bool SVal::hasConjuredSymbol() const {
33   if (Optional<nonloc::SymbolVal> SV = getAs<nonloc::SymbolVal>()) {
34     SymbolRef sym = SV->getSymbol();
35     if (isa<SymbolConjured>(sym))
36       return true;
37   }
38 
39   if (Optional<loc::MemRegionVal> RV = getAs<loc::MemRegionVal>()) {
40     const MemRegion *R = RV->getRegion();
41     if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
42       SymbolRef sym = SR->getSymbol();
43       if (isa<SymbolConjured>(sym))
44         return true;
45     }
46   }
47 
48   return false;
49 }
50 
getAsFunctionDecl() const51 const FunctionDecl *SVal::getAsFunctionDecl() const {
52   if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
53     const MemRegion* R = X->getRegion();
54     if (const FunctionCodeRegion *CTR = R->getAs<FunctionCodeRegion>())
55       if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CTR->getDecl()))
56         return FD;
57   }
58 
59   return nullptr;
60 }
61 
62 /// \brief If this SVal is a location (subclasses Loc) and wraps a symbol,
63 /// return that SymbolRef.  Otherwise return 0.
64 ///
65 /// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element
66 /// region. If that is the case, gets the underlining region.
67 /// When IncludeBaseRegions is set to true and the SubRegion is non-symbolic,
68 /// the first symbolic parent region is returned.
getAsLocSymbol(bool IncludeBaseRegions) const69 SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const {
70   // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
71   if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
72     return X->getLoc().getAsLocSymbol();
73 
74   if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
75     const MemRegion *R = X->getRegion();
76     if (const SymbolicRegion *SymR = IncludeBaseRegions ?
77                                       R->getSymbolicBase() :
78                                       dyn_cast<SymbolicRegion>(R->StripCasts()))
79       return SymR->getSymbol();
80   }
81   return nullptr;
82 }
83 
84 /// Get the symbol in the SVal or its base region.
getLocSymbolInBase() const85 SymbolRef SVal::getLocSymbolInBase() const {
86   Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>();
87 
88   if (!X)
89     return nullptr;
90 
91   const MemRegion *R = X->getRegion();
92 
93   while (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
94     if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SR))
95       return SymR->getSymbol();
96     else
97       R = SR->getSuperRegion();
98   }
99 
100   return nullptr;
101 }
102 
103 // TODO: The next 3 functions have to be simplified.
104 
105 /// \brief If this SVal wraps a symbol return that SymbolRef.
106 /// Otherwise, return 0.
107 ///
108 /// Casts are ignored during lookup.
109 /// \param IncludeBaseRegions The boolean that controls whether the search
110 /// should continue to the base regions if the region is not symbolic.
getAsSymbol(bool IncludeBaseRegion) const111 SymbolRef SVal::getAsSymbol(bool IncludeBaseRegion) const {
112   // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
113   if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
114     return X->getSymbol();
115 
116   return getAsLocSymbol(IncludeBaseRegion);
117 }
118 
119 /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
120 ///  return that expression.  Otherwise return NULL.
getAsSymbolicExpression() const121 const SymExpr *SVal::getAsSymbolicExpression() const {
122   if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
123     return X->getSymbol();
124 
125   return getAsSymbol();
126 }
127 
getAsSymExpr() const128 const SymExpr* SVal::getAsSymExpr() const {
129   const SymExpr* Sym = getAsSymbol();
130   if (!Sym)
131     Sym = getAsSymbolicExpression();
132   return Sym;
133 }
134 
getAsRegion() const135 const MemRegion *SVal::getAsRegion() const {
136   if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>())
137     return X->getRegion();
138 
139   if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
140     return X->getLoc().getAsRegion();
141 
142   return nullptr;
143 }
144 
stripCasts(bool StripBaseCasts) const145 const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const {
146   const MemRegion *R = getRegion();
147   return R ?  R->StripCasts(StripBaseCasts) : nullptr;
148 }
149 
getStore() const150 const void *nonloc::LazyCompoundVal::getStore() const {
151   return static_cast<const LazyCompoundValData*>(Data)->getStore();
152 }
153 
getRegion() const154 const TypedValueRegion *nonloc::LazyCompoundVal::getRegion() const {
155   return static_cast<const LazyCompoundValData*>(Data)->getRegion();
156 }
157 
158 //===----------------------------------------------------------------------===//
159 // Other Iterators.
160 //===----------------------------------------------------------------------===//
161 
begin() const162 nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const {
163   return getValue()->begin();
164 }
165 
end() const166 nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
167   return getValue()->end();
168 }
169 
170 //===----------------------------------------------------------------------===//
171 // Useful predicates.
172 //===----------------------------------------------------------------------===//
173 
isConstant() const174 bool SVal::isConstant() const {
175   return getAs<nonloc::ConcreteInt>() || getAs<loc::ConcreteInt>();
176 }
177 
isConstant(int I) const178 bool SVal::isConstant(int I) const {
179   if (Optional<loc::ConcreteInt> LV = getAs<loc::ConcreteInt>())
180     return LV->getValue() == I;
181   if (Optional<nonloc::ConcreteInt> NV = getAs<nonloc::ConcreteInt>())
182     return NV->getValue() == I;
183   return false;
184 }
185 
isZeroConstant() const186 bool SVal::isZeroConstant() const {
187   return isConstant(0);
188 }
189 
190 
191 //===----------------------------------------------------------------------===//
192 // Transfer function dispatch for Non-Locs.
193 //===----------------------------------------------------------------------===//
194 
evalBinOp(SValBuilder & svalBuilder,BinaryOperator::Opcode Op,const nonloc::ConcreteInt & R) const195 SVal nonloc::ConcreteInt::evalBinOp(SValBuilder &svalBuilder,
196                                     BinaryOperator::Opcode Op,
197                                     const nonloc::ConcreteInt& R) const {
198   const llvm::APSInt* X =
199     svalBuilder.getBasicValueFactory().evalAPSInt(Op, getValue(), R.getValue());
200 
201   if (X)
202     return nonloc::ConcreteInt(*X);
203   else
204     return UndefinedVal();
205 }
206 
207 nonloc::ConcreteInt
evalComplement(SValBuilder & svalBuilder) const208 nonloc::ConcreteInt::evalComplement(SValBuilder &svalBuilder) const {
209   return svalBuilder.makeIntVal(~getValue());
210 }
211 
212 nonloc::ConcreteInt
evalMinus(SValBuilder & svalBuilder) const213 nonloc::ConcreteInt::evalMinus(SValBuilder &svalBuilder) const {
214   return svalBuilder.makeIntVal(-getValue());
215 }
216 
217 //===----------------------------------------------------------------------===//
218 // Transfer function dispatch for Locs.
219 //===----------------------------------------------------------------------===//
220 
evalBinOp(BasicValueFactory & BasicVals,BinaryOperator::Opcode Op,const loc::ConcreteInt & R) const221 SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals,
222                                  BinaryOperator::Opcode Op,
223                                  const loc::ConcreteInt& R) const {
224 
225   assert(BinaryOperator::isComparisonOp(Op) || Op == BO_Sub);
226 
227   const llvm::APSInt *X = BasicVals.evalAPSInt(Op, getValue(), R.getValue());
228 
229   if (X)
230     return nonloc::ConcreteInt(*X);
231   else
232     return UndefinedVal();
233 }
234 
235 //===----------------------------------------------------------------------===//
236 // Pretty-Printing.
237 //===----------------------------------------------------------------------===//
238 
dump() const239 LLVM_DUMP_METHOD void SVal::dump() const { dumpToStream(llvm::errs()); }
240 
dumpToStream(raw_ostream & os) const241 void SVal::dumpToStream(raw_ostream &os) const {
242   switch (getBaseKind()) {
243     case UnknownValKind:
244       os << "Unknown";
245       break;
246     case NonLocKind:
247       castAs<NonLoc>().dumpToStream(os);
248       break;
249     case LocKind:
250       castAs<Loc>().dumpToStream(os);
251       break;
252     case UndefinedValKind:
253       os << "Undefined";
254       break;
255   }
256 }
257 
dumpToStream(raw_ostream & os) const258 void NonLoc::dumpToStream(raw_ostream &os) const {
259   switch (getSubKind()) {
260     case nonloc::ConcreteIntKind: {
261       const nonloc::ConcreteInt& C = castAs<nonloc::ConcreteInt>();
262       if (C.getValue().isUnsigned())
263         os << C.getValue().getZExtValue();
264       else
265         os << C.getValue().getSExtValue();
266       os << ' ' << (C.getValue().isUnsigned() ? 'U' : 'S')
267          << C.getValue().getBitWidth() << 'b';
268       break;
269     }
270     case nonloc::SymbolValKind: {
271       os << castAs<nonloc::SymbolVal>().getSymbol();
272       break;
273     }
274     case nonloc::LocAsIntegerKind: {
275       const nonloc::LocAsInteger& C = castAs<nonloc::LocAsInteger>();
276       os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]";
277       break;
278     }
279     case nonloc::CompoundValKind: {
280       const nonloc::CompoundVal& C = castAs<nonloc::CompoundVal>();
281       os << "compoundVal{";
282       bool first = true;
283       for (nonloc::CompoundVal::iterator I=C.begin(), E=C.end(); I!=E; ++I) {
284         if (first) {
285           os << ' '; first = false;
286         }
287         else
288           os << ", ";
289 
290         (*I).dumpToStream(os);
291       }
292       os << "}";
293       break;
294     }
295     case nonloc::LazyCompoundValKind: {
296       const nonloc::LazyCompoundVal &C = castAs<nonloc::LazyCompoundVal>();
297       os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
298          << ',' << C.getRegion()
299          << '}';
300       break;
301     }
302     default:
303       assert (false && "Pretty-printed not implemented for this NonLoc.");
304       break;
305   }
306 }
307 
dumpToStream(raw_ostream & os) const308 void Loc::dumpToStream(raw_ostream &os) const {
309   switch (getSubKind()) {
310     case loc::ConcreteIntKind:
311       os << castAs<loc::ConcreteInt>().getValue().getZExtValue() << " (Loc)";
312       break;
313     case loc::GotoLabelKind:
314       os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName();
315       break;
316     case loc::MemRegionValKind:
317       os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString();
318       break;
319     default:
320       llvm_unreachable("Pretty-printing not implemented for this Loc.");
321   }
322 }
323