diff options
Diffstat (limited to 'clang/lib')
63 files changed, 567 insertions, 438 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp index 9af0a5ac4fd..3becdca97d8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp @@ -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/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp index 312bc749b18..f76de9bfe6a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp @@ -66,8 +66,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/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp index 5e4b824df4b..e33f72efa57 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -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/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index adf1b239421..b5aa4b3d08d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -39,7 +39,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 @@ -191,7 +192,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); @@ -483,8 +484,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); @@ -522,8 +523,8 @@ 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")); + BT.reset(new APIMisuse( + this, "null passed to CFRetain/CFRelease/CFMakeCollectable")); } // Check if we called CFRetain/CFRelease/CFMakeCollectable. @@ -600,9 +601,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); @@ -708,7 +709,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(); @@ -1263,6 +1265,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/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp index 5169244a6f9..03368b63ce1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp @@ -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)); } } diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index c3736d7e5d7..8396cc750a1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -51,6 +51,11 @@ public: DefaultBool CheckCStringOutOfBounds; DefaultBool CheckCStringBufferOverlap; DefaultBool CheckCStringNotNullTerm; + + CheckName CheckNameCStringNullArg; + CheckName CheckNameCStringOutOfBounds; + CheckName CheckNameCStringBufferOverlap; + CheckName CheckNameCStringNotNullTerm; }; CStringChecksFilter Filter; @@ -232,8 +237,9 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, return NULL; 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); @@ -294,8 +300,9 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, return NULL; 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()); @@ -526,7 +533,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 = @@ -586,8 +594,9 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, return NULL; 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 @@ -703,8 +712,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 +724,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 +772,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); @@ -2057,10 +2067,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/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp index d29a12a90ee..abfb971d4cc 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp +++ b/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/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 8918cd1e882..a562c48a66a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -52,10 +52,10 @@ 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, + OwningPtr<BugType> &BT) const; static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE); void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg, @@ -65,9 +65,9 @@ private: ProgramStateRef state, const ObjCMethodCall &msg) const; - static void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) { + void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) const { if (!BT) - BT.reset(new BuiltinBug(desc)); + BT.reset(new BuiltinBug(this, desc)); } }; } // end anonymous namespace @@ -119,7 +119,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, bool IsFirstArgument, bool checkUninitFields, const CallEvent &Call, - OwningPtr<BugType> &BT) { + OwningPtr<BugType> &BT) const { if (V.isUndef()) { if (ExplodedNode *N = C.generateSink()) { LazyInit_BT("Uninitialized argument value", BT); @@ -234,8 +234,8 @@ 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; } @@ -246,8 +246,8 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, 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 +265,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,8 +290,8 @@ 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; } @@ -301,8 +302,8 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call, 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; } @@ -365,22 +366,21 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg, 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; } @@ -418,7 +418,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(); diff --git a/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp index 5e6e1054148..cd6304057a3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp @@ -69,9 +69,10 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const { 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.")); + 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()); @@ -80,7 +81,6 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const { } } - void ento::registerCastSizeChecker(CheckerManager &mgr) { - mgr.registerChecker<CastSizeChecker>(); + mgr.registerChecker<CastSizeChecker>(); } diff --git a/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp index 60348c73584..e9c7599e153 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp @@ -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/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index 0ea5717037c..39ddf47c737 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/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); @@ -180,7 +181,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 +199,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; } @@ -264,8 +265,8 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D, PathDiagnosticLocation SDLoc = 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 +283,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/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp index d989fdf572d..fbda45e802a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp @@ -40,7 +40,8 @@ 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->getReturnType(); QualType ResAncestor = MethAncestor->getReturnType(); @@ -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(); @@ -118,7 +119,7 @@ static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID, ObjCMethodDecl *MethDerived = MI->second; MI->second = 0; - CompareReturnTypes(MethDerived, M, BR, Ctx, ID); + CompareReturnTypes(MethDerived, M, BR, Ctx, ID, Checker); } C = C->getSuperClass(); @@ -135,7 +136,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/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index 0ee4a433edf..57063643fc3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/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; @@ -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); } @@ -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 " @@ -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 " @@ -397,7 +407,7 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { // Issue a waring. 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", @@ -609,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()); } //===----------------------------------------------------------------------===// @@ -633,7 +644,7 @@ void WalkAST::checkCall_random(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_rand, "'random' is not a secure random number generator", "Security", "The 'random' function produces a sequence of values that " @@ -653,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", @@ -724,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()); } //===----------------------------------------------------------------------===// @@ -745,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/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp index 1207b67c97f..5106b06ca88 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp +++ b/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); @@ -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/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp index 991296538a5..9cfc0f3116a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp @@ -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/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 4ad4e1c8c62..ee12a4d75ff 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -124,6 +124,7 @@ 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; @@ -134,11 +135,12 @@ class DeadStoreObs : public LiveVariables::Observer { 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(0) {} virtual ~DeadStoreObs() {} @@ -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, @@ -439,7 +442,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/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index 72d46c50e10..6ca7879c12f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -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); @@ -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); diff --git a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp index b43dc18c217..4c2047a8ff1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp +++ b/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); } @@ -152,7 +154,8 @@ 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); } } @@ -204,13 +207,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)); } } } diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index 93daf94fbe3..023d5af96e1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -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); diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index 3ed2435b92e..411c1d14876 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -95,7 +95,7 @@ void ExprInspectionChecker::analyzerEval(const CallExpr *CE, 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); @@ -126,7 +126,7 @@ void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, 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/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp index 085a991f786..c73b068300c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp @@ -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/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp index 1dc60c6dbdd..c65dd8ca877 100644 --- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -46,7 +46,7 @@ private: mutable OwningPtr<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 diff --git a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp index faa8cd573f5..aeefc4260b1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp @@ -36,8 +36,10 @@ namespace { class FindIdenticalExprVisitor : public RecursiveASTVisitor<FindIdenticalExprVisitor> { 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 or conditional operators. bool VisitBinaryOperator(const BinaryOperator *B); @@ -45,6 +47,7 @@ public: private: BugReporter &BR; + const CheckerBase *Checker; AnalysisDeclContext *AC; }; } // end anonymous namespace @@ -112,7 +115,8 @@ 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 @@ -137,7 +141,8 @@ bool FindIdenticalExprVisitor::VisitConditionalOperator( Sr[0] = C->getTrueExpr()->getSourceRange(); Sr[1] = C->getFalseExpr()->getSourceRange(); BR.EmitBasicReport( - AC->getDecl(), "Identical expressions in conditional expression", + AC->getDecl(), Checker, + "Identical expressions in conditional expression", categories::LogicError, "identical expressions on both sides of ':' in conditional expression", ELoc, Sr); @@ -245,7 +250,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/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp index cc940be7b18..c95654cb218 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp +++ b/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 { @@ -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; @@ -476,7 +480,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. @@ -532,17 +537,17 @@ visit(const ObjCImplementationDecl *ImplD) const { reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, 0); } 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 +562,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 +580,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())); } } @@ -750,10 +756,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/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp index 02a7cc34e4d..2020f66846b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp @@ -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,8 +136,9 @@ 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()); } @@ -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()); } @@ -216,22 +220,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); + ASTFieldVisitor walker(R, BR, Checker); walker.Visit(*I); } } @@ -284,8 +292,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 +308,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/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp index f1f06c798cd..33e9c99b50e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp @@ -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)")); } diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp index 32ebb51226b..2fbfbafbe2c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp @@ -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 diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index e7edc20ac3e..296997a5941 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -155,31 +155,23 @@ class MallocChecker : public Checker<check::DeadSymbols, check::Location, eval::Assume> { - mutable OwningPtr<BugType> BT_DoubleFree; - mutable OwningPtr<BugType> BT_DoubleDelete; - 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) {} /// 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; @@ -207,6 +199,16 @@ public: const char *NL, const char *Sep) const; private: + mutable OwningPtr<BugType> BT_DoubleFree[CK_NumCheckKinds]; + mutable OwningPtr<BugType> BT_DoubleDelete; + mutable OwningPtr<BugType> BT_Leak[CK_NumCheckKinds]; + mutable OwningPtr<BugType> BT_UseFree[CK_NumCheckKinds]; + mutable OwningPtr<BugType> BT_BadFree[CK_NumCheckKinds]; + mutable OwningPtr<BugType> BT_MismatchedDealloc; + mutable OwningPtr<BugType> BT_OffsetFree[CK_NumCheckKinds]; + mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc, + *II_valloc, *II_reallocf, *II_strndup, *II_strdup; + void initIdentifierInfo(ASTContext &C) const; /// \brief Determine family of a deallocation expression. @@ -304,10 +306,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); @@ -507,7 +511,7 @@ bool MallocChecker::isAllocationFunction(const FunctionDecl *FD, return true; } - if (Filter.CMallocOptimistic && FD->hasAttrs()) + if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs()) for (specific_attr_iterator<OwnershipAttr> i = FD->specific_attr_begin<OwnershipAttr>(), e = FD->specific_attr_end<OwnershipAttr>(); @@ -529,7 +533,7 @@ bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const return true; } - if (Filter.CMallocOptimistic && FD->hasAttrs()) + if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs()) for (specific_attr_iterator<OwnershipAttr> i = FD->specific_attr_begin<OwnershipAttr>(), e = FD->specific_attr_end<OwnershipAttr>(); @@ -624,7 +628,8 @@ 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()) @@ -671,7 +676,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()); @@ -1092,18 +1097,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"); @@ -1112,18 +1122,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) { @@ -1217,17 +1227,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); @@ -1253,7 +1267,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); @@ -1267,14 +1281,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); @@ -1318,19 +1333,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) 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); @@ -1361,7 +1380,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); @@ -1370,18 +1389,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); @@ -1395,21 +1417,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) @@ -1421,15 +1447,18 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range, void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const { - if (!Filter.CNewDeleteChecker) + if (!ChecksEnabled[CK_NewDeleteChecker]) return; - if (!isTrackedByCurrentChecker(C, Sym)) + 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("Double delete", "Memory Error")); + BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker], + "Double delete", "Memory Error")); BugReport *R = new BugReport(*BT_DoubleDelete, "Attempt to delete released memory", N); @@ -1601,31 +1630,34 @@ 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. @@ -1656,9 +1688,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); @@ -1732,11 +1764,12 @@ void MallocChecker::checkPreCall(const CallEvent &Call, 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; } @@ -2230,17 +2263,26 @@ 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; + checker->CheckNames[MallocChecker::CK_NewDeleteChecker] = + mgr.getCurrentCheckName(); + } } -#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/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp index 0cdf911bb4b..8097727529d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp @@ -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/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp index 6c776eb9ebb..ec1ed94c595 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp @@ -236,10 +236,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/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp index fc28e1fb7f4..f8570071d1b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp @@ -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/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index 235ad5d534d..4f7f011e37c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -75,7 +75,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); } } @@ -123,7 +123,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 +136,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)") {} }; } @@ -264,11 +266,10 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const { BugType *bug = 0; if (isNSError) - bug = new NSErrorDerefBug(); + bug = new NSErrorDerefBug(this); else - bug = new CFErrorDerefBug(); - BugReport *report = new BugReport(*bug, os.str(), - event.SinkNode); + bug = new CFErrorDerefBug(this); + BugReport *report = new BugReport(*bug, os.str(), event.SinkNode); BR.emitReport(report); } @@ -305,14 +306,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/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp index f7c9bc2c179..0e9cbba3505 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp @@ -150,7 +150,6 @@ void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg, C.generateSink(); } - void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) { mgr.registerChecker<NoReturnFunctionChecker>(); } diff --git a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp index bde902707eb..c9b86399fd9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp @@ -162,8 +162,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", @@ -177,7 +176,7 @@ 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", diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp index 4018a66ecf5..74929296b92 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp @@ -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); @@ -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/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp index 503b1b501a7..239860d64dc 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp +++ b/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); @@ -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/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp index b9e96ee99fc..165bdafccbc 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp @@ -33,7 +33,7 @@ class ObjCContainersChecker : public Checker< check::PreStmt<CallExpr>, mutable OwningPtr<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/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp index 789b9f4cc19..a9e43b0e641 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp @@ -212,7 +212,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/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp index 8506e08b2b9..33200a06d9a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp @@ -81,10 +81,10 @@ public: namespace { class InitSelfBug : public BugType { - const std::string desc; public: - InitSelfBug() : BugType("Missing \"self = [(super or self) init...]\"", - categories::CoreFoundationObjectiveC) {} + InitSelfBug(const CheckerBase *Checker) + : BugType(Checker, "Missing \"self = [(super or self) init...]\"", + categories::CoreFoundationObjectiveC) {} }; } // end anonymous namespace @@ -147,7 +147,8 @@ static bool isInvalidSelf(const Expr *E, CheckerContext &C) { } static void checkForInvalidSelf(const Expr *E, CheckerContext &C, - const char *errorStr) { + const char *errorStr, + const CheckerBase *Checker) { if (!E) return; @@ -162,8 +163,7 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C, if (!N) return; - BugReport *report = - new BugReport(*new InitSelfBug(), errorStr, N); + BugReport *report = new BugReport(*new InitSelfBug(Checker), errorStr, N); C.emitReport(report); } @@ -205,9 +205,11 @@ 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...]'", + this); } void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S, @@ -218,8 +220,9 @@ 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...]'", + this); } // When a call receives a reference to 'self', [Pre/Post]Call pass diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp index 99cbe4b3458..606c734a309 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp @@ -111,7 +111,8 @@ 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; @@ -172,7 +173,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 +188,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/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp index bcbfacdb177..3e86c7618fa 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp @@ -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/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp index 07c82d46194..8f63cecfd39 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp @@ -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/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp index 9e83ef891e2..ac76e0bf8c2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp @@ -102,7 +102,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, if (state->contains<LockSet>(lockR)) { if (!BT_doublelock) - BT_doublelock.reset(new BugType("Double locking", "Lock checker")); + BT_doublelock.reset(new BugType(this, "Double locking", "Lock checker")); ExplodedNode *N = C.generateSink(); if (!N) return; @@ -165,7 +165,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, const MemRegion *firstLockR = LS.getHead(); if (firstLockR != lockR) { if (!BT_lor) - BT_lor.reset(new BugType("Lock order reversal", "Lock checker")); + BT_lor.reset(new BugType(this, "Lock order reversal", "Lock checker")); ExplodedNode *N = C.generateSink(); if (!N) return; @@ -184,7 +184,6 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, C.addTransition(state); } - void ento::registerPthreadLockChecker(CheckerManager &mgr) { mgr.registerChecker<PthreadLockChecker>(); } diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index a25586550db..16616224f9a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -1547,8 +1547,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. @@ -1559,7 +1560,8 @@ namespace { class UseAfterRelease : public CFRefBug { public: - UseAfterRelease() : CFRefBug("Use-after-release") {} + UseAfterRelease(const CheckerBase *checker) + : CFRefBug(checker, "Use-after-release") {} const char *getDescription() const { return "Reference-counted object is used after it is released"; @@ -1568,7 +1570,7 @@ namespace { class BadRelease : public CFRefBug { public: - BadRelease() : CFRefBug("Bad release") {} + BadRelease(const CheckerBase *checker) : CFRefBug(checker, "Bad release") {} const char *getDescription() const { return "Incorrect decrement of the reference count of an object that is " @@ -1578,8 +1580,8 @@ 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 { return "-dealloc called while using garbage collection"; @@ -1588,8 +1590,8 @@ namespace { 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 { return "-dealloc sent to object that may be referenced elsewhere"; @@ -1598,8 +1600,8 @@ namespace { 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 { return "Object autoreleased too many times"; @@ -1608,8 +1610,8 @@ namespace { 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 { return "Object with a +0 retain count returned to caller where a +1 " @@ -1619,8 +1621,7 @@ 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); } @@ -2406,17 +2407,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(); @@ -2426,17 +2428,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(); @@ -3075,22 +3079,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; } @@ -3342,7 +3346,7 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, 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, @@ -3530,7 +3534,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 = diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp index fe253b719b5..6a43bf8aa28 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp @@ -69,9 +69,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/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp index ed96c401a7a..5a4632518e2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -94,9 +94,9 @@ 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); } @@ -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/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp index 9ca0ab5d7fb..ac250cac1e1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp @@ -109,11 +109,11 @@ public: SimpleStreamChecker::SimpleStreamChecker() : IIfopen(0), IIfclose(0) { // 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/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp index 4fd778ef58c..96384904f6b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -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; @@ -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/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index ffdf2d54b4c..7a4831b32a1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -270,9 +270,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); @@ -348,8 +349,8 @@ ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state, 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); } @@ -378,9 +379,9 @@ 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); @@ -407,8 +408,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/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp index 264f7f9fdb9..2d261ca62cf 100644 --- a/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp @@ -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/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp index 8235e68937a..410390d0fc0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp @@ -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/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp index e746028cea6..927f28da3d4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp @@ -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/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp index 3f6549de56b..fd3c8f15381 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -55,7 +55,8 @@ 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); diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp index 5df8846766e..3468e67f3c6 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp @@ -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/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp index 016e3c80459..b06ecb05761 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -54,7 +54,7 @@ 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; diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp index 16007a9d912..46ae858a08d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -57,21 +57,15 @@ private: const unsigned numArgs, const unsigned sizeArg, const char *fn) const; + void LazyInitialize(OwningPtr<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) //===----------------------------------------------------------------------===// @@ -217,7 +211,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); diff --git a/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp index 1ba7301ac42..4c913a6e4a0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp @@ -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); } } diff --git a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp index 30aef060690..a558c348562 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp @@ -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); diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp index 7b6adbfad87..800d7c439c8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ b/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(0) {} + 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,7 +213,7 @@ 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(); diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index e1961ecbe15..eedf05685cc 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -3420,7 +3420,8 @@ void BugReporter::FlushReport(BugReport *exampleReport, BugType& BT = exampleReport->getBugType(); OwningPtr<PathDiagnostic> - D(new PathDiagnostic(exampleReport->getDeclWithIssue(), + D(new PathDiagnostic(exampleReport->getBugType().getCheckName(), + exampleReport->getDeclWithIssue(), exampleReport->getBugType().getName(), exampleReport->getDescription(), exampleReport->getShortDescription(/*Fallback=*/false), @@ -3472,13 +3473,21 @@ void BugReporter::FlushReport(BugReport *exampleReport, } 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,15 +3496,16 @@ 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; diff --git a/clang/lib/StaticAnalyzer/Core/Checker.cpp b/clang/lib/StaticAnalyzer/Core/Checker.cpp index 07e0aac2d42..e2b2a19e964 100644 --- a/clang/lib/StaticAnalyzer/Core/Checker.cpp +++ b/clang/lib/StaticAnalyzer/Core/Checker.cpp @@ -22,6 +22,8 @@ StringRef CheckerBase::getTagDescription() const { return "A Checker"; } +CheckName CheckerBase::getCheckName() const { return Name; } + void Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, diff --git a/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp index 47299030cc4..1937ecf2c36 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp @@ -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/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index c4297292e97..fec39bdc0b8 100644 --- a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -106,12 +106,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)), |