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