/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- BasicValueFactory.cpp - Basic values for Path Sens analysis --------===// |
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 | | #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" |
16 | | #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" |
17 | | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" |
18 | | #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" |
19 | | #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" |
20 | | #include "llvm/ADT/APSInt.h" |
21 | | #include "llvm/ADT/FoldingSet.h" |
22 | | #include "llvm/ADT/ImmutableList.h" |
23 | | #include "llvm/ADT/STLExtras.h" |
24 | | #include "llvm/ADT/SmallPtrSet.h" |
25 | | #include <cassert> |
26 | | #include <cstdint> |
27 | | #include <utility> |
28 | | |
29 | | using namespace clang; |
30 | | using namespace ento; |
31 | | |
32 | | void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T, |
33 | 1.96k | llvm::ImmutableList<SVal> L) { |
34 | 1.96k | T.Profile(ID); |
35 | 1.96k | ID.AddPointer(L.getInternalPointer()); |
36 | 1.96k | } |
37 | | |
38 | | void LazyCompoundValData::Profile(llvm::FoldingSetNodeID& ID, |
39 | | const StoreRef &store, |
40 | 102k | const TypedValueRegion *region) { |
41 | 102k | ID.AddPointer(store.getStore()); |
42 | 102k | ID.AddPointer(region); |
43 | 102k | } |
44 | | |
45 | | void PointerToMemberData::Profile( |
46 | | llvm::FoldingSetNodeID &ID, const NamedDecl *D, |
47 | 41 | llvm::ImmutableList<const CXXBaseSpecifier *> L) { |
48 | 41 | ID.AddPointer(D); |
49 | 41 | ID.AddPointer(L.getInternalPointer()); |
50 | 41 | } |
51 | | |
52 | | using SValData = std::pair<SVal, uintptr_t>; |
53 | | using SValPair = std::pair<SVal, SVal>; |
54 | | |
55 | | namespace llvm { |
56 | | |
57 | | template<> struct FoldingSetTrait<SValData> { |
58 | 190 | static inline void Profile(const SValData& X, llvm::FoldingSetNodeID& ID) { |
59 | 190 | X.first.Profile(ID); |
60 | 190 | ID.AddPointer( (void*) X.second); |
61 | 190 | } |
62 | | }; |
63 | | |
64 | | template<> struct FoldingSetTrait<SValPair> { |
65 | 0 | static inline void Profile(const SValPair& X, llvm::FoldingSetNodeID& ID) { |
66 | 0 | X.first.Profile(ID); |
67 | 0 | X.second.Profile(ID); |
68 | 0 | } |
69 | | }; |
70 | | |
71 | | } // namespace llvm |
72 | | |
73 | | using PersistentSValsTy = |
74 | | llvm::FoldingSet<llvm::FoldingSetNodeWrapper<SValData>>; |
75 | | |
76 | | using PersistentSValPairsTy = |
77 | | llvm::FoldingSet<llvm::FoldingSetNodeWrapper<SValPair>>; |
78 | | |
79 | 16.3k | BasicValueFactory::~BasicValueFactory() { |
80 | | // Note that the dstor for the contents of APSIntSet will never be called, |
81 | | // so we iterate over the set and invoke the dstor for each APSInt. This |
82 | | // frees an aux. memory allocated to represent very large constants. |
83 | 16.3k | for (const auto &I : APSIntSet) |
84 | 121k | I.getValue().~APSInt(); |
85 | | |
86 | 16.3k | delete (PersistentSValsTy*) PersistentSVals; |
87 | 16.3k | delete (PersistentSValPairsTy*) PersistentSValPairs; |
88 | 16.3k | } |
89 | | |
90 | 3.88M | const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) { |
91 | 3.88M | llvm::FoldingSetNodeID ID; |
92 | 3.88M | void *InsertPos; |
93 | | |
94 | 3.88M | using FoldNodeTy = llvm::FoldingSetNodeWrapper<llvm::APSInt>; |
95 | | |
96 | 3.88M | X.Profile(ID); |
97 | 3.88M | FoldNodeTy* P = APSIntSet.FindNodeOrInsertPos(ID, InsertPos); |
98 | | |
99 | 3.88M | if (!P) { |
100 | 121k | P = new (BPAlloc) FoldNodeTy(X); |
101 | 121k | APSIntSet.InsertNode(P, InsertPos); |
102 | 121k | } |
103 | | |
104 | 3.88M | return *P; |
105 | 3.88M | } |
106 | | |
107 | | const llvm::APSInt& BasicValueFactory::getValue(const llvm::APInt& X, |
108 | 96.7k | bool isUnsigned) { |
109 | 96.7k | llvm::APSInt V(X, isUnsigned); |
110 | 96.7k | return getValue(V); |
111 | 96.7k | } |
112 | | |
113 | | const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth, |
114 | 1.00M | bool isUnsigned) { |
115 | 1.00M | llvm::APSInt V(BitWidth, isUnsigned); |
116 | 1.00M | V = X; |
117 | 1.00M | return getValue(V); |
118 | 1.00M | } |
119 | | |
120 | 398k | const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) { |
121 | 398k | return getValue(getAPSIntType(T).getValue(X)); |
122 | 398k | } |
123 | | |
124 | | const CompoundValData* |
125 | | BasicValueFactory::getCompoundValData(QualType T, |
126 | 1.64k | llvm::ImmutableList<SVal> Vals) { |
127 | 1.64k | llvm::FoldingSetNodeID ID; |
128 | 1.64k | CompoundValData::Profile(ID, T, Vals); |
129 | 1.64k | void *InsertPos; |
130 | | |
131 | 1.64k | CompoundValData* D = CompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos); |
132 | | |
133 | 1.64k | if (!D) { |
134 | 1.34k | D = new (BPAlloc) CompoundValData(T, Vals); |
135 | 1.34k | CompoundValDataSet.InsertNode(D, InsertPos); |
136 | 1.34k | } |
137 | | |
138 | 1.64k | return D; |
139 | 1.64k | } |
140 | | |
141 | | const LazyCompoundValData* |
142 | | BasicValueFactory::getLazyCompoundValData(const StoreRef &store, |
143 | 58.9k | const TypedValueRegion *region) { |
144 | 58.9k | llvm::FoldingSetNodeID ID; |
145 | 58.9k | LazyCompoundValData::Profile(ID, store, region); |
146 | 58.9k | void *InsertPos; |
147 | | |
148 | 58.9k | LazyCompoundValData *D = |
149 | 58.9k | LazyCompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos); |
150 | | |
151 | 58.9k | if (!D) { |
152 | 21.4k | D = new (BPAlloc) LazyCompoundValData(store, region); |
153 | 21.4k | LazyCompoundValDataSet.InsertNode(D, InsertPos); |
154 | 21.4k | } |
155 | | |
156 | 58.9k | return D; |
157 | 58.9k | } |
158 | | |
159 | | const PointerToMemberData *BasicValueFactory::getPointerToMemberData( |
160 | 32 | const NamedDecl *ND, llvm::ImmutableList<const CXXBaseSpecifier *> L) { |
161 | 32 | llvm::FoldingSetNodeID ID; |
162 | 32 | PointerToMemberData::Profile(ID, ND, L); |
163 | 32 | void *InsertPos; |
164 | | |
165 | 32 | PointerToMemberData *D = |
166 | 32 | PointerToMemberDataSet.FindNodeOrInsertPos(ID, InsertPos); |
167 | | |
168 | 32 | if (!D) { |
169 | 24 | D = new (BPAlloc) PointerToMemberData(ND, L); |
170 | 24 | PointerToMemberDataSet.InsertNode(D, InsertPos); |
171 | 24 | } |
172 | | |
173 | 32 | return D; |
174 | 32 | } |
175 | | |
176 | | LLVM_ATTRIBUTE_UNUSED bool hasNoRepeatedElements( |
177 | 32 | llvm::ImmutableList<const CXXBaseSpecifier *> BaseSpecList) { |
178 | 32 | llvm::SmallPtrSet<QualType, 16> BaseSpecSeen; |
179 | 32 | for (const CXXBaseSpecifier *BaseSpec : BaseSpecList) { |
180 | 30 | QualType BaseType = BaseSpec->getType(); |
181 | | // Check whether inserted |
182 | 30 | if (!BaseSpecSeen.insert(BaseType).second) |
183 | 0 | return false; |
184 | 30 | } |
185 | 32 | return true; |
186 | 32 | } |
187 | | |
188 | | const PointerToMemberData *BasicValueFactory::accumCXXBase( |
189 | | llvm::iterator_range<CastExpr::path_const_iterator> PathRange, |
190 | 32 | const nonloc::PointerToMember &PTM, const CastKind &kind) { |
191 | 32 | assert((kind == CK_DerivedToBaseMemberPointer || |
192 | 32 | kind == CK_BaseToDerivedMemberPointer || |
193 | 32 | kind == CK_ReinterpretMemberPointer) && |
194 | 32 | "accumCXXBase called with wrong CastKind"); |
195 | 32 | nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData(); |
196 | 32 | const NamedDecl *ND = nullptr; |
197 | 32 | llvm::ImmutableList<const CXXBaseSpecifier *> BaseSpecList; |
198 | | |
199 | 32 | if (PTMDT.isNull() || PTMDT.is<const NamedDecl *>()31 ) { |
200 | 14 | if (PTMDT.is<const NamedDecl *>()) |
201 | 14 | ND = PTMDT.get<const NamedDecl *>(); |
202 | | |
203 | 14 | BaseSpecList = CXXBaseListFactory.getEmptyList(); |
204 | 18 | } else { |
205 | 18 | const PointerToMemberData *PTMD = PTMDT.get<const PointerToMemberData *>(); |
206 | 18 | ND = PTMD->getDeclaratorDecl(); |
207 | | |
208 | 18 | BaseSpecList = PTMD->getCXXBaseList(); |
209 | 18 | } |
210 | | |
211 | 32 | assert(hasNoRepeatedElements(BaseSpecList) && |
212 | 32 | "CXXBaseSpecifier list of PointerToMemberData must not have repeated " |
213 | 32 | "elements"); |
214 | | |
215 | 32 | if (kind == CK_DerivedToBaseMemberPointer) { |
216 | | // Here we pop off matching CXXBaseSpecifiers from BaseSpecList. |
217 | | // Because, CK_DerivedToBaseMemberPointer comes from a static_cast and |
218 | | // serves to remove a matching implicit cast. Note that static_cast's that |
219 | | // are no-ops do not count since they produce an empty PathRange, a nice |
220 | | // thing about Clang AST. |
221 | | |
222 | | // Now we know that there are no repetitions in BaseSpecList. |
223 | | // So, popping the first element from it corresponding to each element in |
224 | | // PathRange is equivalent to only including elements that are in |
225 | | // BaseSpecList but not it PathRange |
226 | 5 | auto ReducedBaseSpecList = CXXBaseListFactory.getEmptyList(); |
227 | 9 | for (const CXXBaseSpecifier *BaseSpec : BaseSpecList) { |
228 | 11 | auto IsSameAsBaseSpec = [&BaseSpec](const CXXBaseSpecifier *I) -> bool { |
229 | 11 | return BaseSpec->getType() == I->getType(); |
230 | 11 | }; |
231 | 9 | if (llvm::none_of(PathRange, IsSameAsBaseSpec)) |
232 | 2 | ReducedBaseSpecList = |
233 | 2 | CXXBaseListFactory.add(BaseSpec, ReducedBaseSpecList); |
234 | 9 | } |
235 | | |
236 | 5 | return getPointerToMemberData(ND, ReducedBaseSpecList); |
237 | 5 | } |
238 | | // FIXME: Reinterpret casts on member-pointers are not handled properly by |
239 | | // this code |
240 | 27 | for (const CXXBaseSpecifier *I : llvm::reverse(PathRange)) |
241 | 32 | BaseSpecList = prependCXXBase(I, BaseSpecList); |
242 | 27 | return getPointerToMemberData(ND, BaseSpecList); |
243 | 32 | } |
244 | | |
245 | | const llvm::APSInt* |
246 | | BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, |
247 | 118k | const llvm::APSInt& V1, const llvm::APSInt& V2) { |
248 | 118k | switch (Op) { |
249 | 0 | default: |
250 | 0 | llvm_unreachable("Invalid Opcode."); |
251 | |
|
252 | 2.51k | case BO_Mul: |
253 | 2.51k | return &getValue( V1 * V2 ); |
254 | | |
255 | 2.07k | case BO_Div: |
256 | 2.07k | if (V2 == 0) // Avoid division by zero |
257 | 1 | return nullptr; |
258 | 2.07k | return &getValue( V1 / V2 ); |
259 | | |
260 | 83 | case BO_Rem: |
261 | 83 | if (V2 == 0) // Avoid division by zero |
262 | 0 | return nullptr; |
263 | 83 | return &getValue( V1 % V2 ); |
264 | | |
265 | 21.6k | case BO_Add: |
266 | 21.6k | return &getValue( V1 + V2 ); |
267 | | |
268 | 4.63k | case BO_Sub: |
269 | 4.63k | return &getValue( V1 - V2 ); |
270 | | |
271 | 387 | case BO_Shl: { |
272 | | // FIXME: This logic should probably go higher up, where we can |
273 | | // test these conditions symbolically. |
274 | | |
275 | 387 | if (V2.isSigned() && V2.isNegative()369 ) |
276 | 3 | return nullptr; |
277 | | |
278 | 384 | uint64_t Amt = V2.getZExtValue(); |
279 | | |
280 | 384 | if (Amt >= V1.getBitWidth()) |
281 | 5 | return nullptr; |
282 | | |
283 | 379 | if (!Ctx.getLangOpts().CPlusPlus20) { |
284 | 366 | if (V1.isSigned() && V1.isNegative()205 ) |
285 | 3 | return nullptr; |
286 | | |
287 | 363 | if (V1.isSigned() && Amt > V1.countl_zero()202 ) |
288 | 3 | return nullptr; |
289 | 363 | } |
290 | | |
291 | 373 | return &getValue( V1.operator<<( (unsigned) Amt )); |
292 | 379 | } |
293 | | |
294 | 974 | case BO_Shr: { |
295 | | // FIXME: This logic should probably go higher up, where we can |
296 | | // test these conditions symbolically. |
297 | | |
298 | 974 | if (V2.isSigned() && V2.isNegative()970 ) |
299 | 0 | return nullptr; |
300 | | |
301 | 974 | uint64_t Amt = V2.getZExtValue(); |
302 | | |
303 | 974 | if (Amt >= V1.getBitWidth()) |
304 | 0 | return nullptr; |
305 | | |
306 | 974 | return &getValue( V1.operator>>( (unsigned) Amt )); |
307 | 974 | } |
308 | | |
309 | 70.1k | case BO_LT: |
310 | 70.1k | return &getTruthValue( V1 < V2 ); |
311 | | |
312 | 2.11k | case BO_GT: |
313 | 2.11k | return &getTruthValue( V1 > V2 ); |
314 | | |
315 | 1.89k | case BO_LE: |
316 | 1.89k | return &getTruthValue( V1 <= V2 ); |
317 | | |
318 | 3.69k | case BO_GE: |
319 | 3.69k | return &getTruthValue( V1 >= V2 ); |
320 | | |
321 | 6.94k | case BO_EQ: |
322 | 6.94k | return &getTruthValue( V1 == V2 ); |
323 | | |
324 | 489 | case BO_NE: |
325 | 489 | return &getTruthValue( V1 != V2 ); |
326 | | |
327 | | // Note: LAnd, LOr, Comma are handled specially by higher-level logic. |
328 | | |
329 | 983 | case BO_And: |
330 | 983 | return &getValue( V1 & V2 ); |
331 | | |
332 | 307 | case BO_Or: |
333 | 307 | return &getValue( V1 | V2 ); |
334 | | |
335 | 12 | case BO_Xor: |
336 | 12 | return &getValue( V1 ^ V2 ); |
337 | 118k | } |
338 | 118k | } |
339 | | |
340 | | const std::pair<SVal, uintptr_t>& |
341 | 413 | BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) { |
342 | | // Lazily create the folding set. |
343 | 413 | if (!PersistentSVals) PersistentSVals = new PersistentSValsTy()152 ; |
344 | | |
345 | 413 | llvm::FoldingSetNodeID ID; |
346 | 413 | void *InsertPos; |
347 | 413 | V.Profile(ID); |
348 | 413 | ID.AddPointer((void*) Data); |
349 | | |
350 | 413 | PersistentSValsTy& Map = *((PersistentSValsTy*) PersistentSVals); |
351 | | |
352 | 413 | using FoldNodeTy = llvm::FoldingSetNodeWrapper<SValData>; |
353 | | |
354 | 413 | FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos); |
355 | | |
356 | 413 | if (!P) { |
357 | 225 | P = new (BPAlloc) FoldNodeTy(std::make_pair(V, Data)); |
358 | 225 | Map.InsertNode(P, InsertPos); |
359 | 225 | } |
360 | | |
361 | 413 | return P->getValue(); |
362 | 413 | } |
363 | | |
364 | | const std::pair<SVal, SVal>& |
365 | 0 | BasicValueFactory::getPersistentSValPair(const SVal& V1, const SVal& V2) { |
366 | | // Lazily create the folding set. |
367 | 0 | if (!PersistentSValPairs) PersistentSValPairs = new PersistentSValPairsTy(); |
368 | |
|
369 | 0 | llvm::FoldingSetNodeID ID; |
370 | 0 | void *InsertPos; |
371 | 0 | V1.Profile(ID); |
372 | 0 | V2.Profile(ID); |
373 | |
|
374 | 0 | PersistentSValPairsTy& Map = *((PersistentSValPairsTy*) PersistentSValPairs); |
375 | |
|
376 | 0 | using FoldNodeTy = llvm::FoldingSetNodeWrapper<SValPair>; |
377 | |
|
378 | 0 | FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos); |
379 | |
|
380 | 0 | if (!P) { |
381 | 0 | P = new (BPAlloc) FoldNodeTy(std::make_pair(V1, V2)); |
382 | 0 | Map.InsertNode(P, InsertPos); |
383 | 0 | } |
384 | |
|
385 | 0 | return P->getValue(); |
386 | 0 | } |
387 | | |
388 | 0 | const SVal* BasicValueFactory::getPersistentSVal(SVal X) { |
389 | 0 | return &getPersistentSValWithData(X, 0).first; |
390 | 0 | } |