[clang] [LifetimeSafety] Implement a basic use-after-free diagnostic (PR #149731)

Yitzhak Mandelbaum via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 31 09:40:55 PDT 2025


================
@@ -0,0 +1,263 @@
+// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -verify %s
+
+struct MyObj {
+  int id;
+  ~MyObj() {}  // Non-trivial destructor
+  MyObj operator+(MyObj);
+};
+
+//===----------------------------------------------------------------------===//
+// Basic Definite Use-After-Free (-W...permissive)
+// These are cases where the pointer is guaranteed to be dangling at the use site.
+//===----------------------------------------------------------------------===//
+
+void definite_simple_case() {
+  MyObj* p;
+  {
+    MyObj s;
+    p = &s;     // expected-warning {{object whose reference is captured does not live long enough}}
+  }             // expected-note {{destroyed here}}
+  (void)*p;     // expected-note {{later used here}}
+}
+
+void no_use_no_error() {
+  MyObj* p;
+  {
+    MyObj s;
+    p = &s;
+  }
+}
+
+void definite_pointer_chain() {
+  MyObj* p;
+  MyObj* q;
+  {
+    MyObj s;
+    p = &s;     // expected-warning {{does not live long enough}}
+    q = p;
+  }             // expected-note {{destroyed here}}
+  (void)*q;     // expected-note {{later used here}}
+}
+
+void definite_multiple_uses_one_warning() {
+  MyObj* p;
+  {
+    MyObj s;
+    p = &s;     // expected-warning {{does not live long enough}}
+  }             // expected-note {{destroyed here}}
+  (void)*p;     // expected-note {{later used here}}
+  // No second warning for the same loan.
+  p->id = 1;
+  MyObj* q = p;
+  (void)*q;
+}
+
+void definite_multiple_pointers() {
+  MyObj *p, *q, *r;
+  {
+    MyObj s;
+    p = &s;     // expected-warning {{does not live long enough}}
+    q = &s;     // expected-warning {{does not live long enough}}
+    r = &s;     // expected-warning {{does not live long enough}}
+  }             // expected-note 3 {{destroyed here}}
+  (void)*p;     // expected-note {{later used here}}
+  (void)*q;     // expected-note {{later used here}}
+  (void)*r;     // expected-note {{later used here}}
+}
+
+void definite_single_pointer_multiple_loans(bool cond) {
+  MyObj *p;
+  if (cond){
+    MyObj s;
+    p = &s;     // expected-warning {{does not live long enough}}
+  }             // expected-note {{destroyed here}}
+  else {
+    MyObj t;
+    p = &t;     // expected-warning {{does not live long enough}}
+  }             // expected-note {{destroyed here}}
+  (void)*p;     // expected-note 2  {{later used here}}
+}
+
+
+//===----------------------------------------------------------------------===//
+// Potential (Maybe) Use-After-Free (-W...strict)
+// These are cases where the pointer *may* become dangling, depending on the path taken.
+//===----------------------------------------------------------------------===//
+
+void potential_if_branch(bool cond) {
----------------
ymand wrote:

Why is this only in strict mode? As long as `cond` is satisfiable (not dead code), we have a safety violation.

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


More information about the cfe-commits mailing list