1515#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H
1616
1717#include " clang/AST/Expr.h"
18+ #include " clang/AST/OperationKinds.h"
1819#include " clang/AST/Type.h"
1920#include " clang/Analysis/AnalysisDeclContext.h"
2021#include " clang/Basic/LLVM.h"
22+ #include " clang/StaticAnalyzer/Core/AnalyzerOptions.h"
2123#include " clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h"
2224#include " clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
2325#include " clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
2628#include " llvm/ADT/DenseSet.h"
2729#include " llvm/ADT/FoldingSet.h"
2830#include " llvm/ADT/ImmutableSet.h"
31+ #include " llvm/ADT/STLExtras.h"
2932#include " llvm/ADT/iterator_range.h"
3033#include " llvm/Support/Allocator.h"
3134#include < cassert>
35+ #include < type_traits>
3236
3337namespace clang {
3438
@@ -133,6 +137,47 @@ class SymbolConjured : public SymbolData {
133137 static constexpr bool classof (Kind K) { return K == ClassKind; }
134138};
135139
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+
136181// / A symbol representing the value of a MemRegion whose parent region has
137182// / symbolic value.
138183class SymbolDerived : public SymbolData {
@@ -285,6 +330,7 @@ class SymbolMetadata : public SymbolData {
285330
286331// / Represents a cast expression.
287332class SymbolCast : public SymExpr {
333+ friend class SymbolManager ;
288334 const SymExpr *Operand;
289335
290336 // / Type of the operand.
@@ -295,20 +341,19 @@ class SymbolCast : public SymExpr {
295341
296342 friend class SymExprAllocator ;
297343 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) {
299346 assert (In);
300347 assert (isValidTypeForSymbol (From));
301348 // FIXME: GenericTaintChecker creates symbols of void type.
302349 // Otherwise, 'To' should also be a valid type.
303350 }
304351
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 ;
310354 }
311355
356+ public:
312357 QualType getType () const override { return ToTy; }
313358
314359 LLVM_ATTRIBUTE_RETURNS_NONNULL
@@ -336,14 +381,16 @@ class SymbolCast : public SymExpr {
336381
337382// / Represents a symbolic expression involving a unary operator.
338383class UnarySymExpr : public SymExpr {
384+ friend class SymbolManager ;
339385 const SymExpr *Operand;
340386 UnaryOperator::Opcode Op;
341387 QualType T;
342388
343389 friend class SymExprAllocator ;
344390 UnarySymExpr (SymbolID Sym, const SymExpr *In, UnaryOperator::Opcode Op,
345391 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) {
347394 // Note, some unary operators are modeled as a binary operator. E.g. ++x is
348395 // modeled as x + 1.
349396 assert ((Op == UO_Minus || Op == UO_Not) && " non-supported unary expression" );
@@ -354,13 +401,12 @@ class UnarySymExpr : public SymExpr {
354401 assert (!Loc::isLocType (T) && " unary symbol should be nonloc" );
355402 }
356403
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 ;
362407 }
363408
409+ public:
364410 const SymExpr *getOperand () const { return Operand; }
365411 UnaryOperator::Opcode getOpcode () const { return Op; }
366412 QualType getType () const override { return T; }
@@ -391,8 +437,9 @@ class BinarySymExpr : public SymExpr {
391437 QualType T;
392438
393439protected:
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) {
396443 assert (classof (this ));
397444 // Binary expressions are results of arithmetic. Pointer arithmetic is not
398445 // handled by binary expressions, but it is instead handled by applying
@@ -415,7 +462,7 @@ class BinarySymExpr : public SymExpr {
415462
416463protected:
417464 static unsigned computeOperandComplexity (const SymExpr *Value) {
418- return Value->computeComplexity ();
465+ return Value->complexity ();
419466 }
420467 static unsigned computeOperandComplexity (const llvm::APSInt &Value) {
421468 return 1 ;
@@ -432,17 +479,26 @@ class BinarySymExpr : public SymExpr {
432479// / Template implementation for all binary symbolic expressions
433480template <class LHSTYPE , class RHSTYPE , SymExpr::Kind ClassK>
434481class BinarySymExprImpl : public BinarySymExpr {
482+ friend class SymbolManager ;
435483 LHSTYPE LHS;
436484 RHSTYPE RHS;
437485
438486 friend class SymExprAllocator ;
439487 BinarySymExprImpl (SymbolID Sym, LHSTYPE lhs, BinaryOperator::Opcode op,
440488 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) {
442492 assert (getPointer (lhs));
443493 assert (getPointer (rhs));
444494 }
445495
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+
446502public:
447503 void dumpToStream (raw_ostream &os) const override {
448504 dumpToStreamImpl (os, LHS);
@@ -453,13 +509,6 @@ class BinarySymExprImpl : public BinarySymExpr {
453509 LHSTYPE getLHS () const { return LHS; }
454510 RHSTYPE getRHS () const { return RHS; }
455511
456- unsigned computeComplexity () const override {
457- if (Complexity == 0 )
458- Complexity =
459- computeOperandComplexity (RHS) + computeOperandComplexity (LHS);
460- return Complexity;
461- }
462-
463512 static void Profile (llvm::FoldingSetNodeID &ID, LHSTYPE lhs,
464513 BinaryOperator::Opcode op, RHSTYPE rhs, QualType t) {
465514 ID.AddInteger ((unsigned )ClassKind);
@@ -520,27 +569,30 @@ class SymbolManager {
520569 SymExprAllocator Alloc;
521570 BasicValueFactory &BV;
522571 ASTContext &Ctx;
572+ const unsigned MaxCompComplexity;
523573
524574public:
525575 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+ }
528581
529582 static bool canSymbolicate (QualType T);
530583
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.
532585 // / Use the arguments to check for an existing SymExpr and return it,
533586 // / 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);
536591
537592 const SymbolConjured *conjureSymbol (ConstCFGElementRef Elem,
538593 const LocationContext *LCtx, QualType T,
539594 unsigned VisitCount,
540- const void *SymbolTag = nullptr ) {
541-
542- return acquire<SymbolConjured>(Elem, LCtx, T, VisitCount, SymbolTag);
543- }
595+ const void *SymbolTag = nullptr );
544596
545597 QualType getType (const SymExpr *SE) const {
546598 return SE->getType ();
@@ -673,17 +725,22 @@ class SymbolVisitor {
673725 virtual bool VisitMemRegion (const MemRegion *) { return true ; }
674726};
675727
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) {
678731 llvm::FoldingSetNodeID profile;
679732 T::Profile (profile, args...);
680733 void *InsertPos;
681734 SymExpr *SD = DataSet.FindNodeOrInsertPos (profile, InsertPos);
682735 if (!SD) {
683736 SD = Alloc.make <T>(std::forward<Args>(args)...);
684737 DataSet.InsertNode (SD, InsertPos);
738+ if (SD->complexity () > MaxCompComplexity) {
739+ return cast<Ret>(acquire<SymbolOverlyComplex>(SD));
740+ }
685741 }
686- return cast<T>(SD);
742+
743+ return cast<Ret>(SD);
687744}
688745
689746} // namespace ento
0 commit comments