SVals.cpp revision 076add680e281709cf081052be0dcb822dc8f37d
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" 18using namespace clang; 19using namespace ento; 20using llvm::APSInt; 21 22//===----------------------------------------------------------------------===// 23// Symbol iteration within an SVal. 24//===----------------------------------------------------------------------===// 25 26 27//===----------------------------------------------------------------------===// 28// Utility methods. 29//===----------------------------------------------------------------------===// 30 31bool 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 50const 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. 65SymbolRef 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. 79SymbolRef 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. 101SymbolRef 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 if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this)) 107 if (SymbolRef Y = X->getSymbol()) 108 return Y; 109 110 return getAsLocSymbol(); 111} 112 113/// getAsSymbolicExpression - If this Sval wraps a symbolic expression then 114/// return that expression. Otherwise return NULL. 115const SymExpr *SVal::getAsSymbolicExpression() const { 116 if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this)) 117 return X->getSymbol(); 118 119 return getAsSymbol(); 120} 121 122const SymExpr* SVal::getAsSymExpr() const { 123 const SymExpr* Sym = getAsSymbol(); 124 if (!Sym) 125 Sym = getAsSymbolicExpression(); 126 return Sym; 127} 128 129const MemRegion *SVal::getAsRegion() const { 130 if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) 131 return X->getRegion(); 132 133 if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) { 134 return X->getLoc().getAsRegion(); 135 } 136 137 return 0; 138} 139 140const MemRegion *loc::MemRegionVal::stripCasts() const { 141 const MemRegion *R = getRegion(); 142 return R ? R->StripCasts() : NULL; 143} 144 145const void *nonloc::LazyCompoundVal::getStore() const { 146 return static_cast<const LazyCompoundValData*>(Data)->getStore(); 147} 148 149const TypedRegion *nonloc::LazyCompoundVal::getRegion() const { 150 return static_cast<const LazyCompoundValData*>(Data)->getRegion(); 151} 152 153//===----------------------------------------------------------------------===// 154// Other Iterators. 155//===----------------------------------------------------------------------===// 156 157nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const { 158 return getValue()->begin(); 159} 160 161nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const { 162 return getValue()->end(); 163} 164 165//===----------------------------------------------------------------------===// 166// Useful predicates. 167//===----------------------------------------------------------------------===// 168 169bool SVal::isConstant() const { 170 return isa<nonloc::ConcreteInt>(this) || isa<loc::ConcreteInt>(this); 171} 172 173bool SVal::isConstant(int I) const { 174 if (isa<loc::ConcreteInt>(*this)) 175 return cast<loc::ConcreteInt>(*this).getValue() == I; 176 else if (isa<nonloc::ConcreteInt>(*this)) 177 return cast<nonloc::ConcreteInt>(*this).getValue() == I; 178 else 179 return false; 180} 181 182bool SVal::isZeroConstant() const { 183 return isConstant(0); 184} 185 186 187//===----------------------------------------------------------------------===// 188// Transfer function dispatch for Non-Locs. 189//===----------------------------------------------------------------------===// 190 191SVal nonloc::ConcreteInt::evalBinOp(SValBuilder &svalBuilder, 192 BinaryOperator::Opcode Op, 193 const nonloc::ConcreteInt& R) const { 194 const llvm::APSInt* X = 195 svalBuilder.getBasicValueFactory().evalAPSInt(Op, getValue(), R.getValue()); 196 197 if (X) 198 return nonloc::ConcreteInt(*X); 199 else 200 return UndefinedVal(); 201} 202 203nonloc::ConcreteInt 204nonloc::ConcreteInt::evalComplement(SValBuilder &svalBuilder) const { 205 return svalBuilder.makeIntVal(~getValue()); 206} 207 208nonloc::ConcreteInt 209nonloc::ConcreteInt::evalMinus(SValBuilder &svalBuilder) const { 210 return svalBuilder.makeIntVal(-getValue()); 211} 212 213//===----------------------------------------------------------------------===// 214// Transfer function dispatch for Locs. 215//===----------------------------------------------------------------------===// 216 217SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals, 218 BinaryOperator::Opcode Op, 219 const loc::ConcreteInt& R) const { 220 221 assert (Op == BO_Add || Op == BO_Sub || 222 (Op >= BO_LT && Op <= BO_NE)); 223 224 const llvm::APSInt* X = BasicVals.evalAPSInt(Op, getValue(), R.getValue()); 225 226 if (X) 227 return loc::ConcreteInt(*X); 228 else 229 return UndefinedVal(); 230} 231 232//===----------------------------------------------------------------------===// 233// Pretty-Printing. 234//===----------------------------------------------------------------------===// 235 236void SVal::dump() const { dumpToStream(llvm::errs()); } 237 238void SVal::dumpToStream(raw_ostream &os) const { 239 switch (getBaseKind()) { 240 case UnknownKind: 241 os << "Unknown"; 242 break; 243 case NonLocKind: 244 cast<NonLoc>(this)->dumpToStream(os); 245 break; 246 case LocKind: 247 cast<Loc>(this)->dumpToStream(os); 248 break; 249 case UndefinedKind: 250 os << "Undefined"; 251 break; 252 } 253} 254 255void NonLoc::dumpToStream(raw_ostream &os) const { 256 switch (getSubKind()) { 257 case nonloc::ConcreteIntKind: { 258 const nonloc::ConcreteInt& C = *cast<nonloc::ConcreteInt>(this); 259 if (C.getValue().isUnsigned()) 260 os << C.getValue().getZExtValue(); 261 else 262 os << C.getValue().getSExtValue(); 263 os << ' ' << (C.getValue().isUnsigned() ? 'U' : 'S') 264 << C.getValue().getBitWidth() << 'b'; 265 break; 266 } 267 case nonloc::SymbolValKind: { 268 os << cast<nonloc::SymbolVal>(this)->getSymbol(); 269 break; 270 } 271 case nonloc::LocAsIntegerKind: { 272 const nonloc::LocAsInteger& C = *cast<nonloc::LocAsInteger>(this); 273 os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]"; 274 break; 275 } 276 case nonloc::CompoundValKind: { 277 const nonloc::CompoundVal& C = *cast<nonloc::CompoundVal>(this); 278 os << "compoundVal{"; 279 bool first = true; 280 for (nonloc::CompoundVal::iterator I=C.begin(), E=C.end(); I!=E; ++I) { 281 if (first) { 282 os << ' '; first = false; 283 } 284 else 285 os << ", "; 286 287 (*I).dumpToStream(os); 288 } 289 os << "}"; 290 break; 291 } 292 case nonloc::LazyCompoundValKind: { 293 const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this); 294 os << "lazyCompoundVal{" << const_cast<void *>(C.getStore()) 295 << ',' << C.getRegion() 296 << '}'; 297 break; 298 } 299 default: 300 assert (false && "Pretty-printed not implemented for this NonLoc."); 301 break; 302 } 303} 304 305void Loc::dumpToStream(raw_ostream &os) const { 306 switch (getSubKind()) { 307 case loc::ConcreteIntKind: 308 os << cast<loc::ConcreteInt>(this)->getValue().getZExtValue() << " (Loc)"; 309 break; 310 case loc::GotoLabelKind: 311 os << "&&" << cast<loc::GotoLabel>(this)->getLabel()->getName(); 312 break; 313 case loc::MemRegionKind: 314 os << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString(); 315 break; 316 case loc::ObjCPropRefKind: { 317 const ObjCPropertyRefExpr *E = cast<loc::ObjCPropRef>(this)->getPropRefExpr(); 318 os << "objc-prop{"; 319 if (E->isSuperReceiver()) 320 os << "super."; 321 else if (E->getBase()) 322 os << "<base>."; 323 324 if (E->isImplicitProperty()) 325 os << E->getImplicitPropertyGetter()->getSelector().getAsString(); 326 else 327 os << E->getExplicitProperty()->getName(); 328 329 os << "}"; 330 break; 331 } 332 default: 333 llvm_unreachable("Pretty-printing not implemented for this Loc."); 334 } 335} 336