[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

Denis Mikhailov via cfe-commits cfe-commits at lists.llvm.org
Mon Jun 23 06:34:43 PDT 2025


================
@@ -0,0 +1,163 @@
+.. title:: clang-tidy - bugprone-null-check-after-dereference
+
+bugprone-null-check-after-dereference
+=====================================
+
+.. note::
+
+   This check uses a flow-sensitive static analysis to produce its
+   results. Therefore, it may be more resource intensive (RAM, CPU) than the
+   average Clang-tidy check.
+
+Identifies redundant pointer null-checks, by finding cases where the pointer
+cannot be null at the location of the null-check.
+
+Redundant null-checks can signal faulty assumptions about the current value of
+a pointer at different points in the program. Either the null-check is
+redundant, or there could be a null-pointer dereference earlier in the program.
+
+.. code-block:: c++
+
+   int f(int *ptr) {
+     *ptr = 20; // note: one of the locations where the pointer's value cannot be null
+     // ...
+     if (ptr) { // bugprone: pointer is checked even though it cannot be null at this point
+       return *ptr;
+     }
+     return 0;
+   }
+
+Supported pointer operations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Pointer null-checks
+-------------------
+
+The check currently supports null-checks on pointers that use
+``operator bool``, such as when being used as the condition
+for an ``if`` statement. It also supports comparisons such as ``!= nullptr``, and
+``== other_ptr``.
+
+.. code-block:: c++
+
+   int f(int *ptr) {
+     if (ptr) {
+       if (ptr) { // bugprone: pointer is re-checked after its null-ness is already checked.
+         return *ptr;
+       }
+
+       return ptr ? *ptr : 0; // bugprone: pointer is re-checked after its null-ness is already checked.
+     }
+     return 0;
+   }
+
+Pointer dereferences
+--------------------
+
+Pointer star- and arrow-dereferences are supported.
+
+.. code-block:: c++
+
+   struct S {
+     int val;
+   };
+
+   void f(int *ptr, S *wrapper) {
+     *ptr = 20;
+     wrapper->val = 15;
+   }
+
+Null-pointer and other value assignments
+----------------------------------------
+
+The check supports assigning various values to pointers, making them *null*
+or *non-null*. The check also supports passing pointers of a pointer to
+external functions.
+
+.. code-block:: c++
+
+   extern int *external();
+   extern void refresh(int **ptr_ptr);
+   
+   int f() {
+     int *ptr_null = nullptr;
+     if (ptr_null) { // bugprone: pointer is checked where it cannot be non-null.
+       return *ptr_null;
+     }
+
+     int *ptr = external();
+     if (ptr) { // safe: external() could return either nullable or nonnull pointers.
+       return *ptr;
+     }
+
+     int *ptr2 = external();
+     *ptr2 = 20;
+     refresh(&ptr2);
+     if (ptr2) { // safe: pointer could be changed by refresh().
+       return *ptr2;
+     }
+     return 0;
+   }
+
+Limitations
+~~~~~~~~~~~
+
+The check only supports C++ due to limitations in the data-flow framework.
+
+The annotations ``_Nullable`` and ``_Nonnull`` are not supported.
+
+.. code-block:: c++
+
+   extern int *_nonnull external_nonnull();
+
+   int annotations() {
+     int *ptr = external_nonnull();
+
+     return ptr ? *ptr : 0; // false-negative: pointer is known to be non-null.
+   }
+
+Function calls taking a pointer value as a reference or a pointer-to-pointer are
+not supported.
+
+.. code-block:: c++
+
+   extern int *external();
+   extern void refresh_ref(int *&ptr);
+   extern void refresh_ptr(int **ptr);
+
+   int extern_ref() {
+     int *ptr = external();
+     *ptr = 20;
+
+     refresh_ref(ptr);
+     refresh_ptr(&ptr);
+
+     return ptr ? *ptr : 0; // false-positive: pointer could be changed by refresh_ref().
+   }
+
+Note tags are currently appended to a single location, even if all paths ensure
+a pointer is not null.
+
+.. code-block:: c++
+
+   int branches(int *p, bool b) {
+     if (b) {
+       *p = 42; // true-positive: note-tag appended here
+     } else {
+       *p = 20; // false-positive: note tag not appended here
+     }
+
+     return ptr ? *ptr : 0;
----------------
denzor200 wrote:

`return p ? *p : 0;` ?

https://github.com/llvm/llvm-project/pull/84166


More information about the cfe-commits mailing list