Coverage Report

Created: 2023-09-21 18:56

/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
}