[clang] [analyzer] Conversion to CheckerFamily: StackAddrEscapeChecker (PR #151136)
DonĂ¡t Nagy via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 30 04:25:17 PDT 2025
https://github.com/NagyDonat updated https://github.com/llvm/llvm-project/pull/151136
>From 2ca9d38d8aa41108cc2ab26edf1a12e4dd7177bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.nagy at ericsson.com>
Date: Tue, 29 Jul 2025 14:14:33 +0200
Subject: [PATCH 1/2] [analyzer] Conversion to CheckerFamily:
StackAddrEscapeChecker
This commit converts the class StackAddrEscapeChecker to the checker
family framework and slightly simplifies the implementation.
This commit is almost NFC, the only technically "functional" change is
that it removes the hidden modeling checker `core.StackAddrEscapeBase`
which was only relevant as an implementation detail of the old checker
registration procedure.
---
.../clang/StaticAnalyzer/Checkers/Checkers.td | 23 +++---
.../Checkers/StackAddrEscapeChecker.cpp | 77 +++++++------------
.../test/Analysis/analyzer-enabled-checkers.c | 1 -
...c-library-functions-arg-enabled-checkers.c | 1 -
4 files changed, 36 insertions(+), 66 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 6225977e980cc..ebadc45783a37 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -233,15 +233,11 @@ def UndefResultChecker : Checker<"UndefinedBinaryOperatorResult">,
HelpText<"Check for undefined results of binary operators">,
Documentation<HasDocumentation>;
-def StackAddrEscapeBase : Checker<"StackAddrEscapeBase">,
- HelpText<"Generate information about stack address escapes.">,
- Documentation<NotDocumented>,
- Hidden;
-
-def StackAddrEscapeChecker : Checker<"StackAddressEscape">,
- HelpText<"Check that addresses to stack memory do not escape the function">,
- Dependencies<[StackAddrEscapeBase]>,
- Documentation<HasDocumentation>;
+def StackAddrEscapeChecker
+ : Checker<"StackAddressEscape">,
+ HelpText<
+ "Check that addresses to stack memory do not escape the function">,
+ Documentation<HasDocumentation>;
def DynamicTypePropagation : Checker<"DynamicTypePropagation">,
HelpText<"Generate dynamic type information">,
@@ -295,10 +291,11 @@ def DynamicTypeChecker
Dependencies<[DynamicTypePropagation]>,
Documentation<HasDocumentation>;
-def StackAddrAsyncEscapeChecker : Checker<"StackAddressAsyncEscape">,
- HelpText<"Check that addresses to stack memory do not escape the function">,
- Dependencies<[StackAddrEscapeBase]>,
- Documentation<HasDocumentation>;
+def StackAddrAsyncEscapeChecker
+ : Checker<"StackAddressAsyncEscape">,
+ HelpText<
+ "Check that addresses to stack memory do not escape the function">,
+ Documentation<HasDocumentation>;
def PthreadLockBase : Checker<"PthreadLockBase">,
HelpText<"Helper registering multiple checks.">,
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index a63497c593e5d..37431f8541d43 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -28,23 +28,20 @@ using namespace ento;
namespace {
class StackAddrEscapeChecker
- : public Checker<check::PreCall, check::PreStmt<ReturnStmt>,
- check::EndFunction> {
+ : public CheckerFamily<check::PreCall, check::PreStmt<ReturnStmt>,
+ check::EndFunction> {
mutable IdentifierInfo *dispatch_semaphore_tII = nullptr;
- mutable std::unique_ptr<BugType> BT_stackleak;
- mutable std::unique_ptr<BugType> BT_returnstack;
- mutable std::unique_ptr<BugType> BT_capturedstackasync;
- mutable std::unique_ptr<BugType> BT_capturedstackret;
public:
- enum CheckKind {
- CK_StackAddrEscapeChecker,
- CK_StackAddrAsyncEscapeChecker,
- CK_NumCheckKinds
- };
+ StringRef getDebugTag() const override { return "StackAddrEscapeChecker"; }
- bool ChecksEnabled[CK_NumCheckKinds] = {false};
- CheckerNameRef CheckNames[CK_NumCheckKinds];
+ CheckerFrontend StackAddrEscape, StackAddrAsyncEscape;
+ const BugType StackLeak{&StackAddrEscape,
+ "Stack address leaks outside of stack frame"};
+ const BugType ReturnStack{&StackAddrEscape,
+ "Return of address to stack-allocated memory"};
+ const BugType CapturedStackAsync{
+ &StackAddrAsyncEscape, "Address of stack-allocated memory is captured"};
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
@@ -170,10 +167,6 @@ void StackAddrEscapeChecker::EmitReturnLeakError(CheckerContext &C,
ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N)
return;
- if (!BT_returnstack)
- BT_returnstack = std::make_unique<BugType>(
- CheckNames[CK_StackAddrEscapeChecker],
- "Return of address to stack-allocated memory");
// Generate a report for this bug.
SmallString<128> buf;
@@ -184,7 +177,7 @@ void StackAddrEscapeChecker::EmitReturnLeakError(CheckerContext &C,
EmitReturnedAsPartOfError(os, C.getSVal(RetE), R);
auto report =
- std::make_unique<PathSensitiveBugReport>(*BT_returnstack, os.str(), N);
+ std::make_unique<PathSensitiveBugReport>(ReturnStack, os.str(), N);
report->addRange(RetE->getSourceRange());
if (range.isValid())
report->addRange(range);
@@ -215,16 +208,12 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N)
continue;
- if (!BT_capturedstackasync)
- BT_capturedstackasync = std::make_unique<BugType>(
- CheckNames[CK_StackAddrAsyncEscapeChecker],
- "Address of stack-allocated memory is captured");
SmallString<128> Buf;
llvm::raw_svector_ostream Out(Buf);
SourceRange Range = genName(Out, Region, C.getASTContext());
Out << " is captured by an asynchronously-executed block";
- auto Report = std::make_unique<PathSensitiveBugReport>(
- *BT_capturedstackasync, Out.str(), N);
+ auto Report = std::make_unique<PathSensitiveBugReport>(CapturedStackAsync,
+ Out.str(), N);
if (Range.isValid())
Report->addRange(Range);
C.emitReport(std::move(Report));
@@ -233,7 +222,7 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
void StackAddrEscapeChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
- if (!ChecksEnabled[CK_StackAddrAsyncEscapeChecker])
+ if (!StackAddrAsyncEscape.isEnabled())
return;
if (!Call.isGlobalCFunction("dispatch_after") &&
!Call.isGlobalCFunction("dispatch_async"))
@@ -357,7 +346,7 @@ FindEscapingStackRegions(CheckerContext &C, const Expr *RetE, SVal RetVal) {
void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
CheckerContext &C) const {
- if (!ChecksEnabled[CK_StackAddrEscapeChecker])
+ if (!StackAddrEscape.isEnabled())
return;
const Expr *RetE = RS->getRetValue();
@@ -456,7 +445,7 @@ static bool isInvalidatedSymbolRegion(const MemRegion *Region) {
void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
CheckerContext &Ctx) const {
- if (!ChecksEnabled[CK_StackAddrEscapeChecker])
+ if (!StackAddrEscape.isEnabled())
return;
ExplodedNode *Node = Ctx.getPredecessor();
@@ -581,11 +570,6 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
if (!N)
return;
- if (!BT_stackleak)
- BT_stackleak =
- std::make_unique<BugType>(CheckNames[CK_StackAddrEscapeChecker],
- "Stack address leaks outside of stack frame");
-
for (const auto &P : Cb.V) {
const MemRegion *Referrer = P.first->getBaseRegion();
const MemRegion *Referred = P.second;
@@ -604,7 +588,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
Out << " is still referred to by a temporary object on the stack"
<< CommonSuffix;
auto Report =
- std::make_unique<PathSensitiveBugReport>(*BT_stackleak, Out.str(), N);
+ std::make_unique<PathSensitiveBugReport>(StackLeak, Out.str(), N);
if (Range.isValid())
Report->addRange(Range);
Ctx.emitReport(std::move(Report));
@@ -618,7 +602,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
Out << " is still referred to by the " << *ReferrerVariable << CommonSuffix;
auto Report =
- std::make_unique<PathSensitiveBugReport>(*BT_stackleak, Out.str(), N);
+ std::make_unique<PathSensitiveBugReport>(StackLeak, Out.str(), N);
if (Range.isValid())
Report->addRange(Range);
@@ -626,23 +610,14 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
}
}
-void ento::registerStackAddrEscapeBase(CheckerManager &mgr) {
- mgr.registerChecker<StackAddrEscapeChecker>();
-}
-
-bool ento::shouldRegisterStackAddrEscapeBase(const CheckerManager &mgr) {
- return true;
-}
-
-#define REGISTER_CHECKER(name) \
- void ento::register##name(CheckerManager &Mgr) { \
- StackAddrEscapeChecker *Chk = Mgr.getChecker<StackAddrEscapeChecker>(); \
- Chk->ChecksEnabled[StackAddrEscapeChecker::CK_##name] = true; \
- Chk->CheckNames[StackAddrEscapeChecker::CK_##name] = \
- Mgr.getCurrentCheckerName(); \
+#define REGISTER_CHECKER(NAME) \
+ void ento::register##NAME##Checker(CheckerManager &Mgr) { \
+ Mgr.getChecker<StackAddrEscapeChecker>()->NAME.enable(Mgr); \
} \
\
- bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
+ bool ento::shouldRegister##NAME##Checker(const CheckerManager &) { \
+ return true; \
+ }
-REGISTER_CHECKER(StackAddrEscapeChecker)
-REGISTER_CHECKER(StackAddrAsyncEscapeChecker)
+REGISTER_CHECKER(StackAddrEscape)
+REGISTER_CHECKER(StackAddrAsyncEscape)
diff --git a/clang/test/Analysis/analyzer-enabled-checkers.c b/clang/test/Analysis/analyzer-enabled-checkers.c
index a632b70fa843a..32afcf30646bf 100644
--- a/clang/test/Analysis/analyzer-enabled-checkers.c
+++ b/clang/test/Analysis/analyzer-enabled-checkers.c
@@ -20,7 +20,6 @@
// CHECK-NEXT: core.NonNullParamChecker
// CHECK-NEXT: core.NonnilStringConstants
// CHECK-NEXT: core.NullDereference
-// CHECK-NEXT: core.StackAddrEscapeBase
// CHECK-NEXT: core.StackAddressEscape
// CHECK-NEXT: core.UndefinedBinaryOperatorResult
// CHECK-NEXT: core.VLASize
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 b388c312ba957..77fa037259440 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
@@ -28,7 +28,6 @@
// CHECK-NEXT: core.NonNullParamChecker
// CHECK-NEXT: core.NonnilStringConstants
// CHECK-NEXT: core.NullDereference
-// CHECK-NEXT: core.StackAddrEscapeBase
// CHECK-NEXT: core.StackAddressEscape
// CHECK-NEXT: core.UndefinedBinaryOperatorResult
// CHECK-NEXT: core.VLASize
>From d9cf9ed109bc3c208b77b25d74853b4cef8c715f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.nagy at ericsson.com>
Date: Wed, 30 Jul 2025 13:25:02 +0200
Subject: [PATCH 2/2] Split declarations
---
clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 37431f8541d43..019e81f91400d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -35,7 +35,9 @@ class StackAddrEscapeChecker
public:
StringRef getDebugTag() const override { return "StackAddrEscapeChecker"; }
- CheckerFrontend StackAddrEscape, StackAddrAsyncEscape;
+ CheckerFrontend StackAddrEscape;
+ CheckerFrontend StackAddrAsyncEscape;
+
const BugType StackLeak{&StackAddrEscape,
"Stack address leaks outside of stack frame"};
const BugType ReturnStack{&StackAddrEscape,
More information about the cfe-commits
mailing list