diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h index a7ff38c786a8f..e70c70335e597 100644 --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -122,7 +122,8 @@ class CFGElement { return (Kind) x; } - void dumpToStream(llvm::raw_ostream &OS) const; + void dumpToStream(llvm::raw_ostream &OS, + bool TerminateWithNewLine = true) const; void dump() const { dumpToStream(llvm::errs()); @@ -695,6 +696,11 @@ class CFGBlock { void dump() const { dumpToStream(llvm::errs()); } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(Parent); + ID.AddInteger(Index); + } }; template class ElementRefIterator { @@ -1190,6 +1196,8 @@ class CFGBlock { } }; +using ConstCFGElementRef = CFGBlock::ConstCFGElementRef; + /// CFGCallback defines methods that should be called when a logical /// operator error is found when building the CFG. class CFGCallback { diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h index 519d2d5b3676b..6c1025ecc7f4d 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h +++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h @@ -19,6 +19,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" namespace clang { @@ -29,6 +30,13 @@ class SValExplainer : public FullSValVisitor { ASTContext &ACtx; ProgramStateRef State; + std::string printCFGElementRef(ConstCFGElementRef Elem) { + std::string Str; + llvm::raw_string_ostream OS(Str); + Elem->dumpToStream(OS, /*TerminateWithNewLine=*/false); + return Str; + } + std::string printStmt(const Stmt *S) { std::string Str; llvm::raw_string_ostream OS(Str); @@ -114,7 +122,8 @@ class SValExplainer : public FullSValVisitor { std::string VisitSymbolConjured(const SymbolConjured *S) { return "symbol of type '" + S->getType().getAsString() + - "' conjured at statement '" + printStmt(S->getStmt()) + "'"; + "' conjured at CFG element '" + + printCFGElementRef(S->getCFGElementRef()) + "'"; } std::string VisitSymbolDerived(const SymbolDerived *S) { diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index bb33a6912bec7..63ca3efc6d228 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -151,6 +151,8 @@ class CheckerContext { return Pred->getSVal(S); } + ConstCFGElementRef getCFGElementRef() const { return Eng.getCFGElementRef(); } + /// Returns true if the value of \p E is greater than or equal to \p /// Val under unsigned comparison. bool isGreaterOrEqual(const Expr *E, unsigned long long Val); diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 5f855251b3cde..285194148d3d3 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -226,7 +226,7 @@ class ExprEngine { return (*G.roots_begin())->getLocation().getLocationContext(); } - CFGBlock::ConstCFGElementRef getCFGElementRef() const { + ConstCFGElementRef getCFGElementRef() const { const CFGBlock *blockPtr = currBldrCtx ? currBldrCtx->getBlock() : nullptr; return {blockPtr, currStmtIdx}; } diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h index e75228f92a8e5..50f2197b8a174 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h @@ -27,7 +27,8 @@ namespace ento { /// by the loop body in any iteration. ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, const LocationContext *LCtx, - unsigned BlockCount, const Stmt *LoopStmt); + unsigned BlockCount, + ConstCFGElementRef Elem); } // end namespace ento } // end namespace clang diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 4d66e086a2c2c..52714535e7907 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -313,7 +313,7 @@ class ProgramState : public llvm::FoldingSetNode { /// be triggered by this event. /// /// \param Regions the set of regions to be invalidated. - /// \param E the expression that caused the invalidation. + /// \param Elem The CFG Element that caused the invalidation. /// \param BlockCount The number of times the current basic block has been /// visited. /// \param CausesPointerEscape the flag is set to true when the invalidation @@ -325,16 +325,17 @@ class ProgramState : public llvm::FoldingSetNode { /// \param ITraits information about special handling for particular regions /// or symbols. [[nodiscard]] ProgramStateRef - invalidateRegions(ArrayRef Regions, const Stmt *S, - unsigned BlockCount, const LocationContext *LCtx, - bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr, + invalidateRegions(ArrayRef Regions, + ConstCFGElementRef Elem, unsigned BlockCount, + const LocationContext *LCtx, bool CausesPointerEscape, + InvalidatedSymbols *IS = nullptr, const CallEvent *Call = nullptr, RegionAndSymbolInvalidationTraits *ITraits = nullptr) const; [[nodiscard]] ProgramStateRef - invalidateRegions(ArrayRef Values, const Stmt *S, unsigned BlockCount, - const LocationContext *LCtx, bool CausesPointerEscape, - InvalidatedSymbols *IS = nullptr, + invalidateRegions(ArrayRef Values, ConstCFGElementRef Elem, + unsigned BlockCount, const LocationContext *LCtx, + bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr, const CallEvent *Call = nullptr, RegionAndSymbolInvalidationTraits *ITraits = nullptr) const; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index 54430d426a82a..bd5d245645788 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -19,6 +19,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/Type.h" +#include "clang/Analysis/CFG.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" @@ -171,19 +172,11 @@ class SValBuilder { // Forwarding methods to SymbolManager. - const SymbolConjured* conjureSymbol(const Stmt *stmt, + const SymbolConjured *conjureSymbol(ConstCFGElementRef Elem, const LocationContext *LCtx, - QualType type, - unsigned visitCount, + QualType type, unsigned visitCount, const void *symbolTag = nullptr) { - return SymMgr.conjureSymbol(stmt, LCtx, type, visitCount, symbolTag); - } - - const SymbolConjured* conjureSymbol(const Expr *expr, - const LocationContext *LCtx, - unsigned visitCount, - const void *symbolTag = nullptr) { - return SymMgr.conjureSymbol(expr, LCtx, visitCount, symbolTag); + return SymMgr.conjureSymbol(Elem, LCtx, type, visitCount, symbolTag); } /// Construct an SVal representing '0' for the specified type. @@ -199,29 +192,19 @@ class SValBuilder { /// preserve the relation between related(or even equivalent) expressions, so /// conjured symbols should be used sparingly. DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, - const Expr *expr, + ConstCFGElementRef elem, const LocationContext *LCtx, unsigned count); - DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Stmt *S, + DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, + ConstCFGElementRef elem, const LocationContext *LCtx, QualType type, unsigned count); - DefinedOrUnknownSVal conjureSymbolVal(const Stmt *stmt, + DefinedOrUnknownSVal conjureSymbolVal(ConstCFGElementRef elem, const LocationContext *LCtx, - QualType type, - unsigned visitCount); + QualType type, unsigned visitCount); /// Conjure a symbol representing heap allocated memory region. - /// - /// Note, the expression should represent a location. - DefinedSVal getConjuredHeapSymbolVal(const Expr *E, - const LocationContext *LCtx, - unsigned Count); - - /// Conjure a symbol representing heap allocated memory region. - /// - /// Note, now, the expression *doesn't* need to represent a location. - /// But the type need to! - DefinedSVal getConjuredHeapSymbolVal(const Expr *E, + DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem, const LocationContext *LCtx, QualType type, unsigned Count); diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index cf7623c7be409..29a53fcc9e28d 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -14,13 +14,13 @@ #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H #include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" -#include "clang/Basic/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" @@ -223,7 +223,7 @@ class StoreManager { /// /// \param[in] store The initial store. /// \param[in] Values The values to invalidate. - /// \param[in] S The current statement being evaluated. Used to conjure + /// \param[in] Elem The current CFG Element being evaluated. Used to conjure /// symbols to mark the values of invalidated regions. /// \param[in] Count The current block count. Used to conjure /// symbols to mark the values of invalidated regions. @@ -241,8 +241,8 @@ class StoreManager { /// even if they do not currently have bindings. Pass \c NULL if this /// information will not be used. virtual StoreRef invalidateRegions( - Store store, ArrayRef Values, const Stmt *S, unsigned Count, - const LocationContext *LCtx, const CallEvent *Call, + Store store, ArrayRef Values, ConstCFGElementRef Elem, + unsigned Count, const LocationContext *LCtx, const CallEvent *Call, InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits, InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated) = 0; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index cbbea1b56bb40..9e7c98fdded17 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -80,29 +80,62 @@ class SymbolRegionValue : public SymbolData { /// A symbol representing the result of an expression in the case when we do /// not know anything about what the expression is. class SymbolConjured : public SymbolData { - const Stmt *S; + ConstCFGElementRef Elem; QualType T; unsigned Count; const LocationContext *LCtx; const void *SymbolTag; friend class SymExprAllocator; - SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx, - QualType t, unsigned count, const void *symbolTag) - : SymbolData(SymbolConjuredKind, sym), S(s), T(t), Count(count), + SymbolConjured(SymbolID sym, ConstCFGElementRef elem, + const LocationContext *lctx, QualType t, unsigned count, + const void *symbolTag) + : SymbolData(SymbolConjuredKind, sym), Elem(elem), T(t), Count(count), LCtx(lctx), SymbolTag(symbolTag) { - // FIXME: 's' might be a nullptr if we're conducting invalidation - // that was caused by a destructor call on a temporary object, - // which has no statement associated with it. - // Due to this, we might be creating the same invalidation symbol for - // two different invalidation passes (for two different temporaries). assert(lctx); assert(isValidTypeForSymbol(t)); } public: - /// It might return null. - const Stmt *getStmt() const { return S; } + ConstCFGElementRef getCFGElementRef() const { return Elem; } + + // It might return null. + const Stmt *getStmt() const { + switch (Elem->getKind()) { + case CFGElement::Initializer: + return Elem->castAs().getInitializer()->getInit(); + case CFGElement::ScopeBegin: + return Elem->castAs().getTriggerStmt(); + case CFGElement::ScopeEnd: + return Elem->castAs().getTriggerStmt(); + case CFGElement::NewAllocator: + return Elem->castAs().getAllocatorExpr(); + case CFGElement::LifetimeEnds: + return Elem->castAs().getTriggerStmt(); + case CFGElement::LoopExit: + return Elem->castAs().getLoopStmt(); + case CFGElement::Statement: + return Elem->castAs().getStmt(); + case CFGElement::Constructor: + return Elem->castAs().getStmt(); + case CFGElement::CXXRecordTypedCall: + return Elem->castAs().getStmt(); + case CFGElement::AutomaticObjectDtor: + return Elem->castAs().getTriggerStmt(); + case CFGElement::DeleteDtor: + return Elem->castAs().getDeleteExpr(); + case CFGElement::BaseDtor: + return nullptr; + case CFGElement::MemberDtor: + return nullptr; + case CFGElement::TemporaryDtor: + return Elem->castAs().getBindTemporaryExpr(); + case CFGElement::CleanupFunction: + return nullptr; + } + return nullptr; + } + unsigned getCount() const { return Count; } /// It might return null. const void *getTag() const { return SymbolTag; } @@ -113,11 +146,11 @@ class SymbolConjured : public SymbolData { void dumpToStream(raw_ostream &os) const override; - static void Profile(llvm::FoldingSetNodeID &profile, const Stmt *S, + static void Profile(llvm::FoldingSetNodeID &profile, ConstCFGElementRef Elem, const LocationContext *LCtx, QualType T, unsigned Count, const void *SymbolTag) { profile.AddInteger((unsigned)SymbolConjuredKind); - profile.AddPointer(S); + profile.Add(Elem); profile.AddPointer(LCtx); profile.Add(T); profile.AddInteger(Count); @@ -125,7 +158,7 @@ class SymbolConjured : public SymbolData { } void Profile(llvm::FoldingSetNodeID& profile) override { - Profile(profile, S, LCtx, T, Count, SymbolTag); + Profile(profile, Elem, LCtx, T, Count, SymbolTag); } // Implement isa support. @@ -533,18 +566,12 @@ class SymbolManager { template const SymExprT *acquire(Args &&...args); - const SymbolConjured *conjureSymbol(const Stmt *E, + const SymbolConjured *conjureSymbol(ConstCFGElementRef Elem, const LocationContext *LCtx, QualType T, unsigned VisitCount, const void *SymbolTag = nullptr) { - return acquire(E, LCtx, T, VisitCount, SymbolTag); - } - const SymbolConjured* conjureSymbol(const Expr *E, - const LocationContext *LCtx, - unsigned VisitCount, - const void *SymbolTag = nullptr) { - return conjureSymbol(E, LCtx, E->getType(), VisitCount, SymbolTag); + return acquire(Elem, LCtx, T, VisitCount, SymbolTag); } QualType getType(const SymExpr *SE) const { diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 9af1e915482da..962d8781dc322 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -5803,16 +5803,17 @@ static void print_construction_context(raw_ostream &OS, } static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, - const CFGElement &E); + const CFGElement &E, bool TerminateWithNewLine = true); -void CFGElement::dumpToStream(llvm::raw_ostream &OS) const { +void CFGElement::dumpToStream(llvm::raw_ostream &OS, + bool TerminateWithNewLine) const { LangOptions LangOpts; StmtPrinterHelper Helper(nullptr, LangOpts); - print_elem(OS, Helper, *this); + print_elem(OS, Helper, *this, TerminateWithNewLine); } static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, - const CFGElement &E) { + const CFGElement &E, bool TerminateWithNewLine) { switch (E.getKind()) { case CFGElement::Kind::Statement: case CFGElement::Kind::CXXRecordTypedCall: @@ -5829,7 +5830,9 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, if (Children.begin() != Children.end()) { OS << "({ ... ; "; Helper.handledStmt(*SE->getSubStmt()->body_rbegin(),OS); - OS << " })\n"; + OS << " })"; + if (TerminateWithNewLine) + OS << '\n'; return; } } @@ -5838,7 +5841,8 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, if (B->getOpcode() == BO_Comma) { OS << "... , "; Helper.handledStmt(B->getRHS(),OS); - OS << '\n'; + if (TerminateWithNewLine) + OS << '\n'; return; } } @@ -5866,15 +5870,14 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, } // Expressions need a newline. - if (isa(S)) + if (isa(S) && TerminateWithNewLine) OS << '\n'; - break; + return; } case CFGElement::Kind::Initializer: print_initializer(OS, Helper, E.castAs().getInitializer()); - OS << '\n'; break; case CFGElement::Kind::AutomaticObjectDtor: { @@ -5888,43 +5891,44 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, OS << ".~"; T.getUnqualifiedType().print(OS, PrintingPolicy(Helper.getLangOpts())); - OS << "() (Implicit destructor)\n"; + OS << "() (Implicit destructor)"; break; } case CFGElement::Kind::CleanupFunction: OS << "CleanupFunction (" - << E.castAs().getFunctionDecl()->getName() << ")\n"; + << E.castAs().getFunctionDecl()->getName() << ")"; break; case CFGElement::Kind::LifetimeEnds: Helper.handleDecl(E.castAs().getVarDecl(), OS); - OS << " (Lifetime ends)\n"; + OS << " (Lifetime ends)"; break; case CFGElement::Kind::LoopExit: - OS << E.castAs().getLoopStmt()->getStmtClassName() << " (LoopExit)\n"; + OS << E.castAs().getLoopStmt()->getStmtClassName() + << " (LoopExit)"; break; case CFGElement::Kind::ScopeBegin: OS << "CFGScopeBegin("; if (const VarDecl *VD = E.castAs().getVarDecl()) OS << VD->getQualifiedNameAsString(); - OS << ")\n"; + OS << ")"; break; case CFGElement::Kind::ScopeEnd: OS << "CFGScopeEnd("; if (const VarDecl *VD = E.castAs().getVarDecl()) OS << VD->getQualifiedNameAsString(); - OS << ")\n"; + OS << ")"; break; case CFGElement::Kind::NewAllocator: OS << "CFGNewAllocator("; if (const CXXNewExpr *AllocExpr = E.castAs().getAllocatorExpr()) AllocExpr->getType().print(OS, PrintingPolicy(Helper.getLangOpts())); - OS << ")\n"; + OS << ")"; break; case CFGElement::Kind::DeleteDtor: { @@ -5936,14 +5940,14 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, const_cast(DE.getDeleteExpr()); Helper.handledStmt(cast(DelExpr->getArgument()), OS); OS << "->~" << RD->getName().str() << "()"; - OS << " (Implicit destructor)\n"; + OS << " (Implicit destructor)"; break; } case CFGElement::Kind::BaseDtor: { const CXXBaseSpecifier *BS = E.castAs().getBaseSpecifier(); OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()"; - OS << " (Base object destructor)\n"; + OS << " (Base object destructor)"; break; } @@ -5952,7 +5956,7 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, const Type *T = FD->getType()->getBaseElementTypeUnsafe(); OS << "this->" << FD->getName(); OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()"; - OS << " (Member object destructor)\n"; + OS << " (Member object destructor)"; break; } @@ -5961,10 +5965,12 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, E.castAs().getBindTemporaryExpr(); OS << "~"; BT->getType().print(OS, PrintingPolicy(Helper.getLangOpts())); - OS << "() (Temporary object destructor)\n"; + OS << "() (Temporary object destructor)"; break; } } + if (TerminateWithNewLine) + OS << '\n'; } static void print_block(raw_ostream &OS, const CFG* cfg, diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 39dcaf02dbe25..49ca39fd4ac3b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -273,28 +273,29 @@ class CStringChecker : public Checker< eval::Call, /// Invalidate the destination buffer determined by characters copied. static ProgramStateRef invalidateDestinationBufferBySize(CheckerContext &C, ProgramStateRef S, - const Expr *BufE, SVal BufV, SVal SizeV, - QualType SizeTy); + const Expr *BufE, ConstCFGElementRef Elem, + SVal BufV, SVal SizeV, QualType SizeTy); /// Operation never overflows, do not invalidate the super region. static ProgramStateRef invalidateDestinationBufferNeverOverflows( - CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV); + CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV); /// We do not know whether the operation can overflow (e.g. size is unknown), /// invalidate the super region and escape related pointers. static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion( - CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV); + CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV); /// Invalidate the source buffer for escaping pointers. static ProgramStateRef invalidateSourceBuffer(CheckerContext &C, ProgramStateRef S, - const Expr *BufE, SVal BufV); + ConstCFGElementRef Elem, + SVal BufV); /// @param InvalidationTraitOperations Determine how to invlidate the /// MemRegion by setting the invalidation traits. Return true to cause pointer /// escape, or false otherwise. static ProgramStateRef invalidateBufferAux( - CheckerContext &C, ProgramStateRef State, const Expr *Ex, SVal V, + CheckerContext &C, ProgramStateRef State, ConstCFGElementRef Elem, SVal V, llvm::function_ref InvalidationTraitOperations); @@ -302,8 +303,8 @@ class CStringChecker : public Checker< eval::Call, static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx, const MemRegion *MR); - static bool memsetAux(const Expr *DstBuffer, SVal CharE, - const Expr *Size, CheckerContext &C, + static bool memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem, + SVal CharE, const Expr *Size, CheckerContext &C, ProgramStateRef &State); // Re-usable checks @@ -1211,8 +1212,8 @@ bool CStringChecker::isFirstBufInBound(CheckerContext &C, ProgramStateRef State, } ProgramStateRef CStringChecker::invalidateDestinationBufferBySize( - CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV, - SVal SizeV, QualType SizeTy) { + CheckerContext &C, ProgramStateRef S, const Expr *BufE, + ConstCFGElementRef Elem, SVal BufV, SVal SizeV, QualType SizeTy) { auto InvalidationTraitOperations = [&C, S, BufTy = BufE->getType(), BufV, SizeV, SizeTy](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) { @@ -1227,22 +1228,22 @@ ProgramStateRef CStringChecker::invalidateDestinationBufferBySize( return false; }; - return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations); + return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations); } ProgramStateRef CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion( - CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV) { + CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV) { auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &, const MemRegion *R) { return isa(R); }; - return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations); + return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations); } ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows( - CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV) { + CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV) { auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) { if (MemRegion::FieldRegionKind == R->getKind()) @@ -1252,12 +1253,12 @@ ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows( return false; }; - return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations); + return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations); } ProgramStateRef CStringChecker::invalidateSourceBuffer(CheckerContext &C, ProgramStateRef S, - const Expr *BufE, + ConstCFGElementRef Elem, SVal BufV) { auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) { @@ -1269,11 +1270,11 @@ ProgramStateRef CStringChecker::invalidateSourceBuffer(CheckerContext &C, return true; }; - return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations); + return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations); } ProgramStateRef CStringChecker::invalidateBufferAux( - CheckerContext &C, ProgramStateRef State, const Expr *E, SVal V, + CheckerContext &C, ProgramStateRef State, ConstCFGElementRef Elem, SVal V, llvm::function_ref InvalidationTraitOperations) { @@ -1299,7 +1300,7 @@ ProgramStateRef CStringChecker::invalidateBufferAux( RegionAndSymbolInvalidationTraits ITraits; bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R); - return State->invalidateRegions(R, E, C.blockCount(), LCtx, + return State->invalidateRegions(R, Elem, C.blockCount(), LCtx, CausesPointerEscape, nullptr, nullptr, &ITraits); } @@ -1349,9 +1350,9 @@ bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, } } -bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal, - const Expr *Size, CheckerContext &C, - ProgramStateRef &State) { +bool CStringChecker::memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem, + SVal CharVal, const Expr *Size, + CheckerContext &C, ProgramStateRef &State) { SVal MemVal = C.getSVal(DstBuffer); SVal SizeVal = C.getSVal(Size); const MemRegion *MR = MemVal.getAsRegion(); @@ -1404,8 +1405,8 @@ bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal, } else { // If the destination buffer's extent is not equal to the value of // third argument, just invalidate buffer. - State = invalidateDestinationBufferBySize(C, State, DstBuffer, MemVal, - SizeVal, Size->getType()); + State = invalidateDestinationBufferBySize( + C, State, DstBuffer, Elem, MemVal, SizeVal, Size->getType()); } if (StateNullChar && !StateNonNullChar) { @@ -1430,7 +1431,7 @@ bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal, } else { // If the offset is not zero and char value is not concrete, we can do // nothing but invalidate the buffer. - State = invalidateDestinationBufferBySize(C, State, DstBuffer, MemVal, + State = invalidateDestinationBufferBySize(C, State, DstBuffer, Elem, MemVal, SizeVal, Size->getType()); } return true; @@ -1515,7 +1516,8 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call, // conjure a return value for later. if (lastElement.isUnknown()) lastElement = C.getSValBuilder().conjureSymbolVal( - nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); + /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, + C.blockCount()); // The byte after the last byte copied is the return value. state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement); @@ -1532,12 +1534,12 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call, // This would probably remove any existing bindings past the end of the // copied region, but that's still an improvement over blank invalidation. state = invalidateDestinationBufferBySize( - C, state, Dest.Expression, C.getSVal(Dest.Expression), sizeVal, - Size.Expression->getType()); + C, state, Dest.Expression, Call.getCFGElementRef(), + C.getSVal(Dest.Expression), sizeVal, Size.Expression->getType()); // Invalidate the source (const-invalidation without const-pointer-escaping // the address of the top-level region). - state = invalidateSourceBuffer(C, state, Source.Expression, + state = invalidateSourceBuffer(C, state, Call.getCFGElementRef(), C.getSVal(Source.Expression)); C.addTransition(state); @@ -1665,8 +1667,8 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call, State = CheckBufferAccess(C, State, Left, Size, AccessKind::read, CK); if (State) { // The return value is the comparison result, which we don't know. - SVal CmpV = Builder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, - C.blockCount()); + SVal CmpV = Builder.conjureSymbolVal( + /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV); C.addTransition(State); } @@ -1770,7 +1772,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, // All we know is the return value is the min of the string length // and the limit. This is better than nothing. result = C.getSValBuilder().conjureSymbolVal( - nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); + /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); NonLoc resultNL = result.castAs(); if (strLengthNL) { @@ -1794,7 +1796,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, // value, so it can be used in constraints, at least. if (result.isUnknown()) { result = C.getSValBuilder().conjureSymbolVal( - nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); + /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); } } @@ -2235,13 +2237,13 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call, // can use LazyCompoundVals to copy the source values into the destination. // This would probably remove any existing bindings past the end of the // string, but that's still an improvement over blank invalidation. - state = invalidateDestinationBufferBySize(C, state, Dst.Expression, - *dstRegVal, amountCopied, - C.getASTContext().getSizeType()); + state = invalidateDestinationBufferBySize( + C, state, Dst.Expression, Call.getCFGElementRef(), *dstRegVal, + amountCopied, C.getASTContext().getSizeType()); // Invalidate the source (const-invalidation without const-pointer-escaping // the address of the top-level region). - state = invalidateSourceBuffer(C, state, srcExpr.Expression, srcVal); + state = invalidateSourceBuffer(C, state, Call.getCFGElementRef(), srcVal); // Set the C string length of the destination, if we know it. if (IsBounded && (appendK == ConcatFnKind::none)) { @@ -2261,8 +2263,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call, // If this is a stpcpy-style copy, but we were unable to check for a buffer // overflow, we still need a result. Conjure a return value. if (ReturnEnd && Result.isUnknown()) { - Result = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, - C.blockCount()); + Result = svalBuilder.conjureSymbolVal( + /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); } } // Set the return value. @@ -2361,8 +2363,8 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallEvent &Call, const StringLiteral *RightStrLiteral = getCStringLiteral(C, state, Right.Expression, RightVal); bool canComputeResult = false; - SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(), - LCtx, C.blockCount()); + SVal resultVal = svalBuilder.conjureSymbolVal( + /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); if (LeftStrLiteral && RightStrLiteral) { StringRef LeftStrRef = LeftStrLiteral->getString(); @@ -2463,20 +2465,20 @@ void CStringChecker::evalStrsep(CheckerContext &C, // character to NUL. // As the replacement never overflows, do not invalidate its super region. State = invalidateDestinationBufferNeverOverflows( - C, State, SearchStrPtr.Expression, Result); + C, State, Call.getCFGElementRef(), Result); // Overwrite the search string pointer. The new value is either an address // further along in the same string, or NULL if there are no more tokens. State = State->bindLoc(*SearchStrLoc, - SVB.conjureSymbolVal(getTag(), Call.getOriginExpr(), + SVB.conjureSymbolVal(getTag(), Call.getCFGElementRef(), LCtx, CharPtrTy, C.blockCount()), LCtx); } else { assert(SearchStrVal.isUnknown()); // Conjure a symbolic value. It's the best we can do. - Result = SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, - C.blockCount()); + Result = SVB.conjureSymbolVal( + /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); } // Set the return value, and finish. @@ -2514,13 +2516,13 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C, SVal DstVal = State->getSVal(Dst, LCtx); // FIXME: As we do not know how many items are copied, we also invalidate the // super region containing the target location. - State = - invalidateDestinationBufferAlwaysEscapeSuperRegion(C, State, Dst, DstVal); + State = invalidateDestinationBufferAlwaysEscapeSuperRegion( + C, State, Call.getCFGElementRef(), DstVal); SValBuilder &SVB = C.getSValBuilder(); - SVal ResultVal = - SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); + SVal ResultVal = SVB.conjureSymbolVal( + /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); State = State->BindExpr(Call.getOriginExpr(), LCtx, ResultVal); C.addTransition(State); @@ -2569,8 +2571,8 @@ void CStringChecker::evalMemset(CheckerContext &C, // According to the values of the arguments, bind the value of the second // argument to the destination buffer and set string length, or just // invalidate the destination buffer. - if (!memsetAux(Buffer.Expression, C.getSVal(CharE.Expression), - Size.Expression, C, State)) + if (!memsetAux(Buffer.Expression, Call.getCFGElementRef(), + C.getSVal(CharE.Expression), Size.Expression, C, State)) return; State = State->BindExpr(Call.getOriginExpr(), LCtx, BufferPtrVal); @@ -2614,7 +2616,8 @@ void CStringChecker::evalBzero(CheckerContext &C, const CallEvent &Call) const { if (!State) return; - if (!memsetAux(Buffer.Expression, Zero, Size.Expression, C, State)) + if (!memsetAux(Buffer.Expression, Call.getCFGElementRef(), Zero, + Size.Expression, C, State)) return; C.addTransition(State); diff --git a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp index d850344db6591..3cc49e408387b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp @@ -33,11 +33,11 @@ namespace { class ContainerModeling : public Checker { - void handleBegin(CheckerContext &C, const Expr *CE, SVal RetVal, + void handleBegin(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, SVal Cont) const; - void handleEnd(CheckerContext &C, const Expr *CE, SVal RetVal, + void handleEnd(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, SVal Cont) const; - void handleAssignment(CheckerContext &C, SVal Cont, const Expr *CE = nullptr, + void handleAssignment(CheckerContext &C, SVal Cont, ConstCFGElementRef Elem, SVal OldCont = UndefinedVal()) const; void handleAssign(CheckerContext &C, SVal Cont, const Expr *ContE) const; void handleClear(CheckerContext &C, SVal Cont, const Expr *ContE) const; @@ -108,11 +108,12 @@ bool backModifiable(ProgramStateRef State, const MemRegion *Reg); SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont); SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont); ProgramStateRef createContainerBegin(ProgramStateRef State, - const MemRegion *Cont, const Expr *E, - QualType T, const LocationContext *LCtx, + const MemRegion *Cont, + ConstCFGElementRef Elem, QualType T, + const LocationContext *LCtx, unsigned BlockCount); ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, - const Expr *E, QualType T, + ConstCFGElementRef Elem, QualType T, const LocationContext *LCtx, unsigned BlockCount); ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, @@ -163,12 +164,12 @@ void ContainerModeling::checkPostCall(const CallEvent &Call, return; if (cast(Func)->isMoveAssignmentOperator()) { - handleAssignment(C, InstCall->getCXXThisVal(), Call.getOriginExpr(), - Call.getArgSVal(0)); + handleAssignment(C, InstCall->getCXXThisVal(), Call.getCFGElementRef(), + Call.getArgSVal(0)); return; } - handleAssignment(C, InstCall->getCXXThisVal()); + handleAssignment(C, InstCall->getCXXThisVal(), C.getCFGElementRef()); return; } } else { @@ -198,13 +199,13 @@ void ContainerModeling::checkPostCall(const CallEvent &Call, return; if (isBeginCall(Func)) { - handleBegin(C, OrigExpr, Call.getReturnValue(), + handleBegin(C, Call.getCFGElementRef(), Call.getReturnValue(), InstCall->getCXXThisVal()); return; } if (isEndCall(Func)) { - handleEnd(C, OrigExpr, Call.getReturnValue(), + handleEnd(C, Call.getCFGElementRef(), Call.getReturnValue(), InstCall->getCXXThisVal()); return; } @@ -250,8 +251,8 @@ void ContainerModeling::checkDeadSymbols(SymbolReaper &SR, C.addTransition(State); } -void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE, - SVal RetVal, SVal Cont) const { +void ContainerModeling::handleBegin(CheckerContext &C, ConstCFGElementRef Elem, + SVal RetVal, SVal Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -263,7 +264,7 @@ void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE, auto State = C.getState(); auto BeginSym = getContainerBegin(State, ContReg); if (!BeginSym) { - State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy, + State = createContainerBegin(State, ContReg, Elem, C.getASTContext().LongTy, C.getLocationContext(), C.blockCount()); BeginSym = getContainerBegin(State, ContReg); } @@ -272,8 +273,8 @@ void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE, C.addTransition(State); } -void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE, - SVal RetVal, SVal Cont) const { +void ContainerModeling::handleEnd(CheckerContext &C, ConstCFGElementRef Elem, + SVal RetVal, SVal Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -285,7 +286,7 @@ void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE, auto State = C.getState(); auto EndSym = getContainerEnd(State, ContReg); if (!EndSym) { - State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy, + State = createContainerEnd(State, ContReg, Elem, C.getASTContext().LongTy, C.getLocationContext(), C.blockCount()); EndSym = getContainerEnd(State, ContReg); } @@ -295,7 +296,8 @@ void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE, } void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont, - const Expr *CE, SVal OldCont) const { + ConstCFGElementRef Elem, + SVal OldCont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -329,7 +331,7 @@ void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont, auto &SVB = C.getSValBuilder(); // Then generate and assign a new "end" symbol for the new container. auto NewEndSym = - SymMgr.conjureSymbol(CE, C.getLocationContext(), + SymMgr.conjureSymbol(Elem, C.getLocationContext(), C.getASTContext().LongTy, C.blockCount()); State = assumeNoOverflow(State, NewEndSym, 4); if (CData) { @@ -848,8 +850,9 @@ SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) { } ProgramStateRef createContainerBegin(ProgramStateRef State, - const MemRegion *Cont, const Expr *E, - QualType T, const LocationContext *LCtx, + const MemRegion *Cont, + ConstCFGElementRef Elem, QualType T, + const LocationContext *LCtx, unsigned BlockCount) { // Only create if it does not exist const auto *CDataPtr = getContainerData(State, Cont); @@ -857,8 +860,8 @@ ProgramStateRef createContainerBegin(ProgramStateRef State, return State; auto &SymMgr = State->getSymbolManager(); - const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, - "begin"); + const SymbolConjured *Sym = + SymMgr.conjureSymbol(Elem, LCtx, T, BlockCount, "begin"); State = assumeNoOverflow(State, Sym, 4); if (CDataPtr) { @@ -871,7 +874,7 @@ ProgramStateRef createContainerBegin(ProgramStateRef State, } ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, - const Expr *E, QualType T, + ConstCFGElementRef Elem, QualType T, const LocationContext *LCtx, unsigned BlockCount) { // Only create if it does not exist @@ -880,8 +883,8 @@ ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, return State; auto &SymMgr = State->getSymbolManager(); - const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, - "end"); + const SymbolConjured *Sym = + SymMgr.conjureSymbol(Elem, LCtx, T, BlockCount, "end"); State = assumeNoOverflow(State, Sym, 4); if (CDataPtr) { diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp index 6ffc05f06742b..abfc5d20d3094 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp @@ -124,7 +124,7 @@ void ErrnoModeling::checkBeginFunction(CheckerContext &C) const { // of the data member `ErrnoDecl` of the singleton `ErrnoModeling` checker // object. const SymbolConjured *Sym = SVB.conjureSymbol( - nullptr, C.getLocationContext(), + C.getCFGElementRef(), C.getLocationContext(), ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl); // The symbolic region is untyped, create a typed sub-region in it. @@ -256,11 +256,11 @@ ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C, ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State, CheckerContext &C, - const Expr *InvalE) { + ConstCFGElementRef Elem) { const MemRegion *ErrnoR = State->get(); if (!ErrnoR) return State; - State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(), + State = State->invalidateRegions(ErrnoR, Elem, C.blockCount(), C.getLocationContext(), false); if (!State) return nullptr; diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h index 95da8a28d3253..e414353322054 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h +++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h @@ -96,9 +96,10 @@ ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C, /// Set errno state for the common case when a standard function indicates /// failure only by \c errno. Sets \c ErrnoCheckState to \c MustBeChecked, and /// invalidates the errno region (clear of previous value). -/// \arg \c InvalE Expression that causes invalidation of \c errno. +/// \arg \c Elem CFG Element that causes invalidation of \c errno. ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State, - CheckerContext &C, const Expr *InvalE); + CheckerContext &C, + ConstCFGElementRef Elem); } // namespace errno_modeling } // namespace ento diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp index 6076a6bc78973..be70819175299 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp @@ -131,7 +131,8 @@ void ErrnoTesterChecker::evalSetErrnoIfErrorRange(CheckerContext &C, ProgramStateRef StateFailure = State->BindExpr( Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true)); DefinedOrUnknownSVal ErrnoVal = SVB.conjureSymbolVal( - nullptr, Call.getOriginExpr(), C.getLocationContext(), C.blockCount()); + /*symbolTag=*/nullptr, Call.getCFGElementRef(), C.getLocationContext(), + C.blockCount()); StateFailure = StateFailure->assume(ErrnoVal, true); assert(StateFailure && "Failed to assume on an initial value."); StateFailure = diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp index ba561ddebdb69..e9825b7077c7d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp @@ -207,14 +207,15 @@ ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val, } ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val, - const MemRegion *Cont, const Stmt *S, + const MemRegion *Cont, + ConstCFGElementRef Elem, const LocationContext *LCtx, unsigned blockCount) { auto &StateMgr = State->getStateManager(); auto &SymMgr = StateMgr.getSymbolManager(); auto &ACtx = StateMgr.getContext(); - auto Sym = SymMgr.conjureSymbol(S, LCtx, ACtx.LongTy, blockCount); + auto *Sym = SymMgr.conjureSymbol(Elem, LCtx, ACtx.LongTy, blockCount); State = assumeNoOverflow(State, Sym, 4); return setIteratorPosition(State, Val, IteratorPosition::getPosition(Cont, Sym)); diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.h b/clang/lib/StaticAnalyzer/Checkers/Iterator.h index 46de8ea01d77b..0a26db0f2b0a1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/Iterator.h +++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.h @@ -165,7 +165,8 @@ const IteratorPosition *getIteratorPosition(ProgramStateRef State, SVal Val); ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val, const IteratorPosition &Pos); ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val, - const MemRegion *Cont, const Stmt *S, + const MemRegion *Cont, + ConstCFGElementRef Elem, const LocationContext *LCtx, unsigned blockCount); ProgramStateRef advancePosition(ProgramStateRef State, SVal Iter, diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp index d4ce73b03acb8..6139585f1c409 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp @@ -90,8 +90,9 @@ class IteratorModeling check::PostStmt, check::Bind, check::LiveSymbols, check::DeadSymbols> { - using AdvanceFn = void (IteratorModeling::*)(CheckerContext &, const Expr *, - SVal, SVal, SVal) const; + using AdvanceFn = void (IteratorModeling::*)(CheckerContext &, + ConstCFGElementRef, SVal, SVal, + SVal) const; void handleOverloadedOperator(CheckerContext &C, const CallEvent &Call, OverloadedOperatorKind Op) const; @@ -99,8 +100,9 @@ class IteratorModeling const Expr *OrigExpr, const AdvanceFn *Handler) const; - void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal, - SVal LVal, SVal RVal, OverloadedOperatorKind Op) const; + void handleComparison(CheckerContext &C, const Expr *CE, + ConstCFGElementRef Elem, SVal RetVal, SVal LVal, + SVal RVal, OverloadedOperatorKind Op) const; void processComparison(CheckerContext &C, ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, SVal RetVal, OverloadedOperatorKind Op) const; @@ -108,19 +110,20 @@ class IteratorModeling bool Postfix) const; void handleDecrement(CheckerContext &C, SVal RetVal, SVal Iter, bool Postfix) const; - void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE, + void handleRandomIncrOrDecr(CheckerContext &C, ConstCFGElementRef Elem, OverloadedOperatorKind Op, SVal RetVal, SVal Iterator, SVal Amount) const; void handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator, - OverloadedOperatorKind OK, SVal Offset) const; - void handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, - SVal Amount) const; - void handlePrev(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, - SVal Amount) const; - void handleNext(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, - SVal Amount) const; - void assignToContainer(CheckerContext &C, const Expr *CE, SVal RetVal, - const MemRegion *Cont) const; + ConstCFGElementRef Elem, OverloadedOperatorKind OK, + SVal Offset) const; + void handleAdvance(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, + SVal Iter, SVal Amount) const; + void handlePrev(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, + SVal Iter, SVal Amount) const; + void handleNext(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, + SVal Iter, SVal Amount) const; + void assignToContainer(CheckerContext &C, ConstCFGElementRef Elem, + SVal RetVal, const MemRegion *Cont) const; bool noChangeInAdvance(CheckerContext &C, SVal Iter, const Expr *CE) const; void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const override; @@ -224,7 +227,7 @@ void IteratorModeling::checkPostCall(const CallEvent &Call, C.getASTContext()).getTypePtr() == Call.getResultType().getDesugaredType(C.getASTContext()).getTypePtr()) { if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) { - assignToContainer(C, OrigExpr, Call.getReturnValue(), + assignToContainer(C, Call.getCFGElementRef(), Call.getReturnValue(), Pos->getContainer()); return; } @@ -255,7 +258,7 @@ void IteratorModeling::checkPostStmt(const UnaryOperator *UO, return; auto &SVB = C.getSValBuilder(); - handlePtrIncrOrDecr(C, UO->getSubExpr(), + handlePtrIncrOrDecr(C, UO->getSubExpr(), C.getCFGElementRef(), isIncrementOperator(OK) ? OO_Plus : OO_Minus, SVB.makeArrayIndex(1)); } @@ -271,7 +274,7 @@ void IteratorModeling::checkPostStmt(const BinaryOperator *BO, if (isSimpleComparisonOperator(BO->getOpcode())) { SVal Result = State->getSVal(BO, C.getLocationContext()); - handleComparison(C, BO, Result, LVal, RVal, + handleComparison(C, BO, C.getCFGElementRef(), Result, LVal, RVal, BinaryOperator::getOverloadedOperator(OK)); } else if (isRandomIncrOrDecrOperator(OK)) { // In case of operator+ the iterator can be either on the LHS (eg.: it + 1), @@ -284,8 +287,8 @@ void IteratorModeling::checkPostStmt(const BinaryOperator *BO, if (!AmountExpr->getType()->isIntegralOrEnumerationType()) return; SVal AmountVal = IsIterOnLHS ? RVal : LVal; - handlePtrIncrOrDecr(C, IterExpr, BinaryOperator::getOverloadedOperator(OK), - AmountVal); + handlePtrIncrOrDecr(C, IterExpr, C.getCFGElementRef(), + BinaryOperator::getOverloadedOperator(OK), AmountVal); } } @@ -351,27 +354,29 @@ IteratorModeling::handleOverloadedOperator(CheckerContext &C, OverloadedOperatorKind Op) const { if (isSimpleComparisonOperator(Op)) { const auto *OrigExpr = Call.getOriginExpr(); + const auto Elem = Call.getCFGElementRef(); if (!OrigExpr) return; if (const auto *InstCall = dyn_cast(&Call)) { - handleComparison(C, OrigExpr, Call.getReturnValue(), + handleComparison(C, OrigExpr, Elem, Call.getReturnValue(), InstCall->getCXXThisVal(), Call.getArgSVal(0), Op); return; } - handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0), - Call.getArgSVal(1), Op); + handleComparison(C, OrigExpr, Elem, Call.getReturnValue(), + Call.getArgSVal(0), Call.getArgSVal(1), Op); return; } else if (isRandomIncrOrDecrOperator(Op)) { const auto *OrigExpr = Call.getOriginExpr(); + const auto Elem = Call.getCFGElementRef(); if (!OrigExpr) return; if (const auto *InstCall = dyn_cast(&Call)) { if (Call.getNumArgs() >= 1 && Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) { - handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(), + handleRandomIncrOrDecr(C, Elem, Op, Call.getReturnValue(), InstCall->getCXXThisVal(), Call.getArgSVal(0)); return; } @@ -391,8 +396,8 @@ IteratorModeling::handleOverloadedOperator(CheckerContext &C, SVal Iterator = IsIterFirst ? FirstArg : SecondArg; SVal Amount = IsIterFirst ? SecondArg : FirstArg; - handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(), - Iterator, Amount); + handleRandomIncrOrDecr(C, Elem, Op, Call.getReturnValue(), Iterator, + Amount); return; } } @@ -425,7 +430,7 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C, const Expr *OrigExpr, const AdvanceFn *Handler) const { if (!C.wasInlined) { - (this->**Handler)(C, OrigExpr, Call.getReturnValue(), + (this->**Handler)(C, Call.getCFGElementRef(), Call.getReturnValue(), Call.getArgSVal(0), Call.getArgSVal(1)); return; } @@ -436,7 +441,7 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C, if (IdInfo) { if (IdInfo->getName() == "advance") { if (noChangeInAdvance(C, Call.getArgSVal(0), OrigExpr)) { - (this->**Handler)(C, OrigExpr, Call.getReturnValue(), + (this->**Handler)(C, Call.getCFGElementRef(), Call.getReturnValue(), Call.getArgSVal(0), Call.getArgSVal(1)); } } @@ -444,7 +449,8 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C, } void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE, - SVal RetVal, SVal LVal, SVal RVal, + ConstCFGElementRef Elem, SVal RetVal, + SVal LVal, SVal RVal, OverloadedOperatorKind Op) const { // Record the operands and the operator of the comparison for the next // evalAssume, if the result is a symbolic expression. If it is a concrete @@ -467,7 +473,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE, SymbolRef Sym; if (!LPos || !RPos) { auto &SymMgr = C.getSymbolManager(); - Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(), + Sym = SymMgr.conjureSymbol(Elem, C.getLocationContext(), C.getASTContext().LongTy, C.blockCount()); State = assumeNoOverflow(State, Sym, 4); } @@ -494,7 +500,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE, auto &SymMgr = C.getSymbolManager(); auto *LCtx = C.getLocationContext(); RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol( - CE, LCtx, C.getASTContext().BoolTy, C.blockCount())); + Elem, LCtx, C.getASTContext().BoolTy, C.blockCount())); State = State->BindExpr(CE, LCtx, RetVal); } @@ -583,7 +589,8 @@ void IteratorModeling::handleDecrement(CheckerContext &C, SVal RetVal, C.addTransition(State); } -void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE, +void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, + ConstCFGElementRef Elem, OverloadedOperatorKind Op, SVal RetVal, SVal Iterator, SVal Amount) const { @@ -617,12 +624,13 @@ void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE, State = setIteratorPosition(State, TgtVal, *NewPos); C.addTransition(State); } else { - assignToContainer(C, CE, TgtVal, Pos->getContainer()); + assignToContainer(C, Elem, TgtVal, Pos->getContainer()); } } void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator, + ConstCFGElementRef Elem, OverloadedOperatorKind OK, SVal Offset) const { if (!isa(Offset)) @@ -661,34 +669,35 @@ void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C, ProgramStateRef NewState = setIteratorPosition(State, NewVal, *NewPos); C.addTransition(NewState); } else { - assignToContainer(C, Iterator, NewVal, OldPos->getContainer()); + assignToContainer(C, Elem, NewVal, OldPos->getContainer()); } } -void IteratorModeling::handleAdvance(CheckerContext &C, const Expr *CE, +void IteratorModeling::handleAdvance(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, SVal Iter, SVal Amount) const { - handleRandomIncrOrDecr(C, CE, OO_PlusEqual, RetVal, Iter, Amount); + handleRandomIncrOrDecr(C, Elem, OO_PlusEqual, RetVal, Iter, Amount); } -void IteratorModeling::handlePrev(CheckerContext &C, const Expr *CE, +void IteratorModeling::handlePrev(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, SVal Iter, SVal Amount) const { - handleRandomIncrOrDecr(C, CE, OO_Minus, RetVal, Iter, Amount); + handleRandomIncrOrDecr(C, Elem, OO_Minus, RetVal, Iter, Amount); } -void IteratorModeling::handleNext(CheckerContext &C, const Expr *CE, +void IteratorModeling::handleNext(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, SVal Iter, SVal Amount) const { - handleRandomIncrOrDecr(C, CE, OO_Plus, RetVal, Iter, Amount); + handleRandomIncrOrDecr(C, Elem, OO_Plus, RetVal, Iter, Amount); } -void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE, - SVal RetVal, +void IteratorModeling::assignToContainer(CheckerContext &C, + ConstCFGElementRef Elem, SVal RetVal, const MemRegion *Cont) const { Cont = Cont->getMostDerivedObjectRegion(); auto State = C.getState(); const auto *LCtx = C.getLocationContext(); - State = createIteratorPosition(State, RetVal, Cont, CE, LCtx, C.blockCount()); + State = + createIteratorPosition(State, RetVal, Cont, Elem, LCtx, C.blockCount()); C.addTransition(State); } diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 1c4293c30abdb..e970a891d75d0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1833,8 +1833,10 @@ ProgramStateRef MallocChecker::MallocBindRetVal(CheckerContext &C, unsigned Count = C.blockCount(); SValBuilder &SVB = C.getSValBuilder(); const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); - DefinedSVal RetVal = isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count) - : SVB.getConjuredHeapSymbolVal(CE, LCtx, Count); + DefinedSVal RetVal = + isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count) + : SVB.getConjuredHeapSymbolVal(Call.getCFGElementRef(), LCtx, + CE->getType(), Count); return State->BindExpr(CE, C.getLocationContext(), RetVal); } @@ -2304,7 +2306,7 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr, // Assume that after memory is freed, it contains unknown values. This // conforts languages standards, since reading from freed memory is considered // UB and may result in arbitrary value. - State = State->invalidateRegions({location}, Call.getOriginExpr(), + State = State->invalidateRegions({location}, Call.getCFGElementRef(), C.blockCount(), C.getLocationContext(), /*CausesPointerEscape=*/false, /*InvalidatedSymbols=*/nullptr); diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp index cc1ced7358710..03a6b60f93375 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -932,7 +932,8 @@ bool RetainCountChecker::evalCall(const CallEvent &Call, (hasTrustedImplementationAnnotation && !ResultTy.isNull())) { SValBuilder &SVB = C.getSValBuilder(); RetVal = - SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount()); + SVB.conjureSymbolVal(/*symbolTag=*/nullptr, Call.getCFGElementRef(), + LCtx, ResultTy, C.blockCount()); } // Bind the value. diff --git a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp index e037719b90298..8e1996306d7a5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp @@ -25,12 +25,12 @@ using namespace iterator; namespace { class STLAlgorithmModeling : public Checker { - bool evalFind(CheckerContext &C, const CallExpr *CE) const; + bool evalFind(CheckerContext &C, const CallEvent &Call) const; - void Find(CheckerContext &C, const CallExpr *CE, unsigned paramNum) const; + void Find(CheckerContext &C, const CallEvent &Call, unsigned paramNum) const; using FnCheck = bool (STLAlgorithmModeling::*)(CheckerContext &, - const CallExpr *) const; + const CallEvent &Call) const; const CallDescriptionMap Callbacks = { {{CDM::SimpleFunc, {"std", "find"}, 3}, &STLAlgorithmModeling::evalFind}, @@ -97,11 +97,12 @@ bool STLAlgorithmModeling::evalCall(const CallEvent &Call, if (!Handler) return false; - return (this->**Handler)(C, CE); + return (this->**Handler)(C, Call); } bool STLAlgorithmModeling::evalFind(CheckerContext &C, - const CallExpr *CE) const { + const CallEvent &Call) const { + const auto *CE = dyn_cast(Call.getOriginExpr()); // std::find()-like functions either take their primary range in the first // two parameters, or if the first parameter is "execution policy" then in // the second and third. This means that the second parameter must always be @@ -112,27 +113,29 @@ bool STLAlgorithmModeling::evalFind(CheckerContext &C, // If no "execution policy" parameter is used then the first argument is the // beginning of the range. if (isIteratorType(CE->getArg(0)->getType())) { - Find(C, CE, 0); + Find(C, Call, 0); return true; } // If "execution policy" parameter is used then the second argument is the // beginning of the range. if (isIteratorType(CE->getArg(2)->getType())) { - Find(C, CE, 1); + Find(C, Call, 1); return true; } return false; } -void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE, +void STLAlgorithmModeling::Find(CheckerContext &C, const CallEvent &Call, unsigned paramNum) const { + const auto *CE = dyn_cast(Call.getOriginExpr()); + const auto &Elem = Call.getCFGElementRef(); auto State = C.getState(); auto &SVB = C.getSValBuilder(); const auto *LCtx = C.getLocationContext(); - SVal RetVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); + SVal RetVal = SVB.conjureSymbolVal(nullptr, Elem, LCtx, C.blockCount()); SVal Param = State->getSVal(CE->getArg(paramNum), LCtx); auto StateFound = State->BindExpr(CE, LCtx, RetVal); @@ -144,7 +147,7 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE, const auto *Pos = getIteratorPosition(State, Param); if (Pos) { StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(), - CE, LCtx, C.blockCount()); + Elem, LCtx, C.blockCount()); const auto *NewPos = getIteratorPosition(StateFound, RetVal); assert(NewPos && "Failed to create new iterator position."); @@ -166,7 +169,7 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE, Pos = getIteratorPosition(State, Param); if (Pos) { StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(), - CE, LCtx, C.blockCount()); + Elem, LCtx, C.blockCount()); const auto *NewPos = getIteratorPosition(StateFound, RetVal); assert(NewPos && "Failed to create new iterator position."); @@ -199,4 +202,3 @@ void ento::registerSTLAlgorithmModeling(CheckerManager &Mgr) { bool ento::shouldRegisterSTLAlgorithmModeling(const CheckerManager &mgr) { return true; } - diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp index 321388ad857f4..9b0ce151954f3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp @@ -78,10 +78,9 @@ class SmartPtrModeling bool handleOstreamOperator(const CallEvent &Call, CheckerContext &C) const; bool handleSwap(ProgramStateRef State, SVal First, SVal Second, CheckerContext &C) const; - std::pair - retrieveOrConjureInnerPtrVal(ProgramStateRef State, - const MemRegion *ThisRegion, const Expr *E, - QualType Type, CheckerContext &C) const; + std::pair retrieveOrConjureInnerPtrVal( + ProgramStateRef State, const MemRegion *ThisRegion, + ConstCFGElementRef Elem, QualType Type, CheckerContext &C) const; using SmartPtrMethodHandlerFn = void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const; @@ -306,7 +305,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call, return false; const auto PtrVal = C.getSValBuilder().getConjuredHeapSymbolVal( - Call.getOriginExpr(), C.getLocationContext(), + Call.getCFGElementRef(), C.getLocationContext(), getPointerTypeFromTemplateArg(Call, C), C.blockCount()); const MemRegion *ThisRegion = ThisRegionOpt->getAsRegion(); @@ -437,12 +436,12 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call, } std::pair SmartPtrModeling::retrieveOrConjureInnerPtrVal( - ProgramStateRef State, const MemRegion *ThisRegion, const Expr *E, + ProgramStateRef State, const MemRegion *ThisRegion, ConstCFGElementRef Elem, QualType Type, CheckerContext &C) const { const auto *Ptr = State->get(ThisRegion); if (Ptr) return {*Ptr, State}; - auto Val = C.getSValBuilder().conjureSymbolVal(E, C.getLocationContext(), + auto Val = C.getSValBuilder().conjureSymbolVal(Elem, C.getLocationContext(), Type, C.blockCount()); State = State->set(ThisRegion, Val); return {Val, State}; @@ -469,6 +468,7 @@ bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call, // https://en.cppreference.com/w/cpp/memory/unique_ptr/operator_cmp. auto makeSValFor = [&C, this](ProgramStateRef State, const Expr *E, + ConstCFGElementRef Elem, SVal S) -> std::pair { if (S.isZeroConstant()) { return {S, State}; @@ -477,7 +477,7 @@ bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call, assert(Reg && "this pointer of std::unique_ptr should be obtainable as MemRegion"); QualType Type = getInnerPointerType(C, E->getType()->getAsCXXRecordDecl()); - return retrieveOrConjureInnerPtrVal(State, Reg, E, Type, C); + return retrieveOrConjureInnerPtrVal(State, Reg, Elem, Type, C); }; SVal First = Call.getArgSVal(0); @@ -491,8 +491,10 @@ bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call, ProgramStateRef State = C.getState(); SVal FirstPtrVal, SecondPtrVal; - std::tie(FirstPtrVal, State) = makeSValFor(State, FirstExpr, First); - std::tie(SecondPtrVal, State) = makeSValFor(State, SecondExpr, Second); + std::tie(FirstPtrVal, State) = + makeSValFor(State, FirstExpr, Call.getCFGElementRef(), First); + std::tie(SecondPtrVal, State) = + makeSValFor(State, SecondExpr, Call.getCFGElementRef(), Second); BinaryOperatorKind BOK = operationKindFromOverloadedOperator(OOK, true).GetBinaryOpUnsafe(); auto RetVal = Bldr.evalBinOp(State, BOK, FirstPtrVal, SecondPtrVal, @@ -530,7 +532,7 @@ bool SmartPtrModeling::handleOstreamOperator(const CallEvent &Call, if (!StreamThisRegion) return false; State = - State->invalidateRegions({StreamThisRegion}, Call.getOriginExpr(), + State->invalidateRegions({StreamThisRegion}, Call.getCFGElementRef(), C.blockCount(), C.getLocationContext(), false); State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), StreamVal); @@ -722,7 +724,7 @@ void SmartPtrModeling::handleGet(const CallEvent &Call, SVal InnerPointerVal; std::tie(InnerPointerVal, State) = retrieveOrConjureInnerPtrVal( - State, ThisRegion, Call.getOriginExpr(), Call.getResultType(), C); + State, ThisRegion, Call.getCFGElementRef(), Call.getResultType(), C); State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), InnerPointerVal); // TODO: Add NoteTag, for how the raw pointer got using 'get' method. @@ -853,7 +855,7 @@ void SmartPtrModeling::handleBoolConversion(const CallEvent &Call, const LocationContext *LC = C.getLocationContext(); InnerPointerVal = C.getSValBuilder().conjureSymbolVal( - CallExpr, LC, InnerPointerType, C.blockCount()); + Call.getCFGElementRef(), LC, InnerPointerType, C.blockCount()); State = State->set(ThisRegion, InnerPointerVal); } diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 9c0b79ab58618..3628a146fe537 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -585,7 +585,7 @@ class StdLibraryFunctionsChecker CheckerContext &C) const override { SValBuilder &SVB = C.getSValBuilder(); NonLoc ErrnoSVal = - SVB.conjureSymbolVal(&Tag, Call.getOriginExpr(), + SVB.conjureSymbolVal(&Tag, Call.getCFGElementRef(), C.getLocationContext(), C.getASTContext().IntTy, C.blockCount()) .castAs(); @@ -621,7 +621,7 @@ class StdLibraryFunctionsChecker const Summary &Summary, CheckerContext &C) const override { return errno_modeling::setErrnoStdMustBeChecked(State, C, - Call.getOriginExpr()); + Call.getCFGElementRef()); } const std::string describe(CheckerContext &C) const override { @@ -1482,7 +1482,8 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call, const LocationContext *LC = C.getLocationContext(); const auto *CE = cast(Call.getOriginExpr()); SVal V = C.getSValBuilder().conjureSymbolVal( - CE, LC, CE->getType().getCanonicalType(), C.blockCount()); + Call.getCFGElementRef(), LC, CE->getType().getCanonicalType(), + C.blockCount()); State = State->BindExpr(CE, LC, V); C.addTransition(State); diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 80969ce664530..6481b76e69171 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -224,18 +224,16 @@ SVal getStreamArg(const FnDescription *Desc, const CallEvent &Call) { } /// Create a conjured symbol return value for a call expression. -DefinedSVal makeRetVal(CheckerContext &C, const CallExpr *CE) { - assert(CE && "Expecting a call expression."); - - const LocationContext *LCtx = C.getLocationContext(); +DefinedSVal makeRetVal(CheckerContext &C, ConstCFGElementRef Elem) { return C.getSValBuilder() - .conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()) + .conjureSymbolVal(/*symbolTag=*/nullptr, Elem, C.getLocationContext(), + C.blockCount()) .castAs(); } ProgramStateRef bindAndAssumeTrue(ProgramStateRef State, CheckerContext &C, - const CallExpr *CE) { - DefinedSVal RetVal = makeRetVal(C, CE); + const CallExpr *CE, ConstCFGElementRef Elem) { + DefinedSVal RetVal = makeRetVal(C, Elem); State = State->BindExpr(CE, C.getLocationContext(), RetVal); State = State->assume(RetVal, true); assert(State && "Assumption on new value should not fail."); @@ -645,6 +643,7 @@ struct StreamOperationEvaluator { SymbolRef StreamSym = nullptr; const StreamState *SS = nullptr; const CallExpr *CE = nullptr; + std::optional Elem; StreamErrorState NewES; StreamOperationEvaluator(CheckerContext &C) @@ -664,6 +663,7 @@ struct StreamOperationEvaluator { CE = dyn_cast_or_null(Call.getOriginExpr()); if (!CE) return false; + Elem = Call.getCFGElementRef(); assertStreamStateOpened(SS); @@ -683,7 +683,7 @@ struct StreamOperationEvaluator { } ProgramStateRef makeAndBindRetVal(ProgramStateRef State, CheckerContext &C) { - NonLoc RetVal = makeRetVal(C, CE).castAs(); + NonLoc RetVal = makeRetVal(C, Elem.value()).castAs(); return State->BindExpr(CE, C.getLocationContext(), RetVal); } @@ -716,7 +716,7 @@ struct StreamOperationEvaluator { ConstraintManager::ProgramStatePair makeRetValAndAssumeDual(ProgramStateRef State, CheckerContext &C) { - DefinedSVal RetVal = makeRetVal(C, CE); + DefinedSVal RetVal = makeRetVal(C, Elem.value()); State = State->BindExpr(CE, C.getLocationContext(), RetVal); return C.getConstraintManager().assumeDual(State, RetVal); } @@ -858,7 +858,7 @@ escapeByStartIndexAndCount(ProgramStateRef State, const CallEvent &Call, ITraits.setTrait(Element, DoNotInvalidateSuperRegion); } return State->invalidateRegions( - EscapingVals, Call.getOriginExpr(), BlockCount, LCtx, + EscapingVals, Call.getCFGElementRef(), BlockCount, LCtx, /*CausesPointerEscape=*/false, /*InvalidatedSymbols=*/nullptr, &Call, &ITraits); } @@ -868,7 +868,7 @@ static ProgramStateRef escapeArgs(ProgramStateRef State, CheckerContext &C, ArrayRef EscapingArgs) { auto GetArgSVal = [&Call](int Idx) { return Call.getArgSVal(Idx); }; auto EscapingVals = to_vector(map_range(EscapingArgs, GetArgSVal)); - State = State->invalidateRegions(EscapingVals, Call.getOriginExpr(), + State = State->invalidateRegions(EscapingVals, Call.getCFGElementRef(), C.blockCount(), C.getLocationContext(), /*CausesPointerEscape=*/false, /*InvalidatedSymbols=*/nullptr); @@ -931,7 +931,7 @@ void StreamChecker::evalFopen(const FnDescription *Desc, const CallEvent &Call, if (!CE) return; - DefinedSVal RetVal = makeRetVal(C, CE); + DefinedSVal RetVal = makeRetVal(C, Call.getCFGElementRef()); SymbolRef RetSym = RetVal.getAsSymbol(); assert(RetSym && "RetVal must be a symbol here."); @@ -1200,7 +1200,7 @@ void StreamChecker::evalFreadFwrite(const FnDescription *Desc, if (!IsFread && !PedanticMode) return; - NonLoc RetVal = makeRetVal(C, E.CE).castAs(); + NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs(); ProgramStateRef StateFailed = State->BindExpr(E.CE, C.getLocationContext(), RetVal); StateFailed = E.assumeBinOpNN(StateFailed, BO_LT, RetVal, *NMembVal); @@ -1235,7 +1235,7 @@ void StreamChecker::evalFgetx(const FnDescription *Desc, const CallEvent &Call, State = escapeArgs(State, C, Call, {0}); if (SingleChar) { // Generate a transition for the success state of `fgetc`. - NonLoc RetVal = makeRetVal(C, E.CE).castAs(); + NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs(); ProgramStateRef StateNotFailed = State->BindExpr(E.CE, C.getLocationContext(), RetVal); // The returned 'unsigned char' of `fgetc` is converted to 'int', @@ -1300,7 +1300,7 @@ void StreamChecker::evalFputx(const FnDescription *Desc, const CallEvent &Call, C.addTransition(StateNotFailed); } else { // Generate a transition for the success state of `fputs`. - NonLoc RetVal = makeRetVal(C, E.CE).castAs(); + NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs(); ProgramStateRef StateNotFailed = State->BindExpr(E.CE, C.getLocationContext(), RetVal); StateNotFailed = @@ -1334,7 +1334,7 @@ void StreamChecker::evalFprintf(const FnDescription *Desc, if (!E.Init(Desc, Call, C, State)) return; - NonLoc RetVal = makeRetVal(C, E.CE).castAs(); + NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs(); State = State->BindExpr(E.CE, C.getLocationContext(), RetVal); auto Cond = E.SVB @@ -1379,7 +1379,7 @@ void StreamChecker::evalFscanf(const FnDescription *Desc, const CallEvent &Call, // case, and no error flags are set on the stream. This is probably not // accurate, and the POSIX documentation does not tell more. if (!E.isStreamEof()) { - NonLoc RetVal = makeRetVal(C, E.CE).castAs(); + NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs(); ProgramStateRef StateNotFailed = State->BindExpr(E.CE, C.getLocationContext(), RetVal); StateNotFailed = @@ -1460,7 +1460,7 @@ void StreamChecker::evalGetdelim(const FnDescription *Desc, State = escapeArgs(State, C, Call, {0, 1}); // Add transition for the successful state. - NonLoc RetVal = makeRetVal(C, E.CE).castAs(); + NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs(); ProgramStateRef StateNotFailed = E.bindReturnValue(State, C, RetVal); StateNotFailed = E.assumeBinOpNN(StateNotFailed, BO_GE, RetVal, E.getZeroVal(Call)); @@ -1601,7 +1601,7 @@ void StreamChecker::evalFtell(const FnDescription *Desc, const CallEvent &Call, if (!E.Init(Desc, Call, C, State)) return; - NonLoc RetVal = makeRetVal(C, E.CE).castAs(); + NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs(); ProgramStateRef StateNotFailed = State->BindExpr(E.CE, C.getLocationContext(), RetVal); StateNotFailed = @@ -1735,7 +1735,8 @@ void StreamChecker::evalFeofFerror(const FnDescription *Desc, // Execution path with error of ErrorKind. // Function returns true. // From now on it is the only one error state. - ProgramStateRef TrueState = bindAndAssumeTrue(State, C, E.CE); + ProgramStateRef TrueState = + bindAndAssumeTrue(State, C, E.CE, E.Elem.value()); C.addTransition(E.setStreamState( TrueState, StreamState::getOpened(Desc, ErrorKind, E.SS->FilePositionIndeterminate && @@ -1769,7 +1770,7 @@ void StreamChecker::evalFileno(const FnDescription *Desc, const CallEvent &Call, if (!E.Init(Desc, Call, C, State)) return; - NonLoc RetVal = makeRetVal(C, E.CE).castAs(); + NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs(); State = State->BindExpr(E.CE, C.getLocationContext(), RetVal); State = E.assumeBinOpNN(State, BO_GE, RetVal, E.getZeroVal(Call)); if (!State) diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp index fefe846b6911f..044f9ba61113b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp @@ -207,7 +207,7 @@ void InvalidPtrChecker::postPreviousReturnInvalidatingCall( // Function call will return a pointer to the new symbolic region. DefinedOrUnknownSVal RetVal = C.getSValBuilder().conjureSymbolVal( - CE, LCtx, CE->getType(), C.blockCount()); + Call.getCFGElementRef(), LCtx, CE->getType(), C.blockCount()); State = State->BindExpr(CE, LCtx, RetVal); const auto *SymRegOfRetVal = diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index bb4a39f68280c..583315f4f3a90 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -280,7 +280,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, // Invalidate designated regions using the batch invalidation API. // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate // global variables. - return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(), + return Result->invalidateRegions(ValuesToInvalidate, getCFGElementRef(), BlockCount, getLocationContext(), /*CausedByPointerEscape*/ true, /*Symbols=*/nullptr, this, &ETraits); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 86e2e8f634bfd..2af6a60273a9c 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -422,7 +422,7 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded( break; case SubobjectAdjustment::MemberPointerAdjustment: // FIXME: Unimplemented. - State = State->invalidateRegions(Reg, InitWithAdjustments, + State = State->invalidateRegions(Reg, getCFGElementRef(), currBldrCtx->blockCount(), LC, true, nullptr, nullptr, nullptr); return State; @@ -439,8 +439,8 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded( // values inside Reg would be correct. SVal InitVal = State->getSVal(Init, LC); if (InitVal.isUnknown()) { - InitVal = getSValBuilder().conjureSymbolVal(Result, LC, Init->getType(), - currBldrCtx->blockCount()); + InitVal = getSValBuilder().conjureSymbolVal( + getCFGElementRef(), LC, Init->getType(), currBldrCtx->blockCount()); State = State->bindLoc(BaseReg.castAs(), InitVal, LC, false); // Then we'd need to take the value that certainly exists and bind it @@ -449,7 +449,7 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded( // Try to recover some path sensitivity in case we couldn't // compute the value. InitValWithAdjustments = getSValBuilder().conjureSymbolVal( - Result, LC, InitWithAdjustments->getType(), + getCFGElementRef(), LC, InitWithAdjustments->getType(), currBldrCtx->blockCount()); } State = @@ -1215,9 +1215,9 @@ void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit, // If we fail to get the value for some reason, use a symbolic value. if (InitVal.isUnknownOrUndef()) { SValBuilder &SVB = getSValBuilder(); - InitVal = SVB.conjureSymbolVal(BMI->getInit(), stackFrame, - Field->getType(), - currBldrCtx->blockCount()); + InitVal = + SVB.conjureSymbolVal(getCFGElementRef(), stackFrame, + Field->getType(), currBldrCtx->blockCount()); } } else { InitVal = State->getSVal(BMI->getInit(), stackFrame); @@ -2051,9 +2051,9 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, for (const auto N : preVisit) { const LocationContext *LCtx = N->getLocationContext(); - SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, - resultType, - currBldrCtx->blockCount()); + SVal result = svalBuilder.conjureSymbolVal( + /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType, + currBldrCtx->blockCount()); ProgramStateRef State = N->getState()->BindExpr(Ex, LCtx, result); // Escape pointers passed into the list, unless it's an ObjC boxed @@ -2556,10 +2556,18 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminatorStmt(); if (!isa_and_nonnull(Term)) return; + // Widen. const LocationContext *LCtx = Pred->getLocationContext(); - ProgramStateRef WidenedState = - getWidenedLoopState(Pred->getState(), LCtx, BlockCount, Term); + + // FIXME: + // We cannot use the CFG element from the via `ExprEngine::getCFGElementRef` + // since we are currently at the block entrance and the current reference + // would be stale. Ideally, we should pass on the terminator of the CFG + // block, but the terminator cannot be referred as a CFG element. + // Here we just pass the current stale block. + ProgramStateRef WidenedState = getWidenedLoopState( + Pred->getState(), LCtx, BlockCount, getCFGElementRef()); nodeBuilder.generateNode(WidenedState, Pred); return; } @@ -3541,11 +3549,10 @@ void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred, ValuesToInvalidate.push_back(SubExprVal); } - State = State->invalidateRegions(ValuesToInvalidate, AE, - currBldrCtx->blockCount(), - LCtx, - /*CausedByPointerEscape*/true, - /*Symbols=*/nullptr); + State = State->invalidateRegions(ValuesToInvalidate, getCFGElementRef(), + currBldrCtx->blockCount(), LCtx, + /*CausedByPointerEscape*/ true, + /*Symbols=*/nullptr); SVal ResultVal = UnknownVal(); State = State->BindExpr(AE, LCtx, ResultVal); @@ -3892,7 +3899,8 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, assert(!isa(X)); // Should be an Lval, or unknown, undef. if (std::optional LV = X.getAs()) - state = state->invalidateRegions(*LV, A, currBldrCtx->blockCount(), + state = state->invalidateRegions(*LV, getCFGElementRef(), + currBldrCtx->blockCount(), Pred->getLocationContext(), /*CausedByPointerEscape=*/true); } @@ -3902,7 +3910,8 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, SVal X = state->getSVal(I, Pred->getLocationContext()); if (std::optional LV = X.getAs()) - state = state->invalidateRegions(*LV, A, currBldrCtx->blockCount(), + state = state->invalidateRegions(*LV, getCFGElementRef(), + currBldrCtx->blockCount(), Pred->getLocationContext(), /*CausedByPointerEscape=*/true); } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 3d0a69a515ab8..6e52df5e90944 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -21,18 +21,19 @@ using namespace ento; using llvm::APSInt; /// Optionally conjure and return a symbol for offset when processing -/// an expression \p Expression. +/// \p Elem. /// If \p Other is a location, conjure a symbol for \p Symbol /// (offset) if it is unknown so that memory arithmetic always /// results in an ElementRegion. /// \p Count The number of times the current basic block was visited. -static SVal conjureOffsetSymbolOnLocation( - SVal Symbol, SVal Other, Expr* Expression, SValBuilder &svalBuilder, - unsigned Count, const LocationContext *LCtx) { - QualType Ty = Expression->getType(); +static SVal conjureOffsetSymbolOnLocation(SVal Symbol, SVal Other, + ConstCFGElementRef Elem, QualType Ty, + SValBuilder &svalBuilder, + unsigned Count, + const LocationContext *LCtx) { if (isa(Other) && Ty->isIntegralOrEnumerationType() && Symbol.isUnknown()) { - return svalBuilder.conjureSymbolVal(Expression, LCtx, Ty, Count); + return svalBuilder.conjureSymbolVal(Elem, LCtx, Ty, Count); } return Symbol; } @@ -65,7 +66,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // FIXME: Handle structs. if (RightV.isUnknown()) { unsigned Count = currBldrCtx->blockCount(); - RightV = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, + RightV = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx, Count); } // Simulate the effects of a "store": bind the value of the RHS @@ -84,9 +85,11 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // SymSymExpr. unsigned Count = currBldrCtx->blockCount(); RightV = conjureOffsetSymbolOnLocation( - RightV, LeftV, RHS, svalBuilder, Count, LCtx); - LeftV = conjureOffsetSymbolOnLocation( - LeftV, RightV, LHS, svalBuilder, Count, LCtx); + RightV, LeftV, getCFGElementRef(), RHS->getType(), svalBuilder, + Count, LCtx); + LeftV = conjureOffsetSymbolOnLocation(LeftV, RightV, getCFGElementRef(), + LHS->getType(), svalBuilder, + Count, LCtx); } // Although we don't yet model pointers-to-members, we do need to make @@ -165,7 +168,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // The symbolic value is actually for the type of the left-hand side // expression, not the computation type, as this is the value the // LValue on the LHS will bind to. - LHSVal = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, LTy, + LHSVal = svalBuilder.conjureSymbolVal(/*symbolTag=*/nullptr, + getCFGElementRef(), LCtx, LTy, currBldrCtx->blockCount()); // However, we need to convert the symbol to the computation type. Result = svalBuilder.evalCast(LHSVal, CTy, LTy); @@ -459,9 +463,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, } else { // If we don't know if the cast succeeded, conjure a new symbol. if (val.isUnknown()) { - DefinedOrUnknownSVal NewSym = - svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType, - currBldrCtx->blockCount()); + DefinedOrUnknownSVal NewSym = svalBuilder.conjureSymbolVal( + /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType, + currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, NewSym); } else // Else, bind to the derived region value. @@ -483,9 +487,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, // Failed to cast or the result is unknown, fall back to conservative. if (val.isUnknown()) { - val = - svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType, - currBldrCtx->blockCount()); + val = svalBuilder.conjureSymbolVal( + /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType, + currBldrCtx->blockCount()); } state = state->BindExpr(CastE, LCtx, val); Bldr.generateNode(CastE, Pred, state); @@ -529,7 +533,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, if (CastE->isGLValue()) resultType = getContext().getPointerType(resultType); SVal result = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, CastE, LCtx, resultType, + /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType, currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, result); Bldr.generateNode(CastE, Pred, state); @@ -621,8 +625,9 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, Ty = getContext().getPointerType(Ty); } - InitVal = svalBuilder.conjureSymbolVal(nullptr, InitEx, LC, Ty, - currBldrCtx->blockCount()); + InitVal = svalBuilder.conjureSymbolVal( + /*symbolTag=*/nullptr, getCFGElementRef(), LC, Ty, + currBldrCtx->blockCount()); } @@ -839,7 +844,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, } if (!hasValue) - V = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, + V = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx, currBldrCtx->blockCount()); // Generate a new node with the binding from the appropriate path. @@ -1121,9 +1126,9 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, // Conjure a new symbol if necessary to recover precision. if (Result.isUnknown()){ - DefinedOrUnknownSVal SymVal = - svalBuilder.conjureSymbolVal(nullptr, U, LCtx, - currBldrCtx->blockCount()); + DefinedOrUnknownSVal SymVal = svalBuilder.conjureSymbolVal( + /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, + currBldrCtx->blockCount()); Result = SymVal; // If the value is a location, ++/-- should always preserve diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 7e878f922a939..cf08b4e6ecdbe 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -242,8 +242,8 @@ SVal ExprEngine::computeObjectUnderConstruction( assert(RetE && "Void returns should not have a construction context"); QualType ReturnTy = RetE->getType(); QualType RegionTy = ACtx.getPointerType(ReturnTy); - return SVB.conjureSymbolVal(&TopLevelSymRegionTag, RetE, SFC, RegionTy, - currBldrCtx->blockCount()); + return SVB.conjureSymbolVal(&TopLevelSymRegionTag, getCFGElementRef(), + SFC, RegionTy, currBldrCtx->blockCount()); } llvm_unreachable("Unhandled return value construction context!"); } @@ -974,10 +974,11 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // a custom global allocator. if (symVal.isUnknown()) { if (IsStandardGlobalOpNewFunction) - symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount); + symVal = svalBuilder.getConjuredHeapSymbolVal(getCFGElementRef(), LCtx, + CNE->getType(), blockCount); else - symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(), - blockCount); + symVal = svalBuilder.conjureSymbolVal( + /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, blockCount); } CallEventManager &CEMgr = getStateManager().getCallEventManager(); @@ -1109,7 +1110,7 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred, } const LocationContext *LCtx = Pred->getLocationContext(); - SVal V = svalBuilder.conjureSymbolVal(CS, LCtx, VD->getType(), + SVal V = svalBuilder.conjureSymbolVal(getCFGElementRef(), LCtx, VD->getType(), currBldrCtx->blockCount()); ProgramStateRef state = Pred->getState(); state = state->bindLoc(state->getLValue(VD, LCtx), V, LCtx); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 1a44ba4f49133..90625a96e9059 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -746,6 +746,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, const LocationContext *LCtx, ProgramStateRef State) { const Expr *E = Call.getOriginExpr(); + const ConstCFGElementRef &Elem = Call.getCFGElementRef(); if (!E) return State; @@ -788,7 +789,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, RegionAndSymbolInvalidationTraits ITraits; ITraits.setTrait(TargetR, RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion); - State = State->invalidateRegions(TargetR, E, Count, LCtx, + State = State->invalidateRegions(TargetR, Elem, Count, LCtx, /* CausesPointerEscape=*/false, nullptr, &Call, &ITraits); @@ -800,7 +801,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, // a regular unknown pointer. const auto *CNE = dyn_cast(E); if (CNE && CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) { - R = svalBuilder.getConjuredHeapSymbolVal(E, LCtx, Count); + R = svalBuilder.getConjuredHeapSymbolVal(Elem, LCtx, E->getType(), Count); const MemRegion *MR = R.getAsRegion()->StripCasts(); // Store the extent of the allocated object(s). @@ -824,7 +825,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, State = setDynamicExtent(State, MR, Size.castAs()); } else { - R = svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count); + R = svalBuilder.conjureSymbolVal(Elem, LCtx, ResultTy, Count); } } return State->BindExpr(E, LCtx, R); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp index 9426e0afd65a0..f2e5a163afb62 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp @@ -45,7 +45,7 @@ void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, /// for-loop iterator. static void populateObjCForDestinationSet( ExplodedNodeSet &dstLocation, SValBuilder &svalBuilder, - const ObjCForCollectionStmt *S, const Stmt *elem, SVal elementV, + const ObjCForCollectionStmt *S, ConstCFGElementRef elem, SVal elementV, SymbolManager &SymMgr, const NodeBuilderContext *currBldrCtx, StmtNodeBuilder &Bldr, bool hasElements) { @@ -66,8 +66,8 @@ static void populateObjCForDestinationSet( SVal V; if (hasElements) { - SymbolRef Sym = SymMgr.conjureSymbol(elem, LCtx, T, - currBldrCtx->blockCount()); + SymbolRef Sym = + SymMgr.conjureSymbol(elem, LCtx, T, currBldrCtx->blockCount()); V = svalBuilder.makeLoc(Sym); } else { V = svalBuilder.makeIntVal(0, T); @@ -110,6 +110,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, const Stmt *elem = S->getElement(); const Stmt *collection = S->getCollection(); + const ConstCFGElementRef &elemRef = getCFGElementRef(); ProgramStateRef state = Pred->getState(); SVal collectionV = state->getSVal(collection, Pred->getLocationContext()); @@ -132,11 +133,12 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, StmtNodeBuilder Bldr(dstLocation, Tmp, *currBldrCtx); if (!isContainerNull) - populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, elem, - elementV, SymMgr, currBldrCtx, Bldr, + populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, + elemRef, elementV, SymMgr, currBldrCtx, + Bldr, /*hasElements=*/true); - populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, elem, + populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, elemRef, elementV, SymMgr, currBldrCtx, Bldr, /*hasElements=*/false); diff --git a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp index 9e42801760622..2cddf1faa1619 100644 --- a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp +++ b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp @@ -13,10 +13,10 @@ /// //===----------------------------------------------------------------------===// +#include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h" #include "clang/AST/AST.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h" using namespace clang; using namespace ento; @@ -24,31 +24,13 @@ using namespace clang::ast_matchers; const auto MatchRef = "matchref"; -/// Return the loops condition Stmt or NULL if LoopStmt is not a loop -static const Expr *getLoopCondition(const Stmt *LoopStmt) { - switch (LoopStmt->getStmtClass()) { - default: - return nullptr; - case Stmt::ForStmtClass: - return cast(LoopStmt)->getCond(); - case Stmt::WhileStmtClass: - return cast(LoopStmt)->getCond(); - case Stmt::DoStmtClass: - return cast(LoopStmt)->getCond(); - case Stmt::CXXForRangeStmtClass: - return cast(LoopStmt)->getCond(); - } -} - namespace clang { namespace ento { ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, const LocationContext *LCtx, - unsigned BlockCount, const Stmt *LoopStmt) { - - assert((isa(LoopStmt))); - + unsigned BlockCount, + ConstCFGElementRef Elem) { // Invalidate values in the current state. // TODO Make this more conservative by only invalidating values that might // be modified by the body of the loop. @@ -93,9 +75,8 @@ ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, RegionAndSymbolInvalidationTraits::TK_PreserveContents); } - return PrevState->invalidateRegions(Regions, getLoopCondition(LoopStmt), - BlockCount, LCtx, true, nullptr, nullptr, - &ITraits); + return PrevState->invalidateRegions(Regions, Elem, BlockCount, LCtx, true, + nullptr, nullptr, &ITraits); } } // end namespace ento diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index 492209d4d2bf0..19af8993f41ed 100644 --- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -149,7 +149,7 @@ typedef ArrayRef RegionList; typedef ArrayRef ValueList; ProgramStateRef ProgramState::invalidateRegions( - RegionList Regions, const Stmt *S, unsigned Count, + RegionList Regions, ConstCFGElementRef Elem, unsigned Count, const LocationContext *LCtx, bool CausedByPointerEscape, InvalidatedSymbols *IS, const CallEvent *Call, RegionAndSymbolInvalidationTraits *ITraits) const { @@ -157,12 +157,12 @@ ProgramStateRef ProgramState::invalidateRegions( for (const MemRegion *Reg : Regions) Values.push_back(loc::MemRegionVal(Reg)); - return invalidateRegions(Values, S, Count, LCtx, CausedByPointerEscape, IS, + return invalidateRegions(Values, Elem, Count, LCtx, CausedByPointerEscape, IS, Call, ITraits); } ProgramStateRef ProgramState::invalidateRegions( - ValueList Values, const Stmt *S, unsigned Count, + ValueList Values, ConstCFGElementRef Elem, unsigned Count, const LocationContext *LCtx, bool CausedByPointerEscape, InvalidatedSymbols *IS, const CallEvent *Call, RegionAndSymbolInvalidationTraits *ITraits) const { @@ -181,7 +181,7 @@ ProgramStateRef ProgramState::invalidateRegions( StoreManager::InvalidatedRegions TopLevelInvalidated; StoreManager::InvalidatedRegions Invalidated; const StoreRef &NewStore = Mgr.StoreMgr->invalidateRegions( - getStore(), Values, S, Count, LCtx, Call, *IS, *ITraits, + getStore(), Values, Elem, Count, LCtx, Call, *IS, *ITraits, &TopLevelInvalidated, &Invalidated); ProgramStateRef NewState = makeWithStore(NewStore); diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 79cb5a07701fd..3f1e61587452d 100644 --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -563,15 +563,15 @@ class RegionStoreManager : public StoreManager { //===-------------------------------------------------------------------===// // Binding values to regions. //===-------------------------------------------------------------------===// - RegionBindingsRef invalidateGlobalRegion(MemRegion::Kind K, const Stmt *S, - unsigned Count, - const LocationContext *LCtx, - RegionBindingsRef B, - InvalidatedRegions *Invalidated); - - StoreRef invalidateRegions(Store store, ArrayRef Values, const Stmt *S, - unsigned Count, const LocationContext *LCtx, - const CallEvent *Call, InvalidatedSymbols &IS, + RegionBindingsRef + invalidateGlobalRegion(MemRegion::Kind K, ConstCFGElementRef Elem, + unsigned Count, const LocationContext *LCtx, + RegionBindingsRef B, InvalidatedRegions *Invalidated); + + StoreRef invalidateRegions(Store store, ArrayRef Values, + ConstCFGElementRef Elem, unsigned Count, + const LocationContext *LCtx, const CallEvent *Call, + InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits, InvalidatedRegions *Invalidated, InvalidatedRegions *InvalidatedTopLevel) override; @@ -1147,7 +1147,7 @@ RegionStoreManager::removeSubRegionBindings(LimitedRegionBindingsConstRef B, namespace { class InvalidateRegionsWorker : public ClusterAnalysis { - const Stmt *S; + ConstCFGElementRef Elem; unsigned Count; const LocationContext *LCtx; InvalidatedSymbols &IS; @@ -1156,12 +1156,13 @@ class InvalidateRegionsWorker : public ClusterAnalysis GlobalsFilterKind GlobalsFilter; public: InvalidateRegionsWorker(RegionStoreManager &rm, ProgramStateManager &stateMgr, - RegionBindingsRef b, const Stmt *S, unsigned count, - const LocationContext *lctx, InvalidatedSymbols &is, + RegionBindingsRef b, ConstCFGElementRef elem, + unsigned count, const LocationContext *lctx, + InvalidatedSymbols &is, RegionAndSymbolInvalidationTraits &ITraitsIn, StoreManager::InvalidatedRegions *r, GlobalsFilterKind GFK) - : ClusterAnalysis(rm, stateMgr, b), S(S), + : ClusterAnalysis(rm, stateMgr, b), Elem(elem), Count(count), LCtx(lctx), IS(is), ITraits(ITraitsIn), Regions(r), GlobalsFilter(GFK) {} @@ -1296,7 +1297,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelevant. DefinedOrUnknownSVal V = - svalBuilder.conjureSymbolVal(baseR, S, LCtx, Ctx.IntTy, Count); + svalBuilder.conjureSymbolVal(baseR, Elem, LCtx, Ctx.IntTy, Count); B = B.addBinding(baseR, BindingKey::Default, V); return; } @@ -1318,7 +1319,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelevant. DefinedOrUnknownSVal V = - svalBuilder.conjureSymbolVal(baseR, S, LCtx, Ctx.IntTy, Count); + svalBuilder.conjureSymbolVal(baseR, Elem, LCtx, Ctx.IntTy, Count); B = B.addBinding(baseR, BindingKey::Default, V); return; } @@ -1386,13 +1387,13 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, conjure_default: // Set the default value of the array to conjured symbol. DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal( - baseR, S, LCtx, AT->getElementType(), Count); + baseR, Elem, LCtx, AT->getElementType(), Count); B = B.addBinding(baseR, BindingKey::Default, V); return; } DefinedOrUnknownSVal V = - svalBuilder.conjureSymbolVal(baseR, S, LCtx, T, Count); + svalBuilder.conjureSymbolVal(baseR, Elem, LCtx, T, Count); assert(SymbolManager::canSymbolicate(T) || V.isUnknown()); B = B.addBinding(baseR, BindingKey::Direct, V); } @@ -1421,15 +1422,15 @@ bool InvalidateRegionsWorker::includeEntireMemorySpace(const MemRegion *Base) { } RegionBindingsRef RegionStoreManager::invalidateGlobalRegion( - MemRegion::Kind K, const Stmt *S, unsigned Count, + MemRegion::Kind K, ConstCFGElementRef Elem, unsigned Count, const LocationContext *LCtx, RegionBindingsRef B, InvalidatedRegions *Invalidated) { // Bind the globals memory space to a new symbol that we will use to derive // the bindings for all globals. const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion(K); - SVal V = - svalBuilder.conjureSymbolVal(/* symbolTag = */ (const void *)GS, S, LCtx, - /* type does not matter */ Ctx.IntTy, Count); + SVal V = svalBuilder.conjureSymbolVal( + /* symbolTag = */ (const void *)GS, Elem, LCtx, + /* type does not matter */ Ctx.IntTy, Count); B = B.removeBinding(GS) .addBinding(BindingKey::Make(GS, BindingKey::Default), V); @@ -1464,7 +1465,7 @@ void RegionStoreManager::populateWorkList(InvalidateRegionsWorker &W, } StoreRef RegionStoreManager::invalidateRegions( - Store store, ArrayRef Values, const Stmt *S, unsigned Count, + Store store, ArrayRef Values, ConstCFGElementRef Elem, unsigned Count, const LocationContext *LCtx, const CallEvent *Call, InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits, InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated) { @@ -1479,7 +1480,7 @@ StoreRef RegionStoreManager::invalidateRegions( } RegionBindingsRef B = getRegionBindings(store); - InvalidateRegionsWorker W(*this, StateMgr, B, S, Count, LCtx, IS, ITraits, + InvalidateRegionsWorker W(*this, StateMgr, B, Elem, Count, LCtx, IS, ITraits, Invalidated, GlobalsFilter); // Scan the bindings and generate the clusters. @@ -1499,12 +1500,12 @@ StoreRef RegionStoreManager::invalidateRegions( // TODO: This could possibly be more precise with modules. switch (GlobalsFilter) { case GFK_All: - B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind, S, + B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind, Elem, Count, LCtx, B, Invalidated); [[fallthrough]]; case GFK_SystemOnly: - B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, S, Count, - LCtx, B, Invalidated); + B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, Elem, + Count, LCtx, B, Invalidated); [[fallthrough]]; case GFK_None: break; diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index eb5054708fece..f1f842e64ed39 100644 --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -152,9 +152,11 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion *region) { } DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag, - const Expr *Ex, + ConstCFGElementRef elem, const LocationContext *LCtx, unsigned Count) { + const Expr *Ex = dyn_cast(elem->getAs()->getStmt()); + assert(Ex && "elem must be a CFGStmt containing an Expr"); QualType T = Ex->getType(); if (T->isNullPtrType()) @@ -166,11 +168,11 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag, if (Ex->isGLValue()) T = LCtx->getAnalysisDeclContext()->getASTContext().getPointerType(ExType); - return conjureSymbolVal(SymbolTag, Ex, LCtx, T, Count); + return conjureSymbolVal(SymbolTag, elem, LCtx, T, Count); } DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, - const Stmt *St, + ConstCFGElementRef elem, const LocationContext *LCtx, QualType type, unsigned count) { @@ -180,7 +182,7 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, if (!SymbolManager::canSymbolicate(type)) return UnknownVal(); - SymbolRef sym = SymMgr.conjureSymbol(St, LCtx, type, count, symbolTag); + SymbolRef sym = SymMgr.conjureSymbol(elem, LCtx, type, count, symbolTag); if (Loc::isLocType(type)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); @@ -188,7 +190,7 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, return nonloc::SymbolVal(sym); } -DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt, +DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(ConstCFGElementRef elem, const LocationContext *LCtx, QualType type, unsigned visitCount) { @@ -198,7 +200,7 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt, if (!SymbolManager::canSymbolicate(type)) return UnknownVal(); - SymbolRef sym = SymMgr.conjureSymbol(stmt, LCtx, type, visitCount); + SymbolRef sym = SymMgr.conjureSymbol(elem, LCtx, type, visitCount); if (Loc::isLocType(type)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); @@ -206,14 +208,7 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt, return nonloc::SymbolVal(sym); } -DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E, - const LocationContext *LCtx, - unsigned VisitCount) { - QualType T = E->getType(); - return getConjuredHeapSymbolVal(E, LCtx, T, VisitCount); -} - -DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E, +DefinedSVal SValBuilder::getConjuredHeapSymbolVal(ConstCFGElementRef elem, const LocationContext *LCtx, QualType type, unsigned VisitCount) { @@ -225,7 +220,7 @@ DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E, return makeZeroVal(type).castAs(); } - SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, type, VisitCount); + SymbolRef sym = SymMgr.conjureSymbol(elem, LCtx, type, VisitCount); return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym)); } diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp index a4648f5922ef1..a6ade661d04a2 100644 --- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -82,7 +82,7 @@ void UnarySymExpr::dumpToStream(raw_ostream &os) const { void SymbolConjured::dumpToStream(raw_ostream &os) const { os << getKindStr() << getSymbolID() << '{' << T << ", LC" << LCtx->getID(); - if (S) + if (auto *S = getStmt()) os << ", S" << S->getID(LCtx->getDecl()->getASTContext()); else os << ", no stmt"; diff --git a/clang/test/Analysis/PR57270.cpp b/clang/test/Analysis/PR57270.cpp new file mode 100644 index 0000000000000..7d7a658ef441b --- /dev/null +++ b/clang/test/Analysis/PR57270.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -verify %s + +using size_t = __typeof(sizeof(int)); + +void clang_analyzer_explain(int); +void clang_analyzer_dump(int); +void *memset(void *, int, size_t); + +struct S +{ + static int a; + ~S(){}; +}; + +int S::a = 0; + +void foo() +{ + S::a = 0; + + int x = 3; + memset(&x, 1, sizeof(x)); + + S *arr = new S[x]; + delete[] arr; + + clang_analyzer_dump(S::a); // expected-warning-re{{{{derived_\$[0-9]+{conj_\$[0-9]+{int, LC[0-9]+, S[0-9]+, #[0-9]+},a}}}}} + + clang_analyzer_explain(S::a); // expected-warning-re{{{{value derived from \(symbol of type 'int' conjured at CFG element '->~S\(\) \(Implicit destructor\)'\) for global variable 'S::a'}}}} +} diff --git a/clang/test/Analysis/container-modeling.cpp b/clang/test/Analysis/container-modeling.cpp index bf4a12a0e0fe2..5dcb6274b071a 100644 --- a/clang/test/Analysis/container-modeling.cpp +++ b/clang/test/Analysis/container-modeling.cpp @@ -196,7 +196,7 @@ void pop_front(std::list &L, int n) { void push_back() { std::vector V; V.end(); - + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); V.push_back(1); // expected-note{{Container 'V' extended to the back by 1 position}} @@ -256,7 +256,7 @@ void print_state(std::vector &V) { V.cend(); clang_analyzer_printState(); - + // CHECK: "checker_messages": [ // CHECK-NEXT: { "checker": "alpha.cplusplus.ContainerModeling", "messages": [ // CHECK-NEXT: "Container Data :", diff --git a/clang/test/Analysis/dump_egraph.cpp b/clang/test/Analysis/dump_egraph.cpp index 13459699a06f6..2cea5f705f116 100644 --- a/clang/test/Analysis/dump_egraph.cpp +++ b/clang/test/Analysis/dump_egraph.cpp @@ -24,4 +24,3 @@ void foo() { // CHECK: \"cluster\": \"t\", \"pointer\": \"{{0x[0-9a-f]+}}\", \"items\": [\l        \{ \"kind\": \"Default\", \"offset\": 0, \"value\": \"conj_$3\{int, LC5, no stmt, #1\}\" // CHECK: \"dynamic_types\": [\l      \{ \"region\": \"HeapSymRegion\{conj_$1\{S *, LC1, S{{[0-9]+}}, #1\}\}\", \"dyn_type\": \"S\", \"sub_classable\": false \}\l - diff --git a/clang/test/Analysis/explain-svals.cpp b/clang/test/Analysis/explain-svals.cpp index d1615e6cc6c9a..267980c3b20c8 100644 --- a/clang/test/Analysis/explain-svals.cpp +++ b/clang/test/Analysis/explain-svals.cpp @@ -47,12 +47,12 @@ void test_1(int param, void *ptr) { void test_2(char *ptr, int ext) { clang_analyzer_explain((void *) "asdf"); // expected-warning-re{{{{^pointer to element of type 'char' with index 0 of string literal "asdf"$}}}} clang_analyzer_explain(strlen(ptr)); // expected-warning-re{{{{^metadata of type 'unsigned long' tied to pointee of argument 'ptr'$}}}} - clang_analyzer_explain(conjure()); // expected-warning-re{{{{^symbol of type 'int' conjured at statement 'conjure\(\)'$}}}} - clang_analyzer_explain(glob); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure\(\)'\) for global variable 'glob'$}}}} - clang_analyzer_explain(glob_ptr); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure\(\)'\) for global variable 'glob_ptr'$}}}} + clang_analyzer_explain(conjure()); // expected-warning-re{{{{^symbol of type 'int' conjured at CFG element 'conjure\(\)'$}}}} + clang_analyzer_explain(glob); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at CFG element 'conjure\(\)'\) for global variable 'glob'$}}}} + clang_analyzer_explain(glob_ptr); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at CFG element 'conjure\(\)'\) for global variable 'glob_ptr'$}}}} clang_analyzer_explain(clang_analyzer_getExtent(ptr)); // expected-warning-re{{{{^extent of pointee of argument 'ptr'$}}}} int *x = new int[ext]; - clang_analyzer_explain(x); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of heap segment that starts at symbol of type 'int \*' conjured at statement 'new int \[ext\]'$}}}} + clang_analyzer_explain(x); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of heap segment that starts at symbol of type 'int \*' conjured at CFG element 'CFGNewAllocator\(int \*\)'$}}}} // Sic! What gets computed is the extent of the element-region. clang_analyzer_explain(clang_analyzer_getExtent(x)); // expected-warning-re{{{{^\(argument 'ext'\) \* 4$}}}} delete[] x; @@ -99,8 +99,8 @@ class C { } // end of anonymous namespace void test_6() { - clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^symbol of type 'int' conjured at statement 'conjure_S\(\)'$}}}} - clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure_S\(\)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}} + clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^symbol of type 'int' conjured at CFG element 'conjure_S\(\) \(CXXRecordTypedCall, \+0\)'$}}}} + clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at CFG element 'conjure_S\(\) \(CXXRecordTypedCall, \)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}} } class C_top_level { diff --git a/clang/test/Analysis/explain-svals.m b/clang/test/Analysis/explain-svals.m index e93258b3626a5..e79ceabcacebb 100644 --- a/clang/test/Analysis/explain-svals.m +++ b/clang/test/Analysis/explain-svals.m @@ -17,8 +17,8 @@ void test_1(Object *p) { clang_analyzer_explain(p); // expected-warning-re{{{{^argument 'p'$}}}} clang_analyzer_explain(p->x); // expected-warning-re{{{{^initial value of instance variable 'x' of object at argument 'p'$}}}} Object *q = [[Object alloc] init]; - clang_analyzer_explain(q); // expected-warning-re{{{{^symbol of type 'Object \*' conjured at statement '\[\[Object alloc\] init\]'$}}}} - clang_analyzer_explain(q->x); // expected-warning-re{{{{^initial value of instance variable 'x' of object at symbol of type 'Object \*' conjured at statement '\[\[Object alloc\] init\]'$}}}} + clang_analyzer_explain(q); // expected-warning-re{{{{^symbol of type 'Object \*' conjured at CFG element '\[\[Object alloc\] init\]'$}}}} + clang_analyzer_explain(q->x); // expected-warning-re{{{{^initial value of instance variable 'x' of object at symbol of type 'Object \*' conjured at CFG element '\[\[Object alloc\] init\]'$}}}} } void test_2(void) {