https://github.com/benedekaibas created 
https://github.com/llvm/llvm-project/pull/200145

I have implemented the checkPostCall function to understand the lifetimebound 
annotations when a parameter is annotated with it. I have generated the 
ExplodedGraph as well and the annotation is present.

This PR is just the very base of the whole implementation of making the 
annotations present in the program state and I do not cover all the cases yet, 
but I just want to see if you have any suggestions for me.

Here is the Compiler Explorer link to the code I have used as a test: 
https://godbolt.org/z/K896aceMf

>From 826dbd7525158bf0946b41ec0f629c235b8238b2 Mon Sep 17 00:00:00 2001
From: benedekaibas <[email protected]>
Date: Thu, 28 May 2026 11:37:49 +0200
Subject: [PATCH] Started implementing the lifetime annotation checker.

---
 .../clang/StaticAnalyzer/Checkers/Checkers.td |  4 +
 .../StaticAnalyzer/Checkers/CMakeLists.txt    |  1 +
 .../Checkers/LifetimeAnnotations.cpp          | 73 +++++++++++++++++++
 3 files changed, 78 insertions(+)
 create mode 100644 clang/lib/StaticAnalyzer/Checkers/LifetimeAnnotations.cpp

diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td 
b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index eca2afbe340a9..85d59fc139728 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -788,6 +788,10 @@ def SmartPtrChecker: Checker<"SmartPtr">,
   Dependencies<[SmartPtrModeling]>,
   Documentation<HasDocumentation>;
 
+def LifetimeAnnotations : Checker<"LifetimeAnnotations">,
+  HelpText<"Check for lifetime violations using lifetime annotations">,
+  Documentation<NotDocumented>;
+
 } // end: "alpha.cplusplus"
 
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt 
b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 8a0621077b977..3f426186189fa 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -55,6 +55,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   IteratorModeling.cpp
   IteratorRangeChecker.cpp
   IvarInvalidationChecker.cpp
+  LifetimeAnnotations.cpp
   LLVMConventionsChecker.cpp
   LocalizationChecker.cpp
   MacOSKeychainAPIChecker.cpp
diff --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeAnnotations.cpp 
b/clang/lib/StaticAnalyzer/Checkers/LifetimeAnnotations.cpp
new file mode 100644
index 0000000000000..54e98b945c7b3
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeAnnotations.cpp
@@ -0,0 +1,73 @@
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <AllocationState.h>
+
+using namespace clang;
+using namespace ento;
+
+REGISTER_MAP_WITH_PROGRAMSTATE(LifetimeBoundMap, const MemRegion *,
+                               const MemRegion *);
+
+class LifetimeAnnotations : public Checker<check::PostCall> {
+public:
+  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+  void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
+                  const char *Sep) const override;
+};
+
+void LifetimeAnnotations::checkPostCall(const CallEvent &Call,
+                                        CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+
+  const auto *MethodDecl = dyn_cast_if_present<CXXMethodDecl>(Call.getDecl());
+
+  if (!MethodDecl)
+    return;
+
+  unsigned LBParamIdx = MethodDecl->getNumParams();
+  for (unsigned i = 0; i < MethodDecl->getNumParams(); i++) {
+    if (MethodDecl->getParamDecl(i)->hasAttr<LifetimeBoundAttr>()) {
+      LBParamIdx = i;
+      break;
+    }
+  }
+  if (LBParamIdx == MethodDecl->getNumParams())
+    return;
+
+  SVal RetVal = Call.getReturnValue();
+  const MemRegion *RetValRegion = RetVal.getAsRegion();
+  if (!RetValRegion)
+    return;
+
+  SVal ArgVal = Call.getArgSVal(LBParamIdx);
+  const MemRegion *ArgValRegion = ArgVal.getAsRegion();
+  if (!ArgValRegion)
+    return;
+
+  State = State->set<LifetimeBoundMap>(RetValRegion, ArgValRegion);
+  C.addTransition(State);
+}
+
+void LifetimeAnnotations::printState(raw_ostream &Out, ProgramStateRef State,
+                                     const char *NL, const char *Sep) const {
+  auto LBTy = State->get<LifetimeBoundMap>();
+
+  if (!LBTy.isEmpty()) {
+    Out << Sep << "LifetimeBound objects: ";
+
+    for (auto I : LBTy) {
+      Out << I.first << " bound to " << I.second << NL;
+    }
+  }
+}
+
+void ento::registerLifetimeAnnotations(CheckerManager &mgr) {
+  mgr.registerChecker<LifetimeAnnotations>();
+}
+
+bool ento::shouldRegisterLifetimeAnnotations(const CheckerManager &mgr) {
+  return true;
+}

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

Reply via email to