[clang] [clang][docs] Add documentation for the DanglingPtrDeref checker (PR #216688)
Benedek Kaibas via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 26 04:53:50 PDT 2026
https://github.com/benedekaibas updated https://github.com/llvm/llvm-project/pull/216688
>From 2938322915465c7ff19d2b5a04a6e5b5940f87ee Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Thu, 20 Aug 2026 16:21:38 +0200
Subject: [PATCH 1/5] Include the documentation in the checkers.md that
replaced checkers.rst.
---
clang/docs/analyzer/checkers.md | 67 +++++++++++++++++++
.../clang/StaticAnalyzer/Checkers/Checkers.td | 20 +++---
clang/test/Analysis/dangling-ptr-deref.cpp | 2 +-
3 files changed, 78 insertions(+), 11 deletions(-)
diff --git a/clang/docs/analyzer/checkers.md b/clang/docs/analyzer/checkers.md
index 3b54c3a359c3f..cfe15eef9326c 100644
--- a/clang/docs/analyzer/checkers.md
+++ b/clang/docs/analyzer/checkers.md
@@ -3300,6 +3300,73 @@ remove the const qualifier from the original declaration or use a mutable copy.
### alpha.cplusplus
+(alpha-cplusplus-danglingptrderef)=
+
+#### alpha.cplusplus.DanglingPtrDeref (C++)
+
+Check for dereferences of pointers that refer to an object whose
+lifetime has already ended. Such a pointer is dangling. The checker
+reports it when it is dereferenced and when it is passed to a function.
+This includes a dereference in a return statement. A return statement that
+does not dereference the pointer does not lead to a report. Such a case is
+reported by the {ref}`core-StackAddressEscape` checker.
+
+Each object is reported at most once on an execution path. If the same dangling
+pointer is used several times then only the first use is reported.
+
+```cpp
+void test_deref() {
+ int *ptr = 0;
+ {
+ int num = 5;
+ ptr = #
+ } // note: 'num' is destroyed here
+ *ptr = 6; // warn: use of 'num' after its lifetime ended
+}
+
+int test_deref_in_return() {
+ int *ptr = 0;
+ {
+ int num = 5;
+ ptr = #
+ } // note: 'num' is destroyed here
+ return *ptr; // warn: use of 'num' after its lifetime ended
+}
+
+void test_in_scope() {
+ int num = 5;
+ int *ptr = #
+ {
+ *ptr = 6; // no warning, 'num' is still in scope
+ }
+}
+```
+
+The `-analyzer-config cfg-lifetime=true` option is a prerequisite for these
+reports. Without it the checker does not report anything and no error is emitted
+by the analyzer.
+
+**Limitations**
+
+If the analyzer cannot analyze the body of the called function, for example because
+its definition is not available in the given translation unit, then a dangling
+pointer passed to it is reported even if the function would never dereference
+it. This can lead to false positives.
+
+```cpp
+// The definition of the function is not available that is why the analyzer
+// assumes the pointer is used.
+int is_null(int *p);
+
+void argument_example() {
+ int *ptr = 0;
+ {
+ int num = 5;
+ ptr = #
+ }
+ is_null(ptr); // false positive: the pointer is compared, not dereferenced
+}
+```
(alpha-cplusplus-deletewithnonvirtualdtor)=
#### alpha.cplusplus.DeleteWithNonVirtualDtor (C++)
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index b6b3857dc7b35..3e6e7c9ea13d5 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -289,6 +289,16 @@ def StdVariantChecker : Checker<"StdVariant">,
HelpText<"Check for bad type access for std::variant.">,
Documentation<HasDocumentation>;
+def LifetimeModeling : Checker<"LifetimeModeling">,
+ HelpText<"Model lifetime annotations for other checkers">,
+ Documentation<NotDocumented>,
+ Hidden;
+
+def DanglingPtrDeref : Checker<"DanglingPtrDeref">,
+ HelpText<"Check for dereferences of a dangling pointer">,
+ Dependencies<[LifetimeModeling]>,
+ Documentation<HasDocumentation>;
+
} // end "alpha.core"
//===----------------------------------------------------------------------===//
@@ -802,22 +812,12 @@ def SmartPtrChecker: Checker<"SmartPtr">,
Dependencies<[SmartPtrModeling]>,
Documentation<HasDocumentation>;
-def LifetimeModeling : Checker<"LifetimeModeling">,
- HelpText<"Model lifetime annotations for other checkers">,
- Documentation<NotDocumented>,
- Hidden;
-
def UseAfterLifetimeEnd : Checker<"UseAfterLifetimeEnd">,
HelpText<"Check for uses of references or pointers that "
"outlive their bound object">,
Dependencies<[LifetimeModeling]>,
Documentation<NotDocumented>;
-def DanglingPtrDeref : Checker<"DanglingPtrDeref">,
- HelpText<"Check for dereferences of a dangling pointer">,
- Dependencies<[LifetimeModeling]>,
- Documentation<NotDocumented>;
-
} // end: "alpha.cplusplus"
//===----------------------------------------------------------------------===//
diff --git a/clang/test/Analysis/dangling-ptr-deref.cpp b/clang/test/Analysis/dangling-ptr-deref.cpp
index 55dd5eadc8ad0..8572b6416f150 100644
--- a/clang/test/Analysis/dangling-ptr-deref.cpp
+++ b/clang/test/Analysis/dangling-ptr-deref.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.DanglingPtrDeref \
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.DanglingPtrDeref \
// RUN: -analyzer-config cfg-lifetime=true -analyzer-output=text -verify %s
void test_case_one() {
>From 628d1f5f49b228c67a8fcb25615db0364cd76b3f Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Mon, 17 Aug 2026 15:05:13 +0200
Subject: [PATCH 2/5] Revert move to alpha.core.
---
.../clang/StaticAnalyzer/Checkers/Checkers.td | 20 +++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 3e6e7c9ea13d5..b1b87dc883ed6 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -289,16 +289,6 @@ def StdVariantChecker : Checker<"StdVariant">,
HelpText<"Check for bad type access for std::variant.">,
Documentation<HasDocumentation>;
-def LifetimeModeling : Checker<"LifetimeModeling">,
- HelpText<"Model lifetime annotations for other checkers">,
- Documentation<NotDocumented>,
- Hidden;
-
-def DanglingPtrDeref : Checker<"DanglingPtrDeref">,
- HelpText<"Check for dereferences of a dangling pointer">,
- Dependencies<[LifetimeModeling]>,
- Documentation<HasDocumentation>;
-
} // end "alpha.core"
//===----------------------------------------------------------------------===//
@@ -812,12 +802,22 @@ def SmartPtrChecker: Checker<"SmartPtr">,
Dependencies<[SmartPtrModeling]>,
Documentation<HasDocumentation>;
+def LifetimeModeling : Checker<"LifetimeModeling">,
+ HelpText<"Model lifetime annotations for other checkers">,
+ Documentation<NotDocumented>,
+ Hidden;
+
def UseAfterLifetimeEnd : Checker<"UseAfterLifetimeEnd">,
HelpText<"Check for uses of references or pointers that "
"outlive their bound object">,
Dependencies<[LifetimeModeling]>,
Documentation<NotDocumented>;
+def DanglingPtrDeref : Checker<"DanglingPtrDeref">,
+ HelpText<"Check for dereferences of a dangling pointer">,
+ Dependencies<[LifetimeModeling]>,
+ Documentation<HasDocumentation>;
+
} // end: "alpha.cplusplus"
//===----------------------------------------------------------------------===//
>From f5aff877f4242f4224515bda4ee5e513123f2118 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Mon, 17 Aug 2026 15:27:54 +0200
Subject: [PATCH 3/5] Correct RUN lines for the DanglingPtrDeref test suite.
---
clang/test/Analysis/dangling-ptr-deref.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/Analysis/dangling-ptr-deref.cpp b/clang/test/Analysis/dangling-ptr-deref.cpp
index 8572b6416f150..55dd5eadc8ad0 100644
--- a/clang/test/Analysis/dangling-ptr-deref.cpp
+++ b/clang/test/Analysis/dangling-ptr-deref.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.DanglingPtrDeref \
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.DanglingPtrDeref \
// RUN: -analyzer-config cfg-lifetime=true -analyzer-output=text -verify %s
void test_case_one() {
>From 737f1a3d446b3e420b0481aae27b26d1986a2d14 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Wed, 26 Aug 2026 13:40:53 +0200
Subject: [PATCH 4/5] Remove test and text for dereference in return statement.
---
clang/docs/analyzer/checkers.md | 14 ++------------
1 file changed, 2 insertions(+), 12 deletions(-)
diff --git a/clang/docs/analyzer/checkers.md b/clang/docs/analyzer/checkers.md
index cfe15eef9326c..41c040d229fff 100644
--- a/clang/docs/analyzer/checkers.md
+++ b/clang/docs/analyzer/checkers.md
@@ -3307,9 +3307,8 @@ remove the const qualifier from the original declaration or use a mutable copy.
Check for dereferences of pointers that refer to an object whose
lifetime has already ended. Such a pointer is dangling. The checker
reports it when it is dereferenced and when it is passed to a function.
-This includes a dereference in a return statement. A return statement that
-does not dereference the pointer does not lead to a report. Such a case is
-reported by the {ref}`core-StackAddressEscape` checker.
+A return statement that does not dereference the pointer does not lead to a report.
+Such a case is reported by the {ref}`core-StackAddressEscape` checker.
Each object is reported at most once on an execution path. If the same dangling
pointer is used several times then only the first use is reported.
@@ -3324,15 +3323,6 @@ void test_deref() {
*ptr = 6; // warn: use of 'num' after its lifetime ended
}
-int test_deref_in_return() {
- int *ptr = 0;
- {
- int num = 5;
- ptr = #
- } // note: 'num' is destroyed here
- return *ptr; // warn: use of 'num' after its lifetime ended
-}
-
void test_in_scope() {
int num = 5;
int *ptr = #
>From 0181e057fbd2e3fe44f3a20be311a14390761ced Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Wed, 26 Aug 2026 13:53:30 +0200
Subject: [PATCH 5/5] Explanation for suppressing the fp report.
---
clang/docs/analyzer/checkers.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/clang/docs/analyzer/checkers.md b/clang/docs/analyzer/checkers.md
index 41c040d229fff..81c91ccffb14f 100644
--- a/clang/docs/analyzer/checkers.md
+++ b/clang/docs/analyzer/checkers.md
@@ -3311,7 +3311,9 @@ A return statement that does not dereference the pointer does not lead to a repo
Such a case is reported by the {ref}`core-StackAddressEscape` checker.
Each object is reported at most once on an execution path. If the same dangling
-pointer is used several times then only the first use is reported.
+pointer is used several times then only the first use is reported. Setting the pointer
+to null when the object goes out of scope avoids the dangling pointer and suppresses
+the report.
```cpp
void test_deref() {
More information about the cfe-commits
mailing list