15
15
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H
16
16
17
17
#include " clang/AST/Expr.h"
18
+ #include " clang/AST/OperationKinds.h"
18
19
#include " clang/AST/Type.h"
19
20
#include " clang/Analysis/AnalysisDeclContext.h"
20
21
#include " clang/Basic/LLVM.h"
22
+ #include " clang/StaticAnalyzer/Core/AnalyzerOptions.h"
21
23
#include " clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h"
22
24
#include " clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
23
25
#include " clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
26
28
#include " llvm/ADT/DenseSet.h"
27
29
#include " llvm/ADT/FoldingSet.h"
28
30
#include " llvm/ADT/ImmutableSet.h"
31
+ #include " llvm/ADT/STLExtras.h"
29
32
#include " llvm/ADT/iterator_range.h"
30
33
#include " llvm/Support/Allocator.h"
31
34
#include < cassert>
35
+ #include < type_traits>
32
36
33
37
namespace clang {
34
38
@@ -133,6 +137,47 @@ class SymbolConjured : public SymbolData {
133
137
static constexpr bool classof (Kind K) { return K == ClassKind; }
134
138
};
135
139
140
+ // / A symbol representing the result of an expression that became too
141
+ // / complicated. In other words, its complexity surpassed the
142
+ // / MaxSymbolComplexity threshold.
143
+ // / TODO: When the MaxSymbolComplexity is reached, we should propagate the taint
144
+ // / info to it.
145
+ class SymbolOverlyComplex final : public SymbolData {
146
+ const SymExpr *OverlyComplicatedSymbol;
147
+
148
+ friend class SymExprAllocator ;
149
+
150
+ SymbolOverlyComplex (SymbolID Sym, const SymExpr *OverlyComplicatedSymbol)
151
+ : SymbolData(ClassKind, Sym),
152
+ OverlyComplicatedSymbol (OverlyComplicatedSymbol) {
153
+ assert (OverlyComplicatedSymbol);
154
+ }
155
+
156
+ public:
157
+ QualType getType () const override {
158
+ return OverlyComplicatedSymbol->getType ();
159
+ }
160
+
161
+ StringRef getKindStr () const override ;
162
+
163
+ void dumpToStream (raw_ostream &os) const override ;
164
+
165
+ static void Profile (llvm::FoldingSetNodeID &profile,
166
+ const SymExpr *OverlyComplicatedSymbol) {
167
+ profile.AddInteger ((unsigned )ClassKind);
168
+ profile.AddPointer (OverlyComplicatedSymbol);
169
+ }
170
+
171
+ void Profile (llvm::FoldingSetNodeID &profile) override {
172
+ Profile (profile, OverlyComplicatedSymbol);
173
+ }
174
+
175
+ // Implement isa<T> support.
176
+ static constexpr Kind ClassKind = SymbolOverlyComplexKind;
177
+ static bool classof (const SymExpr *SE) { return classof (SE->getKind ()); }
178
+ static constexpr bool classof (Kind K) { return K == ClassKind; }
179
+ };
180
+
136
181
// / A symbol representing the value of a MemRegion whose parent region has
137
182
// / symbolic value.
138
183
class SymbolDerived : public SymbolData {
@@ -285,6 +330,7 @@ class SymbolMetadata : public SymbolData {
285
330
286
331
// / Represents a cast expression.
287
332
class SymbolCast : public SymExpr {
333
+ friend class SymbolManager ;
288
334
const SymExpr *Operand;
289
335
290
336
// / Type of the operand.
@@ -295,20 +341,19 @@ class SymbolCast : public SymExpr {
295
341
296
342
friend class SymExprAllocator ;
297
343
SymbolCast (SymbolID Sym, const SymExpr *In, QualType From, QualType To)
298
- : SymExpr(ClassKind, Sym), Operand(In), FromTy(From), ToTy(To) {
344
+ : SymExpr(ClassKind, Sym, computeComplexity(In, From, To)), Operand(In),
345
+ FromTy (From), ToTy(To) {
299
346
assert (In);
300
347
assert (isValidTypeForSymbol (From));
301
348
// FIXME: GenericTaintChecker creates symbols of void type.
302
349
// Otherwise, 'To' should also be a valid type.
303
350
}
304
351
305
- public:
306
- unsigned computeComplexity () const override {
307
- if (Complexity == 0 )
308
- Complexity = 1 + Operand->computeComplexity ();
309
- return Complexity;
352
+ static unsigned computeComplexity (const SymExpr *In, QualType, QualType) {
353
+ return In->complexity () + 1 ;
310
354
}
311
355
356
+ public:
312
357
QualType getType () const override { return ToTy; }
313
358
314
359
LLVM_ATTRIBUTE_RETURNS_NONNULL
@@ -336,14 +381,16 @@ class SymbolCast : public SymExpr {
336
381
337
382
// / Represents a symbolic expression involving a unary operator.
338
383
class UnarySymExpr : public SymExpr {
384
+ friend class SymbolManager ;
339
385
const SymExpr *Operand;
340
386
UnaryOperator::Opcode Op;
341
387
QualType T;
342
388
343
389
friend class SymExprAllocator ;
344
390
UnarySymExpr (SymbolID Sym, const SymExpr *In, UnaryOperator::Opcode Op,
345
391
QualType T)
346
- : SymExpr(ClassKind, Sym), Operand(In), Op(Op), T(T) {
392
+ : SymExpr(ClassKind, Sym, computeComplexity(In, Op, T)), Operand(In),
393
+ Op (Op), T(T) {
347
394
// Note, some unary operators are modeled as a binary operator. E.g. ++x is
348
395
// modeled as x + 1.
349
396
assert ((Op == UO_Minus || Op == UO_Not) && " non-supported unary expression" );
@@ -354,13 +401,12 @@ class UnarySymExpr : public SymExpr {
354
401
assert (!Loc::isLocType (T) && " unary symbol should be nonloc" );
355
402
}
356
403
357
- public:
358
- unsigned computeComplexity () const override {
359
- if (Complexity == 0 )
360
- Complexity = 1 + Operand->computeComplexity ();
361
- return Complexity;
404
+ static unsigned computeComplexity (const SymExpr *In, UnaryOperator::Opcode,
405
+ QualType) {
406
+ return In->complexity () + 1 ;
362
407
}
363
408
409
+ public:
364
410
const SymExpr *getOperand () const { return Operand; }
365
411
UnaryOperator::Opcode getOpcode () const { return Op; }
366
412
QualType getType () const override { return T; }
@@ -391,8 +437,9 @@ class BinarySymExpr : public SymExpr {
391
437
QualType T;
392
438
393
439
protected:
394
- BinarySymExpr (SymbolID Sym, Kind k, BinaryOperator::Opcode op, QualType t)
395
- : SymExpr(k, Sym), Op(op), T(t) {
440
+ BinarySymExpr (SymbolID Sym, Kind k, BinaryOperator::Opcode op, QualType t,
441
+ unsigned Complexity)
442
+ : SymExpr(k, Sym, Complexity), Op(op), T(t) {
396
443
assert (classof (this ));
397
444
// Binary expressions are results of arithmetic. Pointer arithmetic is not
398
445
// handled by binary expressions, but it is instead handled by applying
@@ -415,7 +462,7 @@ class BinarySymExpr : public SymExpr {
415
462
416
463
protected:
417
464
static unsigned computeOperandComplexity (const SymExpr *Value) {
418
- return Value->computeComplexity ();
465
+ return Value->complexity ();
419
466
}
420
467
static unsigned computeOperandComplexity (const llvm::APSInt &Value) {
421
468
return 1 ;
@@ -432,17 +479,26 @@ class BinarySymExpr : public SymExpr {
432
479
// / Template implementation for all binary symbolic expressions
433
480
template <class LHSTYPE , class RHSTYPE , SymExpr::Kind ClassK>
434
481
class BinarySymExprImpl : public BinarySymExpr {
482
+ friend class SymbolManager ;
435
483
LHSTYPE LHS;
436
484
RHSTYPE RHS;
437
485
438
486
friend class SymExprAllocator ;
439
487
BinarySymExprImpl (SymbolID Sym, LHSTYPE lhs, BinaryOperator::Opcode op,
440
488
RHSTYPE rhs, QualType t)
441
- : BinarySymExpr(Sym, ClassKind, op, t), LHS(lhs), RHS(rhs) {
489
+ : BinarySymExpr(Sym, ClassKind, op, t,
490
+ computeComplexity (lhs, op, rhs, t)),
491
+ LHS(lhs), RHS(rhs) {
442
492
assert (getPointer (lhs));
443
493
assert (getPointer (rhs));
444
494
}
445
495
496
+ static unsigned computeComplexity (LHSTYPE lhs, BinaryOperator::Opcode,
497
+ RHSTYPE rhs, QualType) {
498
+ // FIXME: Should we add 1 to complexity?
499
+ return computeOperandComplexity (lhs) + computeOperandComplexity (rhs);
500
+ }
501
+
446
502
public:
447
503
void dumpToStream (raw_ostream &os) const override {
448
504
dumpToStreamImpl (os, LHS);
@@ -453,13 +509,6 @@ class BinarySymExprImpl : public BinarySymExpr {
453
509
LHSTYPE getLHS () const { return LHS; }
454
510
RHSTYPE getRHS () const { return RHS; }
455
511
456
- unsigned computeComplexity () const override {
457
- if (Complexity == 0 )
458
- Complexity =
459
- computeOperandComplexity (RHS) + computeOperandComplexity (LHS);
460
- return Complexity;
461
- }
462
-
463
512
static void Profile (llvm::FoldingSetNodeID &ID, LHSTYPE lhs,
464
513
BinaryOperator::Opcode op, RHSTYPE rhs, QualType t) {
465
514
ID.AddInteger ((unsigned )ClassKind);
@@ -520,27 +569,30 @@ class SymbolManager {
520
569
SymExprAllocator Alloc;
521
570
BasicValueFactory &BV;
522
571
ASTContext &Ctx;
572
+ const unsigned MaxCompComplexity;
523
573
524
574
public:
525
575
SymbolManager (ASTContext &ctx, BasicValueFactory &bv,
526
- llvm::BumpPtrAllocator &bpalloc)
527
- : SymbolDependencies(16 ), Alloc(bpalloc), BV(bv), Ctx(ctx) {}
576
+ llvm::BumpPtrAllocator &bpalloc, const AnalyzerOptions &Opts)
577
+ : SymbolDependencies(16 ), Alloc(bpalloc), BV(bv), Ctx(ctx),
578
+ MaxCompComplexity (Opts.MaxSymbolComplexity) {
579
+ assert (MaxCompComplexity > 0 && " Zero max complexity doesn't make sense" );
580
+ }
528
581
529
582
static bool canSymbolicate (QualType T);
530
583
531
- // / Create or retrieve a SymExpr of type \p SymExprT for the given arguments.
584
+ // / Create or retrieve a SymExpr of type \p T for the given arguments.
532
585
// / Use the arguments to check for an existing SymExpr and return it,
533
586
// / otherwise, create a new one and keep a pointer to it to avoid duplicates.
534
- template <typename SymExprT, typename ... Args>
535
- const SymExprT *acquire (Args &&...args);
587
+ template <typename T, typename ... Args,
588
+ typename Ret = std::conditional_t <SymbolData::classof(T::ClassKind),
589
+ T, SymExpr>>
590
+ LLVM_ATTRIBUTE_RETURNS_NONNULL const Ret *acquire (Args &&...args);
536
591
537
592
const SymbolConjured *conjureSymbol (ConstCFGElementRef Elem,
538
593
const LocationContext *LCtx, QualType T,
539
594
unsigned VisitCount,
540
- const void *SymbolTag = nullptr ) {
541
-
542
- return acquire<SymbolConjured>(Elem, LCtx, T, VisitCount, SymbolTag);
543
- }
595
+ const void *SymbolTag = nullptr );
544
596
545
597
QualType getType (const SymExpr *SE) const {
546
598
return SE->getType ();
@@ -673,17 +725,22 @@ class SymbolVisitor {
673
725
virtual bool VisitMemRegion (const MemRegion *) { return true ; }
674
726
};
675
727
676
- template <typename T, typename ... Args>
677
- const T *SymbolManager::acquire (Args &&...args) {
728
+ // Returns a const pointer to T if T is a SymbolData, otherwise SymExpr.
729
+ template <typename T, typename ... Args, typename Ret>
730
+ const Ret *SymbolManager::acquire (Args &&...args) {
678
731
llvm::FoldingSetNodeID profile;
679
732
T::Profile (profile, args...);
680
733
void *InsertPos;
681
734
SymExpr *SD = DataSet.FindNodeOrInsertPos (profile, InsertPos);
682
735
if (!SD) {
683
736
SD = Alloc.make <T>(std::forward<Args>(args)...);
684
737
DataSet.InsertNode (SD, InsertPos);
738
+ if (SD->complexity () > MaxCompComplexity) {
739
+ return cast<Ret>(acquire<SymbolOverlyComplex>(SD));
740
+ }
685
741
}
686
- return cast<T>(SD);
742
+
743
+ return cast<Ret>(SD);
687
744
}
688
745
689
746
} // namespace ento
0 commit comments