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 using namespace clang; 19 using namespace ento; 20 using llvm::APSInt; 21 22 //===----------------------------------------------------------------------===// 23 // Symbol iteration within an SVal. 24 //===----------------------------------------------------------------------===// 25 26 27 //===----------------------------------------------------------------------===// 28 // Utility methods. 29 //===----------------------------------------------------------------------===// 30 31 bool SVal::hasConjuredSymbol() const { 32 if (const nonloc::SymbolVal* SV = dyn_cast<nonloc::SymbolVal>(this)) { 33 SymbolRef sym = SV->getSymbol(); 34 if (isa<SymbolConjured>(sym)) 35 return true; 36 } 37 38 if (const loc::MemRegionVal *RV = dyn_cast<loc::MemRegionVal>(this)) { 39 const MemRegion *R = RV->getRegion(); 40 if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) { 41 SymbolRef sym = SR->getSymbol(); 42 if (isa<SymbolConjured>(sym)) 43 return true; 44 } 45 } 46 47 return false; 48 } 49 50 const FunctionDecl *SVal::getAsFunctionDecl() const { 51 if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(this)) { 52 const MemRegion* R = X->getRegion(); 53 if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>()) 54 return CTR->getDecl(); 55 } 56 57 return 0; 58 } 59 60 /// \brief If this SVal is a location (subclasses Loc) and wraps a symbol, 61 /// return that SymbolRef. Otherwise return 0. 62 /// 63 /// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element 64 /// region. If that is the case, gets the underlining region. 65 SymbolRef SVal::getAsLocSymbol() const { 66 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? 67 if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) 68 return X->getLoc().getAsLocSymbol(); 69 70 if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) { 71 const MemRegion *R = X->stripCasts(); 72 if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R)) 73 return SymR->getSymbol(); 74 } 75 return 0; 76 } 77 78 /// Get the symbol in the SVal or its base region. 79 SymbolRef SVal::getLocSymbolInBase() const { 80 const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this); 81 82 if (!X) 83 return 0; 84 85 const MemRegion *R = X->getRegion(); 86 87 while (const SubRegion *SR = dyn_cast<SubRegion>(R)) { 88 if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SR)) 89 return SymR->getSymbol(); 90 else 91 R = SR->getSuperRegion(); 92 } 93 94 return 0; 95 } 96 97 // TODO: The next 3 functions have to be simplified. 98 99 /// \brief If this SVal wraps a symbol return that SymbolRef. 100 /// Otherwise return 0. 101 SymbolRef SVal::getAsSymbol() const { 102 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? 103 if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this)) 104 return X->getSymbol(); 105 106 return getAsLocSymbol(); 107 } 108 109 /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then 110 /// return that expression. Otherwise return NULL. 111 const SymExpr *SVal::getAsSymbolicExpression() const { 112 if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this)) 113 return X->getSymbol(); 114 115 return getAsSymbol(); 116 } 117 118 const SymExpr* SVal::getAsSymExpr() const { 119 const SymExpr* Sym = getAsSymbol(); 120 if (!Sym) 121 Sym = getAsSymbolicExpression(); 122 return Sym; 123 } 124 125 const MemRegion *SVal::getAsRegion() const { 126 if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) 127 return X->getRegion(); 128 129 if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) { 130 return X->getLoc().getAsRegion(); 131 } 132 133 return 0; 134 } 135 136 const MemRegion *loc::MemRegionVal::stripCasts() const { 137 const MemRegion *R = getRegion(); 138 return R ? R->StripCasts() : NULL; 139 } 140 141 const void *nonloc::LazyCompoundVal::getStore() const { 142 return static_cast<const LazyCompoundValData*>(Data)->getStore(); 143 } 144 145 const TypedRegion *nonloc::LazyCompoundVal::getRegion() const { 146 return static_cast<const LazyCompoundValData*>(Data)->getRegion(); 147 } 148 149 //===----------------------------------------------------------------------===// 150 // Other Iterators. 151 //===----------------------------------------------------------------------===// 152 153 nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const { 154 return getValue()->begin(); 155 } 156 157 nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const { 158 return getValue()->end(); 159 } 160 161 //===----------------------------------------------------------------------===// 162 // Useful predicates. 163 //===----------------------------------------------------------------------===// 164 165 bool SVal::isConstant() const { 166 return isa<nonloc::ConcreteInt>(this) || isa<loc::ConcreteInt>(this); 167 } 168 169 bool SVal::isConstant(int I) const { 170 if (isa<loc::ConcreteInt>(*this)) 171 return cast<loc::ConcreteInt>(*this).getValue() == I; 172 else if (isa<nonloc::ConcreteInt>(*this)) 173 return cast<nonloc::ConcreteInt>(*this).getValue() == I; 174 else 175 return false; 176 } 177 178 bool SVal::isZeroConstant() const { 179 return isConstant(0); 180 } 181 182 183 //===----------------------------------------------------------------------===// 184 // Transfer function dispatch for Non-Locs. 185 //===----------------------------------------------------------------------===// 186 187 SVal nonloc::ConcreteInt::evalBinOp(SValBuilder &svalBuilder, 188 BinaryOperator::Opcode Op, 189 const nonloc::ConcreteInt& R) const { 190 const llvm::APSInt* X = 191 svalBuilder.getBasicValueFactory().evalAPSInt(Op, getValue(), R.getValue()); 192 193 if (X) 194 return nonloc::ConcreteInt(*X); 195 else 196 return UndefinedVal(); 197 } 198 199 nonloc::ConcreteInt 200 nonloc::ConcreteInt::evalComplement(SValBuilder &svalBuilder) const { 201 return svalBuilder.makeIntVal(~getValue()); 202 } 203 204 nonloc::ConcreteInt 205 nonloc::ConcreteInt::evalMinus(SValBuilder &svalBuilder) const { 206 return svalBuilder.makeIntVal(-getValue()); 207 } 208 209 //===----------------------------------------------------------------------===// 210 // Transfer function dispatch for Locs. 211 //===----------------------------------------------------------------------===// 212 213 SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals, 214 BinaryOperator::Opcode Op, 215 const loc::ConcreteInt& R) const { 216 217 assert (Op == BO_Add || Op == BO_Sub || 218 (Op >= BO_LT && Op <= BO_NE)); 219 220 const llvm::APSInt* X = BasicVals.evalAPSInt(Op, getValue(), R.getValue()); 221 222 if (X) 223 return loc::ConcreteInt(*X); 224 else 225 return UndefinedVal(); 226 } 227 228 //===----------------------------------------------------------------------===// 229 // Pretty-Printing. 230 //===----------------------------------------------------------------------===// 231 232 void SVal::dump() const { dumpToStream(llvm::errs()); } 233 234 void SVal::dumpToStream(raw_ostream &os) const { 235 switch (getBaseKind()) { 236 case UnknownKind: 237 os << "Unknown"; 238 break; 239 case NonLocKind: 240 cast<NonLoc>(this)->dumpToStream(os); 241 break; 242 case LocKind: 243 cast<Loc>(this)->dumpToStream(os); 244 break; 245 case UndefinedKind: 246 os << "Undefined"; 247 break; 248 } 249 } 250 251 void NonLoc::dumpToStream(raw_ostream &os) const { 252 switch (getSubKind()) { 253 case nonloc::ConcreteIntKind: { 254 const nonloc::ConcreteInt& C = *cast<nonloc::ConcreteInt>(this); 255 if (C.getValue().isUnsigned()) 256 os << C.getValue().getZExtValue(); 257 else 258 os << C.getValue().getSExtValue(); 259 os << ' ' << (C.getValue().isUnsigned() ? 'U' : 'S') 260 << C.getValue().getBitWidth() << 'b'; 261 break; 262 } 263 case nonloc::SymbolValKind: { 264 os << cast<nonloc::SymbolVal>(this)->getSymbol(); 265 break; 266 } 267 case nonloc::LocAsIntegerKind: { 268 const nonloc::LocAsInteger& C = *cast<nonloc::LocAsInteger>(this); 269 os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]"; 270 break; 271 } 272 case nonloc::CompoundValKind: { 273 const nonloc::CompoundVal& C = *cast<nonloc::CompoundVal>(this); 274 os << "compoundVal{"; 275 bool first = true; 276 for (nonloc::CompoundVal::iterator I=C.begin(), E=C.end(); I!=E; ++I) { 277 if (first) { 278 os << ' '; first = false; 279 } 280 else 281 os << ", "; 282 283 (*I).dumpToStream(os); 284 } 285 os << "}"; 286 break; 287 } 288 case nonloc::LazyCompoundValKind: { 289 const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this); 290 os << "lazyCompoundVal{" << const_cast<void *>(C.getStore()) 291 << ',' << C.getRegion() 292 << '}'; 293 break; 294 } 295 default: 296 assert (false && "Pretty-printed not implemented for this NonLoc."); 297 break; 298 } 299 } 300 301 void Loc::dumpToStream(raw_ostream &os) const { 302 switch (getSubKind()) { 303 case loc::ConcreteIntKind: 304 os << cast<loc::ConcreteInt>(this)->getValue().getZExtValue() << " (Loc)"; 305 break; 306 case loc::GotoLabelKind: 307 os << "&&" << cast<loc::GotoLabel>(this)->getLabel()->getName(); 308 break; 309 case loc::MemRegionKind: 310 os << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString(); 311 break; 312 case loc::ObjCPropRefKind: { 313 const ObjCPropertyRefExpr *E = cast<loc::ObjCPropRef>(this)->getPropRefExpr(); 314 os << "objc-prop{"; 315 if (E->isSuperReceiver()) 316 os << "super."; 317 else if (E->getBase()) 318 os << "<base>."; 319 320 if (E->isImplicitProperty()) 321 os << E->getImplicitPropertyGetter()->getSelector().getAsString(); 322 else 323 os << E->getExplicitProperty()->getName(); 324 325 os << "}"; 326 break; 327 } 328 default: 329 llvm_unreachable("Pretty-printing not implemented for this Loc."); 330 } 331 } 332