1 //==- BasicValueFactory.h - Basic values for Path Sens analysis --*- C++ -*-==// 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 BasicValueFactory, a class that manages the lifetime 10 // of APSInt objects and symbolic constraints used by ExprEngine 11 // and related classes. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H 16 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H 17 18 #include "clang/AST/ASTContext.h" 19 #include "clang/AST/Expr.h" 20 #include "clang/AST/Type.h" 21 #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h" 22 #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" 24 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 25 #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" 26 #include "llvm/ADT/APSInt.h" 27 #include "llvm/ADT/FoldingSet.h" 28 #include "llvm/ADT/ImmutableList.h" 29 #include "llvm/ADT/iterator_range.h" 30 #include "llvm/Support/Allocator.h" 31 #include <cassert> 32 #include <cstdint> 33 #include <utility> 34 35 namespace clang { 36 37 class CXXBaseSpecifier; 38 39 namespace ento { 40 41 class CompoundValData : public llvm::FoldingSetNode { 42 QualType T; 43 llvm::ImmutableList<SVal> L; 44 45 public: 46 CompoundValData(QualType t, llvm::ImmutableList<SVal> l) : T(t), L(l) { 47 assert(NonLoc::isCompoundType(t)); 48 } 49 50 using iterator = llvm::ImmutableList<SVal>::iterator; 51 52 iterator begin() const { return L.begin(); } 53 iterator end() const { return L.end(); } 54 55 QualType getType() const { return T; } 56 57 static void Profile(llvm::FoldingSetNodeID& ID, QualType T, 58 llvm::ImmutableList<SVal> L); 59 60 void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); } 61 }; 62 63 class LazyCompoundValData : public llvm::FoldingSetNode { 64 StoreRef store; 65 const TypedValueRegion *region; 66 67 public: 68 LazyCompoundValData(const StoreRef &st, const TypedValueRegion *r) 69 : store(st), region(r) { 70 assert(r); 71 assert(NonLoc::isCompoundType(r->getValueType())); 72 } 73 74 /// It might return null. 75 const void *getStore() const { return store.getStore(); } 76 77 LLVM_ATTRIBUTE_RETURNS_NONNULL 78 const TypedValueRegion *getRegion() const { return region; } 79 80 static void Profile(llvm::FoldingSetNodeID& ID, 81 const StoreRef &store, 82 const TypedValueRegion *region); 83 84 void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); } 85 }; 86 87 class PointerToMemberData : public llvm::FoldingSetNode { 88 const NamedDecl *D; 89 llvm::ImmutableList<const CXXBaseSpecifier *> L; 90 91 public: 92 PointerToMemberData(const NamedDecl *D, 93 llvm::ImmutableList<const CXXBaseSpecifier *> L) 94 : D(D), L(L) {} 95 96 using iterator = llvm::ImmutableList<const CXXBaseSpecifier *>::iterator; 97 98 iterator begin() const { return L.begin(); } 99 iterator end() const { return L.end(); } 100 101 static void Profile(llvm::FoldingSetNodeID &ID, const NamedDecl *D, 102 llvm::ImmutableList<const CXXBaseSpecifier *> L); 103 104 void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, D, L); } 105 106 /// It might return null. 107 const NamedDecl *getDeclaratorDecl() const { return D; } 108 109 llvm::ImmutableList<const CXXBaseSpecifier *> getCXXBaseList() const { 110 return L; 111 } 112 }; 113 114 class BasicValueFactory { 115 using APSIntSetTy = 116 llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt>>; 117 118 ASTContext &Ctx; 119 llvm::BumpPtrAllocator& BPAlloc; 120 121 APSIntSetTy APSIntSet; 122 void *PersistentSVals = nullptr; 123 void *PersistentSValPairs = nullptr; 124 125 llvm::ImmutableList<SVal>::Factory SValListFactory; 126 llvm::ImmutableList<const CXXBaseSpecifier *>::Factory CXXBaseListFactory; 127 llvm::FoldingSet<CompoundValData> CompoundValDataSet; 128 llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet; 129 llvm::FoldingSet<PointerToMemberData> PointerToMemberDataSet; 130 131 // This is private because external clients should use the factory 132 // method that takes a QualType. 133 APSIntPtr getValue(uint64_t X, unsigned BitWidth, bool isUnsigned); 134 135 public: 136 BasicValueFactory(ASTContext &ctx, llvm::BumpPtrAllocator &Alloc) 137 : Ctx(ctx), BPAlloc(Alloc), SValListFactory(Alloc), 138 CXXBaseListFactory(Alloc) {} 139 140 ~BasicValueFactory(); 141 142 ASTContext &getContext() const { return Ctx; } 143 144 APSIntPtr getValue(const llvm::APSInt &X); 145 APSIntPtr getValue(const llvm::APInt &X, bool isUnsigned); 146 APSIntPtr getValue(uint64_t X, QualType T); 147 148 /// Returns the type of the APSInt used to store values of the given QualType. 149 APSIntType getAPSIntType(QualType T) const { 150 // For the purposes of the analysis and constraints, we treat atomics 151 // as their underlying types. 152 if (const AtomicType *AT = T->getAs<AtomicType>()) { 153 T = AT->getValueType(); 154 } 155 156 if (T->isIntegralOrEnumerationType() || Loc::isLocType(T)) { 157 return APSIntType(Ctx.getIntWidth(T), 158 !T->isSignedIntegerOrEnumerationType()); 159 } else { 160 // implicitly handle case of T->isFixedPointType() 161 return APSIntType(Ctx.getIntWidth(T), T->isUnsignedFixedPointType()); 162 } 163 164 llvm_unreachable("Unsupported type in getAPSIntType!"); 165 } 166 167 /// Convert - Create a new persistent APSInt with the same value as 'From' 168 /// but with the bitwidth and signedness of 'To'. 169 APSIntPtr Convert(const llvm::APSInt &To, const llvm::APSInt &From) { 170 APSIntType TargetType(To); 171 if (TargetType == APSIntType(From)) 172 return getValue(From); 173 174 return getValue(TargetType.convert(From)); 175 } 176 177 APSIntPtr Convert(QualType T, const llvm::APSInt &From) { 178 APSIntType TargetType = getAPSIntType(T); 179 return Convert(TargetType, From); 180 } 181 182 APSIntPtr Convert(APSIntType TargetType, const llvm::APSInt &From) { 183 if (TargetType == APSIntType(From)) 184 return getValue(From); 185 186 return getValue(TargetType.convert(From)); 187 } 188 189 APSIntPtr getIntValue(uint64_t X, bool isUnsigned) { 190 QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy; 191 return getValue(X, T); 192 } 193 194 APSIntPtr getMaxValue(const llvm::APSInt &v) { 195 return getValue(APSIntType(v).getMaxValue()); 196 } 197 198 APSIntPtr getMinValue(const llvm::APSInt &v) { 199 return getValue(APSIntType(v).getMinValue()); 200 } 201 202 APSIntPtr getMaxValue(QualType T) { return getMaxValue(getAPSIntType(T)); } 203 204 APSIntPtr getMinValue(QualType T) { return getMinValue(getAPSIntType(T)); } 205 206 APSIntPtr getMaxValue(APSIntType T) { return getValue(T.getMaxValue()); } 207 208 APSIntPtr getMinValue(APSIntType T) { return getValue(T.getMinValue()); } 209 210 APSIntPtr Add1(const llvm::APSInt &V) { 211 llvm::APSInt X = V; 212 ++X; 213 return getValue(X); 214 } 215 216 APSIntPtr Sub1(const llvm::APSInt &V) { 217 llvm::APSInt X = V; 218 --X; 219 return getValue(X); 220 } 221 222 APSIntPtr getZeroWithTypeSize(QualType T) { 223 assert(T->isScalarType()); 224 return getValue(0, Ctx.getTypeSize(T), true); 225 } 226 227 APSIntPtr getTruthValue(bool b, QualType T) { 228 return getValue(b ? 1 : 0, Ctx.getIntWidth(T), 229 T->isUnsignedIntegerOrEnumerationType()); 230 } 231 232 APSIntPtr getTruthValue(bool b) { 233 return getTruthValue(b, Ctx.getLogicalOperationType()); 234 } 235 236 const CompoundValData *getCompoundValData(QualType T, 237 llvm::ImmutableList<SVal> Vals); 238 239 const LazyCompoundValData *getLazyCompoundValData(const StoreRef &store, 240 const TypedValueRegion *region); 241 242 const PointerToMemberData * 243 getPointerToMemberData(const NamedDecl *ND, 244 llvm::ImmutableList<const CXXBaseSpecifier *> L); 245 246 llvm::ImmutableList<SVal> getEmptySValList() { 247 return SValListFactory.getEmptyList(); 248 } 249 250 llvm::ImmutableList<SVal> prependSVal(SVal X, llvm::ImmutableList<SVal> L) { 251 return SValListFactory.add(X, L); 252 } 253 254 llvm::ImmutableList<const CXXBaseSpecifier *> getEmptyCXXBaseList() { 255 return CXXBaseListFactory.getEmptyList(); 256 } 257 258 llvm::ImmutableList<const CXXBaseSpecifier *> prependCXXBase( 259 const CXXBaseSpecifier *CBS, 260 llvm::ImmutableList<const CXXBaseSpecifier *> L) { 261 return CXXBaseListFactory.add(CBS, L); 262 } 263 264 const PointerToMemberData * 265 accumCXXBase(llvm::iterator_range<CastExpr::path_const_iterator> PathRange, 266 const nonloc::PointerToMember &PTM, const clang::CastKind &kind); 267 268 std::optional<APSIntPtr> evalAPSInt(BinaryOperator::Opcode Op, 269 const llvm::APSInt &V1, 270 const llvm::APSInt &V2); 271 272 const std::pair<SVal, uintptr_t>& 273 getPersistentSValWithData(const SVal& V, uintptr_t Data); 274 275 const std::pair<SVal, SVal>& 276 getPersistentSValPair(const SVal& V1, const SVal& V2); 277 278 const SVal* getPersistentSVal(SVal X); 279 }; 280 281 } // namespace ento 282 283 } // namespace clang 284 285 #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H 286