diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/StaticAnalyzer')
102 files changed, 3725 insertions, 3105 deletions
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp index 9af0a5a..166471a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp @@ -8,8 +8,6 @@ //===----------------------------------------------------------------------===// // This file reports various statistics about analyzer visitation. //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "StatsChecker" - #include "ClangSACheckers.h" #include "clang/AST/DeclObjC.h" #include "clang/Basic/SourceManager.h" @@ -26,6 +24,8 @@ using namespace clang; using namespace ento; +#define DEBUG_TYPE "StatsChecker" + STATISTIC(NumBlocks, "The # of blocks in top level functions"); STATISTIC(NumBlocksUnreachable, @@ -41,7 +41,7 @@ public: void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng) const { - const CFG *C = 0; + const CFG *C = nullptr; const SourceManager &SM = B.getSourceManager(); llvm::SmallPtrSet<const CFGBlock*, 256> reachable; @@ -112,7 +112,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G, << " | Empty WorkList: " << (Eng.hasEmptyWorkList() ? "yes" : "no"); - B.EmitBasicReport(D, "Analyzer Statistics", "Internal Statistics", + B.EmitBasicReport(D, this, "Analyzer Statistics", "Internal Statistics", output.str(), PathDiagnosticLocation(D, SM)); // Emit warning for each block we bailed out on. @@ -129,7 +129,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G, outputI << "(" << NameOfRootFunction << ")" << ": The analyzer generated a sink at this point"; B.EmitBasicReport( - D, "Sink Point", "Internal Statistics", outputI.str(), + D, this, "Sink Point", "Internal Statistics", outputI.str(), PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC)); } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp index 312bc74..cb5b010 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp @@ -25,7 +25,8 @@ using namespace ento; namespace { class ArrayBoundChecker : public Checker<check::Location> { - mutable OwningPtr<BuiltinBug> BT; + mutable std::unique_ptr<BuiltinBug> BT; + public: void checkLocation(SVal l, bool isLoad, const Stmt* S, CheckerContext &C) const; @@ -66,8 +67,9 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS, return; if (!BT) - BT.reset(new BuiltinBug("Out-of-bound array access", - "Access out-of-bound array element (buffer overflow)")); + BT.reset(new BuiltinBug( + this, "Out-of-bound array access", + "Access out-of-bound array element (buffer overflow)")); // FIXME: It would be nice to eventually make this diagnostic more clear, // e.g., by referencing the original declaration or by saying *why* this diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp index 5e4b824..20360ef 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -28,8 +28,8 @@ using namespace ento; namespace { class ArrayBoundCheckerV2 : public Checker<check::Location> { - mutable OwningPtr<BuiltinBug> BT; - + mutable std::unique_ptr<BuiltinBug> BT; + enum OOB_Kind { OOB_Precedes, OOB_Excedes, OOB_Tainted }; void reportOOB(CheckerContext &C, ProgramStateRef errorState, @@ -45,9 +45,9 @@ class RegionRawOffsetV2 { private: const SubRegion *baseRegion; SVal byteOffset; - + RegionRawOffsetV2() - : baseRegion(0), byteOffset(UnknownVal()) {} + : baseRegion(nullptr), byteOffset(UnknownVal()) {} public: RegionRawOffsetV2(const SubRegion* base, SVal offset) @@ -120,7 +120,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad, return; ProgramStateRef state_precedesLowerBound, state_withinLowerBound; - llvm::tie(state_precedesLowerBound, state_withinLowerBound) = + std::tie(state_precedesLowerBound, state_withinLowerBound) = state->assume(*lowerBoundToCheck); // Are we constrained enough to definitely precede the lower bound? @@ -152,7 +152,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad, break; ProgramStateRef state_exceedsUpperBound, state_withinUpperBound; - llvm::tie(state_exceedsUpperBound, state_withinUpperBound) = + std::tie(state_exceedsUpperBound, state_withinUpperBound) = state->assume(*upperboundToCheck); // If we are under constrained and the index variables are tainted, report. @@ -187,7 +187,7 @@ void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext, return; if (!BT) - BT.reset(new BuiltinBug("Out-of-bound access")); + BT.reset(new BuiltinBug(this, "Out-of-bound access")); // FIXME: This diagnostics are preliminary. We should get far better // diagnostics for explaining buffer overruns. @@ -311,7 +311,6 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state, return RegionRawOffsetV2(); } - void ento::registerArrayBoundCheckerV2(CheckerManager &mgr) { mgr.registerChecker<ArrayBoundCheckerV2>(); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index f66f8b7..3fd5576 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" +#include "SelectorExtras.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" @@ -39,7 +40,8 @@ using namespace ento; namespace { class APIMisuse : public BugType { public: - APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {} + APIMisuse(const CheckerBase *checker, const char *name) + : BugType(checker, name, "API Misuse (Apple)") {} }; } // end anonymous namespace @@ -94,7 +96,19 @@ namespace { class NilArgChecker : public Checker<check::PreObjCMessage, check::PostStmt<ObjCDictionaryLiteral>, check::PostStmt<ObjCArrayLiteral> > { - mutable OwningPtr<APIMisuse> BT; + mutable std::unique_ptr<APIMisuse> BT; + + mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors; + mutable Selector ArrayWithObjectSel; + mutable Selector AddObjectSel; + mutable Selector InsertObjectAtIndexSel; + mutable Selector ReplaceObjectAtIndexWithObjectSel; + mutable Selector SetObjectAtIndexedSubscriptSel; + mutable Selector ArrayByAddingObjectSel; + mutable Selector DictionaryWithObjectForKeySel; + mutable Selector SetObjectForKeySel; + mutable Selector SetObjectForKeyedSubscriptSel; + mutable Selector RemoveObjectForKeySel; void warnIfNilExpr(const Expr *E, const char *Msg, @@ -170,10 +184,13 @@ void NilArgChecker::warnIfNilArg(CheckerContext &C, assert(Arg == 1); os << "Key argument "; } - os << "to '" << msg.getSelector().getAsString() << "' cannot be nil"; + os << "to '"; + msg.getSelector().print(os); + os << "' cannot be nil"; } else { - os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '" - << msg.getSelector().getAsString() << "' cannot be nil"; + os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"; + msg.getSelector().print(os); + os << "' cannot be nil"; } } @@ -188,7 +205,7 @@ void NilArgChecker::generateBugReport(ExplodedNode *N, const Expr *E, CheckerContext &C) const { if (!BT) - BT.reset(new APIMisuse("nil argument")); + BT.reset(new APIMisuse(this, "nil argument")); BugReport *R = new BugReport(*BT, Msg, N); R->addRange(Range); @@ -210,50 +227,62 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg, if (Class == FC_NSString) { Selector S = msg.getSelector(); - + if (S.isUnarySelector()) return; - - // FIXME: This is going to be really slow doing these checks with - // lexical comparisons. - - std::string NameStr = S.getAsString(); - StringRef Name(NameStr); - assert(!Name.empty()); - - // FIXME: Checking for initWithFormat: will not work in most cases - // yet because [NSString alloc] returns id, not NSString*. We will - // need support for tracking expected-type information in the analyzer - // to find these errors. - if (Name == "caseInsensitiveCompare:" || - Name == "compare:" || - Name == "compare:options:" || - Name == "compare:options:range:" || - Name == "compare:options:range:locale:" || - Name == "componentsSeparatedByCharactersInSet:" || - Name == "initWithFormat:") { - Arg = 0; + + if (StringSelectors.empty()) { + ASTContext &Ctx = C.getASTContext(); + Selector Sels[] = { + getKeywordSelector(Ctx, "caseInsensitiveCompare", nullptr), + getKeywordSelector(Ctx, "compare", nullptr), + getKeywordSelector(Ctx, "compare", "options", nullptr), + getKeywordSelector(Ctx, "compare", "options", "range", nullptr), + getKeywordSelector(Ctx, "compare", "options", "range", "locale", + nullptr), + getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet", + nullptr), + getKeywordSelector(Ctx, "initWithFormat", + nullptr), + getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare", nullptr), + getKeywordSelector(Ctx, "localizedCompare", nullptr), + getKeywordSelector(Ctx, "localizedStandardCompare", nullptr), + }; + for (Selector KnownSel : Sels) + StringSelectors[KnownSel] = 0; } + auto I = StringSelectors.find(S); + if (I == StringSelectors.end()) + return; + Arg = I->second; } else if (Class == FC_NSArray) { Selector S = msg.getSelector(); if (S.isUnarySelector()) return; - if (S.getNameForSlot(0).equals("addObject")) { - Arg = 0; - } else if (S.getNameForSlot(0).equals("insertObject") && - S.getNameForSlot(1).equals("atIndex")) { + if (ArrayWithObjectSel.isNull()) { + ASTContext &Ctx = C.getASTContext(); + ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject", nullptr); + AddObjectSel = getKeywordSelector(Ctx, "addObject", nullptr); + InsertObjectAtIndexSel = + getKeywordSelector(Ctx, "insertObject", "atIndex", nullptr); + ReplaceObjectAtIndexWithObjectSel = + getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject", nullptr); + SetObjectAtIndexedSubscriptSel = + getKeywordSelector(Ctx, "setObject", "atIndexedSubscript", nullptr); + ArrayByAddingObjectSel = + getKeywordSelector(Ctx, "arrayByAddingObject", nullptr); + } + + if (S == ArrayWithObjectSel || S == AddObjectSel || + S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) { Arg = 0; - } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") && - S.getNameForSlot(1).equals("withObject")) { - Arg = 1; - } else if (S.getNameForSlot(0).equals("setObject") && - S.getNameForSlot(1).equals("atIndexedSubscript")) { + } else if (S == SetObjectAtIndexedSubscriptSel) { Arg = 0; CanBeSubscript = true; - } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) { - Arg = 0; + } else if (S == ReplaceObjectAtIndexWithObjectSel) { + Arg = 1; } } else if (Class == FC_NSDictionary) { Selector S = msg.getSelector(); @@ -261,20 +290,26 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg, if (S.isUnarySelector()) return; - if (S.getNameForSlot(0).equals("dictionaryWithObject") && - S.getNameForSlot(1).equals("forKey")) { - Arg = 0; - warnIfNilArg(C, msg, /* Arg */1, Class); - } else if (S.getNameForSlot(0).equals("setObject") && - S.getNameForSlot(1).equals("forKey")) { + if (DictionaryWithObjectForKeySel.isNull()) { + ASTContext &Ctx = C.getASTContext(); + DictionaryWithObjectForKeySel = + getKeywordSelector(Ctx, "dictionaryWithObject", "forKey", nullptr); + SetObjectForKeySel = + getKeywordSelector(Ctx, "setObject", "forKey", nullptr); + SetObjectForKeyedSubscriptSel = + getKeywordSelector(Ctx, "setObject", "forKeyedSubscript", nullptr); + RemoveObjectForKeySel = + getKeywordSelector(Ctx, "removeObjectForKey", nullptr); + } + + if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) { Arg = 0; warnIfNilArg(C, msg, /* Arg */1, Class); - } else if (S.getNameForSlot(0).equals("setObject") && - S.getNameForSlot(1).equals("forKeyedSubscript")) { + } else if (S == SetObjectForKeyedSubscriptSel) { CanBeSubscript = true; Arg = 0; warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript); - } else if (S.getNameForSlot(0).equals("removeObjectForKey")) { + } else if (S == RemoveObjectForKeySel) { Arg = 0; } } @@ -282,7 +317,6 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg, // If argument is '0', report a warning. if ((Arg != InvalidArgIndex)) warnIfNilArg(C, msg, Arg, Class, CanBeSubscript); - } void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL, @@ -309,10 +343,10 @@ void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL, namespace { class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > { - mutable OwningPtr<APIMisuse> BT; + mutable std::unique_ptr<APIMisuse> BT; mutable IdentifierInfo* II; public: - CFNumberCreateChecker() : II(0) {} + CFNumberCreateChecker() : II(nullptr) {} void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; @@ -480,8 +514,8 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, << " bits of the input integer will be lost."; if (!BT) - BT.reset(new APIMisuse("Bad use of CFNumberCreate")); - + BT.reset(new APIMisuse(this, "Bad use of CFNumberCreate")); + BugReport *report = new BugReport(*BT, os.str(), N); report->addRange(CE->getArg(2)->getSourceRange()); C.emitReport(report); @@ -489,15 +523,17 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, } //===----------------------------------------------------------------------===// -// CFRetain/CFRelease/CFMakeCollectable checking for null arguments. +// CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments. //===----------------------------------------------------------------------===// namespace { class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > { - mutable OwningPtr<APIMisuse> BT; - mutable IdentifierInfo *Retain, *Release, *MakeCollectable; + mutable std::unique_ptr<APIMisuse> BT; + mutable IdentifierInfo *Retain, *Release, *MakeCollectable, *Autorelease; public: - CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {} + CFRetainReleaseChecker() + : Retain(nullptr), Release(nullptr), MakeCollectable(nullptr), + Autorelease(nullptr) {} void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; }; } // end anonymous namespace @@ -519,13 +555,15 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE, Retain = &Ctx.Idents.get("CFRetain"); Release = &Ctx.Idents.get("CFRelease"); MakeCollectable = &Ctx.Idents.get("CFMakeCollectable"); - BT.reset( - new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable")); + Autorelease = &Ctx.Idents.get("CFAutorelease"); + BT.reset(new APIMisuse( + this, "null passed to CF memory management function")); } - // Check if we called CFRetain/CFRelease/CFMakeCollectable. + // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease. const IdentifierInfo *FuncII = FD->getIdentifier(); - if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable)) + if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable || + FuncII == Autorelease)) return; // FIXME: The rest of this just checks that the argument is non-null. @@ -548,7 +586,7 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE, // Are they equal? ProgramStateRef stateTrue, stateFalse; - llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull); + std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull); if (stateTrue && !stateFalse) { ExplodedNode *N = C.generateSink(stateTrue); @@ -562,6 +600,8 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE, description = "Null pointer argument in call to CFRelease"; else if (FuncII == MakeCollectable) description = "Null pointer argument in call to CFMakeCollectable"; + else if (FuncII == Autorelease) + description = "Null pointer argument in call to CFAutorelease"; else llvm_unreachable("impossible case"); @@ -586,7 +626,7 @@ class ClassReleaseChecker : public Checker<check::PreObjCMessage> { mutable Selector retainS; mutable Selector autoreleaseS; mutable Selector drainS; - mutable OwningPtr<BugType> BT; + mutable std::unique_ptr<BugType> BT; public: void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const; @@ -597,9 +637,9 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const { if (!BT) { - BT.reset(new APIMisuse("message incorrectly sent to class instead of class " - "instance")); - + BT.reset(new APIMisuse( + this, "message incorrectly sent to class instead of class instance")); + ASTContext &Ctx = C.getASTContext(); releaseS = GetNullarySelector("release", Ctx); retainS = GetNullarySelector("retain", Ctx); @@ -620,7 +660,9 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg, SmallString<200> buf; llvm::raw_svector_ostream os(buf); - os << "The '" << S.getAsString() << "' message should be sent to instances " + os << "The '"; + S.print(os); + os << "' message should be sent to instances " "of class '" << Class->getName() << "' and not the class directly"; @@ -643,7 +685,7 @@ class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> { mutable Selector orderedSetWithObjectsS; mutable Selector initWithObjectsS; mutable Selector initWithObjectsAndKeysS; - mutable OwningPtr<BugType> BT; + mutable std::unique_ptr<BugType> BT; bool isVariadicMessage(const ObjCMethodCall &msg) const; @@ -703,7 +745,8 @@ VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const { void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const { if (!BT) { - BT.reset(new APIMisuse("Arguments passed to variadic method aren't all " + BT.reset(new APIMisuse(this, + "Arguments passed to variadic method aren't all " "Objective-C pointer types")); ASTContext &Ctx = C.getASTContext(); @@ -733,8 +776,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg, // Verify that all arguments have Objective-C types. Optional<ExplodedNode*> errorNode; - ProgramStateRef state = C.getState(); - + for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) { QualType ArgTy = msg.getArgExpr(I)->getType(); if (ArgTy->isObjCObjectPointerType()) @@ -772,8 +814,8 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg, else os << "Argument to method '"; - os << msg.getSelector().getAsString() - << "' should be an Objective-C pointer type, not '"; + msg.getSelector().print(os); + os << "' should be an Objective-C pointer type, not '"; ArgTy.print(os, C.getLangOpts()); os << "'"; @@ -804,7 +846,7 @@ class ObjCLoopChecker CheckerContext &C) const; public: - ObjCLoopChecker() : CountSelectorII(0) {} + ObjCLoopChecker() : CountSelectorII(nullptr) {} void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const; void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; @@ -844,7 +886,7 @@ static ProgramStateRef checkCollectionNonNil(CheckerContext &C, ProgramStateRef State, const ObjCForCollectionStmt *FCS) { if (!State) - return NULL; + return nullptr; SVal CollectionVal = C.getSVal(FCS->getCollection()); Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>(); @@ -852,10 +894,10 @@ static ProgramStateRef checkCollectionNonNil(CheckerContext &C, return State; ProgramStateRef StNonNil, StNil; - llvm::tie(StNonNil, StNil) = State->assume(*KnownCollection); + std::tie(StNonNil, StNil) = State->assume(*KnownCollection); if (StNil && !StNonNil) { // The collection is nil. This path is infeasible. - return NULL; + return nullptr; } return StNonNil; @@ -869,7 +911,7 @@ static ProgramStateRef checkElementNonNil(CheckerContext &C, ProgramStateRef State, const ObjCForCollectionStmt *FCS) { if (!State) - return NULL; + return nullptr; // See if the collection is one where we /know/ the elements are non-nil. if (!isKnownNonNilCollectionType(FCS->getCollection()->getType())) @@ -882,7 +924,7 @@ static ProgramStateRef checkElementNonNil(CheckerContext &C, Optional<Loc> ElementLoc; if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) { const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl()); - assert(ElemDecl->getInit() == 0); + assert(ElemDecl->getInit() == nullptr); ElementLoc = State->getLValue(ElemDecl, LCtx); } else { ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>(); @@ -909,7 +951,7 @@ assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State, const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS); if (!KnownNonEmpty) return State->set<ContainerNonEmptyMap>(CollectionS, Assumption); - return (Assumption == *KnownNonEmpty) ? State : NULL; + return (Assumption == *KnownNonEmpty) ? State : nullptr; } SValBuilder &SvalBuilder = C.getSValBuilder(); @@ -934,7 +976,7 @@ assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State, const ObjCForCollectionStmt *FCS, bool Assumption) { if (!State) - return NULL; + return nullptr; SymbolRef CollectionS = State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol(); @@ -1049,11 +1091,11 @@ void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M, static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) { const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call); if (!Message) - return 0; + return nullptr; const ObjCMethodDecl *MD = Message->getDecl(); if (!MD) - return 0; + return nullptr; const ObjCInterfaceDecl *StaticClass; if (isa<ObjCProtocolDecl>(MD->getDeclContext())) { @@ -1066,11 +1108,11 @@ static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) { } if (!StaticClass) - return 0; + return nullptr; switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) { case FC_None: - return 0; + return nullptr; case FC_NSArray: case FC_NSDictionary: case FC_NSEnumerator: @@ -1135,7 +1177,10 @@ namespace { /// \brief The checker restricts the return values of APIs known to /// never (or almost never) return 'nil'. class ObjCNonNilReturnValueChecker - : public Checker<check::PostObjCMessage> { + : public Checker<check::PostObjCMessage, + check::PostStmt<ObjCArrayLiteral>, + check::PostStmt<ObjCDictionaryLiteral>, + check::PostStmt<ObjCBoxedExpr> > { mutable bool Initialized; mutable Selector ObjectAtIndex; mutable Selector ObjectAtIndexedSubscript; @@ -1143,13 +1188,32 @@ class ObjCNonNilReturnValueChecker public: ObjCNonNilReturnValueChecker() : Initialized(false) {} + + ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr, + ProgramStateRef State, + CheckerContext &C) const; + void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const { + C.addTransition(assumeExprIsNonNull(E, C.getState(), C)); + } + + void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const { + assumeExprIsNonNull(E, C); + } + void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const { + assumeExprIsNonNull(E, C); + } + void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const { + assumeExprIsNonNull(E, C); + } + void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; }; } -static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr, - ProgramStateRef State, - CheckerContext &C) { +ProgramStateRef +ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr, + ProgramStateRef State, + CheckerContext &C) const { SVal Val = State->getSVal(NonNullExpr, C.getLocationContext()); if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>()) return State->assume(*DV, true); @@ -1237,6 +1301,7 @@ void ento::registerObjCLoopChecker(CheckerManager &mgr) { mgr.registerChecker<ObjCLoopChecker>(); } -void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) { +void +ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) { mgr.registerChecker<ObjCNonNilReturnValueChecker>(); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp index 5169244..83a37c9 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp @@ -23,7 +23,7 @@ using namespace ento; namespace { class BoolAssignmentChecker : public Checker< check::Bind > { - mutable OwningPtr<BuiltinBug> BT; + mutable std::unique_ptr<BuiltinBug> BT; void emitReport(ProgramStateRef state, CheckerContext &C) const; public: void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const; @@ -34,7 +34,7 @@ void BoolAssignmentChecker::emitReport(ProgramStateRef state, CheckerContext &C) const { if (ExplodedNode *N = C.addTransition(state)) { if (!BT) - BT.reset(new BuiltinBug("Assignment of a non-Boolean value")); + BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value")); C.emitReport(new BugReport(*BT, BT->getDescription(), N)); } } @@ -96,7 +96,7 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S, } ProgramStateRef stateLT, stateGE; - llvm::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero); + std::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero); // Is it possible for the value to be less than zero? if (stateLT) { @@ -132,7 +132,7 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S, } ProgramStateRef stateGT, stateLE; - llvm::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne); + std::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne); // Is it possible for the value to be greater than one? if (stateGT) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index c3736d7..0693bd6f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -35,11 +35,8 @@ class CStringChecker : public Checker< eval::Call, check::DeadSymbols, check::RegionChanges > { - mutable OwningPtr<BugType> BT_Null, - BT_Bounds, - BT_Overlap, - BT_NotCString, - BT_AdditionOverflow; + mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap, + BT_NotCString, BT_AdditionOverflow; mutable const char *CurrentFunctionDescription; @@ -51,6 +48,11 @@ public: DefaultBool CheckCStringOutOfBounds; DefaultBool CheckCStringBufferOverlap; DefaultBool CheckCStringNotNullTerm; + + CheckName CheckNameCStringNullArg; + CheckName CheckNameCStringOutOfBounds; + CheckName CheckNameCStringBufferOverlap; + CheckName CheckNameCStringNotNullTerm; }; CStringChecksFilter Filter; @@ -157,24 +159,24 @@ public: ProgramStateRef state, const Expr *S, SVal l, - const char *message = NULL) const; + const char *message = nullptr) const; ProgramStateRef CheckBufferAccess(CheckerContext &C, ProgramStateRef state, const Expr *Size, const Expr *FirstBuf, const Expr *SecondBuf, - const char *firstMessage = NULL, - const char *secondMessage = NULL, + const char *firstMessage = nullptr, + const char *secondMessage = nullptr, bool WarnAboutSize = false) const; ProgramStateRef CheckBufferAccess(CheckerContext &C, ProgramStateRef state, const Expr *Size, const Expr *Buf, - const char *message = NULL, + const char *message = nullptr, bool WarnAboutSize = false) const { // This is a convenience override. - return CheckBufferAccess(C, state, Size, Buf, NULL, message, NULL, + return CheckBufferAccess(C, state, Size, Buf, nullptr, message, nullptr, WarnAboutSize); } ProgramStateRef CheckOverlap(CheckerContext &C, @@ -218,22 +220,23 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, const Expr *S, SVal l) const { // If a previous check has failed, propagate the failure. if (!state) - return NULL; + return nullptr; ProgramStateRef stateNull, stateNonNull; - llvm::tie(stateNull, stateNonNull) = assumeZero(C, state, l, S->getType()); + std::tie(stateNull, stateNonNull) = assumeZero(C, state, l, S->getType()); if (stateNull && !stateNonNull) { if (!Filter.CheckCStringNullArg) - return NULL; + return nullptr; ExplodedNode *N = C.generateSink(stateNull); if (!N) - return NULL; + return nullptr; if (!BT_Null) - BT_Null.reset(new BuiltinBug(categories::UnixAPI, - "Null pointer argument in call to byte string function")); + BT_Null.reset(new BuiltinBug( + Filter.CheckNameCStringNullArg, categories::UnixAPI, + "Null pointer argument in call to byte string function")); SmallString<80> buf; llvm::raw_svector_ostream os(buf); @@ -247,7 +250,7 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, report->addRange(S->getSourceRange()); bugreporter::trackNullOrUndefValue(N, S, *report); C.emitReport(report); - return NULL; + return nullptr; } // From here on, assume that the value is non-null. @@ -262,7 +265,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, const char *warningMsg) const { // If a previous check has failed, propagate the failure. if (!state) - return NULL; + return nullptr; // Check for out of bound array element access. const MemRegion *R = l.getAsRegion(); @@ -291,11 +294,12 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, if (StOutBound && !StInBound) { ExplodedNode *N = C.generateSink(StOutBound); if (!N) - return NULL; + return nullptr; if (!BT_Bounds) { - BT_Bounds.reset(new BuiltinBug("Out-of-bound array access", - "Byte string function accesses out-of-bound array element")); + BT_Bounds.reset(new BuiltinBug( + Filter.CheckNameCStringOutOfBounds, "Out-of-bound array access", + "Byte string function accesses out-of-bound array element")); } BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Bounds.get()); @@ -321,7 +325,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, report->addRange(S->getSourceRange()); C.emitReport(report); - return NULL; + return nullptr; } // Array bound check succeeded. From this point forward the array bound @@ -339,7 +343,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, bool WarnAboutSize) const { // If a previous check has failed, propagate the failure. if (!state) - return NULL; + return nullptr; SValBuilder &svalBuilder = C.getSValBuilder(); ASTContext &Ctx = svalBuilder.getContext(); @@ -352,7 +356,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, SVal BufVal = state->getSVal(FirstBuf, LCtx); state = checkNonNull(C, state, FirstBuf, BufVal); if (!state) - return NULL; + return nullptr; // If out-of-bounds checking is turned off, skip the rest. if (!Filter.CheckCStringOutOfBounds) @@ -382,7 +386,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, // If the buffer isn't large enough, abort. if (!state) - return NULL; + return nullptr; } // If there's a second buffer, check it as well. @@ -390,7 +394,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, BufVal = state->getSVal(SecondBuf, LCtx); state = checkNonNull(C, state, SecondBuf, BufVal); if (!state) - return NULL; + return nullptr; BufStart = svalBuilder.evalCast(BufVal, PtrTy, SecondBuf->getType()); if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) { @@ -420,7 +424,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, // If a previous check has failed, propagate the failure. if (!state) - return NULL; + return nullptr; ProgramStateRef stateTrue, stateFalse; @@ -439,13 +443,13 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, // Are the two values the same? SValBuilder &svalBuilder = C.getSValBuilder(); - llvm::tie(stateTrue, stateFalse) = + std::tie(stateTrue, stateFalse) = state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc)); if (stateTrue && !stateFalse) { // If the values are known to be equal, that's automatically an overlap. emitOverlapBug(C, stateTrue, First, Second); - return NULL; + return nullptr; } // assume the two expressions are not equal. @@ -461,7 +465,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, if (!reverseTest) return state; - llvm::tie(stateTrue, stateFalse) = state->assume(*reverseTest); + std::tie(stateTrue, stateFalse) = state->assume(*reverseTest); if (stateTrue) { if (stateFalse) { // If we don't know which one comes first, we can't perform this test. @@ -506,12 +510,12 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, if (!OverlapTest) return state; - llvm::tie(stateTrue, stateFalse) = state->assume(*OverlapTest); + std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest); if (stateTrue && !stateFalse) { // Overlap! emitOverlapBug(C, stateTrue, First, Second); - return NULL; + return nullptr; } // assume the two expressions don't overlap. @@ -526,7 +530,8 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state, return; if (!BT_Overlap) - BT_Overlap.reset(new BugType(categories::UnixAPI, "Improper arguments")); + BT_Overlap.reset(new BugType(Filter.CheckNameCStringBufferOverlap, + categories::UnixAPI, "Improper arguments")); // Generate a report for this bug. BugReport *report = @@ -548,7 +553,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, // If a previous check has failed, propagate the failure. if (!state) - return NULL; + return nullptr; SValBuilder &svalBuilder = C.getSValBuilder(); BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); @@ -576,18 +581,19 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, *maxMinusRightNL, cmpTy); ProgramStateRef stateOverflow, stateOkay; - llvm::tie(stateOverflow, stateOkay) = + std::tie(stateOverflow, stateOkay) = state->assume(willOverflow.castAs<DefinedOrUnknownSVal>()); if (stateOverflow && !stateOkay) { // We have an overflow. Emit a bug report. ExplodedNode *N = C.generateSink(stateOverflow); if (!N) - return NULL; + return nullptr; if (!BT_AdditionOverflow) - BT_AdditionOverflow.reset(new BuiltinBug("API", - "Sum of expressions causes overflow")); + BT_AdditionOverflow.reset( + new BuiltinBug(Filter.CheckNameCStringOutOfBounds, "API", + "Sum of expressions causes overflow")); // This isn't a great error message, but this should never occur in real // code anyway -- you'd have to create a buffer longer than a size_t can @@ -600,7 +606,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, BugReport *report = new BugReport(*BT_AdditionOverflow, warning, N); C.emitReport(report); - return NULL; + return nullptr; } // From now on, assume an overflow didn't occur. @@ -703,8 +709,9 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, if (ExplodedNode *N = C.addTransition(state)) { if (!BT_NotCString) - BT_NotCString.reset(new BuiltinBug(categories::UnixAPI, - "Argument is not a null-terminated string.")); + BT_NotCString.reset(new BuiltinBug( + Filter.CheckNameCStringNotNullTerm, categories::UnixAPI, + "Argument is not a null-terminated string.")); SmallString<120> buf; llvm::raw_svector_ostream os(buf); @@ -714,8 +721,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, << "', which is not a null-terminated string"; // Generate a report for this bug. - BugReport *report = new BugReport(*BT_NotCString, - os.str(), N); + BugReport *report = new BugReport(*BT_NotCString, os.str(), N); report->addRange(Ex->getSourceRange()); C.emitReport(report); @@ -763,8 +769,9 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, if (ExplodedNode *N = C.addTransition(state)) { if (!BT_NotCString) - BT_NotCString.reset(new BuiltinBug(categories::UnixAPI, - "Argument is not a null-terminated string.")); + BT_NotCString.reset(new BuiltinBug( + Filter.CheckNameCStringNotNullTerm, categories::UnixAPI, + "Argument is not a null-terminated string.")); SmallString<120> buf; llvm::raw_svector_ostream os(buf); @@ -795,7 +802,7 @@ const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C, // Get the memory region pointed to by the val. const MemRegion *bufRegion = val.getAsRegion(); if (!bufRegion) - return NULL; + return nullptr; // Strip casts off the memory region. bufRegion = bufRegion->StripCasts(); @@ -803,7 +810,7 @@ const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C, // Cast the memory region to a string region. const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion); if (!strRegion) - return NULL; + return nullptr; // Return the actual string in the string region. return strRegion->getStringLiteral(); @@ -845,7 +852,8 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C, } return state->invalidateRegions(R, E, C.blockCount(), LCtx, - CausesPointerEscape, 0, 0, &ITraits); + CausesPointerEscape, nullptr, nullptr, + &ITraits); } // If we have a non-region value by chance, just remove the binding. @@ -909,7 +917,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, QualType sizeTy = Size->getType(); ProgramStateRef stateZeroSize, stateNonZeroSize; - llvm::tie(stateZeroSize, stateNonZeroSize) = + std::tie(stateZeroSize, stateNonZeroSize) = assumeZero(C, state, sizeVal, sizeTy); // Get the value of the Dest. @@ -946,7 +954,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const char * const writeWarning = "Memory copy function overflows destination buffer"; state = CheckBufferAccess(C, state, Size, Dest, Source, - writeWarning, /* sourceWarning = */ NULL); + writeWarning, /* sourceWarning = */ nullptr); if (Restricted) state = CheckOverlap(C, state, Size, Dest, Source); @@ -971,7 +979,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, } else { // If we don't know how much we copied, we can at least // conjure a return value for later. - SVal result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, + SVal result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); state = state->BindExpr(CE, LCtx, result); } @@ -1066,7 +1074,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { QualType sizeTy = Size->getType(); ProgramStateRef stateZeroSize, stateNonZeroSize; - llvm::tie(stateZeroSize, stateNonZeroSize) = + std::tie(stateZeroSize, stateNonZeroSize) = assumeZero(C, state, sizeVal, sizeTy); // If the size can be zero, the result will be 0 in that case, and we don't @@ -1092,7 +1100,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { // See if they are the same. DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV); ProgramStateRef StSameBuf, StNotSameBuf; - llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); + std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); // If the two arguments might be the same buffer, we know the result is 0, // and we only need to check one size. @@ -1113,7 +1121,8 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { state = CheckBufferAccess(C, state, Size, Left, Right); if (state) { // The return value is the comparison result, which we don't know. - SVal CmpV = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount()); + SVal CmpV = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, + C.blockCount()); state = state->BindExpr(CE, LCtx, CmpV); C.addTransition(state); } @@ -1150,7 +1159,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); ProgramStateRef stateZeroSize, stateNonZeroSize; - llvm::tie(stateZeroSize, stateNonZeroSize) = + std::tie(stateZeroSize, stateNonZeroSize) = assumeZero(C, state, maxlenVal, maxlenExpr->getType()); // If the size can be zero, the result will be 0 in that case, and we don't @@ -1204,10 +1213,10 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, ProgramStateRef stateStringTooLong, stateStringNotTooLong; // Check if the strLength is greater than the maxlen. - llvm::tie(stateStringTooLong, stateStringNotTooLong) = - state->assume(C.getSValBuilder().evalBinOpNN( - state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy) - .castAs<DefinedOrUnknownSVal>()); + std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume( + C.getSValBuilder() + .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy) + .castAs<DefinedOrUnknownSVal>()); if (stateStringTooLong && !stateStringNotTooLong) { // If the string is longer than maxlen, return maxlen. @@ -1223,7 +1232,8 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, // no guarantee the full string length will actually be returned. // All we know is the return value is the min of the string length // and the limit. This is better than nothing. - result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, C.blockCount()); + result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, + C.blockCount()); NonLoc resultNL = result.castAs<NonLoc>(); if (strLengthNL) { @@ -1246,7 +1256,8 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, // If we don't know the length of the string, conjure a return // value, so it can be used in constraints, at least. if (result.isUnknown()) { - result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, C.blockCount()); + result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, + C.blockCount()); } } @@ -1349,7 +1360,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, // - potential overflows caused by a bound that could exceed the destination SVal amountCopied = UnknownVal(); SVal maxLastElementIndex = UnknownVal(); - const char *boundWarning = NULL; + const char *boundWarning = nullptr; // If the function is strncpy, strncat, etc... it is bounded. if (isBounded) { @@ -1371,7 +1382,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, // Check if the max number to copy is less than the length of the src. // If the bound is equal to the source length, strncpy won't null- // terminate the result! - llvm::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume( + std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume( svalBuilder.evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy) .castAs<DefinedOrUnknownSVal>()); @@ -1418,7 +1429,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, // case strncpy will do no work at all. Our bounds check uses n-1 // as the last element accessed, so n == 0 is problematic. ProgramStateRef StateZeroSize, StateNonZeroSize; - llvm::tie(StateZeroSize, StateNonZeroSize) = + std::tie(StateZeroSize, StateNonZeroSize) = assumeZero(C, state, *lenValNL, sizeTy); // If the size is known to be zero, we're done. @@ -1629,7 +1640,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, // If this is a stpcpy-style copy, but we were unable to check for a buffer // overflow, we still need a result. Conjure a return value. if (returnEnd && Result.isUnknown()) { - Result = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount()); + Result = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); } // Set the return value. @@ -1711,7 +1722,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, SValBuilder &svalBuilder = C.getSValBuilder(); DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV); ProgramStateRef StSameBuf, StNotSameBuf; - llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); + std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); // If the two arguments might be the same buffer, we know the result is 0, // and we only need to check one size. @@ -1786,7 +1797,8 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, if (!canComputeResult) { // Conjure a symbolic value. It's the best we can do. - SVal resultVal = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount()); + SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, + C.blockCount()); state = state->BindExpr(CE, LCtx, resultVal); } @@ -1843,7 +1855,7 @@ void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const { } else { assert(SearchStrVal.isUnknown()); // Conjure a symbolic value. It's the best we can do. - Result = SVB.conjureSymbolVal(0, CE, LCtx, C.blockCount()); + Result = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); } // Set the return value, and finish. @@ -1863,7 +1875,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { return false; // FIXME: Poorly-factored string switches are slow. - FnCheck evalFunction = 0; + FnCheck evalFunction = nullptr; if (C.isCLibraryFunction(FDecl, "memcpy")) evalFunction = &CStringChecker::evalMemcpy; else if (C.isCLibraryFunction(FDecl, "mempcpy")) @@ -1907,7 +1919,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { // Make sure each function sets its own description. // (But don't bother in a release build.) - assert(!(CurrentFunctionDescription = NULL)); + assert(!(CurrentFunctionDescription = nullptr)); // Check and evaluate the call. (this->*evalFunction)(C, CE); @@ -1928,9 +1940,8 @@ void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { // Record string length for char a[] = "abc"; ProgramStateRef state = C.getState(); - for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end(); - I != E; ++I) { - const VarDecl *D = dyn_cast<VarDecl>(*I); + for (const auto *I : DS->decls()) { + const VarDecl *D = dyn_cast<VarDecl>(I); if (!D) continue; @@ -2057,10 +2068,12 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR, C.addTransition(state); } -#define REGISTER_CHECKER(name) \ -void ento::register##name(CheckerManager &mgr) {\ - mgr.registerChecker<CStringChecker>()->Filter.Check##name = true; \ -} +#define REGISTER_CHECKER(name) \ + void ento::register##name(CheckerManager &mgr) { \ + CStringChecker *checker = mgr.registerChecker<CStringChecker>(); \ + checker->Filter.Check##name = true; \ + checker->Filter.CheckName##name = mgr.getCurrentCheckName(); \ + } REGISTER_CHECKER(CStringNullArg) REGISTER_CHECKER(CStringOutOfBounds) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp index d29a12a..abfb971d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp @@ -31,6 +31,7 @@ using namespace ento; namespace { class WalkAST: public StmtVisitor<WalkAST> { + const CheckerBase *Checker; BugReporter &BR; AnalysisDeclContext* AC; @@ -81,9 +82,8 @@ class WalkAST: public StmtVisitor<WalkAST> { bool containsBadStrncatPattern(const CallExpr *CE); public: - WalkAST(BugReporter &br, AnalysisDeclContext* ac) : - BR(br), AC(ac) { - } + WalkAST(const CheckerBase *checker, BugReporter &br, AnalysisDeclContext *ac) + : Checker(checker), BR(br), AC(ac) {} // Statement visitor methods. void VisitChildren(Stmt *S); @@ -157,8 +157,9 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { os << "U"; os << "se a safer 'strlcat' API"; - BR.EmitBasicReport(FD, "Anti-pattern in the argument", "C String API", - os.str(), Loc, LenArg->getSourceRange()); + BR.EmitBasicReport(FD, Checker, "Anti-pattern in the argument", + "C String API", os.str(), Loc, + LenArg->getSourceRange()); } } @@ -179,7 +180,7 @@ public: void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr, BugReporter &BR) const { - WalkAST walker(BR, Mgr.getAnalysisDeclContext(D)); + WalkAST walker(this, BR, Mgr.getAnalysisDeclContext(D)); walker.Visit(D->getBody()); } }; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index fefcbe7..adb7a54 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -27,24 +27,35 @@ using namespace clang; using namespace ento; namespace { + +struct ChecksFilter { + DefaultBool Check_CallAndMessageUnInitRefArg; + DefaultBool Check_CallAndMessageChecker; + + CheckName CheckName_CallAndMessageUnInitRefArg; + CheckName CheckName_CallAndMessageChecker; +}; + class CallAndMessageChecker : public Checker< check::PreStmt<CallExpr>, check::PreStmt<CXXDeleteExpr>, check::PreObjCMessage, check::PreCall > { - mutable OwningPtr<BugType> BT_call_null; - mutable OwningPtr<BugType> BT_call_undef; - mutable OwningPtr<BugType> BT_cxx_call_null; - mutable OwningPtr<BugType> BT_cxx_call_undef; - mutable OwningPtr<BugType> BT_call_arg; - mutable OwningPtr<BugType> BT_cxx_delete_undef; - mutable OwningPtr<BugType> BT_msg_undef; - mutable OwningPtr<BugType> BT_objc_prop_undef; - mutable OwningPtr<BugType> BT_objc_subscript_undef; - mutable OwningPtr<BugType> BT_msg_arg; - mutable OwningPtr<BugType> BT_msg_ret; - mutable OwningPtr<BugType> BT_call_few_args; + mutable std::unique_ptr<BugType> BT_call_null; + mutable std::unique_ptr<BugType> BT_call_undef; + mutable std::unique_ptr<BugType> BT_cxx_call_null; + mutable std::unique_ptr<BugType> BT_cxx_call_undef; + mutable std::unique_ptr<BugType> BT_call_arg; + mutable std::unique_ptr<BugType> BT_cxx_delete_undef; + mutable std::unique_ptr<BugType> BT_msg_undef; + mutable std::unique_ptr<BugType> BT_objc_prop_undef; + mutable std::unique_ptr<BugType> BT_objc_subscript_undef; + mutable std::unique_ptr<BugType> BT_msg_arg; + mutable std::unique_ptr<BugType> BT_msg_ret; + mutable std::unique_ptr<BugType> BT_call_few_args; + public: + ChecksFilter Filter; void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const; @@ -52,10 +63,11 @@ public: void checkPreCall(const CallEvent &Call, CheckerContext &C) const; private: - static bool PreVisitProcessArg(CheckerContext &C, SVal V, - SourceRange argRange, const Expr *argEx, - bool IsFirstArgument, bool checkUninitFields, - const CallEvent &Call, OwningPtr<BugType> &BT); + bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange, + const Expr *ArgEx, bool IsFirstArgument, + bool CheckUninitFields, const CallEvent &Call, + std::unique_ptr<BugType> &BT, + const ParmVarDecl *ParamDecl) const; static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE); void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg, @@ -65,10 +77,14 @@ private: ProgramStateRef state, const ObjCMethodCall &msg) const; - static void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) { + void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const { if (!BT) - BT.reset(new BuiltinBug(desc)); + BT.reset(new BuiltinBug(this, desc)); } + bool uninitRefOrPointer(CheckerContext &C, const SVal &V, + const SourceRange &ArgRange, + const Expr *ArgEx, std::unique_ptr<BugType> &BT, + const ParmVarDecl *ParamDecl, const char *BD) const; }; } // end anonymous namespace @@ -113,30 +129,86 @@ static StringRef describeUninitializedArgumentInCall(const CallEvent &Call, } } +bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C, + const SVal &V, + const SourceRange &ArgRange, + const Expr *ArgEx, + std::unique_ptr<BugType> &BT, + const ParmVarDecl *ParamDecl, + const char *BD) const { + if (!Filter.Check_CallAndMessageUnInitRefArg) + return false; + + // No parameter declaration available, i.e. variadic function argument. + if(!ParamDecl) + return false; + + // If parameter is declared as pointer to const in function declaration, + // then check if corresponding argument in function call is + // pointing to undefined symbol value (uninitialized memory). + StringRef Message; + + if (ParamDecl->getType()->isPointerType()) { + Message = "Function call argument is a pointer to uninitialized value"; + } else if (ParamDecl->getType()->isReferenceType()) { + Message = "Function call argument is an uninitialized value"; + } else + return false; + + if(!ParamDecl->getType()->getPointeeType().isConstQualified()) + return false; + + if (const MemRegion *SValMemRegion = V.getAsRegion()) { + const ProgramStateRef State = C.getState(); + const SVal PSV = State->getSVal(SValMemRegion); + if (PSV.isUndef()) { + if (ExplodedNode *N = C.generateSink()) { + LazyInit_BT(BD, BT); + BugReport *R = new BugReport(*BT, Message, N); + R->addRange(ArgRange); + if (ArgEx) { + bugreporter::trackNullOrUndefValue(N, ArgEx, *R); + } + C.emitReport(R); + } + return true; + } + } + return false; +} + bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, - SVal V, SourceRange argRange, - const Expr *argEx, + SVal V, + SourceRange ArgRange, + const Expr *ArgEx, bool IsFirstArgument, - bool checkUninitFields, + bool CheckUninitFields, const CallEvent &Call, - OwningPtr<BugType> &BT) { + std::unique_ptr<BugType> &BT, + const ParmVarDecl *ParamDecl + ) const { + const char *BD = "Uninitialized argument value"; + + if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD)) + return true; + if (V.isUndef()) { if (ExplodedNode *N = C.generateSink()) { - LazyInit_BT("Uninitialized argument value", BT); + LazyInit_BT(BD, BT); // Generate a report for this bug. - StringRef Desc = describeUninitializedArgumentInCall(Call, - IsFirstArgument); + StringRef Desc = + describeUninitializedArgumentInCall(Call, IsFirstArgument); BugReport *R = new BugReport(*BT, Desc, N); - R->addRange(argRange); - if (argEx) - bugreporter::trackNullOrUndefValue(N, argEx, *R); + R->addRange(ArgRange); + if (ArgEx) + bugreporter::trackNullOrUndefValue(N, ArgEx, *R); C.emitReport(R); } return true; } - if (!checkUninitFields) + if (!CheckUninitFields) return false; if (Optional<nonloc::LazyCompoundVal> LV = @@ -159,10 +231,9 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, if (const RecordType *RT = T->getAsStructureType()) { const RecordDecl *RD = RT->getDecl()->getDefinition(); assert(RD && "Referred record has no definition"); - for (RecordDecl::field_iterator I = - RD->field_begin(), E = RD->field_end(); I!=E; ++I) { - const FieldRegion *FR = MrMgr.getFieldRegion(*I, R); - FieldChain.push_back(*I); + for (const auto *I : RD->fields()) { + const FieldRegion *FR = MrMgr.getFieldRegion(I, R); + FieldChain.push_back(I); T = I->getType(); if (T->getAsStructureType()) { if (Find(FR)) @@ -188,7 +259,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, if (F.Find(D->getRegion())) { if (ExplodedNode *N = C.generateSink()) { - LazyInit_BT("Uninitialized argument value", BT); + LazyInit_BT(BD, BT); SmallString<512> Str; llvm::raw_svector_ostream os(Str); os << "Passed-by-value struct argument contains uninitialized data"; @@ -211,7 +282,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, // Generate a report for this bug. BugReport *R = new BugReport(*BT, os.str(), N); - R->addRange(argRange); + R->addRange(ArgRange); // FIXME: enhance track back for uninitialized value for arbitrary // memregions @@ -234,20 +305,19 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, if (L.isUndef()) { if (!BT_call_undef) - BT_call_undef.reset(new BuiltinBug("Called function pointer is an " - "uninitalized pointer value")); + BT_call_undef.reset(new BuiltinBug( + this, "Called function pointer is an uninitalized pointer value")); emitBadCall(BT_call_undef.get(), C, Callee); return; } ProgramStateRef StNonNull, StNull; - llvm::tie(StNonNull, StNull) = - State->assume(L.castAs<DefinedOrUnknownSVal>()); + std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>()); if (StNull && !StNonNull) { if (!BT_call_null) - BT_call_null.reset( - new BuiltinBug("Called function pointer is null (null dereference)")); + BT_call_null.reset(new BuiltinBug( + this, "Called function pointer is null (null dereference)")); emitBadCall(BT_call_null.get(), C, Callee); return; } @@ -265,7 +335,8 @@ void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE, if (!N) return; if (!BT_cxx_delete_undef) - BT_cxx_delete_undef.reset(new BuiltinBug("Uninitialized argument value")); + BT_cxx_delete_undef.reset( + new BuiltinBug(this, "Uninitialized argument value")); if (DE->isArrayFormAsWritten()) Desc = "Argument to 'delete[]' is uninitialized"; else @@ -289,20 +360,20 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call, SVal V = CC->getCXXThisVal(); if (V.isUndef()) { if (!BT_cxx_call_undef) - BT_cxx_call_undef.reset(new BuiltinBug("Called C++ object pointer is " - "uninitialized")); + BT_cxx_call_undef.reset( + new BuiltinBug(this, "Called C++ object pointer is uninitialized")); emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr()); return; } ProgramStateRef StNonNull, StNull; - llvm::tie(StNonNull, StNull) = + std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>()); if (StNull && !StNonNull) { if (!BT_cxx_call_null) - BT_cxx_call_null.reset(new BuiltinBug("Called C++ object pointer " - "is null")); + BT_cxx_call_null.reset( + new BuiltinBug(this, "Called C++ object pointer is null")); emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr()); return; } @@ -311,7 +382,8 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call, } const Decl *D = Call.getDecl(); - if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) { + const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D); + if (FD) { // If we have a declaration, we can make sure we pass enough parameters to // the function. unsigned Params = FD->getNumParams(); @@ -340,17 +412,21 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call, const bool checkUninitFields = !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody())); - OwningPtr<BugType> *BT; + std::unique_ptr<BugType> *BT; if (isa<ObjCMethodCall>(Call)) BT = &BT_msg_arg; else BT = &BT_call_arg; - for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) + for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) { + const ParmVarDecl *ParamDecl = nullptr; + if(FD && i < FD->getNumParams()) + ParamDecl = FD->getParamDecl(i); if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i), Call.getArgExpr(i), /*IsFirstArgument=*/i == 0, - checkUninitFields, Call, *BT)) + checkUninitFields, Call, *BT, ParamDecl)) return; + } // If we make it here, record our assumptions about the callee. C.addTransition(State); @@ -361,26 +437,25 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg, SVal recVal = msg.getReceiverSVal(); if (recVal.isUndef()) { if (ExplodedNode *N = C.generateSink()) { - BugType *BT = 0; + BugType *BT = nullptr; switch (msg.getMessageKind()) { case OCM_Message: if (!BT_msg_undef) - BT_msg_undef.reset(new BuiltinBug("Receiver in message expression " + BT_msg_undef.reset(new BuiltinBug(this, + "Receiver in message expression " "is an uninitialized value")); BT = BT_msg_undef.get(); break; case OCM_PropertyAccess: if (!BT_objc_prop_undef) - BT_objc_prop_undef.reset(new BuiltinBug("Property access on an " - "uninitialized object " - "pointer")); + BT_objc_prop_undef.reset(new BuiltinBug( + this, "Property access on an uninitialized object pointer")); BT = BT_objc_prop_undef.get(); break; case OCM_Subscript: if (!BT_objc_subscript_undef) - BT_objc_subscript_undef.reset(new BuiltinBug("Subscript access on an " - "uninitialized object " - "pointer")); + BT_objc_subscript_undef.reset(new BuiltinBug( + this, "Subscript access on an uninitialized object pointer")); BT = BT_objc_subscript_undef.get(); break; } @@ -402,7 +477,7 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg, ProgramStateRef state = C.getState(); ProgramStateRef notNilState, nilState; - llvm::tie(notNilState, nilState) = state->assume(receiverVal); + std::tie(notNilState, nilState) = state->assume(receiverVal); // Handle receiver must be nil. if (nilState && !notNilState) { @@ -418,7 +493,7 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, if (!BT_msg_ret) BT_msg_ret.reset( - new BuiltinBug("Receiver in message expression is 'nil'")); + new BuiltinBug(this, "Receiver in message expression is 'nil'")); const ObjCMessageExpr *ME = msg.getOriginExpr(); @@ -426,8 +501,9 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, SmallString<200> buf; llvm::raw_svector_ostream os(buf); - os << "The receiver of message '" << ME->getSelector().getAsString() - << "' is nil"; + os << "The receiver of message '"; + ME->getSelector().print(os); + os << "' is nil"; if (ResTy->isReferenceType()) { os << ", which results in forming a null reference"; } else { @@ -454,7 +530,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, ProgramStateRef state, const ObjCMethodCall &Msg) const { ASTContext &Ctx = C.getASTContext(); - static SimpleProgramPointTag Tag("CallAndMessageChecker : NilReceiver"); + static CheckerProgramPointTag Tag(this, "NilReceiver"); // Check the return type of the message expression. A message to nil will // return different values depending on the return type and the architecture. @@ -484,7 +560,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, Ctx.LongDoubleTy == CanRetTy || Ctx.LongLongTy == CanRetTy || Ctx.UnsignedLongLongTy == CanRetTy)))) { - if (ExplodedNode *N = C.generateSink(state, 0 , &Tag)) + if (ExplodedNode *N = C.generateSink(state, nullptr, &Tag)) emitNilReceiverBug(C, Msg, N); return; } @@ -510,6 +586,13 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, C.addTransition(state); } -void ento::registerCallAndMessageChecker(CheckerManager &mgr) { - mgr.registerChecker<CallAndMessageChecker>(); -} +#define REGISTER_CHECKER(name) \ + void ento::register##name(CheckerManager &mgr) { \ + CallAndMessageChecker *Checker = \ + mgr.registerChecker<CallAndMessageChecker>(); \ + Checker->Filter.Check_##name = true; \ + Checker->Filter.CheckName_##name = mgr.getCurrentCheckName(); \ + } + +REGISTER_CHECKER(CallAndMessageUnInitRefArg) +REGISTER_CHECKER(CallAndMessageChecker) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp index 5e6e1054..3ba063d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp @@ -23,12 +23,71 @@ using namespace ento; namespace { class CastSizeChecker : public Checker< check::PreStmt<CastExpr> > { - mutable OwningPtr<BuiltinBug> BT; + mutable std::unique_ptr<BuiltinBug> BT; + public: void checkPreStmt(const CastExpr *CE, CheckerContext &C) const; }; } +/// Check if we are casting to a struct with a flexible array at the end. +/// \code +/// struct foo { +/// size_t len; +/// struct bar data[]; +/// }; +/// \endcode +/// or +/// \code +/// struct foo { +/// size_t len; +/// struct bar data[0]; +/// } +/// \endcode +/// In these cases it is also valid to allocate size of struct foo + a multiple +/// of struct bar. +static bool evenFlexibleArraySize(ASTContext &Ctx, CharUnits RegionSize, + CharUnits TypeSize, QualType ToPointeeTy) { + const RecordType *RT = ToPointeeTy->getAs<RecordType>(); + if (!RT) + return false; + + const RecordDecl *RD = RT->getDecl(); + RecordDecl::field_iterator Iter(RD->field_begin()); + RecordDecl::field_iterator End(RD->field_end()); + const FieldDecl *Last = nullptr; + for (; Iter != End; ++Iter) + Last = *Iter; + assert(Last && "empty structs should already be handled"); + + const Type *ElemType = Last->getType()->getArrayElementTypeNoTypeQual(); + CharUnits FlexSize; + if (const ConstantArrayType *ArrayTy = + Ctx.getAsConstantArrayType(Last->getType())) { + FlexSize = Ctx.getTypeSizeInChars(ElemType); + if (ArrayTy->getSize() == 1 && TypeSize > FlexSize) + TypeSize -= FlexSize; + else if (ArrayTy->getSize() != 0) + return false; + } else if (RD->hasFlexibleArrayMember()) { + FlexSize = Ctx.getTypeSizeInChars(ElemType); + } else { + return false; + } + + if (FlexSize.isZero()) + return false; + + CharUnits Left = RegionSize - TypeSize; + if (Left.isNegative()) + return false; + + if (Left % FlexSize == 0) + return true; + + return false; +} + void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const { const Expr *E = CE->getSubExpr(); ASTContext &Ctx = C.getASTContext(); @@ -46,11 +105,11 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const { ProgramStateRef state = C.getState(); const MemRegion *R = state->getSVal(E, C.getLocationContext()).getAsRegion(); - if (R == 0) + if (!R) return; const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R); - if (SR == 0) + if (!SR) return; SValBuilder &svalBuilder = C.getSValBuilder(); @@ -66,21 +125,23 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const { if (typeSize.isZero()) return; - if (regionSize % typeSize != 0) { - if (ExplodedNode *errorNode = C.generateSink()) { - if (!BT) - BT.reset(new BuiltinBug("Cast region with wrong size.", - "Cast a region whose size is not a multiple of the" - " destination type size.")); - BugReport *R = new BugReport(*BT, BT->getDescription(), - errorNode); - R->addRange(CE->getSourceRange()); - C.emitReport(R); - } + if (regionSize % typeSize == 0) + return; + + if (evenFlexibleArraySize(Ctx, regionSize, typeSize, ToPointeeTy)) + return; + + if (ExplodedNode *errorNode = C.generateSink()) { + if (!BT) + BT.reset(new BuiltinBug(this, "Cast region with wrong size.", + "Cast a region whose size is not a multiple" + " of the destination type size.")); + BugReport *R = new BugReport(*BT, BT->getDescription(), errorNode); + R->addRange(CE->getSourceRange()); + C.emitReport(R); } } - void ento::registerCastSizeChecker(CheckerManager &mgr) { - mgr.registerChecker<CastSizeChecker>(); + mgr.registerChecker<CastSizeChecker>(); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp index 60348c7..d765315 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp @@ -24,7 +24,7 @@ using namespace ento; namespace { class CastToStructChecker : public Checker< check::PreStmt<CastExpr> > { - mutable OwningPtr<BuiltinBug> BT; + mutable std::unique_ptr<BuiltinBug> BT; public: void checkPreStmt(const CastExpr *CE, CheckerContext &C) const; @@ -58,10 +58,11 @@ void CastToStructChecker::checkPreStmt(const CastExpr *CE, if (!OrigPointeeTy->isRecordType()) { if (ExplodedNode *N = C.addTransition()) { if (!BT) - BT.reset(new BuiltinBug("Cast from non-struct type to struct type", - "Casting a non-structure type to a structure type " - "and accessing a field can lead to memory access " - "errors or data corruption.")); + BT.reset( + new BuiltinBug(this, "Cast from non-struct type to struct type", + "Casting a non-structure type to a structure type " + "and accessing a field can lead to memory access " + "errors or data corruption.")); BugReport *R = new BugReport(*BT,BT->getDescription(), N); R->addRange(CE->getSourceRange()); C.emitReport(R); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index 3f9b3cc..d186144 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -97,8 +97,9 @@ static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID, return false; } -static void checkObjCDealloc(const ObjCImplementationDecl *D, - const LangOptions& LOpts, BugReporter& BR) { +static void checkObjCDealloc(const CheckerBase *Checker, + const ObjCImplementationDecl *D, + const LangOptions &LOpts, BugReporter &BR) { assert (LOpts.getGC() != LangOptions::GCOnly); @@ -112,15 +113,12 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D, bool containsPointerIvar = false; - for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end(); - I!=E; ++I) { - - ObjCIvarDecl *ID = *I; - QualType T = ID->getType(); + for (const auto *Ivar : ID->ivars()) { + QualType T = Ivar->getType(); if (!T->isObjCObjectPointerType() || - ID->getAttr<IBOutletAttr>() || // Skip IBOutlets. - ID->getAttr<IBOutletCollectionAttr>()) // Skip IBOutletCollections. + Ivar->hasAttr<IBOutletAttr>() || // Skip IBOutlets. + Ivar->hasAttr<IBOutletCollectionAttr>()) // Skip IBOutletCollections. continue; containsPointerIvar = true; @@ -155,14 +153,12 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D, // Get the "dealloc" selector. IdentifierInfo* II = &Ctx.Idents.get("dealloc"); Selector S = Ctx.Selectors.getSelector(0, &II); - ObjCMethodDecl *MD = 0; + const ObjCMethodDecl *MD = nullptr; // Scan the instance methods for "dealloc". - for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(), - E = D->instmeth_end(); I!=E; ++I) { - - if ((*I)->getSelector() == S) { - MD = *I; + for (const auto *I : D->instance_methods()) { + if (I->getSelector() == S) { + MD = I; break; } } @@ -180,7 +176,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D, llvm::raw_string_ostream os(buf); os << "Objective-C class '" << *D << "' lacks a 'dealloc' instance method"; - BR.EmitBasicReport(D, name, categories::CoreFoundationObjectiveC, + BR.EmitBasicReport(D, Checker, name, categories::CoreFoundationObjectiveC, os.str(), DLoc); return; } @@ -198,7 +194,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D, << "' does not send a 'dealloc' message to its super class" " (missing [super dealloc])"; - BR.EmitBasicReport(MD, name, categories::CoreFoundationObjectiveC, + BR.EmitBasicReport(MD, Checker, name, categories::CoreFoundationObjectiveC, os.str(), DLoc); return; } @@ -212,9 +208,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D, // Scan for missing and extra releases of ivars used by implementations // of synthesized properties - for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(), - E = D->propimpl_end(); I!=E; ++I) { - + for (const auto *I : D->property_impls()) { // We can only check the synthesized properties if (I->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize) continue; @@ -239,7 +233,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D, bool requiresRelease = PD->getSetterKind() != ObjCPropertyDecl::Assign; if (scan_ivar_release(MD->getBody(), ID, PD, RS, SelfII, Ctx) != requiresRelease) { - const char *name = 0; + const char *name = nullptr; std::string buf; llvm::raw_string_ostream os(buf); @@ -262,10 +256,10 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D, } PathDiagnosticLocation SDLoc = - PathDiagnosticLocation::createBegin(*I, BR.getSourceManager()); + PathDiagnosticLocation::createBegin(I, BR.getSourceManager()); - BR.EmitBasicReport(MD, name, categories::CoreFoundationObjectiveC, - os.str(), SDLoc); + BR.EmitBasicReport(MD, Checker, name, + categories::CoreFoundationObjectiveC, os.str(), SDLoc); } } } @@ -282,7 +276,8 @@ public: BugReporter &BR) const { if (mgr.getLangOpts().getGC() == LangOptions::GCOnly) return; - checkObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOpts(), BR); + checkObjCDealloc(this, cast<ObjCImplementationDecl>(D), mgr.getLangOpts(), + BR); } }; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp index 9cb1d2d..cc4c0c3 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp @@ -40,10 +40,11 @@ static bool AreTypesCompatible(QualType Derived, QualType Ancestor, static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, const ObjCMethodDecl *MethAncestor, BugReporter &BR, ASTContext &Ctx, - const ObjCImplementationDecl *ID) { + const ObjCImplementationDecl *ID, + const CheckerBase *Checker) { - QualType ResDerived = MethDerived->getResultType(); - QualType ResAncestor = MethAncestor->getResultType(); + QualType ResDerived = MethDerived->getReturnType(); + QualType ResAncestor = MethAncestor->getReturnType(); if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) { std::string sbuf; @@ -53,9 +54,9 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, << *MethDerived->getClassInterface() << "', which is derived from class '" << *MethAncestor->getClassInterface() - << "', defines the instance method '" - << MethDerived->getSelector().getAsString() - << "' whose return type is '" + << "', defines the instance method '"; + MethDerived->getSelector().print(os); + os << "' whose return type is '" << ResDerived.getAsString() << "'. A method with the same name (same selector) is also defined in " "class '" @@ -69,15 +70,15 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, PathDiagnosticLocation::createBegin(MethDerived, BR.getSourceManager()); - BR.EmitBasicReport(MethDerived, - "Incompatible instance method return type", - categories::CoreFoundationObjectiveC, - os.str(), MethDLoc); + BR.EmitBasicReport( + MethDerived, Checker, "Incompatible instance method return type", + categories::CoreFoundationObjectiveC, os.str(), MethDLoc); } } static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID, - BugReporter& BR) { + BugReporter &BR, + const CheckerBase *Checker) { const ObjCInterfaceDecl *D = ID->getClassInterface(); const ObjCInterfaceDecl *C = D->getSuperClass(); @@ -92,10 +93,7 @@ static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID, MapTy IMeths; unsigned NumMethods = 0; - for (ObjCImplementationDecl::instmeth_iterator I=ID->instmeth_begin(), - E=ID->instmeth_end(); I!=E; ++I) { - - ObjCMethodDecl *M = *I; + for (auto *M : ID->instance_methods()) { IMeths[M->getSelector()] = M; ++NumMethods; } @@ -103,22 +101,19 @@ static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID, // Now recurse the class hierarchy chain looking for methods with the // same signatures. while (C && NumMethods) { - for (ObjCInterfaceDecl::instmeth_iterator I=C->instmeth_begin(), - E=C->instmeth_end(); I!=E; ++I) { - - ObjCMethodDecl *M = *I; + for (const auto *M : C->instance_methods()) { Selector S = M->getSelector(); MapTy::iterator MI = IMeths.find(S); - if (MI == IMeths.end() || MI->second == 0) + if (MI == IMeths.end() || MI->second == nullptr) continue; --NumMethods; ObjCMethodDecl *MethDerived = MI->second; - MI->second = 0; + MI->second = nullptr; - CompareReturnTypes(MethDerived, M, BR, Ctx, ID); + CompareReturnTypes(MethDerived, M, BR, Ctx, ID, Checker); } C = C->getSuperClass(); @@ -135,7 +130,7 @@ class ObjCMethSigsChecker : public Checker< public: void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr, BugReporter &BR) const { - CheckObjCInstMethSignature(D, BR); + CheckObjCInstMethSignature(D, BR, this); } }; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index 415d3ec..45768b2 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -46,8 +46,18 @@ struct ChecksFilter { DefaultBool check_vfork; DefaultBool check_FloatLoopCounter; DefaultBool check_UncheckedReturn; + + CheckName checkName_gets; + CheckName checkName_getpw; + CheckName checkName_mktemp; + CheckName checkName_mkstemp; + CheckName checkName_strcpy; + CheckName checkName_rand; + CheckName checkName_vfork; + CheckName checkName_FloatLoopCounter; + CheckName checkName_UncheckedReturn; }; - + class WalkAST : public StmtVisitor<WalkAST> { BugReporter &BR; AnalysisDeclContext* AC; @@ -139,7 +149,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { .Case("rand_r", &WalkAST::checkCall_rand) .Case("random", &WalkAST::checkCall_random) .Case("vfork", &WalkAST::checkCall_vfork) - .Default(NULL); + .Default(nullptr); // If the callee isn't defined, it is not of security concern. // Check and evaluate the call. @@ -179,7 +189,7 @@ getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) { if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) { if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() || B->getOpcode() == BO_Comma)) - return NULL; + return nullptr; if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y)) return lhs; @@ -187,19 +197,19 @@ getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) { if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y)) return rhs; - return NULL; + return nullptr; } if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) { const NamedDecl *ND = DR->getDecl(); - return ND == x || ND == y ? DR : NULL; + return ND == x || ND == y ? DR : nullptr; } if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr)) return U->isIncrementDecrementOp() - ? getIncrementedVar(U->getSubExpr(), x, y) : NULL; + ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr; - return NULL; + return nullptr; } /// CheckLoopConditionForFloat - This check looks for 'for' statements that @@ -243,14 +253,14 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) { dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts()); // Does at least one of the variables have a floating point type? - drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : NULL; - drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : NULL; + drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : nullptr; + drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : nullptr; if (!drLHS && !drRHS) return; - const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : NULL; - const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : NULL; + const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : nullptr; + const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : nullptr; if (!vdLHS && !vdRHS) return; @@ -281,7 +291,7 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) { PathDiagnosticLocation FSLoc = PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC); - BR.EmitBasicReport(AC->getDecl(), + BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter, bugType, "Security", os.str(), FSLoc, ranges); } @@ -302,11 +312,11 @@ void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) { return; // Verify that the function takes a single argument. - if (FPT->getNumArgs() != 1) + if (FPT->getNumParams() != 1) return; // Is the argument a 'char*'? - const PointerType *PT = FPT->getArgType(0)->getAs<PointerType>(); + const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>(); if (!PT) return; @@ -316,7 +326,7 @@ void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) { // Issue a warning. PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport(AC->getDecl(), + BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets, "Potential buffer overflow in call to 'gets'", "Security", "Call to function 'gets' is extremely insecure as it can " @@ -338,15 +348,15 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) { return; // Verify that the function takes two arguments. - if (FPT->getNumArgs() != 2) + if (FPT->getNumParams() != 2) return; // Verify the first argument type is integer. - if (!FPT->getArgType(0)->isIntegralOrUnscopedEnumerationType()) + if (!FPT->getParamType(0)->isIntegralOrUnscopedEnumerationType()) return; // Verify the second argument type is char*. - const PointerType *PT = FPT->getArgType(1)->getAs<PointerType>(); + const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>(); if (!PT) return; @@ -356,7 +366,7 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) { // Issue a warning. PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport(AC->getDecl(), + BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw, "Potential buffer overflow in call to 'getpw'", "Security", "The getpw() function is dangerous as it may overflow the " @@ -382,11 +392,11 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { return; // Verify that the function takes a single argument. - if (FPT->getNumArgs() != 1) + if (FPT->getNumParams() != 1) return; // Verify that the argument is Pointer Type. - const PointerType *PT = FPT->getArgType(0)->getAs<PointerType>(); + const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>(); if (!PT) return; @@ -394,10 +404,10 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy) return; - // Issue a waring. + // Issue a warning. PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport(AC->getDecl(), + BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp, "Potential insecure temporary file in call 'mktemp'", "Security", "Call to function 'mktemp' is insecure as it always " @@ -483,7 +493,7 @@ void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) { out << " used as a suffix"; } out << ')'; - BR.EmitBasicReport(AC->getDecl(), + BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp, "Insecure temporary file creation", "Security", out.str(), CELoc, strArg->getSourceRange()); } @@ -504,7 +514,7 @@ void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) { // Issue a warning. PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport(AC->getDecl(), + BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy, "Potential insecure memory buffer bounds restriction in " "call 'strcpy'", "Security", @@ -531,7 +541,7 @@ void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) { // Issue a warning. PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport(AC->getDecl(), + BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy, "Potential insecure memory buffer bounds restriction in " "call 'strcat'", "Security", @@ -551,14 +561,14 @@ bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) { return false; // Verify the function takes two arguments, three in the _chk version. - int numArgs = FPT->getNumArgs(); + int numArgs = FPT->getNumParams(); if (numArgs != 2 && numArgs != 3) return false; // Verify the type for both arguments. for (int i = 0; i < 2; i++) { // Verify that the arguments are pointers. - const PointerType *PT = FPT->getArgType(i)->getAs<PointerType>(); + const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>(); if (!PT) return false; @@ -584,17 +594,16 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) { if (!FTP) return; - if (FTP->getNumArgs() == 1) { + if (FTP->getNumParams() == 1) { // Is the argument an 'unsigned short *'? // (Actually any integer type is allowed.) - const PointerType *PT = FTP->getArgType(0)->getAs<PointerType>(); + const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>(); if (!PT) return; if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType()) return; - } - else if (FTP->getNumArgs() != 0) + } else if (FTP->getNumParams() != 0) return; // Issue a warning. @@ -610,8 +619,9 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) { PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport(AC->getDecl(), os1.str(), "Security", os2.str(), - CELoc, CE->getCallee()->getSourceRange()); + BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(), + "Security", os2.str(), CELoc, + CE->getCallee()->getSourceRange()); } //===----------------------------------------------------------------------===// @@ -628,13 +638,13 @@ void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) { return; // Verify that the function takes no argument. - if (FTP->getNumArgs() != 0) + if (FTP->getNumParams() != 0) return; // Issue a warning. PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport(AC->getDecl(), + BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, "'random' is not a secure random number generator", "Security", "The 'random' function produces a sequence of values that " @@ -654,7 +664,7 @@ void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) { // All calls to vfork() are insecure, issue a warning. PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport(AC->getDecl(), + BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork, "Potential insecure implementation-specific behavior in " "call 'vfork'", "Security", @@ -678,7 +688,7 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) { if (!FD) return; - if (II_setid[0] == NULL) { + if (II_setid[0] == nullptr) { static const char * const identifiers[num_setids] = { "setuid", "setgid", "seteuid", "setegid", "setreuid", "setregid" @@ -704,12 +714,12 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) { // Verify that the function takes one or two arguments (depending on // the function). - if (FTP->getNumArgs() != (identifierid < 4 ? 1 : 2)) + if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2)) return; // The arguments must be integers. - for (unsigned i = 0; i < FTP->getNumArgs(); i++) - if (! FTP->getArgType(i)->isIntegralOrUnscopedEnumerationType()) + for (unsigned i = 0; i < FTP->getNumParams(); i++) + if (!FTP->getParamType(i)->isIntegralOrUnscopedEnumerationType()) return; // Issue a warning. @@ -725,8 +735,9 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) { PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport(AC->getDecl(), os1.str(), "Security", os2.str(), - CELoc, CE->getCallee()->getSourceRange()); + BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(), + "Security", os2.str(), CELoc, + CE->getCallee()->getSourceRange()); } //===----------------------------------------------------------------------===// @@ -746,10 +757,13 @@ public: }; } -#define REGISTER_CHECKER(name) \ -void ento::register##name(CheckerManager &mgr) {\ - mgr.registerChecker<SecuritySyntaxChecker>()->filter.check_##name = true;\ -} +#define REGISTER_CHECKER(name) \ + void ento::register##name(CheckerManager &mgr) { \ + SecuritySyntaxChecker *checker = \ + mgr.registerChecker<SecuritySyntaxChecker>(); \ + checker->filter.check_##name = true; \ + checker->filter.checkName_##name = mgr.getCurrentCheckName(); \ + } REGISTER_CHECKER(gets) REGISTER_CHECKER(getpw) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp index 1207b67..a61e658 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp @@ -24,10 +24,12 @@ using namespace ento; namespace { class WalkAST : public StmtVisitor<WalkAST> { BugReporter &BR; + const CheckerBase *Checker; AnalysisDeclContext* AC; public: - WalkAST(BugReporter &br, AnalysisDeclContext* ac) : BR(br), AC(ac) {} + WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac) + : BR(br), Checker(checker), AC(ac) {} void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); void VisitStmt(Stmt *S) { VisitChildren(S); } void VisitChildren(Stmt *S); @@ -45,7 +47,7 @@ void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { if (E->getKind() != UETT_SizeOf) return; - // If an explicit type is used in the code, usually the coder knows what he is + // If an explicit type is used in the code, usually the coder knows what they are // doing. if (E->isArgumentType()) return; @@ -62,7 +64,7 @@ void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { PathDiagnosticLocation ELoc = PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC); - BR.EmitBasicReport(AC->getDecl(), + BR.EmitBasicReport(AC->getDecl(), Checker, "Potential unintended use of sizeof() on pointer type", categories::LogicError, "The code calls sizeof() on a pointer type. " @@ -80,7 +82,7 @@ class SizeofPointerChecker : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { - WalkAST walker(BR, mgr.getAnalysisDeclContext(D)); + WalkAST walker(BR, this, mgr.getAnalysisDeclContext(D)); walker.Visit(D->getBody()); } }; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td index 862212d..44eb641 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td @@ -120,6 +120,14 @@ def SizeofPointerChecker : Checker<"SizeofPtr">, HelpText<"Warn about unintended use of sizeof() on pointer expressions">, DescFile<"CheckSizeofPointer.cpp">; +def CallAndMessageUnInitRefArg : Checker<"CallAndMessageUnInitRefArg">, + HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers, and pointer to undefined variables)">, + DescFile<"CallAndMessageChecker.cpp">; + +def TestAfterDivZeroChecker : Checker<"TestAfterDivZero">, + HelpText<"Check for division by variable that is later compared against 0. Either the comparison is useless or there is division by zero.">, + DescFile<"TestAfterDivZeroChecker.cpp">; + } // end "alpha.core" //===----------------------------------------------------------------------===// @@ -203,10 +211,6 @@ def DeadStoresChecker : Checker<"DeadStores">, let ParentPackage = DeadCodeAlpha in { -def IdempotentOperationChecker : Checker<"IdempotentOperations">, - HelpText<"Warn about idempotent operations">, - DescFile<"IdempotentOperationChecker.cpp">; - def UnreachableCodeChecker : Checker<"UnreachableCode">, HelpText<"Check unreachable code">, DescFile<"UnreachableCodeChecker.cpp">; @@ -416,6 +420,10 @@ def ObjCNonNilReturnValueChecker : Checker<"NonNilReturnValue">, HelpText<"Model the APIs that are guaranteed to return a non-nil value">, DescFile<"BasicObjCFoundationChecks.cpp">; +def ObjCSuperCallChecker : Checker<"MissingSuperCall">, + HelpText<"Warn about Objective-C methods that lack a necessary call to super">, + DescFile<"ObjCMissingSuperCallChecker.cpp">; + def NSErrorChecker : Checker<"NSError">, HelpText<"Check usage of NSError** parameters">, DescFile<"NSErrorChecker.cpp">; @@ -448,10 +456,6 @@ def DirectIvarAssignmentForAnnotatedFunctions : Checker<"DirectIvarAssignmentFor HelpText<"Check for direct assignments to instance variables in the methods annotated with objc_no_direct_instance_variable_assignment">, DescFile<"DirectIvarAssignment.cpp">; -def ObjCSuperCallChecker : Checker<"MissingSuperCall">, - HelpText<"Warn about Objective-C methods that lack a necessary call to super">, - DescFile<"ObjCMissingSuperCallChecker.cpp">; - } // end "alpha.osx.cocoa" let ParentPackage = CoreFoundation in { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp index 9912965..ad41577 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp @@ -41,11 +41,11 @@ bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; } class ChrootChecker : public Checker<eval::Call, check::PreStmt<CallExpr> > { mutable IdentifierInfo *II_chroot, *II_chdir; // This bug refers to possibly break out of a chroot() jail. - mutable OwningPtr<BuiltinBug> BT_BreakJail; + mutable std::unique_ptr<BuiltinBug> BT_BreakJail; public: - ChrootChecker() : II_chroot(0), II_chdir(0) {} - + ChrootChecker() : II_chroot(nullptr), II_chdir(nullptr) {} + static void *getTag() { static int x; return &x; @@ -142,9 +142,9 @@ void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { if (isRootChanged((intptr_t) *k)) if (ExplodedNode *N = C.addTransition()) { if (!BT_BreakJail) - BT_BreakJail.reset(new BuiltinBug("Break out of jail", - "No call of chdir(\"/\") immediately " - "after chroot")); + BT_BreakJail.reset(new BuiltinBug( + this, "Break out of jail", "No call of chdir(\"/\") immediately " + "after chroot")); BugReport *R = new BugReport(*BT_BreakJail, BT_BreakJail->getDescription(), N); C.emitReport(R); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 9d855ce..c1ea767 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -124,21 +124,23 @@ class DeadStoreObs : public LiveVariables::Observer { const CFG &cfg; ASTContext &Ctx; BugReporter& BR; + const CheckerBase *Checker; AnalysisDeclContext* AC; ParentMap& Parents; llvm::SmallPtrSet<const VarDecl*, 20> Escaped; - OwningPtr<ReachableCode> reachableCode; + std::unique_ptr<ReachableCode> reachableCode; const CFGBlock *currentBlock; - OwningPtr<llvm::DenseSet<const VarDecl *> > InEH; + std::unique_ptr<llvm::DenseSet<const VarDecl *>> InEH; enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit }; public: - DeadStoreObs(const CFG &cfg, ASTContext &ctx, - BugReporter& br, AnalysisDeclContext* ac, ParentMap& parents, - llvm::SmallPtrSet<const VarDecl*, 20> &escaped) - : cfg(cfg), Ctx(ctx), BR(br), AC(ac), Parents(parents), - Escaped(escaped), currentBlock(0) {} + DeadStoreObs(const CFG &cfg, ASTContext &ctx, BugReporter &br, + const CheckerBase *checker, AnalysisDeclContext *ac, + ParentMap &parents, + llvm::SmallPtrSet<const VarDecl *, 20> &escaped) + : cfg(cfg), Ctx(ctx), BR(br), Checker(checker), AC(ac), Parents(parents), + Escaped(escaped), currentBlock(nullptr) {} virtual ~DeadStoreObs() {} @@ -176,7 +178,7 @@ public: SmallString<64> buf; llvm::raw_svector_ostream os(buf); - const char *BugType = 0; + const char *BugType = nullptr; switch (dsk) { case DeadInit: @@ -199,7 +201,8 @@ public: return; } - BR.EmitBasicReport(AC->getDecl(), BugType, "Dead store", os.str(), L, R); + BR.EmitBasicReport(AC->getDecl(), Checker, BugType, "Dead store", os.str(), + L, R); } void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val, @@ -214,7 +217,8 @@ public: return; if (!isLive(Live, VD) && - !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) { + !(VD->hasAttr<UnusedAttr>() || VD->hasAttr<BlocksAttr>() || + VD->hasAttr<ObjCPreciseLifetimeAttr>())) { PathDiagnosticLocation ExLoc = PathDiagnosticLocation::createBegin(Ex, BR.getSourceManager(), AC); @@ -251,8 +255,8 @@ public: return false; } - virtual void observeStmt(const Stmt *S, const CFGBlock *block, - const LiveVariables::LivenessValues &Live) { + void observeStmt(const Stmt *S, const CFGBlock *block, + const LiveVariables::LivenessValues &Live) override { currentBlock = block; @@ -309,10 +313,8 @@ public: else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) // Iterate through the decls. Warn if any initializers are complex // expressions that are not live (never used). - for (DeclStmt::const_decl_iterator DI=DS->decl_begin(), DE=DS->decl_end(); - DI != DE; ++DI) { - - VarDecl *V = dyn_cast<VarDecl>(*DI); + for (const auto *DI : DS->decls()) { + const auto *V = dyn_cast<VarDecl>(DI); if (!V) continue; @@ -339,8 +341,10 @@ public: // A dead initialization is a variable that is dead after it // is initialized. We don't flag warnings for those variables - // marked 'unused'. - if (!isLive(Live, V) && V->getAttr<UnusedAttr>() == 0) { + // marked 'unused' or 'objc_precise_lifetime'. + if (!isLive(Live, V) && + !V->hasAttr<UnusedAttr>() && + !V->hasAttr<ObjCPreciseLifetimeAttr>()) { // Special case: check for initializations with constants. // // e.g. : int x = 0; @@ -436,7 +440,7 @@ public: ParentMap &pmap = mgr.getParentMap(D); FindEscaped FS; cfg.VisitBlockStmts(FS); - DeadStoreObs A(cfg, BR.getContext(), BR, AC, pmap, FS.Escaped); + DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped); L->runOnAllBlocks(A); } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp index a2c8d1f..51e7a3d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp @@ -95,6 +95,11 @@ class CFGDumper : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { + PrintingPolicy Policy(mgr.getLangOpts()); + Policy.TerseOutput = true; + Policy.PolishForDeclaration = true; + D->print(llvm::errs(), Policy); + if (CFG *cfg = mgr.getCFG(D)) { cfg->dump(mgr.getLangOpts(), llvm::sys::Process::StandardErrHasColors()); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index 72d46c5..4ee0223 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -29,8 +29,8 @@ class DereferenceChecker : public Checker< check::Location, check::Bind, EventDispatcher<ImplicitNullDerefEvent> > { - mutable OwningPtr<BuiltinBug> BT_null; - mutable OwningPtr<BuiltinBug> BT_undef; + mutable std::unique_ptr<BuiltinBug> BT_null; + mutable std::unique_ptr<BuiltinBug> BT_undef; void reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C, bool IsBind = false) const; @@ -97,7 +97,7 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, // We know that 'location' cannot be non-null. This is what // we call an "explicit" null dereference. if (!BT_null) - BT_null.reset(new BuiltinBug("Dereference of null pointer")); + BT_null.reset(new BuiltinBug(this, "Dereference of null pointer")); SmallString<100> buf; llvm::raw_svector_ostream os(buf); @@ -126,7 +126,7 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, os << "Array access"; const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S); AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), - State.getPtr(), N->getLocationContext()); + State.get(), N->getLocationContext()); os << " results in a null pointer dereference"; break; } @@ -134,7 +134,7 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, os << "Dereference of null pointer"; const UnaryOperator *U = cast<UnaryOperator>(S); AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), - State.getPtr(), N->getLocationContext(), true); + State.get(), N->getLocationContext(), true); break; } case Stmt::MemberExprClass: { @@ -143,7 +143,7 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, os << "Access to field '" << M->getMemberNameInfo() << "' results in a dereference of a null pointer"; AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), - State.getPtr(), N->getLocationContext(), true); + State.get(), N->getLocationContext(), true); } break; } @@ -152,7 +152,7 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, os << "Access to instance variable '" << *IV->getDecl() << "' results in a dereference of a null pointer"; AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(), - State.getPtr(), N->getLocationContext(), true); + State.get(), N->getLocationContext(), true); break; } default: @@ -180,7 +180,8 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, if (l.isUndef()) { if (ExplodedNode *N = C.generateSink()) { if (!BT_undef) - BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value")); + BT_undef.reset( + new BuiltinBug(this, "Dereference of undefined pointer value")); BugReport *report = new BugReport(*BT_undef, BT_undef->getDescription(), N); @@ -200,7 +201,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, ProgramStateRef state = C.getState(); ProgramStateRef notNullState, nullState; - llvm::tie(notNullState, nullState) = state->assume(location); + std::tie(notNullState, nullState) = state->assume(location); // The explicit NULL case. if (nullState) { @@ -239,8 +240,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, ProgramStateRef State = C.getState(); ProgramStateRef StNonNull, StNull; - llvm::tie(StNonNull, StNull) = - State->assume(V.castAs<DefinedOrUnknownSVal>()); + std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>()); if (StNull) { if (!StNonNull) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp index b43dc18..0bcebf6 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp @@ -63,13 +63,15 @@ class DirectIvarAssignment : const ObjCMethodDecl *MD; const ObjCInterfaceDecl *InterfD; BugReporter &BR; + const CheckerBase *Checker; LocationOrAnalysisDeclContext DCtx; public: MethodCrawler(const IvarToPropertyMapTy &InMap, const ObjCMethodDecl *InMD, - const ObjCInterfaceDecl *InID, - BugReporter &InBR, AnalysisDeclContext *InDCtx) - : IvarToPropMap(InMap), MD(InMD), InterfD(InID), BR(InBR), DCtx(InDCtx) {} + const ObjCInterfaceDecl *InID, BugReporter &InBR, + const CheckerBase *Checker, AnalysisDeclContext *InDCtx) + : IvarToPropMap(InMap), MD(InMD), InterfD(InID), BR(InBR), + Checker(Checker), DCtx(InDCtx) {} void VisitStmt(const Stmt *S) { VisitChildren(S); } @@ -122,10 +124,7 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D, IvarToPropertyMapTy IvarToPropMap; // Find all properties for this class. - for (ObjCInterfaceDecl::prop_iterator I = InterD->prop_begin(), - E = InterD->prop_end(); I != E; ++I) { - ObjCPropertyDecl *PD = *I; - + for (const auto *PD : InterD->properties()) { // Find the corresponding IVar. const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterD, Mgr.getASTContext()); @@ -140,10 +139,7 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D, if (IvarToPropMap.empty()) return; - for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(), - E = D->instmeth_end(); I != E; ++I) { - - ObjCMethodDecl *M = *I; + for (const auto *M : D->instance_methods()) { AnalysisDeclContext *DCtx = Mgr.getAnalysisDeclContext(M); if ((*ShouldSkipMethod)(M)) @@ -152,20 +148,17 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D, const Stmt *Body = M->getBody(); assert(Body); - MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, DCtx); + MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, this, + DCtx); MC.VisitStmt(Body); } } static bool isAnnotatedToAllowDirectAssignment(const Decl *D) { - for (specific_attr_iterator<AnnotateAttr> - AI = D->specific_attr_begin<AnnotateAttr>(), - AE = D->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) { - const AnnotateAttr *Ann = *AI; + for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) if (Ann->getAnnotation() == "objc_allow_direct_instance_variable_assignment") return true; - } return false; } @@ -204,13 +197,11 @@ void DirectIvarAssignment::MethodCrawler::VisitBinaryOperator( if (GetterMethod && GetterMethod->getCanonicalDecl() == MD) return; - BR.EmitBasicReport(MD, - "Property access", - categories::CoreFoundationObjectiveC, + BR.EmitBasicReport( + MD, Checker, "Property access", categories::CoreFoundationObjectiveC, "Direct assignment to an instance variable backing a property; " - "use the setter instead", PathDiagnosticLocation(IvarRef, - BR.getSourceManager(), - DCtx)); + "use the setter instead", + PathDiagnosticLocation(IvarRef, BR.getSourceManager(), DCtx)); } } } @@ -225,14 +216,9 @@ void ento::registerDirectIvarAssignment(CheckerManager &mgr) { // Register the checker that checks for direct accesses in functions annotated // with __attribute__((annotate("objc_no_direct_instance_variable_assignment"))). static bool AttrFilter(const ObjCMethodDecl *M) { - for (specific_attr_iterator<AnnotateAttr> - AI = M->specific_attr_begin<AnnotateAttr>(), - AE = M->specific_attr_end<AnnotateAttr>(); - AI != AE; ++AI) { - const AnnotateAttr *Ann = *AI; + for (const auto *Ann : M->specific_attrs<AnnotateAttr>()) if (Ann->getAnnotation() == "objc_no_direct_instance_variable_assignment") return false; - } return true; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index 93daf94..e060c36 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -23,7 +23,7 @@ using namespace ento; namespace { class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > { - mutable OwningPtr<BuiltinBug> BT; + mutable std::unique_ptr<BuiltinBug> BT; void reportBug(const char *Msg, ProgramStateRef StateZero, CheckerContext &C) const ; @@ -37,7 +37,7 @@ void DivZeroChecker::reportBug(const char *Msg, CheckerContext &C) const { if (ExplodedNode *N = C.generateSink(StateZero)) { if (!BT) - BT.reset(new BuiltinBug("Division by zero")); + BT.reset(new BuiltinBug(this, "Division by zero")); BugReport *R = new BugReport(*BT, Msg, N); bugreporter::trackNullOrUndefValue(N, bugreporter::GetDenomExpr(N), *R); @@ -68,7 +68,7 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B, // Check for divide by zero. ConstraintManager &CM = C.getConstraintManager(); ProgramStateRef stateNotZero, stateZero; - llvm::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV); + std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV); if (!stateNotZero) { assert(stateZero); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 7116e4d..43a2812 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -223,7 +223,7 @@ DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, const Expr *RecE = MsgE->getInstanceReceiver(); if (!RecE) - return 0; + return nullptr; RecE= RecE->IgnoreParenImpCasts(); if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) { @@ -237,7 +237,7 @@ DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, return ObjTy; } } - return 0; + return nullptr; } // Return a better dynamic type if one can be derived from the cast. @@ -253,7 +253,7 @@ DynamicTypePropagation::getBetterObjCType(const Expr *CastE, const ObjCObjectPointerType *NewTy = CastE->getType()->getAs<ObjCObjectPointerType>(); if (!NewTy) - return 0; + return nullptr; QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType(); if (OldDTy.isNull()) { return NewTy; @@ -261,7 +261,7 @@ DynamicTypePropagation::getBetterObjCType(const Expr *CastE, const ObjCObjectPointerType *OldTy = OldDTy->getAs<ObjCObjectPointerType>(); if (!OldTy) - return 0; + return nullptr; // Id the old type is 'id', the new one is more precise. if (OldTy->isObjCIdType() && !NewTy->isObjCIdType()) @@ -273,7 +273,7 @@ DynamicTypePropagation::getBetterObjCType(const Expr *CastE, if (ToI && FromI && FromI->isSuperClassOf(ToI)) return NewTy; - return 0; + return nullptr; } void ento::registerDynamicTypePropagation(CheckerManager &mgr) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index 3ed2435..f36ec2c 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -18,7 +18,7 @@ using namespace ento; namespace { class ExprInspectionChecker : public Checker< eval::Call > { - mutable OwningPtr<BugType> BT; + mutable std::unique_ptr<BugType> BT; void analyzerEval(const CallExpr *CE, CheckerContext &C) const; void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const; @@ -43,7 +43,7 @@ bool ExprInspectionChecker::evalCall(const CallExpr *CE, &ExprInspectionChecker::analyzerCheckInlined) .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash) .Case("clang_analyzer_warnIfReached", &ExprInspectionChecker::analyzerWarnIfReached) - .Default(0); + .Default(nullptr); if (!Handler) return false; @@ -68,7 +68,7 @@ static const char *getArgumentValueString(const CallExpr *CE, return "UNDEFINED"; ProgramStateRef StTrue, StFalse; - llvm::tie(StTrue, StFalse) = + std::tie(StTrue, StFalse) = State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>()); if (StTrue) { @@ -91,11 +91,11 @@ void ExprInspectionChecker::analyzerEval(const CallExpr *CE, // A specific instantiation of an inlined function may have more constrained // values than can generally be assumed. Skip the check. - if (LC->getCurrentStackFrame()->getParent() != 0) + if (LC->getCurrentStackFrame()->getParent() != nullptr) return; if (!BT) - BT.reset(new BugType("Checking analyzer assumptions", "debug")); + BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N); C.emitReport(R); @@ -106,7 +106,7 @@ void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE, ExplodedNode *N = C.getPredecessor(); if (!BT) - BT.reset(new BugType("Checking analyzer assumptions", "debug")); + BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); BugReport *R = new BugReport(*BT, "REACHABLE", N); C.emitReport(R); @@ -122,11 +122,11 @@ void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, // when we are analyzing it as an inlined function. This means that // clang_analyzer_checkInlined(true) should always print TRUE, but // clang_analyzer_checkInlined(false) should never actually print anything. - if (LC->getCurrentStackFrame()->getParent() == 0) + if (LC->getCurrentStackFrame()->getParent() == nullptr) return; if (!BT) - BT.reset(new BugType("Checking analyzer assumptions", "debug")); + BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N); C.emitReport(R); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp index 085a991..60bb036 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp @@ -25,7 +25,7 @@ using namespace ento; namespace { class FixedAddressChecker : public Checker< check::PreStmt<BinaryOperator> > { - mutable OwningPtr<BuiltinBug> BT; + mutable std::unique_ptr<BuiltinBug> BT; public: void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; @@ -52,10 +52,11 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B, if (ExplodedNode *N = C.addTransition()) { if (!BT) - BT.reset(new BuiltinBug("Use fixed address", - "Using a fixed address is not portable because that " - "address will probably not be valid in all " - "environments or platforms.")); + BT.reset( + new BuiltinBug(this, "Use fixed address", + "Using a fixed address is not portable because that " + "address will probably not be valid in all " + "environments or platforms.")); BugReport *R = new BugReport(*BT, BT->getDescription(), N); R->addRange(B->getRHS()->getSourceRange()); C.emitReport(R); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp index 1dc60c6..08ba26a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -34,7 +34,6 @@ public: static void *getTag() { static int Tag; return &Tag; } void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; - void checkPostStmt(const DeclRefExpr *DRE, CheckerContext &C) const; void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; @@ -43,10 +42,10 @@ private: /// Denotes the return vale. static const unsigned ReturnValueIndex = UINT_MAX - 1; - mutable OwningPtr<BugType> BT; + mutable std::unique_ptr<BugType> BT; inline void initBugType() const { if (!BT) - BT.reset(new BugType("Use of Untrusted Data", "Untrusted Data")); + BT.reset(new BugType(this, "Use of Untrusted Data", "Untrusted Data")); } /// \brief Catch taint related bugs. Check if tainted data is passed to a @@ -292,7 +291,7 @@ void GenericTaintChecker::checkPostStmt(const CallExpr *CE, void GenericTaintChecker::addSourcesPre(const CallExpr *CE, CheckerContext &C) const { - ProgramStateRef State = 0; + ProgramStateRef State = nullptr; const FunctionDecl *FDecl = C.getCalleeDecl(CE); if (!FDecl || FDecl->getKind() != Decl::Function) return; @@ -315,7 +314,7 @@ void GenericTaintChecker::addSourcesPre(const CallExpr *CE, // Otherwise, check if we have custom pre-processing implemented. FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name) .Case("fscanf", &GenericTaintChecker::preFscanf) - .Default(0); + .Default(nullptr); // Check and evaluate the call. if (evalFunction) State = (this->*evalFunction)(CE, C); @@ -389,11 +388,11 @@ void GenericTaintChecker::addSourcesPost(const CallExpr *CE, .Case("getch", &GenericTaintChecker::postRetTaint) .Case("wgetch", &GenericTaintChecker::postRetTaint) .Case("socket", &GenericTaintChecker::postSocket) - .Default(0); + .Default(nullptr); // If the callee isn't defined, it is not of security concern. // Check and evaluate the call. - ProgramStateRef State = 0; + ProgramStateRef State = nullptr; if (evalFunction) State = (this->*evalFunction)(CE, C); if (!State) @@ -429,11 +428,11 @@ SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C, ProgramStateRef State = C.getState(); SVal AddrVal = State->getSVal(Arg->IgnoreParens(), C.getLocationContext()); if (AddrVal.isUnknownOrUndef()) - return 0; + return nullptr; Optional<Loc> AddrLoc = AddrVal.getAs<Loc>(); if (!AddrLoc) - return 0; + return nullptr; const PointerType *ArgTy = dyn_cast<PointerType>(Arg->getType().getCanonicalType().getTypePtr()); @@ -527,7 +526,7 @@ ProgramStateRef GenericTaintChecker::preFscanf(const CallExpr *CE, return State; } - return 0; + return nullptr; } @@ -613,11 +612,7 @@ static bool getPrintfFormatArgumentNum(const CallExpr *CE, const FunctionDecl *FDecl = C.getCalleeDecl(CE); if (!FDecl) return false; - for (specific_attr_iterator<FormatAttr> - i = FDecl->specific_attr_begin<FormatAttr>(), - e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) { - - const FormatAttr *Format = *i; + for (const auto *Format : FDecl->specific_attrs<FormatAttr>()) { ArgNum = Format->getFormatIdx() - 1; if ((Format->getType()->getName() == "printf") && CE->getNumArgs() > ArgNum) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp deleted file mode 100644 index 4997f8d..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp +++ /dev/null @@ -1,737 +0,0 @@ -//==- IdempotentOperationChecker.cpp - Idempotent Operations ----*- C++ -*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines a set of path-sensitive checks for idempotent and/or -// tautological operations. Each potential operation is checked along all paths -// to see if every path results in a pointless operation. -// +-------------------------------------------+ -// |Table of idempotent/tautological operations| -// +-------------------------------------------+ -//+--------------------------------------------------------------------------+ -//|Operator | x op x | x op 1 | 1 op x | x op 0 | 0 op x | x op ~0 | ~0 op x | -//+--------------------------------------------------------------------------+ -// +, += | | | | x | x | | -// -, -= | | | | x | -x | | -// *, *= | | x | x | 0 | 0 | | -// /, /= | 1 | x | | N/A | 0 | | -// &, &= | x | | | 0 | 0 | x | x -// |, |= | x | | | x | x | ~0 | ~0 -// ^, ^= | 0 | | | x | x | | -// <<, <<= | | | | x | 0 | | -// >>, >>= | | | | x | 0 | | -// || | x | 1 | 1 | x | x | 1 | 1 -// && | x | x | x | 0 | 0 | x | x -// = | x | | | | | | -// == | 1 | | | | | | -// >= | 1 | | | | | | -// <= | 1 | | | | | | -// > | 0 | | | | | | -// < | 0 | | | | | | -// != | 0 | | | | | | -//===----------------------------------------------------------------------===// -// -// Things TODO: -// - Improved error messages -// - Handle mixed assumptions (which assumptions can belong together?) -// - Finer grained false positive control (levels) -// - Handling ~0 values - -#include "ClangSACheckers.h" -#include "clang/AST/Stmt.h" -#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" -#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h" -#include "clang/Analysis/CFGStmtMap.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/Checker.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" - -using namespace clang; -using namespace ento; - -namespace { -class IdempotentOperationChecker - : public Checker<check::PreStmt<BinaryOperator>, - check::PostStmt<BinaryOperator>, - check::EndAnalysis> { -public: - void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; - void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const; - void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const; - -private: - // Our assumption about a particular operation. - enum Assumption { Possible = 0, Impossible, Equal, LHSis1, RHSis1, LHSis0, - RHSis0 }; - - static void UpdateAssumption(Assumption &A, const Assumption &New); - - // False positive reduction methods - static bool isSelfAssign(const Expr *LHS, const Expr *RHS); - static bool isUnused(const Expr *E, AnalysisDeclContext *AC); - static bool isTruncationExtensionAssignment(const Expr *LHS, - const Expr *RHS); - static bool pathWasCompletelyAnalyzed(AnalysisDeclContext *AC, - const CFGBlock *CB, - const CoreEngine &CE); - static bool CanVary(const Expr *Ex, - AnalysisDeclContext *AC); - static bool isConstantOrPseudoConstant(const DeclRefExpr *DR, - AnalysisDeclContext *AC); - static bool containsNonLocalVarDecl(const Stmt *S); - - // Hash table and related data structures - struct BinaryOperatorData { - BinaryOperatorData() : assumption(Possible) {} - - Assumption assumption; - ExplodedNodeSet explodedNodes; // Set of ExplodedNodes that refer to a - // BinaryOperator - }; - typedef llvm::DenseMap<const BinaryOperator *, BinaryOperatorData> - AssumptionMap; - mutable AssumptionMap hash; - mutable OwningPtr<BugType> BT; -}; -} - -void IdempotentOperationChecker::checkPreStmt(const BinaryOperator *B, - CheckerContext &C) const { - // Find or create an entry in the hash for this BinaryOperator instance. - // If we haven't done a lookup before, it will get default initialized to - // 'Possible'. At this stage we do not store the ExplodedNode, as it has not - // been created yet. - BinaryOperatorData &Data = hash[B]; - Assumption &A = Data.assumption; - AnalysisDeclContext *AC = C.getCurrentAnalysisDeclContext(); - - // If we already have visited this node on a path that does not contain an - // idempotent operation, return immediately. - if (A == Impossible) - return; - - // Retrieve both sides of the operator and determine if they can vary (which - // may mean this is a false positive. - const Expr *LHS = B->getLHS(); - const Expr *RHS = B->getRHS(); - - // At this stage we can calculate whether each side contains a false positive - // that applies to all operators. We only need to calculate this the first - // time. - bool LHSContainsFalsePositive = false, RHSContainsFalsePositive = false; - if (A == Possible) { - // An expression contains a false positive if it can't vary, or if it - // contains a known false positive VarDecl. - LHSContainsFalsePositive = !CanVary(LHS, AC) - || containsNonLocalVarDecl(LHS); - RHSContainsFalsePositive = !CanVary(RHS, AC) - || containsNonLocalVarDecl(RHS); - } - - ProgramStateRef state = C.getState(); - const LocationContext *LCtx = C.getLocationContext(); - SVal LHSVal = state->getSVal(LHS, LCtx); - SVal RHSVal = state->getSVal(RHS, LCtx); - - // If either value is unknown, we can't be 100% sure of all paths. - if (LHSVal.isUnknownOrUndef() || RHSVal.isUnknownOrUndef()) { - A = Impossible; - return; - } - BinaryOperator::Opcode Op = B->getOpcode(); - - // Dereference the LHS SVal if this is an assign operation - switch (Op) { - default: - break; - - // Fall through intentional - case BO_AddAssign: - case BO_SubAssign: - case BO_MulAssign: - case BO_DivAssign: - case BO_AndAssign: - case BO_OrAssign: - case BO_XorAssign: - case BO_ShlAssign: - case BO_ShrAssign: - case BO_Assign: - // Assign statements have one extra level of indirection - if (!LHSVal.getAs<Loc>()) { - A = Impossible; - return; - } - LHSVal = state->getSVal(LHSVal.castAs<Loc>(), LHS->getType()); - } - - - // We now check for various cases which result in an idempotent operation. - - // x op x - switch (Op) { - default: - break; // We don't care about any other operators. - - // Fall through intentional - case BO_Assign: - // x Assign x can be used to silence unused variable warnings intentionally. - // If this is a self assignment and the variable is referenced elsewhere, - // and the assignment is not a truncation or extension, then it is a false - // positive. - if (isSelfAssign(LHS, RHS)) { - if (!isUnused(LHS, AC) && !isTruncationExtensionAssignment(LHS, RHS)) { - UpdateAssumption(A, Equal); - return; - } - else { - A = Impossible; - return; - } - } - - case BO_SubAssign: - case BO_DivAssign: - case BO_AndAssign: - case BO_OrAssign: - case BO_XorAssign: - case BO_Sub: - case BO_Div: - case BO_And: - case BO_Or: - case BO_Xor: - case BO_LOr: - case BO_LAnd: - case BO_EQ: - case BO_NE: - if (LHSVal != RHSVal || LHSContainsFalsePositive - || RHSContainsFalsePositive) - break; - UpdateAssumption(A, Equal); - return; - } - - // x op 1 - switch (Op) { - default: - break; // We don't care about any other operators. - - // Fall through intentional - case BO_MulAssign: - case BO_DivAssign: - case BO_Mul: - case BO_Div: - case BO_LOr: - case BO_LAnd: - if (!RHSVal.isConstant(1) || RHSContainsFalsePositive) - break; - UpdateAssumption(A, RHSis1); - return; - } - - // 1 op x - switch (Op) { - default: - break; // We don't care about any other operators. - - // Fall through intentional - case BO_MulAssign: - case BO_Mul: - case BO_LOr: - case BO_LAnd: - if (!LHSVal.isConstant(1) || LHSContainsFalsePositive) - break; - UpdateAssumption(A, LHSis1); - return; - } - - // x op 0 - switch (Op) { - default: - break; // We don't care about any other operators. - - // Fall through intentional - case BO_AddAssign: - case BO_SubAssign: - case BO_MulAssign: - case BO_AndAssign: - case BO_OrAssign: - case BO_XorAssign: - case BO_Add: - case BO_Sub: - case BO_Mul: - case BO_And: - case BO_Or: - case BO_Xor: - case BO_Shl: - case BO_Shr: - case BO_LOr: - case BO_LAnd: - if (!RHSVal.isConstant(0) || RHSContainsFalsePositive) - break; - UpdateAssumption(A, RHSis0); - return; - } - - // 0 op x - switch (Op) { - default: - break; // We don't care about any other operators. - - // Fall through intentional - //case BO_AddAssign: // Common false positive - case BO_SubAssign: // Check only if unsigned - case BO_MulAssign: - case BO_DivAssign: - case BO_AndAssign: - //case BO_OrAssign: // Common false positive - //case BO_XorAssign: // Common false positive - case BO_ShlAssign: - case BO_ShrAssign: - case BO_Add: - case BO_Sub: - case BO_Mul: - case BO_Div: - case BO_And: - case BO_Or: - case BO_Xor: - case BO_Shl: - case BO_Shr: - case BO_LOr: - case BO_LAnd: - if (!LHSVal.isConstant(0) || LHSContainsFalsePositive) - break; - UpdateAssumption(A, LHSis0); - return; - } - - // If we get to this point, there has been a valid use of this operation. - A = Impossible; -} - -// At the post visit stage, the predecessor ExplodedNode will be the -// BinaryOperator that was just created. We use this hook to collect the -// ExplodedNode. -void IdempotentOperationChecker::checkPostStmt(const BinaryOperator *B, - CheckerContext &C) const { - // Add the ExplodedNode we just visited - BinaryOperatorData &Data = hash[B]; - - const Stmt *predStmt = - C.getPredecessor()->getLocation().castAs<StmtPoint>().getStmt(); - - // Ignore implicit calls to setters. - if (!isa<BinaryOperator>(predStmt)) - return; - - Data.explodedNodes.Add(C.getPredecessor()); -} - -void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G, - BugReporter &BR, - ExprEngine &Eng) const { - if (!BT) - BT.reset(new BugType("Idempotent operation", "Dead code")); - - // Iterate over the hash to see if we have any paths with definite - // idempotent operations. - for (AssumptionMap::const_iterator i = hash.begin(); i != hash.end(); ++i) { - // Unpack the hash contents - const BinaryOperatorData &Data = i->second; - const Assumption &A = Data.assumption; - const ExplodedNodeSet &ES = Data.explodedNodes; - - // If there are no nodes accosted with the expression, nothing to report. - // FIXME: This is possible because the checker does part of processing in - // checkPreStmt and part in checkPostStmt. - if (ES.begin() == ES.end()) - continue; - - const BinaryOperator *B = i->first; - - if (A == Impossible) - continue; - - // If the analyzer did not finish, check to see if we can still emit this - // warning - if (Eng.hasWorkRemaining()) { - // If we can trace back - AnalysisDeclContext *AC = (*ES.begin())->getLocationContext() - ->getAnalysisDeclContext(); - if (!pathWasCompletelyAnalyzed(AC, - AC->getCFGStmtMap()->getBlock(B), - Eng.getCoreEngine())) - continue; - } - - // Select the error message and SourceRanges to report. - SmallString<128> buf; - llvm::raw_svector_ostream os(buf); - bool LHSRelevant = false, RHSRelevant = false; - switch (A) { - case Equal: - LHSRelevant = true; - RHSRelevant = true; - if (B->getOpcode() == BO_Assign) - os << "Assigned value is always the same as the existing value"; - else - os << "Both operands to '" << B->getOpcodeStr() - << "' always have the same value"; - break; - case LHSis1: - LHSRelevant = true; - os << "The left operand to '" << B->getOpcodeStr() << "' is always 1"; - break; - case RHSis1: - RHSRelevant = true; - os << "The right operand to '" << B->getOpcodeStr() << "' is always 1"; - break; - case LHSis0: - LHSRelevant = true; - os << "The left operand to '" << B->getOpcodeStr() << "' is always 0"; - break; - case RHSis0: - RHSRelevant = true; - os << "The right operand to '" << B->getOpcodeStr() << "' is always 0"; - break; - case Possible: - llvm_unreachable("Operation was never marked with an assumption"); - case Impossible: - llvm_unreachable(0); - } - - // Add a report for each ExplodedNode - for (ExplodedNodeSet::iterator I = ES.begin(), E = ES.end(); I != E; ++I) { - BugReport *report = new BugReport(*BT, os.str(), *I); - - // Add source ranges and visitor hooks - if (LHSRelevant) { - const Expr *LHS = i->first->getLHS(); - report->addRange(LHS->getSourceRange()); - FindLastStoreBRVisitor::registerStatementVarDecls(*report, LHS, false); - } - if (RHSRelevant) { - const Expr *RHS = i->first->getRHS(); - report->addRange(i->first->getRHS()->getSourceRange()); - FindLastStoreBRVisitor::registerStatementVarDecls(*report, RHS, false); - } - - BR.emitReport(report); - } - } - - hash.clear(); -} - -// Updates the current assumption given the new assumption -inline void IdempotentOperationChecker::UpdateAssumption(Assumption &A, - const Assumption &New) { -// If the assumption is the same, there is nothing to do - if (A == New) - return; - - switch (A) { - // If we don't currently have an assumption, set it - case Possible: - A = New; - return; - - // If we have determined that a valid state happened, ignore the new - // assumption. - case Impossible: - return; - - // Any other case means that we had a different assumption last time. We don't - // currently support mixing assumptions for diagnostic reasons, so we set - // our assumption to be impossible. - default: - A = Impossible; - return; - } -} - -// Check for a statement where a variable is self assigned to possibly avoid an -// unused variable warning. -bool IdempotentOperationChecker::isSelfAssign(const Expr *LHS, const Expr *RHS) { - LHS = LHS->IgnoreParenCasts(); - RHS = RHS->IgnoreParenCasts(); - - const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS); - if (!LHS_DR) - return false; - - const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl()); - if (!VD) - return false; - - const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS); - if (!RHS_DR) - return false; - - if (VD != RHS_DR->getDecl()) - return false; - - return true; -} - -// Returns true if the Expr points to a VarDecl that is not read anywhere -// outside of self-assignments. -bool IdempotentOperationChecker::isUnused(const Expr *E, - AnalysisDeclContext *AC) { - if (!E) - return false; - - const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()); - if (!DR) - return false; - - const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); - if (!VD) - return false; - - if (AC->getPseudoConstantAnalysis()->wasReferenced(VD)) - return false; - - return true; -} - -// Check for self casts truncating/extending a variable -bool IdempotentOperationChecker::isTruncationExtensionAssignment( - const Expr *LHS, - const Expr *RHS) { - - const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParenCasts()); - if (!LHS_DR) - return false; - - const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl()); - if (!VD) - return false; - - const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS->IgnoreParenCasts()); - if (!RHS_DR) - return false; - - if (VD != RHS_DR->getDecl()) - return false; - - return dyn_cast<DeclRefExpr>(RHS->IgnoreParenLValueCasts()) == NULL; -} - -// Returns false if a path to this block was not completely analyzed, or true -// otherwise. -bool -IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisDeclContext *AC, - const CFGBlock *CB, - const CoreEngine &CE) { - - CFGReverseBlockReachabilityAnalysis *CRA = AC->getCFGReachablityAnalysis(); - - // Test for reachability from any aborted blocks to this block - typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator; - for (ExhaustedIterator I = CE.blocks_exhausted_begin(), - E = CE.blocks_exhausted_end(); I != E; ++I) { - const BlockEdge &BE = I->first; - - // The destination block on the BlockEdge is the first block that was not - // analyzed. If we can reach this block from the aborted block, then this - // block was not completely analyzed. - // - // Also explicitly check if the current block is the destination block. - // While technically reachable, it means we aborted the analysis on - // a path that included that block. - const CFGBlock *destBlock = BE.getDst(); - if (destBlock == CB || CRA->isReachable(destBlock, CB)) - return false; - } - - // Test for reachability from blocks we just gave up on. - typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator; - for (AbortedIterator I = CE.blocks_aborted_begin(), - E = CE.blocks_aborted_end(); I != E; ++I) { - const CFGBlock *destBlock = I->first; - if (destBlock == CB || CRA->isReachable(destBlock, CB)) - return false; - } - - // For the items still on the worklist, see if they are in blocks that - // can eventually reach 'CB'. - class VisitWL : public WorkList::Visitor { - const CFGStmtMap *CBM; - const CFGBlock *TargetBlock; - CFGReverseBlockReachabilityAnalysis &CRA; - public: - VisitWL(const CFGStmtMap *cbm, const CFGBlock *targetBlock, - CFGReverseBlockReachabilityAnalysis &cra) - : CBM(cbm), TargetBlock(targetBlock), CRA(cra) {} - virtual bool visit(const WorkListUnit &U) { - ProgramPoint P = U.getNode()->getLocation(); - const CFGBlock *B = 0; - if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) { - B = CBM->getBlock(SP->getStmt()); - } else if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { - B = BE->getDst(); - } else if (Optional<BlockEntrance> BEnt = P.getAs<BlockEntrance>()) { - B = BEnt->getBlock(); - } else if (Optional<BlockExit> BExit = P.getAs<BlockExit>()) { - B = BExit->getBlock(); - } - if (!B) - return true; - - return B == TargetBlock || CRA.isReachable(B, TargetBlock); - } - }; - VisitWL visitWL(AC->getCFGStmtMap(), CB, *CRA); - // Were there any items in the worklist that could potentially reach - // this block? - if (CE.getWorkList()->visitItemsInWorkList(visitWL)) - return false; - - // Verify that this block is reachable from the entry block - if (!CRA->isReachable(&AC->getCFG()->getEntry(), CB)) - return false; - - // If we get to this point, there is no connection to the entry block or an - // aborted block. This path is unreachable and we can report the error. - return true; -} - -// Recursive function that determines whether an expression contains any element -// that varies. This could be due to a compile-time constant like sizeof. An -// expression may also involve a variable that behaves like a constant. The -// function returns true if the expression varies, and false otherwise. -bool IdempotentOperationChecker::CanVary(const Expr *Ex, - AnalysisDeclContext *AC) { - // Parentheses and casts are irrelevant here - Ex = Ex->IgnoreParenCasts(); - - if (Ex->getLocStart().isMacroID()) - return false; - - switch (Ex->getStmtClass()) { - // Trivially true cases - case Stmt::ArraySubscriptExprClass: - case Stmt::MemberExprClass: - case Stmt::StmtExprClass: - case Stmt::CallExprClass: - case Stmt::VAArgExprClass: - case Stmt::ShuffleVectorExprClass: - return true; - default: - return true; - - // Trivially false cases - case Stmt::IntegerLiteralClass: - case Stmt::CharacterLiteralClass: - case Stmt::FloatingLiteralClass: - case Stmt::PredefinedExprClass: - case Stmt::ImaginaryLiteralClass: - case Stmt::StringLiteralClass: - case Stmt::OffsetOfExprClass: - case Stmt::CompoundLiteralExprClass: - case Stmt::AddrLabelExprClass: - case Stmt::BinaryTypeTraitExprClass: - case Stmt::GNUNullExprClass: - case Stmt::InitListExprClass: - case Stmt::DesignatedInitExprClass: - case Stmt::BlockExprClass: - return false; - - // Cases requiring custom logic - case Stmt::UnaryExprOrTypeTraitExprClass: { - const UnaryExprOrTypeTraitExpr *SE = - cast<const UnaryExprOrTypeTraitExpr>(Ex); - if (SE->getKind() != UETT_SizeOf) - return false; - return SE->getTypeOfArgument()->isVariableArrayType(); - } - case Stmt::DeclRefExprClass: - // Check for constants/pseudoconstants - return !isConstantOrPseudoConstant(cast<DeclRefExpr>(Ex), AC); - - // The next cases require recursion for subexpressions - case Stmt::BinaryOperatorClass: { - const BinaryOperator *B = cast<const BinaryOperator>(Ex); - - // Exclude cases involving pointer arithmetic. These are usually - // false positives. - if (B->getOpcode() == BO_Sub || B->getOpcode() == BO_Add) - if (B->getLHS()->getType()->getAs<PointerType>()) - return false; - - return CanVary(B->getRHS(), AC) - || CanVary(B->getLHS(), AC); - } - case Stmt::UnaryOperatorClass: - return CanVary(cast<UnaryOperator>(Ex)->getSubExpr(), AC); - case Stmt::ConditionalOperatorClass: - case Stmt::BinaryConditionalOperatorClass: - return CanVary(cast<AbstractConditionalOperator>(Ex)->getCond(), AC); - } -} - -// Returns true if a DeclRefExpr is or behaves like a constant. -bool IdempotentOperationChecker::isConstantOrPseudoConstant( - const DeclRefExpr *DR, - AnalysisDeclContext *AC) { - // Check if the type of the Decl is const-qualified - if (DR->getType().isConstQualified()) - return true; - - // Check for an enum - if (isa<EnumConstantDecl>(DR->getDecl())) - return true; - - const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); - if (!VD) - return true; - - // Check if the Decl behaves like a constant. This check also takes care of - // static variables, which can only change between function calls if they are - // modified in the AST. - PseudoConstantAnalysis *PCA = AC->getPseudoConstantAnalysis(); - if (PCA->isPseudoConstant(VD)) - return true; - - return false; -} - -// Recursively find any substatements containing VarDecl's with storage other -// than local -bool IdempotentOperationChecker::containsNonLocalVarDecl(const Stmt *S) { - const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S); - - if (DR) - if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) - if (!VD->hasLocalStorage()) - return true; - - for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); - ++I) - if (const Stmt *child = *I) - if (containsNonLocalVarDecl(child)) - return true; - - return false; -} - - -void ento::registerIdempotentOperationChecker(CheckerManager &mgr) { - mgr.registerChecker<IdempotentOperationChecker>(); -} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp index e696e38..d5c52b4 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp @@ -11,22 +11,23 @@ /// \brief This defines IdenticalExprChecker, a check that warns about /// unintended use of identical expressions. /// -/// It checks for use of identical expressions with comparison operators. +/// It checks for use of identical expressions with comparison operators and +/// inside conditional expressions. /// //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "clang/AST/RecursiveASTVisitor.h" using namespace clang; using namespace ento; -static bool isIdenticalExpr(const ASTContext &Ctx, const Expr *Expr1, - const Expr *Expr2); +static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, + const Stmt *Stmt2, bool IgnoreSideEffects = false); //===----------------------------------------------------------------------===// // FindIdenticalExprVisitor - Identify nodes using identical expressions. //===----------------------------------------------------------------------===// @@ -34,23 +35,153 @@ static bool isIdenticalExpr(const ASTContext &Ctx, const Expr *Expr1, namespace { class FindIdenticalExprVisitor : public RecursiveASTVisitor<FindIdenticalExprVisitor> { + BugReporter &BR; + const CheckerBase *Checker; + AnalysisDeclContext *AC; public: - explicit FindIdenticalExprVisitor(BugReporter &B, AnalysisDeclContext *A) - : BR(B), AC(A) {} + explicit FindIdenticalExprVisitor(BugReporter &B, + const CheckerBase *Checker, + AnalysisDeclContext *A) + : BR(B), Checker(Checker), AC(A) {} // FindIdenticalExprVisitor only visits nodes - // that are binary operators. + // that are binary operators, if statements or + // conditional operators. bool VisitBinaryOperator(const BinaryOperator *B); + bool VisitIfStmt(const IfStmt *I); + bool VisitConditionalOperator(const ConditionalOperator *C); private: - BugReporter &BR; - AnalysisDeclContext *AC; + void reportIdenticalExpr(const BinaryOperator *B, bool CheckBitwise, + ArrayRef<SourceRange> Sr); + void checkBitwiseOrLogicalOp(const BinaryOperator *B, bool CheckBitwise); + void checkComparisonOp(const BinaryOperator *B); }; } // end anonymous namespace +void FindIdenticalExprVisitor::reportIdenticalExpr(const BinaryOperator *B, + bool CheckBitwise, + ArrayRef<SourceRange> Sr) { + StringRef Message; + if (CheckBitwise) + Message = "identical expressions on both sides of bitwise operator"; + else + Message = "identical expressions on both sides of logical operator"; + + PathDiagnosticLocation ELoc = + PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager()); + BR.EmitBasicReport(AC->getDecl(), Checker, + "Use of identical expressions", + categories::LogicError, + Message, ELoc, Sr); +} + +void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B, + bool CheckBitwise) { + SourceRange Sr[2]; + + const Expr *LHS = B->getLHS(); + const Expr *RHS = B->getRHS(); + + // Split operators as long as we still have operators to split on. We will + // get called for every binary operator in an expression so there is no need + // to check every one against each other here, just the right most one with + // the others. + while (const BinaryOperator *B2 = dyn_cast<BinaryOperator>(LHS)) { + if (B->getOpcode() != B2->getOpcode()) + break; + if (isIdenticalStmt(AC->getASTContext(), RHS, B2->getRHS())) { + Sr[0] = RHS->getSourceRange(); + Sr[1] = B2->getRHS()->getSourceRange(); + reportIdenticalExpr(B, CheckBitwise, Sr); + } + LHS = B2->getLHS(); + } + + if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) { + Sr[0] = RHS->getSourceRange(); + Sr[1] = LHS->getSourceRange(); + reportIdenticalExpr(B, CheckBitwise, Sr); + } +} + +bool FindIdenticalExprVisitor::VisitIfStmt(const IfStmt *I) { + const Stmt *Stmt1 = I->getThen(); + const Stmt *Stmt2 = I->getElse(); + + // Check for identical conditions: + // + // if (b) { + // foo1(); + // } else if (b) { + // foo2(); + // } + if (Stmt1 && Stmt2) { + const Expr *Cond1 = I->getCond(); + const Stmt *Else = Stmt2; + while (const IfStmt *I2 = dyn_cast_or_null<IfStmt>(Else)) { + const Expr *Cond2 = I2->getCond(); + if (isIdenticalStmt(AC->getASTContext(), Cond1, Cond2, false)) { + SourceRange Sr = Cond1->getSourceRange(); + PathDiagnosticLocation ELoc(Cond2, BR.getSourceManager(), AC); + BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions", + categories::LogicError, + "expression is identical to previous condition", + ELoc, Sr); + } + Else = I2->getElse(); + } + } + + if (!Stmt1 || !Stmt2) + return true; + + // Special handling for code like: + // + // if (b) { + // i = 1; + // } else + // i = 1; + if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) { + if (CompStmt->size() == 1) + Stmt1 = CompStmt->body_back(); + } + if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) { + if (CompStmt->size() == 1) + Stmt2 = CompStmt->body_back(); + } + + if (isIdenticalStmt(AC->getASTContext(), Stmt1, Stmt2, true)) { + PathDiagnosticLocation ELoc = + PathDiagnosticLocation::createBegin(I, BR.getSourceManager(), AC); + BR.EmitBasicReport(AC->getDecl(), Checker, + "Identical branches", + categories::LogicError, + "true and false branches are identical", ELoc); + } + return true; +} + bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) { BinaryOperator::Opcode Op = B->getOpcode(); - if (!BinaryOperator::isComparisonOp(Op)) - return true; + + if (BinaryOperator::isBitwiseOp(Op)) + checkBitwiseOrLogicalOp(B, true); + + if (BinaryOperator::isLogicalOp(Op)) + checkBitwiseOrLogicalOp(B, false); + + if (BinaryOperator::isComparisonOp(Op)) + checkComparisonOp(B); + + // We want to visit ALL nodes (subexpressions of binary comparison + // expressions too) that contains comparison operators. + // True is always returned to traverse ALL nodes. + return true; +} + +void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) { + BinaryOperator::Opcode Op = B->getOpcode(); + // // Special case for floating-point representation. // @@ -83,26 +214,26 @@ bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) { (DeclRef2->getType()->hasFloatingRepresentation())) { if (DeclRef1->getDecl() == DeclRef2->getDecl()) { if ((Op == BO_EQ) || (Op == BO_NE)) { - return true; + return; } } } } else if ((FloatLit1) && (FloatLit2)) { if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) { if ((Op == BO_EQ) || (Op == BO_NE)) { - return true; + return; } } } else if (LHS->getType()->hasFloatingRepresentation()) { // If any side of comparison operator still has floating-point // representation, then it's an expression. Don't warn. // Here only LHS is checked since RHS will be implicit casted to float. - return true; + return; } else { // No special case with floating-point representation, report as usual. } - if (isIdenticalExpr(AC->getASTContext(), B->getLHS(), B->getRHS())) { + if (isIdenticalStmt(AC->getASTContext(), B->getLHS(), B->getRHS())) { PathDiagnosticLocation ELoc = PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager()); StringRef Message; @@ -110,15 +241,41 @@ bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) { Message = "comparison of identical expressions always evaluates to true"; else Message = "comparison of identical expressions always evaluates to false"; - BR.EmitBasicReport(AC->getDecl(), "Compare of identical expressions", + BR.EmitBasicReport(AC->getDecl(), Checker, + "Compare of identical expressions", categories::LogicError, Message, ELoc); } - // We want to visit ALL nodes (subexpressions of binary comparison - // expressions too) that contains comparison operators. - // True is always returned to traverse ALL nodes. +} + +bool FindIdenticalExprVisitor::VisitConditionalOperator( + const ConditionalOperator *C) { + + // Check if expressions in conditional expression are identical + // from a symbolic point of view. + + if (isIdenticalStmt(AC->getASTContext(), C->getTrueExpr(), + C->getFalseExpr(), true)) { + PathDiagnosticLocation ELoc = + PathDiagnosticLocation::createConditionalColonLoc( + C, BR.getSourceManager()); + + SourceRange Sr[2]; + Sr[0] = C->getTrueExpr()->getSourceRange(); + Sr[1] = C->getFalseExpr()->getSourceRange(); + BR.EmitBasicReport( + AC->getDecl(), Checker, + "Identical expressions in conditional expression", + categories::LogicError, + "identical expressions on both sides of ':' in conditional expression", + ELoc, Sr); + } + // We want to visit ALL nodes (expressions in conditional + // expressions too) that contains conditional operators, + // thus always return true to traverse ALL nodes. return true; } -/// \brief Determines whether two expression trees are identical regarding + +/// \brief Determines whether two statement trees are identical regarding /// operators and symbols. /// /// Exceptions: expressions containing macros or functions with possible side @@ -126,82 +283,189 @@ bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) { /// Limitations: (t + u) and (u + t) are not considered identical. /// t*(u + t) and t*u + t*t are not considered identical. /// -static bool isIdenticalExpr(const ASTContext &Ctx, const Expr *Expr1, - const Expr *Expr2) { - // If Expr1 & Expr2 are of different class then they are not - // identical expression. - if (Expr1->getStmtClass() != Expr2->getStmtClass()) - return false; - // If Expr1 has side effects then don't warn even if expressions - // are identical. - if (Expr1->HasSideEffects(Ctx)) - return false; - // Is expression is based on macro then don't warn even if - // the expressions are identical. - if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID())) - return false; - // If all children of two expressions are identical, return true. - Expr::const_child_iterator I1 = Expr1->child_begin(); - Expr::const_child_iterator I2 = Expr2->child_begin(); - while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) { - const Expr *Child1 = dyn_cast<Expr>(*I1); - const Expr *Child2 = dyn_cast<Expr>(*I2); - if (!Child1 || !Child2 || !isIdenticalExpr(Ctx, Child1, Child2)) - return false; - ++I1; - ++I2; - } - // If there are different number of children in the expressions, return false. - // (TODO: check if this is a redundant condition.) - if (I1 != Expr1->child_end()) +static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, + const Stmt *Stmt2, bool IgnoreSideEffects) { + + if (!Stmt1 || !Stmt2) { + if (!Stmt1 && !Stmt2) + return true; return false; - if (I2 != Expr2->child_end()) + } + + // If Stmt1 & Stmt2 are of different class then they are not + // identical statements. + if (Stmt1->getStmtClass() != Stmt2->getStmtClass()) return false; - switch (Expr1->getStmtClass()) { + const Expr *Expr1 = dyn_cast<Expr>(Stmt1); + const Expr *Expr2 = dyn_cast<Expr>(Stmt2); + + if (Expr1 && Expr2) { + // If Stmt1 has side effects then don't warn even if expressions + // are identical. + if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx)) + return false; + // If either expression comes from a macro then don't warn even if + // the expressions are identical. + if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID())) + return false; + + // If all children of two expressions are identical, return true. + Expr::const_child_iterator I1 = Expr1->child_begin(); + Expr::const_child_iterator I2 = Expr2->child_begin(); + while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) { + if (!*I1 || !*I2 || !isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects)) + return false; + ++I1; + ++I2; + } + // If there are different number of children in the statements, return + // false. + if (I1 != Expr1->child_end()) + return false; + if (I2 != Expr2->child_end()) + return false; + } + + switch (Stmt1->getStmtClass()) { default: return false; + case Stmt::CallExprClass: case Stmt::ArraySubscriptExprClass: - case Stmt::CStyleCastExprClass: case Stmt::ImplicitCastExprClass: case Stmt::ParenExprClass: + case Stmt::BreakStmtClass: + case Stmt::ContinueStmtClass: + case Stmt::NullStmtClass: + return true; + case Stmt::CStyleCastExprClass: { + const CStyleCastExpr* CastExpr1 = cast<CStyleCastExpr>(Stmt1); + const CStyleCastExpr* CastExpr2 = cast<CStyleCastExpr>(Stmt2); + + return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten(); + } + case Stmt::ReturnStmtClass: { + const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1); + const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2); + + return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(), + ReturnStmt2->getRetValue(), IgnoreSideEffects); + } + case Stmt::ForStmtClass: { + const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1); + const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2); + + if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(), + IgnoreSideEffects)) + return false; + return true; + } + case Stmt::DoStmtClass: { + const DoStmt *DStmt1 = cast<DoStmt>(Stmt1); + const DoStmt *DStmt2 = cast<DoStmt>(Stmt2); + + if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(), + IgnoreSideEffects)) + return false; + return true; + } + case Stmt::WhileStmtClass: { + const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1); + const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2); + + if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(), + IgnoreSideEffects)) + return false; return true; + } + case Stmt::IfStmtClass: { + const IfStmt *IStmt1 = cast<IfStmt>(Stmt1); + const IfStmt *IStmt2 = cast<IfStmt>(Stmt2); + + if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(), + IgnoreSideEffects)) + return false; + return true; + } + case Stmt::CompoundStmtClass: { + const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1); + const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2); + + if (CompStmt1->size() != CompStmt2->size()) + return false; + + CompoundStmt::const_body_iterator I1 = CompStmt1->body_begin(); + CompoundStmt::const_body_iterator I2 = CompStmt2->body_begin(); + while (I1 != CompStmt1->body_end() && I2 != CompStmt2->body_end()) { + if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects)) + return false; + ++I1; + ++I2; + } + + return true; + } + case Stmt::CompoundAssignOperatorClass: case Stmt::BinaryOperatorClass: { - const BinaryOperator *BinOp1 = dyn_cast<BinaryOperator>(Expr1); - const BinaryOperator *BinOp2 = dyn_cast<BinaryOperator>(Expr2); + const BinaryOperator *BinOp1 = cast<BinaryOperator>(Stmt1); + const BinaryOperator *BinOp2 = cast<BinaryOperator>(Stmt2); return BinOp1->getOpcode() == BinOp2->getOpcode(); } case Stmt::CharacterLiteralClass: { - const CharacterLiteral *CharLit1 = dyn_cast<CharacterLiteral>(Expr1); - const CharacterLiteral *CharLit2 = dyn_cast<CharacterLiteral>(Expr2); + const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Stmt1); + const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Stmt2); return CharLit1->getValue() == CharLit2->getValue(); } case Stmt::DeclRefExprClass: { - const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(Expr1); - const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(Expr2); + const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1); + const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2); return DeclRef1->getDecl() == DeclRef2->getDecl(); } case Stmt::IntegerLiteralClass: { - const IntegerLiteral *IntLit1 = dyn_cast<IntegerLiteral>(Expr1); - const IntegerLiteral *IntLit2 = dyn_cast<IntegerLiteral>(Expr2); + const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1); + const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2); return IntLit1->getValue() == IntLit2->getValue(); } case Stmt::FloatingLiteralClass: { - const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(Expr1); - const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(Expr2); + const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Stmt1); + const FloatingLiteral *FloatLit2 = cast<FloatingLiteral>(Stmt2); return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue()); } + case Stmt::StringLiteralClass: { + const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1); + const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2); + return StringLit1->getString() == StringLit2->getString(); + } case Stmt::MemberExprClass: { - const MemberExpr *MemberExpr1 = dyn_cast<MemberExpr>(Expr1); - const MemberExpr *MemberExpr2 = dyn_cast<MemberExpr>(Expr2); - return MemberExpr1->getMemberDecl() == MemberExpr2->getMemberDecl(); + const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1); + const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2); + return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl(); } case Stmt::UnaryOperatorClass: { - const UnaryOperator *UnaryOp1 = dyn_cast<UnaryOperator>(Expr1); - const UnaryOperator *UnaryOp2 = dyn_cast<UnaryOperator>(Expr2); - if (UnaryOp1->getOpcode() != UnaryOp2->getOpcode()) - return false; - return !UnaryOp1->isIncrementDecrementOp(); + const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Stmt1); + const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Stmt2); + return UnaryOp1->getOpcode() == UnaryOp2->getOpcode(); } } } @@ -215,7 +479,7 @@ class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr, BugReporter &BR) const { - FindIdenticalExprVisitor Visitor(BR, Mgr.getAnalysisDeclContext(D)); + FindIdenticalExprVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D)); Visitor.TraverseDecl(const_cast<Decl *>(D)); } }; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp index cc940be..1926600 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp @@ -49,6 +49,9 @@ struct ChecksFilter { DefaultBool check_MissingInvalidationMethod; /// Check that all ivars are invalidated. DefaultBool check_InstanceVariableInvalidation; + + CheckName checkName_MissingInvalidationMethod; + CheckName checkName_InstanceVariableInvalidation; }; class IvarInvalidationCheckerImpl { @@ -154,7 +157,7 @@ class IvarInvalidationCheckerImpl { PropertySetterToIvarMap(InPropertySetterToIvarMap), PropertyGetterToIvarMap(InPropertyGetterToIvarMap), PropertyToIvarMap(InPropertyToIvarMap), - InvalidationMethod(0), + InvalidationMethod(nullptr), Ctx(InCtx) {} void VisitStmt(const Stmt *S) { VisitChildren(S); } @@ -200,7 +203,8 @@ class IvarInvalidationCheckerImpl { const ObjCIvarDecl *IvarDecl, const IvarToPropMapTy &IvarToPopertyMap); - void reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl, + void reportNoInvalidationMethod(CheckName CheckName, + const ObjCIvarDecl *FirstIvarDecl, const IvarToPropMapTy &IvarToPopertyMap, const ObjCInterfaceDecl *InterfaceD, bool MissingDeclaration) const; @@ -223,10 +227,7 @@ public: }; static bool isInvalidationMethod(const ObjCMethodDecl *M, bool LookForPartial) { - for (specific_attr_iterator<AnnotateAttr> - AI = M->specific_attr_begin<AnnotateAttr>(), - AE = M->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) { - const AnnotateAttr *Ann = *AI; + for (const auto *Ann : M->specific_attrs<AnnotateAttr>()) { if (!LookForPartial && Ann->getAnnotation() == "objc_instance_variable_invalidator") return true; @@ -247,33 +248,22 @@ void IvarInvalidationCheckerImpl::containsInvalidationMethod( // TODO: Cache the results. // Check all methods. - for (ObjCContainerDecl::method_iterator - I = D->meth_begin(), - E = D->meth_end(); I != E; ++I) { - const ObjCMethodDecl *MDI = *I; - if (isInvalidationMethod(MDI, Partial)) - OutInfo.addInvalidationMethod( - cast<ObjCMethodDecl>(MDI->getCanonicalDecl())); - } + for (const auto *MDI : D->methods()) + if (isInvalidationMethod(MDI, Partial)) + OutInfo.addInvalidationMethod( + cast<ObjCMethodDecl>(MDI->getCanonicalDecl())); // If interface, check all parent protocols and super. if (const ObjCInterfaceDecl *InterfD = dyn_cast<ObjCInterfaceDecl>(D)) { // Visit all protocols. - for (ObjCInterfaceDecl::protocol_iterator - I = InterfD->protocol_begin(), - E = InterfD->protocol_end(); I != E; ++I) { - containsInvalidationMethod((*I)->getDefinition(), OutInfo, Partial); - } + for (const auto *I : InterfD->protocols()) + containsInvalidationMethod(I->getDefinition(), OutInfo, Partial); // Visit all categories in case the invalidation method is declared in // a category. - for (ObjCInterfaceDecl::visible_extensions_iterator - Ext = InterfD->visible_extensions_begin(), - ExtEnd = InterfD->visible_extensions_end(); - Ext != ExtEnd; ++Ext) { - containsInvalidationMethod(*Ext, OutInfo, Partial); - } + for (const auto *Ext : InterfD->visible_extensions()) + containsInvalidationMethod(Ext, OutInfo, Partial); containsInvalidationMethod(InterfD->getSuperClass(), OutInfo, Partial); return; @@ -281,10 +271,8 @@ void IvarInvalidationCheckerImpl::containsInvalidationMethod( // If protocol, check all parent protocols. if (const ObjCProtocolDecl *ProtD = dyn_cast<ObjCProtocolDecl>(D)) { - for (ObjCInterfaceDecl::protocol_iterator - I = ProtD->protocol_begin(), - E = ProtD->protocol_end(); I != E; ++I) { - containsInvalidationMethod((*I)->getDefinition(), OutInfo, Partial); + for (const auto *I : ProtD->protocols()) { + containsInvalidationMethod(I->getDefinition(), OutInfo, Partial); } return; } @@ -318,7 +306,7 @@ const ObjCIvarDecl *IvarInvalidationCheckerImpl::findPropertyBackingIvar( const ObjCInterfaceDecl *InterfaceD, IvarSet &TrackedIvars, const ObjCIvarDecl **FirstIvarDecl) { - const ObjCIvarDecl *IvarD = 0; + const ObjCIvarDecl *IvarD = nullptr; // Lookup for the synthesized case. IvarD = Prop->getPropertyIvarDecl(); @@ -355,7 +343,7 @@ const ObjCIvarDecl *IvarInvalidationCheckerImpl::findPropertyBackingIvar( // Note, this is a possible source of false positives. We could look at the // getter implementation to find the ivar when its name is not derived from // the property name. - return 0; + return nullptr; } void IvarInvalidationCheckerImpl::printIvar(llvm::raw_svector_ostream &os, @@ -379,7 +367,7 @@ visit(const ObjCImplementationDecl *ImplD) const { // Record the first Ivar needing invalidation; used in reporting when only // one ivar is sufficient. Cannot grab the first on the Ivars set to ensure // deterministic output. - const ObjCIvarDecl *FirstIvarDecl = 0; + const ObjCIvarDecl *FirstIvarDecl = nullptr; const ObjCInterfaceDecl *InterfaceD = ImplD->getClassInterface(); // Collect ivars declared in this class, its extensions and its implementation @@ -476,7 +464,8 @@ visit(const ObjCImplementationDecl *ImplD) const { // Report an error in case none of the invalidation methods are declared. if (!Info.needsInvalidation() && !PartialInfo.needsInvalidation()) { if (Filter.check_MissingInvalidationMethod) - reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD, + reportNoInvalidationMethod(Filter.checkName_MissingInvalidationMethod, + FirstIvarDecl, IvarToPopertyMap, InterfaceD, /*MissingDeclaration*/ true); // If there are no invalidation methods, there is no ivar validation work // to be done. @@ -529,20 +518,20 @@ visit(const ObjCImplementationDecl *ImplD) const { // invalidation methods. for (IvarSet::const_iterator I = Ivars.begin(), E = Ivars.end(); I != E; ++I) - reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, 0); + reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, nullptr); } else { // Otherwise, no invalidation methods were implemented. - reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD, + reportNoInvalidationMethod(Filter.checkName_InstanceVariableInvalidation, + FirstIvarDecl, IvarToPopertyMap, InterfaceD, /*MissingDeclaration*/ false); } } } -void IvarInvalidationCheckerImpl:: -reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl, - const IvarToPropMapTy &IvarToPopertyMap, - const ObjCInterfaceDecl *InterfaceD, - bool MissingDeclaration) const { +void IvarInvalidationCheckerImpl::reportNoInvalidationMethod( + CheckName CheckName, const ObjCIvarDecl *FirstIvarDecl, + const IvarToPropMapTy &IvarToPopertyMap, + const ObjCInterfaceDecl *InterfaceD, bool MissingDeclaration) const { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); assert(FirstIvarDecl); @@ -557,7 +546,7 @@ reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl, PathDiagnosticLocation IvarDecLocation = PathDiagnosticLocation::createBegin(FirstIvarDecl, BR.getSourceManager()); - BR.EmitBasicReport(FirstIvarDecl, "Incomplete invalidation", + BR.EmitBasicReport(FirstIvarDecl, CheckName, "Incomplete invalidation", categories::CoreFoundationObjectiveC, os.str(), IvarDecLocation); } @@ -575,15 +564,16 @@ reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD, PathDiagnosticLocation::createEnd(MethodD->getBody(), BR.getSourceManager(), Mgr.getAnalysisDeclContext(MethodD)); - BR.EmitBasicReport(MethodD, "Incomplete invalidation", + BR.EmitBasicReport(MethodD, Filter.checkName_InstanceVariableInvalidation, + "Incomplete invalidation", categories::CoreFoundationObjectiveC, os.str(), MethodDecLocation); } else { - BR.EmitBasicReport(IvarD, "Incomplete invalidation", - categories::CoreFoundationObjectiveC, os.str(), - PathDiagnosticLocation::createBegin(IvarD, - BR.getSourceManager())); - + BR.EmitBasicReport( + IvarD, Filter.checkName_InstanceVariableInvalidation, + "Incomplete invalidation", categories::CoreFoundationObjectiveC, + os.str(), + PathDiagnosticLocation::createBegin(IvarD, BR.getSourceManager())); } } @@ -727,7 +717,7 @@ void IvarInvalidationCheckerImpl::MethodCrawler::VisitObjCMessageExpr( if (Receiver) { InvalidationMethod = MD; check(Receiver->IgnoreParenCasts()); - InvalidationMethod = 0; + InvalidationMethod = nullptr; } VisitStmt(ME); @@ -750,10 +740,13 @@ public: }; } -#define REGISTER_CHECKER(name) \ -void ento::register##name(CheckerManager &mgr) {\ - mgr.registerChecker<IvarInvalidationChecker>()->Filter.check_##name = true;\ -} +#define REGISTER_CHECKER(name) \ + void ento::register##name(CheckerManager &mgr) { \ + IvarInvalidationChecker *checker = \ + mgr.registerChecker<IvarInvalidationChecker>(); \ + checker->Filter.check_##name = true; \ + checker->Filter.checkName_##name = mgr.getCurrentCheckName(); \ + } REGISTER_CHECKER(InstanceVariableInvalidation) REGISTER_CHECKER(MissingInvalidationMethod) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp index 02a7cc3..0b7375a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp @@ -58,7 +58,7 @@ static bool IsStdString(QualType T) { const TypedefNameDecl *TD = TT->getDecl(); - if (!InNamespace(TD, "std")) + if (!TD->isInStdNamespace()) return false; return TD->getName() == "string"; @@ -115,11 +115,14 @@ static bool IsSmallVector(QualType T) { namespace { class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> { - BugReporter &BR; const Decl *DeclWithIssue; + BugReporter &BR; + const CheckerBase *Checker; + public: - StringRefCheckerVisitor(const Decl *declWithIssue, BugReporter &br) - : BR(br), DeclWithIssue(declWithIssue) {} + StringRefCheckerVisitor(const Decl *declWithIssue, BugReporter &br, + const CheckerBase *checker) + : DeclWithIssue(declWithIssue), BR(br), Checker(checker) {} void VisitChildren(Stmt *S) { for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ; I != E; ++I) @@ -133,16 +136,17 @@ private: }; } // end anonymous namespace -static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) { - StringRefCheckerVisitor walker(D, BR); +static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR, + const CheckerBase *Checker) { + StringRefCheckerVisitor walker(D, BR, Checker); walker.Visit(D->getBody()); } void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) { VisitChildren(S); - for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();I!=E; ++I) - if (VarDecl *VD = dyn_cast<VarDecl>(*I)) + for (auto *I : S->decls()) + if (VarDecl *VD = dyn_cast<VarDecl>(I)) VisitVarDecl(VD); } @@ -179,7 +183,7 @@ void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) { "std::string that it outlives"; PathDiagnosticLocation VDLoc = PathDiagnosticLocation::createBegin(VD, BR.getSourceManager()); - BR.EmitBasicReport(DeclWithIssue, desc, "LLVM Conventions", desc, + BR.EmitBasicReport(DeclWithIssue, Checker, desc, "LLVM Conventions", desc, VDLoc, Init->getSourceRange()); } @@ -197,9 +201,7 @@ static bool IsPartOfAST(const CXXRecordDecl *R) { if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R) || IsClangAttr(R)) return true; - for (CXXRecordDecl::base_class_const_iterator I = R->bases_begin(), - E = R->bases_end(); I!=E; ++I) { - CXXBaseSpecifier BS = *I; + for (const auto &BS : R->bases()) { QualType T = BS.getType(); if (const RecordType *baseT = T->getAs<RecordType>()) { CXXRecordDecl *baseD = cast<CXXRecordDecl>(baseT->getDecl()); @@ -216,23 +218,26 @@ class ASTFieldVisitor { SmallVector<FieldDecl*, 10> FieldChain; const CXXRecordDecl *Root; BugReporter &BR; + const CheckerBase *Checker; + public: - ASTFieldVisitor(const CXXRecordDecl *root, BugReporter &br) - : Root(root), BR(br) {} + ASTFieldVisitor(const CXXRecordDecl *root, BugReporter &br, + const CheckerBase *checker) + : Root(root), BR(br), Checker(checker) {} void Visit(FieldDecl *D); void ReportError(QualType T); }; } // end anonymous namespace -static void CheckASTMemory(const CXXRecordDecl *R, BugReporter &BR) { +static void CheckASTMemory(const CXXRecordDecl *R, BugReporter &BR, + const CheckerBase *Checker) { if (!IsPartOfAST(R)) return; - for (RecordDecl::field_iterator I = R->field_begin(), E = R->field_end(); - I != E; ++I) { - ASTFieldVisitor walker(R, BR); - walker.Visit(*I); + for (auto *I : R->fields()) { + ASTFieldVisitor walker(R, BR, Checker); + walker.Visit(I); } } @@ -246,9 +251,8 @@ void ASTFieldVisitor::Visit(FieldDecl *D) { if (const RecordType *RT = T->getAs<RecordType>()) { const RecordDecl *RD = RT->getDecl()->getDefinition(); - for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); - I != E; ++I) - Visit(*I); + for (auto *I : RD->fields()) + Visit(I); } FieldChain.pop_back(); @@ -284,8 +288,8 @@ void ASTFieldVisitor::ReportError(QualType T) { // the class may be in the header file, for example). PathDiagnosticLocation L = PathDiagnosticLocation::createBegin( FieldChain.front(), BR.getSourceManager()); - BR.EmitBasicReport(Root, "AST node allocates heap memory", "LLVM Conventions", - os.str(), L); + BR.EmitBasicReport(Root, Checker, "AST node allocates heap memory", + "LLVM Conventions", os.str(), L); } //===----------------------------------------------------------------------===// @@ -300,12 +304,12 @@ public: void checkASTDecl(const CXXRecordDecl *R, AnalysisManager& mgr, BugReporter &BR) const { if (R->isCompleteDefinition()) - CheckASTMemory(R, BR); + CheckASTMemory(R, BR, this); } void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { - CheckStringRefAssignedTemporary(D, BR); + CheckStringRefAssignedTemporary(D, BR, this); } }; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp index f1f06c7..0f227bb 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp @@ -29,7 +29,7 @@ namespace { class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>, check::PostStmt<CallExpr>, check::DeadSymbols> { - mutable OwningPtr<BugType> BT; + mutable std::unique_ptr<BugType> BT; public: /// AllocationState is a part of the checker specific state together with the @@ -91,7 +91,7 @@ private: inline void initBugType() const { if (!BT) - BT.reset(new BugType("Improper use of SecKeychain API", + BT.reset(new BugType(this, "Improper use of SecKeychain API", "API Misuse (Apple)")); } @@ -139,7 +139,7 @@ private: SecKeychainBugVisitor(SymbolRef S) : Sym(S) {} virtual ~SecKeychainBugVisitor() {} - void Profile(llvm::FoldingSetNodeID &ID) const { + void Profile(llvm::FoldingSetNodeID &ID) const override { static int X = 0; ID.AddPointer(&X); ID.AddPointer(Sym); @@ -148,7 +148,7 @@ private: PathDiagnosticPiece *VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, - BugReport &BR); + BugReport &BR) override; }; }; } @@ -224,7 +224,7 @@ static SymbolRef getAsPointeeSymbol(const Expr *Expr, if (sym) return sym; } - return 0; + return nullptr; } // When checking for error code, we need to consider the following cases: @@ -458,7 +458,7 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE, // If the argument entered as an enclosing function parameter, skip it to // avoid false positives. if (isEnclosingFunctionParam(ArgExpr) && - C.getLocationContext()->getParent() == 0) + C.getLocationContext()->getParent() == nullptr) return; if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) { @@ -503,7 +503,7 @@ MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N, // symbol was tracked. if (N->getLocationContext() == LeakContext) AllocNode = N; - N = N->pred_empty() ? NULL : *(N->pred_begin()); + N = N->pred_empty() ? nullptr : *(N->pred_begin()); } return AllocNode; @@ -525,7 +525,7 @@ BugReport *MacOSKeychainAPIChecker:: // allocated, and only report a single path. PathDiagnosticLocation LocUsedForUniqueing; const ExplodedNode *AllocNode = getAllocationNode(N, AP.first, C); - const Stmt *AllocStmt = 0; + const Stmt *AllocStmt = nullptr; ProgramPoint P = AllocNode->getLocation(); if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>()) AllocStmt = Exit->getCalleeContext()->getCallSite(); @@ -575,7 +575,7 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR, return; } - static SimpleProgramPointTag Tag("MacOSKeychainAPIChecker : DeadSymbolsLeak"); + static CheckerProgramPointTag Tag(this, "DeadSymbolsLeak"); ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag); // Generate the error reports. @@ -596,10 +596,10 @@ PathDiagnosticPiece *MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode( BugReport &BR) { const AllocationState *AS = N->getState()->get<AllocatedData>(Sym); if (!AS) - return 0; + return nullptr; const AllocationState *ASPrev = PrevN->getState()->get<AllocatedData>(Sym); if (ASPrev) - return 0; + return nullptr; // (!ASPrev && AS) ~ We started tracking symbol in node N, it must be the // allocation site. diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp index 32ebb51..13a401d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp @@ -31,7 +31,7 @@ using namespace ento; namespace { class MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > { - mutable OwningPtr<BugType> BT_dispatchOnce; + mutable std::unique_ptr<BugType> BT_dispatchOnce; public: void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; @@ -67,7 +67,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, return; if (!BT_dispatchOnce) - BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'", + BT_dispatchOnce.reset(new BugType(this, "Improper use of 'dispatch_once'", "API Misuse (Apple)")); // Handle _dispatch_once. In some versions of the OS X SDK we have the case @@ -113,7 +113,7 @@ void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE, "_dispatch_once", "dispatch_once_f", &MacOSXAPIChecker::CheckDispatchOnce) - .Default(NULL); + .Default(nullptr); if (SC) (this->*SC)(C, CE, Name); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index c7aa0fb..a03fa25 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -16,6 +16,7 @@ #include "InterCheckerAPI.h" #include "clang/AST/Attr.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" @@ -48,7 +49,7 @@ class RefState { Allocated, // Reference to released/freed memory. Released, - // The responsibility for freeing resources has transfered from + // The responsibility for freeing resources has transferred from // this reference. A relinquished symbol should not be freed. Relinquished, // We are no longer guaranteed to have observed all manipulations @@ -100,17 +101,16 @@ public: } void dump(raw_ostream &OS) const { - static const char *const Table[] = { - "Allocated", - "Released", - "Relinquished" - }; - OS << Table[(unsigned) K]; + switch (static_cast<Kind>(K)) { +#define CASE(ID) case ID: OS << #ID; break; + CASE(Allocated) + CASE(Released) + CASE(Relinquished) + CASE(Escaped) + } } - LLVM_ATTRIBUTE_USED void dump() const { - dump(llvm::errs()); - } + LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); } }; enum ReallocPairKind { @@ -156,30 +156,25 @@ class MallocChecker : public Checker<check::DeadSymbols, check::Location, eval::Assume> { - mutable OwningPtr<BugType> BT_DoubleFree; - mutable OwningPtr<BugType> BT_Leak; - mutable OwningPtr<BugType> BT_UseFree; - mutable OwningPtr<BugType> BT_BadFree; - mutable OwningPtr<BugType> BT_MismatchedDealloc; - mutable OwningPtr<BugType> BT_OffsetFree; - mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc, - *II_valloc, *II_reallocf, *II_strndup, *II_strdup; - public: - MallocChecker() : II_malloc(0), II_free(0), II_realloc(0), II_calloc(0), - II_valloc(0), II_reallocf(0), II_strndup(0), II_strdup(0) {} + MallocChecker() + : II_malloc(nullptr), II_free(nullptr), II_realloc(nullptr), + II_calloc(nullptr), II_valloc(nullptr), II_reallocf(nullptr), + II_strndup(nullptr), II_strdup(nullptr), II_kmalloc(nullptr) {} /// In pessimistic mode, the checker assumes that it does not know which /// functions might free the memory. - struct ChecksFilter { - DefaultBool CMallocPessimistic; - DefaultBool CMallocOptimistic; - DefaultBool CNewDeleteChecker; - DefaultBool CNewDeleteLeaksChecker; - DefaultBool CMismatchedDeallocatorChecker; + enum CheckKind { + CK_MallocPessimistic, + CK_MallocOptimistic, + CK_NewDeleteChecker, + CK_NewDeleteLeaksChecker, + CK_MismatchedDeallocatorChecker, + CK_NumCheckKinds }; - ChecksFilter Filter; + DefaultBool ChecksEnabled[CK_NumCheckKinds]; + CheckName CheckNames[CK_NumCheckKinds]; void checkPreCall(const CallEvent &Call, CheckerContext &C) const; void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; @@ -204,9 +199,21 @@ public: PointerEscapeKind Kind) const; void printState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep) const; + const char *NL, const char *Sep) const override; private: + mutable std::unique_ptr<BugType> BT_DoubleFree[CK_NumCheckKinds]; + mutable std::unique_ptr<BugType> BT_DoubleDelete; + mutable std::unique_ptr<BugType> BT_Leak[CK_NumCheckKinds]; + mutable std::unique_ptr<BugType> BT_UseFree[CK_NumCheckKinds]; + mutable std::unique_ptr<BugType> BT_BadFree[CK_NumCheckKinds]; + mutable std::unique_ptr<BugType> BT_MismatchedDealloc; + mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds]; + mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc, + *II_valloc, *II_reallocf, *II_strndup, *II_strdup, + *II_kmalloc; + mutable Optional<uint64_t> KernelZeroFlagVal; + void initIdentifierInfo(ASTContext &C) const; /// \brief Determine family of a deallocation expression. @@ -234,9 +241,9 @@ private: bool isAllocationFunction(const FunctionDecl *FD, ASTContext &C) const; bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const; ///@} - static ProgramStateRef MallocMemReturnsAttr(CheckerContext &C, - const CallExpr *CE, - const OwnershipAttr* Att); + ProgramStateRef MallocMemReturnsAttr(CheckerContext &C, + const CallExpr *CE, + const OwnershipAttr* Att) const; static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE, const Expr *SizeEx, SVal Init, ProgramStateRef State, @@ -251,6 +258,12 @@ private: ProgramStateRef State, AllocationFamily Family = AF_Malloc); + // Check if this malloc() for special flags. At present that means M_ZERO or + // __GFP_ZERO (in which case, treat it like calloc). + llvm::Optional<ProgramStateRef> + performKernelMalloc(const CallExpr *CE, CheckerContext &C, + const ProgramStateRef &State) const; + /// Update the RefState to reflect the new memory allocation. static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, @@ -279,6 +292,8 @@ private: bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const; + bool checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const; + /// Check if the function is known free memory, or if it is /// "interesting" and should be modeled explicitly. /// @@ -302,10 +317,12 @@ private: ///@{ /// Tells if a given family/call/symbol is tracked by the current checker. - bool isTrackedByCurrentChecker(AllocationFamily Family) const; - bool isTrackedByCurrentChecker(CheckerContext &C, - const Stmt *AllocDeallocStmt) const; - bool isTrackedByCurrentChecker(CheckerContext &C, SymbolRef Sym) const; + /// Sets CheckKind to the kind of the checker responsible for this + /// family/call/symbol. + Optional<CheckKind> getCheckIfTracked(AllocationFamily Family) const; + Optional<CheckKind> getCheckIfTracked(CheckerContext &C, + const Stmt *AllocDeallocStmt) const; + Optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym) const; ///@} static bool SummarizeValue(raw_ostream &os, SVal V); static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR); @@ -316,12 +333,14 @@ private: SymbolRef Sym, bool OwnershipTransferred) const; void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range, const Expr *DeallocExpr, - const Expr *AllocExpr = 0) const; + const Expr *AllocExpr = nullptr) const; void ReportUseAfterFree(CheckerContext &C, SourceRange Range, SymbolRef Sym) const; void ReportDoubleFree(CheckerContext &C, SourceRange Range, bool Released, SymbolRef Sym, SymbolRef PrevSym) const; + void ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const; + /// Find the location of the allocation for Sym on the path leading to the /// exploded node N. LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym, @@ -352,11 +371,11 @@ private: public: MallocBugVisitor(SymbolRef S, bool isLeak = false) - : Sym(S), Mode(Normal), FailedReallocSymbol(0), IsLeak(isLeak) {} + : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr), IsLeak(isLeak) {} virtual ~MallocBugVisitor() {} - void Profile(llvm::FoldingSetNodeID &ID) const { + void Profile(llvm::FoldingSetNodeID &ID) const override { static int X = 0; ID.AddPointer(&X); ID.AddPointer(Sym); @@ -398,13 +417,13 @@ private: PathDiagnosticPiece *VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, - BugReport &BR); + BugReport &BR) override; PathDiagnosticPiece* getEndPath(BugReporterContext &BRC, const ExplodedNode *EndPathNode, - BugReport &BR) { + BugReport &BR) override { if (!IsLeak) - return 0; + return nullptr; PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath(EndPathNode, @@ -420,7 +439,8 @@ private: StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M) : StackHintGeneratorForSymbol(S, M) {} - virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) { + std::string getMessageForArg(const Expr *ArgE, + unsigned ArgIndex) override { // Printed parameters start at 1, not 0. ++ArgIndex; @@ -433,7 +453,7 @@ private: return os.str(); } - virtual std::string getMessageForReturn(const CallExpr *CallExpr) { + std::string getMessageForReturn(const CallExpr *CallExpr) override { return "Reallocation of returned value failed"; } }; @@ -455,7 +475,7 @@ public: StopTrackingCallback(ProgramStateRef st) : state(st) {} ProgramStateRef getState() const { return state; } - bool VisitSymbol(SymbolRef sym) { + bool VisitSymbol(SymbolRef sym) override { state = state->remove<RegionState>(sym); return true; } @@ -473,6 +493,7 @@ void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const { II_valloc = &Ctx.Idents.get("valloc"); II_strdup = &Ctx.Idents.get("strdup"); II_strndup = &Ctx.Idents.get("strndup"); + II_kmalloc = &Ctx.Idents.get("kmalloc"); } bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const { @@ -499,16 +520,13 @@ bool MallocChecker::isAllocationFunction(const FunctionDecl *FD, if (FunI == II_malloc || FunI == II_realloc || FunI == II_reallocf || FunI == II_calloc || FunI == II_valloc || - FunI == II_strdup || FunI == II_strndup) + FunI == II_strdup || FunI == II_strndup || FunI == II_kmalloc) return true; } - if (Filter.CMallocOptimistic && FD->hasAttrs()) - for (specific_attr_iterator<OwnershipAttr> - i = FD->specific_attr_begin<OwnershipAttr>(), - e = FD->specific_attr_end<OwnershipAttr>(); - i != e; ++i) - if ((*i)->getOwnKind() == OwnershipAttr::Returns) + if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs()) + for (const auto *I : FD->specific_attrs<OwnershipAttr>()) + if (I->getOwnKind() == OwnershipAttr::Returns) return true; return false; } @@ -525,13 +543,10 @@ bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const return true; } - if (Filter.CMallocOptimistic && FD->hasAttrs()) - for (specific_attr_iterator<OwnershipAttr> - i = FD->specific_attr_begin<OwnershipAttr>(), - e = FD->specific_attr_end<OwnershipAttr>(); - i != e; ++i) - if ((*i)->getOwnKind() == OwnershipAttr::Takes || - (*i)->getOwnKind() == OwnershipAttr::Holds) + if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs()) + for (const auto *I : FD->specific_attrs<OwnershipAttr>()) + if (I->getOwnKind() == OwnershipAttr::Takes || + I->getOwnKind() == OwnershipAttr::Holds) return true; return false; } @@ -569,10 +584,88 @@ bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD, return true; } +llvm::Optional<ProgramStateRef> MallocChecker::performKernelMalloc( + const CallExpr *CE, CheckerContext &C, const ProgramStateRef &State) const { + // 3-argument malloc(), as commonly used in {Free,Net,Open}BSD Kernels: + // + // void *malloc(unsigned long size, struct malloc_type *mtp, int flags); + // + // One of the possible flags is M_ZERO, which means 'give me back an + // allocation which is already zeroed', like calloc. + + // 2-argument kmalloc(), as used in the Linux kernel: + // + // void *kmalloc(size_t size, gfp_t flags); + // + // Has the similar flag value __GFP_ZERO. + + // This logic is largely cloned from O_CREAT in UnixAPIChecker, maybe some + // code could be shared. + + ASTContext &Ctx = C.getASTContext(); + llvm::Triple::OSType OS = Ctx.getTargetInfo().getTriple().getOS(); + + if (!KernelZeroFlagVal.hasValue()) { + if (OS == llvm::Triple::FreeBSD) + KernelZeroFlagVal = 0x0100; + else if (OS == llvm::Triple::NetBSD) + KernelZeroFlagVal = 0x0002; + else if (OS == llvm::Triple::OpenBSD) + KernelZeroFlagVal = 0x0008; + else if (OS == llvm::Triple::Linux) + // __GFP_ZERO + KernelZeroFlagVal = 0x8000; + else + // FIXME: We need a more general way of getting the M_ZERO value. + // See also: O_CREAT in UnixAPIChecker.cpp. + + // Fall back to normal malloc behavior on platforms where we don't + // know M_ZERO. + return None; + } + + // We treat the last argument as the flags argument, and callers fall-back to + // normal malloc on a None return. This works for the FreeBSD kernel malloc + // as well as Linux kmalloc. + if (CE->getNumArgs() < 2) + return None; + + const Expr *FlagsEx = CE->getArg(CE->getNumArgs() - 1); + const SVal V = State->getSVal(FlagsEx, C.getLocationContext()); + if (!V.getAs<NonLoc>()) { + // The case where 'V' can be a location can only be due to a bad header, + // so in this case bail out. + return None; + } + + NonLoc Flags = V.castAs<NonLoc>(); + NonLoc ZeroFlag = C.getSValBuilder() + .makeIntVal(KernelZeroFlagVal.getValue(), FlagsEx->getType()) + .castAs<NonLoc>(); + SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And, + Flags, ZeroFlag, + FlagsEx->getType()); + if (MaskedFlagsUC.isUnknownOrUndef()) + return None; + DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>(); + + // Check if maskedFlags is non-zero. + ProgramStateRef TrueState, FalseState; + std::tie(TrueState, FalseState) = State->assume(MaskedFlags); + + // If M_ZERO is set, treat this like calloc (initialized). + if (TrueState && !FalseState) { + SVal ZeroVal = C.getSValBuilder().makeZeroVal(Ctx.CharTy); + return MallocMemAux(C, CE, CE->getArg(0), ZeroVal, TrueState); + } + + return None; +} + void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { if (C.wasInlined) return; - + const FunctionDecl *FD = C.getCalleeDecl(CE); if (!FD) return; @@ -584,7 +677,27 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { initIdentifierInfo(C.getASTContext()); IdentifierInfo *FunI = FD->getIdentifier(); - if (FunI == II_malloc || FunI == II_valloc) { + if (FunI == II_malloc) { + if (CE->getNumArgs() < 1) + return; + if (CE->getNumArgs() < 3) { + State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State); + } else if (CE->getNumArgs() == 3) { + llvm::Optional<ProgramStateRef> MaybeState = + performKernelMalloc(CE, C, State); + if (MaybeState.hasValue()) + State = MaybeState.getValue(); + else + State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State); + } + } else if (FunI == II_kmalloc) { + llvm::Optional<ProgramStateRef> MaybeState = + performKernelMalloc(CE, C, State); + if (MaybeState.hasValue()) + State = MaybeState.getValue(); + else + State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State); + } else if (FunI == II_valloc) { if (CE->getNumArgs() < 1) return; State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State); @@ -620,21 +733,19 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { } } - if (Filter.CMallocOptimistic || Filter.CMismatchedDeallocatorChecker) { + if (ChecksEnabled[CK_MallocOptimistic] || + ChecksEnabled[CK_MismatchedDeallocatorChecker]) { // Check all the attributes, if there are any. // There can be multiple of these attributes. if (FD->hasAttrs()) - for (specific_attr_iterator<OwnershipAttr> - i = FD->specific_attr_begin<OwnershipAttr>(), - e = FD->specific_attr_end<OwnershipAttr>(); - i != e; ++i) { - switch ((*i)->getOwnKind()) { + for (const auto *I : FD->specific_attrs<OwnershipAttr>()) { + switch (I->getOwnKind()) { case OwnershipAttr::Returns: - State = MallocMemReturnsAttr(C, CE, *i); + State = MallocMemReturnsAttr(C, CE, I); break; case OwnershipAttr::Takes: case OwnershipAttr::Holds: - State = FreeMemAttr(C, CE, *i); + State = FreeMemAttr(C, CE, I); break; } } @@ -667,7 +778,7 @@ void MallocChecker::checkPostStmt(const CXXNewExpr *NE, void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const { - if (!Filter.CNewDeleteChecker) + if (!ChecksEnabled[CK_NewDeleteChecker]) if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol()) checkUseAfterFree(Sym, C, DE->getArgument()); @@ -729,11 +840,11 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call, C.addTransition(State); } -ProgramStateRef MallocChecker::MallocMemReturnsAttr(CheckerContext &C, - const CallExpr *CE, - const OwnershipAttr* Att) { - if (Att->getModule() != "malloc") - return 0; +ProgramStateRef +MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, + const OwnershipAttr *Att) const { + if (Att->getModule() != II_malloc) + return nullptr; OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); if (I != E) { @@ -760,7 +871,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, // We expect the malloc functions to return a pointer. if (!RetVal.getAs<Loc>()) - return 0; + return nullptr; // Fill the region with the initialization value. State = State->bindDefault(RetVal, Init); @@ -769,7 +880,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, const SymbolicRegion *R = dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion()); if (!R) - return 0; + return nullptr; if (Optional<DefinedOrUnknownSVal> DefinedSize = Size.getAs<DefinedOrUnknownSVal>()) { SValBuilder &svalBuilder = C.getSValBuilder(); @@ -793,7 +904,7 @@ ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C, // We expect the malloc functions to return a pointer. if (!retVal.getAs<Loc>()) - return 0; + return nullptr; SymbolRef Sym = retVal.getAsLocSymbol(); assert(Sym); @@ -804,16 +915,15 @@ ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C, ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE, - const OwnershipAttr* Att) const { - if (Att->getModule() != "malloc") - return 0; + const OwnershipAttr *Att) const { + if (Att->getModule() != II_malloc) + return nullptr; ProgramStateRef State = C.getState(); bool ReleasedAllocated = false; - for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); - I != E; ++I) { - ProgramStateRef StateI = FreeMemAux(C, CE, State, *I, + for (const auto &Arg : Att->args()) { + ProgramStateRef StateI = FreeMemAux(C, CE, State, Arg, Att->getOwnKind() == OwnershipAttr::Holds, ReleasedAllocated); if (StateI) @@ -830,7 +940,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, bool &ReleasedAllocated, bool ReturnsNullOnFailure) const { if (CE->getNumArgs() < (Num + 1)) - return 0; + return nullptr; return FreeMemAux(C, CE->getArg(Num), CE, state, Hold, ReleasedAllocated, ReturnsNullOnFailure); @@ -909,7 +1019,7 @@ bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C, os << "-"; else os << "+"; - os << Msg->getSelector().getAsString(); + Msg->getSelector().print(os); return true; } @@ -962,23 +1072,23 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, SVal ArgVal = State->getSVal(ArgExpr, C.getLocationContext()); if (!ArgVal.getAs<DefinedOrUnknownSVal>()) - return 0; + return nullptr; DefinedOrUnknownSVal location = ArgVal.castAs<DefinedOrUnknownSVal>(); // Check for null dereferences. if (!location.getAs<Loc>()) - return 0; + return nullptr; // The explicit NULL case, no operation is performed. ProgramStateRef notNullState, nullState; - llvm::tie(notNullState, nullState) = State->assume(location); + std::tie(notNullState, nullState) = State->assume(location); if (nullState && !notNullState) - return 0; + return nullptr; // Unknown values could easily be okay // Undefined values are handled elsewhere if (ArgVal.isUnknownOrUndef()) - return 0; + return nullptr; const MemRegion *R = ArgVal.getAsRegion(); @@ -986,7 +1096,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, // Non-region locations (labels and fixed addresses) also shouldn't be freed. if (!R) { ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr); - return 0; + return nullptr; } R = R->StripCasts(); @@ -994,7 +1104,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, // Blocks might show up as heap data, but should not be free()d if (isa<BlockDataRegion>(R)) { ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr); - return 0; + return nullptr; } const MemSpaceRegion *MS = R->getMemorySpace(); @@ -1011,18 +1121,18 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, // False negatives are better than false positives. ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr); - return 0; + return nullptr; } const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(R->getBaseRegion()); // Various cases could lead to non-symbol values here. // For now, ignore them. if (!SrBase) - return 0; + return nullptr; SymbolRef SymBase = SrBase->getSymbol(); const RefState *RsBase = State->get<RegionState>(SymBase); - SymbolRef PreviousRetStatusSymbol = 0; + SymbolRef PreviousRetStatusSymbol = nullptr; if (RsBase) { @@ -1031,7 +1141,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) { ReportDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(), SymBase, PreviousRetStatusSymbol); - return 0; + return nullptr; // If the pointer is allocated or escaped, but we are now trying to free it, // check that the call to free is proper. @@ -1043,7 +1153,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, if (!DeallocMatchesAlloc) { ReportMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr, RsBase, SymBase, Hold); - return 0; + return nullptr; } // Check if the memory location being freed is the actual location @@ -1055,12 +1165,12 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, const Expr *AllocExpr = cast<Expr>(RsBase->getStmt()); ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, AllocExpr); - return 0; + return nullptr; } } } - ReleasedAllocated = (RsBase != 0) && RsBase->isAllocated(); + ReleasedAllocated = (RsBase != nullptr) && RsBase->isAllocated(); // Clean out the info on previous call to free return info. State = State->remove<FreeReturnValue>(SymBase); @@ -1088,18 +1198,23 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, RefState::getReleased(Family, ParentExpr)); } -bool MallocChecker::isTrackedByCurrentChecker(AllocationFamily Family) const { +Optional<MallocChecker::CheckKind> +MallocChecker::getCheckIfTracked(AllocationFamily Family) const { switch (Family) { case AF_Malloc: { - if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic) - return false; - return true; + if (ChecksEnabled[CK_MallocOptimistic]) { + return CK_MallocOptimistic; + } else if (ChecksEnabled[CK_MallocPessimistic]) { + return CK_MallocPessimistic; + } + return Optional<MallocChecker::CheckKind>(); } case AF_CXXNew: case AF_CXXNewArray: { - if (!Filter.CNewDeleteChecker) - return false; - return true; + if (ChecksEnabled[CK_NewDeleteChecker]) { + return CK_NewDeleteChecker; + } + return Optional<MallocChecker::CheckKind>(); } case AF_None: { llvm_unreachable("no family"); @@ -1108,18 +1223,18 @@ bool MallocChecker::isTrackedByCurrentChecker(AllocationFamily Family) const { llvm_unreachable("unhandled family"); } -bool -MallocChecker::isTrackedByCurrentChecker(CheckerContext &C, - const Stmt *AllocDeallocStmt) const { - return isTrackedByCurrentChecker(getAllocationFamily(C, AllocDeallocStmt)); +Optional<MallocChecker::CheckKind> +MallocChecker::getCheckIfTracked(CheckerContext &C, + const Stmt *AllocDeallocStmt) const { + return getCheckIfTracked(getAllocationFamily(C, AllocDeallocStmt)); } -bool MallocChecker::isTrackedByCurrentChecker(CheckerContext &C, - SymbolRef Sym) const { +Optional<MallocChecker::CheckKind> +MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym) const { const RefState *RS = C.getState()->get<RegionState>(Sym); assert(RS); - return isTrackedByCurrentChecker(RS->getAllocationFamily()); + return getCheckIfTracked(RS->getAllocationFamily()); } bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) { @@ -1162,8 +1277,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os, if (VR) VD = VR->getDecl(); else - VD = NULL; - + VD = nullptr; + if (VD) os << "the address of the local variable '" << VD->getName() << "'"; else @@ -1177,8 +1292,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os, if (VR) VD = VR->getDecl(); else - VD = NULL; - + VD = nullptr; + if (VD) os << "the address of the parameter '" << VD->getName() << "'"; else @@ -1192,8 +1307,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os, if (VR) VD = VR->getDecl(); else - VD = NULL; - + VD = nullptr; + if (VD) { if (VD->isStaticLocal()) os << "the address of the static variable '" << VD->getName() << "'"; @@ -1213,17 +1328,21 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange Range, const Expr *DeallocExpr) const { - if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic && - !Filter.CNewDeleteChecker) + if (!ChecksEnabled[CK_MallocOptimistic] && + !ChecksEnabled[CK_MallocPessimistic] && + !ChecksEnabled[CK_NewDeleteChecker]) return; - if (!isTrackedByCurrentChecker(C, DeallocExpr)) + Optional<MallocChecker::CheckKind> CheckKind = + getCheckIfTracked(C, DeallocExpr); + if (!CheckKind.hasValue()) return; if (ExplodedNode *N = C.generateSink()) { - if (!BT_BadFree) - BT_BadFree.reset(new BugType("Bad free", "Memory Error")); - + if (!BT_BadFree[*CheckKind]) + BT_BadFree[*CheckKind].reset( + new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error")); + SmallString<100> buf; llvm::raw_svector_ostream os(buf); @@ -1249,7 +1368,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, printExpectedAllocName(os, C, DeallocExpr); } - BugReport *R = new BugReport(*BT_BadFree, os.str(), N); + BugReport *R = new BugReport(*BT_BadFree[*CheckKind], os.str(), N); R->markInteresting(MR); R->addRange(Range); C.emitReport(R); @@ -1263,14 +1382,15 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C, SymbolRef Sym, bool OwnershipTransferred) const { - if (!Filter.CMismatchedDeallocatorChecker) + if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) return; if (ExplodedNode *N = C.generateSink()) { if (!BT_MismatchedDealloc) - BT_MismatchedDealloc.reset(new BugType("Bad deallocator", - "Memory Error")); - + BT_MismatchedDealloc.reset( + new BugType(CheckNames[CK_MismatchedDeallocatorChecker], + "Bad deallocator", "Memory Error")); + SmallString<100> buf; llvm::raw_svector_ostream os(buf); @@ -1314,19 +1434,23 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range, const Expr *DeallocExpr, const Expr *AllocExpr) const { - if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic && - !Filter.CNewDeleteChecker) + if (!ChecksEnabled[CK_MallocOptimistic] && + !ChecksEnabled[CK_MallocPessimistic] && + !ChecksEnabled[CK_NewDeleteChecker]) return; - if (!isTrackedByCurrentChecker(C, AllocExpr)) + Optional<MallocChecker::CheckKind> CheckKind = + getCheckIfTracked(C, AllocExpr); + if (!CheckKind.hasValue()) return; ExplodedNode *N = C.generateSink(); - if (N == NULL) + if (!N) return; - if (!BT_OffsetFree) - BT_OffsetFree.reset(new BugType("Offset free", "Memory Error")); + if (!BT_OffsetFree[*CheckKind]) + BT_OffsetFree[*CheckKind].reset( + new BugType(CheckNames[*CheckKind], "Offset free", "Memory Error")); SmallString<100> buf; llvm::raw_svector_ostream os(buf); @@ -1357,7 +1481,7 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal, else os << "allocated memory"; - BugReport *R = new BugReport(*BT_OffsetFree, os.str(), N); + BugReport *R = new BugReport(*BT_OffsetFree[*CheckKind], os.str(), N); R->markInteresting(MR->getBaseRegion()); R->addRange(Range); C.emitReport(R); @@ -1366,18 +1490,21 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal, void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range, SymbolRef Sym) const { - if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic && - !Filter.CNewDeleteChecker) + if (!ChecksEnabled[CK_MallocOptimistic] && + !ChecksEnabled[CK_MallocPessimistic] && + !ChecksEnabled[CK_NewDeleteChecker]) return; - if (!isTrackedByCurrentChecker(C, Sym)) + Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym); + if (!CheckKind.hasValue()) return; if (ExplodedNode *N = C.generateSink()) { - if (!BT_UseFree) - BT_UseFree.reset(new BugType("Use-after-free", "Memory Error")); + if (!BT_UseFree[*CheckKind]) + BT_UseFree[*CheckKind].reset(new BugType( + CheckNames[*CheckKind], "Use-after-free", "Memory Error")); - BugReport *R = new BugReport(*BT_UseFree, + BugReport *R = new BugReport(*BT_UseFree[*CheckKind], "Use of memory after it is freed", N); R->markInteresting(Sym); @@ -1391,21 +1518,25 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range, bool Released, SymbolRef Sym, SymbolRef PrevSym) const { - if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic && - !Filter.CNewDeleteChecker) + if (!ChecksEnabled[CK_MallocOptimistic] && + !ChecksEnabled[CK_MallocPessimistic] && + !ChecksEnabled[CK_NewDeleteChecker]) return; - if (!isTrackedByCurrentChecker(C, Sym)) + Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym); + if (!CheckKind.hasValue()) return; if (ExplodedNode *N = C.generateSink()) { - if (!BT_DoubleFree) - BT_DoubleFree.reset(new BugType("Double free", "Memory Error")); - - BugReport *R = new BugReport(*BT_DoubleFree, - (Released ? "Attempt to free released memory" - : "Attempt to free non-owned memory"), - N); + if (!BT_DoubleFree[*CheckKind]) + BT_DoubleFree[*CheckKind].reset( + new BugType(CheckNames[*CheckKind], "Double free", "Memory Error")); + + BugReport *R = + new BugReport(*BT_DoubleFree[*CheckKind], + (Released ? "Attempt to free released memory" + : "Attempt to free non-owned memory"), + N); R->addRange(Range); R->markInteresting(Sym); if (PrevSym) @@ -1415,18 +1546,42 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range, } } +void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const { + + if (!ChecksEnabled[CK_NewDeleteChecker]) + return; + + Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym); + if (!CheckKind.hasValue()) + return; + assert(*CheckKind == CK_NewDeleteChecker && "invalid check kind"); + + if (ExplodedNode *N = C.generateSink()) { + if (!BT_DoubleDelete) + BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker], + "Double delete", "Memory Error")); + + BugReport *R = new BugReport(*BT_DoubleDelete, + "Attempt to delete released memory", N); + + R->markInteresting(Sym); + R->addVisitor(new MallocBugVisitor(Sym)); + C.emitReport(R); + } +} + ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE, bool FreesOnFail) const { if (CE->getNumArgs() < 2) - return 0; + return nullptr; ProgramStateRef state = C.getState(); const Expr *arg0Expr = CE->getArg(0); const LocationContext *LCtx = C.getLocationContext(); SVal Arg0Val = state->getSVal(arg0Expr, LCtx); if (!Arg0Val.getAs<DefinedOrUnknownSVal>()) - return 0; + return nullptr; DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>(); SValBuilder &svalBuilder = C.getSValBuilder(); @@ -1437,12 +1592,12 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C, // Get the size argument. If there is no size arg then give up. const Expr *Arg1 = CE->getArg(1); if (!Arg1) - return 0; + return nullptr; // Get the value of the size argument. SVal Arg1ValG = state->getSVal(Arg1, LCtx); if (!Arg1ValG.getAs<DefinedOrUnknownSVal>()) - return 0; + return nullptr; DefinedOrUnknownSVal Arg1Val = Arg1ValG.castAs<DefinedOrUnknownSVal>(); // Compare the size argument to 0. @@ -1451,9 +1606,9 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C, svalBuilder.makeIntValWithPtrWidth(0, false)); ProgramStateRef StatePtrIsNull, StatePtrNotNull; - llvm::tie(StatePtrIsNull, StatePtrNotNull) = state->assume(PtrEQ); + std::tie(StatePtrIsNull, StatePtrNotNull) = state->assume(PtrEQ); ProgramStateRef StateSizeIsZero, StateSizeNotZero; - llvm::tie(StateSizeIsZero, StateSizeNotZero) = state->assume(SizeZero); + std::tie(StateSizeIsZero, StateSizeNotZero) = state->assume(SizeZero); // We only assume exceptional states if they are definitely true; if the // state is under-constrained, assume regular realloc behavior. bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull; @@ -1468,7 +1623,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C, } if (PrtIsNull && SizeIsZero) - return 0; + return nullptr; // Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size). assert(!PrtIsNull); @@ -1476,7 +1631,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C, SVal RetVal = state->getSVal(CE, LCtx); SymbolRef ToPtr = RetVal.getAsSymbol(); if (!FromPtr || !ToPtr) - return 0; + return nullptr; bool ReleasedAllocated = false; @@ -1498,7 +1653,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C, ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1), UnknownVal(), stateFree); if (!stateRealloc) - return 0; + return nullptr; ReallocPairKind Kind = RPToBeFreedAfterFailure; if (FreesOnFail) @@ -1514,12 +1669,12 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C, C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr); return stateRealloc; } - return 0; + return nullptr; } ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE){ if (CE->getNumArgs() < 2) - return 0; + return nullptr; ProgramStateRef state = C.getState(); SValBuilder &svalBuilder = C.getSValBuilder(); @@ -1540,7 +1695,7 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym, // Walk the ExplodedGraph backwards and find the first node that referred to // the tracked symbol. const ExplodedNode *AllocNode = N; - const MemRegion *ReferenceRegion = 0; + const MemRegion *ReferenceRegion = nullptr; while (N) { ProgramStateRef State = N->getState(); @@ -1567,7 +1722,7 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym, // symbol was tracked. if (N->getLocationContext() == LeakContext) AllocNode = N; - N = N->pred_empty() ? NULL : *(N->pred_begin()); + N = N->pred_empty() ? nullptr : *(N->pred_begin()); } return LeakInfo(AllocNode, ReferenceRegion); @@ -1576,43 +1731,46 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym, void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const { - if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic && - !Filter.CNewDeleteLeaksChecker) + if (!ChecksEnabled[CK_MallocOptimistic] && + !ChecksEnabled[CK_MallocPessimistic] && + !ChecksEnabled[CK_NewDeleteLeaksChecker]) return; const RefState *RS = C.getState()->get<RegionState>(Sym); assert(RS && "cannot leak an untracked symbol"); AllocationFamily Family = RS->getAllocationFamily(); - if (!isTrackedByCurrentChecker(Family)) + Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family); + if (!CheckKind.hasValue()) return; // Special case for new and new[]; these are controlled by a separate checker // flag so that they can be selectively disabled. if (Family == AF_CXXNew || Family == AF_CXXNewArray) - if (!Filter.CNewDeleteLeaksChecker) + if (!ChecksEnabled[CK_NewDeleteLeaksChecker]) return; assert(N); - if (!BT_Leak) { - BT_Leak.reset(new BugType("Memory leak", "Memory Error")); + if (!BT_Leak[*CheckKind]) { + BT_Leak[*CheckKind].reset( + new BugType(CheckNames[*CheckKind], "Memory leak", "Memory Error")); // Leaks should not be reported if they are post-dominated by a sink: // (1) Sinks are higher importance bugs. // (2) NoReturnFunctionChecker uses sink nodes to represent paths ending // with __noreturn functions such as assert() or exit(). We choose not // to report leaks on such paths. - BT_Leak->setSuppressOnSink(true); + BT_Leak[*CheckKind]->setSuppressOnSink(true); } // Most bug reports are cached at the location where they occurred. // With leaks, we want to unique them by the location where they were // allocated, and only report a single path. PathDiagnosticLocation LocUsedForUniqueing; - const ExplodedNode *AllocNode = 0; - const MemRegion *Region = 0; - llvm::tie(AllocNode, Region) = getAllocationSite(N, Sym, C); + const ExplodedNode *AllocNode = nullptr; + const MemRegion *Region = nullptr; + std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C); ProgramPoint P = AllocNode->getLocation(); - const Stmt *AllocationStmt = 0; + const Stmt *AllocationStmt = nullptr; if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>()) AllocationStmt = Exit->getCalleeContext()->getCallSite(); else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) @@ -1631,9 +1789,9 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, os << "Potential memory leak"; } - BugReport *R = new BugReport(*BT_Leak, os.str(), N, - LocUsedForUniqueing, - AllocNode->getLocationContext()->getDecl()); + BugReport *R = + new BugReport(*BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing, + AllocNode->getLocationContext()->getDecl()); R->markInteresting(Sym); R->addVisitor(new MallocBugVisitor(Sym, true)); C.emitReport(R); @@ -1681,7 +1839,7 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, // Generate leak node. ExplodedNode *N = C.getPredecessor(); if (!Errors.empty()) { - static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak"); + static CheckerProgramPointTag Tag("MallocChecker", "DeadSymbolsLeak"); N = C.addTransition(C.getState(), C.getPredecessor(), &Tag); for (SmallVectorImpl<SymbolRef>::iterator I = Errors.begin(), E = Errors.end(); I != E; ++I) { @@ -1695,17 +1853,24 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, void MallocChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { + if (const CXXDestructorCall *DC = dyn_cast<CXXDestructorCall>(&Call)) { + SymbolRef Sym = DC->getCXXThisVal().getAsSymbol(); + if (!Sym || checkDoubleDelete(Sym, C)) + return; + } + // We will check for double free in the post visit. if (const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&Call)) { const FunctionDecl *FD = FC->getDecl(); if (!FD) return; - if ((Filter.CMallocOptimistic || Filter.CMallocPessimistic) && + if ((ChecksEnabled[CK_MallocOptimistic] || + ChecksEnabled[CK_MallocPessimistic]) && isFreeFunction(FD, C.getASTContext())) return; - if (Filter.CNewDeleteChecker && + if (ChecksEnabled[CK_NewDeleteChecker] && isStandardNewDelete(FD, C.getASTContext())) return; } @@ -1803,8 +1968,7 @@ bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const { bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const { - // FIXME: Handle destructor called from delete more precisely. - if (isReleased(Sym, C) && S) { + if (isReleased(Sym, C)) { ReportUseAfterFree(C, S->getSourceRange(), Sym); return true; } @@ -1812,6 +1976,15 @@ bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C, return false; } +bool MallocChecker::checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const { + + if (isReleased(Sym, C)) { + ReportDoubleDelete(C, Sym); + return true; + } + return false; +} + // Check if the location is a freed symbolic region. void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S, CheckerContext &C) const { @@ -1867,13 +2040,13 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( ProgramStateRef State, SymbolRef &EscapingSymbol) const { assert(Call); - EscapingSymbol = 0; - - // For now, assume that any C++ call can free memory. + EscapingSymbol = nullptr; + + // For now, assume that any C++ or block call can free memory. // TODO: If we want to be more optimistic here, we'll need to make sure that // regions escape to C++ containers. They seem to do that even now, but for // mysterious reasons. - if (!(isa<FunctionCall>(Call) || isa<ObjCMethodCall>(Call))) + if (!(isa<SimpleFunctionCall>(Call) || isa<ObjCMethodCall>(Call))) return true; // Check Objective-C messages by selector name. @@ -1909,7 +2082,8 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( // that the pointers get freed by following the container itself. if (FirstSlot.startswith("addPointer") || FirstSlot.startswith("insertPointer") || - FirstSlot.startswith("replacePointer")) { + FirstSlot.startswith("replacePointer") || + FirstSlot.equals("valueWithPointer")) { return true; } @@ -1927,7 +2101,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( } // At this point the only thing left to handle is straight function calls. - const FunctionDecl *FD = cast<FunctionCall>(Call)->getDecl(); + const FunctionDecl *FD = cast<SimpleFunctionCall>(Call)->getDecl(); if (!FD) return true; @@ -2043,7 +2217,7 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State, bool(*CheckRefState)(const RefState*)) const { // If we know that the call does not free memory, or we want to process the // call later, keep tracking the top level arguments. - SymbolRef EscapingSymbol = 0; + SymbolRef EscapingSymbol = nullptr; if (Kind == PSK_DirectEscapeOnCall && !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State, EscapingSymbol) && @@ -2081,7 +2255,7 @@ static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, return sym; } - return NULL; + return nullptr; } PathDiagnosticPiece * @@ -2095,11 +2269,11 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, const RefState *RS = state->get<RegionState>(Sym); const RefState *RSPrev = statePrev->get<RegionState>(Sym); if (!RS) - return 0; + return nullptr; - const Stmt *S = 0; - const char *Msg = 0; - StackHintGeneratorForSymbol *StackHint = 0; + const Stmt *S = nullptr; + const char *Msg = nullptr; + StackHintGeneratorForSymbol *StackHint = nullptr; // Retrieve the associated statement. ProgramPoint ProgLoc = N->getLocation(); @@ -2114,7 +2288,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, } if (!S) - return 0; + return nullptr; // FIXME: We will eventually need to handle non-statement-based events // (__attribute__((cleanup))). @@ -2130,7 +2304,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, StackHint = new StackHintGeneratorForSymbol(Sym, "Returning; memory was released"); } else if (isRelinquished(RS, RSPrev, S)) { - Msg = "Memory ownership is transfered"; + Msg = "Memory ownership is transferred"; StackHint = new StackHintGeneratorForSymbol(Sym, ""); } else if (isReallocFailedCheck(RS, RSPrev, S)) { Mode = ReallocationFailed; @@ -2157,13 +2331,13 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, Msg = "Attempt to reallocate memory"; StackHint = new StackHintGeneratorForSymbol(Sym, "Returned reallocated memory"); - FailedReallocSymbol = NULL; + FailedReallocSymbol = nullptr; Mode = Normal; } } if (!Msg) - return 0; + return nullptr; assert(StackHint); // Generate the extra diagnostic. @@ -2178,11 +2352,17 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State, RegionStateTy RS = State->get<RegionState>(); if (!RS.isEmpty()) { - Out << Sep << "MallocChecker:" << NL; + Out << Sep << "MallocChecker :" << NL; for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) { + const RefState *RefS = State->get<RegionState>(I.getKey()); + AllocationFamily Family = RefS->getAllocationFamily(); + Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family); + I.getKey()->dumpToStream(Out); Out << " : "; I.getData().dump(Out); + if (CheckKind.hasValue()) + Out << " (" << CheckNames[*CheckKind].getName() << ")"; Out << NL; } } @@ -2190,17 +2370,23 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State, void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) { registerCStringCheckerBasic(mgr); - mgr.registerChecker<MallocChecker>()->Filter.CNewDeleteLeaksChecker = true; + MallocChecker *checker = mgr.registerChecker<MallocChecker>(); + checker->ChecksEnabled[MallocChecker::CK_NewDeleteLeaksChecker] = true; + checker->CheckNames[MallocChecker::CK_NewDeleteLeaksChecker] = + mgr.getCurrentCheckName(); // We currently treat NewDeleteLeaks checker as a subchecker of NewDelete // checker. - mgr.registerChecker<MallocChecker>()->Filter.CNewDeleteChecker = true; + if (!checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker]) + checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker] = true; } -#define REGISTER_CHECKER(name) \ -void ento::register##name(CheckerManager &mgr) {\ - registerCStringCheckerBasic(mgr); \ - mgr.registerChecker<MallocChecker>()->Filter.C##name = true;\ -} +#define REGISTER_CHECKER(name) \ + void ento::register##name(CheckerManager &mgr) { \ + registerCStringCheckerBasic(mgr); \ + MallocChecker *checker = mgr.registerChecker<MallocChecker>(); \ + checker->ChecksEnabled[MallocChecker::CK_##name] = true; \ + checker->CheckNames[MallocChecker::CK_##name] = mgr.getCurrentCheckName(); \ + } REGISTER_CHECKER(MallocPessimistic) REGISTER_CHECKER(MallocOptimistic) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp index 0cdf911..f38ce77 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp @@ -65,7 +65,7 @@ void MallocOverflowSecurityChecker::CheckMallocArgument( conditional expression, an operation that could reduce the range of the result, or anything too complicated :-). */ const Expr * e = TheArgument; - const BinaryOperator * mulop = NULL; + const BinaryOperator * mulop = nullptr; for (;;) { e = e->IgnoreParenImpCasts(); @@ -73,7 +73,7 @@ void MallocOverflowSecurityChecker::CheckMallocArgument( const BinaryOperator * binop = dyn_cast<BinaryOperator>(e); BinaryOperatorKind opc = binop->getOpcode(); // TODO: ignore multiplications by 1, reject if multiplied by 0. - if (mulop == NULL && opc == BO_Mul) + if (mulop == nullptr && opc == BO_Mul) mulop = binop; if (opc != BO_Mul && opc != BO_Add && opc != BO_Sub && opc != BO_Shl) return; @@ -94,7 +94,7 @@ void MallocOverflowSecurityChecker::CheckMallocArgument( return; } - if (mulop == NULL) + if (mulop == nullptr) return; // We've found the right structure of malloc argument, now save @@ -213,11 +213,12 @@ void MallocOverflowSecurityChecker::OutputPossibleOverflows( e = PossibleMallocOverflows.end(); i != e; ++i) { - BR.EmitBasicReport(D, "malloc() size overflow", categories::UnixAPI, - "the computation of the size of the memory allocation may overflow", - PathDiagnosticLocation::createOperatorLoc(i->mulop, - BR.getSourceManager()), - i->mulop->getSourceRange()); + BR.EmitBasicReport( + D, this, "malloc() size overflow", categories::UnixAPI, + "the computation of the size of the memory allocation may overflow", + PathDiagnosticLocation::createOperatorLoc(i->mulop, + BR.getSourceManager()), + i->mulop->getSourceRange()); } } @@ -262,6 +263,7 @@ void MallocOverflowSecurityChecker::checkASTCodeBody(const Decl *D, OutputPossibleOverflows(PossibleMallocOverflows, D, BR, mgr); } -void ento::registerMallocOverflowSecurityChecker(CheckerManager &mgr) { +void +ento::registerMallocOverflowSecurityChecker(CheckerManager &mgr) { mgr.registerChecker<MallocOverflowSecurityChecker>(); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp index 6c776eb..4a50d93 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp @@ -95,15 +95,14 @@ public: if (FD) { IdentifierInfo *II = FD->getIdentifier(); if (II == II_malloc || II == II_calloc || II == II_realloc) - return TypeCallPair((const TypeSourceInfo *)0, E); + return TypeCallPair((const TypeSourceInfo *)nullptr, E); } return TypeCallPair(); } TypeCallPair VisitDeclStmt(const DeclStmt *S) { - for (DeclStmt::const_decl_iterator I = S->decl_begin(), E = S->decl_end(); - I!=E; ++I) - if (const VarDecl *VD = dyn_cast<VarDecl>(*I)) + for (const auto *I : S->decls()) + if (const VarDecl *VD = dyn_cast<VarDecl>(I)) if (const Expr *Init = VD->getInit()) VisitChild(VD, Init); return TypeCallPair(); @@ -206,7 +205,7 @@ public: if (compatibleWithArrayType(BR.getContext(), PointeeType, SizeofType)) continue; - const TypeSourceInfo *TSI = 0; + const TypeSourceInfo *TSI = nullptr; if (i->CastedExprParent.is<const VarDecl *>()) { TSI = i->CastedExprParent.get<const VarDecl *>()->getTypeSourceInfo(); @@ -236,10 +235,8 @@ public: PathDiagnosticLocation::createBegin(i->AllocCall->getCallee(), BR.getSourceManager(), ADC); - BR.EmitBasicReport(D, "Allocator sizeof operand mismatch", - categories::UnixAPI, - OS.str(), - L, Ranges); + BR.EmitBasicReport(D, this, "Allocator sizeof operand mismatch", + categories::UnixAPI, OS.str(), L, Ranges); } } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp index fc28e1f..b180c03 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp @@ -32,7 +32,7 @@ using namespace ento; namespace { class NSAutoreleasePoolChecker : public Checker<check::PreObjCMessage> { - mutable OwningPtr<BugType> BT; + mutable std::unique_ptr<BugType> BT; mutable Selector releaseS; public: @@ -59,7 +59,7 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg, return; if (!BT) - BT.reset(new BugType("Use -drain instead of -release", + BT.reset(new BugType(this, "Use -drain instead of -release", "API Upgrade (Apple)")); ExplodedNode *N = C.addTransition(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index 9f01522..2be7f1d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -42,7 +42,7 @@ class NSErrorMethodChecker mutable IdentifierInfo *II; public: - NSErrorMethodChecker() : II(0) { } + NSErrorMethodChecker() : II(nullptr) {} void checkASTDecl(const ObjCMethodDecl *D, AnalysisManager &mgr, BugReporter &BR) const; @@ -54,16 +54,15 @@ void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D, BugReporter &BR) const { if (!D->isThisDeclarationADefinition()) return; - if (!D->getResultType()->isVoidType()) + if (!D->getReturnType()->isVoidType()) return; if (!II) II = &D->getASTContext().Idents.get("NSError"); bool hasNSError = false; - for (ObjCMethodDecl::param_const_iterator - I = D->param_begin(), E = D->param_end(); I != E; ++I) { - if (IsNSError((*I)->getType(), II)) { + for (const auto *I : D->params()) { + if (IsNSError(I->getType(), II)) { hasNSError = true; break; } @@ -75,7 +74,7 @@ void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D, "error occurred"; PathDiagnosticLocation L = PathDiagnosticLocation::create(D, BR.getSourceManager()); - BR.EmitBasicReport(D, "Bad return type when passing NSError**", + BR.EmitBasicReport(D, this, "Bad return type when passing NSError**", "Coding conventions (Apple)", err, L); } } @@ -90,7 +89,7 @@ class CFErrorFunctionChecker mutable IdentifierInfo *II; public: - CFErrorFunctionChecker() : II(0) { } + CFErrorFunctionChecker() : II(nullptr) {} void checkASTDecl(const FunctionDecl *D, AnalysisManager &mgr, BugReporter &BR) const; @@ -102,16 +101,15 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D, BugReporter &BR) const { if (!D->doesThisDeclarationHaveABody()) return; - if (!D->getResultType()->isVoidType()) + if (!D->getReturnType()->isVoidType()) return; if (!II) II = &D->getASTContext().Idents.get("CFErrorRef"); bool hasCFError = false; - for (FunctionDecl::param_const_iterator - I = D->param_begin(), E = D->param_end(); I != E; ++I) { - if (IsCFError((*I)->getType(), II)) { + for (auto I : D->params()) { + if (IsCFError(I->getType(), II)) { hasCFError = true; break; } @@ -123,7 +121,7 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D, "error occurred"; PathDiagnosticLocation L = PathDiagnosticLocation::create(D, BR.getSourceManager()); - BR.EmitBasicReport(D, "Bad return type when passing CFErrorRef*", + BR.EmitBasicReport(D, this, "Bad return type when passing CFErrorRef*", "Coding conventions (Apple)", err, L); } } @@ -136,14 +134,16 @@ namespace { class NSErrorDerefBug : public BugType { public: - NSErrorDerefBug() : BugType("NSError** null dereference", - "Coding conventions (Apple)") {} + NSErrorDerefBug(const CheckerBase *Checker) + : BugType(Checker, "NSError** null dereference", + "Coding conventions (Apple)") {} }; class CFErrorDerefBug : public BugType { public: - CFErrorDerefBug() : BugType("CFErrorRef* null dereference", - "Coding conventions (Apple)") {} + CFErrorDerefBug(const CheckerBase *Checker) + : BugType(Checker, "CFErrorRef* null dereference", + "Coding conventions (Apple)") {} }; } @@ -153,9 +153,11 @@ class NSOrCFErrorDerefChecker : public Checker< check::Location, check::Event<ImplicitNullDerefEvent> > { mutable IdentifierInfo *NSErrorII, *CFErrorII; + mutable std::unique_ptr<NSErrorDerefBug> NSBT; + mutable std::unique_ptr<CFErrorDerefBug> CFBT; public: bool ShouldCheckNSError, ShouldCheckCFError; - NSOrCFErrorDerefChecker() : NSErrorII(0), CFErrorII(0), + NSOrCFErrorDerefChecker() : NSErrorII(nullptr), CFErrorII(nullptr), ShouldCheckNSError(0), ShouldCheckCFError(0) { } void checkLocation(SVal loc, bool isLoad, const Stmt *S, @@ -262,13 +264,18 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const { os << " may be null"; - BugType *bug = 0; - if (isNSError) - bug = new NSErrorDerefBug(); - else - bug = new CFErrorDerefBug(); - BugReport *report = new BugReport(*bug, os.str(), - event.SinkNode); + BugType *bug = nullptr; + if (isNSError) { + if (!NSBT) + NSBT.reset(new NSErrorDerefBug(this)); + bug = NSBT.get(); + } + else { + if (!CFBT) + CFBT.reset(new CFErrorDerefBug(this)); + bug = CFBT.get(); + } + BugReport *report = new BugReport(*bug, os.str(), event.SinkNode); BR.emitReport(report); } @@ -305,14 +312,14 @@ static bool IsCFError(QualType T, IdentifierInfo *II) { void ento::registerNSErrorChecker(CheckerManager &mgr) { mgr.registerChecker<NSErrorMethodChecker>(); - NSOrCFErrorDerefChecker * - checker = mgr.registerChecker<NSOrCFErrorDerefChecker>(); + NSOrCFErrorDerefChecker *checker = + mgr.registerChecker<NSOrCFErrorDerefChecker>(); checker->ShouldCheckNSError = true; } void ento::registerCFErrorChecker(CheckerManager &mgr) { mgr.registerChecker<CFErrorFunctionChecker>(); - NSOrCFErrorDerefChecker * - checker = mgr.registerChecker<NSOrCFErrorDerefChecker>(); + NSOrCFErrorDerefChecker *checker = + mgr.registerChecker<NSOrCFErrorDerefChecker>(); checker->ShouldCheckCFError = true; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp index 0e1064e..ba82d1d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" +#include "SelectorExtras.h" #include "clang/AST/Attr.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" @@ -28,6 +29,8 @@ namespace { class NoReturnFunctionChecker : public Checker< check::PostCall, check::PostObjCMessage > { + mutable Selector HandleFailureInFunctionSel; + mutable Selector HandleFailureInMethodSel; public: void checkPostCall(const CallEvent &CE, CheckerContext &C) const; void checkPostObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const; @@ -37,11 +40,10 @@ public: void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE, CheckerContext &C) const { - ProgramStateRef state = C.getState(); bool BuildSinks = false; if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE.getDecl())) - BuildSinks = FD->getAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn(); + BuildSinks = FD->hasAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn(); const Expr *Callee = CE.getOriginExpr(); if (!BuildSinks && Callee) @@ -82,24 +84,6 @@ void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE, C.generateSink(); } -static bool END_WITH_NULL isMultiArgSelector(const Selector *Sel, ...) { - va_list argp; - va_start(argp, Sel); - - unsigned Slot = 0; - const char *Arg; - while ((Arg = va_arg(argp, const char *))) { - if (!Sel->getNameForSlot(Slot).equals(Arg)) - break; // still need to va_end! - ++Slot; - } - - va_end(argp); - - // We only succeeded if we made it to the end of the argument list. - return (Arg == NULL); -} - void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg, CheckerContext &C) const { // Check if the method is annotated with analyzer_noreturn. @@ -136,13 +120,17 @@ void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg, default: return; case 4: - if (!isMultiArgSelector(&Sel, "handleFailureInFunction", "file", - "lineNumber", "description", NULL)) + lazyInitKeywordSelector(HandleFailureInFunctionSel, C.getASTContext(), + "handleFailureInFunction", "file", "lineNumber", + "description", nullptr); + if (Sel != HandleFailureInFunctionSel) return; break; case 5: - if (!isMultiArgSelector(&Sel, "handleFailureInMethod", "object", "file", - "lineNumber", "description", NULL)) + lazyInitKeywordSelector(HandleFailureInMethodSel, C.getASTContext(), + "handleFailureInMethod", "object", "file", + "lineNumber", "description", nullptr); + if (Sel != HandleFailureInMethodSel) return; break; } @@ -151,7 +139,6 @@ void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg, C.generateSink(); } - void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) { mgr.registerChecker<NoReturnFunctionChecker>(); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp index 273a7a3..61d2b87 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp @@ -29,8 +29,9 @@ using namespace ento; namespace { class NonNullParamChecker : public Checker< check::PreCall > { - mutable OwningPtr<BugType> BTAttrNonNull; - mutable OwningPtr<BugType> BTNullRefArg; + mutable std::unique_ptr<BugType> BTAttrNonNull; + mutable std::unique_ptr<BugType> BTNullRefArg; + public: void checkPreCall(const CallEvent &Call, CheckerContext &C) const; @@ -43,7 +44,7 @@ public: } // end anonymous namespace void NonNullParamChecker::checkPreCall(const CallEvent &Call, - CheckerContext &C) const { + CheckerContext &C) const { const Decl *FD = Call.getDecl(); if (!FD) return; @@ -66,6 +67,12 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call, } bool haveAttrNonNull = Att && Att->isNonNull(idx); + if (!haveAttrNonNull) { + // Check if the parameter is also marked 'nonnull'. + ArrayRef<ParmVarDecl*> parms = Call.parameters(); + if (idx < parms.size()) + haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>(); + } if (!haveRefTypeParam && !haveAttrNonNull) continue; @@ -98,7 +105,9 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call, V = *CSV_I; DV = V.getAs<DefinedSVal>(); assert(++CSV_I == CSV->end()); - if (!DV) + // FIXME: Handle (some_union){ some_other_union_val }, which turns into + // a LazyCompoundVal inside a CompoundVal. + if (!V.getAs<Loc>()) continue; // Retrieve the corresponding expression. if (const CompoundLiteralExpr *CE = dyn_cast<CompoundLiteralExpr>(ArgE)) @@ -114,14 +123,14 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call, ConstraintManager &CM = C.getConstraintManager(); ProgramStateRef stateNotNull, stateNull; - llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); + std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); if (stateNull && !stateNotNull) { // Generate an error node. Check for a null node in case // we cache out. if (ExplodedNode *errorNode = C.generateSink(stateNull)) { - BugReport *R = 0; + BugReport *R = nullptr; if (haveAttrNonNull) R = genReportNullAttrNonNull(errorNode, ArgE); else if (haveRefTypeParam) @@ -156,8 +165,7 @@ BugReport *NonNullParamChecker::genReportNullAttrNonNull( // the BugReport is passed to 'EmitWarning'. if (!BTAttrNonNull) BTAttrNonNull.reset(new BugType( - "Argument with 'nonnull' attribute passed null", - "API")); + this, "Argument with 'nonnull' attribute passed null", "API")); BugReport *R = new BugReport(*BTAttrNonNull, "Null pointer passed as an argument to a 'nonnull' parameter", @@ -171,14 +179,14 @@ BugReport *NonNullParamChecker::genReportNullAttrNonNull( BugReport *NonNullParamChecker::genReportReferenceToNullPointer( const ExplodedNode *ErrorNode, const Expr *ArgE) const { if (!BTNullRefArg) - BTNullRefArg.reset(new BuiltinBug("Dereference of null pointer")); + BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer")); BugReport *R = new BugReport(*BTNullRefArg, "Forming reference to null pointer", ErrorNode); if (ArgE) { const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE); - if (ArgEDeref == 0) + if (!ArgEDeref) ArgEDeref = ArgE; bugreporter::trackNullOrUndefValue(ErrorNode, ArgEDeref, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp index 4018a66..fbf2d73 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp @@ -26,8 +26,8 @@ using namespace ento; namespace { class ObjCAtSyncChecker : public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > { - mutable OwningPtr<BuiltinBug> BT_null; - mutable OwningPtr<BuiltinBug> BT_undef; + mutable std::unique_ptr<BuiltinBug> BT_null; + mutable std::unique_ptr<BuiltinBug> BT_undef; public: void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const; @@ -45,8 +45,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, if (V.getAs<UndefinedVal>()) { if (ExplodedNode *N = C.generateSink()) { if (!BT_undef) - BT_undef.reset(new BuiltinBug("Uninitialized value used as mutex " - "for @synchronized")); + BT_undef.reset(new BuiltinBug(this, "Uninitialized value used as mutex " + "for @synchronized")); BugReport *report = new BugReport(*BT_undef, BT_undef->getDescription(), N); bugreporter::trackNullOrUndefValue(N, Ex, *report); @@ -60,7 +60,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, // Check for null mutexes. ProgramStateRef notNullState, nullState; - llvm::tie(notNullState, nullState) = state->assume(V.castAs<DefinedSVal>()); + std::tie(notNullState, nullState) = state->assume(V.castAs<DefinedSVal>()); if (nullState) { if (!notNullState) { @@ -68,8 +68,9 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, // a null mutex just means no synchronization occurs. if (ExplodedNode *N = C.addTransition(nullState)) { if (!BT_null) - BT_null.reset(new BuiltinBug("Nil value used as mutex for @synchronized() " - "(no synchronization will occur)")); + BT_null.reset(new BuiltinBug( + this, "Nil value used as mutex for @synchronized() " + "(no synchronization will occur)")); BugReport *report = new BugReport(*BT_null, BT_null->getDescription(), N); bugreporter::trackNullOrUndefValue(N, Ex, *report); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp index 503b1b5..e3fc611 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp @@ -27,6 +27,7 @@ using namespace ento; namespace { class WalkAST : public StmtVisitor<WalkAST> { BugReporter &BR; + const CheckerBase *Checker; AnalysisDeclContext* AC; ASTContext &ASTC; uint64_t PtrWidth; @@ -71,9 +72,9 @@ class WalkAST : public StmtVisitor<WalkAST> { } public: - WalkAST(BugReporter &br, AnalysisDeclContext* ac) - : BR(br), AC(ac), ASTC(AC->getASTContext()), - PtrWidth(ASTC.getTargetInfo().getPointerWidth(0)) {} + WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac) + : BR(br), Checker(checker), AC(ac), ASTC(AC->getASTContext()), + PtrWidth(ASTC.getTargetInfo().getPointerWidth(0)) {} // Statement visitor methods. void VisitChildren(Stmt *S); @@ -99,7 +100,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { if (Name.empty()) return; - const Expr *Arg = 0; + const Expr *Arg = nullptr; unsigned ArgNum; if (Name.equals("CFArrayCreate") || Name.equals("CFSetCreate")) { @@ -142,9 +143,9 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport(AC->getDecl(), - OsName.str(), categories::CoreFoundationObjectiveC, - Os.str(), CELoc, Arg->getSourceRange()); + BR.EmitBasicReport(AC->getDecl(), Checker, OsName.str(), + categories::CoreFoundationObjectiveC, Os.str(), CELoc, + Arg->getSourceRange()); } // Recurse and check children. @@ -163,7 +164,7 @@ public: void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr, BugReporter &BR) const { - WalkAST walker(BR, Mgr.getAnalysisDeclContext(D)); + WalkAST walker(BR, this, Mgr.getAnalysisDeclContext(D)); walker.Visit(D->getBody()); } }; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp index b9e96ee..8e51154 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp @@ -30,10 +30,10 @@ using namespace ento; namespace { class ObjCContainersChecker : public Checker< check::PreStmt<CallExpr>, check::PostStmt<CallExpr> > { - mutable OwningPtr<BugType> BT; + mutable std::unique_ptr<BugType> BT; inline void initBugType() const { if (!BT) - BT.reset(new BugType("CFArray API", + BT.reset(new BugType(this, "CFArray API", categories::CoreFoundationObjectiveC)); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp index 789b9f4..a2cf8e1 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp @@ -181,16 +181,12 @@ void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D, // Iterate over all instance methods. - for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(), - E = D->instmeth_end(); - I != E; ++I) { - Selector S = (*I)->getSelector(); + for (auto *MD : D->instance_methods()) { + Selector S = MD->getSelector(); // Find out whether this is a selector that we want to check. if (!SelectorsForClass[SuperclassName].count(S)) continue; - ObjCMethodDecl *MD = *I; - // Check if the method calls its superclass implementation. if (MD->getBody()) { @@ -212,7 +208,7 @@ void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D, << "' instance method in " << SuperclassName.str() << " subclass '" << *D << "' is missing a [super " << S.getAsString() << "] call"; - BR.EmitBasicReport(MD, Name, categories::CoreFoundationObjectiveC, + BR.EmitBasicReport(MD, this, Name, categories::CoreFoundationObjectiveC, os.str(), DLoc); } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp index 8506e08..51bc7e6 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp @@ -62,7 +62,13 @@ class ObjCSelfInitChecker : public Checker< check::PostObjCMessage, check::PostCall, check::Location, check::Bind > { + mutable std::unique_ptr<BugType> BT; + + void checkForInvalidSelf(const Expr *E, CheckerContext &C, + const char *errorStr) const; + public: + ObjCSelfInitChecker() {} void checkPostObjCMessage(const ObjCMethodCall &Msg, CheckerContext &C) const; void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const; void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; @@ -74,22 +80,11 @@ public: void checkPostCall(const CallEvent &CE, CheckerContext &C) const; void printState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep) const; + const char *NL, const char *Sep) const override; }; } // end anonymous namespace namespace { - -class InitSelfBug : public BugType { - const std::string desc; -public: - InitSelfBug() : BugType("Missing \"self = [(super or self) init...]\"", - categories::CoreFoundationObjectiveC) {} -}; - -} // end anonymous namespace - -namespace { enum SelfFlagEnum { /// \brief No flag set. SelfFlag_None = 0x0, @@ -146,8 +141,8 @@ static bool isInvalidSelf(const Expr *E, CheckerContext &C) { return true; } -static void checkForInvalidSelf(const Expr *E, CheckerContext &C, - const char *errorStr) { +void ObjCSelfInitChecker::checkForInvalidSelf(const Expr *E, CheckerContext &C, + const char *errorStr) const { if (!E) return; @@ -162,8 +157,10 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C, if (!N) return; - BugReport *report = - new BugReport(*new InitSelfBug(), errorStr, N); + if (!BT) + BT.reset(new BugType(this, "Missing \"self = [(super or self) init...]\"", + categories::CoreFoundationObjectiveC)); + BugReport *report = new BugReport(*BT, errorStr, N); C.emitReport(report); } @@ -205,9 +202,10 @@ void ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E, C.getCurrentAnalysisDeclContext()->getDecl()))) return; - checkForInvalidSelf(E->getBase(), C, - "Instance variable used while 'self' is not set to the result of " - "'[(super or self) init...]'"); + checkForInvalidSelf( + E->getBase(), C, + "Instance variable used while 'self' is not set to the result of " + "'[(super or self) init...]'"); } void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S, @@ -218,8 +216,8 @@ void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S, return; checkForInvalidSelf(S->getRetValue(), C, - "Returning 'self' while it is not set to the result of " - "'[(super or self) init...]'"); + "Returning 'self' while it is not set to the result of " + "'[(super or self) init...]'"); } // When a call receives a reference to 'self', [Pre/Post]Call pass @@ -347,7 +345,7 @@ void ObjCSelfInitChecker::printState(raw_ostream &Out, ProgramStateRef State, if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags) return; - Out << Sep << NL << "ObjCSelfInitChecker:" << NL; + Out << Sep << NL << *this << " :" << NL; if (DidCallInit) Out << " An init method has been called." << NL; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp index c66c7d0..d3b1753 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp @@ -77,22 +77,17 @@ static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl *D) { static void Scan(IvarUsageMap& M, const ObjCContainerDecl *D) { // Scan the methods for accesses. - for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(), - E = D->instmeth_end(); I!=E; ++I) - Scan(M, (*I)->getBody()); + for (const auto *I : D->instance_methods()) + Scan(M, I->getBody()); if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) { // Scan for @synthesized property methods that act as setters/getters // to an ivar. - for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(), - E = ID->propimpl_end(); I!=E; ++I) - Scan(M, *I); + for (const auto *I : ID->property_impls()) + Scan(M, I); // Scan the associated categories as well. - for (ObjCInterfaceDecl::visible_categories_iterator - Cat = ID->getClassInterface()->visible_categories_begin(), - CatEnd = ID->getClassInterface()->visible_categories_end(); - Cat != CatEnd; ++Cat) { + for (const auto *Cat : ID->getClassInterface()->visible_categories()) { if (const ObjCCategoryImplDecl *CID = Cat->getImplementation()) Scan(M, CID); } @@ -101,9 +96,8 @@ static void Scan(IvarUsageMap& M, const ObjCContainerDecl *D) { static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID, SourceManager &SM) { - for (DeclContext::decl_iterator I=C->decls_begin(), E=C->decls_end(); - I!=E; ++I) - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { + for (const auto *I : C->decls()) + if (const auto *FD = dyn_cast<FunctionDecl>(I)) { SourceLocation L = FD->getLocStart(); if (SM.getFileID(L) == FID) Scan(M, FD->getBody()); @@ -111,29 +105,26 @@ static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID, } static void checkObjCUnusedIvar(const ObjCImplementationDecl *D, - BugReporter &BR) { + BugReporter &BR, + const CheckerBase *Checker) { const ObjCInterfaceDecl *ID = D->getClassInterface(); IvarUsageMap M; // Iterate over the ivars. - for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), - E=ID->ivar_end(); I!=E; ++I) { - - const ObjCIvarDecl *ID = *I; - + for (const auto *Ivar : ID->ivars()) { // Ignore ivars that... // (a) aren't private // (b) explicitly marked unused // (c) are iboutlets // (d) are unnamed bitfields - if (ID->getAccessControl() != ObjCIvarDecl::Private || - ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>() || - ID->getAttr<IBOutletCollectionAttr>() || - ID->isUnnamedBitfield()) + if (Ivar->getAccessControl() != ObjCIvarDecl::Private || + Ivar->hasAttr<UnusedAttr>() || Ivar->hasAttr<IBOutletAttr>() || + Ivar->hasAttr<IBOutletCollectionAttr>() || + Ivar->isUnnamedBitfield()) continue; - M[ID] = Unused; + M[Ivar] = Unused; } if (M.empty()) @@ -172,7 +163,7 @@ static void checkObjCUnusedIvar(const ObjCImplementationDecl *D, PathDiagnosticLocation L = PathDiagnosticLocation::create(I->first, BR.getSourceManager()); - BR.EmitBasicReport(D, "Unused instance variable", "Optimization", + BR.EmitBasicReport(D, Checker, "Unused instance variable", "Optimization", os.str(), L); } } @@ -187,7 +178,7 @@ class ObjCUnusedIvarsChecker : public Checker< public: void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr, BugReporter &BR) const { - checkObjCUnusedIvar(D, BR); + checkObjCUnusedIvar(D, BR, this); } }; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp index bcbfacd..00480e4 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp @@ -24,7 +24,7 @@ using namespace ento; namespace { class PointerArithChecker : public Checker< check::PreStmt<BinaryOperator> > { - mutable OwningPtr<BuiltinBug> BT; + mutable std::unique_ptr<BuiltinBug> BT; public: void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; @@ -53,10 +53,11 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B, if (ExplodedNode *N = C.addTransition()) { if (!BT) - BT.reset(new BuiltinBug("Dangerous pointer arithmetic", - "Pointer arithmetic done on non-array variables " - "means reliance on memory layout, which is " - "dangerous.")); + BT.reset( + new BuiltinBug(this, "Dangerous pointer arithmetic", + "Pointer arithmetic done on non-array variables " + "means reliance on memory layout, which is " + "dangerous.")); BugReport *R = new BugReport(*BT, BT->getDescription(), N); R->addRange(B->getSourceRange()); C.emitReport(R); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp index 07c82d4..fbb2628 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp @@ -25,7 +25,7 @@ using namespace ento; namespace { class PointerSubChecker : public Checker< check::PreStmt<BinaryOperator> > { - mutable OwningPtr<BuiltinBug> BT; + mutable std::unique_ptr<BuiltinBug> BT; public: void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; @@ -62,9 +62,10 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B, if (ExplodedNode *N = C.addTransition()) { if (!BT) - BT.reset(new BuiltinBug("Pointer subtraction", - "Subtraction of two pointers that do not point to " - "the same memory chunk may cause incorrect result.")); + BT.reset( + new BuiltinBug(this, "Pointer subtraction", + "Subtraction of two pointers that do not point to " + "the same memory chunk may cause incorrect result.")); BugReport *R = new BugReport(*BT, BT->getDescription(), N); R->addRange(B->getSourceRange()); C.emitReport(R); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp index ffb8cf2..1ede3a2 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp @@ -24,9 +24,37 @@ using namespace clang; using namespace ento; namespace { + +struct LockState { + enum Kind { Destroyed, Locked, Unlocked } K; + +private: + LockState(Kind K) : K(K) {} + +public: + static LockState getLocked(void) { return LockState(Locked); } + static LockState getUnlocked(void) { return LockState(Unlocked); } + static LockState getDestroyed(void) { return LockState(Destroyed); } + + bool operator==(const LockState &X) const { + return K == X.K; + } + + bool isLocked() const { return K == Locked; } + bool isUnlocked() const { return K == Unlocked; } + bool isDestroyed() const { return K == Destroyed; } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(K); + } +}; + class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > { - mutable OwningPtr<BugType> BT_doublelock; - mutable OwningPtr<BugType> BT_lor; + mutable std::unique_ptr<BugType> BT_doublelock; + mutable std::unique_ptr<BugType> BT_doubleunlock; + mutable std::unique_ptr<BugType> BT_destroylock; + mutable std::unique_ptr<BugType> BT_initlock; + mutable std::unique_ptr<BugType> BT_lor; enum LockingSemantics { NotApplicable = 0, PthreadSemantics, @@ -39,12 +67,16 @@ public: bool isTryLock, enum LockingSemantics semantics) const; void ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const; + void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const; + void InitLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const; + void reportUseDestroyedBug(CheckerContext &C, const CallExpr *CE) const; }; } // end anonymous namespace // GDM Entry for tracking lock state. REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *) +REGISTER_MAP_WITH_PROGRAMSTATE(LockMap, const MemRegion *, LockState) void PthreadLockChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { @@ -54,7 +86,7 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE, if (FName.empty()) return; - if (CE->getNumArgs() != 1) + if (CE->getNumArgs() != 1 && CE->getNumArgs() != 2) return; if (FName == "pthread_mutex_lock" || @@ -69,7 +101,7 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE, false, XNUSemantics); else if (FName == "pthread_mutex_trylock" || FName == "pthread_rwlock_tryrdlock" || - FName == "pthread_rwlock_tryrwlock") + FName == "pthread_rwlock_trywrlock") AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx), true, PthreadSemantics); else if (FName == "lck_mtx_try_lock" || @@ -82,6 +114,11 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE, FName == "lck_mtx_unlock" || FName == "lck_rw_done") ReleaseLock(C, CE, state->getSVal(CE->getArg(0), LCtx)); + else if (FName == "pthread_mutex_destroy" || + FName == "lck_mtx_destroy") + DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx)); + else if (FName == "pthread_mutex_init") + InitLock(C, CE, state->getSVal(CE->getArg(0), LCtx)); } void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, @@ -100,18 +137,24 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, DefinedSVal retVal = X.castAs<DefinedSVal>(); - if (state->contains<LockSet>(lockR)) { - if (!BT_doublelock) - BT_doublelock.reset(new BugType("Double locking", "Lock checker")); - ExplodedNode *N = C.generateSink(); - if (!N) + if (const LockState *LState = state->get<LockMap>(lockR)) { + if (LState->isLocked()) { + if (!BT_doublelock) + BT_doublelock.reset(new BugType(this, "Double locking", + "Lock checker")); + ExplodedNode *N = C.generateSink(); + if (!N) + return; + BugReport *report = new BugReport(*BT_doublelock, + "This lock has already been acquired", + N); + report->addRange(CE->getArg(0)->getSourceRange()); + C.emitReport(report); return; - BugReport *report = new BugReport(*BT_doublelock, - "This lock has already " - "been acquired", N); - report->addRange(CE->getArg(0)->getSourceRange()); - C.emitReport(report); - return; + } else if (LState->isDestroyed()) { + reportUseDestroyedBug(C, CE); + return; + } } ProgramStateRef lockSucc = state; @@ -120,10 +163,10 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, ProgramStateRef lockFail; switch (semantics) { case PthreadSemantics: - llvm::tie(lockFail, lockSucc) = state->assume(retVal); + std::tie(lockFail, lockSucc) = state->assume(retVal); break; case XNUSemantics: - llvm::tie(lockSucc, lockFail) = state->assume(retVal); + std::tie(lockSucc, lockFail) = state->assume(retVal); break; default: llvm_unreachable("Unknown tryLock locking semantics"); @@ -144,6 +187,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, // Record that the lock was acquired. lockSucc = lockSucc->add<LockSet>(lockR); + lockSucc = lockSucc->set<LockMap>(lockR, LockState::getLocked()); C.addTransition(lockSucc); } @@ -155,35 +199,140 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, return; ProgramStateRef state = C.getState(); + + if (const LockState *LState = state->get<LockMap>(lockR)) { + if (LState->isUnlocked()) { + if (!BT_doubleunlock) + BT_doubleunlock.reset(new BugType(this, "Double unlocking", + "Lock checker")); + ExplodedNode *N = C.generateSink(); + if (!N) + return; + BugReport *Report = new BugReport(*BT_doubleunlock, + "This lock has already been unlocked", + N); + Report->addRange(CE->getArg(0)->getSourceRange()); + C.emitReport(Report); + return; + } else if (LState->isDestroyed()) { + reportUseDestroyedBug(C, CE); + return; + } + } + LockSetTy LS = state->get<LockSet>(); // FIXME: Better analysis requires IPA for wrappers. - // FIXME: check for double unlocks - if (LS.isEmpty()) - return; - - const MemRegion *firstLockR = LS.getHead(); - if (firstLockR != lockR) { - if (!BT_lor) - BT_lor.reset(new BugType("Lock order reversal", "Lock checker")); - ExplodedNode *N = C.generateSink(); - if (!N) + + if (!LS.isEmpty()) { + const MemRegion *firstLockR = LS.getHead(); + if (firstLockR != lockR) { + if (!BT_lor) + BT_lor.reset(new BugType(this, "Lock order reversal", "Lock checker")); + ExplodedNode *N = C.generateSink(); + if (!N) + return; + BugReport *report = new BugReport(*BT_lor, + "This was not the most recently " + "acquired lock. Possible lock order " + "reversal", + N); + report->addRange(CE->getArg(0)->getSourceRange()); + C.emitReport(report); return; - BugReport *report = new BugReport(*BT_lor, - "This was not the most " - "recently acquired lock. " - "Possible lock order " - "reversal", N); - report->addRange(CE->getArg(0)->getSourceRange()); - C.emitReport(report); - return; + } + // Record that the lock was released. + state = state->set<LockSet>(LS.getTail()); } - // Record that the lock was released. - state = state->set<LockSet>(LS.getTail()); + state = state->set<LockMap>(lockR, LockState::getUnlocked()); C.addTransition(state); } +void PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE, + SVal Lock) const { + + const MemRegion *LockR = Lock.getAsRegion(); + if (!LockR) + return; + + ProgramStateRef State = C.getState(); + + const LockState *LState = State->get<LockMap>(LockR); + if (!LState || LState->isUnlocked()) { + State = State->set<LockMap>(LockR, LockState::getDestroyed()); + C.addTransition(State); + return; + } + + StringRef Message; + + if (LState->isLocked()) { + Message = "This lock is still locked"; + } else { + Message = "This lock has already been destroyed"; + } + + if (!BT_destroylock) + BT_destroylock.reset(new BugType(this, "Destroy invalid lock", + "Lock checker")); + ExplodedNode *N = C.generateSink(); + if (!N) + return; + BugReport *Report = new BugReport(*BT_destroylock, Message, N); + Report->addRange(CE->getArg(0)->getSourceRange()); + C.emitReport(Report); +} + +void PthreadLockChecker::InitLock(CheckerContext &C, const CallExpr *CE, + SVal Lock) const { + + const MemRegion *LockR = Lock.getAsRegion(); + if (!LockR) + return; + + ProgramStateRef State = C.getState(); + + const struct LockState *LState = State->get<LockMap>(LockR); + if (!LState || LState->isDestroyed()) { + State = State->set<LockMap>(LockR, LockState::getUnlocked()); + C.addTransition(State); + return; + } + + StringRef Message; + + if (LState->isLocked()) { + Message = "This lock is still being held"; + } else { + Message = "This lock has already been initialized"; + } + + if (!BT_initlock) + BT_initlock.reset(new BugType(this, "Init invalid lock", + "Lock checker")); + ExplodedNode *N = C.generateSink(); + if (!N) + return; + BugReport *Report = new BugReport(*BT_initlock, Message, N); + Report->addRange(CE->getArg(0)->getSourceRange()); + C.emitReport(Report); +} + +void PthreadLockChecker::reportUseDestroyedBug(CheckerContext &C, + const CallExpr *CE) const { + if (!BT_destroylock) + BT_destroylock.reset(new BugType(this, "Use destroyed lock", + "Lock checker")); + ExplodedNode *N = C.generateSink(); + if (!N) + return; + BugReport *Report = new BugReport(*BT_destroylock, + "This lock has already been destroyed", + N); + Report->addRange(CE->getArg(0)->getSourceRange()); + C.emitReport(Report); +} void ento::registerPthreadLockChecker(CheckerManager &mgr) { mgr.registerChecker<PthreadLockChecker>(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index c474e78..eb699d6 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -13,6 +13,8 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" +#include "AllocationDiagnostics.h" +#include "SelectorExtras.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -20,6 +22,7 @@ #include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" +#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Core/Checker.h" @@ -28,7 +31,6 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" -#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableList.h" @@ -38,8 +40,6 @@ #include "llvm/ADT/StringExtras.h" #include <cstdarg> -#include "AllocationDiagnostics.h" - using namespace clang; using namespace ento; using namespace objc_retain; @@ -95,29 +95,70 @@ public: }; private: - Kind kind; - RetEffect::ObjKind okind; + /// The number of outstanding retains. unsigned Cnt; + /// The number of outstanding autoreleases. unsigned ACnt; + /// The (static) type of the object at the time we started tracking it. QualType T; - RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t) - : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {} + /// The current state of the object. + /// + /// See the RefVal::Kind enum for possible values. + unsigned RawKind : 5; + + /// The kind of object being tracked (CF or ObjC), if known. + /// + /// See the RetEffect::ObjKind enum for possible values. + unsigned RawObjectKind : 2; + + /// True if the current state and/or retain count may turn out to not be the + /// best possible approximation of the reference counting state. + /// + /// If true, the checker may decide to throw away ("override") this state + /// in favor of something else when it sees the object being used in new ways. + /// + /// This setting should not be propagated to state derived from this state. + /// Once we start deriving new states, it would be inconsistent to override + /// them. + unsigned IsOverridable : 1; + + RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t, + bool Overridable = false) + : Cnt(cnt), ACnt(acnt), T(t), RawKind(static_cast<unsigned>(k)), + RawObjectKind(static_cast<unsigned>(o)), IsOverridable(Overridable) { + assert(getKind() == k && "not enough bits for the kind"); + assert(getObjKind() == o && "not enough bits for the object kind"); + } public: - Kind getKind() const { return kind; } + Kind getKind() const { return static_cast<Kind>(RawKind); } - RetEffect::ObjKind getObjKind() const { return okind; } + RetEffect::ObjKind getObjKind() const { + return static_cast<RetEffect::ObjKind>(RawObjectKind); + } unsigned getCount() const { return Cnt; } unsigned getAutoreleaseCount() const { return ACnt; } unsigned getCombinedCounts() const { return Cnt + ACnt; } - void clearCounts() { Cnt = 0; ACnt = 0; } - void setCount(unsigned i) { Cnt = i; } - void setAutoreleaseCount(unsigned i) { ACnt = i; } + void clearCounts() { + Cnt = 0; + ACnt = 0; + IsOverridable = false; + } + void setCount(unsigned i) { + Cnt = i; + IsOverridable = false; + } + void setAutoreleaseCount(unsigned i) { + ACnt = i; + IsOverridable = false; + } QualType getType() const { return T; } + bool isOverridable() const { return IsOverridable; } + bool isOwned() const { return getKind() == Owned; } @@ -134,20 +175,31 @@ public: return getKind() == ReturnedNotOwned; } + /// Create a state for an object whose lifetime is the responsibility of the + /// current function, at least partially. + /// + /// Most commonly, this is an owned object with a retain count of +1. static RefVal makeOwned(RetEffect::ObjKind o, QualType t, unsigned Count = 1) { return RefVal(Owned, o, Count, 0, t); } + /// Create a state for an object whose lifetime is not the responsibility of + /// the current function. + /// + /// Most commonly, this is an unowned object with a retain count of +0. static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t, unsigned Count = 0) { return RefVal(NotOwned, o, Count, 0, t); } - // Comparison, profiling, and pretty-printing. - - bool operator==(const RefVal& X) const { - return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt; + /// Create an "overridable" state for an unowned object at +0. + /// + /// An overridable state is one that provides a good approximation of the + /// reference counting state now, but which may be discarded later if the + /// checker sees the object being used in new ways. + static RefVal makeOverridableNotOwned(RetEffect::ObjKind o, QualType t) { + return RefVal(NotOwned, o, 0, 0, t, /*Overridable=*/true); } RefVal operator-(size_t i) const { @@ -170,11 +222,24 @@ public: getType()); } + // Comparison, profiling, and pretty-printing. + + bool hasSameState(const RefVal &X) const { + return getKind() == X.getKind() && Cnt == X.Cnt && ACnt == X.ACnt; + } + + bool operator==(const RefVal& X) const { + return T == X.T && hasSameState(X) && getObjKind() == X.getObjKind() && + IsOverridable == X.IsOverridable; + } + void Profile(llvm::FoldingSetNodeID& ID) const { - ID.AddInteger((unsigned) kind); + ID.Add(T); + ID.AddInteger(RawKind); ID.AddInteger(Cnt); ID.AddInteger(ACnt); - ID.Add(T); + ID.AddInteger(RawObjectKind); + ID.AddBoolean(IsOverridable); } void print(raw_ostream &Out) const; @@ -184,6 +249,9 @@ void RefVal::print(raw_ostream &Out) const { if (!T.isNull()) Out << "Tracked " << T.getAsString() << '/'; + if (isOverridable()) + Out << "(overridable) "; + switch (getKind()) { default: llvm_unreachable("Invalid RefVal kind"); case Owned: { @@ -383,10 +451,10 @@ public: : II(ii), S(s) {} ObjCSummaryKey(const ObjCInterfaceDecl *d, Selector s) - : II(d ? d->getIdentifier() : 0), S(s) {} + : II(d ? d->getIdentifier() : nullptr), S(s) {} ObjCSummaryKey(Selector s) - : II(0), S(s) {} + : II(nullptr), S(s) {} IdentifierInfo *getIdentifier() const { return II; } Selector getSelector() const { return S; } @@ -435,7 +503,7 @@ public: if (I != M.end()) return I->second; if (!D) - return NULL; + return nullptr; // Walk the super chain. If we find a hit with a parent, we'll end // up returning that summary. We actually allow that key (null,S), as @@ -448,7 +516,7 @@ public: break; if (!C) - return NULL; + return nullptr; } // Cache the summary with original key to make the next lookup faster @@ -466,7 +534,7 @@ public: if (I == M.end()) I = M.find(ObjCSummaryKey(S)); - return I == M.end() ? NULL : I->second; + return I == M.end() ? nullptr : I->second; } const RetainSummary *& operator[](ObjCSummaryKey K) { @@ -608,18 +676,9 @@ private: ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; } - Selector generateSelector(va_list argp) { - SmallVector<IdentifierInfo*, 10> II; - - while (const char* s = va_arg(argp, const char*)) - II.push_back(&Ctx.Idents.get(s)); - - return Ctx.Selectors.getSelector(II.size(), &II[0]); - } - - void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy& Summaries, - const RetainSummary * Summ, va_list argp) { - Selector S = generateSelector(argp); + void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy &Summaries, + const RetainSummary *Summ, va_list argp) { + Selector S = getKeywordSelector(Ctx, argp); Summaries[ObjCSummaryKey(ClsII, S)] = Summ; } @@ -653,18 +712,18 @@ public: AF(BPAlloc), ScratchArgs(AF.getEmptyMap()), ObjCAllocRetE(gcenabled ? RetEffect::MakeGCNotOwned() - : (usesARC ? RetEffect::MakeARCNotOwned() + : (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC) : RetEffect::MakeOwned(RetEffect::ObjC, true))), ObjCInitRetE(gcenabled ? RetEffect::MakeGCNotOwned() - : (usesARC ? RetEffect::MakeARCNotOwned() + : (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC) : RetEffect::MakeOwnedWhenTrackedReceiver())) { InitializeClassMethodSummaries(); InitializeMethodSummaries(); } const RetainSummary *getSummary(const CallEvent &Call, - ProgramStateRef State = 0); + ProgramStateRef State = nullptr); const RetainSummary *getFunctionSummary(const FunctionDecl *FD); @@ -689,7 +748,7 @@ public: const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) { const ObjCInterfaceDecl *ID = MD->getClassInterface(); Selector S = MD->getSelector(); - QualType ResultTy = MD->getResultType(); + QualType ResultTy = MD->getReturnType(); ObjCMethodSummariesTy *CachedSummaries; if (MD->isInstanceMethod()) @@ -861,7 +920,7 @@ void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S, // Special cases where the callback argument CANNOT free the return value. // This can generally only happen if we know that the callback will only be // called when the return value is already being deallocated. - if (const FunctionCall *FC = dyn_cast<FunctionCall>(&Call)) { + if (const SimpleFunctionCall *FC = dyn_cast<SimpleFunctionCall>(&Call)) { if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) { // When the CGBitmapContext is deallocated, the callback here will free // the associated data buffer. @@ -909,7 +968,7 @@ RetainSummaryManager::getSummary(const CallEvent &Call, const RetainSummary *Summ; switch (Call.getKind()) { case CE_Function: - Summ = getFunctionSummary(cast<FunctionCall>(Call).getDecl()); + Summ = getFunctionSummary(cast<SimpleFunctionCall>(Call).getDecl()); break; case CE_CXXMember: case CE_CXXMemberOperator: @@ -947,7 +1006,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { return I->second; // No summary? Generate one. - const RetainSummary *S = 0; + const RetainSummary *S = nullptr; bool AllowAnnotations = true; do { @@ -971,7 +1030,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { FName = FName.substr(FName.find_first_not_of('_')); // Inspect the result type. - QualType RetTy = FT->getResultType(); + QualType RetTy = FT->getReturnType(); // FIXME: This should all be refactored into a chain of "summary lookup" // filters. @@ -1102,7 +1161,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { break; } - if (FD->getAttr<CFAuditedTransferAttr>()) { + if (FD->hasAttr<CFAuditedTransferAttr>()) { S = getCFCreateGetRuleSummary(FD); break; } @@ -1175,7 +1234,7 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT, // Sanity check that this is *really* a unary function. This can // happen if people do weird things. const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT); - if (!FTP || FTP->getNumArgs() != 1) + if (!FTP || FTP->getNumParams() != 1) return getPersistentStopSummary(); assert (ScratchArgs.isEmpty()); @@ -1214,21 +1273,21 @@ Optional<RetEffect> RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy, const Decl *D) { if (cocoa::isCocoaObjectRef(RetTy)) { - if (D->getAttr<NSReturnsRetainedAttr>()) + if (D->hasAttr<NSReturnsRetainedAttr>()) return ObjCAllocRetE; - if (D->getAttr<NSReturnsNotRetainedAttr>() || - D->getAttr<NSReturnsAutoreleasedAttr>()) + if (D->hasAttr<NSReturnsNotRetainedAttr>() || + D->hasAttr<NSReturnsAutoreleasedAttr>()) return RetEffect::MakeNotOwned(RetEffect::ObjC); } else if (!RetTy->isPointerType()) { return None; } - if (D->getAttr<CFReturnsRetainedAttr>()) + if (D->hasAttr<CFReturnsRetainedAttr>()) return RetEffect::MakeOwned(RetEffect::CF, true); - if (D->getAttr<CFReturnsNotRetainedAttr>()) + if (D->hasAttr<CFReturnsNotRetainedAttr>()) return RetEffect::MakeNotOwned(RetEffect::CF); return None; @@ -1248,13 +1307,13 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, for (FunctionDecl::param_const_iterator pi = FD->param_begin(), pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) { const ParmVarDecl *pd = *pi; - if (pd->getAttr<NSConsumedAttr>()) + if (pd->hasAttr<NSConsumedAttr>()) Template->addArg(AF, parm_idx, DecRefMsg); - else if (pd->getAttr<CFConsumedAttr>()) + else if (pd->hasAttr<CFConsumedAttr>()) Template->addArg(AF, parm_idx, DecRef); } - - QualType RetTy = FD->getResultType(); + + QualType RetTy = FD->getReturnType(); if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD)) Template->setRetEffect(*RetE); } @@ -1269,7 +1328,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, RetainSummaryTemplate Template(Summ, *this); // Effects on the receiver. - if (MD->getAttr<NSConsumesSelfAttr>()) + if (MD->hasAttr<NSConsumesSelfAttr>()) Template->setReceiverEffect(DecRefMsg); // Effects on the parameters. @@ -1278,14 +1337,14 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, pi=MD->param_begin(), pe=MD->param_end(); pi != pe; ++pi, ++parm_idx) { const ParmVarDecl *pd = *pi; - if (pd->getAttr<NSConsumedAttr>()) + if (pd->hasAttr<NSConsumedAttr>()) Template->addArg(AF, parm_idx, DecRefMsg); - else if (pd->getAttr<CFConsumedAttr>()) { + else if (pd->hasAttr<CFConsumedAttr>()) { Template->addArg(AF, parm_idx, DecRef); } } - - QualType RetTy = MD->getResultType(); + + QualType RetTy = MD->getReturnType(); if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD)) Template->setRetEffect(*RetE); } @@ -1388,7 +1447,7 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD, const RetainSummary * RetainSummaryManager::getInstanceMethodSummary(const ObjCMethodCall &Msg, ProgramStateRef State) { - const ObjCInterfaceDecl *ReceiverClass = 0; + const ObjCInterfaceDecl *ReceiverClass = nullptr; // We do better tracking of the type of the object than the core ExprEngine. // See if we have its type in our private state. @@ -1507,6 +1566,11 @@ void RetainSummaryManager::InitializeMethodSummaries() { // as for NSWindow objects. addClassMethSummary("NSPanel", "alloc", NoTrackYet); + // For NSNull, objects returned by +null are singletons that ignore + // retain/release semantics. Just don't track them. + // <rdar://problem/12858915> + addClassMethSummary("NSNull", "null", NoTrackYet); + // Don't track allocated autorelease pools, as it is okay to prematurely // exit a method. addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet); @@ -1543,8 +1607,9 @@ namespace { class CFRefBug : public BugType { protected: - CFRefBug(StringRef name) - : BugType(name, categories::MemoryCoreFoundationObjectiveC) {} + CFRefBug(const CheckerBase *checker, StringRef name) + : BugType(checker, name, categories::MemoryCoreFoundationObjectiveC) {} + public: // FIXME: Eventually remove. @@ -1555,18 +1620,19 @@ namespace { class UseAfterRelease : public CFRefBug { public: - UseAfterRelease() : CFRefBug("Use-after-release") {} + UseAfterRelease(const CheckerBase *checker) + : CFRefBug(checker, "Use-after-release") {} - const char *getDescription() const { + const char *getDescription() const override { return "Reference-counted object is used after it is released"; } }; class BadRelease : public CFRefBug { public: - BadRelease() : CFRefBug("Bad release") {} + BadRelease(const CheckerBase *checker) : CFRefBug(checker, "Bad release") {} - const char *getDescription() const { + const char *getDescription() const override { return "Incorrect decrement of the reference count of an object that is " "not owned at this point by the caller"; } @@ -1574,40 +1640,40 @@ namespace { class DeallocGC : public CFRefBug { public: - DeallocGC() - : CFRefBug("-dealloc called while using garbage collection") {} + DeallocGC(const CheckerBase *checker) + : CFRefBug(checker, "-dealloc called while using garbage collection") {} - const char *getDescription() const { + const char *getDescription() const override { return "-dealloc called while using garbage collection"; } }; class DeallocNotOwned : public CFRefBug { public: - DeallocNotOwned() - : CFRefBug("-dealloc sent to non-exclusively owned object") {} + DeallocNotOwned(const CheckerBase *checker) + : CFRefBug(checker, "-dealloc sent to non-exclusively owned object") {} - const char *getDescription() const { + const char *getDescription() const override { return "-dealloc sent to object that may be referenced elsewhere"; } }; class OverAutorelease : public CFRefBug { public: - OverAutorelease() - : CFRefBug("Object autoreleased too many times") {} + OverAutorelease(const CheckerBase *checker) + : CFRefBug(checker, "Object autoreleased too many times") {} - const char *getDescription() const { + const char *getDescription() const override { return "Object autoreleased too many times"; } }; class ReturnedNotOwnedForOwned : public CFRefBug { public: - ReturnedNotOwnedForOwned() - : CFRefBug("Method should return an owned object") {} + ReturnedNotOwnedForOwned(const CheckerBase *checker) + : CFRefBug(checker, "Method should return an owned object") {} - const char *getDescription() const { + const char *getDescription() const override { return "Object with a +0 retain count returned to caller where a +1 " "(owning) retain count is expected"; } @@ -1615,15 +1681,14 @@ namespace { class Leak : public CFRefBug { public: - Leak(StringRef name) - : CFRefBug(name) { + Leak(const CheckerBase *checker, StringRef name) : CFRefBug(checker, name) { // Leaks should not be reported if they are post-dominated by a sink. setSuppressOnSink(true); } - const char *getDescription() const { return ""; } + const char *getDescription() const override { return ""; } - bool isLeak() const { return true; } + bool isLeak() const override { return true; } }; //===---------===// @@ -1640,20 +1705,20 @@ namespace { CFRefReportVisitor(SymbolRef sym, bool gcEnabled, const SummaryLogTy &log) : Sym(sym), SummaryLog(log), GCEnabled(gcEnabled) {} - virtual void Profile(llvm::FoldingSetNodeID &ID) const { + void Profile(llvm::FoldingSetNodeID &ID) const override { static int x = 0; ID.AddPointer(&x); ID.AddPointer(Sym); } - virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext &BRC, - BugReport &BR); + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override; - virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, - const ExplodedNode *N, - BugReport &BR); + PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, + const ExplodedNode *N, + BugReport &BR) override; }; class CFRefLeakReportVisitor : public CFRefReportVisitor { @@ -1664,9 +1729,9 @@ namespace { PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, const ExplodedNode *N, - BugReport &BR); + BugReport &BR) override; - virtual BugReporterVisitor *clone() const { + BugReporterVisitor *clone() const override { // The curiously-recurring template pattern only works for one level of // subclassing. Rather than make a new template base for // CFRefReportVisitor, we simply override clone() to do the right thing. @@ -1697,7 +1762,7 @@ namespace { addGCModeDescription(LOpts, GCEnabled); } - virtual std::pair<ranges_iterator, ranges_iterator> getRanges() { + std::pair<ranges_iterator, ranges_iterator> getRanges() override { const CFRefBug& BugTy = static_cast<CFRefBug&>(getBugType()); if (!BugTy.isLeak()) return BugReport::getRanges(); @@ -1714,7 +1779,7 @@ namespace { CheckerContext &Ctx, bool IncludeAllocationLine); - PathDiagnosticLocation getLocation(const SourceManager &SM) const { + PathDiagnosticLocation getLocation(const SourceManager &SM) const override { assert(Location.isValid()); return Location; } @@ -1723,7 +1788,7 @@ namespace { void CFRefReport::addGCModeDescription(const LangOptions &LOpts, bool GCEnabled) { - const char *GCModeDescription = 0; + const char *GCModeDescription = nullptr; switch (LOpts.getGC()) { case LangOptions::GCOnly: @@ -1770,7 +1835,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, // FIXME: We will eventually need to handle non-statement-based events // (__attribute__((cleanup))). if (!N->getLocation().getAs<StmtPoint>()) - return NULL; + return nullptr; // Check if the type state has changed. ProgramStateRef PrevSt = PrevN->getState(); @@ -1778,7 +1843,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, const LocationContext *LCtx = N->getLocationContext(); const RefVal* CurrT = getRefBinding(CurrSt, Sym); - if (!CurrT) return NULL; + if (!CurrT) return nullptr; const RefVal &CurrV = *CurrT; const RefVal *PrevT = getRefBinding(PrevSt, Sym); @@ -1803,7 +1868,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, if (isNumericLiteralExpression(BL->getSubExpr())) os << "NSNumber literal is an object with a +0 retain count"; else { - const ObjCInterfaceDecl *BoxClass = 0; + const ObjCInterfaceDecl *BoxClass = nullptr; if (const ObjCMethodDecl *Method = BL->getBoxingMethod()) BoxClass = Method->getClassInterface(); @@ -1918,7 +1983,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, if (!GCEnabled && std::find(AEffects.begin(), AEffects.end(), Dealloc) != AEffects.end()) { // Determine if the object's reference count was pushed to zero. - assert(!(PrevV == CurrV) && "The typestate *must* have changed."); + assert(!PrevV.hasSameState(CurrV) && "The state should have changed."); // We may not have transitioned to 'release' if we hit an error. // This case is handled elsewhere. if (CurrV.getKind() == RefVal::Released) { @@ -1939,7 +2004,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, if (GCEnabled) { // Determine if the object's reference count was pushed to zero. - assert(!(PrevV == CurrV) && "The typestate *must* have changed."); + assert(!PrevV.hasSameState(CurrV) && "The state should have changed."); os << "In GC mode a call to '" << *FD << "' decrements an object's retain count and registers the " @@ -1964,7 +2029,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, } // Determine if the typestate has changed. - if (!(PrevV == CurrV)) + if (!PrevV.hasSameState(CurrV)) switch (CurrV.getKind()) { case RefVal::Owned: case RefVal::NotOwned: @@ -1972,7 +2037,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, if (PrevV.getCount() == CurrV.getCount()) { // Did an autorelease message get sent? if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount()) - return 0; + return nullptr; assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount()); os << "Object autoreleased"; @@ -2002,7 +2067,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, case RefVal::ReturnedOwned: // Autoreleases can be applied after marking a node ReturnedOwned. if (CurrV.getAutoreleaseCount()) - return NULL; + return nullptr; os << "Object returned to caller as an owning reference (single " "retain count transferred to caller)"; @@ -2013,7 +2078,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, break; default: - return NULL; + return nullptr; } // Emit any remaining diagnostics for the argument effects (if any). @@ -2038,7 +2103,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, } while (0); if (os.str().empty()) - return 0; // We have nothing to say! + return nullptr; // We have nothing to say! const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); PathDiagnosticLocation Pos(S, BRC.getSourceManager(), @@ -2078,12 +2143,12 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N, SymbolRef Sym) { const ExplodedNode *AllocationNode = N; const ExplodedNode *AllocationNodeInCurrentContext = N; - const MemRegion* FirstBinding = 0; + const MemRegion *FirstBinding = nullptr; const LocationContext *LeakContext = N->getLocationContext(); // The location context of the init method called on the leaked object, if // available. - const LocationContext *InitMethodContext = 0; + const LocationContext *InitMethodContext = nullptr; while (N) { ProgramStateRef St = N->getState(); @@ -2127,12 +2192,12 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N, } } - N = N->pred_empty() ? NULL : *(N->pred_begin()); + N = N->pred_empty() ? nullptr : *(N->pred_begin()); } // If we are reporting a leak of the object that was allocated with alloc, // mark its init method as interesting. - const LocationContext *InterestingMethodContext = 0; + const LocationContext *InterestingMethodContext = nullptr; if (InitMethodContext) { const ProgramPoint AllocPP = AllocationNode->getLocation(); if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>()) @@ -2145,7 +2210,7 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N, // do not report the binding. assert(N && "Could not find allocation node"); if (N->getLocationContext() != LeakContext) { - FirstBinding = 0; + FirstBinding = nullptr; } return AllocationInfo(AllocationNodeInCurrentContext, @@ -2212,9 +2277,9 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, os << (isa<ObjCMethodDecl>(D) ? " is returned from a method " : " is returned from a function "); - if (D->getAttr<CFReturnsNotRetainedAttr>()) + if (D->hasAttr<CFReturnsNotRetainedAttr>()) os << "that is annotated as CF_RETURNS_NOT_RETAINED"; - else if (D->getAttr<NSReturnsNotRetainedAttr>()) + else if (D->hasAttr<NSReturnsNotRetainedAttr>()) os << "that is annotated as NS_RETURNS_NOT_RETAINED"; else { if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { @@ -2262,7 +2327,7 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, // Note that this is *not* the trimmed graph; we are guaranteed, however, // that all ancestor nodes that represent the allocation site have the // same SourceLocation. - const ExplodedNode *AllocNode = 0; + const ExplodedNode *AllocNode = nullptr; const SourceManager& SMgr = Ctx.getSourceManager(); @@ -2275,14 +2340,27 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, // Get the SourceLocation for the allocation site. // FIXME: This will crash the analyzer if an allocation comes from an - // implicit call. (Currently there are no such allocations in Cocoa, though.) - const Stmt *AllocStmt; + // implicit call (ex: a destructor call). + // (Currently there are no such allocations in Cocoa, though.) + const Stmt *AllocStmt = 0; ProgramPoint P = AllocNode->getLocation(); if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>()) AllocStmt = Exit->getCalleeContext()->getCallSite(); - else - AllocStmt = P.castAs<PostStmt>().getStmt(); - assert(AllocStmt && "All allocations must come from explicit calls"); + else { + // We are going to get a BlockEdge when the leak and allocation happen in + // different, non-nested frames (contexts). For example, the case where an + // allocation happens in a block that captures a reference to it and + // that reference is overwritten/dropped by another call to the block. + if (Optional<BlockEdge> Edge = P.getAs<BlockEdge>()) { + if (Optional<CFGStmt> St = Edge->getDst()->front().getAs<CFGStmt>()) { + AllocStmt = St->getStmt(); + } + } + else { + AllocStmt = P.castAs<PostStmt>().getStmt(); + } + } + assert(AllocStmt && "Cannot find allocation statement"); PathDiagnosticLocation AllocLocation = PathDiagnosticLocation::createBegin(AllocStmt, SMgr, @@ -2328,24 +2406,25 @@ class RetainCountChecker check::PostStmt<ObjCArrayLiteral>, check::PostStmt<ObjCDictionaryLiteral>, check::PostStmt<ObjCBoxedExpr>, + check::PostStmt<ObjCIvarRefExpr>, check::PostCall, check::PreStmt<ReturnStmt>, check::RegionChanges, eval::Assume, eval::Call > { - mutable OwningPtr<CFRefBug> useAfterRelease, releaseNotOwned; - mutable OwningPtr<CFRefBug> deallocGC, deallocNotOwned; - mutable OwningPtr<CFRefBug> overAutorelease, returnNotOwnedForOwned; - mutable OwningPtr<CFRefBug> leakWithinFunction, leakAtReturn; - mutable OwningPtr<CFRefBug> leakWithinFunctionGC, leakAtReturnGC; + mutable std::unique_ptr<CFRefBug> useAfterRelease, releaseNotOwned; + mutable std::unique_ptr<CFRefBug> deallocGC, deallocNotOwned; + mutable std::unique_ptr<CFRefBug> overAutorelease, returnNotOwnedForOwned; + mutable std::unique_ptr<CFRefBug> leakWithinFunction, leakAtReturn; + mutable std::unique_ptr<CFRefBug> leakWithinFunctionGC, leakAtReturnGC; - typedef llvm::DenseMap<SymbolRef, const SimpleProgramPointTag *> SymbolTagMap; + typedef llvm::DenseMap<SymbolRef, const CheckerProgramPointTag *> SymbolTagMap; // This map is only used to ensure proper deletion of any allocated tags. mutable SymbolTagMap DeadSymbolTags; - mutable OwningPtr<RetainSummaryManager> Summaries; - mutable OwningPtr<RetainSummaryManager> SummariesGC; + mutable std::unique_ptr<RetainSummaryManager> Summaries; + mutable std::unique_ptr<RetainSummaryManager> SummariesGC; mutable SummaryLogTy SummaryLog; mutable bool ShouldResetSummaryLog; @@ -2402,17 +2481,18 @@ public: bool GCEnabled) const { if (GCEnabled) { if (!leakWithinFunctionGC) - leakWithinFunctionGC.reset(new Leak("Leak of object when using " - "garbage collection")); + leakWithinFunctionGC.reset(new Leak(this, "Leak of object when using " + "garbage collection")); return leakWithinFunctionGC.get(); } else { if (!leakWithinFunction) { if (LOpts.getGC() == LangOptions::HybridGC) { - leakWithinFunction.reset(new Leak("Leak of object when not using " + leakWithinFunction.reset(new Leak(this, + "Leak of object when not using " "garbage collection (GC) in " "dual GC/non-GC code")); } else { - leakWithinFunction.reset(new Leak("Leak")); + leakWithinFunction.reset(new Leak(this, "Leak")); } } return leakWithinFunction.get(); @@ -2422,17 +2502,19 @@ public: CFRefBug *getLeakAtReturnBug(const LangOptions &LOpts, bool GCEnabled) const { if (GCEnabled) { if (!leakAtReturnGC) - leakAtReturnGC.reset(new Leak("Leak of returned object when using " + leakAtReturnGC.reset(new Leak(this, + "Leak of returned object when using " "garbage collection")); return leakAtReturnGC.get(); } else { if (!leakAtReturn) { if (LOpts.getGC() == LangOptions::HybridGC) { - leakAtReturn.reset(new Leak("Leak of returned object when not using " + leakAtReturn.reset(new Leak(this, + "Leak of returned object when not using " "garbage collection (GC) in dual " "GC/non-GC code")); } else { - leakAtReturn.reset(new Leak("Leak of returned object")); + leakAtReturn.reset(new Leak(this, "Leak of returned object")); } } return leakAtReturn.get(); @@ -2464,7 +2546,7 @@ public: } void printState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep) const; + const char *NL, const char *Sep) const override; void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const; void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; @@ -2474,6 +2556,8 @@ public: void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const; void checkPostStmt(const ObjCBoxedExpr *BE, CheckerContext &C) const; + void checkPostStmt(const ObjCIvarRefExpr *IRE, CheckerContext &C) const; + void checkPostCall(const CallEvent &Call, CheckerContext &C) const; void checkSummary(const RetainSummary &Summ, const CallEvent &Call, @@ -2531,7 +2615,7 @@ public: ExplodedNode *processLeaks(ProgramStateRef state, SmallVectorImpl<SymbolRef> &Leaked, CheckerContext &Ctx, - ExplodedNode *Pred = 0) const; + ExplodedNode *Pred = nullptr) const; }; } // end anonymous namespace @@ -2542,7 +2626,7 @@ public: StopTrackingCallback(ProgramStateRef st) : state(st) {} ProgramStateRef getState() const { return state; } - bool VisitSymbol(SymbolRef sym) { + bool VisitSymbol(SymbolRef sym) override { state = state->remove<RefBindings>(sym); return true; } @@ -2691,6 +2775,20 @@ void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex, C.addTransition(State); } +void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + // If an instance variable was previously accessed through a property, + // it may have a synthesized refcount of +0. Override right now that we're + // doing direct access. + if (Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>()) + if (SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol()) + if (const RefVal *RV = getRefBinding(State, Sym)) + if (RV->isOverridable()) + State = removeRefBinding(State, Sym); + C.addTransition(State); +} + void RetainCountChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { RetainSummaryManager &Summaries = getSummaryManager(C); @@ -2731,6 +2829,16 @@ static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) { return RetTy; } +static bool wasSynthesizedProperty(const ObjCMethodCall *Call, + ExplodedNode *N) { + if (!Call || !Call->getDecl()->isPropertyAccessor()) + return false; + + CallExitEnd PP = N->getLocation().castAs<CallExitEnd>(); + const StackFrameContext *Frame = PP.getCalleeContext(); + return Frame->getAnalysisDeclContext()->isBodyAutosynthesized(); +} + // We don't always get the exact modeling of the function with regards to the // retain count checker even when the function is inlined. For example, we need // to stop tracking the symbols which were marked with StopTrackingHard. @@ -2765,6 +2873,19 @@ void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ, SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol(); if (Sym) state = removeRefBinding(state, Sym); + } else if (RE.getKind() == RetEffect::NotOwnedSymbol) { + if (wasSynthesizedProperty(MsgInvocation, C.getPredecessor())) { + // Believe the summary if we synthesized the body of a property getter + // and the return value is currently untracked. If the corresponding + // instance variable is later accessed directly, however, we're going to + // want to override this state, so that the owning object can perform + // reference counting operations on its own ivars. + SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol(); + if (Sym && !getRefBinding(state, Sym)) + state = setRefBinding(state, Sym, + RefVal::makeOverridableNotOwned(RE.getObjKind(), + Sym->getType())); + } } C.addTransition(state); @@ -2778,7 +2899,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ, // Evaluate the effect of the arguments. RefVal::Kind hasErr = (RefVal::Kind) 0; SourceRange ErrorRange; - SymbolRef ErrorSym = 0; + SymbolRef ErrorSym = nullptr; for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) { SVal V = CallOrMsg.getArgSVal(idx); @@ -2857,7 +2978,6 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ, } case RetEffect::GCNotOwnedSymbol: - case RetEffect::ARCNotOwnedSymbol: case RetEffect::NotOwnedSymbol: { const Expr *Ex = CallOrMsg.getOriginExpr(); SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol(); @@ -3053,22 +3173,22 @@ void RetainCountChecker::processNonLeakError(ProgramStateRef St, llvm_unreachable("Unhandled error."); case RefVal::ErrorUseAfterRelease: if (!useAfterRelease) - useAfterRelease.reset(new UseAfterRelease()); + useAfterRelease.reset(new UseAfterRelease(this)); BT = &*useAfterRelease; break; case RefVal::ErrorReleaseNotOwned: if (!releaseNotOwned) - releaseNotOwned.reset(new BadRelease()); + releaseNotOwned.reset(new BadRelease(this)); BT = &*releaseNotOwned; break; case RefVal::ErrorDeallocGC: if (!deallocGC) - deallocGC.reset(new DeallocGC()); + deallocGC.reset(new DeallocGC(this)); BT = &*deallocGC; break; case RefVal::ErrorDeallocNotOwned: if (!deallocNotOwned) - deallocNotOwned.reset(new DeallocNotOwned()); + deallocNotOwned.reset(new DeallocNotOwned(this)); BT = &*deallocNotOwned; break; } @@ -3135,7 +3255,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { if (RetVal.isUnknown()) { // If the receiver is unknown, conjure a return value. SValBuilder &SVB = C.getSValBuilder(); - RetVal = SVB.conjureSymbolVal(0, CE, LCtx, ResultTy, C.blockCount()); + RetVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount()); } state = state->BindExpr(CE, LCtx, RetVal, false); @@ -3144,7 +3264,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { if (const MemRegion *ArgRegion = RetVal.getAsRegion()) { // Save the refcount status of the argument. SymbolRef Sym = RetVal.getAsLocSymbol(); - const RefVal *Binding = 0; + const RefVal *Binding = nullptr; if (Sym) Binding = getRefBinding(state, Sym); @@ -3232,8 +3352,7 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S, return; // Update the autorelease counts. - static SimpleProgramPointTag - AutoreleaseTag("RetainCountChecker : Autorelease"); + static CheckerProgramPointTag AutoreleaseTag(this, "Autorelease"); state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X); // Did we cache out? @@ -3294,8 +3413,7 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, // Generate an error node. state = setRefBinding(state, Sym, X); - static SimpleProgramPointTag - ReturnOwnLeakTag("RetainCountChecker : ReturnsOwnLeak"); + static CheckerProgramPointTag ReturnOwnLeakTag(this, "ReturnsOwnLeak"); ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag); if (N) { const LangOptions &LOpts = C.getASTContext().getLangOpts(); @@ -3315,12 +3433,12 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, // owned object. state = setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned); - static SimpleProgramPointTag - ReturnNotOwnedTag("RetainCountChecker : ReturnNotOwnedForOwned"); + static CheckerProgramPointTag ReturnNotOwnedTag(this, + "ReturnNotOwnedForOwned"); ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag); if (N) { if (!returnNotOwnedForOwned) - returnNotOwnedForOwned.reset(new ReturnedNotOwnedForOwned()); + returnNotOwnedForOwned.reset(new ReturnedNotOwnedForOwned(this)); CFRefReport *report = new CFRefReport(*returnNotOwnedForOwned, @@ -3375,7 +3493,7 @@ void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S, // false positives. if (const VarRegion *LVR = dyn_cast_or_null<VarRegion>(loc.getAsRegion())) { const VarDecl *VD = LVR->getDecl(); - if (VD->getAttr<CleanupAttr>()) { + if (VD->hasAttr<CleanupAttr>()) { escapes = true; } } @@ -3508,7 +3626,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, os << "has a +" << V.getCount() << " retain count"; if (!overAutorelease) - overAutorelease.reset(new OverAutorelease()); + overAutorelease.reset(new OverAutorelease(this)); const LangOptions &LOpts = Ctx.getASTContext().getLangOpts(); CFRefReport *report = @@ -3517,7 +3635,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, Ctx.emitReport(report); } - return 0; + return nullptr; } ProgramStateRef @@ -3578,7 +3696,7 @@ void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const { } for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { - state = handleAutoreleaseCounts(state, Pred, /*Tag=*/0, Ctx, + state = handleAutoreleaseCounts(state, Pred, /*Tag=*/nullptr, Ctx, I->first, I->second); if (!state) return; @@ -3602,13 +3720,13 @@ void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const { const ProgramPointTag * RetainCountChecker::getDeadSymbolTag(SymbolRef sym) const { - const SimpleProgramPointTag *&tag = DeadSymbolTags[sym]; + const CheckerProgramPointTag *&tag = DeadSymbolTags[sym]; if (!tag) { SmallString<64> buf; llvm::raw_svector_ostream out(buf); - out << "RetainCountChecker : Dead Symbol : "; + out << "Dead Symbol : "; sym->dumpToStream(out); - tag = new SimpleProgramPointTag(out.str()); + tag = new CheckerProgramPointTag(this, out.str()); } return tag; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp index fe253b7..b1cde6b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp @@ -25,7 +25,8 @@ using namespace ento; namespace { class ReturnPointerRangeChecker : public Checker< check::PreStmt<ReturnStmt> > { - mutable OwningPtr<BuiltinBug> BT; + mutable std::unique_ptr<BuiltinBug> BT; + public: void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; }; @@ -69,9 +70,10 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS, // FIXME: This bug correspond to CWE-466. Eventually we should have bug // types explicitly reference such exploit categories (when applicable). if (!BT) - BT.reset(new BuiltinBug("Return of pointer value outside of expected range", - "Returned pointer value points outside the original object " - "(potential buffer overflow)")); + BT.reset(new BuiltinBug( + this, "Return of pointer value outside of expected range", + "Returned pointer value points outside the original object " + "(potential buffer overflow)")); // FIXME: It would be nice to eventually make this diagnostic more clear, // e.g., by referencing the original declaration or by saying *why* this diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp index ed96c40..6622313 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -25,8 +25,8 @@ using namespace ento; namespace { class ReturnUndefChecker : public Checker< check::PreStmt<ReturnStmt> > { - mutable OwningPtr<BuiltinBug> BT_Undef; - mutable OwningPtr<BuiltinBug> BT_NullReference; + mutable std::unique_ptr<BuiltinBug> BT_Undef; + mutable std::unique_ptr<BuiltinBug> BT_NullReference; void emitUndef(CheckerContext &C, const Expr *RetE) const; void checkReference(CheckerContext &C, const Expr *RetE, @@ -79,7 +79,7 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS, } static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE, - const Expr *TrackingE = 0) { + const Expr *TrackingE = nullptr) { ExplodedNode *N = C.generateSink(); if (!N) return; @@ -94,16 +94,16 @@ static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE, void ReturnUndefChecker::emitUndef(CheckerContext &C, const Expr *RetE) const { if (!BT_Undef) - BT_Undef.reset(new BuiltinBug("Garbage return value", - "Undefined or garbage value " - "returned to caller")); + BT_Undef.reset( + new BuiltinBug(this, "Garbage return value", + "Undefined or garbage value returned to caller")); emitBug(C, *BT_Undef, RetE); } void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE, DefinedOrUnknownSVal RetVal) const { ProgramStateRef StNonNull, StNull; - llvm::tie(StNonNull, StNull) = C.getState()->assume(RetVal); + std::tie(StNonNull, StNull) = C.getState()->assume(RetVal); if (StNonNull) { // Going forward, assume the location is non-null. @@ -113,7 +113,7 @@ void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE, // The return value is known to be null. Emit a bug report. if (!BT_NullReference) - BT_NullReference.reset(new BuiltinBug("Returning null reference")); + BT_NullReference.reset(new BuiltinBug(this, "Returning null reference")); emitBug(C, *BT_NullReference, RetE, bugreporter::getDerefExpr(RetE)); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/SelectorExtras.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/SelectorExtras.h new file mode 100644 index 0000000..48d96eb --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/SelectorExtras.h @@ -0,0 +1,68 @@ +//=== SelectorExtras.h - Helpers for checkers using selectors -----*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SA_CHECKERS_SELECTOREXTRAS +#define LLVM_CLANG_SA_CHECKERS_SELECTOREXTRAS + +#include "clang/AST/ASTContext.h" +#include <cstdarg> + +namespace clang { +namespace ento { + +static inline Selector getKeywordSelectorImpl(ASTContext &Ctx, + const char *First, + va_list argp) { + SmallVector<IdentifierInfo*, 10> II; + II.push_back(&Ctx.Idents.get(First)); + + while (const char *s = va_arg(argp, const char *)) + II.push_back(&Ctx.Idents.get(s)); + + return Ctx.Selectors.getSelector(II.size(), &II[0]); +} + +static inline Selector getKeywordSelector(ASTContext &Ctx, va_list argp) { + const char *First = va_arg(argp, const char *); + assert(First && "keyword selectors must have at least one argument"); + return getKeywordSelectorImpl(Ctx, First, argp); +} + +END_WITH_NULL +static inline Selector getKeywordSelector(ASTContext &Ctx, + const char *First, ...) { + va_list argp; + va_start(argp, First); + Selector result = getKeywordSelectorImpl(Ctx, First, argp); + va_end(argp); + return result; +} + +END_WITH_NULL +static inline void lazyInitKeywordSelector(Selector &Sel, ASTContext &Ctx, + const char *First, ...) { + if (!Sel.isNull()) + return; + va_list argp; + va_start(argp, First); + Sel = getKeywordSelectorImpl(Ctx, First, argp); + va_end(argp); +} + +static inline void lazyInitNullarySelector(Selector &Sel, ASTContext &Ctx, + const char *Name) { + if (!Sel.isNull()) + return; + Sel = GetNullarySelector(Name, Ctx); +} + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp index 9ca0ab5..3e9b57b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp @@ -54,8 +54,8 @@ class SimpleStreamChecker : public Checker<check::PostCall, mutable IdentifierInfo *IIfopen, *IIfclose; - OwningPtr<BugType> DoubleCloseBugType; - OwningPtr<BugType> LeakBugType; + std::unique_ptr<BugType> DoubleCloseBugType; + std::unique_ptr<BugType> LeakBugType; void initIdentifierInfo(ASTContext &Ctx) const; @@ -99,21 +99,21 @@ public: StopTrackingCallback(ProgramStateRef st) : state(st) {} ProgramStateRef getState() const { return state; } - bool VisitSymbol(SymbolRef sym) { + bool VisitSymbol(SymbolRef sym) override { state = state->remove<StreamMap>(sym); return true; } }; } // end anonymous namespace - -SimpleStreamChecker::SimpleStreamChecker() : IIfopen(0), IIfclose(0) { +SimpleStreamChecker::SimpleStreamChecker() + : IIfopen(nullptr), IIfclose(nullptr) { // Initialize the bug types. - DoubleCloseBugType.reset(new BugType("Double fclose", - "Unix Stream API Error")); + DoubleCloseBugType.reset( + new BugType(this, "Double fclose", "Unix Stream API Error")); - LeakBugType.reset(new BugType("Resource Leak", - "Unix Stream API Error")); + LeakBugType.reset( + new BugType(this, "Resource Leak", "Unix Stream API Error")); // Sinks are higher importance bugs as well as calls to assert() or exit(0). LeakBugType->setSuppressOnSink(true); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp index 4fd778e..327a9e0 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -28,8 +28,8 @@ using namespace ento; namespace { class StackAddrEscapeChecker : public Checker< check::PreStmt<ReturnStmt>, check::EndFunction > { - mutable OwningPtr<BuiltinBug> BT_stackleak; - mutable OwningPtr<BuiltinBug> BT_returnstack; + mutable std::unique_ptr<BuiltinBug> BT_stackleak; + mutable std::unique_ptr<BuiltinBug> BT_returnstack; public: void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; @@ -100,8 +100,8 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion * return; if (!BT_returnstack) - BT_returnstack.reset( - new BuiltinBug("Return of address to stack-allocated memory")); + BT_returnstack.reset( + new BuiltinBug(this, "Return of address to stack-allocated memory")); // Generate a report for this bug. SmallString<512> buf; @@ -177,8 +177,8 @@ void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const { {} bool HandleBinding(StoreManager &SMgr, Store store, - const MemRegion *region, SVal val) { - + const MemRegion *region, SVal val) override { + if (!isa<GlobalsSpaceRegion>(region->getMemorySpace())) return true; @@ -217,11 +217,11 @@ void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const { if (!BT_stackleak) BT_stackleak.reset( - new BuiltinBug("Stack address stored into global variable", - "Stack address was saved into a global variable. " - "This is dangerous because the address will become " - "invalid after returning from the function")); - + new BuiltinBug(this, "Stack address stored into global variable", + "Stack address was saved into a global variable. " + "This is dangerous because the address will become " + "invalid after returning from the function")); + for (unsigned i = 0, e = cb.V.size(); i != e; ++i) { // Generate a report for this bug. SmallString<512> buf; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index ffdf2d5..894765a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -62,14 +62,16 @@ class StreamChecker : public Checker<eval::Call, *II_fwrite, *II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos, *II_clearerr, *II_feof, *II_ferror, *II_fileno; - mutable OwningPtr<BuiltinBug> BT_nullfp, BT_illegalwhence, - BT_doubleclose, BT_ResourceLeak; + mutable std::unique_ptr<BuiltinBug> BT_nullfp, BT_illegalwhence, + BT_doubleclose, BT_ResourceLeak; public: StreamChecker() - : II_fopen(0), II_tmpfile(0) ,II_fclose(0), II_fread(0), II_fwrite(0), - II_fseek(0), II_ftell(0), II_rewind(0), II_fgetpos(0), II_fsetpos(0), - II_clearerr(0), II_feof(0), II_ferror(0), II_fileno(0) {} + : II_fopen(nullptr), II_tmpfile(nullptr), II_fclose(nullptr), + II_fread(nullptr), II_fwrite(nullptr), II_fseek(nullptr), + II_ftell(nullptr), II_rewind(nullptr), II_fgetpos(nullptr), + II_fsetpos(nullptr), II_clearerr(nullptr), II_feof(nullptr), + II_ferror(nullptr), II_fileno(nullptr) {} bool evalCall(const CallExpr *CE, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; @@ -210,7 +212,8 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const { ProgramStateRef state = C.getState(); SValBuilder &svalBuilder = C.getSValBuilder(); const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); - DefinedSVal RetVal = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount()) + DefinedSVal RetVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, + C.blockCount()) .castAs<DefinedSVal>(); state = state->BindExpr(CE, C.getLocationContext(), RetVal); @@ -218,7 +221,7 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const { // Bifurcate the state into two: one with a valid FILE* pointer, the other // with a NULL. ProgramStateRef stateNotNull, stateNull; - llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal); + std::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal); if (SymbolRef Sym = RetVal.getAsSymbol()) { // if RetVal is not NULL, set the symbol's state to Opened. @@ -270,9 +273,10 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const { if (ExplodedNode *N = C.addTransition(state)) { if (!BT_illegalwhence) - BT_illegalwhence.reset(new BuiltinBug("Illegal whence argument", - "The whence argument to fseek() should be " - "SEEK_SET, SEEK_END, or SEEK_CUR.")); + BT_illegalwhence.reset( + new BuiltinBug(this, "Illegal whence argument", + "The whence argument to fseek() should be " + "SEEK_SET, SEEK_END, or SEEK_CUR.")); BugReport *R = new BugReport(*BT_illegalwhence, BT_illegalwhence->getDescription(), N); C.emitReport(R); @@ -339,21 +343,21 @@ ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state, CheckerContext &C) const { Optional<DefinedSVal> DV = SV.getAs<DefinedSVal>(); if (!DV) - return 0; + return nullptr; ConstraintManager &CM = C.getConstraintManager(); ProgramStateRef stateNotNull, stateNull; - llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); + std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); if (!stateNotNull && stateNull) { if (ExplodedNode *N = C.generateSink(stateNull)) { if (!BT_nullfp) - BT_nullfp.reset(new BuiltinBug("NULL stream pointer", - "Stream pointer might be NULL.")); + BT_nullfp.reset(new BuiltinBug(this, "NULL stream pointer", + "Stream pointer might be NULL.")); BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N); C.emitReport(R); } - return 0; + return nullptr; } return stateNotNull; } @@ -378,14 +382,14 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE, ExplodedNode *N = C.generateSink(); if (N) { if (!BT_doubleclose) - BT_doubleclose.reset(new BuiltinBug("Double fclose", - "Try to close a file Descriptor already" - " closed. Cause undefined behaviour.")); + BT_doubleclose.reset(new BuiltinBug( + this, "Double fclose", "Try to close a file Descriptor already" + " closed. Cause undefined behaviour.")); BugReport *R = new BugReport(*BT_doubleclose, BT_doubleclose->getDescription(), N); C.emitReport(R); } - return NULL; + return nullptr; } // Close the File Descriptor. @@ -407,8 +411,9 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, ExplodedNode *N = C.generateSink(); if (N) { if (!BT_ResourceLeak) - BT_ResourceLeak.reset(new BuiltinBug("Resource Leak", - "Opened File never closed. Potential Resource leak.")); + BT_ResourceLeak.reset(new BuiltinBug( + this, "Resource Leak", + "Opened File never closed. Potential Resource leak.")); BugReport *R = new BugReport(*BT_ResourceLeak, BT_ResourceLeak->getDescription(), N); C.emitReport(R); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp index 264f7f9..d33c977 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp @@ -22,7 +22,7 @@ using namespace ento; namespace { class TaintTesterChecker : public Checker< check::PostStmt<Expr> > { - mutable OwningPtr<BugType> BT; + mutable std::unique_ptr<BugType> BT; void initBugType() const; /// Given a pointer argument, get the symbol of the value it contains @@ -38,7 +38,7 @@ public: inline void TaintTesterChecker::initBugType() const { if (!BT) - BT.reset(new BugType("Tainted data", "General")); + BT.reset(new BugType(this, "Tainted data", "General")); } void TaintTesterChecker::checkPostStmt(const Expr *E, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp new file mode 100644 index 0000000..dad5c0d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp @@ -0,0 +1,264 @@ +//== TestAfterDivZeroChecker.cpp - Test after division by zero checker --*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines TestAfterDivZeroChecker, a builtin check that performs checks +// for division by zero where the division occurs before comparison with zero. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "llvm/ADT/FoldingSet.h" + +using namespace clang; +using namespace ento; + +namespace { + +class ZeroState { +private: + SymbolRef ZeroSymbol; + unsigned BlockID; + const StackFrameContext *SFC; + +public: + ZeroState(SymbolRef S, unsigned B, const StackFrameContext *SFC) + : ZeroSymbol(S), BlockID(B), SFC(SFC) {} + + const StackFrameContext *getStackFrameContext() const { return SFC; } + + bool operator==(const ZeroState &X) const { + return BlockID == X.BlockID && SFC == X.SFC && ZeroSymbol == X.ZeroSymbol; + } + + bool operator<(const ZeroState &X) const { + if (BlockID != X.BlockID) + return BlockID < X.BlockID; + if (SFC != X.SFC) + return SFC < X.SFC; + return ZeroSymbol < X.ZeroSymbol; + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(BlockID); + ID.AddPointer(SFC); + ID.AddPointer(ZeroSymbol); + } +}; + +class DivisionBRVisitor : public BugReporterVisitorImpl<DivisionBRVisitor> { +private: + SymbolRef ZeroSymbol; + const StackFrameContext *SFC; + bool Satisfied; + +public: + DivisionBRVisitor(SymbolRef ZeroSymbol, const StackFrameContext *SFC) + : ZeroSymbol(ZeroSymbol), SFC(SFC), Satisfied(false) {} + + void Profile(llvm::FoldingSetNodeID &ID) const override { + ID.Add(ZeroSymbol); + ID.Add(SFC); + } + + PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ, + const ExplodedNode *Pred, + BugReporterContext &BRC, + BugReport &BR) override; +}; + +class TestAfterDivZeroChecker + : public Checker<check::PreStmt<BinaryOperator>, check::BranchCondition, + check::EndFunction> { + mutable std::unique_ptr<BuiltinBug> DivZeroBug; + void reportBug(SVal Val, CheckerContext &C) const; + +public: + void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; + void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const; + void checkEndFunction(CheckerContext &C) const; + void setDivZeroMap(SVal Var, CheckerContext &C) const; + bool hasDivZeroMap(SVal Var, const CheckerContext &C) const; + bool isZero(SVal S, CheckerContext &C) const; +}; +} // end anonymous namespace + +REGISTER_SET_WITH_PROGRAMSTATE(DivZeroMap, ZeroState) + +PathDiagnosticPiece *DivisionBRVisitor::VisitNode(const ExplodedNode *Succ, + const ExplodedNode *Pred, + BugReporterContext &BRC, + BugReport &BR) { + if (Satisfied) + return nullptr; + + const Expr *E = nullptr; + + if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>()) + if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) { + BinaryOperator::Opcode Op = BO->getOpcode(); + if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign || + Op == BO_RemAssign) { + E = BO->getRHS(); + } + } + + if (!E) + return nullptr; + + ProgramStateRef State = Succ->getState(); + SVal S = State->getSVal(E, Succ->getLocationContext()); + if (ZeroSymbol == S.getAsSymbol() && SFC == Succ->getStackFrame()) { + Satisfied = true; + + // Construct a new PathDiagnosticPiece. + ProgramPoint P = Succ->getLocation(); + PathDiagnosticLocation L = + PathDiagnosticLocation::create(P, BRC.getSourceManager()); + + if (!L.isValid() || !L.asLocation().isValid()) + return nullptr; + + return new PathDiagnosticEventPiece( + L, "Division with compared value made here"); + } + + return nullptr; +} + +bool TestAfterDivZeroChecker::isZero(SVal S, CheckerContext &C) const { + Optional<DefinedSVal> DSV = S.getAs<DefinedSVal>(); + + if (!DSV) + return false; + + ConstraintManager &CM = C.getConstraintManager(); + return !CM.assume(C.getState(), *DSV, true); +} + +void TestAfterDivZeroChecker::setDivZeroMap(SVal Var, CheckerContext &C) const { + SymbolRef SR = Var.getAsSymbol(); + if (!SR) + return; + + ProgramStateRef State = C.getState(); + State = + State->add<DivZeroMap>(ZeroState(SR, C.getBlockID(), C.getStackFrame())); + C.addTransition(State); +} + +bool TestAfterDivZeroChecker::hasDivZeroMap(SVal Var, + const CheckerContext &C) const { + SymbolRef SR = Var.getAsSymbol(); + if (!SR) + return false; + + ZeroState ZS(SR, C.getBlockID(), C.getStackFrame()); + return C.getState()->contains<DivZeroMap>(ZS); +} + +void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const { + if (ExplodedNode *N = C.generateSink(C.getState())) { + if (!DivZeroBug) + DivZeroBug.reset(new BuiltinBug(this, "Division by zero")); + + BugReport *R = + new BugReport(*DivZeroBug, "Value being compared against zero has " + "already been used for division", + N); + + R->addVisitor(new DivisionBRVisitor(Val.getAsSymbol(), C.getStackFrame())); + C.emitReport(R); + } +} + +void TestAfterDivZeroChecker::checkEndFunction(CheckerContext &C) const { + ProgramStateRef State = C.getState(); + + DivZeroMapTy DivZeroes = State->get<DivZeroMap>(); + if (DivZeroes.isEmpty()) + return; + + DivZeroMapTy::Factory &F = State->get_context<DivZeroMap>(); + for (llvm::ImmutableSet<ZeroState>::iterator I = DivZeroes.begin(), + E = DivZeroes.end(); + I != E; ++I) { + ZeroState ZS = *I; + if (ZS.getStackFrameContext() == C.getStackFrame()) + DivZeroes = F.remove(DivZeroes, ZS); + } + C.addTransition(State->set<DivZeroMap>(DivZeroes)); +} + +void TestAfterDivZeroChecker::checkPreStmt(const BinaryOperator *B, + CheckerContext &C) const { + BinaryOperator::Opcode Op = B->getOpcode(); + if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign || + Op == BO_RemAssign) { + SVal S = C.getSVal(B->getRHS()); + + if (!isZero(S, C)) + setDivZeroMap(S, C); + } +} + +void TestAfterDivZeroChecker::checkBranchCondition(const Stmt *Condition, + CheckerContext &C) const { + if (const BinaryOperator *B = dyn_cast<BinaryOperator>(Condition)) { + if (B->isComparisonOp()) { + const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(B->getRHS()); + bool LRHS = true; + if (!IntLiteral) { + IntLiteral = dyn_cast<IntegerLiteral>(B->getLHS()); + LRHS = false; + } + + if (!IntLiteral || IntLiteral->getValue() != 0) + return; + + SVal Val = C.getSVal(LRHS ? B->getLHS() : B->getRHS()); + if (hasDivZeroMap(Val, C)) + reportBug(Val, C); + } + } else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(Condition)) { + if (U->getOpcode() == UO_LNot) { + SVal Val; + if (const ImplicitCastExpr *I = + dyn_cast<ImplicitCastExpr>(U->getSubExpr())) + Val = C.getSVal(I->getSubExpr()); + + if (hasDivZeroMap(Val, C)) + reportBug(Val, C); + else { + Val = C.getSVal(U->getSubExpr()); + if (hasDivZeroMap(Val, C)) + reportBug(Val, C); + } + } + } else if (const ImplicitCastExpr *IE = + dyn_cast<ImplicitCastExpr>(Condition)) { + SVal Val = C.getSVal(IE->getSubExpr()); + + if (hasDivZeroMap(Val, C)) + reportBug(Val, C); + else { + SVal Val = C.getSVal(Condition); + + if (hasDivZeroMap(Val, C)) + reportBug(Val, C); + } + } +} + +void ento::registerTestAfterDivZeroChecker(CheckerManager &mgr) { + mgr.registerChecker<TestAfterDivZeroChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp index 57c9ed4..d02d2df 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp @@ -72,7 +72,7 @@ public: void CallDumper::checkPreCall(const CallEvent &Call, CheckerContext &C) const { unsigned Indentation = 0; for (const LocationContext *LC = C.getLocationContext()->getParent(); - LC != 0; LC = LC->getParent()) + LC != nullptr; LC = LC->getParent()) ++Indentation; // It is mildly evil to print directly to llvm::outs() rather than emitting @@ -89,7 +89,7 @@ void CallDumper::checkPostCall(const CallEvent &Call, CheckerContext &C) const { unsigned Indentation = 0; for (const LocationContext *LC = C.getLocationContext()->getParent(); - LC != 0; LC = LC->getParent()) + LC != nullptr; LC = LC->getParent()) ++Indentation; // It is mildly evil to print directly to llvm::outs() rather than emitting diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp index 8235e68..fc49a46 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp @@ -24,7 +24,7 @@ using namespace ento; namespace { class UndefBranchChecker : public Checker<check::BranchCondition> { - mutable OwningPtr<BuiltinBug> BT; + mutable std::unique_ptr<BuiltinBug> BT; struct FindUndefExpr { ProgramStateRef St; @@ -35,7 +35,7 @@ class UndefBranchChecker : public Checker<check::BranchCondition> { const Expr *FindExpr(const Expr *Ex) { if (!MatchesCriteria(Ex)) - return 0; + return nullptr; for (Stmt::const_child_iterator I = Ex->child_begin(), E = Ex->child_end();I!=E;++I) @@ -67,8 +67,8 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition, ExplodedNode *N = Ctx.generateSink(); if (N) { if (!BT) - BT.reset( - new BuiltinBug("Branch condition evaluates to a garbage value")); + BT.reset(new BuiltinBug( + this, "Branch condition evaluates to a garbage value")); // What's going on here: we want to highlight the subexpression of the // condition that is the most likely source of the "uninitialized diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp index 93812f7..93687db 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp @@ -27,7 +27,7 @@ using namespace ento; namespace { class UndefCapturedBlockVarChecker : public Checker< check::PostStmt<BlockExpr> > { - mutable OwningPtr<BugType> BT; + mutable std::unique_ptr<BugType> BT; public: void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; @@ -48,7 +48,7 @@ static const DeclRefExpr *FindBlockDeclRefExpr(const Stmt *S, return BR; } - return NULL; + return nullptr; } void @@ -71,7 +71,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE, const VarRegion *VR = I.getCapturedRegion(); const VarDecl *VD = VR->getDecl(); - if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage()) + if (VD->hasAttr<BlocksAttr>() || !VD->hasLocalStorage()) continue; // Get the VarRegion associated with VD in the local stack frame. @@ -79,7 +79,8 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE, state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) { if (ExplodedNode *N = C.generateSink()) { if (!BT) - BT.reset(new BuiltinBug("uninitialized variable captured by block")); + BT.reset( + new BuiltinBug(this, "uninitialized variable captured by block")); // Generate a bug report. SmallString<128> buf; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp index 3f6549d..f3f4dce 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -28,8 +28,8 @@ namespace { class UndefResultChecker : public Checker< check::PostStmt<BinaryOperator> > { - mutable OwningPtr<BugType> BT; - + mutable std::unique_ptr<BugType> BT; + public: void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const; }; @@ -55,11 +55,12 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B, return; if (!BT) - BT.reset(new BuiltinBug("Result of operation is garbage or undefined")); + BT.reset( + new BuiltinBug(this, "Result of operation is garbage or undefined")); SmallString<256> sbuf; llvm::raw_svector_ostream OS(sbuf); - const Expr *Ex = NULL; + const Expr *Ex = nullptr; bool isLeft = true; if (state->getSVal(B->getLHS(), LCtx).isUndef()) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp index 5df8846..e952671 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp @@ -25,7 +25,7 @@ using namespace ento; namespace { class UndefinedArraySubscriptChecker : public Checker< check::PreStmt<ArraySubscriptExpr> > { - mutable OwningPtr<BugType> BT; + mutable std::unique_ptr<BugType> BT; public: void checkPreStmt(const ArraySubscriptExpr *A, CheckerContext &C) const; @@ -50,7 +50,7 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A, if (!N) return; if (!BT) - BT.reset(new BuiltinBug("Array subscript is undefined")); + BT.reset(new BuiltinBug(this, "Array subscript is undefined")); // Generate a report for this bug. BugReport *R = new BugReport(*BT, BT->getName(), N); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp index 016e3c8..bd4493d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -24,7 +24,7 @@ using namespace ento; namespace { class UndefinedAssignmentChecker : public Checker<check::Bind> { - mutable OwningPtr<BugType> BT; + mutable std::unique_ptr<BugType> BT; public: void checkBind(SVal location, SVal val, const Stmt *S, @@ -54,10 +54,10 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, const char *str = "Assigned value is garbage or undefined"; if (!BT) - BT.reset(new BuiltinBug(str)); + BT.reset(new BuiltinBug(this, str)); // Generate a report for this bug. - const Expr *ex = 0; + const Expr *ex = nullptr; while (StoreE) { if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp index 4ea07e2..4887d80 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -30,7 +30,7 @@ using namespace ento; namespace { class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > { - mutable OwningPtr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero; + mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero; mutable Optional<uint64_t> Val_O_CREAT; public: @@ -57,21 +57,15 @@ private: const unsigned numArgs, const unsigned sizeArg, const char *fn) const; + void LazyInitialize(std::unique_ptr<BugType> &BT, const char *name) const { + if (BT) + return; + BT.reset(new BugType(this, name, categories::UnixAPI)); + } }; } //end anonymous namespace //===----------------------------------------------------------------------===// -// Utility functions. -//===----------------------------------------------------------------------===// - -static inline void LazyInitialize(OwningPtr<BugType> &BT, - const char *name) { - if (BT) - return; - BT.reset(new BugType(name, categories::UnixAPI)); -} - -//===----------------------------------------------------------------------===// // "open" (man 2 open) //===----------------------------------------------------------------------===// @@ -86,6 +80,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const { // FIXME: We need a more general way of getting the O_CREAT value. // We could possibly grovel through the preprocessor state, but // that would require passing the Preprocessor object to the ExprEngine. + // See also: MallocChecker.cpp / M_ZERO. return; } } @@ -119,7 +114,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const { // Check if maskedFlags is non-zero. ProgramStateRef trueState, falseState; - llvm::tie(trueState, falseState) = state->assume(maskedFlags); + std::tie(trueState, falseState) = state->assume(maskedFlags); // Only emit an error if the value of 'maskedFlags' is properly // constrained; @@ -199,7 +194,7 @@ static bool IsZeroByteAllocation(ProgramStateRef state, const SVal argVal, ProgramStateRef *trueState, ProgramStateRef *falseState) { - llvm::tie(*trueState, *falseState) = + std::tie(*trueState, *falseState) = state->assume(argVal.castAs<DefinedSVal>()); return (*falseState && !*trueState); @@ -207,7 +202,7 @@ static bool IsZeroByteAllocation(ProgramStateRef state, // Generates an error report, indicating that the function whose name is given // will perform a zero byte allocation. -// Returns false if an error occured, true otherwise. +// Returns false if an error occurred, true otherwise. bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C, ProgramStateRef falseState, const Expr *arg, @@ -217,7 +212,7 @@ bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C, return false; LazyInitialize(BT_mallocZero, - "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)"); + "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)"); SmallString<256> S; llvm::raw_svector_ostream os(S); @@ -244,7 +239,7 @@ void UnixAPIChecker::BasicAllocationCheck(CheckerContext &C, // Check if the allocation size is 0. ProgramStateRef state = C.getState(); - ProgramStateRef trueState = NULL, falseState = NULL; + ProgramStateRef trueState = nullptr, falseState = nullptr; const Expr *arg = CE->getArg(sizeArg); SVal argVal = state->getSVal(arg, C.getLocationContext()); @@ -269,7 +264,7 @@ void UnixAPIChecker::CheckCallocZero(CheckerContext &C, return; ProgramStateRef state = C.getState(); - ProgramStateRef trueState = NULL, falseState = NULL; + ProgramStateRef trueState = nullptr, falseState = nullptr; unsigned int i; for (i = 0; i < nArgs; i++) { @@ -348,7 +343,7 @@ void UnixAPIChecker::checkPreStmt(const CallExpr *CE, .Case("reallocf", &UnixAPIChecker::CheckReallocfZero) .Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero) .Case("valloc", &UnixAPIChecker::CheckVallocZero) - .Default(NULL); + .Default(nullptr); if (SC) (this->*SC)(C, CE); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp index a40b5a3..d78de3c 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp @@ -58,10 +58,10 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, if (Eng.hasWorkRemaining()) return; - const Decl *D = 0; - CFG *C = 0; - ParentMap *PM = 0; - const LocationContext *LC = 0; + const Decl *D = nullptr; + CFG *C = nullptr; + ParentMap *PM = nullptr; + const LocationContext *LC = nullptr; // Iterate over ExplodedGraph for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end(); I != E; ++I) { @@ -136,7 +136,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, ci != ce; ++ci) { if (Optional<CFGStmt> S = (*ci).getAs<CFGStmt>()) if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) { - if (CE->isBuiltinCall() == Builtin::BI__builtin_unreachable) { + if (CE->getBuiltinCallee() == Builtin::BI__builtin_unreachable) { foundUnreachable = true; break; } @@ -165,7 +165,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL)) continue; - B.EmitBasicReport(D, "Unreachable code", "Dead code", + B.EmitBasicReport(D, this, "Unreachable code", "Dead code", "This statement is never executed", DL, SR); } } @@ -178,6 +178,9 @@ void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB, for (CFGBlock::const_pred_iterator I = CB->pred_begin(), E = CB->pred_end(); I != E; ++I) { + if (!*I) + continue; + if (!reachable.count((*I)->getBlockID())) { // If we find an unreachable predecessor, mark this block as reachable so // we don't report this block @@ -198,7 +201,7 @@ const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) { if (const Stmt *S = CB->getTerminator()) return S; else - return 0; + return nullptr; } // Determines if the path to this CFGBlock contained an element that infers this @@ -219,6 +222,8 @@ bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB, return false; const CFGBlock *pred = *CB->pred_begin(); + if (!pred) + return false; // Get the predecessor block's terminator conditon const Stmt *cond = pred->getTerminatorCondition(); @@ -240,9 +245,9 @@ bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB, // Returns true if the given CFGBlock is empty bool UnreachableCodeChecker::isEmptyCFGBlock(const CFGBlock *CB) { - return CB->getLabel() == 0 // No labels + return CB->getLabel() == nullptr // No labels && CB->size() == 0 // No statements - && CB->getTerminator() == 0; // No terminator + && !CB->getTerminator(); // No terminator } void ento::registerUnreachableCodeChecker(CheckerManager &mgr) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp index 30aef06..198a628 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp @@ -29,7 +29,7 @@ using namespace ento; namespace { class VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > { - mutable OwningPtr<BugType> BT; + mutable std::unique_ptr<BugType> BT; enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted }; void reportBug(VLASize_Kind Kind, @@ -51,7 +51,8 @@ void VLASizeChecker::reportBug(VLASize_Kind Kind, return; if (!BT) - BT.reset(new BuiltinBug("Dangerous variable-length array (VLA) declaration")); + BT.reset(new BuiltinBug( + this, "Dangerous variable-length array (VLA) declaration")); SmallString<256> buf; llvm::raw_svector_ostream os(buf); @@ -105,7 +106,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { // Check if the size is tainted. if (state->isTainted(sizeV)) { - reportBug(VLA_Tainted, SE, 0, C); + reportBug(VLA_Tainted, SE, nullptr, C); return; } @@ -113,7 +114,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { DefinedSVal sizeD = sizeV.castAs<DefinedSVal>(); ProgramStateRef stateNotZero, stateZero; - llvm::tie(stateNotZero, stateZero) = state->assume(sizeD); + std::tie(stateNotZero, stateZero) = state->assume(sizeD); if (stateZero && !stateNotZero) { reportBug(VLA_Zero, SE, stateZero, C); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp index 7b6adbf..f8f5cf9 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp @@ -28,6 +28,7 @@ using namespace ento; namespace { class WalkAST : public StmtVisitor<WalkAST> { + const CheckerBase *Checker; BugReporter &BR; AnalysisDeclContext *AC; @@ -58,11 +59,10 @@ class WalkAST : public StmtVisitor<WalkAST> { const CallExpr *visitingCallExpr; public: - WalkAST(BugReporter &br, AnalysisDeclContext *ac) - : BR(br), - AC(ac), - visitingCallExpr(0) {} - + WalkAST(const CheckerBase *checker, BugReporter &br, + AnalysisDeclContext *ac) + : Checker(checker), BR(br), AC(ac), visitingCallExpr(nullptr) {} + bool hasWork() const { return !WList.empty(); } /// This method adds a CallExpr to the worklist and marks the callee as @@ -187,21 +187,19 @@ void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) { if (isPure) { os << "\n" << "Call pure virtual functions during construction or " << "destruction may leads undefined behaviour"; - BR.EmitBasicReport(AC->getDecl(), + BR.EmitBasicReport(AC->getDecl(), Checker, "Call pure virtual function during construction or " "Destruction", - "Cplusplus", - os.str(), CELoc, R); + "Cplusplus", os.str(), CELoc, R); return; } else { os << "\n" << "Call virtual functions during construction or " << "destruction will never go to a more derived class"; - BR.EmitBasicReport(AC->getDecl(), + BR.EmitBasicReport(AC->getDecl(), Checker, "Call virtual function during construction or " "Destruction", - "Cplusplus", - os.str(), CELoc, R); + "Cplusplus", os.str(), CELoc, R); return; } } @@ -215,11 +213,10 @@ class VirtualCallChecker : public Checker<check::ASTDecl<CXXRecordDecl> > { public: void checkASTDecl(const CXXRecordDecl *RD, AnalysisManager& mgr, BugReporter &BR) const { - WalkAST walker(BR, mgr.getAnalysisDeclContext(RD)); + WalkAST walker(this, BR, mgr.getAnalysisDeclContext(RD)); // Check the constructors. - for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(), E = RD->ctor_end(); - I != E; ++I) { + for (const auto *I : RD->ctors()) { if (!I->isCopyOrMoveConstructor()) if (Stmt *Body = I->getBody()) { walker.Visit(Body); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index 9dcf58b..7944c7e 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -39,7 +39,7 @@ IPAKind AnalyzerOptions::getIPAMode() { // Use the User Mode to set the default IPA value. // Note, we have to add the string to the Config map for the ConfigDumper // checker to function properly. - const char *DefaultIPA = 0; + const char *DefaultIPA = nullptr; UserModeKind HighLevelMode = getUserMode(); if (HighLevelMode == UMK_Shallow) DefaultIPA = "inlining"; @@ -134,8 +134,14 @@ bool AnalyzerOptions::mayInlineTemplateFunctions() { /*Default=*/true); } -bool AnalyzerOptions::mayInlineCXXContainerCtorsAndDtors() { - return getBooleanOption(InlineCXXContainerCtorsAndDtors, +bool AnalyzerOptions::mayInlineCXXAllocator() { + return getBooleanOption(InlineCXXAllocator, + "c++-allocator-inlining", + /*Default=*/false); +} + +bool AnalyzerOptions::mayInlineCXXContainerMethods() { + return getBooleanOption(InlineCXXContainerMethods, "c++-container-inlining", /*Default=*/false); } @@ -183,6 +189,13 @@ bool AnalyzerOptions::shouldReportIssuesInMainSourceFile() { /* Default = */ false); } + +bool AnalyzerOptions::shouldWriteStableReportFilename() { + return getBooleanOption(StableReportFilename, + "stable-report-filename", + /* Default = */ false); +} + int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) { SmallString<10> StrBuf; llvm::raw_svector_ostream OS(StrBuf); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp index a6c400f..0e90566 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp @@ -173,12 +173,12 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, // FIXME: Expand these checks to include all undefined behavior. if (V2.isSigned() && V2.isNegative()) - return NULL; + return nullptr; uint64_t Amt = V2.getZExtValue(); - if (Amt > V1.getBitWidth()) - return NULL; + if (Amt >= V1.getBitWidth()) + return nullptr; return &getValue( V1.operator<<( (unsigned) Amt )); } @@ -191,12 +191,12 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, // FIXME: Expand these checks to include all undefined behavior. if (V2.isSigned() && V2.isNegative()) - return NULL; + return nullptr; uint64_t Amt = V2.getZExtValue(); - if (Amt > V1.getBitWidth()) - return NULL; + if (Amt >= V1.getBitWidth()) + return nullptr; return &getValue( V1.operator>>( (unsigned) Amt )); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BlockCounter.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BlockCounter.cpp index 74d761e..c1ac03d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BlockCounter.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BlockCounter.cpp @@ -34,8 +34,7 @@ public: } bool operator<(const CountKey &RHS) const { - return (CallSite == RHS.CallSite) ? (BlockID < RHS.BlockID) - : (CallSite < RHS.CallSite); + return std::tie(CallSite, BlockID) < std::tie(RHS.CallSite, RHS.BlockID); } void Profile(llvm::FoldingSetNodeID &ID) const { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index 1940fa7..141a48b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -12,16 +12,14 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "BugReporter" - #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ParentMap.h" -#include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/ProgramPoint.h" #include "clang/Basic/SourceManager.h" @@ -30,16 +28,18 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/raw_ostream.h" +#include <memory> #include <queue> using namespace clang; using namespace ento; +#define DEBUG_TYPE "BugReporter" + STATISTIC(MaxBugClassSize, "The maximum number of bug reports in the same equivalence class"); STATISTIC(MaxValidBugClassSize, @@ -59,7 +59,7 @@ static const Stmt *GetPreviousStmt(const ExplodedNode *N) { if (const Stmt *S = PathDiagnosticLocation::getStmt(N)) return S; - return 0; + return nullptr; } static inline const Stmt* @@ -83,15 +83,15 @@ eventsDescribeSameCondition(PathDiagnosticEventPiece *X, const void *tagLesser = TrackConstraintBRVisitor::getTag(); if (X->getLocation() != Y->getLocation()) - return 0; - + return nullptr; + if (X->getTag() == tagPreferred && Y->getTag() == tagLesser) return X; if (Y->getTag() == tagPreferred && X->getTag() == tagLesser) return Y; - - return 0; + + return nullptr; } /// An optimization pass over PathPieces that removes redundant diagnostics @@ -125,7 +125,7 @@ static void removeRedundantMsgs(PathPieces &path) { break; if (PathDiagnosticEventPiece *nextEvent = - dyn_cast<PathDiagnosticEventPiece>(path.front().getPtr())) { + dyn_cast<PathDiagnosticEventPiece>(path.front().get())) { PathDiagnosticEventPiece *event = cast<PathDiagnosticEventPiece>(piece); // Check to see if we should keep one of the two pieces. If we @@ -214,8 +214,9 @@ static bool hasImplicitBody(const Decl *D) { /// Recursively scan through a path and make sure that all call pieces have /// valid locations. -static void adjustCallLocations(PathPieces &Pieces, - PathDiagnosticLocation *LastCallLocation = 0) { +static void +adjustCallLocations(PathPieces &Pieces, + PathDiagnosticLocation *LastCallLocation = nullptr) { for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E; ++I) { PathDiagnosticCallPiece *Call = dyn_cast<PathDiagnosticCallPiece>(*I); @@ -265,7 +266,7 @@ static void removeEdgesToDefaultInitializers(PathPieces &Pieces) { I = Pieces.erase(I); continue; } else if (End && isa<CXXDefaultInitExpr>(End)) { - PathPieces::iterator Next = llvm::next(I); + PathPieces::iterator Next = std::next(I); if (Next != E) { if (PathDiagnosticControlFlowPiece *NextCF = dyn_cast<PathDiagnosticControlFlowPiece>(*Next)) { @@ -311,7 +312,7 @@ class NodeMapClosure : public BugReport::NodeResolver { public: NodeMapClosure(InterExplodedGraphMap &m) : M(m) {} - const ExplodedNode *getOriginalNode(const ExplodedNode *N) { + const ExplodedNode *getOriginalNode(const ExplodedNode *N) override { return M.lookup(N); } }; @@ -345,7 +346,7 @@ public: return getParentMap().getParent(S); } - virtual NodeMapClosure& getNodeResolver() { return NMC; } + NodeMapClosure& getNodeResolver() override { return NMC; } PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S); @@ -405,7 +406,7 @@ static const Stmt *getEnclosingParent(const Stmt *S, const ParentMap &PM) { const Stmt *Parent = PM.getParentIgnoreParens(S); if (!Parent) - return 0; + return nullptr; switch (Parent->getStmtClass()) { case Stmt::ForStmtClass: @@ -418,7 +419,7 @@ static const Stmt *getEnclosingParent(const Stmt *S, const ParentMap &PM) { break; } - return 0; + return nullptr; } static PathDiagnosticLocation @@ -564,7 +565,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD, SourceManager& SMgr = PDB.getSourceManager(); const LocationContext *LC = PDB.LC; const ExplodedNode *NextNode = N->pred_empty() - ? NULL : *(N->pred_begin()); + ? nullptr : *(N->pred_begin()); StackDiagVector CallStack; @@ -1263,8 +1264,8 @@ static void reversePropagateIntererstingSymbols(BugReport &R, SVal ChildV = State->getSVal(child, LCtx); R.markInteresting(ChildV); } - break; } + break; } } @@ -1351,11 +1352,11 @@ static const Stmt *getStmtBeforeCond(ParentMap &PM, const Stmt *Term, } N = N->getFirstPred(); } - return 0; + return nullptr; } static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) { - const Stmt *LoopBody = 0; + const Stmt *LoopBody = nullptr; switch (Term->getStmtClass()) { case Stmt::CXXForRangeStmtClass: { const CXXForRangeStmt *FR = cast<CXXForRangeStmt>(Term); @@ -1401,7 +1402,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, StackDiagVector CallStack; InterestingExprs IE; - const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin()); + const ExplodedNode *NextNode = N->pred_empty() ? nullptr : *(N->pred_begin()); while (NextNode) { N = NextNode; NextNode = N->getFirstPred(); @@ -1411,7 +1412,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, if (Optional<PostStmt> PS = P.getAs<PostStmt>()) { if (const Expr *Ex = PS->getStmtAs<Expr>()) reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, - N->getState().getPtr(), Ex, + N->getState().get(), Ex, N->getLocationContext()); } @@ -1419,7 +1420,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, const Stmt *S = CE->getCalleeContext()->getCallSite(); if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) { reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, - N->getState().getPtr(), Ex, + N->getState().get(), Ex, N->getLocationContext()); } @@ -1490,7 +1491,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, const LocationContext *CalleeCtx = PDB.LC; if (CallerCtx != CalleeCtx) { reversePropagateInterestingSymbols(*PDB.getBugReport(), IE, - N->getState().getPtr(), + N->getState().get(), CalleeCtx, CallerCtx); } } @@ -1498,7 +1499,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, // Are we jumping to the head of a loop? Add a special diagnostic. if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) { PathDiagnosticLocation L(Loop, SM, PDB.LC); - const CompoundStmt *CS = NULL; + const CompoundStmt *CS = nullptr; if (const ForStmt *FS = dyn_cast<ForStmt>(Loop)) CS = dyn_cast<CompoundStmt>(FS->getBody()); @@ -1673,7 +1674,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, PathDiagnosticCallPiece *C; if (VisitedEntireCall) { - PathDiagnosticPiece *P = PD.getActivePath().front().getPtr(); + PathDiagnosticPiece *P = PD.getActivePath().front().get(); C = cast<PathDiagnosticCallPiece>(P); } else { const Decl *Caller = CE->getLocationContext()->getDecl(); @@ -1683,11 +1684,11 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, // reset the mapping from active to location context. assert(PD.getActivePath().size() == 1 && PD.getActivePath().front() == C); - LCM[&PD.getActivePath()] = 0; + LCM[&PD.getActivePath()] = nullptr; // Record the location context mapping for the path within // the call. - assert(LCM[&C->path] == 0 || + assert(LCM[&C->path] == nullptr || LCM[&C->path] == CE->getCalleeContext()); LCM[&C->path] = CE->getCalleeContext(); @@ -1727,7 +1728,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, // Propagate the interesting symbols accordingly. if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) { reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, - N->getState().getPtr(), Ex, + N->getState().get(), Ex, N->getLocationContext()); } @@ -1755,7 +1756,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, // interesting symbols correctly. if (const Expr *Ex = PS->getStmtAs<Expr>()) reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, - N->getState().getPtr(), Ex, + N->getState().get(), Ex, N->getLocationContext()); // Add an edge. If this is an ObjCForCollectionStmt do @@ -1778,7 +1779,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, const LocationContext *CalleeCtx = PDB.LC; if (CallerCtx != CalleeCtx) { reversePropagateInterestingSymbols(*PDB.getBugReport(), IE, - N->getState().getPtr(), + N->getState().get(), CalleeCtx, CallerCtx); } } @@ -1786,7 +1787,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, // Are we jumping to the head of a loop? Add a special diagnostic. if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) { PathDiagnosticLocation L(Loop, SM, PDB.LC); - const Stmt *Body = NULL; + const Stmt *Body = nullptr; if (const ForStmt *FS = dyn_cast<ForStmt>(Loop)) Body = FS->getBody(); @@ -1827,7 +1828,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, bool IsInLoopBody = isInLoopBody(PM, getStmtBeforeCond(PM, TermCond, N), Term); - const char *str = 0; + const char *str = nullptr; if (isJumpToFalseBranch(&*BE)) { if (!IsInLoopBody) { @@ -1890,13 +1891,13 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, static const Stmt *getLocStmt(PathDiagnosticLocation L) { if (!L.isValid()) - return 0; + return nullptr; return L.asStmt(); } static const Stmt *getStmtParent(const Stmt *S, const ParentMap &PM) { if (!S) - return 0; + return nullptr; while (true) { S = PM.getParentIgnoreParens(S); @@ -1988,7 +1989,7 @@ static void addContextEdges(PathPieces &pieces, SourceManager &SM, SmallVector<PathDiagnosticLocation, 4> SrcContexts; PathDiagnosticLocation NextSrcContext = SrcLoc; - const Stmt *InnerStmt = 0; + const Stmt *InnerStmt = nullptr; while (NextSrcContext.isValid() && NextSrcContext.asStmt() != InnerStmt) { SrcContexts.push_back(NextSrcContext); InnerStmt = NextSrcContext.asStmt(); @@ -2073,7 +2074,7 @@ static void simplifySimpleBranches(PathPieces &pieces) { if (NextI == E) break; - PathDiagnosticControlFlowPiece *PieceNextI = 0; + PathDiagnosticControlFlowPiece *PieceNextI = nullptr; while (true) { if (NextI == E) @@ -2579,8 +2580,8 @@ const Decl *BugReport::getDeclWithIssue() const { const ExplodedNode *N = getErrorNode(); if (!N) - return 0; - + return nullptr; + const LocationContext *LC = N->getLocationContext(); return LC->getCurrentStackFrame()->getDecl(); } @@ -2703,10 +2704,10 @@ void BugReport::popInterestingSymbolsAndRegions() { const Stmt *BugReport::getStmt() const { if (!ErrorNode) - return 0; + return nullptr; ProgramPoint ProgP = ErrorNode->getLocation(); - const Stmt *S = NULL; + const Stmt *S = nullptr; if (Optional<BlockEntrance> BE = ProgP.getAs<BlockEntrance>()) { CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit(); @@ -2742,12 +2743,10 @@ PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const { assert(!Location.isValid() && "Either Location or ErrorNode should be specified but not both."); return PathDiagnosticLocation::createEndOfPath(ErrorNode, SM); - } else { - assert(Location.isValid()); - return Location; } - return PathDiagnosticLocation(); + assert(Location.isValid()); + return Location; } //===----------------------------------------------------------------------===// @@ -2802,9 +2801,7 @@ void BugReporter::FlushReports() { // EmitBasicReport. // FIXME: There are leaks from checkers that assume that the BugTypes they // create will be destroyed by the BugReporter. - for (llvm::StringMap<BugType*>::iterator - I = StrBugTypes.begin(), E = StrBugTypes.end(); I != E; ++I) - delete I->second; + llvm::DeleteContainerSeconds(StrBugTypes); // Remove all references to the BugType objects. BugTypes = F.getEmptySet(); @@ -2820,7 +2817,7 @@ namespace { class ReportGraph { public: InterExplodedGraphMap BackMap; - OwningPtr<ExplodedGraph> Graph; + std::unique_ptr<ExplodedGraph> Graph; const ExplodedNode *ErrorNode; size_t Index; }; @@ -2835,7 +2832,7 @@ class TrimmedGraph { typedef std::pair<const ExplodedNode *, size_t> NodeIndexPair; SmallVector<NodeIndexPair, 32> ReportNodes; - OwningPtr<ExplodedGraph> G; + std::unique_ptr<ExplodedGraph> G; /// A helper class for sorting ExplodedNodes by priority. template <bool Descending> @@ -2906,7 +2903,7 @@ TrimmedGraph::TrimmedGraph(const ExplodedGraph *OriginalGraph, PriorityMapTy::iterator PriorityEntry; bool IsNew; - llvm::tie(PriorityEntry, IsNew) = + std::tie(PriorityEntry, IsNew) = PriorityMap.insert(std::make_pair(Node, Priority)); ++Priority; @@ -2935,7 +2932,7 @@ bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) { return false; const ExplodedNode *OrigN; - llvm::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val(); + std::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val(); assert(PriorityMap.find(OrigN) != PriorityMap.end() && "error node not accessible from root"); @@ -2947,7 +2944,7 @@ bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) { // Now walk from the error node up the BFS path, always taking the // predeccessor with the lowest number. - ExplodedNode *Succ = 0; + ExplodedNode *Succ = nullptr; while (true) { // Create the equivalent node in the new graph with the same state // and location. @@ -2998,7 +2995,7 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) { for (PathPieces::const_iterator I = path.begin(), E = path.end(); I!=E; ++I) { - PathDiagnosticPiece *piece = I->getPtr(); + PathDiagnosticPiece *piece = I->get(); // Recursively compact calls. if (PathDiagnosticCallPiece *call=dyn_cast<PathDiagnosticCallPiece>(piece)){ @@ -3095,7 +3092,7 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD, } else { // Keep the errorNodes list in sync with the bugReports list. HasInvalid = true; - errorNodes.push_back(0); + errorNodes.push_back(nullptr); } } @@ -3153,21 +3150,21 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD, // Generate the very last diagnostic piece - the piece is visible before // the trace is expanded. - PathDiagnosticPiece *LastPiece = 0; + std::unique_ptr<PathDiagnosticPiece> LastPiece; for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end(); I != E; ++I) { if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) { assert (!LastPiece && "There can only be one final piece in a diagnostic."); - LastPiece = Piece; + LastPiece.reset(Piece); } } if (ActiveScheme != PathDiagnosticConsumer::None) { if (!LastPiece) - LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R); + LastPiece.reset(BugReporterVisitor::getDefaultEndPath(PDB, N, *R)); assert(LastPiece); - PD.setEndOfPath(LastPiece); + PD.setEndOfPath(LastPiece.release()); } // Make sure we get a clean location context map so we don't @@ -3247,6 +3244,9 @@ void BugReporter::Register(BugType *BT) { } void BugReporter::emitReport(BugReport* R) { + // To guarantee memory release. + std::unique_ptr<BugReport> UniqueR(R); + // Defensive checking: throw the bug away if it comes from a BodyFarm- // generated body. We do this very early because report processing relies // on the report's location being valid. @@ -3277,12 +3277,12 @@ void BugReporter::emitReport(BugReport* R) { BugReportEquivClass* EQ = EQClasses.FindNodeOrInsertPos(ID, InsertPos); if (!EQ) { - EQ = new BugReportEquivClass(R); + EQ = new BugReportEquivClass(UniqueR.release()); EQClasses.InsertNode(EQ, InsertPos); EQClassesVector.push_back(EQ); } else - EQ->AddReport(R); + EQ->AddReport(UniqueR.release()); } @@ -3329,7 +3329,7 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ, // DFS traversal of the ExplodedGraph to find a non-sink node. We could write // this as a recursive function, but we don't want to risk blowing out the // stack for very long paths. - BugReport *exampleReport = 0; + BugReport *exampleReport = nullptr; for (; I != E; ++I) { const ExplodedNode *errorNode = I->getErrorNode(); @@ -3403,10 +3403,8 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { SmallVector<BugReport*, 10> bugReports; BugReport *exampleReport = FindReportInEquivalenceClass(EQ, bugReports); if (exampleReport) { - const PathDiagnosticConsumers &C = getPathDiagnosticConsumers(); - for (PathDiagnosticConsumers::const_iterator I=C.begin(), - E=C.end(); I != E; ++I) { - FlushReport(exampleReport, **I, bugReports); + for (PathDiagnosticConsumer *PDC : getPathDiagnosticConsumers()) { + FlushReport(exampleReport, *PDC, bugReports); } } } @@ -3419,14 +3417,13 @@ void BugReporter::FlushReport(BugReport *exampleReport, // Probably doesn't make a difference in practice. BugType& BT = exampleReport->getBugType(); - OwningPtr<PathDiagnostic> - D(new PathDiagnostic(exampleReport->getDeclWithIssue(), - exampleReport->getBugType().getName(), - exampleReport->getDescription(), - exampleReport->getShortDescription(/*Fallback=*/false), - BT.getCategory(), - exampleReport->getUniqueingLocation(), - exampleReport->getUniqueingDecl())); + std::unique_ptr<PathDiagnostic> D(new PathDiagnostic( + exampleReport->getBugType().getCheckName(), + exampleReport->getDeclWithIssue(), exampleReport->getBugType().getName(), + exampleReport->getDescription(), + exampleReport->getShortDescription(/*Fallback=*/false), BT.getCategory(), + exampleReport->getUniqueingLocation(), + exampleReport->getUniqueingDecl())); MaxBugClassSize = std::max(bugReports.size(), static_cast<size_t>(MaxBugClassSize)); @@ -3455,7 +3452,7 @@ void BugReporter::FlushReport(BugReport *exampleReport, PathDiagnosticPiece *piece = new PathDiagnosticEventPiece(L, exampleReport->getDescription()); BugReport::ranges_iterator Beg, End; - llvm::tie(Beg, End) = exampleReport->getRanges(); + std::tie(Beg, End) = exampleReport->getRanges(); for ( ; Beg != End; ++Beg) piece->addRange(*Beg); D->setEndOfPath(piece); @@ -3468,17 +3465,25 @@ void BugReporter::FlushReport(BugReport *exampleReport, D->addMeta(*i); } - PD.HandlePathDiagnostic(D.take()); + PD.HandlePathDiagnostic(D.release()); } void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, - StringRef name, - StringRef category, + const CheckerBase *Checker, + StringRef Name, StringRef Category, + StringRef Str, PathDiagnosticLocation Loc, + ArrayRef<SourceRange> Ranges) { + EmitBasicReport(DeclWithIssue, Checker->getCheckName(), Name, Category, Str, + Loc, Ranges); +} +void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, + CheckName CheckName, + StringRef name, StringRef category, StringRef str, PathDiagnosticLocation Loc, ArrayRef<SourceRange> Ranges) { // 'BT' is owned by BugReporter. - BugType *BT = getBugTypeForName(name, category); + BugType *BT = getBugTypeForName(CheckName, name, category); BugReport *R = new BugReport(*BT, str, Loc); R->setDeclWithIssue(DeclWithIssue); for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); @@ -3487,22 +3492,22 @@ void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, emitReport(R); } -BugType *BugReporter::getBugTypeForName(StringRef name, +BugType *BugReporter::getBugTypeForName(CheckName CheckName, StringRef name, StringRef category) { SmallString<136> fullDesc; - llvm::raw_svector_ostream(fullDesc) << name << ":" << category; + llvm::raw_svector_ostream(fullDesc) << CheckName.getName() << ":" << name + << ":" << category; llvm::StringMapEntry<BugType *> & entry = StrBugTypes.GetOrCreateValue(fullDesc); BugType *BT = entry.getValue(); if (!BT) { - BT = new BugType(name, category); + BT = new BugType(CheckName, name, category); entry.setValue(BT); } return BT; } - -void PathPieces::dump() const { +LLVM_DUMP_METHOD void PathPieces::dump() const { unsigned index = 0; for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { llvm::errs() << "[" << index++ << "] "; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index e1a92b3..0503ace 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -45,7 +45,7 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) { // a[0], p->f, *p const Expr *E = dyn_cast<Expr>(S); if (!E) - return 0; + return nullptr; E = E->IgnoreParenCasts(); while (true) { @@ -79,21 +79,21 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) { break; } - return NULL; + return nullptr; } const Stmt *bugreporter::GetDenomExpr(const ExplodedNode *N) { const Stmt *S = N->getLocationAs<PreStmt>()->getStmt(); if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S)) return BE->getRHS(); - return NULL; + return nullptr; } const Stmt *bugreporter::GetRetValExpr(const ExplodedNode *N) { const Stmt *S = N->getLocationAs<PostStmt>()->getStmt(); if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) return RS->getRetValue(); - return NULL; + return nullptr; } //===----------------------------------------------------------------------===// @@ -104,7 +104,7 @@ PathDiagnosticPiece* BugReporterVisitor::getEndPath(BugReporterContext &BRC, const ExplodedNode *EndPathNode, BugReport &BR) { - return 0; + return nullptr; } PathDiagnosticPiece* @@ -115,7 +115,7 @@ BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC, PathDiagnosticLocation::createEndOfPath(EndPathNode,BRC.getSourceManager()); BugReport::ranges_iterator Beg, End; - llvm::tie(Beg, End) = BR.getRanges(); + std::tie(Beg, End) = BR.getRanges(); // Only add the statement itself as a range if we didn't specify any // special ranges for this report. @@ -156,7 +156,7 @@ public: return static_cast<void *>(&Tag); } - virtual void Profile(llvm::FoldingSetNodeID &ID) const { + void Profile(llvm::FoldingSetNodeID &ID) const override { ID.AddPointer(ReturnVisitor::getTag()); ID.AddPointer(StackFrame); ID.AddBoolean(EnableNullFPSuppression); @@ -237,22 +237,22 @@ public: BugReport &BR) { // Only print a message at the interesting return statement. if (N->getLocationContext() != StackFrame) - return 0; + return nullptr; Optional<StmtPoint> SP = N->getLocationAs<StmtPoint>(); if (!SP) - return 0; + return nullptr; const ReturnStmt *Ret = dyn_cast<ReturnStmt>(SP->getStmt()); if (!Ret) - return 0; + return nullptr; // Okay, we're at the right return statement, but do we have the return // value available? ProgramStateRef State = N->getState(); SVal V = State->getSVal(Ret, StackFrame); if (V.isUnknownOrUndef()) - return 0; + return nullptr; // Don't print any more notes after this one. Mode = Satisfied; @@ -273,7 +273,7 @@ public: // Ignore aggregate rvalues. if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::CompoundVal>()) - return 0; + return nullptr; RetE = RetE->IgnoreParenCasts(); @@ -283,7 +283,7 @@ public: BR.markInteresting(V); ReturnVisitor::addVisitorIfNecessary(N, RetE, BR, EnableNullFPSuppression); - return 0; + return nullptr; } // If we're returning 0, we should track where that 0 came from. @@ -343,10 +343,10 @@ public: // Are we at the entry node for this call? Optional<CallEnter> CE = N->getLocationAs<CallEnter>(); if (!CE) - return 0; + return nullptr; if (CE->getCalleeContext() != StackFrame) - return 0; + return nullptr; Mode = Satisfied; @@ -380,20 +380,20 @@ public: // (We will still look at the other arguments, though.) } - return 0; + return nullptr; } PathDiagnosticPiece *VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, - BugReport &BR) { + BugReport &BR) override { switch (Mode) { case Initial: return visitNodeInitial(N, PrevN, BRC, BR); case MaybeUnsuppress: return visitNodeMaybeUnsuppress(N, PrevN, BRC, BR); case Satisfied: - return 0; + return nullptr; } llvm_unreachable("Invalid visit mode!"); @@ -401,10 +401,10 @@ public: PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, const ExplodedNode *N, - BugReport &BR) { + BugReport &BR) override { if (EnableNullFPSuppression) BR.markInvalid(ReturnVisitor::getTag(), StackFrame); - return 0; + return nullptr; } }; } // end anonymous namespace @@ -453,10 +453,10 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, BugReport &BR) { if (Satisfied) - return NULL; + return nullptr; - const ExplodedNode *StoreSite = 0; - const Expr *InitE = 0; + const ExplodedNode *StoreSite = nullptr; + const Expr *InitE = nullptr; bool IsParam = false; // First see if we reached the declaration of the region. @@ -484,12 +484,12 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, // the same binding was re-assigned here. if (!StoreSite) { if (Succ->getState()->getSVal(R) != V) - return NULL; + return nullptr; if (Pred->getState()->getSVal(R) == V) { Optional<PostStore> PS = Succ->getLocationAs<PostStore>(); if (!PS || PS->getLocationValue() != R) - return NULL; + return nullptr; } StoreSite = Succ; @@ -526,7 +526,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, } if (!StoreSite) - return NULL; + return nullptr; Satisfied = true; // If we have an expression that provided the value, try to track where it @@ -550,7 +550,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, if (Optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) { const Stmt *S = PS->getStmt(); - const char *action = 0; + const char *action = nullptr; const DeclStmt *DS = dyn_cast<DeclStmt>(S); const VarRegion *VR = dyn_cast<VarRegion>(R); @@ -703,7 +703,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, L = PathDiagnosticLocation::create(P, BRC.getSourceManager()); if (!L.isValid() || !L.asLocation().isValid()) - return NULL; + return nullptr; return new PathDiagnosticEventPiece(L, os.str()); } @@ -724,7 +724,7 @@ const char *TrackConstraintBRVisitor::getTag() { bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const { if (IsZeroCheck) return N->getState()->isNull(Constraint).isUnderconstrained(); - return N->getState()->assume(Constraint, !Assumption); + return (bool)N->getState()->assume(Constraint, !Assumption); } PathDiagnosticPiece * @@ -733,7 +733,7 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC, BugReport &BR) { if (IsSatisfied) - return NULL; + return nullptr; // Start tracking after we see the first state in which the value is // constrained. @@ -741,7 +741,7 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, if (!isUnderconstrained(N)) IsTrackingTurnedOn = true; if (!IsTrackingTurnedOn) - return 0; + return nullptr; // Check if in the previous state it was feasible for this constraint // to *not* be true. @@ -765,21 +765,21 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, } if (os.str().empty()) - return NULL; + return nullptr; // Construct a new PathDiagnosticPiece. ProgramPoint P = N->getLocation(); PathDiagnosticLocation L = PathDiagnosticLocation::create(P, BRC.getSourceManager()); if (!L.isValid()) - return NULL; - + return nullptr; + PathDiagnosticEventPiece *X = new PathDiagnosticEventPiece(L, os.str()); X->setTag(getTag()); return X; } - return NULL; + return nullptr; } SuppressInlineDefensiveChecksVisitor:: @@ -813,14 +813,14 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, BugReport &BR) { if (IsSatisfied) - return 0; + return nullptr; // Start tracking after we see the first state in which the value is null. if (!IsTrackingTurnedOn) if (Succ->getState()->isNull(V).isConstrainedTrue()) IsTrackingTurnedOn = true; if (!IsTrackingTurnedOn) - return 0; + return nullptr; // Check if in the previous state it was feasible for this value // to *not* be null. @@ -835,7 +835,7 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ, if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) BR.markInvalid("Suppress IDC", CurLC); } - return 0; + return nullptr; } static const MemRegion *getLocationRegionIfReference(const Expr *E, @@ -843,7 +843,7 @@ static const MemRegion *getLocationRegionIfReference(const Expr *E, if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) { if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { if (!VD->getType()->isReferenceType()) - return 0; + return nullptr; ProgramStateManager &StateMgr = N->getState()->getStateManager(); MemRegionManager &MRMgr = StateMgr.getRegionManager(); return MRMgr.getVarRegion(VD, N->getLocationContext()); @@ -856,7 +856,7 @@ static const MemRegion *getLocationRegionIfReference(const Expr *E, // Wrapper w = { *(int *)0 }; // w.ref = 1; - return 0; + return nullptr; } static const Expr *peelOffOuterExpr(const Expr *Ex, @@ -869,7 +869,7 @@ static const Expr *peelOffOuterExpr(const Expr *Ex, // Peel off the ternary operator. if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(Ex)) { - // Find a node where the branching occured and find out which branch + // Find a node where the branching occurred and find out which branch // we took (true/false) by looking at the ExplodedGraph. const ExplodedNode *NI = N; do { @@ -906,7 +906,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, S = PeeledEx; } - const Expr *Inner = 0; + const Expr *Inner = nullptr; if (const Expr *Ex = dyn_cast<Expr>(S)) { Ex = Ex->IgnoreParenCasts(); if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex)) @@ -948,7 +948,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, // See if the expression we're interested refers to a variable. // If so, we can track both its contents and constraints on its value. if (Inner && ExplodedGraph::isInterestingLValueExpr(Inner)) { - const MemRegion *R = 0; + const MemRegion *R = nullptr; // Find the ExplodedNode where the lvalue (the value of 'Ex') // was computed. We need this for getting the location value. @@ -1060,14 +1060,14 @@ const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S, const ExplodedNode *N) { const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S); if (!ME) - return 0; + return nullptr; if (const Expr *Receiver = ME->getInstanceReceiver()) { ProgramStateRef state = N->getState(); SVal V = state->getSVal(Receiver, N->getLocationContext()); if (state->isNull(V).isConstrainedTrue()) return Receiver; } - return 0; + return nullptr; } PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, @@ -1076,18 +1076,20 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, BugReport &BR) { Optional<PreStmt> P = N->getLocationAs<PreStmt>(); if (!P) - return 0; + return nullptr; const Stmt *S = P->getStmt(); const Expr *Receiver = getNilReceiver(S, N); if (!Receiver) - return 0; + return nullptr; llvm::SmallString<256> Buf; llvm::raw_svector_ostream OS(Buf); if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) { - OS << "'" << ME->getSelector().getAsString() << "' not called"; + OS << "'"; + ME->getSelector().print(OS); + OS << "' not called"; } else { OS << "No method is called"; @@ -1179,15 +1181,15 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, // were generated by the analyzer engine proper, not checkers. if (CurrentState->getGDM().getRoot() == PrevState->getGDM().getRoot()) - return 0; - + return nullptr; + // If an assumption was made on a branch, it should be caught // here by looking at the state transition. if (Optional<BlockEdge> BE = progPoint.getAs<BlockEdge>()) { const CFGBlock *srcBlk = BE->getSrc(); if (const Stmt *term = srcBlk->getTerminator()) return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC); - return 0; + return nullptr; } if (Optional<PostStmt> PS = progPoint.getAs<PostStmt>()) { @@ -1204,11 +1206,11 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, if (tag == tags.second) return VisitTrueTest(cast<Expr>(PS->getStmt()), false, BRC, BR, N); - - return 0; + + return nullptr; } - - return 0; + + return nullptr; } PathDiagnosticPiece * @@ -1218,11 +1220,11 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term, const CFGBlock *dstBlk, BugReport &R, BugReporterContext &BRC) { - const Expr *Cond = 0; - + const Expr *Cond = nullptr; + switch (Term->getStmtClass()) { default: - return 0; + return nullptr; case Stmt::IfStmtClass: Cond = cast<IfStmt>(Term)->getCond(); break; @@ -1250,7 +1252,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, Ex = Ex->IgnoreParenCasts(); switch (Ex->getStmtClass()) { default: - return 0; + return nullptr; case Stmt::BinaryOperatorClass: return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC, R, N); @@ -1264,7 +1266,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, Ex = UO->getSubExpr(); continue; } - return 0; + return nullptr; } } } @@ -1283,13 +1285,13 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex, raw_ostream &Out, if (quotes) { Out << '\''; const LocationContext *LCtx = N->getLocationContext(); - const ProgramState *state = N->getState().getPtr(); + const ProgramState *state = N->getState().get(); if (const MemRegion *R = state->getLValue(cast<VarDecl>(DR->getDecl()), LCtx).getAsRegion()) { if (report.isInteresting(R)) prunable = false; else { - const ProgramState *state = N->getState().getPtr(); + const ProgramState *state = N->getState().get(); SVal V = state->getSVal(R); if (report.isInteresting(V)) prunable = false; @@ -1359,8 +1361,8 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, // both the LHS and RHS. if (LhsString.empty() || RhsString.empty() || !BinaryOperator::isComparisonOp(Op)) - return 0; - + return nullptr; + // Should we invert the strings if the LHS is not a variable name? SmallString<256> buf; llvm::raw_svector_ostream Out(buf); @@ -1385,7 +1387,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, case BO_LE: Op = BO_GT; break; case BO_GE: Op = BO_LT; break; default: - return 0; + return nullptr; } switch (Op) { @@ -1435,7 +1437,7 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, else if (Ty->isIntegralOrEnumerationType()) Out << (tookTrue ? "non-zero" : "zero"); else - return 0; + return nullptr; const LocationContext *LCtx = N->getLocationContext(); PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx); @@ -1444,7 +1446,7 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(CondVarExpr)) { if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { - const ProgramState *state = N->getState().getPtr(); + const ProgramState *state = N->getState().get(); if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { if (report.isInteresting(R)) event->setPrunable(false); @@ -1465,8 +1467,8 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); if (!VD) - return 0; - + return nullptr; + SmallString<256> Buf; llvm::raw_svector_ostream Out(Buf); @@ -1481,14 +1483,14 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, else if (VDTy->isScalarType()) Out << (tookTrue ? "not equal to 0" : "0"); else - return 0; - + return nullptr; + const LocationContext *LCtx = N->getLocationContext(); PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); PathDiagnosticEventPiece *event = new PathDiagnosticEventPiece(Loc, Out.str()); - const ProgramState *state = N->getState().getPtr(); + const ProgramState *state = N->getState().get(); if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { if (report.isInteresting(R)) event->setPrunable(false); @@ -1512,7 +1514,7 @@ static bool isInStdNamespace(const Decl *D) { while (const NamespaceDecl *Parent = dyn_cast<NamespaceDecl>(ND->getParent())) ND = Parent; - return ND->getName() == "std"; + return ND->isStdNamespace(); } @@ -1532,8 +1534,8 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, // Note that this will not help for any other data structure libraries, like // TR1, Boost, or llvm/ADT. if (Options.shouldSuppressFromCXXStandardLibrary()) { - BR.markInvalid(getTag(), 0); - return 0; + BR.markInvalid(getTag(), nullptr); + return nullptr; } else { // If the the complete 'std' suppression is not enabled, suppress reports @@ -1545,8 +1547,8 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { const CXXRecordDecl *CD = MD->getParent(); if (CD->getName() == "list") { - BR.markInvalid(getTag(), 0); - return 0; + BR.markInvalid(getTag(), nullptr); + return nullptr; } } @@ -1556,25 +1558,18 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, // std::u16string s; s += u'a'; // because we cannot reason about the internal invariants of the // datastructure. - const LocationContext *LCtx = N->getLocationContext(); - do { + for (const LocationContext *LCtx = N->getLocationContext(); LCtx; + LCtx = LCtx->getParent()) { const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl()); if (!MD) - break; + continue; const CXXRecordDecl *CD = MD->getParent(); if (CD->getName() == "basic_string") { - BR.markInvalid(getTag(), 0); - return 0; - } else if (CD->getName().find("allocator") == StringRef::npos) { - // Only keep searching if the current method is in a class with the - // word "allocator" in its name, e.g. std::allocator or - // allocator_traits. - break; + BR.markInvalid(getTag(), nullptr); + return nullptr; } - - LCtx = LCtx->getParent(); - } while (LCtx); + } } } @@ -1585,12 +1580,12 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, while (Loc.isMacroID()) { Loc = Loc.getSpellingLoc(); if (SM.getFilename(Loc).endswith("sys/queue.h")) { - BR.markInvalid(getTag(), 0); - return 0; + BR.markInvalid(getTag(), nullptr); + return nullptr; } } - return 0; + return nullptr; } PathDiagnosticPiece * @@ -1605,14 +1600,16 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, // We are only interested in visiting CallEnter nodes. Optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>(); if (!CEnter) - return 0; + return nullptr; // Check if one of the arguments is the region the visitor is tracking. CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager(); CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State); unsigned Idx = 0; - for (CallEvent::param_iterator I = Call->param_begin(), - E = Call->param_end(); I != E; ++I, ++Idx) { + ArrayRef<ParmVarDecl*> parms = Call->parameters(); + + for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end(); + I != E; ++I, ++Idx) { const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion(); // Are we tracking the argument or its subregion? @@ -1639,8 +1636,8 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, SVal BoundVal = State->getSVal(R); if (BoundVal.isUndef() || BoundVal.isZeroConstant()) { BR.markInteresting(CEnter->getCalleeContext()); - return 0; + return nullptr; } } - return 0; + return nullptr; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index a3b34f4..7e0670a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -68,8 +68,7 @@ static bool isCallbackArg(SVal V, QualType T) { if (const RecordType *RT = T->getAsStructureType()) { const RecordDecl *RD = RT->getDecl(); - for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); - I != E; ++I) { + for (const auto *I : RD->fields()) { QualType FieldT = I->getType(); if (FieldT->isBlockPointerType() || FieldT->isFunctionPointerType()) return true; @@ -140,6 +139,11 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, ProgramStateRef Orig) const { ProgramStateRef Result = (Orig ? Orig : getState()); + // Don't invalidate anything if the callee is marked pure/const. + if (const Decl *callee = getDecl()) + if (callee->hasAttr<PureAttr>() || callee->hasAttr<ConstAttr>()) + return Result; + SmallVector<SVal, 8> ValuesToInvalidate; RegionAndSymbolInvalidationTraits ETraits; @@ -168,7 +172,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(), BlockCount, getLocationContext(), /*CausedByPointerEscape*/ true, - /*Symbols=*/0, this, &ETraits); + /*Symbols=*/nullptr, this, &ETraits); } ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit, @@ -209,14 +213,12 @@ SVal CallEvent::getReturnValue() const { return getSVal(E); } -void CallEvent::dump() const { - dump(llvm::errs()); -} +LLVM_DUMP_METHOD void CallEvent::dump() const { dump(llvm::errs()); } void CallEvent::dump(raw_ostream &Out) const { ASTContext &Ctx = getState()->getStateManager().getContext(); if (const Expr *E = getOriginExpr()) { - E->printPretty(Out, 0, Ctx.getPrintingPolicy()); + E->printPretty(Out, nullptr, Ctx.getPrintingPolicy()); Out << "\n"; return; } @@ -241,9 +243,9 @@ bool CallEvent::isCallStmt(const Stmt *S) { QualType CallEvent::getDeclaredResultType(const Decl *D) { assert(D); if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) - return FD->getResultType(); + return FD->getReturnType(); if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D)) - return MD->getResultType(); + return MD->getReturnType(); if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { // Blocks are difficult because the return type may not be stored in the // BlockDecl itself. The AST should probably be enhanced, but for now we @@ -256,7 +258,7 @@ QualType CallEvent::getDeclaredResultType(const Decl *D) { if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten()) { QualType Ty = TSI->getType(); if (const FunctionType *FT = Ty->getAs<FunctionType>()) - Ty = FT->getResultType(); + Ty = FT->getReturnType(); if (!Ty->isDependentType()) return Ty; } @@ -284,14 +286,14 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx, CallEvent::BindingsTy &Bindings, SValBuilder &SVB, const CallEvent &Call, - CallEvent::param_iterator I, - CallEvent::param_iterator E) { + ArrayRef<ParmVarDecl*> parameters) { MemRegionManager &MRMgr = SVB.getRegionManager(); // If the function has fewer parameters than the call has arguments, we simply // do not bind any values to them. unsigned NumArgs = Call.getNumArgs(); unsigned Idx = 0; + ArrayRef<ParmVarDecl*>::iterator I = parameters.begin(), E = parameters.end(); for (; I != E && Idx < NumArgs; ++I, ++Idx) { const ParmVarDecl *ParamDecl = *I; assert(ParamDecl && "Formal parameter has no decl?"); @@ -306,21 +308,11 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx, // FIXME: Variadic arguments are not handled at all right now. } - -CallEvent::param_iterator AnyFunctionCall::param_begin() const { - const FunctionDecl *D = getDecl(); - if (!D) - return 0; - - return D->param_begin(); -} - -CallEvent::param_iterator AnyFunctionCall::param_end() const { +ArrayRef<ParmVarDecl*> AnyFunctionCall::parameters() const { const FunctionDecl *D = getDecl(); if (!D) - return 0; - - return D->param_end(); + return None; + return D->parameters(); } void AnyFunctionCall::getInitialStackFrameContents( @@ -329,7 +321,7 @@ void AnyFunctionCall::getInitialStackFrameContents( const FunctionDecl *D = cast<FunctionDecl>(CalleeCtx->getDecl()); SValBuilder &SVB = getState()->getStateManager().getSValBuilder(); addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this, - D->param_begin(), D->param_end()); + D->parameters()); } bool AnyFunctionCall::argumentsMayEscape() const { @@ -389,7 +381,7 @@ bool AnyFunctionCall::argumentsMayEscape() const { } -const FunctionDecl *SimpleCall::getDecl() const { +const FunctionDecl *SimpleFunctionCall::getDecl() const { const FunctionDecl *D = getOriginExpr()->getDirectCallee(); if (D) return D; @@ -484,7 +476,7 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { // that ExprEngine can decide what to do with it. if (DynType.canBeASubClass()) return RuntimeDefinition(Definition, R->StripCasts()); - return RuntimeDefinition(Definition, /*DispatchRegion=*/0); + return RuntimeDefinition(Definition, /*DispatchRegion=*/nullptr); } void CXXInstanceCall::getInitialStackFrameContents( @@ -550,18 +542,11 @@ const BlockDataRegion *BlockCall::getBlockRegion() const { return dyn_cast_or_null<BlockDataRegion>(DataReg); } -CallEvent::param_iterator BlockCall::param_begin() const { - const BlockDecl *D = getBlockDecl(); +ArrayRef<ParmVarDecl*> BlockCall::parameters() const { + const BlockDecl *D = getDecl(); if (!D) - return 0; - return D->param_begin(); -} - -CallEvent::param_iterator BlockCall::param_end() const { - const BlockDecl *D = getBlockDecl(); - if (!D) - return 0; - return D->param_end(); + return nullptr; + return D->parameters(); } void BlockCall::getExtraInvalidatedValues(ValueList &Values) const { @@ -575,7 +560,7 @@ void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx, const BlockDecl *D = cast<BlockDecl>(CalleeCtx->getDecl()); SValBuilder &SVB = getState()->getStateManager().getSValBuilder(); addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this, - D->param_begin(), D->param_end()); + D->parameters()); } @@ -604,8 +589,6 @@ void CXXConstructorCall::getInitialStackFrameContents( } } - - SVal CXXDestructorCall::getCXXThisVal() const { if (Data) return loc::MemRegionVal(DtorDataTy::getFromOpaqueValue(Data).getPointer()); @@ -621,21 +604,11 @@ RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const { return CXXInstanceCall::getRuntimeDefinition(); } - -CallEvent::param_iterator ObjCMethodCall::param_begin() const { +ArrayRef<ParmVarDecl*> ObjCMethodCall::parameters() const { const ObjCMethodDecl *D = getDecl(); if (!D) - return 0; - - return D->param_begin(); -} - -CallEvent::param_iterator ObjCMethodCall::param_end() const { - const ObjCMethodDecl *D = getDecl(); - if (!D) - return 0; - - return D->param_end(); + return ArrayRef<ParmVarDecl*>(); + return D->parameters(); } void @@ -694,13 +667,13 @@ SourceRange ObjCMethodCall::getSourceRange() const { typedef llvm::PointerIntPair<const PseudoObjectExpr *, 2> ObjCMessageDataTy; const PseudoObjectExpr *ObjCMethodCall::getContainingPseudoObjectExpr() const { - assert(Data != 0 && "Lazy lookup not yet performed."); + assert(Data && "Lazy lookup not yet performed."); assert(getMessageKind() != OCM_Message && "Explicit message send."); return ObjCMessageDataTy::getFromOpaqueValue(Data).getPointer(); } ObjCMessageKind ObjCMethodCall::getMessageKind() const { - if (Data == 0) { + if (!Data) { // Find the parent, ignoring implicit casts. ParentMap &PM = getLocationContext()->getParentMap(); @@ -738,7 +711,7 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const { } const_cast<ObjCMethodCall *>(this)->Data - = ObjCMessageDataTy(0, 1).getOpaqueValue(); + = ObjCMessageDataTy(nullptr, 1).getOpaqueValue(); assert(getMessageKind() == OCM_Message); return OCM_Message; } @@ -774,7 +747,7 @@ bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl, // Find the first declaration in the class hierarchy that declares // the selector. - ObjCMethodDecl *D = 0; + ObjCMethodDecl *D = nullptr; while (true) { D = IDecl->lookupMethod(Sel, true); @@ -813,10 +786,10 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { if (E->isInstanceMessage()) { // Find the the receiver type. - const ObjCObjectPointerType *ReceiverT = 0; + const ObjCObjectPointerType *ReceiverT = nullptr; bool CanBeSubClassed = false; QualType SupersType = E->getSuperType(); - const MemRegion *Receiver = 0; + const MemRegion *Receiver = nullptr; if (!SupersType.isNull()) { // Super always means the type of immediate predecessor to the method @@ -865,14 +838,22 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { Optional<const ObjCMethodDecl *> &Val = PMC[std::make_pair(IDecl, Sel)]; // Query lookupPrivateMethod() if the cache does not hit. - if (!Val.hasValue()) + if (!Val.hasValue()) { Val = IDecl->lookupPrivateMethod(Sel); + // If the method is a property accessor, we should try to "inline" it + // even if we don't actually have an implementation. + if (!*Val) + if (const ObjCMethodDecl *CompileTimeMD = E->getMethodDecl()) + if (CompileTimeMD->isPropertyAccessor()) + Val = IDecl->lookupInstanceMethod(Sel); + } + const ObjCMethodDecl *MD = Val.getValue(); if (CanBeSubClassed) return RuntimeDefinition(MD, Receiver); else - return RuntimeDefinition(MD, 0); + return RuntimeDefinition(MD, nullptr); } } else { @@ -888,13 +869,24 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { return RuntimeDefinition(); } +bool ObjCMethodCall::argumentsMayEscape() const { + if (isInSystemHeader() && !isInstanceMessage()) { + Selector Sel = getSelector(); + if (Sel.getNumArgs() == 1 && + Sel.getIdentifierInfoForSlot(0)->isStr("valueWithPointer")) + return true; + } + + return CallEvent::argumentsMayEscape(); +} + void ObjCMethodCall::getInitialStackFrameContents( const StackFrameContext *CalleeCtx, BindingsTy &Bindings) const { const ObjCMethodDecl *D = cast<ObjCMethodDecl>(CalleeCtx->getDecl()); SValBuilder &SVB = getState()->getStateManager().getSValBuilder(); addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this, - D->param_begin(), D->param_end()); + D->parameters()); SVal SelfVal = getReceiverSVal(); if (!SelfVal.isUnknown()) { @@ -923,7 +915,7 @@ CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State, // Otherwise, it's a normal function call, static member function call, or // something we can't reason about. - return create<FunctionCall>(CE, State, LCtx); + return create<SimpleFunctionCall>(CE, State, LCtx); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Checker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Checker.cpp index 07e0aac..1a3965a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Checker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Checker.cpp @@ -18,8 +18,23 @@ using namespace clang; using namespace ento; StringRef CheckerBase::getTagDescription() const { - // FIXME: We want to return the package + name of the checker here. - return "A Checker"; + return getCheckName().getName(); +} + +CheckName CheckerBase::getCheckName() const { return Name; } + +CheckerProgramPointTag::CheckerProgramPointTag(StringRef CheckerName, + StringRef Msg) + : SimpleProgramPointTag(CheckerName, Msg) {} + +CheckerProgramPointTag::CheckerProgramPointTag(const CheckerBase *Checker, + StringRef Msg) + : SimpleProgramPointTag(Checker->getCheckName().getName(), Msg) {} + +raw_ostream& clang::ento::operator<<(raw_ostream &Out, + const CheckerBase &Checker) { + Out << Checker.getCheckName().getName(); + return Out; } void Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index c1ae7e9..2684cc7 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -58,7 +58,7 @@ void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, assert(D); unsigned DeclKind = D->getKind(); - CachedDeclCheckers *checkers = 0; + CachedDeclCheckers *checkers = nullptr; CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind); if (CCI != CachedDeclCheckersMap.end()) { checkers = &(CCI->second); @@ -109,7 +109,7 @@ static void expandGraphWithCheckers(CHECK_CTX checkCtx, const ExplodedNodeSet *PrevSet = &Src; for (; I != E; ++I) { - ExplodedNodeSet *CurrSet = 0; + ExplodedNodeSet *CurrSet = nullptr; if (I+1 == E) CurrSet = &Dst; else { @@ -477,7 +477,7 @@ CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, // If any checker declares the state infeasible (or if it starts that way), // bail out. if (!state) - return NULL; + return nullptr; state = RegionChangesCheckers[i].CheckFn(state, invalidated, ExplicitRegions, Regions, Call); } @@ -491,7 +491,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, const CallEvent *Call, PointerEscapeKind Kind, RegionAndSymbolInvalidationTraits *ETraits) { - assert((Call != NULL || + assert((Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && "Call must not be NULL when escaping on call"); @@ -499,7 +499,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, // If any checker declares the state infeasible (or if it starts that // way), bail out. if (!State) - return NULL; + return nullptr; State = PointerEscapeCheckers[i](State, Escaped, Call, Kind, ETraits); } return State; @@ -513,7 +513,7 @@ CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, // If any checker declares the state infeasible (or if it starts that way), // bail out. if (!state) - return NULL; + return nullptr; state = EvalAssumeCheckers[i](state, Cond, Assumption); } return state; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp index 4729903..b64e30b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp @@ -45,7 +45,7 @@ static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers, const llvm::StringMap<size_t> &packageSizes, CheckerOptInfo &opt, CheckerInfoSet &collected) { // Use a binary search to find the possible start of the package. - CheckerRegistry::CheckerInfo packageInfo(NULL, opt.getName(), ""); + CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.getName(), ""); CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end(); CheckerRegistry::CheckerInfoList::const_iterator i = std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT); @@ -84,10 +84,10 @@ void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name, // Record the presence of the checker in its packages. StringRef packageName, leafName; - llvm::tie(packageName, leafName) = name.rsplit(PackageSeparator); + std::tie(packageName, leafName) = name.rsplit(PackageSeparator); while (!leafName.empty()) { Packages[packageName] += 1; - llvm::tie(packageName, leafName) = packageName.rsplit(PackageSeparator); + std::tie(packageName, leafName) = packageName.rsplit(PackageSeparator); } } @@ -106,6 +106,7 @@ void CheckerRegistry::initializeManager(CheckerManager &checkerMgr, // Initialize the CheckerManager with all enabled checkers. for (CheckerInfoSet::iterator i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) { + checkerMgr.setCurrentCheckName(CheckName((*i)->FullName)); (*i)->Initialize(checkerMgr); } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index b09b2c2..4623c35 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -12,8 +12,6 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "CoreEngine" - #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" #include "clang/AST/Expr.h" #include "clang/AST/StmtCXX.h" @@ -26,6 +24,8 @@ using namespace clang; using namespace ento; +#define DEBUG_TYPE "CoreEngine" + STATISTIC(NumSteps, "The # of steps executed."); STATISTIC(NumReachedMaxSteps, @@ -43,22 +43,22 @@ namespace { class DFS : public WorkList { SmallVector<WorkListUnit,20> Stack; public: - virtual bool hasWork() const { + bool hasWork() const override { return !Stack.empty(); } - virtual void enqueue(const WorkListUnit& U) { + void enqueue(const WorkListUnit& U) override { Stack.push_back(U); } - virtual WorkListUnit dequeue() { + WorkListUnit dequeue() override { assert (!Stack.empty()); const WorkListUnit& U = Stack.back(); Stack.pop_back(); // This technically "invalidates" U, but we are fine. return U; } - - virtual bool visitItemsInWorkList(Visitor &V) { + + bool visitItemsInWorkList(Visitor &V) override { for (SmallVectorImpl<WorkListUnit>::iterator I = Stack.begin(), E = Stack.end(); I != E; ++I) { if (V.visit(*I)) @@ -71,21 +71,21 @@ public: class BFS : public WorkList { std::deque<WorkListUnit> Queue; public: - virtual bool hasWork() const { + bool hasWork() const override { return !Queue.empty(); } - virtual void enqueue(const WorkListUnit& U) { + void enqueue(const WorkListUnit& U) override { Queue.push_back(U); } - virtual WorkListUnit dequeue() { + WorkListUnit dequeue() override { WorkListUnit U = Queue.front(); Queue.pop_front(); return U; } - - virtual bool visitItemsInWorkList(Visitor &V) { + + bool visitItemsInWorkList(Visitor &V) override { for (std::deque<WorkListUnit>::iterator I = Queue.begin(), E = Queue.end(); I != E; ++I) { if (V.visit(*I)) @@ -109,18 +109,18 @@ namespace { std::deque<WorkListUnit> Queue; SmallVector<WorkListUnit,20> Stack; public: - virtual bool hasWork() const { + bool hasWork() const override { return !Queue.empty() || !Stack.empty(); } - virtual void enqueue(const WorkListUnit& U) { + void enqueue(const WorkListUnit& U) override { if (U.getNode()->getLocation().getAs<BlockEntrance>()) Queue.push_front(U); else Stack.push_back(U); } - virtual WorkListUnit dequeue() { + WorkListUnit dequeue() override { // Process all basic blocks to completion. if (!Stack.empty()) { const WorkListUnit& U = Stack.back(); @@ -135,7 +135,7 @@ namespace { Queue.pop_front(); return U; } - virtual bool visitItemsInWorkList(Visitor &V) { + bool visitItemsInWorkList(Visitor &V) override { for (SmallVectorImpl<WorkListUnit>::iterator I = Stack.begin(), E = Stack.end(); I != E; ++I) { if (V.visit(*I)) @@ -192,9 +192,9 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, if (!InitState) // Generate the root. - generateNode(StartLoc, SubEng.getInitialState(L), 0); + generateNode(StartLoc, SubEng.getInitialState(L), nullptr); else - generateNode(StartLoc, InitState, 0); + generateNode(StartLoc, InitState, nullptr); } // Check if we have a steps limit @@ -532,11 +532,16 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N, return; } + if ((*Block)[Idx].getKind() == CFGElement::NewAllocator) { + WList->enqueue(N, Block, Idx+1); + return; + } + // At this point, we know we're processing a normal statement. CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>(); PostStmt Loc(CS.getStmt(), N->getLocationContext()); - if (Loc == N->getLocation()) { + if (Loc == N->getLocation().withTag(nullptr)) { // Note: 'N' should be a fresh node because otherwise it shouldn't be // a member of Deferred. WList->enqueue(N, Block, Idx+1); @@ -562,7 +567,7 @@ ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N) { bool isNew; ExplodedNode *Node = G->getNode(Loc, N->getState(), false, &isNew); Node->addPredecessor(N, *G); - return isNew ? Node : 0; + return isNew ? Node : nullptr; } @@ -611,7 +616,7 @@ ExplodedNode* NodeBuilder::generateNodeImpl(const ProgramPoint &Loc, Frontier.erase(FromN); if (!IsNew) - return 0; + return nullptr; if (!MarkAsSink) Frontier.Add(N); @@ -635,7 +640,7 @@ ExplodedNode *BranchNodeBuilder::generateNode(ProgramStateRef State, ExplodedNode *NodePred) { // If the branch has been marked infeasible we should not generate a node. if (!isFeasible(branch)) - return NULL; + return nullptr; ProgramPoint Loc = BlockEdge(C.Block, branch ? DstT:DstF, NodePred->getLocationContext()); @@ -654,7 +659,7 @@ IndirectGotoNodeBuilder::generateNode(const iterator &I, Succ->addPredecessor(Pred, *Eng.G); if (!IsNew) - return 0; + return nullptr; if (!IsSink) Eng.WList->enqueue(Succ); @@ -673,7 +678,7 @@ SwitchNodeBuilder::generateCaseStmtNode(const iterator &I, false, &IsNew); Succ->addPredecessor(Pred, *Eng.G); if (!IsNew) - return 0; + return nullptr; Eng.WList->enqueue(Succ); return Succ; @@ -690,8 +695,8 @@ SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St, // Sanity check for default blocks that are unreachable and not caught // by earlier stages. if (!DefaultBlock) - return NULL; - + return nullptr; + bool IsNew; ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock, Pred->getLocationContext()), St, @@ -699,7 +704,7 @@ SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St, Succ->addPredecessor(Pred, *Eng.G); if (!IsNew) - return 0; + return nullptr; if (!IsSink) Eng.WList->enqueue(Succ); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp index 7b133f6..ae5a4cc 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp @@ -54,7 +54,8 @@ static const Stmt *ignoreTransparentExprs(const Stmt *S) { EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L) : std::pair<const Stmt *, const StackFrameContext *>(ignoreTransparentExprs(S), - L ? L->getCurrentStackFrame() : 0) {} + L ? L->getCurrentStackFrame() + : nullptr) {} SVal Environment::lookupExpr(const EnvironmentEntry &E) const { const SVal* X = ExprBindings.lookup(E); @@ -123,11 +124,11 @@ class MarkLiveCallback : public SymbolVisitor { SymbolReaper &SymReaper; public: MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {} - bool VisitSymbol(SymbolRef sym) { + bool VisitSymbol(SymbolRef sym) override { SymReaper.markLive(sym); return true; } - bool VisitMemRegion(const MemRegion *R) { + bool VisitMemRegion(const MemRegion *R) override { SymReaper.markLive(R); return true; } @@ -204,11 +205,12 @@ void Environment::print(raw_ostream &Out, const char *NL, } const Stmt *S = En.getStmt(); - + assert(S != nullptr && "Expected non-null Stmt"); + Out << " (" << (const void*) En.getLocationContext() << ',' << (const void*) S << ") "; LangOptions LO; // FIXME. - S->printPretty(Out, 0, PrintingPolicy(LO)); + S->printPretty(Out, nullptr, PrintingPolicy(LO)); Out << " : " << I.getData(); } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index e9c4a35..1c9a282 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -34,7 +34,7 @@ using namespace ento; ExplodedNode::Auditor::~Auditor() {} #ifndef NDEBUG -static ExplodedNode::Auditor* NodeAuditor = 0; +static ExplodedNode::Auditor* NodeAuditor = nullptr; #endif void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) { @@ -90,8 +90,9 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { // (7) The LocationContext is the same as the predecessor. // (8) Expressions that are *not* lvalue expressions. // (9) The PostStmt isn't for a non-consumed Stmt or Expr. - // (10) The successor is not a CallExpr StmtPoint (so that we would - // be able to find it when retrying a call with no inlining). + // (10) The successor is neither a CallExpr StmtPoint nor a CallEnter or + // PreImplicitCall (so that we would be able to find it when retrying a + // call with no inlining). // FIXME: It may be safe to reclaim PreCall and PostCall nodes as well. // Conditions 1 and 2. @@ -153,6 +154,10 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { if (CallEvent::isCallStmt(SP->getStmt())) return false; + // Condition 10, continuation. + if (SuccLoc.getAs<CallEnter>() || SuccLoc.getAs<PreImplicitCall>()) + return false; + return true; } @@ -271,11 +276,11 @@ unsigned ExplodedNode::NodeGroup::size() const { ExplodedNode * const *ExplodedNode::NodeGroup::begin() const { if (getFlag()) - return 0; + return nullptr; const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P); if (Storage.isNull()) - return 0; + return nullptr; if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>()) return V->begin(); return Storage.getAddrOfPtr1(); @@ -283,11 +288,11 @@ ExplodedNode * const *ExplodedNode::NodeGroup::begin() const { ExplodedNode * const *ExplodedNode::NodeGroup::end() const { if (getFlag()) - return 0; + return nullptr; const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P); if (Storage.isNull()) - return 0; + return nullptr; if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>()) return V->end(); return Storage.getAddrOfPtr1() + 1; @@ -299,7 +304,7 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L, bool* IsNew) { // Profile 'State' to determine if we already have an existing node. llvm::FoldingSetNodeID profile; - void *InsertPos = 0; + void *InsertPos = nullptr; NodeTy::Profile(profile, L, State, IsSink); NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos); @@ -337,7 +342,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, InterExplodedGraphMap *InverseMap) const{ if (Nodes.empty()) - return 0; + return nullptr; typedef llvm::DenseSet<const ExplodedNode*> Pass1Ty; Pass1Ty Pass1; @@ -380,7 +385,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, // We didn't hit a root? Return with a null pointer for the new graph. if (WL2.empty()) - return 0; + return nullptr; // Create an empty graph. ExplodedGraph* G = MakeEmptyGraph(); @@ -395,7 +400,8 @@ 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(), 0); + ExplodedNode *NewN = G->getNode(N->getLocation(), N->State, N->isSink(), + nullptr); Pass2[N] = NewN; // Also record the reverse mapping from the new node to the old node. diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 9907d0c..4e4095c 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -13,8 +13,6 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "ExprEngine" - #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "PrettyStackTraceLocationContext.h" #include "clang/AST/CharUnits.h" @@ -40,6 +38,8 @@ using namespace clang; using namespace ento; using llvm::APSInt; +#define DEBUG_TYPE "ExprEngine" + STATISTIC(NumRemoveDeadBindings, "The # of times RemoveDeadBindings is called"); STATISTIC(NumMaxBlockCountReached, @@ -55,6 +55,8 @@ STATISTIC(NumTimesRetriedWithoutInlining, // Engine construction and deletion. //===----------------------------------------------------------------------===// +static const char* TagProviderName = "ExprEngine"; + ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled, SetOfConstDecls *VisitedCalleesIn, FunctionSummariesTy *FS, @@ -68,7 +70,7 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled, this), SymMgr(StateMgr.getSymbolManager()), svalBuilder(StateMgr.getSValBuilder()), - currStmtIdx(0), currBldrCtx(0), + currStmtIdx(0), currBldrCtx(nullptr), ObjCNoRet(mgr.getASTContext()), ObjCGCEnabled(gcEnabled), BR(mgr, *this), VisitedCallees(VisitedCalleesIn), @@ -118,7 +120,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) { SVal V = state->getSVal(loc::MemRegionVal(R)); SVal Constraint_untested = evalBinOp(state, BO_GT, V, svalBuilder.makeZeroVal(T), - getContext().IntTy); + svalBuilder.getConditionType()); Optional<DefinedOrUnknownSVal> Constraint = Constraint_untested.getAs<DefinedOrUnknownSVal>(); @@ -153,7 +155,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) { // top-level function. This is our starting assumption for // analyzing an "open" program. const StackFrameContext *SFC = InitLoc->getCurrentStackFrame(); - if (SFC->getParent() == 0) { + if (SFC->getParent() == nullptr) { loc::MemRegionVal L = svalBuilder.getCXXThis(MD, SFC); SVal V = state->getSVal(L); if (Optional<Loc> LV = V.getAs<Loc>()) { @@ -209,7 +211,7 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, // Create a temporary object region for the inner expression (which may have // a more derived type) and bind the value into it. - const TypedValueRegion *TR = NULL; + const TypedValueRegion *TR = nullptr; if (const MaterializeTemporaryExpr *MT = dyn_cast<MaterializeTemporaryExpr>(Result)) { StorageDuration SD = MT->getStorageDuration(); @@ -286,6 +288,10 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, case CFGElement::Initializer: ProcessInitializer(E.castAs<CFGInitializer>().getInitializer(), Pred); return; + case CFGElement::NewAllocator: + ProcessNewAllocator(E.castAs<CFGNewAllocator>().getAllocatorExpr(), + Pred); + return; case CFGElement::AutomaticObjectDtor: case CFGElement::DeleteDtor: case CFGElement::BaseDtor: @@ -329,7 +335,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, const Stmt *DiagnosticStmt, ProgramPoint::Kind K) { assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind || - ReferenceStmt == 0 || isa<ReturnStmt>(ReferenceStmt)) + ReferenceStmt == nullptr || isa<ReturnStmt>(ReferenceStmt)) && "PostStmt is not generally supported by the SymbolReaper yet"); assert(LC && "Must pass the current (or expiring) LocationContext"); @@ -350,7 +356,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, LC = LC->getParent(); } - const StackFrameContext *SFC = LC ? LC->getCurrentStackFrame() : 0; + const StackFrameContext *SFC = LC ? LC->getCurrentStackFrame() : nullptr; SymbolReaper SymReaper(SFC, ReferenceStmt, SymMgr, getStoreManager()); getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper); @@ -362,7 +368,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, // Process any special transfer function for dead symbols. // A tag to track convenience transitions, which can be removed at cleanup. - static SimpleProgramPointTag cleanupTag("ExprEngine : Clean Node"); + static SimpleProgramPointTag cleanupTag(TagProviderName, "Clean Node"); if (!SymReaper.hasDeadSymbols()) { // Generate a CleanedNode that has the environment and store cleaned // up. Since no symbols are dead, we can optimize and not clean out @@ -547,6 +553,25 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); } +void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE, + ExplodedNode *Pred) { + ExplodedNodeSet Dst; + AnalysisManager &AMgr = getAnalysisManager(); + AnalyzerOptions &Opts = AMgr.options; + // TODO: We're not evaluating allocators for all cases just yet as + // we're not handling the return value correctly, which causes false + // positives when the alpha.cplusplus.NewDeleteLeaks check is on. + if (Opts.mayInlineCXXAllocator()) + VisitCXXNewAllocatorCall(NE, Pred, Dst); + else { + NodeBuilder Bldr(Pred, Dst, *currBldrCtx); + const LocationContext *LCtx = Pred->getLocationContext(); + PostImplicitCall PP(NE->getOperatorNew(), NE->getLocStart(), LCtx); + Bldr.generateNode(PP, Pred->getState(), Pred); + } + Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); +} + void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor, ExplodedNode *Pred, ExplodedNodeSet &Dst) { @@ -598,7 +623,6 @@ void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor, void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D, ExplodedNode *Pred, ExplodedNodeSet &Dst) { const LocationContext *LCtx = Pred->getLocationContext(); - ProgramStateRef State = Pred->getState(); const CXXDestructorDecl *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl()); Loc ThisPtr = getSValBuilder().getCXXThis(CurDtor, @@ -640,7 +664,7 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, // FIXME: Inlining of temporary destructors is not supported yet anyway, so we // just put a NULL region for now. This will need to be changed later. - VisitCXXDestructor(varType, NULL, D.getBindTemporaryExpr(), + VisitCXXDestructor(varType, nullptr, D.getBindTemporaryExpr(), /*IsBase=*/ false, Pred, Dst); } @@ -664,8 +688,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::MSPropertyRefExprClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::DependentScopeDeclRefExprClass: - case Stmt::UnaryTypeTraitExprClass: - case Stmt::BinaryTypeTraitExprClass: case Stmt::TypeTraitExprClass: case Stmt::ArrayTypeTraitExprClass: case Stmt::ExpressionTraitExprClass: @@ -677,6 +699,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::FunctionParmPackExprClass: case Stmt::SEHTryStmtClass: case Stmt::SEHExceptStmtClass: + case Stmt::SEHLeaveStmtClass: case Stmt::LambdaExprClass: case Stmt::SEHFinallyStmtClass: { const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); @@ -709,6 +732,20 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Expr::MSDependentExistsStmtClass: case Stmt::CapturedStmtClass: case Stmt::OMPParallelDirectiveClass: + case Stmt::OMPSimdDirectiveClass: + case Stmt::OMPForDirectiveClass: + case Stmt::OMPSectionsDirectiveClass: + case Stmt::OMPSectionDirectiveClass: + case Stmt::OMPSingleDirectiveClass: + case Stmt::OMPMasterDirectiveClass: + case Stmt::OMPCriticalDirectiveClass: + case Stmt::OMPParallelForDirectiveClass: + case Stmt::OMPParallelSectionsDirectiveClass: + case Stmt::OMPTaskDirectiveClass: + case Stmt::OMPTaskyieldDirectiveClass: + case Stmt::OMPBarrierDirectiveClass: + case Stmt::OMPTaskwaitDirectiveClass: + case Stmt::OMPFlushDirectiveClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); case Stmt::ObjCSubscriptRefExprClass: @@ -848,7 +885,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, it != et; ++it) { ExplodedNode *N = *it; const LocationContext *LCtx = N->getLocationContext(); - SVal result = svalBuilder.conjureSymbolVal(0, Ex, LCtx, resultType, + SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, + resultType, currBldrCtx->blockCount()); ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result); Bldr2.generateNode(S, N, state); @@ -928,7 +966,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, ProgramStateRef NewState = createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0)); if (NewState != State) { - Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/0, + Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/nullptr, ProgramPoint::PreStmtKind); // Did we cache out? if (!Pred) @@ -1187,14 +1225,14 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N, const StackFrameContext *CalleeSF = CalleeLC->getCurrentStackFrame(); const StackFrameContext *CallerSF = CalleeSF->getParent()->getCurrentStackFrame(); assert(CalleeSF && CallerSF); - ExplodedNode *BeforeProcessingCall = 0; + ExplodedNode *BeforeProcessingCall = nullptr; const Stmt *CE = CalleeSF->getCallSite(); // Find the first node before we started processing the call expression. while (N) { ProgramPoint L = N->getLocation(); BeforeProcessingCall = N; - N = N->pred_empty() ? NULL : *(N->pred_begin()); + N = N->pred_empty() ? nullptr : *(N->pred_begin()); // Skip the nodes corresponding to the inlined code. if (L.getLocationContext()->getCurrentStackFrame() != CallerSF) @@ -1253,7 +1291,7 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, // FIXME: Refactor this into a checker. if (nodeBuilder.getContext().blockCount() >= AMgr.options.maxBlockVisitOnPath) { - static SimpleProgramPointTag tag("ExprEngine : Block count exceeded"); + static SimpleProgramPointTag tag(TagProviderName, "Block count exceeded"); const ExplodedNode *Sink = nodeBuilder.generateSink(Pred->getState(), Pred, &tag); @@ -1329,6 +1367,33 @@ static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr, return state->getSVal(Ex, LCtx); } +#ifndef NDEBUG +static const Stmt *getRightmostLeaf(const Stmt *Condition) { + while (Condition) { + const BinaryOperator *BO = dyn_cast<BinaryOperator>(Condition); + if (!BO || !BO->isLogicalOp()) { + return Condition; + } + Condition = BO->getRHS()->IgnoreParens(); + } + return nullptr; +} +#endif + +// Returns the condition the branch at the end of 'B' depends on and whose value +// has been evaluated within 'B'. +// In most cases, the terminator condition of 'B' will be evaluated fully in +// the last statement of 'B'; in those cases, the resolved condition is the +// given 'Condition'. +// If the condition of the branch is a logical binary operator tree, the CFG is +// optimized: in that case, we know that the expression formed by all but the +// rightmost leaf of the logical binary operator tree must be true, and thus +// the branch condition is at this point equivalent to the truth value of that +// rightmost leaf; the CFG block thus only evaluates this rightmost leaf +// expression in its final statement. As the full condition in that case was +// not evaluated, and is thus not in the SVal cache, we need to use that leaf +// expression to evaluate the truth value of the condition in the current state +// space. static const Stmt *ResolveCondition(const Stmt *Condition, const CFGBlock *B) { if (const Expr *Ex = dyn_cast<Expr>(Condition)) @@ -1338,6 +1403,12 @@ static const Stmt *ResolveCondition(const Stmt *Condition, if (!BO || !BO->isLogicalOp()) return Condition; + // FIXME: This is a workaround until we handle temporary destructor branches + // correctly; currently, temporary destructor branches lead to blocks that + // only have a terminator (and no statements). These blocks violate the + // invariant this function assumes. + if (B->getTerminator().isTemporaryDtorsBranch()) return Condition; + // For logical operations, we still have the case where some branches // use the traditional "merge" approach and others sink the branch // directly into the basic blocks representing the logical operation. @@ -1352,18 +1423,9 @@ static const Stmt *ResolveCondition(const Stmt *Condition, Optional<CFGStmt> CS = Elem.getAs<CFGStmt>(); if (!CS) continue; - if (CS->getStmt() != Condition) - break; - return Condition; - } - - assert(I != E); - - while (Condition) { - BO = dyn_cast<BinaryOperator>(Condition); - if (!BO || !BO->isLogicalOp()) - return Condition; - Condition = BO->getRHS()->IgnoreParens(); + const Stmt *LastStmt = CS->getStmt(); + assert(LastStmt == Condition || LastStmt == getRightmostLeaf(Condition)); + return LastStmt; } llvm_unreachable("could not resolve condition"); } @@ -1443,7 +1505,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, DefinedSVal V = X.castAs<DefinedSVal>(); ProgramStateRef StTrue, StFalse; - tie(StTrue, StFalse) = PrevState->assume(V); + std::tie(StTrue, StFalse) = PrevState->assume(V); // Process the true branch. if (builder.isFeasible(true)) { @@ -1461,7 +1523,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, builder.markInfeasible(false); } } - currBldrCtx = 0; + currBldrCtx = nullptr; } /// The GDM component containing the set of global variables which have been @@ -1490,7 +1552,7 @@ void ExprEngine::processStaticInitializer(const DeclStmt *DS, builder.generateNode(state, initHasRun, Pred); builder.markInfeasible(!initHasRun); - currBldrCtx = 0; + currBldrCtx = nullptr; } /// processIndirectGoto - Called by CoreEngine. Used to generate successor @@ -1631,7 +1693,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { } else { defaultIsFeasible = false; - DefaultSt = NULL; + DefaultSt = nullptr; } } @@ -1692,7 +1754,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, V = UnknownVal(); } - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, ProgramPoint::PostLValueKind); return; } @@ -1704,7 +1766,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, } if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { SVal V = svalBuilder.getFunctionPointer(FD); - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, ProgramPoint::PostLValueKind); return; } @@ -1715,7 +1777,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy, currBldrCtx->blockCount()); state = state->assume(V.castAs<DefinedOrUnknownSVal>(), true); - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, ProgramPoint::PostLValueKind); return; } @@ -1745,82 +1807,91 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, state->getSVal(Idx, LCtx), state->getSVal(Base, LCtx)); assert(A->isGLValue()); - Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), 0, + Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), nullptr, ProgramPoint::PostLValueKind); } } /// VisitMemberExpr - Transfer function for member expressions. void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, - ExplodedNodeSet &TopDst) { + ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, TopDst, *currBldrCtx); - ExplodedNodeSet Dst; + // FIXME: Prechecks eventually go in ::Visit(). + ExplodedNodeSet CheckedSet; + getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, M, *this); + + ExplodedNodeSet EvalSet; ValueDecl *Member = M->getMemberDecl(); // Handle static member variables and enum constants accessed via // member syntax. if (isa<VarDecl>(Member) || isa<EnumConstantDecl>(Member)) { - Bldr.takeNodes(Pred); - VisitCommonDeclRefExpr(M, Member, Pred, Dst); - Bldr.addNodes(Dst); - return; - } - - ProgramStateRef state = Pred->getState(); - const LocationContext *LCtx = Pred->getLocationContext(); - Expr *BaseExpr = M->getBase(); + ExplodedNodeSet Dst; + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I != E; ++I) { + VisitCommonDeclRefExpr(M, Member, Pred, EvalSet); + } + } else { + StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx); + ExplodedNodeSet Tmp; - // Handle C++ method calls. - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) { - if (MD->isInstance()) - state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I != E; ++I) { + ProgramStateRef state = (*I)->getState(); + const LocationContext *LCtx = (*I)->getLocationContext(); + Expr *BaseExpr = M->getBase(); - SVal MDVal = svalBuilder.getFunctionPointer(MD); - state = state->BindExpr(M, LCtx, MDVal); + // Handle C++ method calls. + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) { + if (MD->isInstance()) + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); - Bldr.generateNode(M, Pred, state); - return; - } + SVal MDVal = svalBuilder.getFunctionPointer(MD); + state = state->BindExpr(M, LCtx, MDVal); - // Handle regular struct fields / member variables. - state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); - SVal baseExprVal = state->getSVal(BaseExpr, LCtx); - - FieldDecl *field = cast<FieldDecl>(Member); - SVal L = state->getLValue(field, baseExprVal); - - if (M->isGLValue() || M->getType()->isArrayType()) { - - // We special case rvalue of array type because the analyzer cannot reason - // about it, since we expect all regions to be wrapped in Locs. So we will - // treat these as lvalues assuming that they will decay to pointers as soon - // as they are used. - if (!M->isGLValue()) { - assert(M->getType()->isArrayType()); - const ImplicitCastExpr *PE = - dyn_cast<ImplicitCastExpr>(Pred->getParentMap().getParent(M)); - if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) { - assert(false && - "We assume that array is always wrapped in ArrayToPointerDecay"); - L = UnknownVal(); + Bldr.generateNode(M, *I, state); + continue; } - } - if (field->getType()->isReferenceType()) { - if (const MemRegion *R = L.getAsRegion()) - L = state->getSVal(R); - else - L = UnknownVal(); - } + // Handle regular struct fields / member variables. + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); + SVal baseExprVal = state->getSVal(BaseExpr, LCtx); + + FieldDecl *field = cast<FieldDecl>(Member); + SVal L = state->getLValue(field, baseExprVal); + + if (M->isGLValue() || M->getType()->isArrayType()) { + // We special-case rvalues of array type because the analyzer cannot + // reason about them, since we expect all regions to be wrapped in Locs. + // We instead treat these as lvalues and assume that they will decay to + // pointers as soon as they are used. + if (!M->isGLValue()) { + assert(M->getType()->isArrayType()); + const ImplicitCastExpr *PE = + dyn_cast<ImplicitCastExpr>((*I)->getParentMap().getParent(M)); + if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) { + llvm_unreachable("should always be wrapped in ArrayToPointerDecay"); + } + } - Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), 0, - ProgramPoint::PostLValueKind); - } else { - Bldr.takeNodes(Pred); - evalLoad(Dst, M, M, Pred, state, L); - Bldr.addNodes(Dst); + if (field->getType()->isReferenceType()) { + if (const MemRegion *R = L.getAsRegion()) + L = state->getSVal(R); + else + L = UnknownVal(); + } + + Bldr.generateNode(M, *I, state->BindExpr(M, LCtx, L), nullptr, + ProgramPoint::PostLValueKind); + } else { + Bldr.takeNodes(*I); + evalLoad(Tmp, M, M, *I, state, L); + Bldr.addNodes(Tmp); + } + } } + + getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, M, *this); } namespace { @@ -1830,7 +1901,7 @@ public: CollectReachableSymbolsCallback(ProgramStateRef State) {} const InvalidatedSymbols &getSymbols() const { return Symbols; } - bool VisitSymbol(SymbolRef Sym) { + bool VisitSymbol(SymbolRef Sym) override { Symbols.insert(Sym); return true; } @@ -1876,9 +1947,9 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, const InvalidatedSymbols &EscapedSymbols = Scanner.getSymbols(); State = getCheckerManager().runCheckersForPointerEscape(State, EscapedSymbols, - /*CallEvent*/ 0, + /*CallEvent*/ nullptr, PSK_EscapeOnBind, - 0); + nullptr); return State; } @@ -1897,7 +1968,7 @@ ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State, if (!Call) return getCheckerManager().runCheckersForPointerEscape(State, *Invalidated, - 0, + nullptr, PSK_EscapeOther, &ITraits); @@ -1954,7 +2025,8 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, // If the location is not a 'Loc', it will already be handled by // the checkers. There is nothing left to do. if (!location.getAs<Loc>()) { - const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/0, /*tag*/0); + const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/nullptr, + /*tag*/nullptr); ProgramStateRef state = Pred->getState(); state = processPointerEscapedOnBind(state, location, Val); Bldr.generateNode(L, state, Pred); @@ -1975,13 +2047,13 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, state = state->bindLoc(location.castAs<Loc>(), Val, /* notifyChanges = */ !atDeclInit); - const MemRegion *LocReg = 0; + const MemRegion *LocReg = nullptr; if (Optional<loc::MemRegionVal> LocRegVal = location.getAs<loc::MemRegionVal>()) { LocReg = LocRegVal->getRegion(); } - - const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0); + + const ProgramPoint L = PostStore(StoreE, LC, LocReg, nullptr); Bldr.generateNode(L, state, PredI); } } @@ -2037,7 +2109,7 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst, QualType ValTy = TR->getValueType(); if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) { static SimpleProgramPointTag - loadReferenceTag("ExprEngine : Load Reference"); + loadReferenceTag(TagProviderName, "Load Reference"); ExplodedNodeSet Tmp; evalLoadCommon(Tmp, NodeEx, BoundEx, Pred, state, location, &loadReferenceTag, @@ -2120,7 +2192,7 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, // instead "int *p" is noted as // "Variable 'p' initialized to a null pointer value" - static SimpleProgramPointTag tag("ExprEngine: Location"); + static SimpleProgramPointTag tag(TagProviderName, "Location"); Bldr.generateNode(NodeEx, Pred, state, &tag); } ExplodedNodeSet Tmp; @@ -2132,8 +2204,10 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, std::pair<const ProgramPointTag *, const ProgramPointTag*> ExprEngine::geteagerlyAssumeBinOpBifurcationTags() { static SimpleProgramPointTag - eagerlyAssumeBinOpBifurcationTrue("ExprEngine : Eagerly Assume True"), - eagerlyAssumeBinOpBifurcationFalse("ExprEngine : Eagerly Assume False"); + eagerlyAssumeBinOpBifurcationTrue(TagProviderName, + "Eagerly Assume True"), + eagerlyAssumeBinOpBifurcationFalse(TagProviderName, + "Eagerly Assume False"); return std::make_pair(&eagerlyAssumeBinOpBifurcationTrue, &eagerlyAssumeBinOpBifurcationFalse); } @@ -2161,7 +2235,7 @@ void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, geteagerlyAssumeBinOpBifurcationTags(); ProgramStateRef StateTrue, StateFalse; - tie(StateTrue, StateFalse) = state->assume(*SEV); + std::tie(StateTrue, StateFalse) = state->assume(*SEV); // First assume that the condition is true. if (StateTrue) { @@ -2192,9 +2266,8 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, ProgramStateRef state = Pred->getState(); - for (GCCAsmStmt::const_outputs_iterator OI = A->begin_outputs(), - OE = A->end_outputs(); OI != OE; ++OI) { - SVal X = state->getSVal(*OI, Pred->getLocationContext()); + for (const Expr *O : A->outputs()) { + SVal X = state->getSVal(O, Pred->getLocationContext()); assert (!X.getAs<NonLoc>()); // Should be an Lval, or unknown, undef. if (Optional<Loc> LV = X.getAs<Loc>()) @@ -2368,11 +2441,12 @@ struct DOTGraphTraits<ExplodedNode*> : if (const CaseStmt *C = dyn_cast<CaseStmt>(Label)) { Out << "\\lcase "; LangOptions LO; // FIXME. - C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO)); + if (C->getLHS()) + C->getLHS()->printPretty(Out, nullptr, PrintingPolicy(LO)); if (const Stmt *RHS = C->getRHS()) { Out << " .. "; - RHS->printPretty(Out, 0, PrintingPolicy(LO)); + RHS->printPretty(Out, nullptr, PrintingPolicy(LO)); } Out << ":"; @@ -2411,10 +2485,11 @@ struct DOTGraphTraits<ExplodedNode*> : default: { const Stmt *S = Loc.castAs<StmtPoint>().getStmt(); + assert(S != nullptr && "Expecting non-null Stmt"); Out << S->getStmtClassName() << ' ' << (const void*) S << ' '; LangOptions LO; // FIXME. - S->printPretty(Out, 0, PrintingPolicy(LO)); + S->printPretty(Out, nullptr, PrintingPolicy(LO)); printLocation(Out, S->getLocStart()); if (Loc.getAs<PreStmt>()) @@ -2452,7 +2527,7 @@ struct DOTGraphTraits<ExplodedNode*> : } ProgramStateRef state = N->getState(); - Out << "\\|StateID: " << (const void*) state.getPtr() + Out << "\\|StateID: " << (const void*) state.get() << " NodeID: " << (const void*) N << "\\|"; state->printDOT(Out); @@ -2504,8 +2579,8 @@ void ExprEngine::ViewGraph(bool trim) { llvm::ViewGraph(*G.roots_begin(), "ExprEngine"); - GraphPrintCheckerState = NULL; - GraphPrintSourceManager = NULL; + GraphPrintCheckerState = nullptr; + GraphPrintSourceManager = nullptr; } #endif } @@ -2515,14 +2590,14 @@ void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode*> Nodes) { GraphPrintCheckerState = this; GraphPrintSourceManager = &getContext().getSourceManager(); - OwningPtr<ExplodedGraph> TrimmedG(G.trim(Nodes)); + std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Nodes)); if (!TrimmedG.get()) llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n"; else llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedExprEngine"); - GraphPrintCheckerState = NULL; - GraphPrintSourceManager = NULL; + GraphPrintCheckerState = nullptr; + GraphPrintSourceManager = nullptr; #endif } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 983fda0..ffda527 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -47,7 +47,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // FIXME: Handle structs. if (RightV.isUnknown()) { unsigned Count = currBldrCtx->blockCount(); - RightV = svalBuilder.conjureSymbolVal(0, B->getRHS(), LCtx, Count); + RightV = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, + Count); } // Simulate the effects of a "store": bind the value of the RHS // to the L-Value represented by the LHS. @@ -81,6 +82,12 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, } } + // Although we don't yet model pointers-to-members, we do need to make + // sure that the members of temporaries have a valid 'this' pointer for + // other checks. + if (B->getOpcode() == BO_PtrMemD) + state = createTemporaryRegionIfNeeded(state, LCtx, LHS); + // Process non-assignments except commas or short-circuited // logical expressions (LAnd and LOr). SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType()); @@ -151,7 +158,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // The symbolic value is actually for the type of the left-hand side // expression, not the computation type, as this is the value the // LValue on the LHS will bind to. - LHSVal = svalBuilder.conjureSymbolVal(0, B->getRHS(), LCtx, LTy, + LHSVal = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, LTy, currBldrCtx->blockCount()); // However, we need to convert the symbol to the computation type. Result = svalBuilder.evalCast(LHSVal, CTy, LTy); @@ -211,8 +218,8 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx); Bldr.generateNode(BE, Pred, State->BindExpr(BE, Pred->getLocationContext(), V), - 0, ProgramPoint::PostLValueKind); - + nullptr, ProgramPoint::PostLValueKind); + // FIXME: Move all post/pre visits to ::Visit(). getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this); } @@ -286,6 +293,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_Dependent: case CK_ArrayToPointerDecay: case CK_BitCast: + case CK_AddressSpaceConversion: case CK_IntegralCast: case CK_NullToPointer: case CK_IntegralToPointer: @@ -360,7 +368,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, // If we don't know if the cast succeeded, conjure a new symbol. if (val.isUnknown()) { DefinedOrUnknownSVal NewSym = - svalBuilder.conjureSymbolVal(0, CastE, LCtx, resultType, + svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType, currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, NewSym); } else @@ -388,7 +396,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, QualType resultType = CastE->getType(); if (CastE->isGLValue()) resultType = getContext().getPointerType(resultType); - SVal result = svalBuilder.conjureSymbolVal(0, CastE, LCtx, + SVal result = svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType, currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, result); @@ -486,7 +494,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, Ty = getContext().getPointerType(Ty); } - InitVal = svalBuilder.conjureSymbolVal(0, InitEx, LC, Ty, + InitVal = svalBuilder.conjureSymbolVal(nullptr, InitEx, LC, Ty, currBldrCtx->blockCount()); } @@ -554,7 +562,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, } else { DefinedOrUnknownSVal DefinedRHS = RHSVal.castAs<DefinedOrUnknownSVal>(); ProgramStateRef StTrue, StFalse; - llvm::tie(StTrue, StFalse) = N->getState()->assume(DefinedRHS); + std::tie(StTrue, StFalse) = N->getState()->assume(DefinedRHS); if (StTrue) { if (StFalse) { // We can't constrain the value to 0 or 1. @@ -633,7 +641,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, StmtNodeBuilder B(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); - const CFGBlock *SrcBlock = 0; + const CFGBlock *SrcBlock = nullptr; // Find the predecessor block. ProgramStateRef SrcState = state; @@ -678,7 +686,8 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, } if (!hasValue) - V = svalBuilder.conjureSymbolVal(0, Ex, LCtx, currBldrCtx->blockCount()); + V = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, + currBldrCtx->blockCount()); // Generate a new node with the binding from the appropriate path. B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V, true)); @@ -707,34 +716,43 @@ void ExprEngine:: VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); + // FIXME: Prechecks eventually go in ::Visit(). + ExplodedNodeSet CheckedSet; + getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, Ex, *this); + + ExplodedNodeSet EvalSet; + StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx); QualType T = Ex->getTypeOfArgument(); - - if (Ex->getKind() == UETT_SizeOf) { - if (!T->isIncompleteType() && !T->isConstantSizeType()) { - assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); - - // FIXME: Add support for VLA type arguments and VLA expressions. - // When that happens, we should probably refactor VLASizeChecker's code. - return; - } - else if (T->getAs<ObjCObjectType>()) { - // Some code tries to take the sizeof an ObjCObjectType, relying that - // the compiler has laid out its representation. Just report Unknown - // for these. - return; + + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I != E; ++I) { + if (Ex->getKind() == UETT_SizeOf) { + if (!T->isIncompleteType() && !T->isConstantSizeType()) { + assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); + + // FIXME: Add support for VLA type arguments and VLA expressions. + // When that happens, we should probably refactor VLASizeChecker's code. + continue; + } else if (T->getAs<ObjCObjectType>()) { + // Some code tries to take the sizeof an ObjCObjectType, relying that + // the compiler has laid out its representation. Just report Unknown + // for these. + continue; + } } + + 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); } - - APSInt Value = Ex->EvaluateKnownConstInt(getContext()); - CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue()); - - ProgramStateRef state = Pred->getState(); - state = state->BindExpr(Ex, Pred->getLocationContext(), - svalBuilder.makeIntVal(amt.getQuantity(), - Ex->getType())); - Bldr.generateNode(Ex, Pred, state); + + getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this); } void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, @@ -919,7 +937,8 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, // Conjure a new symbol if necessary to recover precision. if (Result.isUnknown()){ DefinedOrUnknownSVal SymVal = - svalBuilder.conjureSymbolVal(0, Ex, LCtx, currBldrCtx->blockCount()); + svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, + currBldrCtx->blockCount()); Result = SymVal; // If the value is a location, ++/-- should always preserve diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index eba4f94..2a76621 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -91,12 +91,6 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, /// If the type is not an array type at all, the original value is returned. static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue, QualType &Ty) { - // FIXME: This check is just a temporary workaround, because - // ProcessTemporaryDtor sends us NULL regions. It will not be necessary once - // we can properly process temporary destructors. - if (!LValue.getAsRegion()) - return LValue; - SValBuilder &SVB = State->getStateManager().getSValBuilder(); ASTContext &Ctx = SVB.getContext(); @@ -108,13 +102,85 @@ static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue, return LValue; } + +static const MemRegion *getRegionForConstructedObject( + const CXXConstructExpr *CE, ExplodedNode *Pred, ExprEngine &Eng, + unsigned int CurrStmtIdx) { + const LocationContext *LCtx = Pred->getLocationContext(); + ProgramStateRef State = Pred->getState(); + const NodeBuilderContext &CurrBldrCtx = Eng.getBuilderContext(); + + // See if we're constructing an existing region by looking at the next + // element in the CFG. + const CFGBlock *B = CurrBldrCtx.getBlock(); + unsigned int NextStmtIdx = CurrStmtIdx + 1; + if (NextStmtIdx < B->size()) { + CFGElement Next = (*B)[NextStmtIdx]; + + // Is this a destructor? If so, we might be in the middle of an assignment + // to a local or member: look ahead one more element to see what we find. + while (Next.getAs<CFGImplicitDtor>() && NextStmtIdx + 1 < B->size()) { + ++NextStmtIdx; + Next = (*B)[NextStmtIdx]; + } + + // Is this a constructor for a local variable? + if (Optional<CFGStmt> StmtElem = Next.getAs<CFGStmt>()) { + if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt())) { + if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) { + if (Var->getInit() && Var->getInit()->IgnoreImplicit() == CE) { + SVal LValue = State->getLValue(Var, LCtx); + QualType Ty = Var->getType(); + LValue = makeZeroElementRegion(State, LValue, Ty); + return LValue.getAsRegion(); + } + } + } + } + + // Is this a constructor for a member? + if (Optional<CFGInitializer> InitElem = Next.getAs<CFGInitializer>()) { + const CXXCtorInitializer *Init = InitElem->getInitializer(); + assert(Init->isAnyMemberInitializer()); + + const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl()); + Loc ThisPtr = Eng.getSValBuilder().getCXXThis(CurCtor, + LCtx->getCurrentStackFrame()); + SVal ThisVal = State->getSVal(ThisPtr); + + const ValueDecl *Field; + SVal FieldVal; + if (Init->isIndirectMemberInitializer()) { + Field = Init->getIndirectMember(); + FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal); + } else { + Field = Init->getMember(); + FieldVal = State->getLValue(Init->getMember(), ThisVal); + } + + QualType Ty = Field->getType(); + FieldVal = makeZeroElementRegion(State, FieldVal, Ty); + return FieldVal.getAsRegion(); + } + + // FIXME: This will eventually need to handle new-expressions as well. + // Don't forget to update the pre-constructor initialization code in + // ExprEngine::VisitCXXConstructExpr. + } + + // If we couldn't find an existing region to construct into, assume we're + // constructing a temporary. + MemRegionManager &MRMgr = Eng.getSValBuilder().getRegionManager(); + return MRMgr.getCXXTempObjectRegion(CE, LCtx); +} + void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ExplodedNode *Pred, ExplodedNodeSet &destNodes) { const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); - const MemRegion *Target = 0; + const MemRegion *Target = nullptr; // FIXME: Handle arrays, which run the same constructor for every element. // For now, we just run the first constructor (which should still invalidate @@ -122,62 +188,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, switch (CE->getConstructionKind()) { case CXXConstructExpr::CK_Complete: { - // See if we're constructing an existing region by looking at the next - // element in the CFG. - const CFGBlock *B = currBldrCtx->getBlock(); - if (currStmtIdx + 1 < B->size()) { - CFGElement Next = (*B)[currStmtIdx+1]; - - // Is this a constructor for a local variable? - if (Optional<CFGStmt> StmtElem = Next.getAs<CFGStmt>()) { - if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt())) { - if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) { - if (Var->getInit()->IgnoreImplicit() == CE) { - SVal LValue = State->getLValue(Var, LCtx); - QualType Ty = Var->getType(); - LValue = makeZeroElementRegion(State, LValue, Ty); - Target = LValue.getAsRegion(); - } - } - } - } - - // Is this a constructor for a member? - if (Optional<CFGInitializer> InitElem = Next.getAs<CFGInitializer>()) { - const CXXCtorInitializer *Init = InitElem->getInitializer(); - assert(Init->isAnyMemberInitializer()); - - const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl()); - Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor, - LCtx->getCurrentStackFrame()); - SVal ThisVal = State->getSVal(ThisPtr); - - const ValueDecl *Field; - SVal FieldVal; - if (Init->isIndirectMemberInitializer()) { - Field = Init->getIndirectMember(); - FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal); - } else { - Field = Init->getMember(); - FieldVal = State->getLValue(Init->getMember(), ThisVal); - } - - QualType Ty = Field->getType(); - FieldVal = makeZeroElementRegion(State, FieldVal, Ty); - Target = FieldVal.getAsRegion(); - } - - // FIXME: This will eventually need to handle new-expressions as well. - // Don't forget to update the pre-constructor initialization code below. - } - - // If we couldn't find an existing region to construct into, assume we're - // constructing a temporary. - if (!Target) { - MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); - Target = MRMgr.getCXXTempObjectRegion(CE, LCtx); - } - + Target = getRegionForConstructedObject(CE, Pred, *this, currStmtIdx); break; } case CXXConstructExpr::CK_VirtualBase: @@ -251,7 +262,8 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, // since it's then possible to be initializing one part of a multi- // dimensional array. State = State->bindDefault(loc::MemRegionVal(Target), ZeroVal); - Bldr.generateNode(CE, *I, State, /*tag=*/0, ProgramPoint::PreStmtKind); + Bldr.generateNode(CE, *I, State, /*tag=*/nullptr, + ProgramPoint::PreStmtKind); } } } @@ -329,6 +341,32 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType, *Call, *this); } +void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + ProgramStateRef State = Pred->getState(); + const LocationContext *LCtx = Pred->getLocationContext(); + PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), + CNE->getStartLoc(), + "Error evaluating New Allocator Call"); + CallEventManager &CEMgr = getStateManager().getCallEventManager(); + CallEventRef<CXXAllocatorCall> Call = + CEMgr.getCXXAllocatorCall(CNE, State, LCtx); + + ExplodedNodeSet DstPreCall; + getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, + *Call, *this); + + ExplodedNodeSet DstInvalidated; + StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx); + for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); + I != E; ++I) + defaultEvalCall(Bldr, *I, *Call); + getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated, + *Call, *this); +} + + void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // FIXME: Much of this should eventually migrate to CXXAllocatorCall. @@ -360,7 +398,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, if (IsStandardGlobalOpNewFunction) symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount); else - symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx, CNE->getType(), + symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(), blockCount); ProgramStateRef State = Pred->getState(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 06328e4..3f608ba 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -11,8 +11,6 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "ExprEngine" - #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "PrettyStackTraceLocationContext.h" #include "clang/AST/CXXInheritance.h" @@ -28,6 +26,8 @@ using namespace clang; using namespace ento; +#define DEBUG_TYPE "ExprEngine" + STATISTIC(NumOfDynamicDispatchPathSplits, "The # of times we split the path due to imprecise dynamic dispatch info"); @@ -49,7 +49,7 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) { assert(Entry->empty()); assert(Entry->succ_size() == 1); - // Get the solitary sucessor. + // Get the solitary successor. const CFGBlock *Succ = *(Entry->succ_begin()); // Construct an edge representing the starting location in the callee. @@ -69,8 +69,8 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) { // corresponding Block. static std::pair<const Stmt*, const CFGBlock*> getLastStmt(const ExplodedNode *Node) { - const Stmt *S = 0; - const CFGBlock *Blk = 0; + const Stmt *S = nullptr; + const CFGBlock *Blk = nullptr; const StackFrameContext *SF = Node->getLocation().getLocationContext()->getCurrentStackFrame(); @@ -108,12 +108,12 @@ static std::pair<const Stmt*, } if (Node->pred_empty()) - return std::pair<const Stmt*, const CFGBlock*>((Stmt*)0, (CFGBlock*)0); + return std::make_pair(nullptr, nullptr); Node = *Node->pred_begin(); } - return std::pair<const Stmt*, const CFGBlock*>(S, Blk); + return std::make_pair(S, Blk); } /// Adjusts a return value when the called function's return type does not @@ -160,9 +160,9 @@ void ExprEngine::removeDeadOnEndOfFunction(NodeBuilderContext& BC, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // Find the last statement in the function and the corresponding basic block. - const Stmt *LastSt = 0; - const CFGBlock *Blk = 0; - llvm::tie(LastSt, Blk) = getLastStmt(Pred); + const Stmt *LastSt = nullptr; + const CFGBlock *Blk = nullptr; + std::tie(LastSt, Blk) = getLastStmt(Pred); if (!Blk || !LastSt) { Dst.Add(Pred); return; @@ -229,9 +229,9 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { const Stmt *CE = calleeCtx->getCallSite(); ProgramStateRef state = CEBNode->getState(); // Find the last statement in the function and the corresponding basic block. - const Stmt *LastSt = 0; - const CFGBlock *Blk = 0; - llvm::tie(LastSt, Blk) = getLastStmt(CEBNode); + const Stmt *LastSt = nullptr; + const CFGBlock *Blk = nullptr; + std::tie(LastSt, Blk) = getLastStmt(CEBNode); // Generate a CallEvent /before/ cleaning the state, so that we can get the // correct value for 'this' (if necessary). @@ -282,7 +282,7 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { // they occurred. ExplodedNodeSet CleanedNodes; if (LastSt && Blk && AMgr.options.AnalysisPurgeOpt != PurgeNone) { - static SimpleProgramPointTag retValBind("ExprEngine : Bind Return Value"); + static SimpleProgramPointTag retValBind("ExprEngine", "Bind Return Value"); PostStmt Loc(LastSt, calleeCtx, &retValBind); bool isNew; ExplodedNode *BindedRetNode = G.getNode(Loc, state, false, &isNew); @@ -296,10 +296,10 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { // context, telling it to clean up everything in the callee's context // (and its children). We use the callee's function body as a diagnostic // statement, with which the program point will be associated. - removeDead(BindedRetNode, CleanedNodes, 0, calleeCtx, + removeDead(BindedRetNode, CleanedNodes, nullptr, calleeCtx, calleeCtx->getAnalysisDeclContext()->getBody(), ProgramPoint::PostStmtPurgeDeadSymbolsKind); - currBldrCtx = 0; + currBldrCtx = nullptr; } else { CleanedNodes.Add(CEBNode); } @@ -387,14 +387,14 @@ static bool IsInStdNamespace(const FunctionDecl *FD) { 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->getName() == "std"; + return ND->isStdNamespace(); } // The GDM component containing the dynamic dispatch bifurcation info. When @@ -471,7 +471,7 @@ static ProgramStateRef getInlineFailedState(ProgramStateRef State, const Stmt *CallE) { const void *ReplayState = State->get<ReplayWithoutInlining>(); if (!ReplayState) - return 0; + return nullptr; assert(ReplayState == CallE && "Backtracked to the wrong call."); (void)CallE; @@ -565,7 +565,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, QualType ResultTy = Call.getResultType(); SValBuilder &SVB = getSValBuilder(); unsigned Count = currBldrCtx->blockCount(); - SVal R = SVB.conjureSymbolVal(0, E, LCtx, ResultTy, Count); + SVal R = SVB.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count); return State->BindExpr(E, LCtx, R); } @@ -664,6 +664,8 @@ static CallInlinePolicy mayInlineCallKind(const CallEvent &Call, break; } case CE_CXXAllocator: + if (Opts.mayInlineCXXAllocator()) + break; // Do not inline allocators until we model deallocators. // This is unfortunate, but basically necessary for smart pointers and such. return CIP_DisallowedAlways; @@ -706,18 +708,16 @@ static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD) { hasMember(Ctx, RD, "iterator_category"); } -/// Returns true if the given function refers to a constructor or destructor of -/// a C++ container or iterator. +/// Returns true if the given function refers to a method of a C++ container +/// or iterator. /// -/// We generally do a poor job modeling most containers right now, and would -/// prefer not to inline their setup and teardown. -static bool isContainerCtorOrDtor(const ASTContext &Ctx, - const FunctionDecl *FD) { - if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD))) - return false; - - const CXXRecordDecl *RD = cast<CXXMethodDecl>(FD)->getParent(); - return isContainerClass(Ctx, RD); +/// We generally do a poor job modeling most containers right now, and might +/// prefer not to inline their methods. +static bool isContainerMethod(const ASTContext &Ctx, + const FunctionDecl *FD) { + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) + return isContainerClass(Ctx, MD->getParent()); + return false; } /// Returns true if the given function is the destructor of a class named @@ -763,9 +763,9 @@ static bool mayInlineDecl(AnalysisDeclContext *CalleeADC, // Conditionally control the inlining of methods on objects that look // like C++ containers. - if (!Opts.mayInlineCXXContainerCtorsAndDtors()) + if (!Opts.mayInlineCXXContainerMethods()) if (!Ctx.getSourceManager().isInMainFile(FD->getLocation())) - if (isContainerCtorOrDtor(Ctx, FD)) + if (isContainerMethod(Ctx, FD)) return false; // Conditionally control the inlining of the destructor of C++ shared_ptr. diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp index d276d92..a6611e0 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp @@ -77,7 +77,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) { const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl()); - assert(elemD->getInit() == 0); + assert(elemD->getInit() == nullptr); elementV = state->getLValue(elemD, Pred->getLocationContext()); } else { @@ -85,7 +85,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, } ExplodedNodeSet dstLocation; - evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false); + evalLocation(dstLocation, S, elem, Pred, state, elementV, nullptr, false); ExplodedNodeSet Tmp; StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx); @@ -165,7 +165,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME, recVal.castAs<DefinedOrUnknownSVal>(); ProgramStateRef notNilState, nilState; - llvm::tie(notNilState, nilState) = State->assume(receiverVal); + std::tie(notNilState, nilState) = State->assume(receiverVal); // There are three cases: can be nil or non-nil, must be nil, must be // non-nil. We ignore must be nil, and merge the rest two into non-nil. diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index 365f6ab..b1e9f06 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -20,11 +20,13 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Rewrite/Core/HTMLRewrite.h" #include "clang/Rewrite/Core/Rewriter.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include <sstream> using namespace clang; using namespace ento; @@ -39,15 +41,16 @@ class HTMLDiagnostics : public PathDiagnosticConsumer { std::string Directory; bool createdDir, noDir; const Preprocessor &PP; + AnalyzerOptions &AnalyzerOpts; public: - HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp); + HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, const Preprocessor &pp); - virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); } + virtual ~HTMLDiagnostics() { FlushDiagnostics(nullptr); } - virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, - FilesMade *filesMade); + void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, + FilesMade *filesMade) override; - virtual StringRef getName() const { + StringRef getName() const override { return "HTMLDiagnostics"; } @@ -68,16 +71,17 @@ public: } // end anonymous namespace -HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, +HTMLDiagnostics::HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, + const std::string& prefix, const Preprocessor &pp) - : Directory(prefix), createdDir(false), noDir(false), PP(pp) { + : Directory(prefix), createdDir(false), noDir(false), PP(pp), AnalyzerOpts(AnalyzerOpts) { } void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, const std::string& prefix, const Preprocessor &PP) { - C.push_back(new HTMLDiagnostics(prefix, PP)); + C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP)); } //===----------------------------------------------------------------------===// @@ -95,13 +99,11 @@ void HTMLDiagnostics::FlushDiagnosticsImpl( void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, FilesMade *filesMade) { - + // Create the HTML directory if it is missing. if (!createdDir) { createdDir = true; - bool existed; - if (llvm::error_code ec = - llvm::sys::fs::create_directories(Directory, existed)) { + if (std::error_code ec = llvm::sys::fs::create_directories(Directory)) { llvm::errs() << "warning: could not create directory '" << Directory << "': " << ec.message() << '\n'; @@ -128,11 +130,30 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, // Create a new rewriter to generate HTML. Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOpts()); + // Get the function/method name + SmallString<128> declName("unknown"); + int offsetDecl = 0; + if (const Decl *DeclWithIssue = D.getDeclWithIssue()) { + if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) { + declName = ND->getDeclName().getAsString(); + } + + if (const Stmt *Body = DeclWithIssue->getBody()) { + // Retrieve the relative position of the declaration which will be used + // for the file name + FullSourceLoc L( + SMgr.getExpansionLoc((*path.rbegin())->getLocation().asLocation()), + SMgr); + FullSourceLoc FunL(SMgr.getExpansionLoc(Body->getLocStart()), SMgr); + offsetDecl = L.getExpansionLineNumber() - FunL.getExpansionLineNumber(); + } + } + // Process the path. unsigned n = path.size(); unsigned max = n; - for (PathPieces::const_reverse_iterator I = path.rbegin(), + for (PathPieces::const_reverse_iterator I = path.rbegin(), E = path.rend(); I != E; ++I, --n) HandlePiece(R, FID, **I, n, max); @@ -165,6 +186,9 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, DirName += '/'; } + int LineNumber = (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber(); + int ColumnNumber = (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber(); + // Add the name of the file as an <h1> tag. { @@ -178,9 +202,9 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, << html::EscapeText(Entry->getName()) << "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>" "<a href=\"#EndPath\">line " - << (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber() + << LineNumber << ", column " - << (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber() + << ColumnNumber << "</a></td></tr>\n" "<tr><td class=\"rowname\">Description:</td><td>" << D.getVerboseDescription() << "</td></tr>\n"; @@ -217,12 +241,16 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n"; + os << "\n<!-- FILENAME " << llvm::sys::path::filename(Entry->getName()) << " -->\n"; + + os << "\n<!-- FUNCTIONNAME " << declName << " -->\n"; + os << "\n<!-- BUGLINE " - << path.back()->getLocation().asLocation().getExpansionLineNumber() + << LineNumber << " -->\n"; os << "\n<!-- BUGCOLUMN " - << path.back()->getLocation().asLocation().getExpansionColumnNumber() + << ColumnNumber << " -->\n"; os << "\n<!-- BUGPATHLENGTH " << path.size() << " -->\n"; @@ -249,13 +277,42 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, // Create a path for the target HTML file. int FD; SmallString<128> Model, ResultPath; - llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); - if (llvm::error_code EC = + if (!AnalyzerOpts.shouldWriteStableReportFilename()) { + llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); + + if (std::error_code EC = llvm::sys::fs::createUniqueFile(Model.str(), FD, ResultPath)) { - llvm::errs() << "warning: could not create file in '" << Directory - << "': " << EC.message() << '\n'; - return; + llvm::errs() << "warning: could not create file in '" << Directory + << "': " << EC.message() << '\n'; + return; + } + + } else { + int i = 1; + std::error_code EC; + do { + // Find a filename which is not already used + std::stringstream filename; + Model = ""; + filename << "report-" + << llvm::sys::path::filename(Entry->getName()).str() + << "-" << declName.c_str() + << "-" << offsetDecl + << "-" << i << ".html"; + llvm::sys::path::append(Model, Directory, + filename.str()); + EC = llvm::sys::fs::openFileForWrite(Model.str(), + FD, + llvm::sys::fs::F_RW | + llvm::sys::fs::F_Excl); + if (EC && EC != std::errc::file_exists) { + llvm::errs() << "warning: could not create file '" << Model.str() + << "': " << EC.message() << '\n'; + return; + } + i++; + } while (EC); } llvm::raw_fd_ostream os(FD, true); @@ -309,7 +366,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, // Create the html for the message. - const char *Kind = 0; + const char *Kind = nullptr; switch (P.getKind()) { case PathDiagnosticPiece::Call: llvm_unreachable("Calls should already be handled"); @@ -460,7 +517,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, << (num + 1) << ")\">→</a></div></td>"; } - + os << "</tr></table>"; } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index 162cd33..22711f5 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -148,7 +148,7 @@ MemRegionManager::~MemRegionManager() { bool SubRegion::isSubRegionOf(const MemRegion* R) const { const MemRegion* r = getSuperRegion(); - while (r != 0) { + while (r != nullptr) { if (r == R) return true; if (const SubRegion* sr = dyn_cast<SubRegion>(r)) @@ -173,7 +173,7 @@ MemRegionManager* SubRegion::getMemRegionManager() const { const StackFrameContext *VarRegion::getStackFrame() const { const StackSpaceRegion *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace()); - return SSR ? SSR->getStackFrame() : NULL; + return SSR ? SSR->getStackFrame() : nullptr; } //===----------------------------------------------------------------------===// @@ -508,11 +508,13 @@ void ObjCIvarRegion::dumpToStream(raw_ostream &os) const { } void StringRegion::dumpToStream(raw_ostream &os) const { - Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOpts())); + assert(Str != nullptr && "Expecting non-null StringLiteral"); + Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts())); } void ObjCStringRegion::dumpToStream(raw_ostream &os) const { - Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOpts())); + assert(Str != nullptr && "Expecting non-null ObjCStringLiteral"); + Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts())); } void SymbolicRegion::dumpToStream(raw_ostream &os) const { @@ -757,12 +759,12 @@ getStackOrCaptureRegionForDeclContext(const LocationContext *LC, LC = LC->getParent(); } - return (const StackFrameContext*)0; + return (const StackFrameContext *)nullptr; } const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, const LocationContext *LC) { - const MemRegion *sReg = 0; + const MemRegion *sReg = nullptr; if (D->hasGlobalStorage() && !D->isStaticLocal()) { @@ -850,7 +852,7 @@ const BlockDataRegion * MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC, const LocationContext *LC, unsigned blockCount) { - const MemRegion *sReg = 0; + const MemRegion *sReg = nullptr; const BlockDecl *BD = BC->getDecl(); if (!BD->hasCaptures()) { // This handles 'static' blocks. @@ -877,14 +879,14 @@ MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC, const CXXTempObjectRegion * MemRegionManager::getCXXStaticTempObjectRegion(const Expr *Ex) { return getSubRegion<CXXTempObjectRegion>( - Ex, getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, NULL)); + Ex, getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, nullptr)); } const CompoundLiteralRegion* MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL, const LocationContext *LC) { - const MemRegion *sReg = 0; + const MemRegion *sReg = nullptr; if (CL->isFileScope()) sReg = getGlobalsRegion(); @@ -975,10 +977,8 @@ static bool isValidBaseClass(const CXXRecordDecl *BaseClass, if (IsVirtual) return Class->isVirtuallyDerivedFrom(BaseClass); - for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(), - E = Class->bases_end(); - I != E; ++I) { - if (I->getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass) + for (const auto &I : Class->bases()) { + if (I.getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass) return true; } @@ -1113,7 +1113,7 @@ const SymbolicRegion *MemRegion::getSymbolicBase() const { return SymR; SubR = dyn_cast<SubRegion>(SubR->getSuperRegion()); } - return 0; + return nullptr; } // FIXME: Merge with the implementation of the same method in Store.cpp @@ -1130,7 +1130,7 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { RegionRawOffset ElementRegion::getAsArrayOffset() const { CharUnits offset = CharUnits::Zero(); const ElementRegion *ER = this; - const MemRegion *superR = NULL; + const MemRegion *superR = nullptr; ASTContext &C = getContext(); // FIXME: Handle multi-dimensional arrays. @@ -1162,7 +1162,7 @@ RegionRawOffset ElementRegion::getAsArrayOffset() const { continue; } - return NULL; + return nullptr; } assert(superR && "super region cannot be NULL"); @@ -1176,10 +1176,8 @@ static bool isImmediateBase(const CXXRecordDecl *Child, // Note that we do NOT canonicalize the base class here, because // ASTRecordLayout doesn't either. If that leads us down the wrong path, // so be it; at least we won't crash. - for (CXXRecordDecl::base_class_const_iterator I = Child->bases_begin(), - E = Child->bases_end(); - I != E; ++I) { - if (I->getType()->getAsCXXRecordDecl() == Base) + for (const auto &I : Child->bases()) { + if (I.getType()->getAsCXXRecordDecl() == Base) return true; } @@ -1188,7 +1186,7 @@ static bool isImmediateBase(const CXXRecordDecl *Child, RegionOffset MemRegion::getAsOffset() const { const MemRegion *R = this; - const MemRegion *SymbolicOffsetBase = 0; + const MemRegion *SymbolicOffsetBase = nullptr; int64_t Offset = 0; while (1) { @@ -1360,10 +1358,10 @@ RegionOffset MemRegion::getAsOffset() const { std::pair<const VarRegion *, const VarRegion *> BlockDataRegion::getCaptureRegions(const VarDecl *VD) { MemRegionManager &MemMgr = *getMemRegionManager(); - const VarRegion *VR = 0; - const VarRegion *OriginalVR = 0; + const VarRegion *VR = nullptr; + const VarRegion *OriginalVR = nullptr; - if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage()) { + if (!VD->hasAttr<BlocksAttr>() && VD->hasLocalStorage()) { VR = MemMgr.getVarRegion(VD, this); OriginalVR = MemMgr.getVarRegion(VD, LC); } @@ -1386,7 +1384,7 @@ void BlockDataRegion::LazyInitializeReferencedVars() { AnalysisDeclContext *AC = getCodeRegion()->getAnalysisDeclContext(); AnalysisDeclContext::referenced_decls_iterator I, E; - llvm::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl()); + std::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl()); if (I == E) { ReferencedVars = (void*) 0x1; @@ -1404,9 +1402,9 @@ void BlockDataRegion::LazyInitializeReferencedVars() { new (BVOriginal) VarVec(BC, E - I); for ( ; I != E; ++I) { - const VarRegion *VR = 0; - const VarRegion *OriginalVR = 0; - llvm::tie(VR, OriginalVR) = getCaptureRegions(*I); + const VarRegion *VR = nullptr; + const VarRegion *OriginalVR = nullptr; + std::tie(VR, OriginalVR) = getCaptureRegions(*I); assert(VR); assert(OriginalVR); BV->push_back(VR, BC); @@ -1425,8 +1423,8 @@ BlockDataRegion::referenced_vars_begin() const { static_cast<BumpVector<const MemRegion*>*>(ReferencedVars); if (Vec == (void*) 0x1) - return BlockDataRegion::referenced_vars_iterator(0, 0); - + return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr); + BumpVector<const MemRegion*> *VecOriginal = static_cast<BumpVector<const MemRegion*>*>(OriginalVars); @@ -1442,8 +1440,8 @@ BlockDataRegion::referenced_vars_end() const { static_cast<BumpVector<const MemRegion*>*>(ReferencedVars); if (Vec == (void*) 0x1) - return BlockDataRegion::referenced_vars_iterator(0, 0); - + return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr); + BumpVector<const MemRegion*> *VecOriginal = static_cast<BumpVector<const MemRegion*>*>(OriginalVars); @@ -1458,7 +1456,7 @@ const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const { if (I.getCapturedRegion() == R) return I.getOriginalRegion(); } - return 0; + return nullptr; } //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index b504db6..fd25bd8 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -16,6 +16,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/SourceManager.h" @@ -66,7 +67,7 @@ PathPieces::~PathPieces() {} void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, bool ShouldFlattenMacros) const { for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { - PathDiagnosticPiece *Piece = I->getPtr(); + PathDiagnosticPiece *Piece = I->get(); switch (Piece->getKind()) { case PathDiagnosticPiece::Call: { @@ -106,12 +107,13 @@ void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, PathDiagnostic::~PathDiagnostic() {} -PathDiagnostic::PathDiagnostic(const Decl *declWithIssue, +PathDiagnostic::PathDiagnostic(StringRef CheckName, const Decl *declWithIssue, StringRef bugtype, StringRef verboseDesc, StringRef shortDesc, StringRef category, PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique) - : DeclWithIssue(declWithIssue), + : CheckName(CheckName), + DeclWithIssue(declWithIssue), BugType(StripTrailingDots(bugtype)), VerboseDesc(StripTrailingDots(verboseDesc)), ShortDesc(StripTrailingDots(shortDesc)), @@ -127,7 +129,7 @@ getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, // If the call is within a macro, don't do anything (for now). if (CallLoc.isMacroID()) - return 0; + return nullptr; assert(SMgr.isInMainFile(CallLoc) && "The call piece should be in the main file."); @@ -138,7 +140,7 @@ getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, const PathPieces &Path = CP->path; if (Path.empty()) - return 0; + return nullptr; // Check if the last piece in the callee path is a call to a function outside // of the main file. @@ -148,14 +150,14 @@ getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, } // Otherwise, the last piece is in the main file. - return 0; + return nullptr; } void PathDiagnostic::resetDiagnosticLocationToMainFile() { if (path.empty()) return; - PathDiagnosticPiece *LastP = path.back().getPtr(); + PathDiagnosticPiece *LastP = path.back().get(); assert(LastP); const SourceManager &SMgr = LastP->getLocation().getManager(); @@ -196,8 +198,8 @@ PathDiagnosticConsumer::~PathDiagnosticConsumer() { } void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { - OwningPtr<PathDiagnostic> OwningD(D); - + std::unique_ptr<PathDiagnostic> OwningD(D); + if (!D || D->path.empty()) return; @@ -220,7 +222,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) { - const PathDiagnosticPiece *piece = I->getPtr(); + const PathDiagnosticPiece *piece = I->get(); FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); if (FID.isInvalid()) { @@ -258,7 +260,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { // Profile the node to see if we already have something matching it llvm::FoldingSetNodeID profile; D->Profile(profile); - void *InsertPos = 0; + void *InsertPos = nullptr; if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { // Keep the PathDiagnostic with the shorter path. @@ -274,8 +276,8 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { Diags.RemoveNode(orig); delete orig; } - - Diags.InsertNode(OwningD.take()); + + Diags.InsertNode(OwningD.release()); } static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y); @@ -415,17 +417,6 @@ static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { return b.getValue(); } -namespace { -struct CompareDiagnostics { - // Compare if 'X' is "<" than 'Y'. - bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { - if (X == Y) - return false; - return compare(*X, *Y); - } -}; -} - void PathDiagnosticConsumer::FlushDiagnostics( PathDiagnosticConsumer::FilesMade *Files) { if (flushed) @@ -443,8 +434,11 @@ void PathDiagnosticConsumer::FlushDiagnostics( // Sort the diagnostics so that they are always emitted in a deterministic // order. if (!BatchDiags.empty()) - std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics()); - + std::sort(BatchDiags.begin(), BatchDiags.end(), + [](const PathDiagnostic *X, const PathDiagnostic *Y) { + return X != Y && compare(*X, *Y); + }); + FlushDiagnosticsImpl(BatchDiags, Files); // Delete the flushed diagnostics. @@ -458,6 +452,11 @@ void PathDiagnosticConsumer::FlushDiagnostics( Diags.clear(); } +PathDiagnosticConsumer::FilesMade::~FilesMade() { + for (PDFileEntry &Entry : *this) + Entry.~PDFileEntry(); +} + void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, StringRef ConsumerName, StringRef FileName) { @@ -487,7 +486,7 @@ PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { void *InsertPos; PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); if (!Entry) - return 0; + return nullptr; return &Entry->files; } @@ -571,6 +570,7 @@ getLocationForCaller(const StackFrameContext *SFC, return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); } case CFGElement::TemporaryDtor: + case CFGElement::NewAllocator: llvm_unreachable("not yet implemented!"); } @@ -610,6 +610,14 @@ PathDiagnosticLocation } PathDiagnosticLocation + PathDiagnosticLocation::createConditionalColonLoc( + const ConditionalOperator *CO, + const SourceManager &SM) { + return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK); +} + + +PathDiagnosticLocation PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, const SourceManager &SM) { return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); @@ -654,7 +662,7 @@ PathDiagnosticLocation PathDiagnosticLocation::create(const ProgramPoint& P, const SourceManager &SMng) { - const Stmt* S = 0; + const Stmt* S = nullptr; if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { const CFGBlock *BSrc = BE->getSrc(); S = BSrc->getTerminatorCondition(); @@ -695,7 +703,7 @@ const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>()) return PIPP->getInitializer()->getInit(); - return 0; + return nullptr; } const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { @@ -722,7 +730,7 @@ const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { } } - return 0; + return nullptr; } PathDiagnosticLocation @@ -731,8 +739,12 @@ PathDiagnosticLocation assert(N && "Cannot create a location with a null node."); const Stmt *S = getStmt(N); - if (!S) + if (!S) { + // If this is an implicit call, return the implicit call point location. + if (Optional<PreImplicitCall> PIE = N->getLocationAs<PreImplicitCall>()) + return PathDiagnosticLocation(PIE->getLocation(), SM); S = getNextStmt(N); + } if (S) { ProgramPoint P = N->getLocation(); @@ -853,13 +865,13 @@ PathDiagnosticRange void PathDiagnosticLocation::flatten() { if (K == StmtK) { K = RangeK; - S = 0; - D = 0; + S = nullptr; + D = nullptr; } else if (K == DeclK) { K = SingleLocK; - S = 0; - D = 0; + S = nullptr; + D = nullptr; } } @@ -969,7 +981,7 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D, IntrusiveRefCntPtr<PathDiagnosticEventPiece> PathDiagnosticCallPiece::getCallEnterEvent() const { if (!Callee) - return 0; + return nullptr; SmallString<256> buf; llvm::raw_svector_ostream Out(buf); @@ -984,12 +996,12 @@ PathDiagnosticCallPiece::getCallEnterEvent() const { IntrusiveRefCntPtr<PathDiagnosticEventPiece> PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { if (!callEnterWithin.asLocation().isValid()) - return 0; + return nullptr; if (Callee->isImplicit() || !Callee->hasBody()) - return 0; + return nullptr; if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee)) if (MD->isDefaulted()) - return 0; + return nullptr; SmallString<256> buf; llvm::raw_svector_ostream Out(buf); @@ -1003,7 +1015,7 @@ PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { IntrusiveRefCntPtr<PathDiagnosticEventPiece> PathDiagnosticCallPiece::getCallExitEvent() const { if (NoExit) - return 0; + return nullptr; SmallString<256> buf; llvm::raw_svector_ostream Out(buf); @@ -1025,7 +1037,7 @@ PathDiagnosticCallPiece::getCallExitEvent() const { static void compute_path_size(const PathPieces &pieces, unsigned &size) { for (PathPieces::const_iterator it = pieces.begin(), et = pieces.end(); it != et; ++it) { - const PathDiagnosticPiece *piece = it->getPtr(); + const PathDiagnosticPiece *piece = it->get(); if (const PathDiagnosticCallPiece *cp = dyn_cast<PathDiagnosticCallPiece>(piece)) { compute_path_size(cp->path, size); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index 5dca811..ba3ad2e 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -13,6 +13,7 @@ #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/PlistSupport.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" #include "clang/Lex/Preprocessor.h" @@ -21,12 +22,9 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace ento; - -typedef llvm::DenseMap<FileID, unsigned> FIDMap; - +using namespace markup; namespace { class PlistDiagnostics : public PathDiagnosticConsumer { @@ -42,15 +40,17 @@ namespace { virtual ~PlistDiagnostics() {} void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, - FilesMade *filesMade); - - virtual StringRef getName() const { + FilesMade *filesMade) override; + + virtual StringRef getName() const override { return "PlistDiagnostics"; } - PathGenerationScheme getGenerationScheme() const { return Extensive; } - bool supportsLogicalOpControlFlow() const { return true; } - virtual bool supportsCrossFileDiagnostics() const { + PathGenerationScheme getGenerationScheme() const override { + return Extensive; + } + bool supportsLogicalOpControlFlow() const override { return true; } + bool supportsCrossFileDiagnostics() const override { return SupportsCrossFileDiagnostics; } }; @@ -80,84 +80,6 @@ void ento::createPlistMultiFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, PP.getLangOpts(), true)); } -static void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V, - const SourceManager* SM, SourceLocation L) { - - FileID FID = SM->getFileID(SM->getExpansionLoc(L)); - FIDMap::iterator I = FIDs.find(FID); - if (I != FIDs.end()) return; - FIDs[FID] = V.size(); - V.push_back(FID); -} - -static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM, - SourceLocation L) { - FileID FID = SM.getFileID(SM.getExpansionLoc(L)); - FIDMap::const_iterator I = FIDs.find(FID); - assert(I != FIDs.end()); - return I->second; -} - -static raw_ostream &Indent(raw_ostream &o, const unsigned indent) { - for (unsigned i = 0; i < indent; ++i) o << ' '; - return o; -} - -static void EmitLocation(raw_ostream &o, const SourceManager &SM, - const LangOptions &LangOpts, - SourceLocation L, const FIDMap &FM, - unsigned indent, bool extend = false) { - - FullSourceLoc Loc(SM.getExpansionLoc(L), const_cast<SourceManager&>(SM)); - - // Add in the length of the token, so that we cover multi-char tokens. - unsigned offset = - extend ? Lexer::MeasureTokenLength(Loc, SM, LangOpts) - 1 : 0; - - Indent(o, indent) << "<dict>\n"; - Indent(o, indent) << " <key>line</key><integer>" - << Loc.getExpansionLineNumber() << "</integer>\n"; - Indent(o, indent) << " <key>col</key><integer>" - << Loc.getExpansionColumnNumber() + offset << "</integer>\n"; - Indent(o, indent) << " <key>file</key><integer>" - << GetFID(FM, SM, Loc) << "</integer>\n"; - Indent(o, indent) << "</dict>\n"; -} - -static void EmitLocation(raw_ostream &o, const SourceManager &SM, - const LangOptions &LangOpts, - const PathDiagnosticLocation &L, const FIDMap& FM, - unsigned indent, bool extend = false) { - EmitLocation(o, SM, LangOpts, L.asLocation(), FM, indent, extend); -} - -static void EmitRange(raw_ostream &o, const SourceManager &SM, - const LangOptions &LangOpts, - PathDiagnosticRange R, const FIDMap &FM, - unsigned indent) { - Indent(o, indent) << "<array>\n"; - EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1); - EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, !R.isPoint); - Indent(o, indent) << "</array>\n"; -} - -static raw_ostream &EmitString(raw_ostream &o, StringRef s) { - o << "<string>"; - for (StringRef::const_iterator I = s.begin(), E = s.end(); I != E; ++I) { - char c = *I; - switch (c) { - default: o << c; break; - case '&': o << "&"; break; - case '<': o << "<"; break; - case '>': o << ">"; break; - case '\'': o << "'"; break; - case '\"': o << """; break; - } - } - o << "</string>"; - return o; -} - static void ReportControlFlow(raw_ostream &o, const PathDiagnosticControlFlowPiece& P, const FIDMap& FM, @@ -185,11 +107,13 @@ static void ReportControlFlow(raw_ostream &o, // logic for clients. Indent(o, indent) << "<key>start</key>\n"; SourceLocation StartEdge = I->getStart().asRange().getBegin(); - EmitRange(o, SM, LangOpts, SourceRange(StartEdge, StartEdge), FM, indent+1); + EmitRange(o, SM, LangOpts, CharSourceRange::getTokenRange(StartEdge), FM, + indent + 1); Indent(o, indent) << "<key>end</key>\n"; SourceLocation EndEdge = I->getEnd().asRange().getBegin(); - EmitRange(o, SM, LangOpts, SourceRange(EndEdge, EndEdge), FM, indent+1); + EmitRange(o, SM, LangOpts, CharSourceRange::getTokenRange(EndEdge), FM, + indent + 1); --indent; Indent(o, indent) << "</dict>\n"; @@ -241,15 +165,16 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P, ++indent; for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { - EmitRange(o, SM, LangOpts, *I, FM, indent+1); + EmitRange(o, SM, LangOpts, CharSourceRange::getTokenRange(*I), FM, + indent + 1); } --indent; Indent(o, indent) << "</array>\n"; } // Output the call depth. - Indent(o, indent) << "<key>depth</key>" - << "<integer>" << depth << "</integer>\n"; + Indent(o, indent) << "<key>depth</key>"; + EmitInteger(o, depth) << '\n'; // Output the text. assert(!P.getString().empty()); @@ -367,7 +292,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl( // ranges of the diagnostics. FIDMap FM; SmallVector<FileID, 10> Fids; - const SourceManager* SM = 0; + const SourceManager* SM = nullptr; if (!Diags.empty()) SM = &(*(*Diags.begin())->path.begin())->getLocation().getManager(); @@ -386,13 +311,13 @@ void PlistDiagnostics::FlushDiagnosticsImpl( for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) { - const PathDiagnosticPiece *piece = I->getPtr(); - AddFID(FM, Fids, SM, piece->getLocation().asLocation()); + const PathDiagnosticPiece *piece = I->get(); + AddFID(FM, Fids, *SM, piece->getLocation().asLocation()); ArrayRef<SourceRange> Ranges = piece->getRanges(); for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { - AddFID(FM, Fids, SM, I->getBegin()); - AddFID(FM, Fids, SM, I->getEnd()); + AddFID(FM, Fids, *SM, I->getBegin()); + AddFID(FM, Fids, *SM, I->getEnd()); } if (const PathDiagnosticCallPiece *call = @@ -400,7 +325,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl( IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnterWithin = call->getCallEnterWithinCallerEvent(); if (callEnterWithin) - AddFID(FM, Fids, SM, callEnterWithin->getLocation().asLocation()); + AddFID(FM, Fids, *SM, callEnterWithin->getLocation().asLocation()); WorkList.push_back(&call->path); } @@ -414,17 +339,13 @@ void PlistDiagnostics::FlushDiagnosticsImpl( // Open the file. std::string ErrMsg; - llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg); + llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg, llvm::sys::fs::F_Text); if (!ErrMsg.empty()) { llvm::errs() << "warning: could not create file: " << OutputFile << '\n'; return; } - // Write the plist header. - o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" - "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" " - "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" - "<plist version=\"1.0\">\n"; + EmitPlistHeader(o); // Write the root object: a <dict> containing... // - "clang_version", the string representation of clang version @@ -436,11 +357,8 @@ void PlistDiagnostics::FlushDiagnosticsImpl( o << " <key>files</key>\n" " <array>\n"; - for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end(); - I!=E; ++I) { - o << " "; - EmitString(o, SM->getFileEntryForID(*I)->getName()) << '\n'; - } + for (FileID FID : Fids) + EmitString(o << " ", SM->getFileEntryForID(FID)->getName()) << '\n'; o << " </array>\n" " <key>diagnostics</key>\n" @@ -535,7 +453,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl( // Output the location of the bug. o << " <key>location</key>\n"; - EmitLocation(o, *SM, LangOpts, D->getLocation(), FM, 2); + EmitLocation(o, *SM, LangOpts, D->getLocation().asLocation(), FM, 2); // Output the diagnostic to the sub-diagnostic client, if any. if (!filesMade->empty()) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h index ed64fcb..c2af36f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h @@ -33,7 +33,7 @@ public: assert(LCtx); } - virtual void print(raw_ostream &OS) const { + void print(raw_ostream &OS) const override { OS << "While analyzing stack: \n"; LCtx->dumpStack(OS, "\t"); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index 6e23668..1714a27 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -175,7 +175,6 @@ ProgramState::invalidateRegionsImpl(ValueList Values, const CallEvent *Call) const { ProgramStateManager &Mgr = getStateManager(); SubEngine* Eng = Mgr.getOwningEngine(); - InvalidatedSymbols ConstIS; InvalidatedSymbols Invalidated; if (!IS) @@ -208,7 +207,7 @@ ProgramState::invalidateRegionsImpl(ValueList Values, const StoreRef &newStore = Mgr.StoreMgr->invalidateRegions(getStore(), Values, E, Count, LCtx, Call, - *IS, *ITraits, NULL, NULL); + *IS, *ITraits, nullptr, nullptr); return makeWithStore(newStore); } @@ -388,7 +387,7 @@ ProgramStateRef ProgramStateManager::getPersistentState(ProgramState &State) { if (ProgramState *I = StateSet.FindNodeOrInsertPos(ID, InsertPos)) return I; - ProgramState *newState = 0; + ProgramState *newState = nullptr; if (!freeStates.empty()) { newState = freeStates.back(); freeStates.pop_back(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index 3606e09..77578d3 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -45,7 +45,7 @@ public: return *second; } const llvm::APSInt *getConcreteValue() const { - return &From() == &To() ? &From() : NULL; + return &From() == &To() ? &From() : nullptr; } void Profile(llvm::FoldingSetNodeID &ID) const { @@ -98,7 +98,7 @@ public: /// constant then this method returns that value. Otherwise, it returns /// NULL. const llvm::APSInt* getConcreteValue() const { - return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : 0; + return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : nullptr; } private: @@ -290,35 +290,37 @@ public: ProgramStateRef assumeSymNE(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& Int, - const llvm::APSInt& Adjustment); + const llvm::APSInt& Adjustment) override; ProgramStateRef assumeSymEQ(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& Int, - const llvm::APSInt& Adjustment); + const llvm::APSInt& Adjustment) override; ProgramStateRef assumeSymLT(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& Int, - const llvm::APSInt& Adjustment); + const llvm::APSInt& Adjustment) override; ProgramStateRef assumeSymGT(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& Int, - const llvm::APSInt& Adjustment); + const llvm::APSInt& Adjustment) override; ProgramStateRef assumeSymGE(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& Int, - const llvm::APSInt& Adjustment); + const llvm::APSInt& Adjustment) override; ProgramStateRef assumeSymLE(ProgramStateRef state, SymbolRef sym, const llvm::APSInt& Int, - const llvm::APSInt& Adjustment); + const llvm::APSInt& Adjustment) override; - const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) const; - ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym); + const llvm::APSInt* getSymVal(ProgramStateRef St, + SymbolRef sym) const override; + ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override; - ProgramStateRef removeDeadBindings(ProgramStateRef St, SymbolReaper& SymReaper); + ProgramStateRef removeDeadBindings(ProgramStateRef St, + SymbolReaper& SymReaper) override; void print(ProgramStateRef St, raw_ostream &Out, - const char* nl, const char *sep); + const char* nl, const char *sep) override; private: RangeSet::Factory F; @@ -334,7 +336,7 @@ ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) { const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St, SymbolRef sym) const { const ConstraintRangeTy::data_type *T = St->get<ConstraintRange>(sym); - return T ? T->getConcreteValue() : NULL; + return T ? T->getConcreteValue() : nullptr; } ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State, @@ -430,7 +432,7 @@ RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym, // [Int-Adjustment+1, Int-Adjustment-1] // Notice that the lower bound is greater than the upper bound. RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Upper, Lower); - return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New); + return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); } ProgramStateRef @@ -440,12 +442,12 @@ RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym, // Before we do any real work, see if the value can even show up. APSIntType AdjustmentType(Adjustment); if (AdjustmentType.testInRange(Int, true) != APSIntType::RTR_Within) - return NULL; + return nullptr; // [Int-Adjustment, Int-Adjustment] llvm::APSInt AdjInt = AdjustmentType.convert(Int) - Adjustment; RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, AdjInt, AdjInt); - return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New); + return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); } ProgramStateRef @@ -456,7 +458,7 @@ RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym, APSIntType AdjustmentType(Adjustment); switch (AdjustmentType.testInRange(Int, true)) { case APSIntType::RTR_Below: - return NULL; + return nullptr; case APSIntType::RTR_Within: break; case APSIntType::RTR_Above: @@ -467,14 +469,14 @@ RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym, llvm::APSInt ComparisonVal = AdjustmentType.convert(Int); llvm::APSInt Min = AdjustmentType.getMinValue(); if (ComparisonVal == Min) - return NULL; + return nullptr; llvm::APSInt Lower = Min-Adjustment; llvm::APSInt Upper = ComparisonVal-Adjustment; --Upper; RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper); - return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New); + return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); } ProgramStateRef @@ -489,21 +491,21 @@ RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym, case APSIntType::RTR_Within: break; case APSIntType::RTR_Above: - return NULL; + return nullptr; } // Special case for Int == Max. This is always false. llvm::APSInt ComparisonVal = AdjustmentType.convert(Int); llvm::APSInt Max = AdjustmentType.getMaxValue(); if (ComparisonVal == Max) - return NULL; + return nullptr; llvm::APSInt Lower = ComparisonVal-Adjustment; llvm::APSInt Upper = Max-Adjustment; ++Lower; RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper); - return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New); + return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); } ProgramStateRef @@ -518,7 +520,7 @@ RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym, case APSIntType::RTR_Within: break; case APSIntType::RTR_Above: - return NULL; + return nullptr; } // Special case for Int == Min. This is always feasible. @@ -532,7 +534,7 @@ RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym, llvm::APSInt Upper = Max-Adjustment; RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper); - return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New); + return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); } ProgramStateRef @@ -543,7 +545,7 @@ RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym, APSIntType AdjustmentType(Adjustment); switch (AdjustmentType.testInRange(Int, true)) { case APSIntType::RTR_Below: - return NULL; + return nullptr; case APSIntType::RTR_Within: break; case APSIntType::RTR_Above: @@ -561,7 +563,7 @@ RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym, llvm::APSInt Upper = ComparisonVal-Adjustment; RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper); - return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New); + return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); } //===------------------------------------------------------------------------=== diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 0b51976..3bbbb34 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -104,7 +104,7 @@ public: Data == X.Data; } - LLVM_ATTRIBUTE_USED void dump() const; + void dump() const; }; } // end anonymous namespace @@ -133,9 +133,7 @@ namespace llvm { }; } // end llvm namespace -void BindingKey::dump() const { - llvm::errs() << *this; -} +LLVM_DUMP_METHOD void BindingKey::dump() const { llvm::errs() << *this; } //===----------------------------------------------------------------------===// // Actual Store type. @@ -224,9 +222,7 @@ public: } } - LLVM_ATTRIBUTE_USED void dump() const { - dump(llvm::errs(), "\n"); - } + LLVM_DUMP_METHOD void dump() const { dump(llvm::errs(), "\n"); } }; } // end anonymous namespace @@ -266,7 +262,7 @@ RegionBindingsRef RegionBindingsRef::addBinding(const MemRegion *R, const SVal *RegionBindingsRef::lookup(BindingKey K) const { const ClusterBindings *Cluster = lookup(K.getBaseRegion()); if (!Cluster) - return 0; + return nullptr; return Cluster->lookup(K); } @@ -376,9 +372,9 @@ public: /// version of that lvalue (i.e., a pointer to the first element of /// the array). This is called by ExprEngine when evaluating /// casts from arrays to pointers. - SVal ArrayToPointer(Loc Array, QualType ElementTy); + SVal ArrayToPointer(Loc Array, QualType ElementTy) override; - StoreRef getInitialStore(const LocationContext *InitLoc) { + StoreRef getInitialStore(const LocationContext *InitLoc) override { return StoreRef(RBFactory.getEmptyMap().getRootWithoutRetain(), *this); } @@ -400,24 +396,24 @@ public: InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits, InvalidatedRegions *Invalidated, - InvalidatedRegions *InvalidatedTopLevel); + InvalidatedRegions *InvalidatedTopLevel) override; bool scanReachableSymbols(Store S, const MemRegion *R, - ScanReachableSymbols &Callbacks); + ScanReachableSymbols &Callbacks) override; RegionBindingsRef removeSubRegionBindings(RegionBindingsConstRef B, const SubRegion *R); public: // Part of public interface to class. - virtual StoreRef Bind(Store store, Loc LV, SVal V) { + StoreRef Bind(Store store, Loc LV, SVal V) override { return StoreRef(bind(getRegionBindings(store), LV, V).asStore(), *this); } RegionBindingsRef bind(RegionBindingsConstRef B, Loc LV, SVal V); // BindDefault is only used to initialize a region with a default value. - StoreRef BindDefault(Store store, const MemRegion *R, SVal V) { + StoreRef BindDefault(Store store, const MemRegion *R, SVal V) override { RegionBindingsRef B = getRegionBindings(store); assert(!B.lookup(R, BindingKey::Direct)); @@ -471,20 +467,20 @@ public: // Part of public interface to class. /// \brief Create a new store with the specified binding removed. /// \param ST the original store, that is the basis for the new store. /// \param L the location whose binding should be removed. - virtual StoreRef killBinding(Store ST, Loc L); + StoreRef killBinding(Store ST, Loc L) override; - void incrementReferenceCount(Store store) { + void incrementReferenceCount(Store store) override { getRegionBindings(store).manualRetain(); } /// If the StoreManager supports it, decrement the reference count of /// the specified Store object. If the reference count hits 0, the memory /// associated with the object is recycled. - void decrementReferenceCount(Store store) { + void decrementReferenceCount(Store store) override { getRegionBindings(store).manualRelease(); } - - bool includedInBindings(Store store, const MemRegion *region) const; + + bool includedInBindings(Store store, const MemRegion *region) const override; /// \brief Return the value bound to specified location in a given state. /// @@ -499,7 +495,7 @@ public: // Part of public interface to class. /// return undefined /// else /// return symbolic - virtual SVal getBinding(Store S, Loc L, QualType T) { + SVal getBinding(Store S, Loc L, QualType T) override { return getBinding(getRegionBindings(S), L, T); } @@ -564,15 +560,16 @@ public: // Part of public interface to class. /// removeDeadBindings - Scans the RegionStore of 'state' for dead values. /// It returns a new Store with these values removed. StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx, - SymbolReaper& SymReaper); - + SymbolReaper& SymReaper) override; + //===------------------------------------------------------------------===// // Region "extents". //===------------------------------------------------------------------===// // FIXME: This method will soon be eliminated; see the note in Store.h. DefinedOrUnknownSVal getSizeInElements(ProgramStateRef state, - const MemRegion* R, QualType EleTy); + const MemRegion* R, + QualType EleTy) override; //===------------------------------------------------------------------===// // Utility methods. @@ -585,9 +582,9 @@ public: // Part of public interface to class. } void print(Store store, raw_ostream &Out, const char* nl, - const char *sep); + const char *sep) override; - void iterBindings(Store store, BindingsHandler& f) { + 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(); @@ -1016,7 +1013,7 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR, BI != BE; ++BI) { const VarRegion *VR = BI.getCapturedRegion(); const VarDecl *VD = VR->getDecl(); - if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage()) { + if (VD->hasAttr<BlocksAttr>() || !VD->hasLocalStorage()) { AddToWorkList(VR); } else if (Loc::isLocType(VR->getValueType())) { @@ -1628,9 +1625,9 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B, // getBindingForField if 'R' has a direct binding. // Lazy binding? - Store lazyBindingStore = NULL; - const SubRegion *lazyBindingRegion = NULL; - llvm::tie(lazyBindingStore, lazyBindingRegion) = findLazyBinding(B, R, R); + Store lazyBindingStore = nullptr; + const SubRegion *lazyBindingRegion = nullptr; + std::tie(lazyBindingStore, lazyBindingRegion) = findLazyBinding(B, R, R); if (lazyBindingRegion) return getLazyBinding(lazyBindingRegion, getRegionBindings(lazyBindingStore)); @@ -1791,7 +1788,7 @@ RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) { // values to return. const ClusterBindings *Cluster = B.lookup(LazyR->getBaseRegion()); if (!Cluster) - return (LazyBindingsMap[LCV.getCVData()] = llvm_move(List)); + return (LazyBindingsMap[LCV.getCVData()] = std::move(List)); SmallVector<BindingPair, 32> Bindings; collectSubRegionBindings(Bindings, svalBuilder, *Cluster, LazyR, @@ -1813,7 +1810,7 @@ RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) { List.push_back(V); } - return (LazyBindingsMap[LCV.getCVData()] = llvm_move(List)); + return (LazyBindingsMap[LCV.getCVData()] = std::move(List)); } NonLoc RegionStoreManager::createLazyBinding(RegionBindingsConstRef B, @@ -2066,9 +2063,7 @@ RegionStoreManager::tryBindSmallStruct(RegionBindingsConstRef B, if (Class->getNumBases() != 0 || Class->getNumVBases() != 0) return None; - for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); - I != E; ++I) { - const FieldDecl *FD = *I; + for (const auto *FD : RD->fields()) { if (FD->isUnnamedBitfield()) continue; @@ -2081,7 +2076,7 @@ RegionStoreManager::tryBindSmallStruct(RegionBindingsConstRef B, if (!(Ty->isScalarType() || Ty->isReferenceType())) return None; - Fields.push_back(*I); + Fields.push_back(FD); } RegionBindingsRef NewB = B; @@ -2296,7 +2291,7 @@ bool removeDeadBindingsWorker::UpdatePostponed() { if (const SymbolicRegion *SR = *I) { if (SymReaper.isLive(SR->getSymbol())) { changed |= AddToWorkList(SR); - *I = NULL; + *I = nullptr; } } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index adc5465..3ed2bde 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -362,7 +362,7 @@ SVal SValBuilder::evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, DefinedOrUnknownSVal SValBuilder::evalEQ(ProgramStateRef state, DefinedOrUnknownSVal lhs, DefinedOrUnknownSVal rhs) { - return evalBinOp(state, BO_EQ, lhs, rhs, Context.IntTy) + return evalBinOp(state, BO_EQ, lhs, rhs, getConditionType()) .castAs<DefinedOrUnknownSVal>(); } @@ -376,7 +376,7 @@ static bool shouldBeModeledWithNoOp(ASTContext &Context, QualType ToTy, ToTy = Context.getUnqualifiedArrayType(ToTy, Quals1); FromTy = Context.getUnqualifiedArrayType(FromTy, Quals2); - // Make sure that non cvr-qualifiers the other qualifiers (e.g., address + // Make sure that non-cvr-qualifiers the other qualifiers (e.g., address // spaces) are identical. Quals1.removeCVRQualifiers(); Quals2.removeCVRQualifiers(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp index 6506915..8de939f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp @@ -56,7 +56,7 @@ const FunctionDecl *SVal::getAsFunctionDecl() const { return FD; } - return 0; + return nullptr; } /// \brief If this SVal is a location (subclasses Loc) and wraps a symbol, @@ -78,7 +78,7 @@ SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const { dyn_cast<SymbolicRegion>(R->StripCasts())) return SymR->getSymbol(); } - return 0; + return nullptr; } /// Get the symbol in the SVal or its base region. @@ -86,7 +86,7 @@ SymbolRef SVal::getLocSymbolInBase() const { Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>(); if (!X) - return 0; + return nullptr; const MemRegion *R = X->getRegion(); @@ -97,7 +97,7 @@ SymbolRef SVal::getLocSymbolInBase() const { R = SR->getSuperRegion(); } - return 0; + return nullptr; } // TODO: The next 3 functions have to be simplified. @@ -139,12 +139,12 @@ const MemRegion *SVal::getAsRegion() const { if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>()) return X->getLoc().getAsRegion(); - return 0; + return nullptr; } const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const { const MemRegion *R = getRegion(); - return R ? R->StripCasts(StripBaseCasts) : NULL; + return R ? R->StripCasts(StripBaseCasts) : nullptr; } const void *nonloc::LazyCompoundVal::getStore() const { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp index e6653ae..35930e4 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp @@ -181,7 +181,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state, case nonloc::ConcreteIntKind: { bool b = Cond.castAs<nonloc::ConcreteInt>().getValue() != 0; bool isFeasible = b ? Assumption : !Assumption; - return isFeasible ? state : NULL; + return isFeasible ? state : nullptr; } case nonloc::LocAsIntegerKind: diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h index 28a9a4d..21e2283 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h @@ -34,7 +34,7 @@ public: //===------------------------------------------------------------------===// ProgramStateRef assume(ProgramStateRef state, DefinedSVal Cond, - bool Assumption); + bool Assumption) override; ProgramStateRef assume(ProgramStateRef state, NonLoc Cond, bool Assumption); @@ -82,7 +82,7 @@ protected: BasicValueFactory &getBasicVals() const { return SVB.getBasicValueFactory(); } SymbolManager &getSymbolManager() const { return SVB.getSymbolManager(); } - bool canReasonAbout(SVal X) const; + bool canReasonAbout(SVal X) const override; ProgramStateRef assumeAux(ProgramStateRef state, NonLoc Cond, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index cc0ee0b..df9e4d6 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -21,9 +21,9 @@ using namespace ento; namespace { class SimpleSValBuilder : public SValBuilder { protected: - virtual SVal dispatchCast(SVal val, QualType castTy); - virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy); - virtual SVal evalCastFromLoc(Loc val, QualType castTy); + SVal dispatchCast(SVal val, QualType castTy) override; + SVal evalCastFromNonLoc(NonLoc val, QualType castTy) override; + SVal evalCastFromLoc(Loc val, QualType castTy) override; public: SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context, @@ -31,19 +31,19 @@ public: : SValBuilder(alloc, context, stateMgr) {} virtual ~SimpleSValBuilder() {} - virtual SVal evalMinus(NonLoc val); - virtual SVal evalComplement(NonLoc val); - virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, - NonLoc lhs, NonLoc rhs, QualType resultTy); - virtual SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op, - Loc lhs, Loc rhs, QualType resultTy); - virtual SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op, - Loc lhs, NonLoc rhs, QualType resultTy); + SVal evalMinus(NonLoc val) override; + SVal evalComplement(NonLoc val) override; + SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, + NonLoc lhs, NonLoc rhs, QualType resultTy) override; + SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op, + Loc lhs, Loc rhs, QualType resultTy) override; + SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op, + Loc lhs, NonLoc rhs, QualType resultTy) override; /// getKnownValue - evaluates a given SVal. If the SVal has only one possible /// (integer) value, that value is returned. Otherwise, returns NULL. - virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal V); - + const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal V) override; + SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op, const llvm::APSInt &RHS, QualType resultTy); }; @@ -97,7 +97,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { return UnknownVal(); } - // If value is a non integer constant, produce unknown. + // If value is a non-integer constant, produce unknown. if (!val.getAs<nonloc::ConcreteInt>()) return UnknownVal(); @@ -108,7 +108,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { } // Only handle casts from integers to integers - if val is an integer constant - // being cast to a non integer type, produce unknown. + // being cast to a non-integer type, produce unknown. if (!isLocType && !castTy->isIntegralOrEnumerationType()) return UnknownVal(); @@ -158,7 +158,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) { } case loc::GotoLabelKind: - // Labels and non symbolic memory regions are always true. + // Labels and non-symbolic memory regions are always true. return makeTruthVal(true, castTy); } } @@ -569,11 +569,10 @@ static SVal evalBinOpFieldRegionFieldRegion(const FieldRegion *LeftFR, // members and the units in which bit-fields reside have addresses that // increase in the order in which they are declared." bool leftFirst = (op == BO_LT || op == BO_LE); - for (RecordDecl::field_iterator I = RD->field_begin(), - E = RD->field_end(); I!=E; ++I) { - if (*I == LeftFD) + for (const auto *I : RD->fields()) { + if (I == LeftFD) return SVB.makeTruthVal(leftFirst, resultTy); - if (*I == RightFD) + if (I == RightFD) return SVB.makeTruthVal(!leftFirst, resultTy); } @@ -818,7 +817,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state, RegionOffset LeftOffset = LeftMR->getAsOffset(); RegionOffset RightOffset = RightMR->getAsOffset(); - if (LeftOffset.getRegion() != NULL && + if (LeftOffset.getRegion() != nullptr && LeftOffset.getRegion() == RightOffset.getRegion() && !LeftOffset.hasSymbolicOffset() && !RightOffset.hasSymbolicOffset()) { int64_t left = LeftOffset.getOffset(); @@ -901,7 +900,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state, if (const MemRegion *region = lhs.getAsRegion()) { rhs = convertToArrayIndex(rhs).castAs<NonLoc>(); SVal index = UnknownVal(); - const MemRegion *superR = 0; + const MemRegion *superR = nullptr; QualType elementType; if (const ElementRegion *elemReg = dyn_cast<ElementRegion>(region)) { @@ -929,7 +928,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state, const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state, SVal V) { if (V.isUnknownOrUndef()) - return NULL; + return nullptr; if (Optional<loc::ConcreteInt> X = V.getAs<loc::ConcreteInt>()) return &X->getValue(); @@ -941,5 +940,5 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state, return state->getConstraintManager().getSymVal(state, Sym); // FIXME: Add support for SymExprs. - return NULL; + return nullptr; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp index 0beb9db..e38be3e 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp @@ -88,7 +88,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) // We don't know what to make of it. Return a NULL region, which // will be interpretted as UnknownVal. - return NULL; + return nullptr; } // Now assume we are casting from pointer to pointer. Other cases should @@ -166,7 +166,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) // If we cannot compute a raw offset, throw up our hands and return // a NULL MemRegion*. if (!baseR) - return NULL; + return nullptr; CharUnits off = rawOff.getOffset(); @@ -193,7 +193,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) // Compute the index for the new ElementRegion. int64_t newIndex = 0; - const MemRegion *newSuperR = 0; + const MemRegion *newSuperR = nullptr; // We can only compute sizeof(PointeeTy) if it is a complete type. if (IsCompleteType(Ctx, PointeeTy)) { @@ -300,7 +300,7 @@ static const CXXRecordDecl *getCXXRecordType(const MemRegion *MR) { return TVR->getValueType()->getAsCXXRecordDecl(); if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) return SR->getSymbol()->getType()->getPointeeCXXRecordDecl(); - return 0; + return nullptr; } SVal StoreManager::evalDynamicCast(SVal Base, QualType TargetType, @@ -401,7 +401,7 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) { return Base; Loc BaseL = Base.castAs<Loc>(); - const MemRegion* BaseR = 0; + const MemRegion* BaseR = nullptr; switch (BaseL.getSubKind()) { case loc::MemRegionKind: diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp index 1b56f82..cca0461 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -326,11 +326,7 @@ QualType SymbolRegionValue::getType() const { } SymbolManager::~SymbolManager() { - for (SymbolDependTy::const_iterator I = SymbolDependencies.begin(), - E = SymbolDependencies.end(); I != E; ++I) { - delete I->second; - } - + llvm::DeleteContainerSeconds(SymbolDependencies); } bool SymbolManager::canSymbolicate(QualType T) { @@ -351,7 +347,7 @@ bool SymbolManager::canSymbolicate(QualType T) { void SymbolManager::addSymbolDependency(const SymbolRef Primary, const SymbolRef Dependent) { SymbolDependTy::iterator I = SymbolDependencies.find(Primary); - SymbolRefSmallVectorTy *dependencies = 0; + SymbolRefSmallVectorTy *dependencies = nullptr; if (I == SymbolDependencies.end()) { dependencies = new SymbolRefSmallVectorTy(); SymbolDependencies[Primary] = dependencies; @@ -365,7 +361,7 @@ const SymbolRefSmallVectorTy *SymbolManager::getDependentSymbols( const SymbolRef Primary) { SymbolDependTy::const_iterator I = SymbolDependencies.find(Primary); if (I == SymbolDependencies.end()) - return 0; + return nullptr; return I->second; } @@ -491,7 +487,7 @@ bool SymbolReaper::isLive(SymbolRef sym) { bool SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const { - if (LCtx == 0) + if (LCtx == nullptr) return false; if (LCtx != ELCtx) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 9efe997..f0dd274 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -11,15 +11,13 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "AnalysisConsumer" - -#include "AnalysisConsumer.h" +#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" #include "clang/AST/ASTConsumer.h" +#include "clang/AST/DataRecursiveASTVisitor.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ParentMap.h" -#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CallGraph.h" @@ -36,7 +34,6 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" #include "llvm/ADT/DepthFirstIterator.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" @@ -45,12 +42,15 @@ #include "llvm/Support/Program.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" +#include <memory> #include <queue> using namespace clang; using namespace ento; using llvm::SmallPtrSet; +#define DEBUG_TYPE "AnalysisConsumer" + static ExplodedNode::Auditor* CreateUbiViz(); STATISTIC(NumFunctionTopLevel, "The # of functions at top level."); @@ -90,12 +90,12 @@ public: ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag) : Diag(Diag), IncludePath(false) {} virtual ~ClangDiagPathDiagConsumer() {} - virtual StringRef getName() const { return "ClangDiags"; } + StringRef getName() const override { return "ClangDiags"; } - virtual bool supportsLogicalOpControlFlow() const { return true; } - virtual bool supportsCrossFileDiagnostics() const { return true; } + bool supportsLogicalOpControlFlow() const override { return true; } + bool supportsCrossFileDiagnostics() const override { return true; } - virtual PathGenerationScheme getGenerationScheme() const { + PathGenerationScheme getGenerationScheme() const override { return IncludePath ? Minimal : None; } @@ -103,35 +103,17 @@ public: IncludePath = true; } - void emitDiag(SourceLocation L, unsigned DiagID, - ArrayRef<SourceRange> Ranges) { - DiagnosticBuilder DiagBuilder = Diag.Report(L, DiagID); - - for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); - I != E; ++I) { - DiagBuilder << *I; - } - } - void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, - FilesMade *filesMade) { + FilesMade *filesMade) override { + unsigned WarnID = Diag.getCustomDiagID(DiagnosticsEngine::Warning, "%0"); + unsigned NoteID = Diag.getCustomDiagID(DiagnosticsEngine::Note, "%0"); + for (std::vector<const PathDiagnostic*>::iterator I = Diags.begin(), E = Diags.end(); I != E; ++I) { const PathDiagnostic *PD = *I; - StringRef desc = PD->getShortDescription(); - SmallString<512> TmpStr; - llvm::raw_svector_ostream Out(TmpStr); - for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) { - if (*I == '%') - Out << "%%"; - else - Out << *I; - } - Out.flush(); - unsigned ErrorDiag = Diag.getCustomDiagID(DiagnosticsEngine::Warning, - TmpStr); - SourceLocation L = PD->getLocation().asLocation(); - emitDiag(L, ErrorDiag, PD->path.back()->getRanges()); + SourceLocation WarnLoc = PD->getLocation().asLocation(); + Diag.Report(WarnLoc, WarnID) << PD->getShortDescription() + << PD->path.back()->getRanges(); if (!IncludePath) continue; @@ -140,11 +122,9 @@ public: for (PathPieces::const_iterator PI = FlatPath.begin(), PE = FlatPath.end(); PI != PE; ++PI) { - unsigned NoteID = Diag.getCustomDiagID(DiagnosticsEngine::Note, - (*PI)->getString()); - SourceLocation NoteLoc = (*PI)->getLocation().asLocation(); - emitDiag(NoteLoc, NoteID, (*PI)->getRanges()); + Diag.Report(NoteLoc, NoteID) << (*PI)->getString() + << (*PI)->getRanges(); } } } @@ -157,8 +137,8 @@ public: namespace { -class AnalysisConsumer : public ASTConsumer, - public RecursiveASTVisitor<AnalysisConsumer> { +class AnalysisConsumer : public AnalysisASTConsumer, + public DataRecursiveASTVisitor<AnalysisConsumer> { enum { AM_None = 0, AM_Syntax = 0x1, @@ -191,8 +171,8 @@ public: StoreManagerCreator CreateStoreMgr; ConstraintManagerCreator CreateConstraintMgr; - OwningPtr<CheckerManager> checkerMgr; - OwningPtr<AnalysisManager> Mgr; + std::unique_ptr<CheckerManager> checkerMgr; + std::unique_ptr<AnalysisManager> Mgr; /// Time the analyzes time of each translation unit. static llvm::Timer* TUTotalTimer; @@ -205,8 +185,8 @@ public: const std::string& outdir, AnalyzerOptionsRef opts, ArrayRef<std::string> plugins) - : RecVisitorMode(0), RecVisitorBR(0), - Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins) { + : RecVisitorMode(0), RecVisitorBR(nullptr), + Ctx(nullptr), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins) { DigestAnalyzerOptions(); if (Opts->PrintStats) { llvm::EnableStatistics(); @@ -220,21 +200,24 @@ public: } void DigestAnalyzerOptions() { - // Create the PathDiagnosticConsumer. - ClangDiagPathDiagConsumer *clangDiags = - new ClangDiagPathDiagConsumer(PP.getDiagnostics()); - PathConsumers.push_back(clangDiags); - - if (Opts->AnalysisDiagOpt == PD_TEXT) { - clangDiags->enablePaths(); - - } else if (!OutDir.empty()) { - switch (Opts->AnalysisDiagOpt) { - default: -#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \ - case PD_##NAME: CREATEFN(*Opts.getPtr(), PathConsumers, OutDir, PP);\ - break; + if (Opts->AnalysisDiagOpt != PD_NONE) { + // Create the PathDiagnosticConsumer. + ClangDiagPathDiagConsumer *clangDiags = + new ClangDiagPathDiagConsumer(PP.getDiagnostics()); + PathConsumers.push_back(clangDiags); + + if (Opts->AnalysisDiagOpt == PD_TEXT) { + clangDiags->enablePaths(); + + } else if (!OutDir.empty()) { + switch (Opts->AnalysisDiagOpt) { + default: +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \ + case PD_##NAME: \ + CREATEFN(*Opts.get(), PathConsumers, OutDir, PP); \ + break; #include "clang/StaticAnalyzer/Core/Analyses.def" + } } } @@ -299,7 +282,7 @@ public: } } - virtual void Initialize(ASTContext &Context) { + void Initialize(ASTContext &Context) override { Ctx = &Context; checkerMgr.reset(createCheckerManager(*Opts, PP.getLangOpts(), Plugins, PP.getDiagnostics())); @@ -315,16 +298,16 @@ public: /// \brief Store the top level decls in the set to be processed later on. /// (Doing this pre-processing avoids deserialization of data from PCH.) - virtual bool HandleTopLevelDecl(DeclGroupRef D); - virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D); + bool HandleTopLevelDecl(DeclGroupRef D) override; + void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override; - virtual void HandleTranslationUnit(ASTContext &C); + void HandleTranslationUnit(ASTContext &C) override; /// \brief Determine which inlining mode should be used when this function is /// analyzed. This allows to redefine the default inlining policies when /// analyzing a given function. ExprEngine::InliningModes - getInliningModeForFunction(const Decl *D, SetOfConstDecls Visited); + getInliningModeForFunction(const Decl *D, const SetOfConstDecls &Visited); /// \brief Build the call graph for all the top level decls of this TU and /// use it to define the order in which the functions should be visited. @@ -338,7 +321,7 @@ public: /// given root function. void HandleCode(Decl *D, AnalysisMode Mode, ExprEngine::InliningModes IMode = ExprEngine::Inline_Minimal, - SetOfConstDecls *VisitedCallees = 0); + SetOfConstDecls *VisitedCallees = nullptr); void RunPathSensitiveChecks(Decl *D, ExprEngine::InliningModes IMode, @@ -389,6 +372,11 @@ public: return true; } + virtual void + AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer) override { + PathConsumers.push_back(Consumer); + } + private: void storeTopLevelDecls(DeclGroupRef DG); @@ -402,7 +390,7 @@ private: //===----------------------------------------------------------------------===// // AnalysisConsumer implementation. //===----------------------------------------------------------------------===// -llvm::Timer* AnalysisConsumer::TUTotalTimer = 0; +llvm::Timer* AnalysisConsumer::TUTotalTimer = nullptr; bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) { storeTopLevelDecls(DG); @@ -426,8 +414,8 @@ void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) { } static bool shouldSkipFunction(const Decl *D, - SetOfConstDecls Visited, - SetOfConstDecls VisitedAsTopLevel) { + const SetOfConstDecls &Visited, + const SetOfConstDecls &VisitedAsTopLevel) { if (VisitedAsTopLevel.count(D)) return true; @@ -447,7 +435,7 @@ static bool shouldSkipFunction(const Decl *D, ExprEngine::InliningModes AnalysisConsumer::getInliningModeForFunction(const Decl *D, - SetOfConstDecls Visited) { + const SetOfConstDecls &Visited) { // We want to reanalyze all ObjC methods as top level to report Retain // Count naming convention errors more aggressively. But we should tune down // inlining when reanalyzing an already inlined function. @@ -501,7 +489,7 @@ void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) { SetOfConstDecls VisitedCallees; HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited), - (Mgr->options.InliningMode == All ? 0 : &VisitedCallees)); + (Mgr->options.InliningMode == All ? nullptr : &VisitedCallees)); // Add the visited callees to the global visited set. for (SetOfConstDecls::iterator I = VisitedCallees.begin(), @@ -551,14 +539,14 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { // After all decls handled, run checkers on the entire TranslationUnit. checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR); - RecVisitorBR = 0; + RecVisitorBR = nullptr; } // Explicitly destroy the PathDiagnosticConsumer. This will flush its output. // FIXME: This should be replaced with something that doesn't rely on // side-effects in PathDiagnosticConsumer's destructor. This is required when // used with option -disable-free. - Mgr.reset(NULL); + Mgr.reset(); if (TUTotalTimer) TUTotalTimer->stopTimer(); @@ -653,7 +641,7 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled, ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries,IMode); // Set the graph auditor. - OwningPtr<ExplodedNode::Auditor> Auditor; + std::unique_ptr<ExplodedNode::Auditor> Auditor; if (Mgr->options.visualizeExplodedGraphWithUbiGraph) { Auditor.reset(CreateUbiViz()); ExplodedNode::SetAuditor(Auditor.get()); @@ -665,7 +653,7 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled, // Release the auditor (if any) so that it doesn't monitor the graph // created BugReporter. - ExplodedNode::SetAuditor(0); + ExplodedNode::SetAuditor(nullptr); // Visualize the exploded graph. if (Mgr->options.visualizeExplodedGraphWithGraphViz) @@ -699,10 +687,10 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D, // AnalysisConsumer creation. //===----------------------------------------------------------------------===// -ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp, - const std::string& outDir, - AnalyzerOptionsRef opts, - ArrayRef<std::string> plugins) { +AnalysisASTConsumer * +ento::CreateAnalysisConsumer(const Preprocessor &pp, const std::string &outDir, + AnalyzerOptionsRef opts, + ArrayRef<std::string> plugins) { // Disable the effects of '-Werror' when using the AnalysisConsumer. pp.getDiagnostics().setWarningsAsErrors(false); @@ -716,7 +704,7 @@ ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp, namespace { class UbigraphViz : public ExplodedNode::Auditor { - OwningPtr<raw_ostream> Out; + std::unique_ptr<raw_ostream> Out; std::string Filename; unsigned Cntr; @@ -724,11 +712,11 @@ class UbigraphViz : public ExplodedNode::Auditor { VMap M; public: - UbigraphViz(raw_ostream *Out, StringRef Filename); + UbigraphViz(std::unique_ptr<raw_ostream> Out, StringRef Filename); ~UbigraphViz(); - virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst); + void AddEdge(ExplodedNode *Src, ExplodedNode *Dst) override; }; } // end anonymous namespace @@ -739,10 +727,9 @@ static ExplodedNode::Auditor* CreateUbiViz() { llvm::sys::fs::createTemporaryFile("llvm_ubi", "", FD, P); llvm::errs() << "Writing '" << P.str() << "'.\n"; - OwningPtr<llvm::raw_fd_ostream> Stream; - Stream.reset(new llvm::raw_fd_ostream(FD, true)); + auto Stream = llvm::make_unique<llvm::raw_fd_ostream>(FD, true); - return new UbigraphViz(Stream.take(), P); + return new UbigraphViz(std::move(Stream), P); } void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) { @@ -779,8 +766,8 @@ void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) { << ", ('arrow','true'), ('oriented', 'true'))\n"; } -UbigraphViz::UbigraphViz(raw_ostream *Out, StringRef Filename) - : Out(Out), Filename(Filename), Cntr(0) { +UbigraphViz::UbigraphViz(std::unique_ptr<raw_ostream> Out, StringRef Filename) + : Out(std::move(Out)), Filename(Filename), Cntr(0) { *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n"; *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66')," @@ -788,16 +775,17 @@ UbigraphViz::UbigraphViz(raw_ostream *Out, StringRef Filename) } UbigraphViz::~UbigraphViz() { - Out.reset(0); + Out.reset(); llvm::errs() << "Running 'ubiviz' program... "; std::string ErrMsg; std::string Ubiviz = llvm::sys::FindProgramByName("ubiviz"); std::vector<const char*> args; args.push_back(Ubiviz.c_str()); args.push_back(Filename.c_str()); - args.push_back(0); + args.push_back(nullptr); - if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0], 0, 0, 0, 0, &ErrMsg)) { + if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0], nullptr, nullptr, 0, 0, + &ErrMsg)) { llvm::errs() << "Error viewing graph: " << ErrMsg << "\n"; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h deleted file mode 100644 index b75220b..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h +++ /dev/null @@ -1,43 +0,0 @@ -//===--- AnalysisConsumer.h - Front-end Analysis Engine Hooks ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header contains the functions necessary for a front-end to run various -// analyses. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_GR_ANALYSISCONSUMER_H -#define LLVM_CLANG_GR_ANALYSISCONSUMER_H - -#include "clang/Basic/LLVM.h" -#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" -#include <string> - -namespace clang { - -class ASTConsumer; -class Preprocessor; -class DiagnosticsEngine; - -namespace ento { -class CheckerManager; - -/// CreateAnalysisConsumer - Creates an ASTConsumer to run various code -/// analysis passes. (The set of analyses run is controlled by command-line -/// options.) -ASTConsumer* CreateAnalysisConsumer(const Preprocessor &pp, - const std::string &output, - AnalyzerOptionsRef opts, - ArrayRef<std::string> plugins); - -} // end GR namespace - -} // end clang namespace - -#endif diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp index e7def08..e2577c3 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp @@ -20,11 +20,11 @@ #include "clang/StaticAnalyzer/Core/CheckerOptInfo.h" #include "clang/StaticAnalyzer/Core/CheckerRegistry.h" #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include <memory> using namespace clang; using namespace ento; @@ -40,7 +40,7 @@ class ClangCheckerRegistry : public CheckerRegistry { public: ClangCheckerRegistry(ArrayRef<std::string> plugins, - DiagnosticsEngine *diags = 0); + DiagnosticsEngine *diags = nullptr); }; } // end anonymous namespace @@ -73,7 +73,7 @@ ClangCheckerRegistry::ClangCheckerRegistry(ArrayRef<std::string> plugins, bool ClangCheckerRegistry::isCompatibleAPIVersion(const char *versionString) { // If the version string is null, it's not an analyzer plugin. - if (versionString == 0) + if (!versionString) return false; // For now, none of the static analyzer API is considered stable. @@ -104,8 +104,8 @@ CheckerManager *ento::createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts, ArrayRef<std::string> plugins, DiagnosticsEngine &diags) { - OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts, - &opts)); + std::unique_ptr<CheckerManager> checkerMgr( + new CheckerManager(langOpts, &opts)); SmallVector<CheckerOptInfo, 8> checkerOpts; for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) { @@ -123,7 +123,7 @@ CheckerManager *ento::createCheckerManager(AnalyzerOptions &opts, << checkerOpts[i].getName(); } - return checkerMgr.take(); + return checkerMgr.release(); } void ento::printCheckerHelp(raw_ostream &out, ArrayRef<std::string> plugins) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/FrontendActions.cpp index 13971af..aa38077 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/FrontendActions.cpp @@ -8,8 +8,8 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" -#include "AnalysisConsumer.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" using namespace clang; using namespace ento; |