[clang] 854cbbf - [clang][analyzer] Split NullDereferenceChecker into modeling and reporting (#122139)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 10 02:17:11 PST 2025
Author: Balázs Kéri
Date: 2025-01-10T11:17:06+01:00
New Revision: 854cbbf4a8e7e98b7461eae2c2a37cfa767f791c
URL: https://github.com/llvm/llvm-project/commit/854cbbf4a8e7e98b7461eae2c2a37cfa767f791c
DIFF: https://github.com/llvm/llvm-project/commit/854cbbf4a8e7e98b7461eae2c2a37cfa767f791c.diff
LOG: [clang][analyzer] Split NullDereferenceChecker into modeling and reporting (#122139)
The checker currently reports beneath the null dereference dereferences
of undefined value and of label addresses. If we want to add more kinds
of invalid dereferences (or split the existing functionality) it is more
useful to make it separate checkers.
To make this possible the existing checker is split into a
DereferenceModeling part and a NullDereference checker that actually
only switches on the check of null dereference. This is similar
architecture as in MallocChecker and CStringChecker.
The change is almost NFC but a new (modeling) checker is added. If the
NullDereference checker is turned off the found invalid dereferences
will still stop the analysis without emitted warning (this is different
compared to the old behavior).
Added:
Modified:
clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
clang/test/Analysis/analyzer-enabled-checkers.c
clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c
Removed:
################################################################################
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index b34e940682fc5e..1361da46c3c81d 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<HasDocumentation>,
Dependencies<[CallAndMessageModeling]>;
-def DereferenceChecker : Checker<"NullDereference">,
+def DereferenceModeling : Checker<"DereferenceModeling">,
+ HelpText<"General support for dereference related checkers">,
+ Documentation<NotDocumented>,
+ Hidden;
+
+def NullDereferenceChecker : Checker<"NullDereference">,
HelpText<"Check for dereferences of null pointers">,
CheckerOptions<[
CmdLineOption<Boolean,
@@ -215,7 +220,8 @@ def DereferenceChecker : Checker<"NullDereference">,
"true",
Released>
]>,
- Documentation<HasDocumentation>;
+ Documentation<HasDocumentation>,
+ 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 0355eede75eae7..e9e2771c739b60 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -33,12 +33,6 @@ class DereferenceChecker
EventDispatcher<ImplicitNullDerefEvent> > {
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<BugType> BT_Null;
+ std::unique_ptr<BugType> BT_Undef;
+ std::unique_ptr<BugType> 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<DereferenceChecker>();
- Chk->SuppressAddressSpaces = mgr.getAnalyzerOptions().getCheckerBooleanOption(
- mgr.getCurrentCheckerName(), "SuppressAddressSpaces");
+void ento::registerDereferenceModeling(CheckerManager &Mgr) {
+ Mgr.registerChecker<DereferenceChecker>();
+}
+
+bool ento::shouldRegisterDereferenceModeling(const CheckerManager &) {
+ return true;
+}
+
+void ento::registerNullDereferenceChecker(CheckerManager &Mgr) {
+ auto *Chk = Mgr.getChecker<DereferenceChecker>();
+ 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 160e35c77462d1..c70aeb21ab0459 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 0910f030b0f072..faf0a8f19d919e 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
More information about the cfe-commits
mailing list