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 // Pretty-Printing. 257 //===----------------------------------------------------------------------===// 258 259 LLVM_DUMP_METHOD void SVal::dump() const { dumpToStream(llvm::errs()); } 260 261 void SVal::printJson(raw_ostream &Out, bool AddQuotes) const { 262 std::string Buf; 263 llvm::raw_string_ostream TempOut(Buf); 264 265 dumpToStream(TempOut); 266 267 Out << JsonFormat(TempOut.str(), AddQuotes); 268 } 269 270 void SVal::dumpToStream(raw_ostream &os) const { 271 switch (getBaseKind()) { 272 case UnknownValKind: 273 os << "Unknown"; 274 break; 275 case NonLocKind: 276 castAs<NonLoc>().dumpToStream(os); 277 break; 278 case LocKind: 279 castAs<Loc>().dumpToStream(os); 280 break; 281 case UndefinedValKind: 282 os << "Undefined"; 283 break; 284 } 285 } 286 287 void NonLoc::dumpToStream(raw_ostream &os) const { 288 switch (getSubKind()) { 289 case nonloc::ConcreteIntKind: { 290 const auto &Value = castAs<nonloc::ConcreteInt>().getValue(); 291 os << Value << ' ' << (Value.isSigned() ? 'S' : 'U') 292 << Value.getBitWidth() << 'b'; 293 break; 294 } 295 case nonloc::SymbolValKind: 296 os << castAs<nonloc::SymbolVal>().getSymbol(); 297 break; 298 299 case nonloc::LocAsIntegerKind: { 300 const nonloc::LocAsInteger& C = castAs<nonloc::LocAsInteger>(); 301 os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]"; 302 break; 303 } 304 case nonloc::CompoundValKind: { 305 const nonloc::CompoundVal& C = castAs<nonloc::CompoundVal>(); 306 os << "compoundVal{"; 307 bool first = true; 308 for (const auto &I : C) { 309 if (first) { 310 os << ' '; first = false; 311 } 312 else 313 os << ", "; 314 315 I.dumpToStream(os); 316 } 317 os << "}"; 318 break; 319 } 320 case nonloc::LazyCompoundValKind: { 321 const nonloc::LazyCompoundVal &C = castAs<nonloc::LazyCompoundVal>(); 322 os << "lazyCompoundVal{" << const_cast<void *>(C.getStore()) 323 << ',' << C.getRegion() 324 << '}'; 325 break; 326 } 327 case nonloc::PointerToMemberKind: { 328 os << "pointerToMember{"; 329 const nonloc::PointerToMember &CastRes = 330 castAs<nonloc::PointerToMember>(); 331 if (CastRes.getDecl()) 332 os << "|" << CastRes.getDecl()->getQualifiedNameAsString() << "|"; 333 bool first = true; 334 for (const auto &I : CastRes) { 335 if (first) { 336 os << ' '; first = false; 337 } 338 else 339 os << ", "; 340 341 os << I->getType(); 342 } 343 344 os << '}'; 345 break; 346 } 347 default: 348 assert(false && "Pretty-printed not implemented for this NonLoc."); 349 break; 350 } 351 } 352 353 void Loc::dumpToStream(raw_ostream &os) const { 354 switch (getSubKind()) { 355 case loc::ConcreteIntKind: 356 os << castAs<loc::ConcreteInt>().getValue().getZExtValue() << " (Loc)"; 357 break; 358 case loc::GotoLabelKind: 359 os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName(); 360 break; 361 case loc::MemRegionValKind: 362 os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString(); 363 break; 364 default: 365 llvm_unreachable("Pretty-printing not implemented for this Loc."); 366 } 367 } 368