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 if (1 == Value.getBitWidth()) 140 return Context.BoolTy; 141 return Context.getIntTypeForBitwidth(Value.getBitWidth(), Value.isSigned()); 142 } 143 QualType VisitLocConcreteInt(loc::ConcreteInt CI) { 144 return VisitConcreteInt(CI); 145 } 146 QualType VisitNonLocConcreteInt(nonloc::ConcreteInt CI) { 147 return VisitConcreteInt(CI); 148 } 149 QualType VisitNonLocLocAsInteger(nonloc::LocAsInteger LI) { 150 QualType NestedType = Visit(LI.getLoc()); 151 if (NestedType.isNull()) 152 return NestedType; 153 154 return Context.getIntTypeForBitwidth(LI.getNumBits(), 155 NestedType->isSignedIntegerType()); 156 } 157 QualType VisitNonLocCompoundVal(nonloc::CompoundVal CV) { 158 return CV.getValue()->getType(); 159 } 160 QualType VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal LCV) { 161 return LCV.getRegion()->getValueType(); 162 } 163 QualType VisitNonLocSymbolVal(nonloc::SymbolVal SV) { 164 return Visit(SV.getSymbol()); 165 } 166 QualType VisitSymbolicRegion(const SymbolicRegion *SR) { 167 return Visit(SR->getSymbol()); 168 } 169 QualType VisitTypedRegion(const TypedRegion *TR) { 170 return TR->getLocationType(); 171 } 172 QualType VisitSymExpr(const SymExpr *SE) { return SE->getType(); } 173 }; 174 } // end anonymous namespace 175 176 QualType SVal::getType(const ASTContext &Context) const { 177 TypeRetrievingVisitor TRV{Context}; 178 return TRV.Visit(*this); 179 } 180 181 const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const { 182 return getRegion()->StripCasts(StripBaseCasts); 183 } 184 185 const void *nonloc::LazyCompoundVal::getStore() const { 186 return static_cast<const LazyCompoundValData*>(Data)->getStore(); 187 } 188 189 const TypedValueRegion *nonloc::LazyCompoundVal::getRegion() const { 190 return static_cast<const LazyCompoundValData*>(Data)->getRegion(); 191 } 192 193 bool nonloc::PointerToMember::isNullMemberPointer() const { 194 return getPTMData().isNull(); 195 } 196 197 const NamedDecl *nonloc::PointerToMember::getDecl() const { 198 const auto PTMD = this->getPTMData(); 199 if (PTMD.isNull()) 200 return nullptr; 201 202 const NamedDecl *ND = nullptr; 203 if (PTMD.is<const NamedDecl *>()) 204 ND = PTMD.get<const NamedDecl *>(); 205 else 206 ND = PTMD.get<const PointerToMemberData *>()->getDeclaratorDecl(); 207 208 return ND; 209 } 210 211 //===----------------------------------------------------------------------===// 212 // Other Iterators. 213 //===----------------------------------------------------------------------===// 214 215 nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const { 216 return getValue()->begin(); 217 } 218 219 nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const { 220 return getValue()->end(); 221 } 222 223 nonloc::PointerToMember::iterator nonloc::PointerToMember::begin() const { 224 const PTMDataType PTMD = getPTMData(); 225 if (PTMD.is<const NamedDecl *>()) 226 return {}; 227 return PTMD.get<const PointerToMemberData *>()->begin(); 228 } 229 230 nonloc::PointerToMember::iterator nonloc::PointerToMember::end() const { 231 const PTMDataType PTMD = getPTMData(); 232 if (PTMD.is<const NamedDecl *>()) 233 return {}; 234 return PTMD.get<const PointerToMemberData *>()->end(); 235 } 236 237 //===----------------------------------------------------------------------===// 238 // Useful predicates. 239 //===----------------------------------------------------------------------===// 240 241 bool SVal::isConstant() const { 242 return getAs<nonloc::ConcreteInt>() || getAs<loc::ConcreteInt>(); 243 } 244 245 bool SVal::isConstant(int I) const { 246 if (Optional<loc::ConcreteInt> LV = getAs<loc::ConcreteInt>()) 247 return LV->getValue() == I; 248 if (Optional<nonloc::ConcreteInt> NV = getAs<nonloc::ConcreteInt>()) 249 return NV->getValue() == I; 250 return false; 251 } 252 253 bool SVal::isZeroConstant() const { 254 return isConstant(0); 255 } 256 257 //===----------------------------------------------------------------------===// 258 // Pretty-Printing. 259 //===----------------------------------------------------------------------===// 260 261 LLVM_DUMP_METHOD void SVal::dump() const { dumpToStream(llvm::errs()); } 262 263 void SVal::printJson(raw_ostream &Out, bool AddQuotes) const { 264 std::string Buf; 265 llvm::raw_string_ostream TempOut(Buf); 266 267 dumpToStream(TempOut); 268 269 Out << JsonFormat(TempOut.str(), AddQuotes); 270 } 271 272 void SVal::dumpToStream(raw_ostream &os) const { 273 switch (getBaseKind()) { 274 case UnknownValKind: 275 os << "Unknown"; 276 break; 277 case NonLocKind: 278 castAs<NonLoc>().dumpToStream(os); 279 break; 280 case LocKind: 281 castAs<Loc>().dumpToStream(os); 282 break; 283 case UndefinedValKind: 284 os << "Undefined"; 285 break; 286 } 287 } 288 289 void NonLoc::dumpToStream(raw_ostream &os) const { 290 switch (getSubKind()) { 291 case nonloc::ConcreteIntKind: { 292 const auto &Value = castAs<nonloc::ConcreteInt>().getValue(); 293 os << Value << ' ' << (Value.isSigned() ? 'S' : 'U') 294 << Value.getBitWidth() << 'b'; 295 break; 296 } 297 case nonloc::SymbolValKind: 298 os << castAs<nonloc::SymbolVal>().getSymbol(); 299 break; 300 301 case nonloc::LocAsIntegerKind: { 302 const nonloc::LocAsInteger& C = castAs<nonloc::LocAsInteger>(); 303 os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]"; 304 break; 305 } 306 case nonloc::CompoundValKind: { 307 const nonloc::CompoundVal& C = castAs<nonloc::CompoundVal>(); 308 os << "compoundVal{"; 309 bool first = true; 310 for (const auto &I : C) { 311 if (first) { 312 os << ' '; first = false; 313 } 314 else 315 os << ", "; 316 317 I.dumpToStream(os); 318 } 319 os << "}"; 320 break; 321 } 322 case nonloc::LazyCompoundValKind: { 323 const nonloc::LazyCompoundVal &C = castAs<nonloc::LazyCompoundVal>(); 324 os << "lazyCompoundVal{" << const_cast<void *>(C.getStore()) 325 << ',' << C.getRegion() 326 << '}'; 327 break; 328 } 329 case nonloc::PointerToMemberKind: { 330 os << "pointerToMember{"; 331 const nonloc::PointerToMember &CastRes = 332 castAs<nonloc::PointerToMember>(); 333 if (CastRes.getDecl()) 334 os << "|" << CastRes.getDecl()->getQualifiedNameAsString() << "|"; 335 bool first = true; 336 for (const auto &I : CastRes) { 337 if (first) { 338 os << ' '; first = false; 339 } 340 else 341 os << ", "; 342 343 os << I->getType(); 344 } 345 346 os << '}'; 347 break; 348 } 349 default: 350 assert(false && "Pretty-printed not implemented for this NonLoc."); 351 break; 352 } 353 } 354 355 void Loc::dumpToStream(raw_ostream &os) const { 356 switch (getSubKind()) { 357 case loc::ConcreteIntKind: 358 os << castAs<loc::ConcreteInt>().getValue().getZExtValue() << " (Loc)"; 359 break; 360 case loc::GotoLabelKind: 361 os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName(); 362 break; 363 case loc::MemRegionValKind: 364 os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString(); 365 break; 366 default: 367 llvm_unreachable("Pretty-printing not implemented for this Loc."); 368 } 369 } 370