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