25
25
#include " llvm/ADT/DenseMap.h"
26
26
#include " llvm/ADT/DenseSet.h"
27
27
#include " llvm/ADT/FoldingSet.h"
28
+ #include " llvm/ADT/ImmutableSet.h"
28
29
#include " llvm/ADT/iterator_range.h"
29
30
#include " llvm/Support/Allocator.h"
30
31
#include < cassert>
@@ -43,15 +44,16 @@ class StoreManager;
43
44
class SymbolRegionValue : public SymbolData {
44
45
const TypedValueRegion *R;
45
46
46
- public:
47
+ friend class SymExprAllocator ;
47
48
SymbolRegionValue (SymbolID sym, const TypedValueRegion *r)
48
49
: SymbolData(SymbolRegionValueKind, sym), R(r) {
49
50
assert (r);
50
51
assert (isValidTypeForSymbol (r->getValueType ()));
51
52
}
52
53
54
+ public:
53
55
LLVM_ATTRIBUTE_RETURNS_NONNULL
54
- const TypedValueRegion* getRegion () const { return R; }
56
+ const TypedValueRegion * getRegion () const { return R; }
55
57
56
58
static void Profile (llvm::FoldingSetNodeID& profile, const TypedValueRegion* R) {
57
59
profile.AddInteger ((unsigned ) SymbolRegionValueKind);
@@ -84,7 +86,7 @@ class SymbolConjured : public SymbolData {
84
86
const LocationContext *LCtx;
85
87
const void *SymbolTag;
86
88
87
- public:
89
+ friend class SymExprAllocator ;
88
90
SymbolConjured (SymbolID sym, const Stmt *s, const LocationContext *lctx,
89
91
QualType t, unsigned count, const void *symbolTag)
90
92
: SymbolData(SymbolConjuredKind, sym), S(s), T(t), Count(count),
@@ -98,6 +100,7 @@ class SymbolConjured : public SymbolData {
98
100
assert (isValidTypeForSymbol (t));
99
101
}
100
102
103
+ public:
101
104
// / It might return null.
102
105
const Stmt *getStmt () const { return S; }
103
106
unsigned getCount () const { return Count; }
@@ -137,14 +140,15 @@ class SymbolDerived : public SymbolData {
137
140
SymbolRef parentSymbol;
138
141
const TypedValueRegion *R;
139
142
140
- public:
143
+ friend class SymExprAllocator ;
141
144
SymbolDerived (SymbolID sym, SymbolRef parent, const TypedValueRegion *r)
142
145
: SymbolData(SymbolDerivedKind, sym), parentSymbol(parent), R(r) {
143
146
assert (parent);
144
147
assert (r);
145
148
assert (isValidTypeForSymbol (r->getValueType ()));
146
149
}
147
150
151
+ public:
148
152
LLVM_ATTRIBUTE_RETURNS_NONNULL
149
153
SymbolRef getParentSymbol () const { return parentSymbol; }
150
154
LLVM_ATTRIBUTE_RETURNS_NONNULL
@@ -180,12 +184,13 @@ class SymbolDerived : public SymbolData {
180
184
class SymbolExtent : public SymbolData {
181
185
const SubRegion *R;
182
186
183
- public:
187
+ friend class SymExprAllocator ;
184
188
SymbolExtent (SymbolID sym, const SubRegion *r)
185
189
: SymbolData(SymbolExtentKind, sym), R(r) {
186
190
assert (r);
187
191
}
188
192
193
+ public:
189
194
LLVM_ATTRIBUTE_RETURNS_NONNULL
190
195
const SubRegion *getRegion () const { return R; }
191
196
@@ -222,7 +227,7 @@ class SymbolMetadata : public SymbolData {
222
227
unsigned Count;
223
228
const void *Tag;
224
229
225
- public:
230
+ friend class SymExprAllocator ;
226
231
SymbolMetadata (SymbolID sym, const MemRegion* r, const Stmt *s, QualType t,
227
232
const LocationContext *LCtx, unsigned count, const void *tag)
228
233
: SymbolData(SymbolMetadataKind, sym), R(r), S(s), T(t), LCtx(LCtx),
@@ -234,6 +239,7 @@ class SymbolMetadata : public SymbolData {
234
239
assert (tag);
235
240
}
236
241
242
+ public:
237
243
LLVM_ATTRIBUTE_RETURNS_NONNULL
238
244
const MemRegion *getRegion () const { return R; }
239
245
@@ -286,15 +292,16 @@ class SymbolCast : public SymExpr {
286
292
// / The type of the result.
287
293
QualType ToTy;
288
294
289
- public:
290
- SymbolCast (const SymExpr *In, QualType From, QualType To)
291
- : SymExpr(SymbolCastKind), Operand(In), FromTy(From), ToTy(To) {
295
+ friend class SymExprAllocator ;
296
+ SymbolCast (SymbolID Sym, const SymExpr *In, QualType From, QualType To)
297
+ : SymExpr(SymbolCastKind, Sym ), Operand(In), FromTy(From), ToTy(To) {
292
298
assert (In);
293
299
assert (isValidTypeForSymbol (From));
294
300
// FIXME: GenericTaintChecker creates symbols of void type.
295
301
// Otherwise, 'To' should also be a valid type.
296
302
}
297
303
304
+ public:
298
305
unsigned computeComplexity () const override {
299
306
if (Complexity == 0 )
300
307
Complexity = 1 + Operand->computeComplexity ();
@@ -332,9 +339,10 @@ class UnarySymExpr : public SymExpr {
332
339
UnaryOperator::Opcode Op;
333
340
QualType T;
334
341
335
- public:
336
- UnarySymExpr (const SymExpr *In, UnaryOperator::Opcode Op, QualType T)
337
- : SymExpr(UnarySymExprKind), Operand(In), Op(Op), T(T) {
342
+ friend class SymExprAllocator ;
343
+ UnarySymExpr (SymbolID Sym, const SymExpr *In, UnaryOperator::Opcode Op,
344
+ QualType T)
345
+ : SymExpr(UnarySymExprKind, Sym), Operand(In), Op(Op), T(T) {
338
346
// Note, some unary operators are modeled as a binary operator. E.g. ++x is
339
347
// modeled as x + 1.
340
348
assert ((Op == UO_Minus || Op == UO_Not) && " non-supported unary expression" );
@@ -345,6 +353,7 @@ class UnarySymExpr : public SymExpr {
345
353
assert (!Loc::isLocType (T) && " unary symbol should be nonloc" );
346
354
}
347
355
356
+ public:
348
357
unsigned computeComplexity () const override {
349
358
if (Complexity == 0 )
350
359
Complexity = 1 + Operand->computeComplexity ();
@@ -381,8 +390,8 @@ class BinarySymExpr : public SymExpr {
381
390
QualType T;
382
391
383
392
protected:
384
- BinarySymExpr (Kind k, BinaryOperator::Opcode op, QualType t)
385
- : SymExpr(k), Op(op), T(t) {
393
+ BinarySymExpr (SymbolID Sym, Kind k, BinaryOperator::Opcode op, QualType t)
394
+ : SymExpr(k, Sym ), Op(op), T(t) {
386
395
assert (classof (this ));
387
396
// Binary expressions are results of arithmetic. Pointer arithmetic is not
388
397
// handled by binary expressions, but it is instead handled by applying
@@ -425,14 +434,15 @@ class BinarySymExprImpl : public BinarySymExpr {
425
434
LHSTYPE LHS;
426
435
RHSTYPE RHS;
427
436
428
- public:
429
- BinarySymExprImpl (LHSTYPE lhs, BinaryOperator::Opcode op, RHSTYPE rhs ,
430
- QualType t)
431
- : BinarySymExpr(ClassKind, op, t), LHS(lhs), RHS(rhs) {
437
+ friend class SymExprAllocator ;
438
+ BinarySymExprImpl (SymbolID Sym, LHSTYPE lhs, BinaryOperator::Opcode op,
439
+ RHSTYPE rhs, QualType t)
440
+ : BinarySymExpr(Sym, ClassKind, op, t), LHS(lhs), RHS(rhs) {
432
441
assert (getPointer (lhs));
433
442
assert (getPointer (rhs));
434
443
}
435
444
445
+ public:
436
446
void dumpToStream (raw_ostream &os) const override {
437
447
dumpToStreamImpl (os, LHS);
438
448
dumpToStreamImpl (os, getOpcode ());
@@ -478,6 +488,21 @@ using IntSymExpr = BinarySymExprImpl<APSIntPtr, const SymExpr *,
478
488
using SymSymExpr = BinarySymExprImpl<const SymExpr *, const SymExpr *,
479
489
SymExpr::Kind::SymSymExprKind>;
480
490
491
+ class SymExprAllocator {
492
+ SymbolID NextSymbolID = 0 ;
493
+ llvm::BumpPtrAllocator &Alloc;
494
+
495
+ public:
496
+ explicit SymExprAllocator (llvm::BumpPtrAllocator &Alloc) : Alloc(Alloc) {}
497
+
498
+ template <class SymT , typename ... ArgsT> SymT *make (ArgsT &&...Args) {
499
+ return new (Alloc) SymT (nextID (), std::forward<ArgsT>(Args)...);
500
+ }
501
+
502
+ private:
503
+ SymbolID nextID () { return NextSymbolID++; }
504
+ };
505
+
481
506
class SymbolManager {
482
507
using DataSetTy = llvm::FoldingSet<SymExpr>;
483
508
using SymbolDependTy =
@@ -489,15 +514,14 @@ class SymbolManager {
489
514
// / alive as long as the key is live.
490
515
SymbolDependTy SymbolDependencies;
491
516
492
- unsigned SymbolCounter = 0 ;
493
- llvm::BumpPtrAllocator& BPAlloc;
517
+ SymExprAllocator Alloc;
494
518
BasicValueFactory &BV;
495
519
ASTContext &Ctx;
496
520
497
521
public:
498
522
SymbolManager (ASTContext &ctx, BasicValueFactory &bv,
499
- llvm::BumpPtrAllocator& bpalloc)
500
- : SymbolDependencies(16 ), BPAlloc (bpalloc), BV(bv), Ctx(ctx) {}
523
+ llvm::BumpPtrAllocator & bpalloc)
524
+ : SymbolDependencies(16 ), Alloc (bpalloc), BV(bv), Ctx(ctx) {}
501
525
502
526
static bool canSymbolicate (QualType T);
503
527
@@ -687,4 +711,36 @@ class SymbolVisitor {
687
711
688
712
} // namespace clang
689
713
714
+ // Override the default definition that would use pointer values of SymbolRefs
715
+ // to order them, which is unstable due to ASLR.
716
+ // Use the SymbolID instead which reflect the order in which the symbols were
717
+ // allocated. This is usually stable across runs leading to the stability of
718
+ // ConstraintMap and other containers using SymbolRef as keys.
719
+ template <>
720
+ struct ::llvm::ImutContainerInfo<clang::ento::SymbolRef>
721
+ : public ImutProfileInfo<clang::ento::SymbolRef> {
722
+ using value_type = clang::ento::SymbolRef;
723
+ using value_type_ref = clang::ento::SymbolRef;
724
+ using key_type = value_type;
725
+ using key_type_ref = value_type_ref;
726
+ using data_type = bool ;
727
+ using data_type_ref = bool ;
728
+
729
+ static key_type_ref KeyOfValue (value_type_ref D) { return D; }
730
+ static data_type_ref DataOfValue (value_type_ref) { return true ; }
731
+
732
+ static bool isEqual (clang::ento::SymbolRef LHS, clang::ento::SymbolRef RHS) {
733
+ return LHS->getSymbolID () == RHS->getSymbolID ();
734
+ }
735
+
736
+ static bool isLess (clang::ento::SymbolRef LHS, clang::ento::SymbolRef RHS) {
737
+ return LHS->getSymbolID () < RHS->getSymbolID ();
738
+ }
739
+
740
+ // This might seem redundant, but it is required because of the way
741
+ // ImmutableSet is implemented through AVLTree:
742
+ // same as ImmutableMap, but with a non-informative "data".
743
+ static bool isDataEqual (data_type_ref, data_type_ref) { return true ; }
744
+ };
745
+
690
746
#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H
0 commit comments