diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core')
26 files changed, 451 insertions, 472 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/APSIntType.cpp b/clang/lib/StaticAnalyzer/Core/APSIntType.cpp index a1de10c89ed9..1185cdaa044a 100644 --- a/clang/lib/StaticAnalyzer/Core/APSIntType.cpp +++ b/clang/lib/StaticAnalyzer/Core/APSIntType.cpp @@ -23,7 +23,7 @@ APSIntType::testInRange(const llvm::APSInt &Value, unsigned MinBits; if (AllowSignConversions) { if (Value.isSigned() && !IsUnsigned) - MinBits = Value.getMinSignedBits(); + MinBits = Value.getSignificantBits(); else MinBits = Value.getActiveBits(); @@ -33,7 +33,7 @@ APSIntType::testInRange(const llvm::APSInt &Value, // Unsigned integers can be converted to unsigned integers of the same width // or signed integers with one more bit. if (Value.isSigned()) - MinBits = Value.getMinSignedBits() - IsUnsigned; + MinBits = Value.getSignificantBits() - IsUnsigned; else MinBits = Value.getActiveBits() + !IsUnsigned; } diff --git a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp index ecfc7106560e..f9750db7b501 100644 --- a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -50,17 +50,14 @@ AnalysisManager::AnalysisManager(ASTContext &ASTCtx, Preprocessor &PP, AnalysisManager::~AnalysisManager() { FlushDiagnostics(); - for (PathDiagnosticConsumers::iterator I = PathConsumers.begin(), - E = PathConsumers.end(); I != E; ++I) { - delete *I; + for (PathDiagnosticConsumer *Consumer : PathConsumers) { + delete Consumer; } } void AnalysisManager::FlushDiagnostics() { PathDiagnosticConsumer::FilesMade filesMade; - for (PathDiagnosticConsumers::iterator I = PathConsumers.begin(), - E = PathConsumers.end(); - I != E; ++I) { - (*I)->FlushDiagnostics(&filesMade); + for (PathDiagnosticConsumer *Consumer : PathConsumers) { + Consumer->FlushDiagnostics(&filesMade); } } diff --git a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp index 40cdaef1bfa7..5924f6a671c2 100644 --- a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp +++ b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp @@ -97,8 +97,7 @@ const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) { FoldNodeTy* P = APSIntSet.FindNodeOrInsertPos(ID, InsertPos); if (!P) { - P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>(); - new (P) FoldNodeTy(X); + P = new (BPAlloc) FoldNodeTy(X); APSIntSet.InsertNode(P, InsertPos); } @@ -132,8 +131,7 @@ BasicValueFactory::getCompoundValData(QualType T, CompoundValData* D = CompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos); if (!D) { - D = (CompoundValData*) BPAlloc.Allocate<CompoundValData>(); - new (D) CompoundValData(T, Vals); + D = new (BPAlloc) CompoundValData(T, Vals); CompoundValDataSet.InsertNode(D, InsertPos); } @@ -151,8 +149,7 @@ BasicValueFactory::getLazyCompoundValData(const StoreRef &store, LazyCompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos); if (!D) { - D = (LazyCompoundValData*) BPAlloc.Allocate<LazyCompoundValData>(); - new (D) LazyCompoundValData(store, region); + D = new (BPAlloc) LazyCompoundValData(store, region); LazyCompoundValDataSet.InsertNode(D, InsertPos); } @@ -169,8 +166,7 @@ const PointerToMemberData *BasicValueFactory::getPointerToMemberData( PointerToMemberDataSet.FindNodeOrInsertPos(ID, InsertPos); if (!D) { - D = (PointerToMemberData *)BPAlloc.Allocate<PointerToMemberData>(); - new (D) PointerToMemberData(ND, L); + D = new (BPAlloc) PointerToMemberData(ND, L); PointerToMemberDataSet.InsertNode(D, InsertPos); } @@ -288,7 +284,7 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, if (V1.isSigned() && V1.isNegative()) return nullptr; - if (V1.isSigned() && Amt > V1.countLeadingZeros()) + if (V1.isSigned() && Amt > V1.countl_zero()) return nullptr; } @@ -358,8 +354,7 @@ BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) { FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos); if (!P) { - P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>(); - new (P) FoldNodeTy(std::make_pair(V, Data)); + P = new (BPAlloc) FoldNodeTy(std::make_pair(V, Data)); Map.InsertNode(P, InsertPos); } @@ -383,8 +378,7 @@ BasicValueFactory::getPersistentSValPair(const SVal& V1, const SVal& V2) { FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos); if (!P) { - P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>(); - new (P) FoldNodeTy(std::make_pair(V1, V2)); + P = new (BPAlloc) FoldNodeTy(std::make_pair(V1, V2)); Map.InsertNode(P, InsertPos); } diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index a7f149b87e79..dc9820b61f1f 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -296,26 +296,24 @@ std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ return {}; // Check if one of the parameters are set to the interesting symbol. - unsigned ArgIndex = 0; - for (CallExpr::const_arg_iterator I = CE->arg_begin(), - E = CE->arg_end(); I != E; ++I, ++ArgIndex){ - SVal SV = N->getSVal(*I); + for (auto [Idx, ArgExpr] : llvm::enumerate(CE->arguments())) { + SVal SV = N->getSVal(ArgExpr); // Check if the variable corresponding to the symbol is passed by value. SymbolRef AS = SV.getAsLocSymbol(); if (AS == Sym) { - return getMessageForArg(*I, ArgIndex); + return getMessageForArg(ArgExpr, Idx); } // Check if the parameter is a pointer to the symbol. if (std::optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) { // Do not attempt to dereference void*. - if ((*I)->getType()->isVoidPointerType()) + if (ArgExpr->getType()->isVoidPointerType()) continue; SVal PSV = N->getState()->getSVal(Reg->getRegion()); SymbolRef AS = PSV.getAsLocSymbol(); if (AS == Sym) { - return getMessageForArg(*I, ArgIndex); + return getMessageForArg(ArgExpr, Idx); } } } @@ -766,7 +764,7 @@ PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForSwitchOP( case Stmt::CaseStmtClass: { os << "Control jumps to 'case "; const auto *Case = cast<CaseStmt>(S); - const Expr *LHS = Case->getLHS()->IgnoreParenCasts(); + const Expr *LHS = Case->getLHS()->IgnoreParenImpCasts(); // Determine if it is an enum. bool GetRawInt = true; @@ -2627,8 +2625,7 @@ BugPathInfo *BugPathGetter::getNextBugPath() { const ExplodedNode *OrigN; std::tie(CurrentBugPath.Report, OrigN) = ReportNodes.pop_back_val(); - assert(PriorityMap.find(OrigN) != PriorityMap.end() && - "error node not accessible from root"); + assert(PriorityMap.contains(OrigN) && "error node not accessible from root"); // Create a new graph with a single path. This is the graph that will be // returned to the caller. diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 2b461acf9a73..42d03f67510c 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -1786,6 +1786,7 @@ PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ, void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const { static int tag = 0; ID.AddPointer(&tag); + ID.AddString(Message); ID.AddBoolean(Assumption); ID.Add(Constraint); } @@ -1796,8 +1797,12 @@ const char *TrackConstraintBRVisitor::getTag() { return "TrackConstraintBRVisitor"; } +bool TrackConstraintBRVisitor::isZeroCheck() const { + return !Assumption && Constraint.getAs<Loc>(); +} + bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const { - if (IsZeroCheck) + if (isZeroCheck()) return N->getState()->isNull(Constraint).isUnderconstrained(); return (bool)N->getState()->assume(Constraint, !Assumption); } @@ -1827,19 +1832,6 @@ PathDiagnosticPieceRef TrackConstraintBRVisitor::VisitNode( // the transition point. assert(!isUnderconstrained(N)); - // We found the transition point for the constraint. We now need to - // pretty-print the constraint. (work-in-progress) - SmallString<64> sbuf; - llvm::raw_svector_ostream os(sbuf); - - if (isa<Loc>(Constraint)) { - os << "Assuming pointer value is "; - os << (Assumption ? "non-null" : "null"); - } - - if (os.str().empty()) - return nullptr; - // Construct a new PathDiagnosticPiece. ProgramPoint P = N->getLocation(); @@ -1854,7 +1846,7 @@ PathDiagnosticPieceRef TrackConstraintBRVisitor::VisitNode( if (!L.isValid()) return nullptr; - auto X = std::make_shared<PathDiagnosticEventPiece>(L, os.str()); + auto X = std::make_shared<PathDiagnosticEventPiece>(L, Message); X->setTag(getTag()); return std::move(X); } @@ -2366,8 +2358,9 @@ public: // null. if (V.getAsLocSymbol(/*IncludeBaseRegions=*/true)) if (LVState->isNull(V).isConstrainedTrue()) - Report.addVisitor<TrackConstraintBRVisitor>(V.castAs<DefinedSVal>(), - false); + Report.addVisitor<TrackConstraintBRVisitor>( + V.castAs<DefinedSVal>(), + /*Assumption=*/false, "Assuming pointer value is null"); // Add visitor, which will suppress inline defensive checks. if (auto DV = V.getAs<DefinedSVal>()) @@ -2531,7 +2524,7 @@ public: Report.markInteresting(RegionRVal, Opts.Kind); Report.addVisitor<TrackConstraintBRVisitor>( loc::MemRegionVal(RegionRVal), - /*assumption=*/false); + /*Assumption=*/false, "Assuming pointer value is null"); Result.FoundSomethingToTrack = true; } } diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 8516e3643425..195940e5e643 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -287,6 +287,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit, const ProgramPointTag *Tag) const { + if (const Expr *E = getOriginExpr()) { if (IsPreVisit) return PreStmt(E, getLocationContext(), Tag); @@ -295,11 +296,13 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit, const Decl *D = getDecl(); assert(D && "Cannot get a program point without a statement or decl"); + assert(ElemRef.getParent() && + "Cannot get a program point without a CFGElementRef"); SourceLocation Loc = getSourceRange().getBegin(); if (IsPreVisit) - return PreImplicitCall(D, Loc, getLocationContext(), Tag); - return PostImplicitCall(D, Loc, getLocationContext(), Tag); + return PreImplicitCall(D, Loc, getLocationContext(), ElemRef, Tag); + return PostImplicitCall(D, Loc, getLocationContext(), ElemRef, Tag); } SVal CallEvent::getArgSVal(unsigned Index) const { @@ -1373,23 +1376,24 @@ void ObjCMethodCall::getInitialStackFrameContents( CallEventRef<> CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State, - const LocationContext *LCtx) { + const LocationContext *LCtx, + CFGBlock::ConstCFGElementRef ElemRef) { if (const auto *MCE = dyn_cast<CXXMemberCallExpr>(CE)) - return create<CXXMemberCall>(MCE, State, LCtx); + return create<CXXMemberCall>(MCE, State, LCtx, ElemRef); if (const auto *OpCE = dyn_cast<CXXOperatorCallExpr>(CE)) { const FunctionDecl *DirectCallee = OpCE->getDirectCallee(); if (const auto *MD = dyn_cast<CXXMethodDecl>(DirectCallee)) if (MD->isInstance()) - return create<CXXMemberOperatorCall>(OpCE, State, LCtx); + return create<CXXMemberOperatorCall>(OpCE, State, LCtx, ElemRef); } else if (CE->getCallee()->getType()->isBlockPointerType()) { - return create<BlockCall>(CE, State, LCtx); + return create<BlockCall>(CE, State, LCtx, ElemRef); } // Otherwise, it's a normal function call, static member function call, or // something we can't reason about. - return create<SimpleFunctionCall>(CE, State, LCtx); + return create<SimpleFunctionCall>(CE, State, LCtx, ElemRef); } CallEventRef<> @@ -1397,12 +1401,14 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State) { const LocationContext *ParentCtx = CalleeCtx->getParent(); const LocationContext *CallerCtx = ParentCtx->getStackFrame(); + CFGBlock::ConstCFGElementRef ElemRef = {CalleeCtx->getCallSiteBlock(), + CalleeCtx->getIndex()}; assert(CallerCtx && "This should not be used for top-level stack frames"); const Stmt *CallSite = CalleeCtx->getCallSite(); if (CallSite) { - if (CallEventRef<> Out = getCall(CallSite, State, CallerCtx)) + if (CallEventRef<> Out = getCall(CallSite, State, CallerCtx, ElemRef)) return Out; SValBuilder &SVB = State->getStateManager().getSValBuilder(); @@ -1411,10 +1417,11 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx, SVal ThisVal = State->getSVal(ThisPtr); if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) - return getCXXConstructorCall(CE, ThisVal.getAsRegion(), State, CallerCtx); + return getCXXConstructorCall(CE, ThisVal.getAsRegion(), State, CallerCtx, + ElemRef); else if (const auto *CIE = dyn_cast<CXXInheritedCtorInitExpr>(CallSite)) return getCXXInheritedConstructorCall(CIE, ThisVal.getAsRegion(), State, - CallerCtx); + CallerCtx, ElemRef); else { // All other cases are handled by getCall. llvm_unreachable("This is not an inlineable statement"); @@ -1444,19 +1451,20 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx, return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(), E.getAs<CFGBaseDtor>().has_value(), State, - CallerCtx); + CallerCtx, ElemRef); } CallEventRef<> CallEventManager::getCall(const Stmt *S, ProgramStateRef State, - const LocationContext *LC) { + const LocationContext *LC, + CFGBlock::ConstCFGElementRef ElemRef) { if (const auto *CE = dyn_cast<CallExpr>(S)) { - return getSimpleCall(CE, State, LC); + return getSimpleCall(CE, State, LC, ElemRef); } else if (const auto *NE = dyn_cast<CXXNewExpr>(S)) { - return getCXXAllocatorCall(NE, State, LC); + return getCXXAllocatorCall(NE, State, LC, ElemRef); } else if (const auto *DE = dyn_cast<CXXDeleteExpr>(S)) { - return getCXXDeallocatorCall(DE, State, LC); + return getCXXDeallocatorCall(DE, State, LC, ElemRef); } else if (const auto *ME = dyn_cast<ObjCMessageExpr>(S)) { - return getObjCMethodCall(ME, State, LC); + return getObjCMethodCall(ME, State, LC, ElemRef); } else { return nullptr; } diff --git a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp index 1e2532d27633..c25165cce128 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp @@ -14,6 +14,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/Basic/Builtins.h" #include "clang/Lex/Lexer.h" +#include "llvm/ADT/StringExtras.h" using namespace clang; using namespace ento; diff --git a/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp b/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp index d12c35ef156a..e9cc080caf5f 100644 --- a/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp +++ b/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp @@ -23,6 +23,7 @@ const char *const CXXObjectLifecycle = "C++ object lifecycle"; const char *const CXXMoveSemantics = "C++ move semantics"; const char *const SecurityError = "Security error"; const char *const UnusedCode = "Unused code"; +const char *const TaintedData = "Tainted data used"; } // namespace categories } // namespace ento } // namespace clang diff --git a/clang/lib/StaticAnalyzer/Core/Environment.cpp b/clang/lib/StaticAnalyzer/Core/Environment.cpp index 3d017b81762a..0102f743c911 100644 --- a/clang/lib/StaticAnalyzer/Core/Environment.cpp +++ b/clang/lib/StaticAnalyzer/Core/Environment.cpp @@ -17,9 +17,9 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtObjC.h" #include "clang/Analysis/AnalysisDeclContext.h" +#include "clang/Basic/JsonSupport.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" -#include "clang/Basic/JsonSupport.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index d274d4d16db3..f84da769d182 100644 --- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -233,8 +233,7 @@ void ExplodedNode::NodeGroup::addNode(ExplodedNode *N, ExplodedGraph &G) { ExplodedNode *Old = Storage.get<ExplodedNode *>(); BumpVectorContext &Ctx = G.getNodeAllocator(); - V = G.getAllocator().Allocate<ExplodedNodeVector>(); - new (V) ExplodedNodeVector(Ctx, 4); + V = new (G.getAllocator()) ExplodedNodeVector(Ctx, 4); V->push_back(Old, Ctx); Storage = V; @@ -408,7 +407,7 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L, } else { // Allocate a new node. - V = (NodeTy*) getAllocator().Allocate<NodeTy>(); + V = getAllocator().Allocate<NodeTy>(); } ++NumNodes; @@ -432,7 +431,7 @@ ExplodedNode *ExplodedGraph::createUncachedNode(const ProgramPoint &L, ProgramStateRef State, int64_t Id, bool IsSink) { - NodeTy *V = (NodeTy *) getAllocator().Allocate<NodeTy>(); + NodeTy *V = getAllocator().Allocate<NodeTy>(); new (V) NodeTy(L, State, Id, IsSink); return V; } @@ -488,7 +487,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, const ExplodedNode *N = WL2.pop_back_val(); // Skip this node if we have already processed it. - if (Pass2.find(N) != Pass2.end()) + if (Pass2.contains(N)) continue; // Create the corresponding node in the new graph and record the mapping @@ -509,9 +508,8 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, // Walk through the predecessors of 'N' and hook up their corresponding // nodes in the new graph (if any) to the freshly created node. - for (ExplodedNode::pred_iterator I = N->Preds.begin(), E = N->Preds.end(); - I != E; ++I) { - Pass2Ty::iterator PI = Pass2.find(*I); + for (const ExplodedNode *Pred : N->Preds) { + Pass2Ty::iterator PI = Pass2.find(Pred); if (PI == Pass2.end()) continue; @@ -522,17 +520,16 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, // been created, we should hook them up as successors. Otherwise, enqueue // the new nodes from the original graph that should have nodes created // in the new graph. - for (ExplodedNode::succ_iterator I = N->Succs.begin(), E = N->Succs.end(); - I != E; ++I) { - Pass2Ty::iterator PI = Pass2.find(*I); + for (const ExplodedNode *Succ : N->Succs) { + Pass2Ty::iterator PI = Pass2.find(Succ); if (PI != Pass2.end()) { const_cast<ExplodedNode *>(PI->second)->addPredecessor(NewN, *G); continue; } // Enqueue nodes to the worklist that were marked during pass 1. - if (Pass1.count(*I)) - WL2.push_back(*I); + if (Pass1.count(Succ)) + WL2.push_back(Succ); } } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 977c2b7f51fd..144f034a9dfe 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -65,6 +65,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/ImmutableSet.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Casting.h" @@ -386,15 +387,19 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded( State = finishObjectConstruction(State, MT, LC); State = State->BindExpr(Result, LC, *V); return State; - } else { + } else if (const ValueDecl *VD = MT->getExtendingDecl()) { StorageDuration SD = MT->getStorageDuration(); + assert(SD != SD_FullExpression); // If this object is bound to a reference with static storage duration, we // put it in a different region to prevent "address leakage" warnings. if (SD == SD_Static || SD == SD_Thread) { - TR = MRMgr.getCXXStaticTempObjectRegion(Init); + TR = MRMgr.getCXXStaticLifetimeExtendedObjectRegion(Init, VD); } else { - TR = MRMgr.getCXXTempObjectRegion(Init, LC); + TR = MRMgr.getCXXLifetimeExtendedObjectRegion(Init, VD, LC); } + } else { + assert(MT->getStorageDuration() == SD_FullExpression); + TR = MRMgr.getCXXTempObjectRegion(Init, LC); } } else { TR = MRMgr.getCXXTempObjectRegion(Init, LC); @@ -1242,7 +1247,7 @@ ExprEngine::prepareStateForArrayDestruction(const ProgramStateRef State, const QualType &ElementTy, const LocationContext *LCtx, SVal *ElementCountVal) { - assert(Region != nullptr && "Not-null region expected"); + assert(Region != nullptr && "Not-null region expected"); QualType Ty = ElementTy.getDesugaredType(getContext()); while (const auto *NTy = dyn_cast<ArrayType>(Ty)) @@ -1313,7 +1318,8 @@ void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE, else { NodeBuilder Bldr(Pred, Dst, *currBldrCtx); const LocationContext *LCtx = Pred->getLocationContext(); - PostImplicitCall PP(NE->getOperatorNew(), NE->getBeginLoc(), LCtx); + PostImplicitCall PP(NE->getOperatorNew(), NE->getBeginLoc(), LCtx, + getCFGElementRef()); Bldr.generateNode(PP, Pred->getState(), Pred); } Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); @@ -1361,7 +1367,8 @@ void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor, static SimpleProgramPointTag PT( "ExprEngine", "Skipping automatic 0 length array destruction, " "which shouldn't be in the CFG."); - PostImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, &PT); + PostImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, + getCFGElementRef(), &PT); NodeBuilder Bldr(Pred, Dst, *currBldrCtx); Bldr.generateSink(PP, Pred->getState(), Pred); return; @@ -1378,7 +1385,8 @@ void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor, static SimpleProgramPointTag PT("ExprEngine", "Prepare for object destruction"); - PreImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, &PT); + PreImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, getCFGElementRef(), + &PT); Pred = Bldr.generateNode(PP, state, Pred); if (!Pred) @@ -1406,7 +1414,7 @@ void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor, const CXXRecordDecl *RD = BTy->getAsCXXRecordDecl(); const CXXDestructorDecl *Dtor = RD->getDestructor(); - PostImplicitCall PP(Dtor, DE->getBeginLoc(), LCtx); + PostImplicitCall PP(Dtor, DE->getBeginLoc(), LCtx, getCFGElementRef()); NodeBuilder Bldr(Pred, Dst, *currBldrCtx); Bldr.generateNode(PP, Pred->getState(), Pred); return; @@ -1439,7 +1447,8 @@ void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor, static SimpleProgramPointTag PT( "ExprEngine", "Skipping 0 length array delete destruction"); - PostImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, &PT); + PostImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, + getCFGElementRef(), &PT); NodeBuilder Bldr(Pred, Dst, *currBldrCtx); Bldr.generateNode(PP, Pred->getState(), Pred); return; @@ -1453,7 +1462,8 @@ void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor, NodeBuilder Bldr(Pred, Dst, getBuilderContext()); static SimpleProgramPointTag PT("ExprEngine", "Prepare for object destruction"); - PreImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, &PT); + PreImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, + getCFGElementRef(), &PT); Pred = Bldr.generateNode(PP, State, Pred); if (!Pred) @@ -1513,7 +1523,8 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D, static SimpleProgramPointTag PT( "ExprEngine", "Skipping member 0 length array destruction, which " "shouldn't be in the CFG."); - PostImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, &PT); + PostImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, + getCFGElementRef(), &PT); NodeBuilder Bldr(Pred, Dst, *currBldrCtx); Bldr.generateSink(PP, Pred->getState(), Pred); return; @@ -1529,7 +1540,8 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D, static SimpleProgramPointTag PT("ExprEngine", "Prepare for object destruction"); - PreImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, &PT); + PreImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, getCFGElementRef(), + &PT); Pred = Bldr.generateNode(PP, State, Pred); if (!Pred) @@ -1565,7 +1577,7 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, NodeBuilder Bldr(Pred, Dst, *currBldrCtx); PostImplicitCall PP(D.getDestructorDecl(getContext()), D.getBindTemporaryExpr()->getBeginLoc(), - Pred->getLocationContext()); + Pred->getLocationContext(), getCFGElementRef()); Bldr.generateNode(PP, State, Pred); return; } @@ -2114,7 +2126,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, } } } - // FALLTHROUGH [[fallthrough]]; } @@ -2630,9 +2641,7 @@ static const Stmt *ResolveCondition(const Stmt *Condition, // The invariants are still shifting, but it is possible that the // last element in a CFGBlock is not a CFGStmt. Look for the last // CFGStmt as the value of the condition. - CFGBlock::const_reverse_iterator I = B->rbegin(), E = B->rend(); - for (; I != E; ++I) { - CFGElement Elem = *I; + for (CFGElement Elem : llvm::reverse(*B)) { std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>(); if (!CS) continue; @@ -2840,9 +2849,9 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) { if (std::optional<loc::GotoLabel> LV = V.getAs<loc::GotoLabel>()) { const LabelDecl *L = LV->getLabel(); - for (iterator I = builder.begin(), E = builder.end(); I != E; ++I) { - if (I.getLabel() == L) { - builder.generateNode(I, state); + for (iterator Succ : builder) { + if (Succ.getLabel() == L) { + builder.generateNode(Succ, state); return; } } @@ -2861,8 +2870,8 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) { // This is really a catch-all. We don't support symbolics yet. // FIXME: Implement dispatch for symbolic pointers. - for (iterator I = builder.begin(), E = builder.end(); I != E; ++I) - builder.generateNode(I, state); + for (iterator Succ : builder) + builder.generateNode(Succ, state); } void ExprEngine::processBeginOfFunction(NodeBuilderContext &BC, @@ -3795,12 +3804,9 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits { BugReporter &BR = static_cast<ExprEngine &>( N->getState()->getStateManager().getOwningEngine()).getBugReporter(); - const auto EQClasses = - llvm::make_range(BR.EQClasses_begin(), BR.EQClasses_end()); - - for (const auto &EQ : EQClasses) { - for (const auto &I : EQ.getReports()) { - const auto *PR = dyn_cast<PathSensitiveBugReport>(I.get()); + for (const auto &Class : BR.equivalenceClasses()) { + for (const auto &Report : Class.getReports()) { + const auto *PR = dyn_cast<PathSensitiveBugReport>(Report.get()); if (!PR) continue; const ExplodedNode *EN = PR->getErrorNode(); @@ -3898,10 +3904,9 @@ std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) { std::vector<const ExplodedNode *> Src; // Iterate through the reports and get their nodes. - for (BugReporter::EQClasses_iterator - EI = BR.EQClasses_begin(), EE = BR.EQClasses_end(); EI != EE; ++EI) { + for (const auto &Class : BR.equivalenceClasses()) { const auto *R = - dyn_cast<PathSensitiveBugReport>(EI->getReports()[0].get()); + dyn_cast<PathSensitiveBugReport>(Class.getReports()[0].get()); if (!R) continue; const auto *N = const_cast<ExplodedNode *>(R->getErrorNode()); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 6652c065e04f..2a47116db55a 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/AST/ExprCXX.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include <optional> @@ -133,11 +133,9 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, SVal location = LeftV; evalLoad(Tmp, B, LHS, *it, state, location); - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; - ++I) { - - state = (*I)->getState(); - const LocationContext *LCtx = (*I)->getLocationContext(); + for (ExplodedNode *N : Tmp) { + state = N->getState(); + const LocationContext *LCtx = N->getLocationContext(); SVal V = state->getSVal(LHS, LCtx); // Get the computation type. @@ -171,8 +169,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, currBldrCtx->blockCount()); // However, we need to convert the symbol to the computation type. Result = svalBuilder.evalCast(LHSVal, CTy, LTy); - } - else { + } else { // The left-hand side may bind to a different value then the // computation type. LHSVal = svalBuilder.evalCast(Result, LTy, CTy); @@ -185,7 +182,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, else state = state->BindExpr(B, LCtx, Result); - evalStore(Tmp2, B, LHS, *I, state, location, LHSVal); + evalStore(Tmp2, B, LHS, N, state, location, LHSVal); } } @@ -211,14 +208,12 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, if (const BlockDataRegion *BDR = dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) { - BlockDataRegion::referenced_vars_iterator I = BDR->referenced_vars_begin(), - E = BDR->referenced_vars_end(); - + auto ReferencedVars = BDR->referenced_vars(); auto CI = BD->capture_begin(); auto CE = BD->capture_end(); - for (; I != E; ++I) { - const VarRegion *capturedR = I.getCapturedRegion(); - const TypedValueRegion *originalR = I.getOriginalRegion(); + for (auto Var : ReferencedVars) { + const VarRegion *capturedR = Var.getCapturedRegion(); + const TypedValueRegion *originalR = Var.getOriginalRegion(); // If the capture had a copy expression, use the result of evaluating // that expression, otherwise use the original value. @@ -291,9 +286,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, if (CastE->getCastKind() == CK_LValueToRValue || CastE->getCastKind() == CK_LValueToRValueBitCast) { - for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); - I!=E; ++I) { - ExplodedNode *subExprNode = *I; + for (ExplodedNode *subExprNode : dstPreStmt) { ProgramStateRef state = subExprNode->getState(); const LocationContext *LCtx = subExprNode->getLocationContext(); evalLoad(Dst, CastE, CastE, subExprNode, state, state->getSVal(Ex, LCtx)); @@ -309,10 +302,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, T = ExCast->getTypeAsWritten(); StmtNodeBuilder Bldr(dstPreStmt, Dst, *currBldrCtx); - for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); - I != E; ++I) { - - Pred = *I; + for (ExplodedNode *Pred : dstPreStmt) { ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); @@ -883,8 +873,7 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, QualType T = Ex->getTypeOfArgument(); - for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); - I != E; ++I) { + for (ExplodedNode *N : CheckedSet) { if (Ex->getKind() == UETT_SizeOf) { if (!T->isIncompleteType() && !T->isConstantSizeType()) { assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); @@ -903,18 +892,17 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, APSInt Value = Ex->EvaluateKnownConstInt(getContext()); CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue()); - ProgramStateRef state = (*I)->getState(); - state = state->BindExpr(Ex, (*I)->getLocationContext(), - svalBuilder.makeIntVal(amt.getQuantity(), - Ex->getType())); - Bldr.generateNode(Ex, *I, state); + ProgramStateRef state = N->getState(); + state = state->BindExpr( + Ex, N->getLocationContext(), + svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType())); + Bldr.generateNode(Ex, N, state); } getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this); } -void ExprEngine::handleUOExtension(ExplodedNodeSet::iterator I, - const UnaryOperator *U, +void ExprEngine::handleUOExtension(ExplodedNode *N, const UnaryOperator *U, StmtNodeBuilder &Bldr) { // FIXME: We can probably just have some magic in Environment::getSVal() // that propagates values, instead of creating a new node here. @@ -924,10 +912,9 @@ void ExprEngine::handleUOExtension(ExplodedNodeSet::iterator I, // generate an extra node that just propagates the value of the // subexpression. const Expr *Ex = U->getSubExpr()->IgnoreParens(); - ProgramStateRef state = (*I)->getState(); - const LocationContext *LCtx = (*I)->getLocationContext(); - Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, - state->getSVal(Ex, LCtx))); + ProgramStateRef state = N->getState(); + const LocationContext *LCtx = N->getLocationContext(); + Bldr.generateNode(U, N, state->BindExpr(U, LCtx, state->getSVal(Ex, LCtx))); } void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred, @@ -939,13 +926,12 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred, ExplodedNodeSet EvalSet; StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx); - for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); - I != E; ++I) { + for (ExplodedNode *N : CheckedSet) { switch (U->getOpcode()) { default: { - Bldr.takeNodes(*I); + Bldr.takeNodes(N); ExplodedNodeSet Tmp; - VisitIncrementDecrementOperator(U, *I, Tmp); + VisitIncrementDecrementOperator(U, N, Tmp); Bldr.addNodes(Tmp); break; } @@ -960,10 +946,10 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred, // For all other types, UO_Real is an identity operation. assert (U->getType() == Ex->getType()); - ProgramStateRef state = (*I)->getState(); - const LocationContext *LCtx = (*I)->getLocationContext(); - Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, - state->getSVal(Ex, LCtx))); + ProgramStateRef state = N->getState(); + const LocationContext *LCtx = N->getLocationContext(); + Bldr.generateNode(U, N, + state->BindExpr(U, LCtx, state->getSVal(Ex, LCtx))); break; } @@ -975,10 +961,10 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred, break; } // For all other types, UO_Imag returns 0. - ProgramStateRef state = (*I)->getState(); - const LocationContext *LCtx = (*I)->getLocationContext(); + ProgramStateRef state = N->getState(); + const LocationContext *LCtx = N->getLocationContext(); SVal X = svalBuilder.makeZeroVal(Ex->getType()); - Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, X)); + Bldr.generateNode(U, N, state->BindExpr(U, LCtx, X)); break; } @@ -989,15 +975,15 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred, const ValueDecl *VD = DRE->getDecl(); if (isa<CXXMethodDecl, FieldDecl, IndirectFieldDecl>(VD)) { - ProgramStateRef State = (*I)->getState(); - const LocationContext *LCtx = (*I)->getLocationContext(); + ProgramStateRef State = N->getState(); + const LocationContext *LCtx = N->getLocationContext(); SVal SV = svalBuilder.getMemberPointer(cast<NamedDecl>(VD)); - Bldr.generateNode(U, *I, State->BindExpr(U, LCtx, SV)); + Bldr.generateNode(U, N, State->BindExpr(U, LCtx, SV)); break; } } // Explicitly proceed with default handler for this case cascade. - handleUOExtension(I, U, Bldr); + handleUOExtension(N, U, Bldr); break; } case UO_Plus: @@ -1005,7 +991,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred, [[fallthrough]]; case UO_Deref: case UO_Extension: { - handleUOExtension(I, U, Bldr); + handleUOExtension(N, U, Bldr); break; } @@ -1014,14 +1000,14 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred, case UO_Not: { assert (!U->isGLValue()); const Expr *Ex = U->getSubExpr()->IgnoreParens(); - ProgramStateRef state = (*I)->getState(); - const LocationContext *LCtx = (*I)->getLocationContext(); + ProgramStateRef state = N->getState(); + const LocationContext *LCtx = N->getLocationContext(); // Get the value of the subexpression. SVal V = state->getSVal(Ex, LCtx); if (V.isUnknownOrUndef()) { - Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V)); + Bldr.generateNode(U, N, state->BindExpr(U, LCtx, V)); break; } @@ -1058,7 +1044,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred, state = state->BindExpr(U, LCtx, Result); break; } - Bldr.generateNode(U, *I, state); + Bldr.generateNode(U, N, state); break; } } @@ -1084,10 +1070,9 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, ExplodedNodeSet Dst2; StmtNodeBuilder Bldr(Tmp, Dst2, *currBldrCtx); - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end();I!=E;++I) { - - state = (*I)->getState(); - assert(LCtx == (*I)->getLocationContext()); + for (ExplodedNode *N : Tmp) { + state = N->getState(); + assert(LCtx == N->getLocationContext()); SVal V2_untested = state->getSVal(Ex, LCtx); // Propagate unknown and undefined values. @@ -1095,9 +1080,9 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, state = state->BindExpr(U, LCtx, V2_untested); // Perform the store, so that the uninitialized value detection happens. - Bldr.takeNodes(*I); + Bldr.takeNodes(N); ExplodedNodeSet Dst3; - evalStore(Dst3, U, Ex, *I, state, loc, V2_untested); + evalStore(Dst3, U, Ex, N, state, loc, V2_untested); Bldr.addNodes(Dst3); continue; @@ -1163,9 +1148,9 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, state = state->BindExpr(U, LCtx, U->isPostfix() ? V2 : Result); // Perform the store. - Bldr.takeNodes(*I); + Bldr.takeNodes(N); ExplodedNodeSet Dst3; - evalStore(Dst3, U, Ex, *I, state, loc, Result); + evalStore(Dst3, U, Ex, N, state, loc, Result); Bldr.addNodes(Dst3); } Dst.insert(Dst2); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 6eb37287b136..7ee7c1394a67 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -20,6 +20,8 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Sequence.h" #include <optional> using namespace clang; @@ -59,40 +61,39 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, AlwaysReturnsLValue = true; } - assert(ThisRD); - if (ThisRD->isEmpty()) { - // Do nothing for empty classes. Otherwise it'd retrieve an UnknownVal - // and bind it and RegionStore would think that the actual value - // in this region at this offset is unknown. - return; - } - const LocationContext *LCtx = Pred->getLocationContext(); + const Expr *CallExpr = Call.getOriginExpr(); ExplodedNodeSet Dst; Bldr.takeNodes(Pred); - SVal V = Call.getArgSVal(0); - - // If the value being copied is not unknown, load from its location to get - // an aggregate rvalue. - if (std::optional<Loc> L = V.getAs<Loc>()) - V = Pred->getState()->getSVal(*L); - else - assert(V.isUnknownOrUndef()); + assert(ThisRD); + if (!ThisRD->isEmpty()) { + // Load the source value only for non-empty classes. + // Otherwise it'd retrieve an UnknownVal + // and bind it and RegionStore would think that the actual value + // in this region at this offset is unknown. + SVal V = Call.getArgSVal(0); - const Expr *CallExpr = Call.getOriginExpr(); - evalBind(Dst, CallExpr, Pred, ThisVal, V, true); + // If the value being copied is not unknown, load from its location to get + // an aggregate rvalue. + if (std::optional<Loc> L = V.getAs<Loc>()) + V = Pred->getState()->getSVal(*L); + else + assert(V.isUnknownOrUndef()); + evalBind(Dst, CallExpr, Pred, ThisVal, V, true); + } else { + Dst.Add(Pred); + } PostStmt PS(CallExpr, LCtx); - for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); - I != E; ++I) { - ProgramStateRef State = (*I)->getState(); + for (ExplodedNode *N : Dst) { + ProgramStateRef State = N->getState(); if (AlwaysReturnsLValue) State = State->BindExpr(CallExpr, LCtx, ThisVal); else State = bindReturnValue(Call, LCtx, State); - Bldr.generateNode(PS, State, *I); + Bldr.generateNode(PS, State, N); } } @@ -284,7 +285,8 @@ SVal ExprEngine::computeObjectUnderConstruction( CallOpts.IsTemporaryCtorOrDtor = true; if (MTE) { if (const ValueDecl *VD = MTE->getExtendingDecl()) { - assert(MTE->getStorageDuration() != SD_FullExpression); + StorageDuration SD = MTE->getStorageDuration(); + assert(SD != SD_FullExpression); if (!VD->getType()->isReferenceType()) { // We're lifetime-extended by a surrounding aggregate. // Automatic destructors aren't quite working in this case @@ -293,11 +295,15 @@ SVal ExprEngine::computeObjectUnderConstruction( // the MaterializeTemporaryExpr? CallOpts.IsTemporaryLifetimeExtendedViaAggregate = true; } - } - if (MTE->getStorageDuration() == SD_Static || - MTE->getStorageDuration() == SD_Thread) - return loc::MemRegionVal(MRMgr.getCXXStaticTempObjectRegion(E)); + if (SD == SD_Static || SD == SD_Thread) + return loc::MemRegionVal( + MRMgr.getCXXStaticLifetimeExtendedObjectRegion(E, VD)); + + return loc::MemRegionVal( + MRMgr.getCXXLifetimeExtendedObjectRegion(E, VD, LCtx)); + } + assert(MTE->getStorageDuration() == SD_FullExpression); } return loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); @@ -357,7 +363,8 @@ SVal ExprEngine::computeObjectUnderConstruction( }; if (const auto *CE = dyn_cast<CallExpr>(E)) { - CallEventRef<> Caller = CEMgr.getSimpleCall(CE, State, LCtx); + CallEventRef<> Caller = + CEMgr.getSimpleCall(CE, State, LCtx, getCFGElementRef()); if (std::optional<SVal> V = getArgLoc(Caller)) return *V; else @@ -365,14 +372,15 @@ SVal ExprEngine::computeObjectUnderConstruction( } else if (const auto *CCE = dyn_cast<CXXConstructExpr>(E)) { // Don't bother figuring out the target region for the future // constructor because we won't need it. - CallEventRef<> Caller = - CEMgr.getCXXConstructorCall(CCE, /*Target=*/nullptr, State, LCtx); + CallEventRef<> Caller = CEMgr.getCXXConstructorCall( + CCE, /*Target=*/nullptr, State, LCtx, getCFGElementRef()); if (std::optional<SVal> V = getArgLoc(Caller)) return *V; else break; } else if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) { - CallEventRef<> Caller = CEMgr.getObjCMethodCall(ME, State, LCtx); + CallEventRef<> Caller = + CEMgr.getObjCMethodCall(ME, State, LCtx, getCFGElementRef()); if (std::optional<SVal> V = getArgLoc(Caller)) return *V; else @@ -726,9 +734,9 @@ void ExprEngine::handleConstructor(const Expr *E, CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<> Call = CIE ? (CallEventRef<>)CEMgr.getCXXInheritedConstructorCall( - CIE, TargetRegion, State, LCtx) + CIE, TargetRegion, State, LCtx, getCFGElementRef()) : (CallEventRef<>)CEMgr.getCXXConstructorCall( - CE, TargetRegion, State, LCtx); + CE, TargetRegion, State, LCtx, getCFGElementRef()); ExplodedNodeSet DstPreVisit; getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, E, *this); @@ -737,10 +745,8 @@ void ExprEngine::handleConstructor(const Expr *E, if (CE) { // FIXME: Is it possible and/or useful to do this before PreStmt? StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx); - for (ExplodedNodeSet::iterator I = DstPreVisit.begin(), - E = DstPreVisit.end(); - I != E; ++I) { - ProgramStateRef State = (*I)->getState(); + for (ExplodedNode *N : DstPreVisit) { + ProgramStateRef State = N->getState(); if (CE->requiresZeroInitialization()) { // FIXME: Once we properly handle constructors in new-expressions, we'll // need to invalidate the region before setting a default value, to make @@ -757,7 +763,7 @@ void ExprEngine::handleConstructor(const Expr *E, State = State->bindDefaultZero(Target, LCtx); } - Bldr.generateNode(CE, *I, State, /*tag=*/nullptr, + Bldr.generateNode(CE, N, State, /*tag=*/nullptr, ProgramPoint::PreStmtKind); } } else { @@ -775,14 +781,12 @@ void ExprEngine::handleConstructor(const Expr *E, !CallOpts.IsArrayCtorOrDtor) { StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx); // FIXME: Handle other kinds of trivial constructors as well. - for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); - I != E; ++I) - performTrivialCopy(Bldr, *I, *Call); + for (ExplodedNode *N : DstPreCall) + performTrivialCopy(Bldr, N, *Call); } else { - for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); - I != E; ++I) - getCheckerManager().runCheckersForEvalCall(DstEvaluated, *I, *Call, *this, + for (ExplodedNode *N : DstPreCall) + getCheckerManager().runCheckersForEvalCall(DstEvaluated, N, *Call, *this, CallOpts); } @@ -797,7 +801,8 @@ void ExprEngine::handleConstructor(const Expr *E, StmtNodeBuilder Bldr(DstEvaluated, DstEvaluatedPostProcessed, *currBldrCtx); const AnalysisDeclContext *ADC = LCtx->getAnalysisDeclContext(); if (!ADC->getCFGBuildOptions().AddTemporaryDtors) { - if (llvm::isa_and_nonnull<CXXTempObjectRegion>(TargetRegion) && + if (llvm::isa_and_nonnull<CXXTempObjectRegion, + CXXLifetimeExtendedObjectRegion>(TargetRegion) && cast<CXXConstructorDecl>(Call->getDecl()) ->getParent() ->isAnyDestructorNoReturn()) { @@ -869,7 +874,8 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType, // it would interrupt the analysis instead. static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor"); // FIXME: PostImplicitCall with a null decl may crash elsewhere anyway. - PostImplicitCall PP(/*Decl=*/nullptr, S->getEndLoc(), LCtx, &T); + PostImplicitCall PP(/*Decl=*/nullptr, S->getEndLoc(), LCtx, + getCFGElementRef(), &T); NodeBuilder Bldr(Pred, Dst, *currBldrCtx); Bldr.generateNode(PP, Pred->getState(), Pred); return; @@ -894,8 +900,8 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType, } CallEventManager &CEMgr = getStateManager().getCallEventManager(); - CallEventRef<CXXDestructorCall> Call = - CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx); + CallEventRef<CXXDestructorCall> Call = CEMgr.getCXXDestructorCall( + DtorDecl, S, Dest, IsBaseDtor, State, LCtx, getCFGElementRef()); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), Call->getSourceRange().getBegin(), @@ -907,9 +913,8 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType, ExplodedNodeSet DstInvalidated; StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx); - for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); - I != E; ++I) - defaultEvalCall(Bldr, *I, *Call, CallOpts); + for (ExplodedNode *N : DstPreCall) + defaultEvalCall(Bldr, N, *Call, CallOpts); getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated, *Call, *this); @@ -925,7 +930,7 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, "Error evaluating New Allocator Call"); CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXAllocatorCall> Call = - CEMgr.getCXXAllocatorCall(CNE, State, LCtx); + CEMgr.getCXXAllocatorCall(CNE, State, LCtx, getCFGElementRef()); ExplodedNodeSet DstPreCall; getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, @@ -1023,7 +1028,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXAllocatorCall> Call = - CEMgr.getCXXAllocatorCall(CNE, State, LCtx); + CEMgr.getCXXAllocatorCall(CNE, State, LCtx, getCFGElementRef()); if (!AMgr.getAnalyzerOptions().MayInlineCXXAllocator) { // Invalidate placement args. @@ -1124,7 +1129,7 @@ void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXDeallocatorCall> Call = CEMgr.getCXXDeallocatorCall( - CDE, Pred->getState(), Pred->getLocationContext()); + CDE, Pred->getState(), Pred->getLocationContext(), getCFGElementRef()); ExplodedNodeSet DstPreCall; getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, *Call, *this); @@ -1188,18 +1193,13 @@ void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred, // If we created a new MemRegion for the lambda, we should explicitly bind // the captures. - unsigned Idx = 0; - CXXRecordDecl::field_iterator CurField = LE->getLambdaClass()->field_begin(); - for (LambdaExpr::const_capture_init_iterator i = LE->capture_init_begin(), - e = LE->capture_init_end(); - i != e; ++i, ++CurField, ++Idx) { - FieldDecl *FieldForCapture = *CurField; + for (auto const [Idx, FieldForCapture, InitExpr] : + llvm::zip(llvm::seq<unsigned>(0, -1), LE->getLambdaClass()->fields(), + LE->capture_inits())) { SVal FieldLoc = State->getLValue(FieldForCapture, V); SVal InitVal; if (!FieldForCapture->hasCapturedVLAType()) { - const Expr *InitExpr = *i; - assert(InitExpr && "Capture missing initialization expression"); // Capturing a 0 length array is a no-op, so we ignore it to get a more diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 54528475cb31..b987ce278936 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -374,17 +374,15 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { CleanedNodes.Add(CEBNode); } - for (ExplodedNodeSet::iterator I = CleanedNodes.begin(), - E = CleanedNodes.end(); I != E; ++I) { - + for (ExplodedNode *N : CleanedNodes) { // Step 4: Generate the CallExit and leave the callee's context. // CleanedNodes -> CEENode CallExitEnd Loc(calleeCtx, callerCtx); bool isNew; - ProgramStateRef CEEState = (*I == CEBNode) ? state : (*I)->getState(); + ProgramStateRef CEEState = (N == CEBNode) ? state : N->getState(); ExplodedNode *CEENode = G.getNode(Loc, CEEState, false, &isNew); - CEENode->addPredecessor(*I, G); + CEENode->addPredecessor(N, G); if (!isNew) return; @@ -610,15 +608,14 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, // Get the call in its initial state. We use this as a template to perform // all the checks. CallEventManager &CEMgr = getStateManager().getCallEventManager(); - CallEventRef<> CallTemplate - = CEMgr.getSimpleCall(CE, Pred->getState(), Pred->getLocationContext()); + CallEventRef<> CallTemplate = CEMgr.getSimpleCall( + CE, Pred->getState(), Pred->getLocationContext(), getCFGElementRef()); // Evaluate the function call. We try each of the checkers // to see if the can evaluate the function call. ExplodedNodeSet dstCallEvaluated; - for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); - I != E; ++I) { - evalCall(dstCallEvaluated, *I, *CallTemplate); + for (ExplodedNode *N : dstPreVisit) { + evalCall(dstCallEvaluated, N, *CallTemplate); } // Finally, perform the post-condition check of the CallExpr and store @@ -837,7 +834,8 @@ void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr, State = bindReturnValue(Call, Pred->getLocationContext(), State); // And make the result node. - Bldr.generateNode(Call.getProgramPoint(), State, Pred); + static SimpleProgramPointTag PT("ExprEngine", "Conservative eval call"); + Bldr.generateNode(Call.getProgramPoint(false, &PT), State, Pred); } ExprEngine::CallInlinePolicy diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp index 25c36e9aea24..8072531ef6fd 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp @@ -148,8 +148,8 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst) { CallEventManager &CEMgr = getStateManager().getCallEventManager(); - CallEventRef<ObjCMethodCall> Msg = - CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext()); + CallEventRef<ObjCMethodCall> Msg = CEMgr.getObjCMethodCall( + ME, Pred->getState(), Pred->getLocationContext(), getCFGElementRef()); // There are three cases for the receiver: // (1) it is definitely nil, diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index b4578385a147..0fe0c93dc016 100644 --- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -602,9 +602,9 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R, // Output any other meta data. - for (PathDiagnostic::meta_iterator I = D.meta_begin(), E = D.meta_end(); - I != E; ++I) { - os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n"; + for (const std::string &Metadata : + llvm::make_range(D.meta_begin(), D.meta_end())) { + os << "<tr><td></td><td>" << html::EscapeText(Metadata) << "</td></tr>\n"; } os << R"<<<( diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index 0c126a632f74..16db6b249dc9 100644 --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -39,6 +39,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CheckedArithmetic.h" @@ -73,8 +74,7 @@ RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); if (!R) { - R = A.Allocate<RegionTy>(); - new (R) RegionTy(arg1, superRegion); + R = new (A) RegionTy(arg1, superRegion); Regions.InsertNode(R, InsertPos); } @@ -90,8 +90,7 @@ RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2, auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); if (!R) { - R = A.Allocate<RegionTy>(); - new (R) RegionTy(arg1, arg2, superRegion); + R = new (A) RegionTy(arg1, arg2, superRegion); Regions.InsertNode(R, InsertPos); } @@ -109,8 +108,7 @@ RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2, auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); if (!R) { - R = A.Allocate<RegionTy>(); - new (R) RegionTy(arg1, arg2, arg3, superRegion); + R = new (A) RegionTy(arg1, arg2, arg3, superRegion); Regions.InsertNode(R, InsertPos); } @@ -161,6 +159,18 @@ const StackFrameContext *VarRegion::getStackFrame() const { return SSR ? SSR->getStackFrame() : nullptr; } +const StackFrameContext * +CXXLifetimeExtendedObjectRegion::getStackFrame() const { + const auto *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace()); + return SSR ? SSR->getStackFrame() : nullptr; +} + +const StackFrameContext *CXXTempObjectRegion::getStackFrame() const { + assert(isa<StackSpaceRegion>(getMemorySpace()) && + "A temporary object can only be allocated on the stack"); + return cast<StackSpaceRegion>(getMemorySpace())->getStackFrame(); +} + ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg) : DeclRegion(sReg, ObjCIvarRegionKind), IVD(ivd) { assert(IVD); @@ -392,6 +402,20 @@ void CXXTempObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const { ProfileRegion(ID, Ex, getSuperRegion()); } +void CXXLifetimeExtendedObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, + const Expr *E, + const ValueDecl *D, + const MemRegion *sReg) { + ID.AddPointer(E); + ID.AddPointer(D); + ID.AddPointer(sReg); +} + +void CXXLifetimeExtendedObjectRegion::Profile( + llvm::FoldingSetNodeID &ID) const { + ProfileRegion(ID, Ex, ExD, getSuperRegion()); +} + void CXXBaseObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD, bool IsVirtual, @@ -468,11 +492,9 @@ void BlockCodeRegion::dumpToStream(raw_ostream &os) const { void BlockDataRegion::dumpToStream(raw_ostream &os) const { os << "block_data{" << BC; os << "; "; - for (BlockDataRegion::referenced_vars_iterator - I = referenced_vars_begin(), - E = referenced_vars_end(); I != E; ++I) - os << "(" << I.getCapturedRegion() << "<-" << - I.getOriginalRegion() << ") "; + for (auto Var : referenced_vars()) + os << "(" << Var.getCapturedRegion() << "<-" << Var.getOriginalRegion() + << ") "; os << '}'; } @@ -486,6 +508,16 @@ void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const { << "S" << Ex->getID(getContext()) << '}'; } +void CXXLifetimeExtendedObjectRegion::dumpToStream(raw_ostream &os) const { + os << "lifetime_extended_object{" << getValueType() << ", "; + if (const IdentifierInfo *ID = ExD->getIdentifier()) + os << ID->getName(); + else + os << "D" << ExD->getID(); + os << ", " + << "S" << Ex->getID(getContext()) << '}'; +} + void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const { os << "Base{" << superRegion << ',' << getDecl()->getName() << '}'; } @@ -712,21 +744,17 @@ std::string MemRegion::getDescriptiveName(bool UseQuotes) const { } SourceRange MemRegion::sourceRange() const { - const auto *const VR = dyn_cast<VarRegion>(this->getBaseRegion()); - const auto *const FR = dyn_cast<FieldRegion>(this); - // Check for more specific regions first. - // FieldRegion - if (FR) { + if (auto *FR = dyn_cast<FieldRegion>(this)) { return FR->getDecl()->getSourceRange(); } - // VarRegion - else if (VR) { + + if (auto *VR = dyn_cast<VarRegion>(this->getBaseRegion())) { return VR->getDecl()->getSourceRange(); } + // Return invalid source range (can be checked by client). - else - return {}; + return {}; } //===----------------------------------------------------------------------===// @@ -750,6 +778,7 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR, case MemRegion::CXXBaseObjectRegionKind: case MemRegion::CXXDerivedObjectRegionKind: case MemRegion::CXXTempObjectRegionKind: + case MemRegion::CXXLifetimeExtendedObjectRegionKind: case MemRegion::CXXThisRegionKind: case MemRegion::ObjCIvarRegionKind: case MemRegion::NonParamVarRegionKind: @@ -776,49 +805,46 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR, // We currently don't model flexible array members (FAMs), which are: // - int array[]; of IncompleteArrayType // - int array[0]; of ConstantArrayType with size 0 - // - int array[1]; of ConstantArrayType with size 1 (*) - // (*): Consider single element array object members as FAM candidates only - // if the consider-single-element-arrays-as-flexible-array-members - // analyzer option is true. + // - int array[1]; of ConstantArrayType with size 1 // https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html - const auto isFlexibleArrayMemberCandidate = [this, - &SVB](QualType Ty) -> bool { - const ArrayType *AT = Ctx.getAsArrayType(Ty); + const auto isFlexibleArrayMemberCandidate = + [this](const ArrayType *AT) -> bool { if (!AT) return false; - if (isa<IncompleteArrayType>(AT)) - return true; - if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) { - using FAMKind = LangOptions::StrictFlexArraysLevelKind; - const FAMKind StrictFlexArraysLevel = + auto IsIncompleteArray = [](const ArrayType *AT) { + return isa<IncompleteArrayType>(AT); + }; + auto IsArrayOfZero = [](const ArrayType *AT) { + const auto *CAT = dyn_cast<ConstantArrayType>(AT); + return CAT && CAT->getSize() == 0; + }; + auto IsArrayOfOne = [](const ArrayType *AT) { + const auto *CAT = dyn_cast<ConstantArrayType>(AT); + return CAT && CAT->getSize() == 1; + }; + + using FAMKind = LangOptions::StrictFlexArraysLevelKind; + const FAMKind StrictFlexArraysLevel = Ctx.getLangOpts().getStrictFlexArraysLevel(); - const AnalyzerOptions &Opts = SVB.getAnalyzerOptions(); - const llvm::APInt &Size = CAT->getSize(); - - if (StrictFlexArraysLevel <= FAMKind::ZeroOrIncomplete && Size.isZero()) - return true; - - // The "-fstrict-flex-arrays" should have precedence over - // consider-single-element-arrays-as-flexible-array-members - // analyzer-config when checking single element arrays. - if (StrictFlexArraysLevel == FAMKind::Default) { - // FIXME: After clang-17 released, we should remove this branch. - if (Opts.ShouldConsiderSingleElementArraysAsFlexibleArrayMembers && - Size.isOne()) - return true; - } else { - // -fstrict-flex-arrays was specified, since it's not the default, so - // ignore analyzer-config. - if (StrictFlexArraysLevel <= FAMKind::OneZeroOrIncomplete && - Size.isOne()) - return true; - } - } - return false; + + // "Default": Any trailing array member is a FAM. + // Since we cannot tell at this point if this array is a trailing member + // or not, let's just do the same as for "OneZeroOrIncomplete". + if (StrictFlexArraysLevel == FAMKind::Default) + return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT); + + if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete) + return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT); + + if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete) + return IsArrayOfZero(AT) || IsIncompleteArray(AT); + + assert(StrictFlexArraysLevel == FAMKind::IncompleteOnly); + return IsIncompleteArray(AT); }; - if (isFlexibleArrayMemberCandidate(Ty)) + if (isFlexibleArrayMemberCandidate(Ctx.getAsArrayType(Ty))) return UnknownVal(); return Size; @@ -838,8 +864,7 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR, template <typename REG> const REG *MemRegionManager::LazyAllocate(REG*& region) { if (!region) { - region = A.Allocate<REG>(); - new (region) REG(*this); + region = new (A) REG(*this); } return region; @@ -848,8 +873,7 @@ const REG *MemRegionManager::LazyAllocate(REG*& region) { template <typename REG, typename ARG> const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) { if (!region) { - region = A.Allocate<REG>(); - new (region) REG(this, a); + region = new (A) REG(this, a); } return region; @@ -863,8 +887,7 @@ MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) { if (R) return R; - R = A.Allocate<StackLocalsSpaceRegion>(); - new (R) StackLocalsSpaceRegion(*this, STC); + R = new (A) StackLocalsSpaceRegion(*this, STC); return R; } @@ -876,8 +899,7 @@ MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) { if (R) return R; - R = A.Allocate<StackArgumentsSpaceRegion>(); - new (R) StackArgumentsSpaceRegion(*this, STC); + R = new (A) StackArgumentsSpaceRegion(*this, STC); return R; } @@ -898,8 +920,7 @@ const GlobalsSpaceRegion if (R) return R; - R = A.Allocate<StaticGlobalSpaceRegion>(); - new (R) StaticGlobalSpaceRegion(*this, CR); + R = new (A) StaticGlobalSpaceRegion(*this, CR); return R; } @@ -945,13 +966,11 @@ getStackOrCaptureRegionForDeclContext(const LocationContext *LC, if (const auto *BC = dyn_cast<BlockInvocationContext>(LC)) { const auto *BR = static_cast<const BlockDataRegion *>(BC->getData()); // FIXME: This can be made more efficient. - for (BlockDataRegion::referenced_vars_iterator - I = BR->referenced_vars_begin(), - E = BR->referenced_vars_end(); I != E; ++I) { - const TypedValueRegion *OrigR = I.getOriginalRegion(); + for (auto Var : BR->referenced_vars()) { + const TypedValueRegion *OrigR = Var.getOriginalRegion(); if (const auto *VR = dyn_cast<VarRegion>(OrigR)) { if (VR->getDecl() == VD) - return cast<VarRegion>(I.getCapturedRegion()); + return cast<VarRegion>(Var.getCapturedRegion()); } } } @@ -1058,13 +1077,16 @@ const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D, } } - return getSubRegion<NonParamVarRegion>(D, sReg); + return getNonParamVarRegion(D, sReg); } const NonParamVarRegion * MemRegionManager::getNonParamVarRegion(const VarDecl *D, const MemRegion *superR) { + // Prefer the definition over the canonical decl as the canonical form. D = D->getCanonicalDecl(); + if (const VarDecl *Def = D->getDefinition()) + D = Def; return getSubRegion<NonParamVarRegion>(D, superR); } @@ -1109,12 +1131,6 @@ MemRegionManager::getBlockDataRegion(const BlockCodeRegion *BC, return getSubRegion<BlockDataRegion>(BC, LC, blockCount, sReg); } -const CXXTempObjectRegion * -MemRegionManager::getCXXStaticTempObjectRegion(const Expr *Ex) { - return getSubRegion<CXXTempObjectRegion>( - Ex, getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, nullptr)); -} - const CompoundLiteralRegion* MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL, const LocationContext *LC) { @@ -1145,8 +1161,7 @@ MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx, auto *R = cast_or_null<ElementRegion>(data); if (!R) { - R = A.Allocate<ElementRegion>(); - new (R) ElementRegion(T, Idx, superRegion); + R = new (A) ElementRegion(T, Idx, superRegion); Regions.InsertNode(R, InsertPos); } @@ -1197,6 +1212,23 @@ MemRegionManager::getCXXTempObjectRegion(Expr const *E, return getSubRegion<CXXTempObjectRegion>(E, getStackLocalsRegion(SFC)); } +const CXXLifetimeExtendedObjectRegion * +MemRegionManager::getCXXLifetimeExtendedObjectRegion( + const Expr *Ex, const ValueDecl *VD, const LocationContext *LC) { + const StackFrameContext *SFC = LC->getStackFrame(); + assert(SFC); + return getSubRegion<CXXLifetimeExtendedObjectRegion>( + Ex, VD, getStackLocalsRegion(SFC)); +} + +const CXXLifetimeExtendedObjectRegion * +MemRegionManager::getCXXStaticLifetimeExtendedObjectRegion( + const Expr *Ex, const ValueDecl *VD) { + return getSubRegion<CXXLifetimeExtendedObjectRegion>( + Ex, VD, + getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, nullptr)); +} + /// Checks whether \p BaseClass is a valid virtual or direct non-virtual base /// class of the type of \p Super. static bool isValidBaseClass(const CXXRecordDecl *BaseClass, @@ -1283,7 +1315,7 @@ const MemSpaceRegion *MemRegion::getMemorySpace() const { SR = dyn_cast<SubRegion>(R); } - return dyn_cast<MemSpaceRegion>(R); + return cast<MemSpaceRegion>(R); } bool MemRegion::hasStackStorage() const { @@ -1298,10 +1330,6 @@ bool MemRegion::hasStackParametersStorage() const { return isa<StackArgumentsSpaceRegion>(getMemorySpace()); } -bool MemRegion::hasGlobalsOrParametersStorage() const { - return isa<StackArgumentsSpaceRegion, GlobalsSpaceRegion>(getMemorySpace()); -} - // Strips away all elements and fields. // Returns the base region of them. const MemRegion *MemRegion::getBaseRegion() const { @@ -1474,6 +1502,7 @@ static RegionOffset calculateOffset(const MemRegion *R) { case MemRegion::NonParamVarRegionKind: case MemRegion::ParamVarRegionKind: case MemRegion::CXXTempObjectRegionKind: + case MemRegion::CXXLifetimeExtendedObjectRegionKind: // Usual base regions. goto Finish; @@ -1664,10 +1693,8 @@ void BlockDataRegion::LazyInitializeReferencedVars() { using VarVec = BumpVector<const MemRegion *>; - auto *BV = A.Allocate<VarVec>(); - new (BV) VarVec(BC, NumBlockVars); - auto *BVOriginal = A.Allocate<VarVec>(); - new (BVOriginal) VarVec(BC, NumBlockVars); + auto *BV = new (A) VarVec(BC, NumBlockVars); + auto *BVOriginal = new (A) VarVec(BC, NumBlockVars); for (const auto *VD : ReferencedBlockVars) { const VarRegion *VR = nullptr; @@ -1715,10 +1742,13 @@ BlockDataRegion::referenced_vars_end() const { VecOriginal->end()); } +llvm::iterator_range<BlockDataRegion::referenced_vars_iterator> +BlockDataRegion::referenced_vars() const { + return llvm::make_range(referenced_vars_begin(), referenced_vars_end()); +} + const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const { - for (referenced_vars_iterator I = referenced_vars_begin(), - E = referenced_vars_end(); - I != E; ++I) { + for (const auto &I : referenced_vars()) { if (I.getCapturedRegion() == R) return I.getOriginalRegion(); } diff --git a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index a3b08d4581a5..bdf485364cef 100644 --- a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -367,10 +367,8 @@ void PlistPrinter::ReportMacroSubPieces(raw_ostream &o, unsigned indent, unsigned depth) { MacroPieces.push_back(&P); - for (PathPieces::const_iterator I = P.subPieces.begin(), - E = P.subPieces.end(); - I != E; ++I) { - ReportPiece(o, **I, indent, depth, /*includeControlFlow*/ false); + for (const auto &SubPiece : P.subPieces) { + ReportPiece(o, *SubPiece, indent, depth, /*includeControlFlow*/ false); } assert(P.getFixits().size() == 0 && @@ -500,12 +498,12 @@ static void printCoverage(const PathDiagnostic *D, // Mapping from file IDs to executed lines. const FilesToLineNumsMap &ExecutedLines = D->getExecutedLines(); - for (auto I = ExecutedLines.begin(), E = ExecutedLines.end(); I != E; ++I) { - unsigned FileKey = AddFID(FM, Fids, I->first); + for (const auto &[FID, Lines] : ExecutedLines) { + unsigned FileKey = AddFID(FM, Fids, FID); Indent(o, IndentLevel) << "<key>" << FileKey << "</key>\n"; Indent(o, IndentLevel) << "<array>\n"; IndentLevel++; - for (unsigned LineNo : I->second) { + for (unsigned LineNo : Lines) { Indent(o, IndentLevel); EmitInteger(o, LineNo) << "\n"; } @@ -597,8 +595,8 @@ void PlistDiagnostics::printBugPath(llvm::raw_ostream &o, const FIDMap &FM, o << " <array>\n"; - for (PathPieces::const_iterator E = Path.end(); I != E; ++I) - Printer.ReportDiag(o, **I); + for (const auto &Piece : llvm::make_range(I, Path.end())) + Printer.ReportDiag(o, *Piece); o << " </array>\n"; diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index 90ebbaad2bf3..f12f1a5ac970 100644 --- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -156,9 +156,8 @@ ProgramState::invalidateRegions(RegionList Regions, const CallEvent *Call, RegionAndSymbolInvalidationTraits *ITraits) const { SmallVector<SVal, 8> Values; - for (RegionList::const_iterator I = Regions.begin(), - End = Regions.end(); I != End; ++I) - Values.push_back(loc::MemRegionVal(*I)); + for (const MemRegion *Reg : Regions) + Values.push_back(loc::MemRegionVal(Reg)); return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape, IS, ITraits, Call); @@ -424,7 +423,7 @@ ProgramStateRef ProgramStateManager::getPersistentState(ProgramState &State) { freeStates.pop_back(); } else { - newState = (ProgramState*) Alloc.Allocate<ProgramState>(); + newState = Alloc.Allocate<ProgramState>(); } new (newState) ProgramState(State); StateSet.InsertNode(newState, InsertPos); @@ -556,22 +555,20 @@ bool ScanReachableSymbols::scan(nonloc::LazyCompoundVal val) { } bool ScanReachableSymbols::scan(nonloc::CompoundVal val) { - for (nonloc::CompoundVal::iterator I=val.begin(), E=val.end(); I!=E; ++I) - if (!scan(*I)) + for (SVal V : val) + if (!scan(V)) return false; return true; } bool ScanReachableSymbols::scan(const SymExpr *sym) { - for (SymExpr::symbol_iterator SI = sym->symbol_begin(), - SE = sym->symbol_end(); - SI != SE; ++SI) { - bool wasVisited = !visited.insert(*SI).second; + for (SymbolRef SubSym : sym->symbols()) { + bool wasVisited = !visited.insert(SubSym).second; if (wasVisited) continue; - if (!visitor.VisitSymbol(*SI)) + if (!visitor.VisitSymbol(SubSym)) return false; } @@ -630,10 +627,8 @@ bool ScanReachableSymbols::scan(const MemRegion *R) { // Regions captured by a block are also implicitly reachable. if (const BlockDataRegion *BDR = dyn_cast<BlockDataRegion>(R)) { - BlockDataRegion::referenced_vars_iterator I = BDR->referenced_vars_begin(), - E = BDR->referenced_vars_end(); - for ( ; I != E; ++I) { - if (!scan(I.getCapturedRegion())) + for (auto Var : BDR->referenced_vars()) { + if (!scan(Var.getCapturedRegion())) return false; } } diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index 1017dff2b0f3..5de99384449a 100644 --- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -1083,7 +1083,7 @@ areFeasible(ConstraintRangeTy Constraints) { /// /// \returns true if assuming this Sym to be true means equality of operands /// false if it means disequality of operands -/// None otherwise +/// std::nullopt otherwise std::optional<bool> meansEquality(const SymSymExpr *Sym) { switch (Sym->getOpcode()) { case BO_Sub: @@ -2678,7 +2678,18 @@ EquivalenceClass::simplify(SValBuilder &SVB, RangeSet::Factory &F, if (OldState == State) continue; - assert(find(State, MemberSym) == find(State, SimplifiedMemberSym)); + // Be aware that `SimplifiedMemberSym` might refer to an already dead + // symbol. In that case, the eqclass of that might not be the same as the + // eqclass of `MemberSym`. This is because the dead symbols are not + // preserved in the `ClassMap`, hence + // `find(State, SimplifiedMemberSym)` will result in a trivial eqclass + // compared to the eqclass of `MemberSym`. + // These eqclasses should be the same if `SimplifiedMemberSym` is alive. + // --> assert(find(State, MemberSym) == find(State, SimplifiedMemberSym)) + // + // Note that `MemberSym` must be alive here since that is from the + // `ClassMembers` where all the symbols are alive. + // Remove the old and more complex symbol. State = find(State, MemberSym).removeMember(State, MemberSym); diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 46948c12617c..c773cef30d5e 100644 --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -28,6 +28,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" #include <optional> #include <utility> @@ -231,7 +232,7 @@ public: void printJson(raw_ostream &Out, const char *NL = "\n", unsigned int Space = 0, bool IsDot = false) const { - for (iterator I = begin(); I != end(); ++I) { + for (iterator I = begin(), E = end(); I != E; ++I) { // TODO: We might need a .printJson for I.getKey() as well. Indent(Out, Space, IsDot) << "{ \"cluster\": \"" << I.getKey() << "\", \"pointer\": \"" @@ -239,18 +240,19 @@ public: ++Space; const ClusterBindings &CB = I.getData(); - for (ClusterBindings::iterator CI = CB.begin(); CI != CB.end(); ++CI) { + for (ClusterBindings::iterator CI = CB.begin(), CE = CB.end(); CI != CE; + ++CI) { Indent(Out, Space, IsDot) << "{ " << CI.getKey() << ", \"value\": "; CI.getData().printJson(Out, /*AddQuotes=*/true); Out << " }"; - if (std::next(CI) != CB.end()) + if (std::next(CI) != CE) Out << ','; Out << NL; } --Space; Indent(Out, Space, IsDot) << "]}"; - if (std::next(I) != end()) + if (std::next(I) != E) Out << ','; Out << NL; } @@ -644,16 +646,13 @@ public: // Part of public interface to class. void iterBindings(Store store, BindingsHandler& f) override { RegionBindingsRef B = getRegionBindings(store); - for (RegionBindingsRef::iterator I = B.begin(), E = B.end(); I != E; ++I) { - const ClusterBindings &Cluster = I.getData(); - for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end(); - CI != CE; ++CI) { - const BindingKey &K = CI.getKey(); - if (!K.isDirect()) + for (const auto &[Region, Cluster] : B) { + for (const auto &[Key, Value] : Cluster) { + if (!Key.isDirect()) continue; - if (const SubRegion *R = dyn_cast<SubRegion>(K.getRegion())) { + if (const SubRegion *R = dyn_cast<SubRegion>(Key.getRegion())) { // FIXME: Possibly incorporate the offset? - if (!f.HandleBinding(*this, store, R, CI.getData())) + if (!f.HandleBinding(*this, store, R, Value)) return; } } @@ -874,9 +873,8 @@ collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings, Length = FR->getDecl()->getBitWidthValue(SVB.getContext()); } - for (ClusterBindings::iterator I = Cluster.begin(), E = Cluster.end(); - I != E; ++I) { - BindingKey NextKey = I.getKey(); + for (const auto &StoreEntry : Cluster) { + BindingKey NextKey = StoreEntry.first; if (NextKey.getRegion() == TopKey.getRegion()) { // FIXME: This doesn't catch the case where we're really invalidating a // region with a symbolic offset. Example: @@ -887,7 +885,7 @@ collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings, NextKey.getOffset() - TopKey.getOffset() < Length) { // Case 1: The next binding is inside the region we're invalidating. // Include it. - Bindings.push_back(*I); + Bindings.push_back(StoreEntry); } else if (NextKey.getOffset() == TopKey.getOffset()) { // Case 2: The next binding is at the same offset as the region we're @@ -897,7 +895,7 @@ collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings, // FIXME: This is probably incorrect; consider invalidating an outer // struct whose first field is bound to a LazyCompoundVal. if (IncludeAllDefaultBindings || NextKey.isDirect()) - Bindings.push_back(*I); + Bindings.push_back(StoreEntry); } } else if (NextKey.hasSymbolicOffset()) { @@ -908,13 +906,13 @@ collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings, // we'll be conservative and include it. if (IncludeAllDefaultBindings || NextKey.isDirect()) if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions)) - Bindings.push_back(*I); + Bindings.push_back(StoreEntry); } else if (const SubRegion *BaseSR = dyn_cast<SubRegion>(Base)) { // Case 4: The next key is symbolic, but we changed a known // super-region. In this case the binding is certainly included. if (BaseSR->isSubRegionOf(Top)) if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions)) - Bindings.push_back(*I); + Bindings.push_back(StoreEntry); } } } @@ -956,10 +954,8 @@ RegionStoreManager::removeSubRegionBindings(RegionBindingsConstRef B, /*IncludeAllDefaultBindings=*/false); ClusterBindingsRef Result(*Cluster, CBFactory); - for (SmallVectorImpl<BindingPair>::const_iterator I = Bindings.begin(), - E = Bindings.end(); - I != E; ++I) - Result = Result.remove(I->first); + for (BindingKey Key : llvm::make_first_range(Bindings)) + Result = Result.remove(Key); // If we're invalidating a region with a symbolic offset, we need to make sure // we don't treat the base region as uninitialized anymore. @@ -1056,8 +1052,8 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, RegionAndSymbolInvalidationTraits::TK_PreserveContents); if (C) { - for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I) - VisitBinding(I.getData()); + for (SVal Val : llvm::make_second_range(*C)) + VisitBinding(Val); // Invalidate regions contents. if (!PreserveRegionsContents) @@ -1093,10 +1089,8 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, // BlockDataRegion? If so, invalidate captured variables that are passed // by reference. if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(baseR)) { - for (BlockDataRegion::referenced_vars_iterator - BI = BR->referenced_vars_begin(), BE = BR->referenced_vars_end() ; - BI != BE; ++BI) { - const VarRegion *VR = BI.getCapturedRegion(); + for (auto Var : BR->referenced_vars()) { + const VarRegion *VR = Var.getCapturedRegion(); const VarDecl *VD = VR->getDecl(); if (VD->hasAttr<BlocksAttr>() || !VD->hasLocalStorage()) { AddToWorkList(VR); @@ -1200,9 +1194,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, if (!C) goto conjure_default; - for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; - ++I) { - const BindingKey &BK = I.getKey(); + for (const auto &[BK, V] : *C) { std::optional<uint64_t> ROffset = BK.hasSymbolicOffset() ? std::optional<uint64_t>() : BK.getOffset(); @@ -1213,10 +1205,9 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, (UpperOverflow && (*ROffset >= LowerOffset || *ROffset < UpperOffset)) || (LowerOffset == UpperOffset && *ROffset == LowerOffset))) { - B = B.removeBinding(I.getKey()); + B = B.removeBinding(BK); // Bound symbolic regions need to be invalidated for dead symbol // detection. - SVal V = I.getData(); const MemRegion *R = V.getAsRegion(); if (isa_and_nonnull<SymbolicRegion>(R)) VisitBinding(V); @@ -1289,12 +1280,8 @@ RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K, void RegionStoreManager::populateWorkList(InvalidateRegionsWorker &W, ArrayRef<SVal> Values, InvalidatedRegions *TopLevelRegions) { - for (ArrayRef<SVal>::iterator I = Values.begin(), - E = Values.end(); I != E; ++I) { - SVal V = *I; - if (std::optional<nonloc::LazyCompoundVal> LCS = - V.getAs<nonloc::LazyCompoundVal>()) { - + for (SVal V : Values) { + if (auto LCS = V.getAs<nonloc::LazyCompoundVal>()) { for (SVal S : getInterestingValues(*LCS)) if (const MemRegion *R = S.getAsRegion()) W.AddToWorkList(R); @@ -1849,8 +1836,12 @@ std::optional<SVal> RegionStoreManager::getSValFromInitListExpr( // Go to the nested initializer list. ILE = IL; } - llvm_unreachable( - "Unhandled InitListExpr sub-expressions or invalid offsets."); + + assert(ILE); + + // FIXME: Unhandeled InitListExpr sub-expression, possibly constructing an + // enum? + return std::nullopt; } /// Returns an SVal, if possible, for the specified position in a string @@ -2277,10 +2268,7 @@ RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) { SmallVector<BindingPair, 32> Bindings; collectSubRegionBindings(Bindings, svalBuilder, *Cluster, LazyR, /*IncludeAllDefaultBindings=*/true); - for (SmallVectorImpl<BindingPair>::const_iterator I = Bindings.begin(), - E = Bindings.end(); - I != E; ++I) { - SVal V = I->second; + for (SVal V : llvm::make_second_range(Bindings)) { if (V.isUnknownOrUndef() || V.isConstant()) continue; @@ -2605,11 +2593,11 @@ std::optional<RegionBindingsRef> RegionStoreManager::tryBindSmallStruct( RegionBindingsRef NewB = B; - for (FieldVector::iterator I = Fields.begin(), E = Fields.end(); I != E; ++I){ - const FieldRegion *SourceFR = MRMgr.getFieldRegion(*I, LCV.getRegion()); + for (const FieldDecl *Field : Fields) { + const FieldRegion *SourceFR = MRMgr.getFieldRegion(Field, LCV.getRegion()); SVal V = getBindingForField(getRegionBindings(LCV.getStore()), SourceFR); - const FieldRegion *DestFR = MRMgr.getFieldRegion(*I, R); + const FieldRegion *DestFR = MRMgr.getFieldRegion(Field, R); NewB = bind(NewB, loc::MemRegionVal(DestFR), V); } @@ -2825,11 +2813,11 @@ void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR, if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(baseR)) SymReaper.markLive(SymR->getSymbol()); - for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I) { + for (const auto &[Key, Val] : *C) { // Element index of a binding key is live. - SymReaper.markElementIndicesLive(I.getKey().getRegion()); + SymReaper.markElementIndicesLive(Key.getRegion()); - VisitBinding(I.getData()); + VisitBinding(Val); } } @@ -2856,17 +2844,15 @@ void RemoveDeadBindingsWorker::VisitBinding(SVal V) { // All regions captured by a block are also live. if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) { - BlockDataRegion::referenced_vars_iterator I = BR->referenced_vars_begin(), - E = BR->referenced_vars_end(); - for ( ; I != E; ++I) - AddToWorkList(I.getCapturedRegion()); + for (auto Var : BR->referenced_vars()) + AddToWorkList(Var.getCapturedRegion()); } } // Update the set of live symbols. - for (auto SI = V.symbol_begin(), SE = V.symbol_end(); SI!=SE; ++SI) - SymReaper.markLive(*SI); + for (SymbolRef Sym : V.symbols()) + SymReaper.markLive(Sym); } bool RemoveDeadBindingsWorker::UpdatePostponed() { @@ -2874,12 +2860,10 @@ bool RemoveDeadBindingsWorker::UpdatePostponed() { // having done a scan. bool Changed = false; - for (auto I = Postponed.begin(), E = Postponed.end(); I != E; ++I) { - if (const SymbolicRegion *SR = *I) { - if (SymReaper.isLive(SR->getSymbol())) { - Changed |= AddToWorkList(SR); - *I = nullptr; - } + for (const SymbolicRegion *SR : Postponed) { + if (SymReaper.isLive(SR->getSymbol())) { + Changed |= AddToWorkList(SR); + SR = nullptr; } } @@ -2894,9 +2878,8 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store, W.GenerateClusters(); // Enqueue the region roots onto the worklist. - for (SymbolReaper::region_iterator I = SymReaper.region_begin(), - E = SymReaper.region_end(); I != E; ++I) { - W.AddToWorkList(*I); + for (const MemRegion *Reg : SymReaper.regions()) { + W.AddToWorkList(Reg); } do W.RunWorkList(); while (W.UpdatePostponed()); @@ -2904,9 +2887,7 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store, // We have now scanned the store, marking reachable regions and symbols // as live. We now remove all the regions that are dead from the store // as well as update DSymbols with the set symbols that are now dead. - for (RegionBindingsRef::iterator I = B.begin(), E = B.end(); I != E; ++I) { - const MemRegion *Base = I.getKey(); - + for (const MemRegion *Base : llvm::make_first_range(B)) { // If the cluster has been visited, we know the region has been marked. // Otherwise, remove the dead entry. if (!W.isVisited(Base)) diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index fed17c77f03d..4fe828bdf768 100644 --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -395,7 +395,6 @@ std::optional<SVal> SValBuilder::getConstantVal(const Expr *E) { return evalCast(*Val, CE->getType(), SE->getType()); } } - // FALLTHROUGH [[fallthrough]]; } diff --git a/clang/lib/StaticAnalyzer/Core/SVals.cpp b/clang/lib/StaticAnalyzer/Core/SVals.cpp index bc9c1e40d808..2a43a01ff886 100644 --- a/clang/lib/StaticAnalyzer/Core/SVals.cpp +++ b/clang/lib/StaticAnalyzer/Core/SVals.cpp @@ -174,6 +174,9 @@ public: QualType VisitSymbolicRegion(const SymbolicRegion *SR) { return Visit(SR->getSymbol()); } + QualType VisitAllocaRegion(const AllocaRegion *) { + return QualType{Context.VoidPtrTy}; + } QualType VisitTypedRegion(const TypedRegion *TR) { return TR->getLocationType(); } diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp b/clang/lib/StaticAnalyzer/Core/Store.cpp index fe1fa22af7ab..7577b7682a95 100644 --- a/clang/lib/StaticAnalyzer/Core/Store.cpp +++ b/clang/lib/StaticAnalyzer/Core/Store.cpp @@ -144,6 +144,7 @@ std::optional<const MemRegion *> StoreManager::castRegion(const MemRegion *R, case MemRegion::NonParamVarRegionKind: case MemRegion::ParamVarRegionKind: case MemRegion::CXXTempObjectRegionKind: + case MemRegion::CXXLifetimeExtendedObjectRegionKind: case MemRegion::CXXBaseObjectRegionKind: case MemRegion::CXXDerivedObjectRegionKind: return MakeElementRegion(cast<SubRegion>(R), PointeeTy); @@ -256,10 +257,8 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, const CastExpr *Cast) { // Walk through the cast path to create nested CXXBaseRegions. SVal Result = Derived; - for (CastExpr::path_const_iterator I = Cast->path_begin(), - E = Cast->path_end(); - I != E; ++I) { - Result = evalDerivedToBase(Result, (*I)->getType(), (*I)->isVirtual()); + for (const CXXBaseSpecifier *Base : Cast->path()) { + Result = evalDerivedToBase(Result, Base->getType(), Base->isVirtual()); } return Result; } diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp index 3e97f0c95fc3..9025e11a3f51 100644 --- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -170,8 +170,7 @@ SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) { void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { - SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>(); - new (SD) SymbolRegionValue(SymbolCounter, R); + SD = new (BPAlloc) SymbolRegionValue(SymbolCounter, R); DataSet.InsertNode(SD, InsertPos); ++SymbolCounter; } @@ -189,8 +188,7 @@ const SymbolConjured* SymbolManager::conjureSymbol(const Stmt *E, void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { - SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>(); - new (SD) SymbolConjured(SymbolCounter, E, LCtx, T, Count, SymbolTag); + SD = new (BPAlloc) SymbolConjured(SymbolCounter, E, LCtx, T, Count, SymbolTag); DataSet.InsertNode(SD, InsertPos); ++SymbolCounter; } @@ -206,8 +204,7 @@ SymbolManager::getDerivedSymbol(SymbolRef parentSymbol, void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { - SD = (SymExpr*) BPAlloc.Allocate<SymbolDerived>(); - new (SD) SymbolDerived(SymbolCounter, parentSymbol, R); + SD = new (BPAlloc) SymbolDerived(SymbolCounter, parentSymbol, R); DataSet.InsertNode(SD, InsertPos); ++SymbolCounter; } @@ -222,8 +219,7 @@ SymbolManager::getExtentSymbol(const SubRegion *R) { void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { - SD = (SymExpr*) BPAlloc.Allocate<SymbolExtent>(); - new (SD) SymbolExtent(SymbolCounter, R); + SD = new (BPAlloc) SymbolExtent(SymbolCounter, R); DataSet.InsertNode(SD, InsertPos); ++SymbolCounter; } @@ -240,8 +236,7 @@ SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T, void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { - SD = (SymExpr*) BPAlloc.Allocate<SymbolMetadata>(); - new (SD) SymbolMetadata(SymbolCounter, R, S, T, LCtx, Count, SymbolTag); + SD = new (BPAlloc) SymbolMetadata(SymbolCounter, R, S, T, LCtx, Count, SymbolTag); DataSet.InsertNode(SD, InsertPos); ++SymbolCounter; } @@ -257,8 +252,7 @@ SymbolManager::getCastSymbol(const SymExpr *Op, void *InsertPos; SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); if (!data) { - data = (SymbolCast*) BPAlloc.Allocate<SymbolCast>(); - new (data) SymbolCast(Op, From, To); + data = new (BPAlloc) SymbolCast(Op, From, To); DataSet.InsertNode(data, InsertPos); } @@ -275,8 +269,7 @@ const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs, SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); if (!data) { - data = (SymIntExpr*) BPAlloc.Allocate<SymIntExpr>(); - new (data) SymIntExpr(lhs, op, v, t); + data = new (BPAlloc) SymIntExpr(lhs, op, v, t); DataSet.InsertNode(data, InsertPos); } @@ -293,8 +286,7 @@ const IntSymExpr *SymbolManager::getIntSymExpr(const llvm::APSInt& lhs, SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); if (!data) { - data = (IntSymExpr*) BPAlloc.Allocate<IntSymExpr>(); - new (data) IntSymExpr(lhs, op, rhs, t); + data = new (BPAlloc) IntSymExpr(lhs, op, rhs, t); DataSet.InsertNode(data, InsertPos); } @@ -311,8 +303,7 @@ const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs, SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); if (!data) { - data = (SymSymExpr*) BPAlloc.Allocate<SymSymExpr>(); - new (data) SymSymExpr(lhs, op, rhs, t); + data = new (BPAlloc) SymSymExpr(lhs, op, rhs, t); DataSet.InsertNode(data, InsertPos); } @@ -327,8 +318,7 @@ const UnarySymExpr *SymbolManager::getUnarySymExpr(const SymExpr *Operand, void *InsertPos; SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); if (!data) { - data = (UnarySymExpr *)BPAlloc.Allocate<UnarySymExpr>(); - new (data) UnarySymExpr(Operand, Opc, T); + data = new (BPAlloc) UnarySymExpr(Operand, Opc, T); DataSet.InsertNode(data, InsertPos); } @@ -398,7 +388,7 @@ void SymbolReaper::markDependentsLive(SymbolRef sym) { if (const SymbolRefSmallVectorTy *Deps = SymMgr.getDependentSymbols(sym)) { for (const auto I : *Deps) { - if (TheLiving.find(I) != TheLiving.end()) + if (TheLiving.contains(I)) continue; markLive(I); } @@ -424,8 +414,8 @@ void SymbolReaper::markElementIndicesLive(const MemRegion *region) { SR = dyn_cast<SubRegion>(SR->getSuperRegion())) { if (const auto ER = dyn_cast<ElementRegion>(SR)) { SVal Idx = ER->getIndex(); - for (auto SI = Idx.symbol_begin(), SE = Idx.symbol_end(); SI != SE; ++SI) - markLive(*SI); + for (SymbolRef Sym : Idx.symbols()) + markLive(Sym); } } } diff --git a/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp index 05f4d19ebda0..71268af22e24 100644 --- a/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp @@ -86,10 +86,7 @@ public: } }; - for (std::vector<const PathDiagnostic *>::iterator I = Diags.begin(), - E = Diags.end(); - I != E; ++I) { - const PathDiagnostic *PD = *I; + for (const PathDiagnostic *PD : Diags) { std::string WarningMsg = (DiagOpts.ShouldDisplayDiagnosticName ? " [" + PD->getCheckerName() + "]" : "") |
