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