diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index b34e940682fc5..1361da46c3c81 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -206,7 +206,12 @@ def CallAndMessageChecker : Checker<"CallAndMessage">, Documentation, Dependencies<[CallAndMessageModeling]>; -def DereferenceChecker : Checker<"NullDereference">, +def DereferenceModeling : Checker<"DereferenceModeling">, + HelpText<"General support for dereference related checkers">, + Documentation, + Hidden; + +def NullDereferenceChecker : Checker<"NullDereference">, HelpText<"Check for dereferences of null pointers">, CheckerOptions<[ CmdLineOption, "true", Released> ]>, - Documentation; + Documentation, + Dependencies<[DereferenceModeling]>; def NonNullParamChecker : Checker<"NonNullParamChecker">, HelpText<"Check for null pointers passed as arguments to a function whose " diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index 0355eede75eae..e9e2771c739b6 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -33,12 +33,6 @@ class DereferenceChecker EventDispatcher > { enum DerefKind { NullPointer, UndefinedPointerValue, AddressOfLabel }; - BugType BT_Null{this, "Dereference of null pointer", categories::LogicError}; - BugType BT_Undef{this, "Dereference of undefined pointer value", - categories::LogicError}; - BugType BT_Label{this, "Dereference of the address of a label", - categories::LogicError}; - void reportBug(DerefKind K, ProgramStateRef State, const Stmt *S, CheckerContext &C) const; @@ -56,6 +50,12 @@ class DereferenceChecker bool loadedFrom = false); bool SuppressAddressSpaces = false; + + bool CheckNullDereference = false; + + std::unique_ptr BT_Null; + std::unique_ptr BT_Undef; + std::unique_ptr BT_Label; }; } // end anonymous namespace @@ -155,22 +155,27 @@ static bool isDeclRefExprToReference(const Expr *E) { void DereferenceChecker::reportBug(DerefKind K, ProgramStateRef State, const Stmt *S, CheckerContext &C) const { + if (!CheckNullDereference) { + C.addSink(); + return; + } + const BugType *BT = nullptr; llvm::StringRef DerefStr1; llvm::StringRef DerefStr2; switch (K) { case DerefKind::NullPointer: - BT = &BT_Null; + BT = BT_Null.get(); DerefStr1 = " results in a null pointer dereference"; DerefStr2 = " results in a dereference of a null pointer"; break; case DerefKind::UndefinedPointerValue: - BT = &BT_Undef; + BT = BT_Undef.get(); DerefStr1 = " results in an undefined pointer dereference"; DerefStr2 = " results in a dereference of an undefined pointer value"; break; case DerefKind::AddressOfLabel: - BT = &BT_Label; + BT = BT_Label.get(); DerefStr1 = " results in an undefined pointer dereference"; DerefStr2 = " results in a dereference of an address of a label"; break; @@ -351,12 +356,30 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, C.addTransition(State, this); } -void ento::registerDereferenceChecker(CheckerManager &mgr) { - auto *Chk = mgr.registerChecker(); - Chk->SuppressAddressSpaces = mgr.getAnalyzerOptions().getCheckerBooleanOption( - mgr.getCurrentCheckerName(), "SuppressAddressSpaces"); +void ento::registerDereferenceModeling(CheckerManager &Mgr) { + Mgr.registerChecker(); +} + +bool ento::shouldRegisterDereferenceModeling(const CheckerManager &) { + return true; +} + +void ento::registerNullDereferenceChecker(CheckerManager &Mgr) { + auto *Chk = Mgr.getChecker(); + Chk->CheckNullDereference = true; + Chk->SuppressAddressSpaces = Mgr.getAnalyzerOptions().getCheckerBooleanOption( + Mgr.getCurrentCheckerName(), "SuppressAddressSpaces"); + Chk->BT_Null.reset(new BugType(Mgr.getCurrentCheckerName(), + "Dereference of null pointer", + categories::LogicError)); + Chk->BT_Undef.reset(new BugType(Mgr.getCurrentCheckerName(), + "Dereference of undefined pointer value", + categories::LogicError)); + Chk->BT_Label.reset(new BugType(Mgr.getCurrentCheckerName(), + "Dereference of the address of a label", + categories::LogicError)); } -bool ento::shouldRegisterDereferenceChecker(const CheckerManager &mgr) { +bool ento::shouldRegisterNullDereferenceChecker(const CheckerManager &) { return true; } diff --git a/clang/test/Analysis/analyzer-enabled-checkers.c b/clang/test/Analysis/analyzer-enabled-checkers.c index 160e35c77462d..c70aeb21ab045 100644 --- a/clang/test/Analysis/analyzer-enabled-checkers.c +++ b/clang/test/Analysis/analyzer-enabled-checkers.c @@ -14,6 +14,7 @@ // CHECK-NEXT: core.BitwiseShift // CHECK-NEXT: core.CallAndMessageModeling // CHECK-NEXT: core.CallAndMessage +// CHECK-NEXT: core.DereferenceModeling // CHECK-NEXT: core.DivideZero // CHECK-NEXT: core.DynamicTypePropagation // CHECK-NEXT: core.NonNullParamChecker diff --git a/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c b/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c index 0910f030b0f07..faf0a8f19d919 100644 --- a/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c +++ b/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c @@ -22,6 +22,7 @@ // CHECK-NEXT: core.BitwiseShift // CHECK-NEXT: core.CallAndMessageModeling // CHECK-NEXT: core.CallAndMessage +// CHECK-NEXT: core.DereferenceModeling // CHECK-NEXT: core.DivideZero // CHECK-NEXT: core.DynamicTypePropagation // CHECK-NEXT: core.NonNullParamChecker