diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h index e70c70335e597..a7ff38c786a8f 100644 --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -122,8 +122,7 @@ class CFGElement { return (Kind) x; } - void dumpToStream(llvm::raw_ostream &OS, - bool TerminateWithNewLine = true) const; + void dumpToStream(llvm::raw_ostream &OS) const; void dump() const { dumpToStream(llvm::errs()); @@ -696,11 +695,6 @@ class CFGBlock { void dump() const { dumpToStream(llvm::errs()); } - - void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddPointer(Parent); - ID.AddInteger(Index); - } }; template class ElementRefIterator { @@ -1196,8 +1190,6 @@ 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 6c1025ecc7f4d..519d2d5b3676b 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h +++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h @@ -19,7 +19,6 @@ #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 { @@ -30,13 +29,6 @@ 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); @@ -122,8 +114,7 @@ class SValExplainer : public FullSValVisitor { std::string VisitSymbolConjured(const SymbolConjured *S) { return "symbol of type '" + S->getType().getAsString() + - "' conjured at CFG element '" + - printCFGElementRef(S->getCFGElementRef()) + "'"; + "' conjured at statement '" + printStmt(S->getStmt()) + "'"; } 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 63ca3efc6d228..bb33a6912bec7 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -151,8 +151,6 @@ 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 285194148d3d3..5f855251b3cde 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(); } - ConstCFGElementRef getCFGElementRef() const { + CFGBlock::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 50f2197b8a174..e75228f92a8e5 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h @@ -27,8 +27,7 @@ namespace ento { /// by the loop body in any iteration. ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, const LocationContext *LCtx, - unsigned BlockCount, - ConstCFGElementRef Elem); + unsigned BlockCount, const Stmt *LoopStmt); } // 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 52714535e7907..4d66e086a2c2c 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 Elem The CFG Element that caused the invalidation. + /// \param E the expression 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,17 +325,16 @@ class ProgramState : public llvm::FoldingSetNode { /// \param ITraits information about special handling for particular regions /// or symbols. [[nodiscard]] ProgramStateRef - invalidateRegions(ArrayRef Regions, - ConstCFGElementRef Elem, unsigned BlockCount, - const LocationContext *LCtx, bool CausesPointerEscape, - InvalidatedSymbols *IS = nullptr, + invalidateRegions(ArrayRef Regions, const Stmt *S, + unsigned BlockCount, const LocationContext *LCtx, + bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr, const CallEvent *Call = nullptr, RegionAndSymbolInvalidationTraits *ITraits = nullptr) const; [[nodiscard]] ProgramStateRef - invalidateRegions(ArrayRef Values, ConstCFGElementRef Elem, - unsigned BlockCount, const LocationContext *LCtx, - bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr, + invalidateRegions(ArrayRef Values, const Stmt *S, 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 bd5d245645788..54430d426a82a 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -19,7 +19,6 @@ #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" @@ -172,11 +171,19 @@ class SValBuilder { // Forwarding methods to SymbolManager. - const SymbolConjured *conjureSymbol(ConstCFGElementRef Elem, + const SymbolConjured* conjureSymbol(const Stmt *stmt, const LocationContext *LCtx, - QualType type, unsigned visitCount, + QualType type, + unsigned visitCount, const void *symbolTag = nullptr) { - return SymMgr.conjureSymbol(Elem, LCtx, type, visitCount, symbolTag); + 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); } /// Construct an SVal representing '0' for the specified type. @@ -192,19 +199,29 @@ class SValBuilder { /// preserve the relation between related(or even equivalent) expressions, so /// conjured symbols should be used sparingly. DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, - ConstCFGElementRef elem, + const Expr *expr, const LocationContext *LCtx, unsigned count); - DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, - ConstCFGElementRef elem, + DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Stmt *S, const LocationContext *LCtx, QualType type, unsigned count); - DefinedOrUnknownSVal conjureSymbolVal(ConstCFGElementRef elem, + DefinedOrUnknownSVal conjureSymbolVal(const Stmt *stmt, const LocationContext *LCtx, - QualType type, unsigned visitCount); + QualType type, + unsigned visitCount); /// Conjure a symbol representing heap allocated memory region. - DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem, + /// + /// 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, 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 29a53fcc9e28d..cf7623c7be409 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] Elem The current CFG Element being evaluated. Used to conjure + /// \param[in] S The current statement 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, ConstCFGElementRef Elem, - unsigned Count, const LocationContext *LCtx, const CallEvent *Call, + Store store, ArrayRef Values, const Stmt *S, 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 9e7c98fdded17..cbbea1b56bb40 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -80,62 +80,29 @@ 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 { - ConstCFGElementRef Elem; + const Stmt *S; QualType T; unsigned Count; const LocationContext *LCtx; const void *SymbolTag; friend class SymExprAllocator; - SymbolConjured(SymbolID sym, ConstCFGElementRef elem, - const LocationContext *lctx, QualType t, unsigned count, - const void *symbolTag) - : SymbolData(SymbolConjuredKind, sym), Elem(elem), T(t), Count(count), + 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), 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: - 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; - } - + /// It might return null. + const Stmt *getStmt() const { return S; } unsigned getCount() const { return Count; } /// It might return null. const void *getTag() const { return SymbolTag; } @@ -146,11 +113,11 @@ class SymbolConjured : public SymbolData { void dumpToStream(raw_ostream &os) const override; - static void Profile(llvm::FoldingSetNodeID &profile, ConstCFGElementRef Elem, + static void Profile(llvm::FoldingSetNodeID &profile, const Stmt *S, const LocationContext *LCtx, QualType T, unsigned Count, const void *SymbolTag) { profile.AddInteger((unsigned)SymbolConjuredKind); - profile.Add(Elem); + profile.AddPointer(S); profile.AddPointer(LCtx); profile.Add(T); profile.AddInteger(Count); @@ -158,7 +125,7 @@ class SymbolConjured : public SymbolData { } void Profile(llvm::FoldingSetNodeID& profile) override { - Profile(profile, Elem, LCtx, T, Count, SymbolTag); + Profile(profile, S, LCtx, T, Count, SymbolTag); } // Implement isa support. @@ -566,12 +533,18 @@ class SymbolManager { template const SymExprT *acquire(Args &&...args); - const SymbolConjured *conjureSymbol(ConstCFGElementRef Elem, + const SymbolConjured *conjureSymbol(const Stmt *E, const LocationContext *LCtx, QualType T, unsigned VisitCount, const void *SymbolTag = nullptr) { + return acquire(E, LCtx, T, VisitCount, SymbolTag); + } - return acquire(Elem, 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); } QualType getType(const SymExpr *SE) const { diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 4b50b9248d21a..d03a0a544b016 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -5803,17 +5803,16 @@ static void print_construction_context(raw_ostream &OS, } static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, - const CFGElement &E, bool TerminateWithNewLine = true); + const CFGElement &E); -void CFGElement::dumpToStream(llvm::raw_ostream &OS, - bool TerminateWithNewLine) const { +void CFGElement::dumpToStream(llvm::raw_ostream &OS) const { LangOptions LangOpts; StmtPrinterHelper Helper(nullptr, LangOpts); - print_elem(OS, Helper, *this, TerminateWithNewLine); + print_elem(OS, Helper, *this); } static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, - const CFGElement &E, bool TerminateWithNewLine) { + const CFGElement &E) { switch (E.getKind()) { case CFGElement::Kind::Statement: case CFGElement::Kind::CXXRecordTypedCall: @@ -5830,9 +5829,7 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, if (Children.begin() != Children.end()) { OS << "({ ... ; "; Helper.handledStmt(*SE->getSubStmt()->body_rbegin(),OS); - OS << " })"; - if (TerminateWithNewLine) - OS << '\n'; + OS << " })\n"; return; } } @@ -5841,8 +5838,7 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, if (B->getOpcode() == BO_Comma) { OS << "... , "; Helper.handledStmt(B->getRHS(),OS); - if (TerminateWithNewLine) - OS << '\n'; + OS << '\n'; return; } } @@ -5870,14 +5866,15 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, } // Expressions need a newline. - if (isa(S) && TerminateWithNewLine) + if (isa(S)) OS << '\n'; - return; + break; } case CFGElement::Kind::Initializer: print_initializer(OS, Helper, E.castAs().getInitializer()); + OS << '\n'; break; case CFGElement::Kind::AutomaticObjectDtor: { @@ -5891,44 +5888,43 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, OS << ".~"; T.getUnqualifiedType().print(OS, PrintingPolicy(Helper.getLangOpts())); - OS << "() (Implicit destructor)"; + OS << "() (Implicit destructor)\n"; break; } case CFGElement::Kind::CleanupFunction: OS << "CleanupFunction (" - << E.castAs().getFunctionDecl()->getName() << ")"; + << E.castAs().getFunctionDecl()->getName() << ")\n"; break; case CFGElement::Kind::LifetimeEnds: Helper.handleDecl(E.castAs().getVarDecl(), OS); - OS << " (Lifetime ends)"; + OS << " (Lifetime ends)\n"; break; case CFGElement::Kind::LoopExit: - OS << E.castAs().getLoopStmt()->getStmtClassName() - << " (LoopExit)"; + OS << E.castAs().getLoopStmt()->getStmtClassName() << " (LoopExit)\n"; break; case CFGElement::Kind::ScopeBegin: OS << "CFGScopeBegin("; if (const VarDecl *VD = E.castAs().getVarDecl()) OS << VD->getQualifiedNameAsString(); - OS << ")"; + OS << ")\n"; break; case CFGElement::Kind::ScopeEnd: OS << "CFGScopeEnd("; if (const VarDecl *VD = E.castAs().getVarDecl()) OS << VD->getQualifiedNameAsString(); - OS << ")"; + OS << ")\n"; break; case CFGElement::Kind::NewAllocator: OS << "CFGNewAllocator("; if (const CXXNewExpr *AllocExpr = E.castAs().getAllocatorExpr()) AllocExpr->getType().print(OS, PrintingPolicy(Helper.getLangOpts())); - OS << ")"; + OS << ")\n"; break; case CFGElement::Kind::DeleteDtor: { @@ -5940,14 +5936,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)"; + OS << " (Implicit destructor)\n"; break; } case CFGElement::Kind::BaseDtor: { const CXXBaseSpecifier *BS = E.castAs().getBaseSpecifier(); OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()"; - OS << " (Base object destructor)"; + OS << " (Base object destructor)\n"; break; } @@ -5956,7 +5952,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)"; + OS << " (Member object destructor)\n"; break; } @@ -5965,12 +5961,10 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, E.castAs().getBindTemporaryExpr(); OS << "~"; BT->getType().print(OS, PrintingPolicy(Helper.getLangOpts())); - OS << "() (Temporary object destructor)"; + OS << "() (Temporary object destructor)\n"; 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 49ca39fd4ac3b..39dcaf02dbe25 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -273,29 +273,28 @@ class CStringChecker : public Checker< eval::Call, /// Invalidate the destination buffer determined by characters copied. static ProgramStateRef invalidateDestinationBufferBySize(CheckerContext &C, ProgramStateRef S, - const Expr *BufE, ConstCFGElementRef Elem, - SVal BufV, SVal SizeV, QualType SizeTy); + const Expr *BufE, SVal BufV, SVal SizeV, + QualType SizeTy); /// Operation never overflows, do not invalidate the super region. static ProgramStateRef invalidateDestinationBufferNeverOverflows( - CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV); + CheckerContext &C, ProgramStateRef S, const Expr *BufE, 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, ConstCFGElementRef Elem, SVal BufV); + CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV); /// Invalidate the source buffer for escaping pointers. static ProgramStateRef invalidateSourceBuffer(CheckerContext &C, ProgramStateRef S, - ConstCFGElementRef Elem, - SVal BufV); + const Expr *BufE, 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, ConstCFGElementRef Elem, SVal V, + CheckerContext &C, ProgramStateRef State, const Expr *Ex, SVal V, llvm::function_ref InvalidationTraitOperations); @@ -303,8 +302,8 @@ class CStringChecker : public Checker< eval::Call, static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx, const MemRegion *MR); - static bool memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem, - SVal CharE, const Expr *Size, CheckerContext &C, + static bool memsetAux(const Expr *DstBuffer, SVal CharE, + const Expr *Size, CheckerContext &C, ProgramStateRef &State); // Re-usable checks @@ -1212,8 +1211,8 @@ bool CStringChecker::isFirstBufInBound(CheckerContext &C, ProgramStateRef State, } ProgramStateRef CStringChecker::invalidateDestinationBufferBySize( - CheckerContext &C, ProgramStateRef S, const Expr *BufE, - ConstCFGElementRef Elem, SVal BufV, SVal SizeV, QualType SizeTy) { + CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV, + SVal SizeV, QualType SizeTy) { auto InvalidationTraitOperations = [&C, S, BufTy = BufE->getType(), BufV, SizeV, SizeTy](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) { @@ -1228,22 +1227,22 @@ ProgramStateRef CStringChecker::invalidateDestinationBufferBySize( return false; }; - return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations); + return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations); } ProgramStateRef CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion( - CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV) { + CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV) { auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &, const MemRegion *R) { return isa(R); }; - return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations); + return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations); } ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows( - CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV) { + CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV) { auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) { if (MemRegion::FieldRegionKind == R->getKind()) @@ -1253,12 +1252,12 @@ ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows( return false; }; - return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations); + return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations); } ProgramStateRef CStringChecker::invalidateSourceBuffer(CheckerContext &C, ProgramStateRef S, - ConstCFGElementRef Elem, + const Expr *BufE, SVal BufV) { auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) { @@ -1270,11 +1269,11 @@ ProgramStateRef CStringChecker::invalidateSourceBuffer(CheckerContext &C, return true; }; - return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations); + return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations); } ProgramStateRef CStringChecker::invalidateBufferAux( - CheckerContext &C, ProgramStateRef State, ConstCFGElementRef Elem, SVal V, + CheckerContext &C, ProgramStateRef State, const Expr *E, SVal V, llvm::function_ref InvalidationTraitOperations) { @@ -1300,7 +1299,7 @@ ProgramStateRef CStringChecker::invalidateBufferAux( RegionAndSymbolInvalidationTraits ITraits; bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R); - return State->invalidateRegions(R, Elem, C.blockCount(), LCtx, + return State->invalidateRegions(R, E, C.blockCount(), LCtx, CausesPointerEscape, nullptr, nullptr, &ITraits); } @@ -1350,9 +1349,9 @@ bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, } } -bool CStringChecker::memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem, - SVal CharVal, const Expr *Size, - CheckerContext &C, ProgramStateRef &State) { +bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal, + const Expr *Size, CheckerContext &C, + ProgramStateRef &State) { SVal MemVal = C.getSVal(DstBuffer); SVal SizeVal = C.getSVal(Size); const MemRegion *MR = MemVal.getAsRegion(); @@ -1405,8 +1404,8 @@ bool CStringChecker::memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem, } else { // If the destination buffer's extent is not equal to the value of // third argument, just invalidate buffer. - State = invalidateDestinationBufferBySize( - C, State, DstBuffer, Elem, MemVal, SizeVal, Size->getType()); + State = invalidateDestinationBufferBySize(C, State, DstBuffer, MemVal, + SizeVal, Size->getType()); } if (StateNullChar && !StateNonNullChar) { @@ -1431,7 +1430,7 @@ bool CStringChecker::memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem, } 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, Elem, MemVal, + State = invalidateDestinationBufferBySize(C, State, DstBuffer, MemVal, SizeVal, Size->getType()); } return true; @@ -1516,8 +1515,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call, // conjure a return value for later. if (lastElement.isUnknown()) lastElement = C.getSValBuilder().conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, - C.blockCount()); + nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); // The byte after the last byte copied is the return value. state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement); @@ -1534,12 +1532,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, Call.getCFGElementRef(), - C.getSVal(Dest.Expression), sizeVal, Size.Expression->getType()); + C, state, Dest.Expression, 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, Call.getCFGElementRef(), + state = invalidateSourceBuffer(C, state, Source.Expression, C.getSVal(Source.Expression)); C.addTransition(state); @@ -1667,8 +1665,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( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + SVal CmpV = Builder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, + C.blockCount()); State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV); C.addTransition(State); } @@ -1772,7 +1770,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( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); NonLoc resultNL = result.castAs(); if (strLengthNL) { @@ -1796,7 +1794,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, // value, so it can be used in constraints, at least. if (result.isUnknown()) { result = C.getSValBuilder().conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); } } @@ -2237,13 +2235,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, Call.getCFGElementRef(), *dstRegVal, - amountCopied, C.getASTContext().getSizeType()); + state = invalidateDestinationBufferBySize(C, state, Dst.Expression, + *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, Call.getCFGElementRef(), srcVal); + state = invalidateSourceBuffer(C, state, srcExpr.Expression, srcVal); // Set the C string length of the destination, if we know it. if (IsBounded && (appendK == ConcatFnKind::none)) { @@ -2263,8 +2261,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( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + Result = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, + C.blockCount()); } } // Set the return value. @@ -2363,8 +2361,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( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(), + LCtx, C.blockCount()); if (LeftStrLiteral && RightStrLiteral) { StringRef LeftStrRef = LeftStrLiteral->getString(); @@ -2465,20 +2463,20 @@ void CStringChecker::evalStrsep(CheckerContext &C, // character to NUL. // As the replacement never overflows, do not invalidate its super region. State = invalidateDestinationBufferNeverOverflows( - C, State, Call.getCFGElementRef(), Result); + C, State, SearchStrPtr.Expression, 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.getCFGElementRef(), + SVB.conjureSymbolVal(getTag(), Call.getOriginExpr(), LCtx, CharPtrTy, C.blockCount()), LCtx); } else { assert(SearchStrVal.isUnknown()); // Conjure a symbolic value. It's the best we can do. - Result = SVB.conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + Result = SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, + C.blockCount()); } // Set the return value, and finish. @@ -2516,13 +2514,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, Call.getCFGElementRef(), DstVal); + State = + invalidateDestinationBufferAlwaysEscapeSuperRegion(C, State, Dst, DstVal); SValBuilder &SVB = C.getSValBuilder(); - SVal ResultVal = SVB.conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + SVal ResultVal = + SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); State = State->BindExpr(Call.getOriginExpr(), LCtx, ResultVal); C.addTransition(State); @@ -2571,8 +2569,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, Call.getCFGElementRef(), - C.getSVal(CharE.Expression), Size.Expression, C, State)) + if (!memsetAux(Buffer.Expression, C.getSVal(CharE.Expression), + Size.Expression, C, State)) return; State = State->BindExpr(Call.getOriginExpr(), LCtx, BufferPtrVal); @@ -2616,8 +2614,7 @@ void CStringChecker::evalBzero(CheckerContext &C, const CallEvent &Call) const { if (!State) return; - if (!memsetAux(Buffer.Expression, Call.getCFGElementRef(), Zero, - Size.Expression, C, State)) + if (!memsetAux(Buffer.Expression, 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 3cc49e408387b..d850344db6591 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, ConstCFGElementRef Elem, SVal RetVal, + void handleBegin(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Cont) const; - void handleEnd(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, + void handleEnd(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Cont) const; - void handleAssignment(CheckerContext &C, SVal Cont, ConstCFGElementRef Elem, + void handleAssignment(CheckerContext &C, SVal Cont, const Expr *CE = nullptr, 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,12 +108,11 @@ 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, - ConstCFGElementRef Elem, QualType T, - const LocationContext *LCtx, + const MemRegion *Cont, const Expr *E, + QualType T, const LocationContext *LCtx, unsigned BlockCount); ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, - ConstCFGElementRef Elem, QualType T, + const Expr *E, QualType T, const LocationContext *LCtx, unsigned BlockCount); ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, @@ -164,12 +163,12 @@ void ContainerModeling::checkPostCall(const CallEvent &Call, return; if (cast(Func)->isMoveAssignmentOperator()) { - handleAssignment(C, InstCall->getCXXThisVal(), Call.getCFGElementRef(), - Call.getArgSVal(0)); + handleAssignment(C, InstCall->getCXXThisVal(), Call.getOriginExpr(), + Call.getArgSVal(0)); return; } - handleAssignment(C, InstCall->getCXXThisVal(), C.getCFGElementRef()); + handleAssignment(C, InstCall->getCXXThisVal()); return; } } else { @@ -199,13 +198,13 @@ void ContainerModeling::checkPostCall(const CallEvent &Call, return; if (isBeginCall(Func)) { - handleBegin(C, Call.getCFGElementRef(), Call.getReturnValue(), + handleBegin(C, OrigExpr, Call.getReturnValue(), InstCall->getCXXThisVal()); return; } if (isEndCall(Func)) { - handleEnd(C, Call.getCFGElementRef(), Call.getReturnValue(), + handleEnd(C, OrigExpr, Call.getReturnValue(), InstCall->getCXXThisVal()); return; } @@ -251,8 +250,8 @@ void ContainerModeling::checkDeadSymbols(SymbolReaper &SR, C.addTransition(State); } -void ContainerModeling::handleBegin(CheckerContext &C, ConstCFGElementRef Elem, - SVal RetVal, SVal Cont) const { +void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE, + SVal RetVal, SVal Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -264,7 +263,7 @@ void ContainerModeling::handleBegin(CheckerContext &C, ConstCFGElementRef Elem, auto State = C.getState(); auto BeginSym = getContainerBegin(State, ContReg); if (!BeginSym) { - State = createContainerBegin(State, ContReg, Elem, C.getASTContext().LongTy, + State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy, C.getLocationContext(), C.blockCount()); BeginSym = getContainerBegin(State, ContReg); } @@ -273,8 +272,8 @@ void ContainerModeling::handleBegin(CheckerContext &C, ConstCFGElementRef Elem, C.addTransition(State); } -void ContainerModeling::handleEnd(CheckerContext &C, ConstCFGElementRef Elem, - SVal RetVal, SVal Cont) const { +void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE, + SVal RetVal, SVal Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -286,7 +285,7 @@ void ContainerModeling::handleEnd(CheckerContext &C, ConstCFGElementRef Elem, auto State = C.getState(); auto EndSym = getContainerEnd(State, ContReg); if (!EndSym) { - State = createContainerEnd(State, ContReg, Elem, C.getASTContext().LongTy, + State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy, C.getLocationContext(), C.blockCount()); EndSym = getContainerEnd(State, ContReg); } @@ -296,8 +295,7 @@ void ContainerModeling::handleEnd(CheckerContext &C, ConstCFGElementRef Elem, } void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont, - ConstCFGElementRef Elem, - SVal OldCont) const { + const Expr *CE, SVal OldCont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -331,7 +329,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(Elem, C.getLocationContext(), + SymMgr.conjureSymbol(CE, C.getLocationContext(), C.getASTContext().LongTy, C.blockCount()); State = assumeNoOverflow(State, NewEndSym, 4); if (CData) { @@ -850,9 +848,8 @@ SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) { } ProgramStateRef createContainerBegin(ProgramStateRef State, - const MemRegion *Cont, - ConstCFGElementRef Elem, QualType T, - const LocationContext *LCtx, + const MemRegion *Cont, const Expr *E, + QualType T, const LocationContext *LCtx, unsigned BlockCount) { // Only create if it does not exist const auto *CDataPtr = getContainerData(State, Cont); @@ -860,8 +857,8 @@ ProgramStateRef createContainerBegin(ProgramStateRef State, return State; auto &SymMgr = State->getSymbolManager(); - const SymbolConjured *Sym = - SymMgr.conjureSymbol(Elem, LCtx, T, BlockCount, "begin"); + const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, + "begin"); State = assumeNoOverflow(State, Sym, 4); if (CDataPtr) { @@ -874,7 +871,7 @@ ProgramStateRef createContainerBegin(ProgramStateRef State, } ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, - ConstCFGElementRef Elem, QualType T, + const Expr *E, QualType T, const LocationContext *LCtx, unsigned BlockCount) { // Only create if it does not exist @@ -883,8 +880,8 @@ ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, return State; auto &SymMgr = State->getSymbolManager(); - const SymbolConjured *Sym = - SymMgr.conjureSymbol(Elem, LCtx, T, BlockCount, "end"); + const SymbolConjured *Sym = SymMgr.conjureSymbol(E, 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 abfc5d20d3094..6ffc05f06742b 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( - C.getCFGElementRef(), C.getLocationContext(), + nullptr, 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, - ConstCFGElementRef Elem) { + const Expr *InvalE) { const MemRegion *ErrnoR = State->get(); if (!ErrnoR) return State; - State = State->invalidateRegions(ErrnoR, Elem, C.blockCount(), + State = State->invalidateRegions(ErrnoR, InvalE, 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 e414353322054..95da8a28d3253 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h +++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h @@ -96,10 +96,9 @@ 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 Elem CFG Element that causes invalidation of \c errno. +/// \arg \c InvalE Expression that causes invalidation of \c errno. ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State, - CheckerContext &C, - ConstCFGElementRef Elem); + CheckerContext &C, const Expr *InvalE); } // namespace errno_modeling } // namespace ento diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp index be70819175299..6076a6bc78973 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp @@ -131,8 +131,7 @@ void ErrnoTesterChecker::evalSetErrnoIfErrorRange(CheckerContext &C, ProgramStateRef StateFailure = State->BindExpr( Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true)); DefinedOrUnknownSVal ErrnoVal = SVB.conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), C.getLocationContext(), - C.blockCount()); + nullptr, Call.getOriginExpr(), 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 e9825b7077c7d..ba561ddebdb69 100644 --- a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp @@ -207,15 +207,14 @@ ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val, } ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val, - const MemRegion *Cont, - ConstCFGElementRef Elem, + const MemRegion *Cont, const Stmt *S, const LocationContext *LCtx, unsigned blockCount) { auto &StateMgr = State->getStateManager(); auto &SymMgr = StateMgr.getSymbolManager(); auto &ACtx = StateMgr.getContext(); - auto *Sym = SymMgr.conjureSymbol(Elem, LCtx, ACtx.LongTy, blockCount); + auto Sym = SymMgr.conjureSymbol(S, 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 0a26db0f2b0a1..46de8ea01d77b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/Iterator.h +++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.h @@ -165,8 +165,7 @@ 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, - ConstCFGElementRef Elem, + const MemRegion *Cont, const Stmt *S, 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 6139585f1c409..d4ce73b03acb8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp @@ -90,9 +90,8 @@ class IteratorModeling check::PostStmt, check::Bind, check::LiveSymbols, check::DeadSymbols> { - using AdvanceFn = void (IteratorModeling::*)(CheckerContext &, - ConstCFGElementRef, SVal, SVal, - SVal) const; + using AdvanceFn = void (IteratorModeling::*)(CheckerContext &, const Expr *, + SVal, SVal, SVal) const; void handleOverloadedOperator(CheckerContext &C, const CallEvent &Call, OverloadedOperatorKind Op) const; @@ -100,9 +99,8 @@ class IteratorModeling const Expr *OrigExpr, const AdvanceFn *Handler) const; - void handleComparison(CheckerContext &C, const Expr *CE, - ConstCFGElementRef Elem, SVal RetVal, SVal LVal, - SVal RVal, OverloadedOperatorKind Op) const; + void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal, + SVal LVal, SVal RVal, OverloadedOperatorKind Op) const; void processComparison(CheckerContext &C, ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, SVal RetVal, OverloadedOperatorKind Op) const; @@ -110,20 +108,19 @@ class IteratorModeling bool Postfix) const; void handleDecrement(CheckerContext &C, SVal RetVal, SVal Iter, bool Postfix) const; - void handleRandomIncrOrDecr(CheckerContext &C, ConstCFGElementRef Elem, + void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE, OverloadedOperatorKind Op, SVal RetVal, SVal Iterator, SVal Amount) const; void handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator, - 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; + 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; 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; @@ -227,7 +224,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, Call.getCFGElementRef(), Call.getReturnValue(), + assignToContainer(C, OrigExpr, Call.getReturnValue(), Pos->getContainer()); return; } @@ -258,7 +255,7 @@ void IteratorModeling::checkPostStmt(const UnaryOperator *UO, return; auto &SVB = C.getSValBuilder(); - handlePtrIncrOrDecr(C, UO->getSubExpr(), C.getCFGElementRef(), + handlePtrIncrOrDecr(C, UO->getSubExpr(), isIncrementOperator(OK) ? OO_Plus : OO_Minus, SVB.makeArrayIndex(1)); } @@ -274,7 +271,7 @@ void IteratorModeling::checkPostStmt(const BinaryOperator *BO, if (isSimpleComparisonOperator(BO->getOpcode())) { SVal Result = State->getSVal(BO, C.getLocationContext()); - handleComparison(C, BO, C.getCFGElementRef(), Result, LVal, RVal, + handleComparison(C, BO, 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), @@ -287,8 +284,8 @@ void IteratorModeling::checkPostStmt(const BinaryOperator *BO, if (!AmountExpr->getType()->isIntegralOrEnumerationType()) return; SVal AmountVal = IsIterOnLHS ? RVal : LVal; - handlePtrIncrOrDecr(C, IterExpr, C.getCFGElementRef(), - BinaryOperator::getOverloadedOperator(OK), AmountVal); + handlePtrIncrOrDecr(C, IterExpr, BinaryOperator::getOverloadedOperator(OK), + AmountVal); } } @@ -354,29 +351,27 @@ 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, Elem, Call.getReturnValue(), + handleComparison(C, OrigExpr, Call.getReturnValue(), InstCall->getCXXThisVal(), Call.getArgSVal(0), Op); return; } - handleComparison(C, OrigExpr, Elem, Call.getReturnValue(), - Call.getArgSVal(0), Call.getArgSVal(1), Op); + handleComparison(C, OrigExpr, 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, Elem, Op, Call.getReturnValue(), + handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(), InstCall->getCXXThisVal(), Call.getArgSVal(0)); return; } @@ -396,8 +391,8 @@ IteratorModeling::handleOverloadedOperator(CheckerContext &C, SVal Iterator = IsIterFirst ? FirstArg : SecondArg; SVal Amount = IsIterFirst ? SecondArg : FirstArg; - handleRandomIncrOrDecr(C, Elem, Op, Call.getReturnValue(), Iterator, - Amount); + handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(), + Iterator, Amount); return; } } @@ -430,7 +425,7 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C, const Expr *OrigExpr, const AdvanceFn *Handler) const { if (!C.wasInlined) { - (this->**Handler)(C, Call.getCFGElementRef(), Call.getReturnValue(), + (this->**Handler)(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0), Call.getArgSVal(1)); return; } @@ -441,7 +436,7 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C, if (IdInfo) { if (IdInfo->getName() == "advance") { if (noChangeInAdvance(C, Call.getArgSVal(0), OrigExpr)) { - (this->**Handler)(C, Call.getCFGElementRef(), Call.getReturnValue(), + (this->**Handler)(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0), Call.getArgSVal(1)); } } @@ -449,8 +444,7 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C, } void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE, - ConstCFGElementRef Elem, SVal RetVal, - SVal LVal, SVal RVal, + 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 @@ -473,7 +467,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE, SymbolRef Sym; if (!LPos || !RPos) { auto &SymMgr = C.getSymbolManager(); - Sym = SymMgr.conjureSymbol(Elem, C.getLocationContext(), + Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(), C.getASTContext().LongTy, C.blockCount()); State = assumeNoOverflow(State, Sym, 4); } @@ -500,7 +494,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE, auto &SymMgr = C.getSymbolManager(); auto *LCtx = C.getLocationContext(); RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol( - Elem, LCtx, C.getASTContext().BoolTy, C.blockCount())); + CE, LCtx, C.getASTContext().BoolTy, C.blockCount())); State = State->BindExpr(CE, LCtx, RetVal); } @@ -589,8 +583,7 @@ void IteratorModeling::handleDecrement(CheckerContext &C, SVal RetVal, C.addTransition(State); } -void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, - ConstCFGElementRef Elem, +void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE, OverloadedOperatorKind Op, SVal RetVal, SVal Iterator, SVal Amount) const { @@ -624,13 +617,12 @@ void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, State = setIteratorPosition(State, TgtVal, *NewPos); C.addTransition(State); } else { - assignToContainer(C, Elem, TgtVal, Pos->getContainer()); + assignToContainer(C, CE, TgtVal, Pos->getContainer()); } } void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator, - ConstCFGElementRef Elem, OverloadedOperatorKind OK, SVal Offset) const { if (!isa(Offset)) @@ -669,35 +661,34 @@ void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C, ProgramStateRef NewState = setIteratorPosition(State, NewVal, *NewPos); C.addTransition(NewState); } else { - assignToContainer(C, Elem, NewVal, OldPos->getContainer()); + assignToContainer(C, Iterator, NewVal, OldPos->getContainer()); } } -void IteratorModeling::handleAdvance(CheckerContext &C, ConstCFGElementRef Elem, +void IteratorModeling::handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, SVal Amount) const { - handleRandomIncrOrDecr(C, Elem, OO_PlusEqual, RetVal, Iter, Amount); + handleRandomIncrOrDecr(C, CE, OO_PlusEqual, RetVal, Iter, Amount); } -void IteratorModeling::handlePrev(CheckerContext &C, ConstCFGElementRef Elem, +void IteratorModeling::handlePrev(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, SVal Amount) const { - handleRandomIncrOrDecr(C, Elem, OO_Minus, RetVal, Iter, Amount); + handleRandomIncrOrDecr(C, CE, OO_Minus, RetVal, Iter, Amount); } -void IteratorModeling::handleNext(CheckerContext &C, ConstCFGElementRef Elem, +void IteratorModeling::handleNext(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, SVal Amount) const { - handleRandomIncrOrDecr(C, Elem, OO_Plus, RetVal, Iter, Amount); + handleRandomIncrOrDecr(C, CE, OO_Plus, RetVal, Iter, Amount); } -void IteratorModeling::assignToContainer(CheckerContext &C, - ConstCFGElementRef Elem, SVal RetVal, +void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE, + SVal RetVal, const MemRegion *Cont) const { Cont = Cont->getMostDerivedObjectRegion(); auto State = C.getState(); const auto *LCtx = C.getLocationContext(); - State = - createIteratorPosition(State, RetVal, Cont, Elem, LCtx, C.blockCount()); + State = createIteratorPosition(State, RetVal, Cont, CE, LCtx, C.blockCount()); C.addTransition(State); } diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index e970a891d75d0..1c4293c30abdb 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1833,10 +1833,8 @@ 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(Call.getCFGElementRef(), LCtx, - CE->getType(), Count); + DefinedSVal RetVal = isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count) + : SVB.getConjuredHeapSymbolVal(CE, LCtx, Count); return State->BindExpr(CE, C.getLocationContext(), RetVal); } @@ -2306,7 +2304,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.getCFGElementRef(), + State = State->invalidateRegions({location}, Call.getOriginExpr(), 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 03a6b60f93375..cc1ced7358710 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -932,8 +932,7 @@ bool RetainCountChecker::evalCall(const CallEvent &Call, (hasTrustedImplementationAnnotation && !ResultTy.isNull())) { SValBuilder &SVB = C.getSValBuilder(); RetVal = - SVB.conjureSymbolVal(/*symbolTag=*/nullptr, Call.getCFGElementRef(), - LCtx, ResultTy, C.blockCount()); + SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount()); } // Bind the value. diff --git a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp index 8e1996306d7a5..e037719b90298 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 CallEvent &Call) const; + bool evalFind(CheckerContext &C, const CallExpr *CE) const; - void Find(CheckerContext &C, const CallEvent &Call, unsigned paramNum) const; + void Find(CheckerContext &C, const CallExpr *CE, unsigned paramNum) const; using FnCheck = bool (STLAlgorithmModeling::*)(CheckerContext &, - const CallEvent &Call) const; + const CallExpr *) const; const CallDescriptionMap Callbacks = { {{CDM::SimpleFunc, {"std", "find"}, 3}, &STLAlgorithmModeling::evalFind}, @@ -97,12 +97,11 @@ bool STLAlgorithmModeling::evalCall(const CallEvent &Call, if (!Handler) return false; - return (this->**Handler)(C, Call); + return (this->**Handler)(C, CE); } bool STLAlgorithmModeling::evalFind(CheckerContext &C, - const CallEvent &Call) const { - const auto *CE = dyn_cast(Call.getOriginExpr()); + const CallExpr *CE) const { // 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 @@ -113,29 +112,27 @@ 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, Call, 0); + Find(C, CE, 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, Call, 1); + Find(C, CE, 1); return true; } return false; } -void STLAlgorithmModeling::Find(CheckerContext &C, const CallEvent &Call, +void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE, 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, Elem, LCtx, C.blockCount()); + SVal RetVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); SVal Param = State->getSVal(CE->getArg(paramNum), LCtx); auto StateFound = State->BindExpr(CE, LCtx, RetVal); @@ -147,7 +144,7 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallEvent &Call, const auto *Pos = getIteratorPosition(State, Param); if (Pos) { StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(), - Elem, LCtx, C.blockCount()); + CE, LCtx, C.blockCount()); const auto *NewPos = getIteratorPosition(StateFound, RetVal); assert(NewPos && "Failed to create new iterator position."); @@ -169,7 +166,7 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallEvent &Call, Pos = getIteratorPosition(State, Param); if (Pos) { StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(), - Elem, LCtx, C.blockCount()); + CE, LCtx, C.blockCount()); const auto *NewPos = getIteratorPosition(StateFound, RetVal); assert(NewPos && "Failed to create new iterator position."); @@ -202,3 +199,4 @@ 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 9b0ce151954f3..321388ad857f4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp @@ -78,9 +78,10 @@ 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, - ConstCFGElementRef Elem, QualType Type, CheckerContext &C) const; + std::pair + retrieveOrConjureInnerPtrVal(ProgramStateRef State, + const MemRegion *ThisRegion, const Expr *E, + QualType Type, CheckerContext &C) const; using SmartPtrMethodHandlerFn = void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const; @@ -305,7 +306,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call, return false; const auto PtrVal = C.getSValBuilder().getConjuredHeapSymbolVal( - Call.getCFGElementRef(), C.getLocationContext(), + Call.getOriginExpr(), C.getLocationContext(), getPointerTypeFromTemplateArg(Call, C), C.blockCount()); const MemRegion *ThisRegion = ThisRegionOpt->getAsRegion(); @@ -436,12 +437,12 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call, } std::pair SmartPtrModeling::retrieveOrConjureInnerPtrVal( - ProgramStateRef State, const MemRegion *ThisRegion, ConstCFGElementRef Elem, + ProgramStateRef State, const MemRegion *ThisRegion, const Expr *E, QualType Type, CheckerContext &C) const { const auto *Ptr = State->get(ThisRegion); if (Ptr) return {*Ptr, State}; - auto Val = C.getSValBuilder().conjureSymbolVal(Elem, C.getLocationContext(), + auto Val = C.getSValBuilder().conjureSymbolVal(E, C.getLocationContext(), Type, C.blockCount()); State = State->set(ThisRegion, Val); return {Val, State}; @@ -468,7 +469,6 @@ 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, Elem, Type, C); + return retrieveOrConjureInnerPtrVal(State, Reg, E, Type, C); }; SVal First = Call.getArgSVal(0); @@ -491,10 +491,8 @@ bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call, ProgramStateRef State = C.getState(); SVal FirstPtrVal, SecondPtrVal; - std::tie(FirstPtrVal, State) = - makeSValFor(State, FirstExpr, Call.getCFGElementRef(), First); - std::tie(SecondPtrVal, State) = - makeSValFor(State, SecondExpr, Call.getCFGElementRef(), Second); + std::tie(FirstPtrVal, State) = makeSValFor(State, FirstExpr, First); + std::tie(SecondPtrVal, State) = makeSValFor(State, SecondExpr, Second); BinaryOperatorKind BOK = operationKindFromOverloadedOperator(OOK, true).GetBinaryOpUnsafe(); auto RetVal = Bldr.evalBinOp(State, BOK, FirstPtrVal, SecondPtrVal, @@ -532,7 +530,7 @@ bool SmartPtrModeling::handleOstreamOperator(const CallEvent &Call, if (!StreamThisRegion) return false; State = - State->invalidateRegions({StreamThisRegion}, Call.getCFGElementRef(), + State->invalidateRegions({StreamThisRegion}, Call.getOriginExpr(), C.blockCount(), C.getLocationContext(), false); State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), StreamVal); @@ -724,7 +722,7 @@ void SmartPtrModeling::handleGet(const CallEvent &Call, SVal InnerPointerVal; std::tie(InnerPointerVal, State) = retrieveOrConjureInnerPtrVal( - State, ThisRegion, Call.getCFGElementRef(), Call.getResultType(), C); + State, ThisRegion, Call.getOriginExpr(), Call.getResultType(), C); State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), InnerPointerVal); // TODO: Add NoteTag, for how the raw pointer got using 'get' method. @@ -855,7 +853,7 @@ void SmartPtrModeling::handleBoolConversion(const CallEvent &Call, const LocationContext *LC = C.getLocationContext(); InnerPointerVal = C.getSValBuilder().conjureSymbolVal( - Call.getCFGElementRef(), LC, InnerPointerType, C.blockCount()); + CallExpr, 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 3628a146fe537..9c0b79ab58618 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.getCFGElementRef(), + SVB.conjureSymbolVal(&Tag, Call.getOriginExpr(), 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.getCFGElementRef()); + Call.getOriginExpr()); } const std::string describe(CheckerContext &C) const override { @@ -1482,8 +1482,7 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call, const LocationContext *LC = C.getLocationContext(); const auto *CE = cast(Call.getOriginExpr()); SVal V = C.getSValBuilder().conjureSymbolVal( - Call.getCFGElementRef(), LC, CE->getType().getCanonicalType(), - C.blockCount()); + CE, 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 6481b76e69171..80969ce664530 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -224,16 +224,18 @@ SVal getStreamArg(const FnDescription *Desc, const CallEvent &Call) { } /// Create a conjured symbol return value for a call expression. -DefinedSVal makeRetVal(CheckerContext &C, ConstCFGElementRef Elem) { +DefinedSVal makeRetVal(CheckerContext &C, const CallExpr *CE) { + assert(CE && "Expecting a call expression."); + + const LocationContext *LCtx = C.getLocationContext(); return C.getSValBuilder() - .conjureSymbolVal(/*symbolTag=*/nullptr, Elem, C.getLocationContext(), - C.blockCount()) + .conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()) .castAs(); } ProgramStateRef bindAndAssumeTrue(ProgramStateRef State, CheckerContext &C, - const CallExpr *CE, ConstCFGElementRef Elem) { - DefinedSVal RetVal = makeRetVal(C, Elem); + const CallExpr *CE) { + DefinedSVal RetVal = makeRetVal(C, CE); State = State->BindExpr(CE, C.getLocationContext(), RetVal); State = State->assume(RetVal, true); assert(State && "Assumption on new value should not fail."); @@ -643,7 +645,6 @@ struct StreamOperationEvaluator { SymbolRef StreamSym = nullptr; const StreamState *SS = nullptr; const CallExpr *CE = nullptr; - std::optional Elem; StreamErrorState NewES; StreamOperationEvaluator(CheckerContext &C) @@ -663,7 +664,6 @@ 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, Elem.value()).castAs(); + NonLoc RetVal = makeRetVal(C, CE).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, Elem.value()); + DefinedSVal RetVal = makeRetVal(C, CE); 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.getCFGElementRef(), BlockCount, LCtx, + EscapingVals, Call.getOriginExpr(), 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.getCFGElementRef(), + State = State->invalidateRegions(EscapingVals, Call.getOriginExpr(), 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, Call.getCFGElementRef()); + DefinedSVal RetVal = makeRetVal(C, CE); 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.Elem.value()).castAs(); + NonLoc RetVal = makeRetVal(C, E.CE).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.Elem.value()).castAs(); + NonLoc RetVal = makeRetVal(C, E.CE).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.Elem.value()).castAs(); + NonLoc RetVal = makeRetVal(C, E.CE).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.Elem.value()).castAs(); + NonLoc RetVal = makeRetVal(C, E.CE).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.Elem.value()).castAs(); + NonLoc RetVal = makeRetVal(C, E.CE).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.Elem.value()).castAs(); + NonLoc RetVal = makeRetVal(C, E.CE).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.Elem.value()).castAs(); + NonLoc RetVal = makeRetVal(C, E.CE).castAs(); ProgramStateRef StateNotFailed = State->BindExpr(E.CE, C.getLocationContext(), RetVal); StateNotFailed = @@ -1735,8 +1735,7 @@ 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, E.Elem.value()); + ProgramStateRef TrueState = bindAndAssumeTrue(State, C, E.CE); C.addTransition(E.setStreamState( TrueState, StreamState::getOpened(Desc, ErrorKind, E.SS->FilePositionIndeterminate && @@ -1770,7 +1769,7 @@ void StreamChecker::evalFileno(const FnDescription *Desc, const CallEvent &Call, if (!E.Init(Desc, Call, C, State)) return; - NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs(); + NonLoc RetVal = makeRetVal(C, E.CE).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 044f9ba61113b..fefe846b6911f 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( - Call.getCFGElementRef(), LCtx, CE->getType(), C.blockCount()); + CE, 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 583315f4f3a90..bb4a39f68280c 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, getCFGElementRef(), + return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(), 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 2af6a60273a9c..86e2e8f634bfd 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, getCFGElementRef(), + State = State->invalidateRegions(Reg, InitWithAdjustments, 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( - getCFGElementRef(), LC, Init->getType(), currBldrCtx->blockCount()); + InitVal = getSValBuilder().conjureSymbolVal(Result, 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( - getCFGElementRef(), LC, InitWithAdjustments->getType(), + Result, 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(getCFGElementRef(), stackFrame, - Field->getType(), currBldrCtx->blockCount()); + InitVal = SVB.conjureSymbolVal(BMI->getInit(), 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( - /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType, - currBldrCtx->blockCount()); + SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, 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,18 +2556,10 @@ 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(); - - // 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()); + ProgramStateRef WidenedState = + getWidenedLoopState(Pred->getState(), LCtx, BlockCount, Term); nodeBuilder.generateNode(WidenedState, Pred); return; } @@ -3549,10 +3541,11 @@ void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred, ValuesToInvalidate.push_back(SubExprVal); } - State = State->invalidateRegions(ValuesToInvalidate, getCFGElementRef(), - currBldrCtx->blockCount(), LCtx, - /*CausedByPointerEscape*/ true, - /*Symbols=*/nullptr); + State = State->invalidateRegions(ValuesToInvalidate, AE, + currBldrCtx->blockCount(), + LCtx, + /*CausedByPointerEscape*/true, + /*Symbols=*/nullptr); SVal ResultVal = UnknownVal(); State = State->BindExpr(AE, LCtx, ResultVal); @@ -3899,8 +3892,7 @@ 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, getCFGElementRef(), - currBldrCtx->blockCount(), + state = state->invalidateRegions(*LV, A, currBldrCtx->blockCount(), Pred->getLocationContext(), /*CausedByPointerEscape=*/true); } @@ -3910,8 +3902,7 @@ 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, getCFGElementRef(), - currBldrCtx->blockCount(), + state = state->invalidateRegions(*LV, A, currBldrCtx->blockCount(), Pred->getLocationContext(), /*CausedByPointerEscape=*/true); } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 6e52df5e90944..3d0a69a515ab8 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -21,19 +21,18 @@ using namespace ento; using llvm::APSInt; /// Optionally conjure and return a symbol for offset when processing -/// \p Elem. +/// an expression \p Expression. /// 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, - ConstCFGElementRef Elem, QualType Ty, - SValBuilder &svalBuilder, - unsigned Count, - const LocationContext *LCtx) { +static SVal conjureOffsetSymbolOnLocation( + SVal Symbol, SVal Other, Expr* Expression, SValBuilder &svalBuilder, + unsigned Count, const LocationContext *LCtx) { + QualType Ty = Expression->getType(); if (isa(Other) && Ty->isIntegralOrEnumerationType() && Symbol.isUnknown()) { - return svalBuilder.conjureSymbolVal(Elem, LCtx, Ty, Count); + return svalBuilder.conjureSymbolVal(Expression, LCtx, Ty, Count); } return Symbol; } @@ -66,7 +65,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // FIXME: Handle structs. if (RightV.isUnknown()) { unsigned Count = currBldrCtx->blockCount(); - RightV = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx, + RightV = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, Count); } // Simulate the effects of a "store": bind the value of the RHS @@ -85,11 +84,9 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // SymSymExpr. unsigned Count = currBldrCtx->blockCount(); RightV = conjureOffsetSymbolOnLocation( - RightV, LeftV, getCFGElementRef(), RHS->getType(), svalBuilder, - Count, LCtx); - LeftV = conjureOffsetSymbolOnLocation(LeftV, RightV, getCFGElementRef(), - LHS->getType(), svalBuilder, - Count, LCtx); + RightV, LeftV, RHS, svalBuilder, Count, LCtx); + LeftV = conjureOffsetSymbolOnLocation( + LeftV, RightV, LHS, svalBuilder, Count, LCtx); } // Although we don't yet model pointers-to-members, we do need to make @@ -168,8 +165,7 @@ 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(/*symbolTag=*/nullptr, - getCFGElementRef(), LCtx, LTy, + LHSVal = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, LTy, currBldrCtx->blockCount()); // However, we need to convert the symbol to the computation type. Result = svalBuilder.evalCast(LHSVal, CTy, LTy); @@ -463,9 +459,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( - /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType, - currBldrCtx->blockCount()); + DefinedOrUnknownSVal NewSym = + svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType, + currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, NewSym); } else // Else, bind to the derived region value. @@ -487,9 +483,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( - /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType, - currBldrCtx->blockCount()); + val = + svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType, + currBldrCtx->blockCount()); } state = state->BindExpr(CastE, LCtx, val); Bldr.generateNode(CastE, Pred, state); @@ -533,7 +529,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, if (CastE->isGLValue()) resultType = getContext().getPointerType(resultType); SVal result = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType, + /*symbolTag=*/nullptr, CastE, LCtx, resultType, currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, result); Bldr.generateNode(CastE, Pred, state); @@ -625,9 +621,8 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, Ty = getContext().getPointerType(Ty); } - InitVal = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, getCFGElementRef(), LC, Ty, - currBldrCtx->blockCount()); + InitVal = svalBuilder.conjureSymbolVal(nullptr, InitEx, LC, Ty, + currBldrCtx->blockCount()); } @@ -844,7 +839,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, } if (!hasValue) - V = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx, + V = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, currBldrCtx->blockCount()); // Generate a new node with the binding from the appropriate path. @@ -1126,9 +1121,9 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, // Conjure a new symbol if necessary to recover precision. if (Result.isUnknown()){ - DefinedOrUnknownSVal SymVal = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, - currBldrCtx->blockCount()); + DefinedOrUnknownSVal SymVal = + svalBuilder.conjureSymbolVal(nullptr, U, 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 5804dc17115b2..92ce3fa2225c8 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, getCFGElementRef(), - SFC, RegionTy, currBldrCtx->blockCount()); + return SVB.conjureSymbolVal(&TopLevelSymRegionTag, RetE, SFC, RegionTy, + currBldrCtx->blockCount()); } llvm_unreachable("Unhandled return value construction context!"); } @@ -975,11 +975,10 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // a custom global allocator. if (symVal.isUnknown()) { if (IsStandardGlobalOpNewFunction) - symVal = svalBuilder.getConjuredHeapSymbolVal(getCFGElementRef(), LCtx, - CNE->getType(), blockCount); + symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount); else - symVal = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, blockCount); + symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(), + blockCount); } CallEventManager &CEMgr = getStateManager().getCallEventManager(); @@ -1112,7 +1111,7 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred, } const LocationContext *LCtx = Pred->getLocationContext(); - SVal V = svalBuilder.conjureSymbolVal(getCFGElementRef(), LCtx, VD->getType(), + SVal V = svalBuilder.conjureSymbolVal(CS, 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 90625a96e9059..1a44ba4f49133 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -746,7 +746,6 @@ 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; @@ -789,7 +788,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, RegionAndSymbolInvalidationTraits ITraits; ITraits.setTrait(TargetR, RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion); - State = State->invalidateRegions(TargetR, Elem, Count, LCtx, + State = State->invalidateRegions(TargetR, E, Count, LCtx, /* CausesPointerEscape=*/false, nullptr, &Call, &ITraits); @@ -801,7 +800,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(Elem, LCtx, E->getType(), Count); + R = svalBuilder.getConjuredHeapSymbolVal(E, LCtx, Count); const MemRegion *MR = R.getAsRegion()->StripCasts(); // Store the extent of the allocated object(s). @@ -825,7 +824,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, State = setDynamicExtent(State, MR, Size.castAs()); } else { - R = svalBuilder.conjureSymbolVal(Elem, LCtx, ResultTy, Count); + R = svalBuilder.conjureSymbolVal(nullptr, E, 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 f2e5a163afb62..9426e0afd65a0 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, ConstCFGElementRef elem, SVal elementV, + const ObjCForCollectionStmt *S, const Stmt *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,7 +110,6 @@ 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()); @@ -133,12 +132,11 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, StmtNodeBuilder Bldr(dstLocation, Tmp, *currBldrCtx); if (!isContainerNull) - populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, - elemRef, elementV, SymMgr, currBldrCtx, - Bldr, + populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, elem, + elementV, SymMgr, currBldrCtx, Bldr, /*hasElements=*/true); - populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, elemRef, + populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, elem, elementV, SymMgr, currBldrCtx, Bldr, /*hasElements=*/false); diff --git a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp index 2cddf1faa1619..9e42801760622 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,13 +24,31 @@ 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, - ConstCFGElementRef Elem) { + unsigned BlockCount, const Stmt *LoopStmt) { + + assert((isa(LoopStmt))); + // 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. @@ -75,8 +93,9 @@ ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, RegionAndSymbolInvalidationTraits::TK_PreserveContents); } - return PrevState->invalidateRegions(Regions, Elem, BlockCount, LCtx, true, - nullptr, nullptr, &ITraits); + return PrevState->invalidateRegions(Regions, getLoopCondition(LoopStmt), + 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 19af8993f41ed..492209d4d2bf0 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, ConstCFGElementRef Elem, unsigned Count, + RegionList Regions, const Stmt *S, 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, Elem, Count, LCtx, CausedByPointerEscape, IS, + return invalidateRegions(Values, S, Count, LCtx, CausedByPointerEscape, IS, Call, ITraits); } ProgramStateRef ProgramState::invalidateRegions( - ValueList Values, ConstCFGElementRef Elem, unsigned Count, + ValueList Values, const Stmt *S, 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, Elem, Count, LCtx, Call, *IS, *ITraits, + getStore(), Values, S, 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 b6928372e2716..1cc9cb84cbfa4 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, 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, + 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, RegionAndSymbolInvalidationTraits &ITraits, InvalidatedRegions *Invalidated, InvalidatedRegions *InvalidatedTopLevel) override; @@ -1147,7 +1147,7 @@ RegionStoreManager::removeSubRegionBindings(LimitedRegionBindingsConstRef B, namespace { class InvalidateRegionsWorker : public ClusterAnalysis { - ConstCFGElementRef Elem; + const Stmt *S; unsigned Count; const LocationContext *LCtx; InvalidatedSymbols &IS; @@ -1156,13 +1156,12 @@ class InvalidateRegionsWorker : public ClusterAnalysis GlobalsFilterKind GlobalsFilter; public: InvalidateRegionsWorker(RegionStoreManager &rm, ProgramStateManager &stateMgr, - RegionBindingsRef b, ConstCFGElementRef elem, - unsigned count, const LocationContext *lctx, - InvalidatedSymbols &is, + RegionBindingsRef b, const Stmt *S, unsigned count, + const LocationContext *lctx, InvalidatedSymbols &is, RegionAndSymbolInvalidationTraits &ITraitsIn, StoreManager::InvalidatedRegions *r, GlobalsFilterKind GFK) - : ClusterAnalysis(rm, stateMgr, b), Elem(elem), + : ClusterAnalysis(rm, stateMgr, b), S(S), Count(count), LCtx(lctx), IS(is), ITraits(ITraitsIn), Regions(r), GlobalsFilter(GFK) {} @@ -1297,7 +1296,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, Elem, LCtx, Ctx.IntTy, Count); + svalBuilder.conjureSymbolVal(baseR, S, LCtx, Ctx.IntTy, Count); B = B.addBinding(baseR, BindingKey::Default, V); return; } @@ -1319,7 +1318,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, Elem, LCtx, Ctx.IntTy, Count); + svalBuilder.conjureSymbolVal(baseR, S, LCtx, Ctx.IntTy, Count); B = B.addBinding(baseR, BindingKey::Default, V); return; } @@ -1387,13 +1386,13 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, conjure_default: // Set the default value of the array to conjured symbol. DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal( - baseR, Elem, LCtx, AT->getElementType(), Count); + baseR, S, LCtx, AT->getElementType(), Count); B = B.addBinding(baseR, BindingKey::Default, V); return; } DefinedOrUnknownSVal V = - svalBuilder.conjureSymbolVal(baseR, Elem, LCtx, T, Count); + svalBuilder.conjureSymbolVal(baseR, S, LCtx, T, Count); assert(SymbolManager::canSymbolicate(T) || V.isUnknown()); B = B.addBinding(baseR, BindingKey::Direct, V); } @@ -1422,15 +1421,15 @@ bool InvalidateRegionsWorker::includeEntireMemorySpace(const MemRegion *Base) { } RegionBindingsRef RegionStoreManager::invalidateGlobalRegion( - MemRegion::Kind K, ConstCFGElementRef Elem, unsigned Count, + MemRegion::Kind K, const Stmt *S, 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, Elem, LCtx, - /* type does not matter */ Ctx.IntTy, Count); + SVal V = + svalBuilder.conjureSymbolVal(/* symbolTag = */ (const void *)GS, S, LCtx, + /* type does not matter */ Ctx.IntTy, Count); B = B.removeBinding(GS) .addBinding(BindingKey::Make(GS, BindingKey::Default), V); @@ -1465,7 +1464,7 @@ void RegionStoreManager::populateWorkList(InvalidateRegionsWorker &W, } StoreRef RegionStoreManager::invalidateRegions( - Store store, ArrayRef Values, ConstCFGElementRef Elem, unsigned Count, + Store store, ArrayRef Values, const Stmt *S, unsigned Count, const LocationContext *LCtx, const CallEvent *Call, InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits, InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated) { @@ -1480,7 +1479,7 @@ StoreRef RegionStoreManager::invalidateRegions( } RegionBindingsRef B = getRegionBindings(store); - InvalidateRegionsWorker W(*this, StateMgr, B, Elem, Count, LCtx, IS, ITraits, + InvalidateRegionsWorker W(*this, StateMgr, B, S, Count, LCtx, IS, ITraits, Invalidated, GlobalsFilter); // Scan the bindings and generate the clusters. @@ -1500,12 +1499,12 @@ StoreRef RegionStoreManager::invalidateRegions( // TODO: This could possibly be more precise with modules. switch (GlobalsFilter) { case GFK_All: - B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind, Elem, + B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind, S, Count, LCtx, B, Invalidated); [[fallthrough]]; case GFK_SystemOnly: - B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, Elem, - Count, LCtx, B, Invalidated); + B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, S, 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 f1f842e64ed39..eb5054708fece 100644 --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -152,11 +152,9 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion *region) { } DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag, - ConstCFGElementRef elem, + const Expr *Ex, 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()) @@ -168,11 +166,11 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag, if (Ex->isGLValue()) T = LCtx->getAnalysisDeclContext()->getASTContext().getPointerType(ExType); - return conjureSymbolVal(SymbolTag, elem, LCtx, T, Count); + return conjureSymbolVal(SymbolTag, Ex, LCtx, T, Count); } DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, - ConstCFGElementRef elem, + const Stmt *St, const LocationContext *LCtx, QualType type, unsigned count) { @@ -182,7 +180,7 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, if (!SymbolManager::canSymbolicate(type)) return UnknownVal(); - SymbolRef sym = SymMgr.conjureSymbol(elem, LCtx, type, count, symbolTag); + SymbolRef sym = SymMgr.conjureSymbol(St, LCtx, type, count, symbolTag); if (Loc::isLocType(type)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); @@ -190,7 +188,7 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, return nonloc::SymbolVal(sym); } -DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(ConstCFGElementRef elem, +DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt, const LocationContext *LCtx, QualType type, unsigned visitCount) { @@ -200,7 +198,7 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(ConstCFGElementRef elem, if (!SymbolManager::canSymbolicate(type)) return UnknownVal(); - SymbolRef sym = SymMgr.conjureSymbol(elem, LCtx, type, visitCount); + SymbolRef sym = SymMgr.conjureSymbol(stmt, LCtx, type, visitCount); if (Loc::isLocType(type)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); @@ -208,7 +206,14 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(ConstCFGElementRef elem, return nonloc::SymbolVal(sym); } -DefinedSVal SValBuilder::getConjuredHeapSymbolVal(ConstCFGElementRef elem, +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, const LocationContext *LCtx, QualType type, unsigned VisitCount) { @@ -220,7 +225,7 @@ DefinedSVal SValBuilder::getConjuredHeapSymbolVal(ConstCFGElementRef elem, return makeZeroVal(type).castAs(); } - SymbolRef sym = SymMgr.conjureSymbol(elem, LCtx, type, VisitCount); + SymbolRef sym = SymMgr.conjureSymbol(E, 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 a6ade661d04a2..a4648f5922ef1 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 (auto *S = getStmt()) + if (S) 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 deleted file mode 100644 index 7d7a658ef441b..0000000000000 --- a/clang/test/Analysis/PR57270.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// 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 5dcb6274b071a..bf4a12a0e0fe2 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 2cea5f705f116..13459699a06f6 100644 --- a/clang/test/Analysis/dump_egraph.cpp +++ b/clang/test/Analysis/dump_egraph.cpp @@ -24,3 +24,4 @@ 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 267980c3b20c8..d1615e6cc6c9a 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 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(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(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 CFG element 'CFGNewAllocator\(int \*\)'$}}}} + 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\]'$}}}} // 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 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\(\)'$}}}} + 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\(\)'$}}}} } class C_top_level { diff --git a/clang/test/Analysis/explain-svals.m b/clang/test/Analysis/explain-svals.m index e79ceabcacebb..e93258b3626a5 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 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\]'$}}}} + 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\]'$}}}} } void test_2(void) {