1 //===-- SVals.cpp - Abstract RValues for Path-Sens. Value Tracking --------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines SVal, Loc, and NonLoc, classes that represent 10 // abstract r-values for use with path-sensitive value tracking. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 15 #include "clang/AST/ASTContext.h" 16 #include "clang/AST/Decl.h" 17 #include "clang/AST/DeclCXX.h" 18 #include "clang/AST/Expr.h" 19 #include "clang/AST/Type.h" 20 #include "clang/Basic/JsonSupport.h" 21 #include "clang/Basic/LLVM.h" 22 #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" 24 #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" 25 #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h" 26 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" 27 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" 28 #include "llvm/ADT/Optional.h" 29 #include "llvm/Support/Casting.h" 30 #include "llvm/Support/Compiler.h" 31 #include "llvm/Support/ErrorHandling.h" 32 #include "llvm/Support/raw_ostream.h" 33 #include <cassert> 34 35 using namespace clang; 36 using namespace ento; 37 38 //===----------------------------------------------------------------------===// 39 // Symbol iteration within an SVal. 40 //===----------------------------------------------------------------------===// 41 42 //===----------------------------------------------------------------------===// 43 // Utility methods. 44 //===----------------------------------------------------------------------===// 45 46 const FunctionDecl *SVal::getAsFunctionDecl() const { 47 if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) { 48 const MemRegion* R = X->getRegion(); 49 if (const FunctionCodeRegion *CTR = R->getAs<FunctionCodeRegion>()) 50 if (const auto *FD = dyn_cast<FunctionDecl>(CTR->getDecl())) 51 return FD; 52 } 53 54 if (auto X = getAs<nonloc::PointerToMember>()) { 55 if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(X->getDecl())) 56 return MD; 57 } 58 return nullptr; 59 } 60 61 /// If this SVal is a location (subclasses Loc) and wraps a symbol, 62 /// return that SymbolRef. Otherwise return 0. 63 /// 64 /// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element 65 /// region. If that is the case, gets the underlining region. 66 /// When IncludeBaseRegions is set to true and the SubRegion is non-symbolic, 67 /// the first symbolic parent region is returned. 68 SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const { 69 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? 70 if (const MemRegion *R = getAsRegion()) 71 if (const SymbolicRegion *SymR = 72 IncludeBaseRegions ? R->getSymbolicBase() 73 : dyn_cast<SymbolicRegion>(R->StripCasts())) 74 return SymR->getSymbol(); 75 76 return nullptr; 77 } 78 79 /// Get the symbol in the SVal or its base region. 80 SymbolRef SVal::getLocSymbolInBase() const { 81 Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>(); 82 83 if (!X) 84 return nullptr; 85 86 const MemRegion *R = X->getRegion(); 87 88 while (const auto *SR = dyn_cast<SubRegion>(R)) { 89 if (const auto *SymR = dyn_cast<SymbolicRegion>(SR)) 90 return SymR->getSymbol(); 91 else 92 R = SR->getSuperRegion(); 93 } 94 95 return nullptr; 96 } 97 98 /// If this SVal wraps a symbol return that SymbolRef. 99 /// Otherwise, return 0. 100 /// 101 /// Casts are ignored during lookup. 102 /// \param IncludeBaseRegions The boolean that controls whether the search 103 /// should continue to the base regions if the region is not symbolic. 104 SymbolRef SVal::getAsSymbol(bool IncludeBaseRegions) const { 105 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? 106 if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>()) 107 return X->getSymbol(); 108 109 return getAsLocSymbol(IncludeBaseRegions); 110 } 111 112 const MemRegion *SVal::getAsRegion() const { 113 if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) 114 return X->getRegion(); 115 116 if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>()) 117 return X->getLoc().getAsRegion(); 118 119 return nullptr; 120 } 121 122 namespace { 123 class TypeRetrievingVisitor 124 : public FullSValVisitor<TypeRetrievingVisitor, QualType> { 125 private: 126 const ASTContext &Context; 127 128 public: 129 TypeRetrievingVisitor(const ASTContext &Context) : Context(Context) {} 130 131 QualType VisitLocMemRegionVal(loc::MemRegionVal MRV) { 132 return Visit(MRV.getRegion()); 133 } 134 QualType VisitLocGotoLabel(loc::GotoLabel GL) { 135 return QualType{Context.VoidPtrTy}; 136 } 137 template <class ConcreteInt> QualType VisitConcreteInt(ConcreteInt CI) { 138 const llvm::APSInt &Value = CI.getValue(); 139 return Context.getIntTypeForBitwidth(Value.getBitWidth(), Value.isSigned()); 140 } 141 QualType VisitLocConcreteInt(loc::ConcreteInt CI) { 142 return VisitConcreteInt(CI); 143 } 144 QualType VisitNonLocConcreteInt(nonloc::ConcreteInt CI) { 145 return VisitConcreteInt(CI); 146 } 147 QualType VisitNonLocLocAsInteger(nonloc::LocAsInteger LI) { 148 QualType NestedType = Visit(LI.getLoc()); 149 if (NestedType.isNull()) 150 return NestedType; 151 152 return Context.getIntTypeForBitwidth(LI.getNumBits(), 153 NestedType->isSignedIntegerType()); 154 } 155 QualType VisitNonLocCompoundVal(nonloc::CompoundVal CV) { 156 return CV.getValue()->getType(); 157 } 158 QualType VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal LCV) { 159 return LCV.getRegion()->getValueType(); 160 } 161 QualType VisitNonLocSymbolVal(nonloc::SymbolVal SV) { 162 return Visit(SV.getSymbol()); 163 } 164 QualType VisitSymbolicRegion(const SymbolicRegion *SR) { 165 return Visit(SR->getSymbol()); 166 } 167 QualType VisitTypedRegion(const TypedRegion *TR) { 168 return TR->getLocationType(); 169 } 170 QualType VisitSymExpr(const SymExpr *SE) { return SE->getType(); } 171 }; 172 } // end anonymous namespace 173 174 QualType SVal::getType(const ASTContext &Context) const { 175 TypeRetrievingVisitor TRV{Context}; 176 return TRV.Visit(*this); 177 } 178 179 const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const { 180 return getRegion()->StripCasts(StripBaseCasts); 181 } 182 183 const void *nonloc::LazyCompoundVal::getStore() const { 184 return static_cast<const LazyCompoundValData*>(Data)->getStore(); 185 } 186 187 const TypedValueRegion *nonloc::LazyCompoundVal::getRegion() const { 188 return static_cast<const LazyCompoundValData*>(Data)->getRegion(); 189 } 190 191 bool nonloc::PointerToMember::isNullMemberPointer() const { 192 return getPTMData().isNull(); 193 } 194 195 const NamedDecl *nonloc::PointerToMember::getDecl() const { 196 const auto PTMD = this->getPTMData(); 197 if (PTMD.isNull()) 198 return nullptr; 199 200 const NamedDecl *ND = nullptr; 201 if (PTMD.is<const NamedDecl *>()) 202 ND = PTMD.get<const NamedDecl *>(); 203 else 204 ND = PTMD.get<const PointerToMemberData *>()->getDeclaratorDecl(); 205 206 return ND; 207 } 208 209 //===----------------------------------------------------------------------===// 210 // Other Iterators. 211 //===----------------------------------------------------------------------===// 212 213 nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const { 214 return getValue()->begin(); 215 } 216 217 nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const { 218 return getValue()->end(); 219 } 220 221 nonloc::PointerToMember::iterator nonloc::PointerToMember::begin() const { 222 const PTMDataType PTMD = getPTMData(); 223 if (PTMD.is<const NamedDecl *>()) 224 return {}; 225 return PTMD.get<const PointerToMemberData *>()->begin(); 226 } 227 228 nonloc::PointerToMember::iterator nonloc::PointerToMember::end() const { 229 const PTMDataType PTMD = getPTMData(); 230 if (PTMD.is<const NamedDecl *>()) 231 return {}; 232 return PTMD.get<const PointerToMemberData *>()->end(); 233 } 234 235 //===----------------------------------------------------------------------===// 236 // Useful predicates. 237 //===----------------------------------------------------------------------===// 238 239 bool SVal::isConstant() const { 240 return getAs<nonloc::ConcreteInt>() || getAs<loc::ConcreteInt>(); 241 } 242 243 bool SVal::isConstant(int I) const { 244 if (Optional<loc::ConcreteInt> LV = getAs<loc::ConcreteInt>()) 245 return LV->getValue() == I; 246 if (Optional<nonloc::ConcreteInt> NV = getAs<nonloc::ConcreteInt>()) 247 return NV->getValue() == I; 248 return false; 249 } 250 251 bool SVal::isZeroConstant() const { 252 return isConstant(0); 253 } 254 255 //===----------------------------------------------------------------------===// 256 // Transfer function dispatch for Non-Locs. 257 //===----------------------------------------------------------------------===// 258 259 nonloc::ConcreteInt 260 nonloc::ConcreteInt::evalComplement(SValBuilder &svalBuilder) const { 261 return svalBuilder.makeIntVal(~getValue()); 262 } 263 264 nonloc::ConcreteInt 265 nonloc::ConcreteInt::evalMinus(SValBuilder &svalBuilder) const { 266 return svalBuilder.makeIntVal(-getValue()); 267 } 268 269 //===----------------------------------------------------------------------===// 270 // Pretty-Printing. 271 //===----------------------------------------------------------------------===// 272 273 LLVM_DUMP_METHOD void SVal::dump() const { dumpToStream(llvm::errs()); } 274 275 void SVal::printJson(raw_ostream &Out, bool AddQuotes) const { 276 std::string Buf; 277 llvm::raw_string_ostream TempOut(Buf); 278 279 dumpToStream(TempOut); 280 281 Out << JsonFormat(TempOut.str(), AddQuotes); 282 } 283 284 void SVal::dumpToStream(raw_ostream &os) const { 285 switch (getBaseKind()) { 286 case UnknownValKind: 287 os << "Unknown"; 288 break; 289 case NonLocKind: 290 castAs<NonLoc>().dumpToStream(os); 291 break; 292 case LocKind: 293 castAs<Loc>().dumpToStream(os); 294 break; 295 case UndefinedValKind: 296 os << "Undefined"; 297 break; 298 } 299 } 300 301 void NonLoc::dumpToStream(raw_ostream &os) const { 302 switch (getSubKind()) { 303 case nonloc::ConcreteIntKind: { 304 const auto &Value = castAs<nonloc::ConcreteInt>().getValue(); 305 os << Value << ' ' << (Value.isSigned() ? 'S' : 'U') 306 << Value.getBitWidth() << 'b'; 307 break; 308 } 309 case nonloc::SymbolValKind: 310 os << castAs<nonloc::SymbolVal>().getSymbol(); 311 break; 312 313 case nonloc::LocAsIntegerKind: { 314 const nonloc::LocAsInteger& C = castAs<nonloc::LocAsInteger>(); 315 os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]"; 316 break; 317 } 318 case nonloc::CompoundValKind: { 319 const nonloc::CompoundVal& C = castAs<nonloc::CompoundVal>(); 320 os << "compoundVal{"; 321 bool first = true; 322 for (const auto &I : C) { 323 if (first) { 324 os << ' '; first = false; 325 } 326 else 327 os << ", "; 328 329 I.dumpToStream(os); 330 } 331 os << "}"; 332 break; 333 } 334 case nonloc::LazyCompoundValKind: { 335 const nonloc::LazyCompoundVal &C = castAs<nonloc::LazyCompoundVal>(); 336 os << "lazyCompoundVal{" << const_cast<void *>(C.getStore()) 337 << ',' << C.getRegion() 338 << '}'; 339 break; 340 } 341 case nonloc::PointerToMemberKind: { 342 os << "pointerToMember{"; 343 const nonloc::PointerToMember &CastRes = 344 castAs<nonloc::PointerToMember>(); 345 if (CastRes.getDecl()) 346 os << "|" << CastRes.getDecl()->getQualifiedNameAsString() << "|"; 347 bool first = true; 348 for (const auto &I : CastRes) { 349 if (first) { 350 os << ' '; first = false; 351 } 352 else 353 os << ", "; 354 355 os << I->getType(); 356 } 357 358 os << '}'; 359 break; 360 } 361 default: 362 assert(false && "Pretty-printed not implemented for this NonLoc."); 363 break; 364 } 365 } 366 367 void Loc::dumpToStream(raw_ostream &os) const { 368 switch (getSubKind()) { 369 case loc::ConcreteIntKind: 370 os << castAs<loc::ConcreteInt>().getValue().getZExtValue() << " (Loc)"; 371 break; 372 case loc::GotoLabelKind: 373 os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName(); 374 break; 375 case loc::MemRegionValKind: 376 os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString(); 377 break; 378 default: 379 llvm_unreachable("Pretty-printing not implemented for this Loc."); 380 } 381 } 382