https://github.com/benedekaibas updated https://github.com/llvm/llvm-project/pull/216688
>From bd3d24461879a728a3b1b245181f6d0271349044 Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Mon, 17 Aug 2026 12:28:23 +0200 Subject: [PATCH 1/7] [analyzer][docs] Add documentation for the DanglingPtrDeref checker --- clang/docs/analyzer/checkers.rst | 55 +++++++++++++++++++ .../clang/StaticAnalyzer/Checkers/Checkers.td | 20 +++---- clang/test/Analysis/dangling-ptr-deref.cpp | 2 +- 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 1f6b974d5ca7a..5d43579a09eb6 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -3248,6 +3248,61 @@ Loss of sign/precision in implicit conversions. short X = A; // warn (loss of precision) } +.. _alpha-core-DanglingPtrDeref: + +alpha.core.DanglingPtrDeref (C, 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. + +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. + +.. code-block:: 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 + } + + void test_in_scope() { + int num = 5; + int *ptr = # + { + *ptr = 6; // no warning, 'num' is still in scope + } + } + +The checker requires end-of-lifetime information from the CFG. It is enabled +with the ``-analyzer-config cfg-lifetime=true`` option. + +**Limitations** + +If the analyzer does not inline 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. + +.. code-block:: 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-core-DynamicTypeChecker: alpha.core.DynamicTypeChecker (ObjC) 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 0ad17fcca72501a55332c566cf57524bf079f96c Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Mon, 17 Aug 2026 15:05:13 +0200 Subject: [PATCH 2/7] 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 1d887d2031bc8bd1c7dc4be8ea60a48c558b5f9e Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Mon, 17 Aug 2026 15:13:42 +0200 Subject: [PATCH 3/7] Move the DanglingPtrDeref checker to alpha.cplusplus. --- clang/docs/analyzer/checkers.rst | 110 +++++++++++++++---------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 5d43579a09eb6..e89e96a1443e8 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -3248,61 +3248,6 @@ Loss of sign/precision in implicit conversions. short X = A; // warn (loss of precision) } -.. _alpha-core-DanglingPtrDeref: - -alpha.core.DanglingPtrDeref (C, 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. - -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. - -.. code-block:: 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 - } - - void test_in_scope() { - int num = 5; - int *ptr = # - { - *ptr = 6; // no warning, 'num' is still in scope - } - } - -The checker requires end-of-lifetime information from the CFG. It is enabled -with the ``-analyzer-config cfg-lifetime=true`` option. - -**Limitations** - -If the analyzer does not inline 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. - -.. code-block:: 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-core-DynamicTypeChecker: alpha.core.DynamicTypeChecker (ObjC) @@ -3406,6 +3351,61 @@ 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. + +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. + +.. code-block:: 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 + } + + void test_in_scope() { + int num = 5; + int *ptr = # + { + *ptr = 6; // no warning, 'num' is still in scope + } + } + +The checker requires end-of-lifetime information from the CFG. It is enabled +with the ``-analyzer-config cfg-lifetime=true`` option. + +**Limitations** + +If the analyzer does not inline 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. + +.. code-block:: 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++) >From 1158032031ed1802324f391eaf4601aca89fbc9d Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Mon, 17 Aug 2026 15:26:20 +0200 Subject: [PATCH 4/7] Add cleaner explanation on cfg lifetime ends. --- clang/docs/analyzer/checkers.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index e89e96a1443e8..2af37446d77d5 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -3354,7 +3354,7 @@ 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. @@ -3381,8 +3381,9 @@ pointer is used several times then only the first use is reported. } } -The checker requires end-of-lifetime information from the CFG. It is enabled -with the ``-analyzer-config cfg-lifetime=true`` option. +End-of-lifetime information is not included in the CFG by default. Without it +the checker does not report anything and no error is emitted by the analyzer. +Use the ``-analyzer-config cfg-lifetime=true`` option to include it. **Limitations** >From 21ea0e63c75ed39e6e7f9398d94b05c1259fdb10 Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Mon, 17 Aug 2026 15:27:54 +0200 Subject: [PATCH 5/7] 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 4f0d29983a2af8b32c565ed87771c895d725e95f Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Wed, 19 Aug 2026 14:45:20 +0200 Subject: [PATCH 6/7] Add new example for dereference in return statement. --- clang/docs/analyzer/checkers.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 2af37446d77d5..0cb7c6365f4f7 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -3358,6 +3358,7 @@ 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. 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. @@ -3373,6 +3374,15 @@ pointer is used several times then only the first use is reported. *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 3cc45b4d6a5771a7257dbc793da01f18289daf27 Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Wed, 19 Aug 2026 14:55:17 +0200 Subject: [PATCH 7/7] Reword the cfg-lifetime option text. --- clang/docs/analyzer/checkers.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 0cb7c6365f4f7..7ff7199048dc0 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -3358,7 +3358,9 @@ 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. +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. @@ -3391,9 +3393,9 @@ pointer is used several times then only the first use is reported. } } -End-of-lifetime information is not included in the CFG by default. Without it -the checker does not report anything and no error is emitted by the analyzer. -Use the ``-analyzer-config cfg-lifetime=true`` option to include it. +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** _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
