diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h @@ -35,13 +35,13 @@ virtual void anchor(); public: - BugType(CheckerNameRef CheckerName, StringRef Name, StringRef Cat, - bool SuppressOnSink = false) - : CheckerName(CheckerName), Description(Name), Category(Cat), + BugType(CheckerNameRef CheckerName, StringRef Desc, + StringRef Cat = categories::LogicError, bool SuppressOnSink = false) + : CheckerName(CheckerName), Description(Desc), Category(Cat), Checker(nullptr), SuppressOnSink(SuppressOnSink) {} - BugType(const CheckerBase *Checker, StringRef Name, StringRef Cat, - bool SuppressOnSink = false) - : CheckerName(Checker->getCheckerName()), Description(Name), + BugType(const CheckerBase *Checker, StringRef Desc, + StringRef Cat = categories::LogicError, bool SuppressOnSink = false) + : CheckerName(Checker->getCheckerName()), Description(Desc), Category(Cat), Checker(Checker), SuppressOnSink(SuppressOnSink) {} virtual ~BugType() = default; @@ -64,27 +64,6 @@ bool isSuppressOnSink() const { return SuppressOnSink; } }; -class BuiltinBug : public BugType { - const std::string desc; - void anchor() override; -public: - BuiltinBug(class CheckerNameRef checker, const char *name, - const char *description) - : BugType(checker, name, categories::LogicError), desc(description) {} - - BuiltinBug(const CheckerBase *checker, const char *name, - const char *description) - : BugType(checker, name, categories::LogicError), desc(description) {} - - BuiltinBug(class CheckerNameRef checker, const char *name) - : BugType(checker, name, categories::LogicError), desc(name) {} - - BuiltinBug(const CheckerBase *checker, const char *name) - : BugType(checker, name, categories::LogicError), desc(name) {} - - StringRef getDescription() const { return desc; } -}; - } // namespace ento } // end clang namespace diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp @@ -25,7 +25,7 @@ namespace { class ArrayBoundChecker : public Checker { - mutable std::unique_ptr BT; + mutable std::unique_ptr BT; public: void checkLocation(SVal l, bool isLoad, const Stmt* S, @@ -66,17 +66,15 @@ return; if (!BT) - BT.reset(new BuiltinBug( - this, "Out-of-bound array access", - "Access out-of-bound array element (buffer overflow)")); + BT.reset(new BugType(this, "Out-of-bound array access")); // FIXME: It would be nice to eventually make this diagnostic more clear, // e.g., by referencing the original declaration or by saying *why* this // reference is outside the range. // Generate a report for this bug. - auto report = - std::make_unique(*BT, BT->getDescription(), N); + auto report = std::make_unique( + *BT, "Access out-of-bound array element (buffer overflow)", N); report->addRange(LoadS->getSourceRange()); C.emitReport(std::move(report)); diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp --- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -32,7 +32,7 @@ namespace { class ArrayBoundCheckerV2 : public Checker { - mutable std::unique_ptr BT; + mutable std::unique_ptr BT; mutable std::unique_ptr TaintBT; enum OOB_Kind { OOB_Precedes, OOB_Excedes }; @@ -258,7 +258,7 @@ return; if (!BT) - BT.reset(new BuiltinBug(this, "Out-of-bound access")); + BT.reset(new BugType(this, "Out-of-bound access")); // FIXME: This diagnostics are preliminary. We should get far better // diagnostics for explaining buffer overruns. diff --git a/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp @@ -24,7 +24,7 @@ namespace { class BoolAssignmentChecker : public Checker< check::Bind > { - mutable std::unique_ptr BT; + mutable std::unique_ptr BT; void emitReport(ProgramStateRef state, CheckerContext &C, bool IsTainted = false) const; @@ -37,7 +37,7 @@ bool IsTainted) const { if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) { if (!BT) - BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value")); + BT.reset(new BugType(this, "Assignment of a non-Boolean value")); StringRef Msg = IsTainted ? "Might assign a tainted non-Boolean value" : "Assignment of a non-Boolean value"; diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -653,13 +653,15 @@ void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State, const Stmt *S, StringRef WarningMsg) const { if (ExplodedNode *N = C.generateErrorNode(State)) { - if (!BT_Null) - BT_Null.reset(new BuiltinBug( - Filter.CheckNameCStringNullArg, categories::UnixAPI, - "Null pointer argument in call to byte string function")); + if (!BT_Null) { + // FIXME: This call uses the string constant 'categories::UnixAPI' as the + // description of the bug; it should be replaced by a real description. + BT_Null.reset( + new BugType(Filter.CheckNameCStringNullArg, categories::UnixAPI)); + } - BuiltinBug *BT = static_cast(BT_Null.get()); - auto Report = std::make_unique(*BT, WarningMsg, N); + auto Report = + std::make_unique(*BT_Null, WarningMsg, N); Report->addRange(S->getSourceRange()); if (const auto *Ex = dyn_cast(S)) bugreporter::trackExpressionValue(N, Ex, *Report); @@ -674,13 +676,11 @@ const char *Msg = "Bytes string function accesses uninitialized/garbage values"; if (!BT_UninitRead) - BT_UninitRead.reset( - new BuiltinBug(Filter.CheckNameCStringUninitializedRead, - "Accessing unitialized/garbage values", Msg)); + BT_UninitRead.reset(new BugType(Filter.CheckNameCStringUninitializedRead, + "Accessing unitialized/garbage values")); - BuiltinBug *BT = static_cast(BT_UninitRead.get()); - - auto Report = std::make_unique(*BT, Msg, N); + auto Report = + std::make_unique(*BT_UninitRead, Msg, N); Report->addRange(E->getSourceRange()); bugreporter::trackExpressionValue(N, E, *Report); C.emitReport(std::move(Report)); @@ -692,18 +692,16 @@ StringRef WarningMsg) const { if (ExplodedNode *N = C.generateErrorNode(State)) { if (!BT_Bounds) - BT_Bounds.reset(new BuiltinBug( - Filter.CheckCStringOutOfBounds ? Filter.CheckNameCStringOutOfBounds - : Filter.CheckNameCStringNullArg, - "Out-of-bound array access", - "Byte string function accesses out-of-bound array element")); - - BuiltinBug *BT = static_cast(BT_Bounds.get()); + BT_Bounds.reset(new BugType(Filter.CheckCStringOutOfBounds + ? Filter.CheckNameCStringOutOfBounds + : Filter.CheckNameCStringNullArg, + "Out-of-bound array access")); // FIXME: It would be nice to eventually make this diagnostic more clear, // e.g., by referencing the original declaration or by saying *why* this // reference is outside the range. - auto Report = std::make_unique(*BT, WarningMsg, N); + auto Report = + std::make_unique(*BT_Bounds, WarningMsg, N); Report->addRange(S->getSourceRange()); C.emitReport(std::move(Report)); } @@ -713,10 +711,12 @@ const Stmt *S, StringRef WarningMsg) const { if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) { - if (!BT_NotCString) - BT_NotCString.reset(new BuiltinBug( - Filter.CheckNameCStringNotNullTerm, categories::UnixAPI, - "Argument is not a null-terminated string.")); + if (!BT_NotCString) { + // FIXME: This call uses the string constant 'categories::UnixAPI' as the + // description of the bug; it should be replaced by a real description. + BT_NotCString.reset( + new BugType(Filter.CheckNameCStringNotNullTerm, categories::UnixAPI)); + } auto Report = std::make_unique(*BT_NotCString, WarningMsg, N); @@ -729,10 +729,13 @@ void CStringChecker::emitAdditionOverflowBug(CheckerContext &C, ProgramStateRef State) const { if (ExplodedNode *N = C.generateErrorNode(State)) { - if (!BT_AdditionOverflow) + if (!BT_AdditionOverflow) { + // FIXME: This call uses the word "API" as the description of the bug; + // it should be replaced by a better error message (if this unlikely + // situation continues to exist as a separate bug type). BT_AdditionOverflow.reset( - new BuiltinBug(Filter.CheckNameCStringOutOfBounds, "API", - "Sum of expressions causes overflow.")); + new BugType(Filter.CheckNameCStringOutOfBounds, "API")); + } // 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 diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -123,7 +123,7 @@ void LazyInit_BT(const char *desc, std::unique_ptr &BT) const { if (!BT) - BT.reset(new BuiltinBug(OriginalName, desc)); + BT.reset(new BugType(OriginalName, desc)); } bool uninitRefOrPointer(CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx, @@ -379,7 +379,7 @@ return nullptr; } if (!BT_call_undef) - BT_call_undef.reset(new BuiltinBug( + BT_call_undef.reset(new BugType( OriginalName, "Called function pointer is an uninitialized pointer value")); emitBadCall(BT_call_undef.get(), C, Callee); @@ -395,7 +395,7 @@ return nullptr; } if (!BT_call_null) - BT_call_null.reset(new BuiltinBug( + BT_call_null.reset(new BugType( OriginalName, "Called function pointer is null (null dereference)")); emitBadCall(BT_call_null.get(), C, Callee); return nullptr; @@ -450,7 +450,7 @@ return nullptr; } if (!BT_cxx_call_undef) - BT_cxx_call_undef.reset(new BuiltinBug( + BT_cxx_call_undef.reset(new BugType( OriginalName, "Called C++ object pointer is uninitialized")); emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr()); return nullptr; @@ -466,7 +466,7 @@ } if (!BT_cxx_call_null) BT_cxx_call_null.reset( - new BuiltinBug(OriginalName, "Called C++ object pointer is null")); + new BugType(OriginalName, "Called C++ object pointer is null")); emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr()); return nullptr; } @@ -495,13 +495,13 @@ return nullptr; if (!BT_cxx_delete_undef) BT_cxx_delete_undef.reset( - new BuiltinBug(OriginalName, "Uninitialized argument value")); + new BugType(OriginalName, "Uninitialized argument value")); if (DE->isArrayFormAsWritten()) Desc = "Argument to 'delete[]' is uninitialized"; else Desc = "Argument to 'delete' is uninitialized"; - BugType *BT = BT_cxx_delete_undef.get(); - auto R = std::make_unique(*BT, Desc, N); + auto R = + std::make_unique(*BT_cxx_delete_undef, Desc, N); bugreporter::trackExpressionValue(N, DE, *R); C.emitReport(std::move(R)); return nullptr; @@ -585,21 +585,21 @@ switch (msg.getMessageKind()) { case OCM_Message: if (!BT_msg_undef) - BT_msg_undef.reset(new BuiltinBug(OriginalName, - "Receiver in message expression " - "is an uninitialized value")); + BT_msg_undef.reset(new BugType(OriginalName, + "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( + BT_objc_prop_undef.reset(new BugType( OriginalName, "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( + BT_objc_subscript_undef.reset(new BugType( OriginalName, "Subscript access on an uninitialized object pointer")); BT = BT_objc_subscript_undef.get(); @@ -634,8 +634,8 @@ } if (!BT_msg_ret) - BT_msg_ret.reset(new BuiltinBug(OriginalName, - "Receiver in message expression is 'nil'")); + BT_msg_ret.reset( + new BugType(OriginalName, "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 --- a/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp @@ -24,7 +24,7 @@ namespace { class CastSizeChecker : public Checker< check::PreStmt > { - mutable std::unique_ptr BT; + mutable std::unique_ptr BT; public: void checkPreStmt(const CastExpr *CE, CheckerContext &C) const; @@ -132,11 +132,11 @@ if (ExplodedNode *errorNode = C.generateErrorNode()) { if (!BT) - BT.reset(new BuiltinBug(this, "Cast region with wrong size.", - "Cast a region whose size is not a multiple" - " of the destination type size.")); - auto R = std::make_unique(*BT, BT->getDescription(), - errorNode); + BT.reset(new BugType(this, "Cast region with wrong size.")); + constexpr llvm::StringLiteral Msg = + "Cast a region whose size is not a multiple of the destination type " + "size."; + auto R = std::make_unique(*BT, Msg, errorNode); R->addRange(CE->getSourceRange()); C.emitReport(std::move(R)); } diff --git a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp @@ -41,7 +41,7 @@ // bug<--foo()-- JAIL_ENTERED<--foo()-- class ChrootChecker : public Checker { // This bug refers to possibly break out of a chroot() jail. - mutable std::unique_ptr BT_BreakJail; + mutable std::unique_ptr BT_BreakJail; const CallDescription Chroot{{"chroot"}, 1}, Chdir{{"chdir"}, 1}; @@ -125,11 +125,11 @@ if (isRootChanged((intptr_t) *k)) if (ExplodedNode *N = C.generateNonFatalErrorNode()) { if (!BT_BreakJail) - BT_BreakJail.reset(new BuiltinBug( - this, "Break out of jail", "No call of chdir(\"/\") immediately " - "after chroot")); - C.emitReport(std::make_unique( - *BT_BreakJail, BT_BreakJail->getDescription(), N)); + BT_BreakJail.reset(new BugType(this, "Break out of jail")); + constexpr llvm::StringLiteral Msg = + "No call of chdir(\"/\") immediately after chroot"; + C.emitReport( + std::make_unique(*BT_BreakJail, Msg, N)); } } diff --git a/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp @@ -42,7 +42,7 @@ void checkPreStmt(const ImplicitCastExpr *Cast, CheckerContext &C) const; private: - mutable std::unique_ptr BT; + mutable std::unique_ptr BT; bool isLossOfPrecision(const ImplicitCastExpr *Cast, QualType DestType, CheckerContext &C) const; @@ -127,8 +127,7 @@ void ConversionChecker::reportBug(ExplodedNode *N, const Expr *E, CheckerContext &C, const char Msg[]) const { if (!BT) - BT.reset( - new BuiltinBug(this, "Conversion", "Possible loss of sign/precision.")); + BT.reset(new BugType(this, "Conversion")); // Generate a report for this bug. auto R = std::make_unique(*BT, Msg, N); diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp --- a/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp @@ -322,7 +322,7 @@ namespace { class ReportStmts : public Checker> { - BuiltinBug BT_stmtLoc{this, "Statement"}; + BugType BT_stmtLoc{this, "Statement"}; public: void checkPreStmt(const Stmt *S, CheckerContext &C) const { diff --git a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp @@ -58,7 +58,7 @@ // Being conservative, it does not warn if there is slight possibility the // value can be matching. class EnumCastOutOfRangeChecker : public Checker> { - mutable std::unique_ptr EnumValueCastOutOfRange; + mutable std::unique_ptr EnumValueCastOutOfRange; void reportWarning(CheckerContext &C) const; public: @@ -81,12 +81,12 @@ if (const ExplodedNode *N = C.generateNonFatalErrorNode()) { if (!EnumValueCastOutOfRange) EnumValueCastOutOfRange.reset( - new BuiltinBug(this, "Enum cast out of range", - "The value provided to the cast expression is not in " - "the valid range of values for the enum")); + new BugType(this, "Enum cast out of range")); + constexpr llvm::StringLiteral Msg = + "The value provided to the cast expression is not in the valid range" + " of values for the enum"; C.emitReport(std::make_unique( - *EnumValueCastOutOfRange, EnumValueCastOutOfRange->getDescription(), - N)); + *EnumValueCastOutOfRange, Msg, N)); } } diff --git a/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp @@ -24,7 +24,7 @@ namespace { class FixedAddressChecker : public Checker< check::PreStmt > { - mutable std::unique_ptr BT; + mutable std::unique_ptr BT; public: void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; @@ -49,14 +49,13 @@ return; if (ExplodedNode *N = C.generateNonFatalErrorNode()) { + // FIXME: improve grammar in the following strings: if (!BT) - 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.")); - auto R = - std::make_unique(*BT, BT->getDescription(), N); + BT.reset(new BugType(this, "Use fixed address")); + constexpr llvm::StringLiteral Msg = + "Using a fixed address is not portable because that address will " + "probably not be valid in all environments or platforms."; + auto R = std::make_unique(*BT, Msg, N); R->addRange(B->getRHS()->getSourceRange()); C.emitReport(std::move(R)); } diff --git a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp @@ -303,7 +303,7 @@ NonNullParamChecker::genReportReferenceToNullPointer( const ExplodedNode *ErrorNode, const Expr *ArgE) const { if (!BTNullRefArg) - BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer")); + BTNullRefArg.reset(new BugType(this, "Dereference of null pointer")); auto R = std::make_unique( *BTNullRefArg, "Forming reference to null pointer", ErrorNode); diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp @@ -25,8 +25,8 @@ namespace { class ObjCAtSyncChecker : public Checker< check::PreStmt > { - mutable std::unique_ptr BT_null; - mutable std::unique_ptr BT_undef; + mutable std::unique_ptr BT_null; + mutable std::unique_ptr BT_undef; public: void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const; @@ -44,8 +44,8 @@ if (isa(V)) { if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_undef) - BT_undef.reset(new BuiltinBug(this, "Uninitialized value used as mutex " - "for @synchronized")); + BT_undef.reset(new BugType(this, "Uninitialized value used as mutex " + "for @synchronized")); auto report = std::make_unique( *BT_undef, BT_undef->getDescription(), N); bugreporter::trackExpressionValue(N, Ex, *report); @@ -67,9 +67,9 @@ // a null mutex just means no synchronization occurs. if (ExplodedNode *N = C.generateNonFatalErrorNode(nullState)) { if (!BT_null) - BT_null.reset(new BuiltinBug( - this, "Nil value used as mutex for @synchronized() " - "(no synchronization will occur)")); + BT_null.reset( + new BugType(this, "Nil value used as mutex for @synchronized() " + "(no synchronization will occur)")); auto report = std::make_unique( *BT_null, BT_null->getDescription(), N); bugreporter::trackExpressionValue(N, Ex, *report); diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp @@ -11,13 +11,14 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "llvm/ADT/StringRef.h" using namespace clang; using namespace ento; @@ -55,8 +56,8 @@ bool PointedNeeded = false) const; void initAllocIdentifiers(ASTContext &C) const; - mutable std::unique_ptr BT_pointerArith; - mutable std::unique_ptr BT_polyArray; + mutable std::unique_ptr BT_pointerArith; + mutable std::unique_ptr BT_polyArray; mutable llvm::SmallSet AllocFunctions; public: @@ -168,12 +169,11 @@ return; if (ExplodedNode *N = C.generateNonFatalErrorNode()) { if (!BT_polyArray) - BT_polyArray.reset(new BuiltinBug( - this, "Dangerous pointer arithmetic", - "Pointer arithmetic on a pointer to base class is dangerous " - "because derived and base class may have different size.")); - auto R = std::make_unique( - *BT_polyArray, BT_polyArray->getDescription(), N); + BT_polyArray.reset(new BugType(this, "Dangerous pointer arithmetic")); + constexpr llvm::StringLiteral Msg = + "Pointer arithmetic on a pointer to base class is dangerous " + "because derived and base class may have different size."; + auto R = std::make_unique(*BT_polyArray, Msg, N); R->addRange(E->getSourceRange()); R->markInteresting(ArrayRegion); C.emitReport(std::move(R)); @@ -191,12 +191,11 @@ if (ExplodedNode *N = C.generateNonFatalErrorNode()) { if (!BT_pointerArith) - BT_pointerArith.reset(new BuiltinBug(this, "Dangerous pointer arithmetic", - "Pointer arithmetic on non-array " - "variables relies on memory layout, " - "which is dangerous.")); - auto R = std::make_unique( - *BT_pointerArith, BT_pointerArith->getDescription(), N); + BT_pointerArith.reset(new BugType(this, "Dangerous pointer arithmetic")); + constexpr llvm::StringLiteral Msg = + "Pointer arithmetic on non-array variables relies on memory layout, " + "which is dangerous."; + auto R = std::make_unique(*BT_pointerArith, Msg, N); R->addRange(SR); R->markInteresting(Region); C.emitReport(std::move(R)); diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp @@ -17,6 +17,7 @@ #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "llvm/ADT/StringRef.h" using namespace clang; using namespace ento; @@ -24,7 +25,7 @@ namespace { class PointerSubChecker : public Checker< check::PreStmt > { - mutable std::unique_ptr BT; + mutable std::unique_ptr BT; public: void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; @@ -59,12 +60,11 @@ if (ExplodedNode *N = C.generateNonFatalErrorNode()) { if (!BT) - BT.reset( - new BuiltinBug(this, "Pointer subtraction", - "Subtraction of two pointers that do not point to " - "the same memory chunk may cause incorrect result.")); - auto R = - std::make_unique(*BT, BT->getDescription(), N); + BT.reset(new BugType(this, "Pointer subtraction")); + constexpr llvm::StringLiteral Msg = + "Subtraction of two pointers that do not point to the same memory " + "chunk may cause incorrect result."; + auto R = std::make_unique(*BT, Msg, N); R->addRange(B->getSourceRange()); C.emitReport(std::move(R)); } diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp @@ -26,7 +26,7 @@ namespace { class ReturnPointerRangeChecker : public Checker< check::PreStmt > { - mutable std::unique_ptr BT; + mutable std::unique_ptr BT; public: void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; @@ -79,14 +79,13 @@ // 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( - this, "Buffer overflow", - "Returned pointer value points outside the original object " - "(potential buffer overflow)")); + BT.reset(new BugType(this, "Buffer overflow")); + constexpr llvm::StringLiteral Msg = + "Returned pointer value points outside the original object " + "(potential buffer overflow)"; // Generate a report for this bug. - auto Report = - std::make_unique(*BT, BT->getDescription(), N); + auto Report = std::make_unique(*BT, Msg, N); Report->addRange(RetE->getSourceRange()); const auto ConcreteElementCount = ElementCount.getAs(); diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -24,8 +24,8 @@ namespace { class ReturnUndefChecker : public Checker< check::PreStmt > { - mutable std::unique_ptr BT_Undef; - mutable std::unique_ptr BT_NullReference; + mutable std::unique_ptr BT_Undef; + mutable std::unique_ptr BT_NullReference; void emitUndef(CheckerContext &C, const Expr *RetE) const; void checkReference(CheckerContext &C, const Expr *RetE, @@ -77,14 +77,13 @@ } } -static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE, - const Expr *TrackingE = nullptr) { +static void emitBug(CheckerContext &C, BugType &BT, StringRef Msg, + const Expr *RetE, const Expr *TrackingE = nullptr) { ExplodedNode *N = C.generateErrorNode(); if (!N) return; - auto Report = - std::make_unique(BT, BT.getDescription(), N); + auto Report = std::make_unique(BT, Msg, N); Report->addRange(RetE->getSourceRange()); bugreporter::trackExpressionValue(N, TrackingE ? TrackingE : RetE, *Report); @@ -94,10 +93,8 @@ void ReturnUndefChecker::emitUndef(CheckerContext &C, const Expr *RetE) const { if (!BT_Undef) - BT_Undef.reset( - new BuiltinBug(this, "Garbage return value", - "Undefined or garbage value returned to caller")); - emitBug(C, *BT_Undef, RetE); + BT_Undef.reset(new BugType(this, "Garbage return value")); + emitBug(C, *BT_Undef, "Undefined or garbage value returned to caller", RetE); } void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE, @@ -113,9 +110,10 @@ // The return value is known to be null. Emit a bug report. if (!BT_NullReference) - BT_NullReference.reset(new BuiltinBug(this, "Returning null reference")); + BT_NullReference.reset(new BugType(this, "Returning null reference")); - emitBug(C, *BT_NullReference, RetE, bugreporter::getDerefExpr(RetE)); + emitBug(C, *BT_NullReference, BT_NullReference->getDescription(), RetE, + bugreporter::getDerefExpr(RetE)); } void ento::registerReturnUndefChecker(CheckerManager &mgr) { diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -30,10 +30,10 @@ : public Checker, check::EndFunction> { mutable IdentifierInfo *dispatch_semaphore_tII = nullptr; - mutable std::unique_ptr BT_stackleak; - mutable std::unique_ptr BT_returnstack; - mutable std::unique_ptr BT_capturedstackasync; - mutable std::unique_ptr BT_capturedstackret; + mutable std::unique_ptr BT_stackleak; + mutable std::unique_ptr BT_returnstack; + mutable std::unique_ptr BT_capturedstackasync; + mutable std::unique_ptr BT_capturedstackret; public: enum CheckKind { @@ -154,7 +154,7 @@ if (!N) return; if (!BT_returnstack) - BT_returnstack = std::make_unique( + BT_returnstack = std::make_unique( CheckNames[CK_StackAddrEscapeChecker], "Return of address to stack-allocated memory"); // Generate a report for this bug. @@ -194,7 +194,7 @@ if (!N) continue; if (!BT_capturedstackasync) - BT_capturedstackasync = std::make_unique( + BT_capturedstackasync = std::make_unique( CheckNames[CK_StackAddrAsyncEscapeChecker], "Address of stack-allocated memory is captured"); SmallString<128> Buf; @@ -218,7 +218,7 @@ if (!N) continue; if (!BT_capturedstackret) - BT_capturedstackret = std::make_unique( + BT_capturedstackret = std::make_unique( CheckNames[CK_StackAddrEscapeChecker], "Address of stack-allocated memory is captured"); SmallString<128> Buf; @@ -364,12 +364,9 @@ return; if (!BT_stackleak) - BT_stackleak = std::make_unique( - CheckNames[CK_StackAddrEscapeChecker], - "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"); + BT_stackleak = + std::make_unique(CheckNames[CK_StackAddrEscapeChecker], + "Stack address stored into global variable"); for (const auto &P : Cb.V) { const MemRegion *Referrer = P.first; diff --git a/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp @@ -78,7 +78,7 @@ class TestAfterDivZeroChecker : public Checker, check::BranchCondition, check::EndFunction> { - mutable std::unique_ptr DivZeroBug; + mutable std::unique_ptr DivZeroBug; void reportBug(SVal Val, CheckerContext &C) const; public: @@ -166,7 +166,7 @@ void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const { if (ExplodedNode *N = C.generateErrorNode(C.getState())) { if (!DivZeroBug) - DivZeroBug.reset(new BuiltinBug(this, "Division by zero")); + DivZeroBug.reset(new BugType(this, "Division by zero")); auto R = std::make_unique( *DivZeroBug, "Value being compared against zero has already been used " diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp @@ -27,7 +27,7 @@ namespace { class UndefBranchChecker : public Checker { - mutable std::unique_ptr BT; + mutable std::unique_ptr BT; struct FindUndefExpr { ProgramStateRef St; @@ -71,8 +71,8 @@ ExplodedNode *N = Ctx.generateErrorNode(); if (N) { if (!BT) - BT.reset(new BuiltinBug( - this, "Branch condition evaluates to a garbage value")); + BT.reset( + new BugType(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 --- a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp @@ -72,7 +72,7 @@ if (ExplodedNode *N = C.generateErrorNode()) { if (!BT) BT.reset( - new BuiltinBug(this, "uninitialized variable captured by block")); + new BugType(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 --- a/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -92,7 +92,7 @@ if (!BT) BT.reset( - new BuiltinBug(this, "Result of operation is garbage or undefined")); + new BugType(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 --- a/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp @@ -49,7 +49,7 @@ if (!N) return; if (!BT) - BT.reset(new BuiltinBug(this, "Array subscript is undefined")); + BT.reset(new BugType(this, "Array subscript is undefined")); // Generate a report for this bug. auto R = std::make_unique(*BT, BT->getDescription(), N); diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -53,7 +53,7 @@ static const char *const DefaultMsg = "Assigned value is garbage or undefined"; if (!BT) - BT.reset(new BuiltinBug(this, DefaultMsg)); + BT.reset(new BugType(this, DefaultMsg)); // Generate a report for this bug. llvm::SmallString<128> Str; diff --git a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp @@ -38,14 +38,14 @@ class UninitializedObjectChecker : public Checker { - std::unique_ptr BT_uninitField; + std::unique_ptr BT_uninitField; public: // The fields of this struct will be initialized when registering the checker. UninitObjCheckerOptions Opts; UninitializedObjectChecker() - : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {} + : BT_uninitField(new BugType(this, "Uninitialized fields")) {} void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; diff --git a/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp @@ -44,7 +44,7 @@ class VforkChecker : public Checker> { - mutable std::unique_ptr BT; + mutable std::unique_ptr BT; mutable llvm::SmallSet VforkAllowlist; mutable const IdentifierInfo *II_vfork = nullptr; @@ -124,8 +124,7 @@ const char *Details) const { if (ExplodedNode *N = C.generateErrorNode(C.getState())) { if (!BT) - BT.reset(new BuiltinBug(this, - "Dangerous construct in a vforked process")); + BT.reset(new BugType(this, "Dangerous construct in a vforked process")); SmallString<256> buf; llvm::raw_svector_ostream os(buf); diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -2099,8 +2099,6 @@ void BugType::anchor() {} -void BuiltinBug::anchor() {} - //===----------------------------------------------------------------------===// // Methods for BugReport and subclasses. //===----------------------------------------------------------------------===// diff --git a/clang/unittests/StaticAnalyzer/CallEventTest.cpp b/clang/unittests/StaticAnalyzer/CallEventTest.cpp --- a/clang/unittests/StaticAnalyzer/CallEventTest.cpp +++ b/clang/unittests/StaticAnalyzer/CallEventTest.cpp @@ -36,11 +36,11 @@ } class CXXDeallocatorChecker : public Checker { - std::unique_ptr BT_uninitField; + std::unique_ptr BT_uninitField; public: CXXDeallocatorChecker() - : BT_uninitField(new BuiltinBug(this, "CXXDeallocator")) {} + : BT_uninitField(new BugType(this, "CXXDeallocator")) {} void checkPreCall(const CallEvent &Call, CheckerContext &C) const { const auto *DC = dyn_cast(&Call); diff --git a/clang/unittests/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp b/clang/unittests/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp --- a/clang/unittests/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp +++ b/clang/unittests/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp @@ -26,7 +26,7 @@ class FalsePositiveGenerator : public Checker { using Self = FalsePositiveGenerator; - const BuiltinBug FalsePositiveGeneratorBug{this, "FalsePositiveGenerator"}; + const BugType FalsePositiveGeneratorBug{this, "FalsePositiveGenerator"}; using HandlerFn = bool (Self::*)(const CallEvent &Call, CheckerContext &) const; CallDescriptionMap Callbacks = { diff --git a/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp --- a/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp +++ b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp @@ -89,8 +89,8 @@ class CheckerRegistrationOrderPrinter : public Checker> { - std::unique_ptr BT = - std::make_unique(this, "Registration order"); + std::unique_ptr BT = + std::make_unique(this, "Registration order"); public: void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { @@ -125,8 +125,7 @@ #define UNITTEST_CHECKER(CHECKER_NAME, DIAG_MSG) \ class CHECKER_NAME : public Checker> { \ - std::unique_ptr BT = \ - std::make_unique(this, DIAG_MSG); \ + std::unique_ptr BT = std::make_unique(this, DIAG_MSG); \ \ public: \ void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {} \