diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core')
22 files changed, 467 insertions, 188 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index 11be764633cf8..488126b0088a1 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -2922,7 +2922,7 @@ bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) { while (true) { // Create the equivalent node in the new graph with the same state // and location. - ExplodedNode *NewN = GNew->getNode(OrigN->getLocation(), OrigN->getState(), + ExplodedNode *NewN = GNew->createUncachedNode(OrigN->getLocation(), OrigN->getState(), OrigN->isSink()); // Store the mapping to the original node. @@ -3487,7 +3487,7 @@ LLVM_DUMP_METHOD void PathPieces::dump() const { } } -void PathDiagnosticCallPiece::dump() const { +LLVM_DUMP_METHOD void PathDiagnosticCallPiece::dump() const { llvm::errs() << "CALL\n--------------\n"; if (const Stmt *SLoc = getLocStmt(getLocation())) @@ -3498,26 +3498,26 @@ void PathDiagnosticCallPiece::dump() const { getLocation().dump(); } -void PathDiagnosticEventPiece::dump() const { +LLVM_DUMP_METHOD void PathDiagnosticEventPiece::dump() const { llvm::errs() << "EVENT\n--------------\n"; llvm::errs() << getString() << "\n"; llvm::errs() << " ---- at ----\n"; getLocation().dump(); } -void PathDiagnosticControlFlowPiece::dump() const { +LLVM_DUMP_METHOD void PathDiagnosticControlFlowPiece::dump() const { llvm::errs() << "CONTROL\n--------------\n"; getStartLocation().dump(); llvm::errs() << " ---- to ----\n"; getEndLocation().dump(); } -void PathDiagnosticMacroPiece::dump() const { +LLVM_DUMP_METHOD void PathDiagnosticMacroPiece::dump() const { llvm::errs() << "MACRO\n--------------\n"; // FIXME: Print which macro is being invoked. } -void PathDiagnosticLocation::dump() const { +LLVM_DUMP_METHOD void PathDiagnosticLocation::dump() const { if (!isValid()) { llvm::errs() << "<INVALID>\n"; return; diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index cf1e0a6a656cf..0e505463bb5e4 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -14,6 +14,7 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" +#include "clang/Analysis/CFGStmtMap.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" @@ -323,6 +324,9 @@ public: } PathDiagnosticLocation L(Ret, BRC.getSourceManager(), StackFrame); + if (!L.isValid() || !L.asLocation().isValid()) + return nullptr; + return new PathDiagnosticEventPiece(L, Out.str()); } @@ -828,8 +832,53 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ, // Check if this is inlined defensive checks. const LocationContext *CurLC =Succ->getLocationContext(); const LocationContext *ReportLC = BR.getErrorNode()->getLocationContext(); - if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) + if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) { BR.markInvalid("Suppress IDC", CurLC); + return nullptr; + } + + // Treat defensive checks in function-like macros as if they were an inlined + // defensive check. If the bug location is not in a macro and the + // terminator for the current location is in a macro then suppress the + // warning. + auto BugPoint = BR.getErrorNode()->getLocation().getAs<StmtPoint>(); + + if (!BugPoint) + return nullptr; + + SourceLocation BugLoc = BugPoint->getStmt()->getLocStart(); + if (BugLoc.isMacroID()) + return nullptr; + + ProgramPoint CurPoint = Succ->getLocation(); + const Stmt *CurTerminatorStmt = nullptr; + if (auto BE = CurPoint.getAs<BlockEdge>()) { + CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt(); + } else if (auto SP = CurPoint.getAs<StmtPoint>()) { + const Stmt *CurStmt = SP->getStmt(); + if (!CurStmt->getLocStart().isMacroID()) + return nullptr; + + CFGStmtMap *Map = CurLC->getAnalysisDeclContext()->getCFGStmtMap(); + CurTerminatorStmt = Map->getBlock(CurStmt)->getTerminator(); + } else { + return nullptr; + } + + if (!CurTerminatorStmt) + return nullptr; + + SourceLocation TerminatorLoc = CurTerminatorStmt->getLocStart(); + if (TerminatorLoc.isMacroID()) { + const SourceManager &SMgr = BRC.getSourceManager(); + std::pair<FileID, unsigned> TLInfo = SMgr.getDecomposedLoc(TerminatorLoc); + SrcMgr::SLocEntry SE = SMgr.getSLocEntry(TLInfo.first); + const SrcMgr::ExpansionInfo &EInfo = SE.getExpansion(); + if (EInfo.isFunctionMacroExpansion()) { + BR.markInvalid("Suppress Macro IDC", CurLC); + return nullptr; + } + } } return nullptr; } @@ -862,6 +911,15 @@ static const Expr *peelOffOuterExpr(const Expr *Ex, return peelOffOuterExpr(EWC->getSubExpr(), N); if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Ex)) return peelOffOuterExpr(OVE->getSourceExpr(), N); + if (auto *POE = dyn_cast<PseudoObjectExpr>(Ex)) { + auto *PropRef = dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm()); + if (PropRef && PropRef->isMessagingGetter()) { + const Expr *GetterMessageSend = + POE->getSemanticExpr(POE->getNumSemanticExprs() - 1); + assert(isa<ObjCMessageExpr>(GetterMessageSend)); + return peelOffOuterExpr(GetterMessageSend, N); + } + } // Peel off the ternary operator. if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(Ex)) { @@ -1494,20 +1552,6 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, return event; } - -// FIXME: Copied from ExprEngineCallAndReturn.cpp. -static bool isInStdNamespace(const Decl *D) { - const DeclContext *DC = D->getDeclContext()->getEnclosingNamespaceContext(); - const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC); - if (!ND) - return false; - - while (const NamespaceDecl *Parent = dyn_cast<NamespaceDecl>(ND->getParent())) - ND = Parent; - - return ND->isStdNamespace(); -} - std::unique_ptr<PathDiagnosticPiece> LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, const ExplodedNode *N, @@ -1518,7 +1562,7 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, AnalyzerOptions &Options = Eng.getAnalysisManager().options; const Decl *D = N->getLocationContext()->getDecl(); - if (isInStdNamespace(D)) { + if (AnalysisDeclContext::isInStdNamespace(D)) { // Skip reports within the 'std' namespace. Although these can sometimes be // the user's fault, we currently don't report them very well, and // Note that this will not help for any other data structure libraries, like @@ -1552,12 +1596,6 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, } } - // The analyzer issues a false positive on - // std::basic_string<uint8_t> v; v.push_back(1); - // and - // std::u16string s; s += u'a'; - // because we cannot reason about the internal invariants of the - // datastructure. for (const LocationContext *LCtx = N->getLocationContext(); LCtx; LCtx = LCtx->getParent()) { const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl()); @@ -1565,10 +1603,24 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, continue; const CXXRecordDecl *CD = MD->getParent(); + // The analyzer issues a false positive on + // std::basic_string<uint8_t> v; v.push_back(1); + // and + // std::u16string s; s += u'a'; + // because we cannot reason about the internal invariants of the + // datastructure. if (CD->getName() == "basic_string") { BR.markInvalid(getTag(), nullptr); return nullptr; } + + // The analyzer issues a false positive on + // std::shared_ptr<int> p(new int(1)); p = nullptr; + // because it does not reason properly about temporary destructors. + if (CD->getName() == "shared_ptr") { + BR.markInvalid(getTag(), nullptr); + return nullptr; + } } } } diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 69af09b25b6e2..52613186677ac 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -177,7 +177,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, // below for efficiency. if (PreserveArgs.count(Idx)) if (const MemRegion *MR = getArgSVal(Idx).getAsRegion()) - ETraits.setTrait(MR->StripCasts(), + ETraits.setTrait(MR->getBaseRegion(), RegionAndSymbolInvalidationTraits::TK_PreserveContents); // TODO: Factor this out + handle the lower level const pointers. @@ -210,6 +210,16 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit, return PostImplicitCall(D, Loc, getLocationContext(), Tag); } +bool CallEvent::isCalled(const CallDescription &CD) const { + assert(getKind() != CE_ObjCMessage && "Obj-C methods are not supported"); + if (!CD.II) + CD.II = &getState()->getStateManager().getContext().Idents.get(CD.FuncName); + if (getCalleeIdentifier() != CD.II) + return false; + return (CD.RequiredArgs == CallDescription::NoArgRequirement || + CD.RequiredArgs == getNumArgs()); +} + SVal CallEvent::getArgSVal(unsigned Index) const { const Expr *ArgE = getArgExpr(Index); if (!ArgE) @@ -668,9 +678,26 @@ ArrayRef<ParmVarDecl*> ObjCMethodCall::parameters() const { return D->parameters(); } -void -ObjCMethodCall::getExtraInvalidatedValues(ValueList &Values, - RegionAndSymbolInvalidationTraits *ETraits) const { +void ObjCMethodCall::getExtraInvalidatedValues( + ValueList &Values, RegionAndSymbolInvalidationTraits *ETraits) const { + + // If the method call is a setter for property known to be backed by + // an instance variable, don't invalidate the entire receiver, just + // the storage for that instance variable. + if (const ObjCPropertyDecl *PropDecl = getAccessedProperty()) { + if (const ObjCIvarDecl *PropIvar = PropDecl->getPropertyIvarDecl()) { + SVal IvarLVal = getState()->getLValue(PropIvar, getReceiverSVal()); + const MemRegion *IvarRegion = IvarLVal.getAsRegion(); + ETraits->setTrait( + IvarRegion, + RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion); + ETraits->setTrait(IvarRegion, + RegionAndSymbolInvalidationTraits::TK_SuppressEscape); + Values.push_back(IvarLVal); + return; + } + } + Values.push_back(getReceiverSVal()); } @@ -730,6 +757,18 @@ const PseudoObjectExpr *ObjCMethodCall::getContainingPseudoObjectExpr() const { return ObjCMessageDataTy::getFromOpaqueValue(Data).getPointer(); } +static const Expr * +getSyntacticFromForPseudoObjectExpr(const PseudoObjectExpr *POE) { + const Expr *Syntactic = POE->getSyntacticForm(); + + // This handles the funny case of assigning to the result of a getter. + // This can happen if the getter returns a non-const reference. + if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(Syntactic)) + Syntactic = BO->getLHS(); + + return Syntactic; +} + ObjCMessageKind ObjCMethodCall::getMessageKind() const { if (!Data) { @@ -739,12 +778,7 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const { // Check if parent is a PseudoObjectExpr. if (const PseudoObjectExpr *POE = dyn_cast_or_null<PseudoObjectExpr>(S)) { - const Expr *Syntactic = POE->getSyntacticForm(); - - // This handles the funny case of assigning to the result of a getter. - // This can happen if the getter returns a non-const reference. - if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(Syntactic)) - Syntactic = BO->getLHS(); + const Expr *Syntactic = getSyntacticFromForPseudoObjectExpr(POE); ObjCMessageKind K; switch (Syntactic->getStmtClass()) { @@ -780,6 +814,27 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const { return static_cast<ObjCMessageKind>(Info.getInt()); } +const ObjCPropertyDecl *ObjCMethodCall::getAccessedProperty() const { + // Look for properties accessed with property syntax (foo.bar = ...) + if ( getMessageKind() == OCM_PropertyAccess) { + const PseudoObjectExpr *POE = getContainingPseudoObjectExpr(); + assert(POE && "Property access without PseudoObjectExpr?"); + + const Expr *Syntactic = getSyntacticFromForPseudoObjectExpr(POE); + auto *RefExpr = cast<ObjCPropertyRefExpr>(Syntactic); + + if (RefExpr->isExplicitProperty()) + return RefExpr->getExplicitProperty(); + } + + // Look for properties accessed with method syntax ([foo setBar:...]). + const ObjCMethodDecl *MD = getDecl(); + if (!MD || !MD->isPropertyAccessor()) + return nullptr; + + // Note: This is potentially quite slow. + return MD->findPropertyDecl(); +} bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl, Selector Sel) const { @@ -903,8 +958,30 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { // even if we don't actually have an implementation. if (!*Val) if (const ObjCMethodDecl *CompileTimeMD = E->getMethodDecl()) - if (CompileTimeMD->isPropertyAccessor()) - Val = IDecl->lookupInstanceMethod(Sel); + if (CompileTimeMD->isPropertyAccessor()) { + if (!CompileTimeMD->getSelfDecl() && + isa<ObjCCategoryDecl>(CompileTimeMD->getDeclContext())) { + // If the method is an accessor in a category, and it doesn't + // have a self declaration, first + // try to find the method in a class extension. This + // works around a bug in Sema where multiple accessors + // are synthesized for properties in class + // extensions that are redeclared in a category and the + // the implicit parameters are not filled in for + // the method on the category. + // This ensures we find the accessor in the extension, which + // has the implicit parameters filled in. + auto *ID = CompileTimeMD->getClassInterface(); + for (auto *CatDecl : ID->visible_extensions()) { + Val = CatDecl->getMethod(Sel, + CompileTimeMD->isInstanceMethod()); + if (*Val) + break; + } + } + if (!*Val) + Val = IDecl->lookupInstanceMethod(Sel); + } } const ObjCMethodDecl *MD = Val.getValue(); diff --git a/lib/StaticAnalyzer/Core/CheckerContext.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp index 5ec8bfa800744..548b06ef91fce 100644 --- a/lib/StaticAnalyzer/Core/CheckerContext.cpp +++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp @@ -35,6 +35,13 @@ StringRef CheckerContext::getCalleeName(const FunctionDecl *FunDecl) const { return funI->getName(); } +StringRef CheckerContext::getDeclDescription(const Decl *D) { + if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D)) + return "method"; + if (isa<BlockDecl>(D)) + return "anonymous block"; + return "function"; +} bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, StringRef Name) { diff --git a/lib/StaticAnalyzer/Core/CheckerHelpers.cpp b/lib/StaticAnalyzer/Core/CheckerHelpers.cpp index d6aeceb1457db..ed41914ebd054 100644 --- a/lib/StaticAnalyzer/Core/CheckerHelpers.cpp +++ b/lib/StaticAnalyzer/Core/CheckerHelpers.cpp @@ -75,8 +75,8 @@ bool clang::ento::containsBuiltinOffsetOf(const Stmt *S) { // Extract lhs and rhs from assignment statement std::pair<const clang::VarDecl *, const clang::Expr *> clang::ento::parseAssignment(const Stmt *S) { - const VarDecl *VD = 0; - const Expr *RHS = 0; + const VarDecl *VD = nullptr; + const Expr *RHS = nullptr; if (auto Assign = dyn_cast_or_null<BinaryOperator>(S)) { if (Assign->isAssignmentOp()) { diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index 008e8ef31cda7..d8382e88691a5 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -377,6 +377,40 @@ void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, EndAnalysisCheckers[i](G, BR, Eng); } +namespace { +struct CheckBeginFunctionContext { + typedef std::vector<CheckerManager::CheckBeginFunctionFunc> CheckersTy; + const CheckersTy &Checkers; + ExprEngine &Eng; + const ProgramPoint &PP; + + CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } + CheckersTy::const_iterator checkers_end() { return Checkers.end(); } + + CheckBeginFunctionContext(const CheckersTy &Checkers, ExprEngine &Eng, + const ProgramPoint &PP) + : Checkers(Checkers), Eng(Eng), PP(PP) {} + + void runChecker(CheckerManager::CheckBeginFunctionFunc checkFn, + NodeBuilder &Bldr, ExplodedNode *Pred) { + const ProgramPoint &L = PP.withTag(checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L); + + checkFn(C); + } +}; +} + +void CheckerManager::runCheckersForBeginFunction(ExplodedNodeSet &Dst, + const BlockEdge &L, + ExplodedNode *Pred, + ExprEngine &Eng) { + ExplodedNodeSet Src; + Src.insert(Pred); + CheckBeginFunctionContext C(BeginFunctionCheckers, Eng, L); + expandGraphWithCheckers(C, Dst, Src); +} + /// \brief Run checkers for end of path. // Note, We do not chain the checker output (like in expandGraphWithCheckers) // for this callback since end of path nodes are expected to be final. @@ -671,6 +705,10 @@ void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { EndAnalysisCheckers.push_back(checkfn); } +void CheckerManager::_registerForBeginFunction(CheckBeginFunctionFunc checkfn) { + BeginFunctionCheckers.push_back(checkfn); +} + void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) { EndFunctionCheckers.push_back(checkfn); } diff --git a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp index a15e1573e228b..ba03e2f8a3c18 100644 --- a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp +++ b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp @@ -49,12 +49,12 @@ static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers, CheckerOptInfo &opt, CheckerInfoSet &collected) { // Use a binary search to find the possible start of the package. CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.getName(), ""); - CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end(); + auto end = checkers.cend(); CheckerRegistry::CheckerInfoList::const_iterator i = - std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT); + std::lower_bound(checkers.cbegin(), end, packageInfo, checkerNameLT); // If we didn't even find a possible package, give up. - if (i == e) + if (i == end) return; // If what we found doesn't actually start the package, give up. @@ -73,7 +73,7 @@ static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers, size = packageSize->getValue(); // Step through all the checkers in the package. - for (e = i+size; i != e; ++i) { + for (auto checkEnd = i+size; i != checkEnd; ++i) { if (opt.isEnabled()) collected.insert(&*i); else diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp index 39cf7e771755d..da608f6c75588 100644 --- a/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -192,14 +192,27 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, WList->setBlockCounter(BCounterFactory.GetEmptyCounter()); if (!InitState) - // Generate the root. - generateNode(StartLoc, SubEng.getInitialState(L), nullptr); - else - generateNode(StartLoc, InitState, nullptr); + InitState = SubEng.getInitialState(L); + + bool IsNew; + ExplodedNode *Node = G.getNode(StartLoc, InitState, false, &IsNew); + assert (IsNew); + G.addRoot(Node); + + NodeBuilderContext BuilderCtx(*this, StartLoc.getDst(), Node); + ExplodedNodeSet DstBegin; + SubEng.processBeginOfFunction(BuilderCtx, Node, DstBegin, StartLoc); + + enqueue(DstBegin); } // Check if we have a steps limit bool UnlimitedSteps = Steps == 0; + // Cap our pre-reservation in the event that the user specifies + // a very large number of maximum steps. + const unsigned PreReservationCap = 4000000; + if(!UnlimitedSteps) + G.reserve(std::min(Steps,PreReservationCap)); while (WList->hasWork()) { if (!UnlimitedSteps) { @@ -243,8 +256,7 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, break; case ProgramPoint::CallEnterKind: { - CallEnter CEnter = Loc.castAs<CallEnter>(); - SubEng.processCallEnter(CEnter, Pred); + HandleCallEnter(Loc.castAs<CallEnter>(), Pred); break; } @@ -456,6 +468,11 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { Pred->State, Pred); } +void CoreEngine::HandleCallEnter(const CallEnter &CE, ExplodedNode *Pred) { + NodeBuilderContext BuilderCtx(*this, CE.getEntry(), Pred); + SubEng.processCallEnter(BuilderCtx, CE, Pred); +} + void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock * B, ExplodedNode *Pred) { assert(B->succ_size() == 2); diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index 8a09720b2a196..02d382cc4885e 100644 --- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -336,6 +336,14 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L, return V; } +ExplodedNode *ExplodedGraph::createUncachedNode(const ProgramPoint &L, + ProgramStateRef State, + bool IsSink) { + NodeTy *V = (NodeTy *) getAllocator().Allocate<NodeTy>(); + new (V) NodeTy(L, State, IsSink); + return V; +} + std::unique_ptr<ExplodedGraph> ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, InterExplodedGraphMap *ForwardMap, @@ -395,8 +403,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, // Create the corresponding node in the new graph and record the mapping // from the old node to the new node. - ExplodedNode *NewN = G->getNode(N->getLocation(), N->State, N->isSink(), - nullptr); + ExplodedNode *NewN = G->createUncachedNode(N->getLocation(), N->State, N->isSink()); Pass2[N] = NewN; // Also record the reverse mapping from the new node to the old node. diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 662b0a2dd7989..405aecdee0320 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -30,6 +30,7 @@ #include "llvm/ADT/ImmutableList.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SaveAndRestore.h" #ifndef NDEBUG #include "llvm/Support/GraphWriter.h" @@ -754,6 +755,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, // C++ and ARC stuff we don't support yet. case Expr::ObjCIndirectCopyRestoreExprClass: case Stmt::CXXDependentScopeMemberExprClass: + case Stmt::CXXInheritedCtorInitExprClass: case Stmt::CXXTryStmtClass: case Stmt::CXXTypeidExprClass: case Stmt::CXXUuidofExprClass: @@ -830,12 +832,21 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::OMPAtomicDirectiveClass: case Stmt::OMPTargetDirectiveClass: case Stmt::OMPTargetDataDirectiveClass: + case Stmt::OMPTargetEnterDataDirectiveClass: + case Stmt::OMPTargetExitDataDirectiveClass: + case Stmt::OMPTargetParallelDirectiveClass: + case Stmt::OMPTargetParallelForDirectiveClass: + case Stmt::OMPTargetUpdateDirectiveClass: case Stmt::OMPTeamsDirectiveClass: case Stmt::OMPCancellationPointDirectiveClass: case Stmt::OMPCancelDirectiveClass: case Stmt::OMPTaskLoopDirectiveClass: case Stmt::OMPTaskLoopSimdDirectiveClass: case Stmt::OMPDistributeDirectiveClass: + case Stmt::OMPDistributeParallelForDirectiveClass: + case Stmt::OMPDistributeParallelForSimdDirectiveClass: + case Stmt::OMPDistributeSimdDirectiveClass: + case Stmt::OMPTargetParallelForSimdDirectiveClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); case Stmt::ObjCSubscriptRefExprClass: @@ -892,7 +903,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::CUDAKernelCallExprClass: case Stmt::OpaqueValueExprClass: case Stmt::AsTypeExprClass: - case Stmt::AtomicExprClass: // Fall through. // Cases we intentionally don't evaluate, since they don't need @@ -906,6 +916,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::CXXScalarValueInitExprClass: case Stmt::CXXBoolLiteralExprClass: case Stmt::ObjCBoolLiteralExprClass: + case Stmt::ObjCAvailabilityCheckExprClass: case Stmt::FloatingLiteralClass: case Stmt::NoInitExprClass: case Stmt::SizeOfPackExprClass: @@ -1237,6 +1248,12 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, Bldr.addNodes(Dst); break; + case Stmt::AtomicExprClass: + Bldr.takeNodes(Pred); + VisitAtomicExpr(cast<AtomicExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); + break; + case Stmt::ObjCIvarRefExprClass: Bldr.takeNodes(Pred); VisitLvalObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst); @@ -1745,6 +1762,14 @@ static bool stackFrameDoesNotContainInitializedTemporaries(ExplodedNode &Pred) { } #endif +void ExprEngine::processBeginOfFunction(NodeBuilderContext &BC, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const BlockEdge &L) { + SaveAndRestore<const NodeBuilderContext *> NodeContextRAII(currBldrCtx, &BC); + getCheckerManager().runCheckersForBeginFunction(Dst, L, Pred, *this); +} + /// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. void ExprEngine::processEndOfFunction(NodeBuilderContext& BC, @@ -2052,6 +2077,44 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, M, *this); } +void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + ExplodedNodeSet AfterPreSet; + getCheckerManager().runCheckersForPreStmt(AfterPreSet, Pred, AE, *this); + + // For now, treat all the arguments to C11 atomics as escaping. + // FIXME: Ideally we should model the behavior of the atomics precisely here. + + ExplodedNodeSet AfterInvalidateSet; + StmtNodeBuilder Bldr(AfterPreSet, AfterInvalidateSet, *currBldrCtx); + + for (ExplodedNodeSet::iterator I = AfterPreSet.begin(), E = AfterPreSet.end(); + I != E; ++I) { + ProgramStateRef State = (*I)->getState(); + const LocationContext *LCtx = (*I)->getLocationContext(); + + SmallVector<SVal, 8> ValuesToInvalidate; + for (unsigned SI = 0, Count = AE->getNumSubExprs(); SI != Count; SI++) { + const Expr *SubExpr = AE->getSubExprs()[SI]; + SVal SubExprVal = State->getSVal(SubExpr, LCtx); + ValuesToInvalidate.push_back(SubExprVal); + } + + State = State->invalidateRegions(ValuesToInvalidate, AE, + currBldrCtx->blockCount(), + LCtx, + /*CausedByPointerEscape*/true, + /*Symbols=*/nullptr); + + SVal ResultVal = UnknownVal(); + State = State->BindExpr(AE, LCtx, ResultVal); + Bldr.generateNode(AE, *I, State, nullptr, + ProgramPoint::PostStmtKind); + } + + getCheckerManager().runCheckersForPostStmt(Dst, AfterInvalidateSet, AE, *this); +} + namespace { class CollectReachableSymbolsCallback final : public SymbolVisitor { InvalidatedSymbols Symbols; diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 74cc8d2ccbc5b..39d88bfda1486 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -37,13 +37,12 @@ STATISTIC(NumInlinedCalls, STATISTIC(NumReachedInlineCountMax, "The # of times we reached inline count maximum"); -void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) { +void ExprEngine::processCallEnter(NodeBuilderContext& BC, CallEnter CE, + ExplodedNode *Pred) { // Get the entry block in the CFG of the callee. const StackFrameContext *calleeCtx = CE.getCalleeContext(); PrettyStackTraceLocationContext CrashInfo(calleeCtx); - - const CFG *CalleeCFG = calleeCtx->getCFG(); - const CFGBlock *Entry = &(CalleeCFG->getEntry()); + const CFGBlock *Entry = CE.getEntry(); // Validate the CFG. assert(Entry->empty()); @@ -57,12 +56,16 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) { ProgramStateRef state = Pred->getState(); - // Construct a new node and add it to the worklist. + // Construct a new node, notify checkers that analysis of the function has + // begun, and add the resultant nodes to the worklist. bool isNew; ExplodedNode *Node = G.getNode(Loc, state, false, &isNew); Node->addPredecessor(Pred, G); - if (isNew) - Engine.getWorkList()->enqueue(Node); + if (isNew) { + ExplodedNodeSet DstBegin; + processBeginOfFunction(BC, Node, DstBegin, Loc); + Engine.enqueue(DstBegin); + } } // Find the last statement on the path to the exploded node and the @@ -379,22 +382,6 @@ void ExprEngine::examineStackFrames(const Decl *D, const LocationContext *LCtx, } LCtx = LCtx->getParent(); } - -} - -static bool IsInStdNamespace(const FunctionDecl *FD) { - const DeclContext *DC = FD->getEnclosingNamespaceContext(); - const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC); - if (!ND) - return false; - - while (const DeclContext *Parent = ND->getParent()) { - if (!isa<NamespaceDecl>(Parent)) - break; - ND = cast<NamespaceDecl>(Parent); - } - - return ND->isStdNamespace(); } // The GDM component containing the dynamic dispatch bifurcation info. When @@ -408,7 +395,8 @@ namespace { DynamicDispatchModeInlined = 1, DynamicDispatchModeConservative }; -} +} // end anonymous namespace + REGISTER_TRAIT_WITH_PROGRAMSTATE(DynamicDispatchBifurcationMap, CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *, unsigned)) @@ -441,7 +429,6 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, currBldrCtx->getBlock(), currStmtIdx); - CallEnter Loc(CallE, CalleeSFC, CurLC); // Construct a new state which contains the mapping from actual to @@ -761,7 +748,7 @@ static bool mayInlineDecl(AnalysisDeclContext *CalleeADC, // Conditionally control the inlining of C++ standard library functions. if (!Opts.mayInlineCXXStandardLibrary()) if (Ctx.getSourceManager().isInSystemHeader(FD->getLocation())) - if (IsInStdNamespace(FD)) + if (AnalysisDeclContext::isInStdNamespace(FD)) return false; // Conditionally control the inlining of methods on objects that look @@ -778,7 +765,6 @@ static bool mayInlineDecl(AnalysisDeclContext *CalleeADC, if (!Opts.mayInlineCXXSharedPtrDtor()) if (isCXXSharedPtrDtor(FD)) return false; - } } @@ -988,13 +974,10 @@ void ExprEngine::BifurcateCall(const MemRegion *BifurReg, conservativeEvalCall(Call, Bldr, Pred, NoIState); NumOfDynamicDispatchPathSplits++; - return; } - void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - ExplodedNodeSet dstPreVisit; getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this); diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index b3edb8569bd6c..3a18956e41393 100644 --- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -412,13 +412,13 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, // Output a maximum size. if (!isa<PathDiagnosticMacroPiece>(P)) { // Get the string and determining its maximum substring. - const std::string& Msg = P.getString(); + const auto &Msg = P.getString(); unsigned max_token = 0; unsigned cnt = 0; unsigned len = Msg.size(); - for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I) - switch (*I) { + for (char C : Msg) + switch (C) { default: ++cnt; continue; diff --git a/lib/StaticAnalyzer/Core/IssueHash.cpp b/lib/StaticAnalyzer/Core/IssueHash.cpp index 0a3af3dcc7e94..bd5c81179adc9 100644 --- a/lib/StaticAnalyzer/Core/IssueHash.cpp +++ b/lib/StaticAnalyzer/Core/IssueHash.cpp @@ -132,8 +132,11 @@ static std::string NormalizeLine(const SourceManager &SM, FullSourceLoc &L, StringRef Str = GetNthLineOfFile(SM.getBuffer(L.getFileID(), L), L.getExpansionLineNumber()); - unsigned col = Str.find_first_not_of(Whitespaces); - col++; + StringRef::size_type col = Str.find_first_not_of(Whitespaces); + if (col == StringRef::npos) + col = 1; // The line only contains whitespace. + else + col++; SourceLocation StartOfLine = SM.translateLineCol(SM.getFileID(L), L.getExpansionLineNumber(), col); llvm::MemoryBuffer *Buffer = @@ -180,7 +183,7 @@ std::string clang::GetIssueString(const SourceManager &SM, return (llvm::Twine(CheckerName) + Delimiter + GetEnclosingDeclContextSignature(D) + Delimiter + - llvm::utostr(IssueLoc.getExpansionColumnNumber()) + Delimiter + + Twine(IssueLoc.getExpansionColumnNumber()) + Delimiter + NormalizeLine(SM, IssueLoc, LangOpts) + Delimiter + BugType) .str(); } diff --git a/lib/StaticAnalyzer/Core/Makefile b/lib/StaticAnalyzer/Core/Makefile deleted file mode 100644 index c3e00fa36825e..0000000000000 --- a/lib/StaticAnalyzer/Core/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -##===- clang/lib/StaticAnalyzer/Core/Makefile --------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements analyses built on top of source-level CFGs. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../../.. -LIBRARYNAME := clangStaticAnalyzerCore - -include $(CLANG_LEVEL)/Makefile diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index 30052ccacee44..b7b6f42b29102 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -35,7 +35,6 @@ template<typename RegionTy> struct MemRegionManagerTrait; template <typename RegionTy, typename A1> RegionTy* MemRegionManager::getRegion(const A1 a1) { - const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion = MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1); @@ -46,7 +45,7 @@ RegionTy* MemRegionManager::getRegion(const A1 a1) { InsertPos)); if (!R) { - R = (RegionTy*) A.Allocate<RegionTy>(); + R = A.Allocate<RegionTy>(); new (R) RegionTy(a1, superRegion); Regions.InsertNode(R, InsertPos); } @@ -64,7 +63,7 @@ RegionTy* MemRegionManager::getSubRegion(const A1 a1, InsertPos)); if (!R) { - R = (RegionTy*) A.Allocate<RegionTy>(); + R = A.Allocate<RegionTy>(); new (R) RegionTy(a1, superRegion); Regions.InsertNode(R, InsertPos); } @@ -74,7 +73,6 @@ RegionTy* MemRegionManager::getSubRegion(const A1 a1, template <typename RegionTy, typename A1, typename A2> RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) { - const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion = MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1, a2); @@ -85,7 +83,7 @@ RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) { InsertPos)); if (!R) { - R = (RegionTy*) A.Allocate<RegionTy>(); + R = A.Allocate<RegionTy>(); new (R) RegionTy(a1, a2, superRegion); Regions.InsertNode(R, InsertPos); } @@ -96,7 +94,6 @@ RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) { template <typename RegionTy, typename A1, typename A2> RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, const MemRegion *superRegion) { - llvm::FoldingSetNodeID ID; RegionTy::ProfileRegion(ID, a1, a2, superRegion); void *InsertPos; @@ -104,7 +101,7 @@ RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, InsertPos)); if (!R) { - R = (RegionTy*) A.Allocate<RegionTy>(); + R = A.Allocate<RegionTy>(); new (R) RegionTy(a1, a2, superRegion); Regions.InsertNode(R, InsertPos); } @@ -115,7 +112,6 @@ RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, template <typename RegionTy, typename A1, typename A2, typename A3> RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, const A3 a3, const MemRegion *superRegion) { - llvm::FoldingSetNodeID ID; RegionTy::ProfileRegion(ID, a1, a2, a3, superRegion); void *InsertPos; @@ -123,7 +119,7 @@ RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, const A3 a3, InsertPos)); if (!R) { - R = (RegionTy*) A.Allocate<RegionTy>(); + R = A.Allocate<RegionTy>(); new (R) RegionTy(a1, a2, a3, superRegion); Regions.InsertNode(R, InsertPos); } @@ -246,23 +242,23 @@ QualType CXXBaseObjectRegion::getValueType() const { //===----------------------------------------------------------------------===// void MemSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddInteger((unsigned)getKind()); + ID.AddInteger(static_cast<unsigned>(getKind())); } void StackSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddInteger((unsigned)getKind()); + ID.AddInteger(static_cast<unsigned>(getKind())); ID.AddPointer(getStackFrame()); } void StaticGlobalSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddInteger((unsigned)getKind()); + ID.AddInteger(static_cast<unsigned>(getKind())); ID.AddPointer(getCodeRegion()); } void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const StringLiteral* Str, const MemRegion* superRegion) { - ID.AddInteger((unsigned) StringRegionKind); + ID.AddInteger(static_cast<unsigned>(StringRegionKind)); ID.AddPointer(Str); ID.AddPointer(superRegion); } @@ -270,7 +266,7 @@ void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, void ObjCStringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCStringLiteral* Str, const MemRegion* superRegion) { - ID.AddInteger((unsigned) ObjCStringRegionKind); + ID.AddInteger(static_cast<unsigned>(ObjCStringRegionKind)); ID.AddPointer(Str); ID.AddPointer(superRegion); } @@ -278,7 +274,7 @@ void ObjCStringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex, unsigned cnt, const MemRegion *superRegion) { - ID.AddInteger((unsigned) AllocaRegionKind); + ID.AddInteger(static_cast<unsigned>(AllocaRegionKind)); ID.AddPointer(Ex); ID.AddInteger(cnt); ID.AddPointer(superRegion); @@ -295,7 +291,7 @@ void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID& ID) const { void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const CompoundLiteralExpr *CL, const MemRegion* superRegion) { - ID.AddInteger((unsigned) CompoundLiteralRegionKind); + ID.AddInteger(static_cast<unsigned>(CompoundLiteralRegionKind)); ID.AddPointer(CL); ID.AddPointer(superRegion); } @@ -303,7 +299,7 @@ void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, void CXXThisRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, const PointerType *PT, const MemRegion *sRegion) { - ID.AddInteger((unsigned) CXXThisRegionKind); + ID.AddInteger(static_cast<unsigned>(CXXThisRegionKind)); ID.AddPointer(PT); ID.AddPointer(sRegion); } @@ -320,7 +316,7 @@ void ObjCIvarRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D, const MemRegion* superRegion, Kind k) { - ID.AddInteger((unsigned) k); + ID.AddInteger(static_cast<unsigned>(k)); ID.AddPointer(D); ID.AddPointer(superRegion); } @@ -335,7 +331,7 @@ void VarRegion::Profile(llvm::FoldingSetNodeID &ID) const { void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym, const MemRegion *sreg) { - ID.AddInteger((unsigned) MemRegion::SymbolicRegionKind); + ID.AddInteger(static_cast<unsigned>(MemRegion::SymbolicRegionKind)); ID.Add(sym); ID.AddPointer(sreg); } @@ -438,7 +434,7 @@ void SubRegion::anchor() { } // Region pretty-printing. //===----------------------------------------------------------------------===// -void MemRegion::dump() const { +LLVM_DUMP_METHOD void MemRegion::dump() const { dumpToStream(llvm::errs()); } @@ -454,7 +450,7 @@ void MemRegion::dumpToStream(raw_ostream &os) const { } void AllocaRegion::dumpToStream(raw_ostream &os) const { - os << "alloca{" << (const void*) Ex << ',' << Cnt << '}'; + os << "alloca{" << static_cast<const void*>(Ex) << ',' << Cnt << '}'; } void FunctionCodeRegion::dumpToStream(raw_ostream &os) const { @@ -462,7 +458,7 @@ void FunctionCodeRegion::dumpToStream(raw_ostream &os) const { } void BlockCodeRegion::dumpToStream(raw_ostream &os) const { - os << "block_code{" << (const void*) this << '}'; + os << "block_code{" << static_cast<const void*>(this) << '}'; } void BlockDataRegion::dumpToStream(raw_ostream &os) const { @@ -478,12 +474,12 @@ void BlockDataRegion::dumpToStream(raw_ostream &os) const { void CompoundLiteralRegion::dumpToStream(raw_ostream &os) const { // FIXME: More elaborate pretty-printing. - os << "{ " << (const void*) CL << " }"; + os << "{ " << static_cast<const void*>(CL) << " }"; } void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const { os << "temp_object{" << getValueType().getAsString() << ',' - << (const void*) Ex << '}'; + << static_cast<const void*>(Ex) << '}'; } void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const { @@ -525,7 +521,7 @@ void VarRegion::dumpToStream(raw_ostream &os) const { os << *cast<VarDecl>(D); } -void RegionRawOffset::dump() const { +LLVM_DUMP_METHOD void RegionRawOffset::dump() const { dumpToStream(llvm::errs()); } @@ -582,12 +578,10 @@ void MemRegion::printPretty(raw_ostream &os) const { os << "'"; printPrettyAsExpr(os); os << "'"; - return; } void MemRegion::printPrettyAsExpr(raw_ostream &os) const { llvm_unreachable("This region cannot be printed pretty."); - return; } bool VarRegion::canPrintPrettyAsExpr() const { @@ -628,7 +622,6 @@ void FieldRegion::printPretty(raw_ostream &os) const { } else { os << "field " << "\'" << getDecl()->getName() << "'"; } - return; } bool CXXBaseObjectRegion::canPrintPrettyAsExpr() const { @@ -639,6 +632,65 @@ void CXXBaseObjectRegion::printPrettyAsExpr(raw_ostream &os) const { superRegion->printPrettyAsExpr(os); } +std::string MemRegion::getDescriptiveName(bool UseQuotes) const { + std::string VariableName; + std::string ArrayIndices; + const MemRegion *R = this; + SmallString<50> buf; + llvm::raw_svector_ostream os(buf); + + // Obtain array indices to add them to the variable name. + const ElementRegion *ER = nullptr; + while ((ER = R->getAs<ElementRegion>())) { + // Index is a ConcreteInt. + if (auto CI = ER->getIndex().getAs<nonloc::ConcreteInt>()) { + llvm::SmallString<2> Idx; + CI->getValue().toString(Idx); + ArrayIndices = (llvm::Twine("[") + Idx.str() + "]" + ArrayIndices).str(); + } + // If not a ConcreteInt, try to obtain the variable + // name by calling 'getDescriptiveName' recursively. + else { + std::string Idx = ER->getDescriptiveName(false); + if (!Idx.empty()) { + ArrayIndices = (llvm::Twine("[") + Idx + "]" + ArrayIndices).str(); + } + } + R = ER->getSuperRegion(); + } + + // Get variable name. + if (R && R->canPrintPrettyAsExpr()) { + R->printPrettyAsExpr(os); + if (UseQuotes) { + return (llvm::Twine("'") + os.str() + ArrayIndices + "'").str(); + } else { + return (llvm::Twine(os.str()) + ArrayIndices).str(); + } + } + + return VariableName; +} + +SourceRange MemRegion::sourceRange() const { + const VarRegion *const VR = dyn_cast<VarRegion>(this->getBaseRegion()); + const FieldRegion *const FR = dyn_cast<FieldRegion>(this); + + // Check for more specific regions first. + // FieldRegion + if (FR) { + return FR->getDecl()->getSourceRange(); + } + // VarRegion + else if (VR) { + return VR->getDecl()->getSourceRange(); + } + // Return invalid source range (can be checked by client). + else { + return SourceRange{}; + } +} + //===----------------------------------------------------------------------===// // MemRegionManager methods. //===----------------------------------------------------------------------===// @@ -646,7 +698,7 @@ void CXXBaseObjectRegion::printPrettyAsExpr(raw_ostream &os) const { template <typename REG> const REG *MemRegionManager::LazyAllocate(REG*& region) { if (!region) { - region = (REG*) A.Allocate<REG>(); + region = A.Allocate<REG>(); new (region) REG(this); } @@ -656,7 +708,7 @@ const REG *MemRegionManager::LazyAllocate(REG*& region) { template <typename REG, typename ARG> const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) { if (!region) { - region = (REG*) A.Allocate<REG>(); + region = A.Allocate<REG>(); new (region) REG(this, a); } @@ -892,7 +944,6 @@ MemRegionManager::getCXXStaticTempObjectRegion(const Expr *Ex) { const CompoundLiteralRegion* MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL, const LocationContext *LC) { - const MemRegion *sReg = nullptr; if (CL->isFileScope()) @@ -910,7 +961,6 @@ const ElementRegion* MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx, const MemRegion* superRegion, ASTContext &Ctx){ - QualType T = Ctx.getCanonicalType(elementType).getUnqualifiedType(); llvm::FoldingSetNodeID ID; @@ -921,7 +971,7 @@ MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx, ElementRegion* R = cast_or_null<ElementRegion>(data); if (!R) { - R = (ElementRegion*) A.Allocate<ElementRegion>(); + R = A.Allocate<ElementRegion>(); new (R) ElementRegion(T, Idx, superRegion); Regions.InsertNode(R, InsertPos); } @@ -1342,10 +1392,10 @@ RegionOffset MemRegion::getAsOffset() const { // Get the field number. unsigned idx = 0; for (RecordDecl::field_iterator FI = RD->field_begin(), - FE = RD->field_end(); FI != FE; ++FI, ++idx) + FE = RD->field_end(); FI != FE; ++FI, ++idx) { if (FR->getDecl() == *FI) break; - + } const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); // This is offset in bits. Offset += Layout.getFieldOffset(idx); @@ -1406,9 +1456,9 @@ void BlockDataRegion::LazyInitializeReferencedVars() { BumpVectorContext BC(A); typedef BumpVector<const MemRegion*> VarVec; - VarVec *BV = (VarVec*) A.Allocate<VarVec>(); + VarVec *BV = A.Allocate<VarVec>(); new (BV) VarVec(BC, NumBlockVars); - VarVec *BVOriginal = (VarVec*) A.Allocate<VarVec>(); + VarVec *BVOriginal = A.Allocate<VarVec>(); new (BVOriginal) VarVec(BC, NumBlockVars); for (const VarDecl *VD : ReferencedBlockVars) { @@ -1488,7 +1538,7 @@ void RegionAndSymbolInvalidationTraits::setTrait(const MemRegion *MR, } bool RegionAndSymbolInvalidationTraits::hasTrait(SymbolRef Sym, - InvalidationKinds IK) { + InvalidationKinds IK) const { const_symbol_iterator I = SymTraitsMap.find(Sym); if (I != SymTraitsMap.end()) return I->second & IK; @@ -1497,7 +1547,7 @@ bool RegionAndSymbolInvalidationTraits::hasTrait(SymbolRef Sym, } bool RegionAndSymbolInvalidationTraits::hasTrait(const MemRegion *MR, - InvalidationKinds IK) { + InvalidationKinds IK) const { if (!MR) return false; diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 504df30de834c..217d628a129c7 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -61,7 +61,6 @@ PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {} PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {} - void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, bool ShouldFlattenMacros) const { for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { @@ -102,7 +101,6 @@ void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, } } - PathDiagnostic::~PathDiagnostic() {} PathDiagnostic::PathDiagnostic(StringRef CheckName, const Decl *declWithIssue, @@ -278,6 +276,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic( } static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y); + static Optional<bool> compareControlFlow(const PathDiagnosticControlFlowPiece &X, const PathDiagnosticControlFlowPiece &Y) { @@ -505,7 +504,6 @@ static SourceLocation getValidSourceLocation(const Stmt* S, // S might be a temporary statement that does not have a location in the // source code, so find an enclosing statement and use its location. if (!L.isValid()) { - AnalysisDeclContext *ADC; if (LAC.is<const LocationContext*>()) ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext(); @@ -578,22 +576,20 @@ getLocationForCaller(const StackFrameContext *SFC, llvm_unreachable("Unknown CFGElement kind"); } - PathDiagnosticLocation - PathDiagnosticLocation::createBegin(const Decl *D, - const SourceManager &SM) { +PathDiagnosticLocation::createBegin(const Decl *D, + const SourceManager &SM) { return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK); } PathDiagnosticLocation - PathDiagnosticLocation::createBegin(const Stmt *S, - const SourceManager &SM, - LocationOrAnalysisDeclContext LAC) { +PathDiagnosticLocation::createBegin(const Stmt *S, + const SourceManager &SM, + LocationOrAnalysisDeclContext LAC) { return PathDiagnosticLocation(getValidSourceLocation(S, LAC), SM, SingleLocK); } - PathDiagnosticLocation PathDiagnosticLocation::createEnd(const Stmt *S, const SourceManager &SM, @@ -605,13 +601,13 @@ PathDiagnosticLocation::createEnd(const Stmt *S, } PathDiagnosticLocation - PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, - const SourceManager &SM) { +PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, + const SourceManager &SM) { return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); } PathDiagnosticLocation - PathDiagnosticLocation::createConditionalColonLoc( +PathDiagnosticLocation::createConditionalColonLoc( const ConditionalOperator *CO, const SourceManager &SM) { return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK); @@ -619,28 +615,28 @@ PathDiagnosticLocation PathDiagnosticLocation - PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, - const SourceManager &SM) { +PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, + const SourceManager &SM) { return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); } PathDiagnosticLocation - PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, - const SourceManager &SM) { +PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, + const SourceManager &SM) { SourceLocation L = CS->getLBracLoc(); return PathDiagnosticLocation(L, SM, SingleLocK); } PathDiagnosticLocation - PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, - const SourceManager &SM) { +PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, + const SourceManager &SM) { SourceLocation L = CS->getRBracLoc(); return PathDiagnosticLocation(L, SM, SingleLocK); } PathDiagnosticLocation - PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, - const SourceManager &SM) { +PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, + const SourceManager &SM) { // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. if (const CompoundStmt *CS = dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) @@ -653,16 +649,15 @@ PathDiagnosticLocation } PathDiagnosticLocation - PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, - const SourceManager &SM) { +PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, + const SourceManager &SM) { SourceLocation L = LC->getDecl()->getBodyRBrace(); return PathDiagnosticLocation(L, SM, SingleLocK); } PathDiagnosticLocation - PathDiagnosticLocation::create(const ProgramPoint& P, - const SourceManager &SMng) { - +PathDiagnosticLocation::create(const ProgramPoint& P, + const SourceManager &SMng) { const Stmt* S = nullptr; if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { const CFGBlock *BSrc = BE->getSrc(); @@ -1062,7 +1057,6 @@ void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Range.getBegin().getRawEncoding()); ID.AddInteger(Range.getEnd().getRawEncoding()); ID.AddInteger(Loc.getRawEncoding()); - return; } void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index 55e1222e0ac6c..8ad931acdf7f5 100644 --- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -124,7 +124,7 @@ static void ReportControlFlow(raw_ostream &o, --indent; // Output any helper text. - const std::string& s = P.getString(); + const auto &s = P.getString(); if (!s.empty()) { Indent(o, indent) << "<key>alternate</key>"; EmitString(o, s) << '\n'; diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index 100fa75c5f421..adda7af08db8e 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -439,7 +439,7 @@ void ProgramState::printDOT(raw_ostream &Out) const { print(Out, "\\l", "\\|"); } -void ProgramState::dump() const { +LLVM_DUMP_METHOD void ProgramState::dump() const { print(llvm::errs()); } diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index a63f6e4962723..0d173c4644816 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -14,6 +14,7 @@ // parameters are created lazily. // //===----------------------------------------------------------------------===// + #include "clang/AST/Attr.h" #include "clang/AST/CharUnits.h" #include "clang/Analysis/Analyses/LiveVariables.h" @@ -29,6 +30,7 @@ #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/raw_ostream.h" +#include <utility> using namespace clang; using namespace ento; @@ -665,10 +667,9 @@ protected: public: ClusterAnalysis(RegionStoreManager &rm, ProgramStateManager &StateMgr, - RegionBindingsRef b ) - : RM(rm), Ctx(StateMgr.getContext()), - svalBuilder(StateMgr.getSValBuilder()), - B(b) {} + RegionBindingsRef b) + : RM(rm), Ctx(StateMgr.getContext()), + svalBuilder(StateMgr.getSValBuilder()), B(std::move(b)) {} RegionBindingsRef getRegionBindings() const { return B; } @@ -1130,11 +1131,10 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR, // Check offset is not symbolic and within array's boundaries. // Handles arrays of 0 elements and of 0-sized elements as well. if (!ROffset || - (ROffset && - ((*ROffset >= LowerOffset && *ROffset < UpperOffset) || - (UpperOverflow && - (*ROffset >= LowerOffset || *ROffset < UpperOffset)) || - (LowerOffset == UpperOffset && *ROffset == LowerOffset)))) { + ((*ROffset >= LowerOffset && *ROffset < UpperOffset) || + (UpperOverflow && + (*ROffset >= LowerOffset || *ROffset < UpperOffset)) || + (LowerOffset == UpperOffset && *ROffset == LowerOffset))) { B = B.removeBinding(I.getKey()); // Bound symbolic regions need to be invalidated for dead symbol // detection. diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp index 18315225a99d5..72bcdd9ecb06b 100644 --- a/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -367,6 +367,11 @@ SVal SValBuilder::evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, if (lhs.isUnknown() || rhs.isUnknown()) return UnknownVal(); + if (lhs.getAs<nonloc::LazyCompoundVal>() || + rhs.getAs<nonloc::LazyCompoundVal>()) { + return UnknownVal(); + } + if (Optional<Loc> LV = lhs.getAs<Loc>()) { if (Optional<Loc> RV = rhs.getAs<Loc>()) return evalBinOpLL(state, op, *LV, *RV, type); @@ -451,7 +456,7 @@ SVal SValBuilder::evalIntegralCast(ProgramStateRef state, SVal val, NonLoc FromVal = val.castAs<NonLoc>(); QualType CmpTy = getConditionType(); NonLoc CompVal = - evalBinOpNN(state, BO_LT, FromVal, ToTypeMaxVal, CmpTy).castAs<NonLoc>(); + evalBinOpNN(state, BO_LE, FromVal, ToTypeMaxVal, CmpTy).castAs<NonLoc>(); ProgramStateRef IsNotTruncated, IsTruncated; std::tie(IsNotTruncated, IsTruncated) = state->assume(CompVal); if (!IsNotTruncated && IsTruncated) { diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp index dffee6c8c57be..a30beed688b7a 100644 --- a/lib/StaticAnalyzer/Core/SVals.cpp +++ b/lib/StaticAnalyzer/Core/SVals.cpp @@ -236,7 +236,7 @@ SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals, // Pretty-Printing. //===----------------------------------------------------------------------===// -void SVal::dump() const { dumpToStream(llvm::errs()); } +LLVM_DUMP_METHOD void SVal::dump() const { dumpToStream(llvm::errs()); } void SVal::dumpToStream(raw_ostream &os) const { switch (getBaseKind()) { diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp index 2dd252c223fda..b8b4af1179e52 100644 --- a/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -23,7 +23,7 @@ using namespace ento; void SymExpr::anchor() { } -void SymExpr::dump() const { +LLVM_DUMP_METHOD void SymExpr::dump() const { dumpToStream(llvm::errs()); } |