Author: Benedek Kaibas
Date: 2026-07-22T22:48:32+02:00
New Revision: 252f31a6893b6a3dcb8b2a404e13933e376bf36b

URL: 
https://github.com/llvm/llvm-project/commit/252f31a6893b6a3dcb8b2a404e13933e376bf36b
DIFF: 
https://github.com/llvm/llvm-project/commit/252f31a6893b6a3dcb8b2a404e13933e376bf36b.diff

LOG: [analyzer] Detect dangling pointers passed to function calls (#211045)

In order to detect if a dangling pointer is passed to a function the
analyzer has to inspect each call argument. For that reason I have
implemented the `checkPostCall` for the `DanglingPtrDeref` checker to
check if an argument passed to a function is dangling. Since
`checkLocation` only catches dereferences and cannot reason about
whether an argument passed to a function is dangling it cannot detect
these type of bugs alone.

Added: 
    

Modified: 
    clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp
    clang/test/Analysis/dangling-ptr-deref.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp 
b/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp
index 781045a4d0654..ff2087e1db933 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp
@@ -3,16 +3,18 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 
 using namespace clang;
 using namespace ento;
 
 namespace {
-class DanglingPtrDeref : public Checker<check::Location> {
+class DanglingPtrDeref : public Checker<check::Location, check::PostCall> {
 public:
   void checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
                      CheckerContext &C) const;
+  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
   void reportUseAfterScope(const MemRegion *Region, ExplodedNode *N,
                            CheckerContext &C) const;
   const BugType BugMsg{this, "ReportDanglingPtrDeref", "LifetimeBound"};
@@ -48,6 +50,22 @@ void DanglingPtrDeref::checkLocation(SVal Loc, bool IsLoad, 
const Stmt *S,
   }
 }
 
+void DanglingPtrDeref::checkPostCall(const CallEvent &Call,
+                                     CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  // Only check calls arguments if it is not inlined by the engine. In case a
+  // function is inlined checkLocation handles any dereference in its body.
+  if (C.wasInlined)
+    return;
+
+  for (unsigned Idx = 0; Idx < Call.getNumArgs(); Idx++) {
+    if (const MemRegion *ArgRegion = Call.getArgSVal(Idx).getAsRegion())
+      if (lifetime_modeling::isDeallocated(State, ArgRegion))
+        if (ExplodedNode *N = C.generateNonFatalErrorNode())
+          reportUseAfterScope(ArgRegion, N, C);
+  }
+}
+
 void DanglingPtrDeref::reportUseAfterScope(const MemRegion *Region,
                                            ExplodedNode *N,
                                            CheckerContext &C) const {

diff  --git a/clang/test/Analysis/dangling-ptr-deref.cpp 
b/clang/test/Analysis/dangling-ptr-deref.cpp
index ad6a9aceb5981..e661eff9ccbb6 100644
--- a/clang/test/Analysis/dangling-ptr-deref.cpp
+++ b/clang/test/Analysis/dangling-ptr-deref.cpp
@@ -84,3 +84,31 @@ void test_case_seven() {
   // expected-warning@-1 {{Use of 'i' after its lifetime ended}}
   // expected-note@-2    {{Use of 'i' after its lifetime ended}}
 }
+
+void passing_dangling_ptr_to_opaque_func() {
+  int *ptr = nullptr;
+  {
+    int num = 5;
+    ptr = &num;
+  }
+  // expected-note@-1 {{'num' is destroyed here}}
+  escape(ptr);
+  // expected-warning@-1 {{Use of 'num' after its lifetime ended}}
+  // expected-note@-2    {{Use of 'num' after its lifetime ended}}
+}
+
+int deref_param(int *p) { return *p; }
+// expected-warning@-1 {{Use of 'num' after its lifetime ended}}
+// expected-note@-2    {{Use of 'num' after its lifetime ended}}
+
+void inlined_callee_single_report() {
+  int *ptr = nullptr;
+  {
+    int num = 5;
+    ptr = &num;
+  }
+  // expected-note@-1 {{'num' is destroyed here}}
+  int r = deref_param(ptr);
+  // expected-note@-1 {{Calling 'deref_param'}}
+  (void)r;
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to