Skip to content

Conversation

@kashika0112
Copy link
Contributor

@kashika0112 kashika0112 commented Dec 8, 2025

Adding Annotation Inference in Lifetime Analysis.

This PR implicitly adds lifetime bound annotations to the AST which is then used by functions which are parsed later to detect UARs etc. Example:

std::string_view f1(std::string_view a) {
  return a;
}

std::string_view f2(std::string_view a) {
  return f1(a);
}

std::string_view ff(std::string_view a) {
  std::string stack = "something on stack";
  return f2(stack); // warning: address of stack memory is returned
}

Note:

  1. We only add lifetime bound annotations to the functions being analyzed currently.
  2. Currently, both annotation suggestion and inference work simultaneously. This can be modified based on requirements.
  3. The current approach works given that functions are already present in the correct order (callee-before-caller). For not so ideal cases, we can create a CallGraph prior to calling the analysis. This can be done in the next PR.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:analysis clang:temporal-safety Issue/FR relating to the lifetime analysis in Clang (-Wdangling, -Wreturn-local-addr) labels Dec 8, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 8, 2025

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-temporal-safety

Author: Kashika Akhouri (kashika0112)

Changes

Adding Annotation Inference in Lifetime Analysis.

This PR implicitly adds lifetime bound annotations to the AST which is then used by functions which are parsed later to detect UARs etc. Example:

std::string_view f1(std::string_view a) {
  return a;
}

std::string_view f2(std::string_view a) {
  return f1(a);
}

std::string_view ff(std::string_view a) {
  std::string stack = "something on stack";
  return f2(stack); // warning: return-stack-addr
}

Note:

  1. We only add lifetime bound annotations to the functions being analyzed currently.
  2. Currently, both annotation suggestion and inference work simultaneously. This can be modified based on requirements.
  3. The current approach works given that functions are already present in the correct order (callee-before-caller). For not so ideal cases, we can create a CallGraph prior to calling the analysis. This can be done in the next PR.

Full diff: https://github.com/llvm/llvm-project/pull/171081.diff

3 Files Affected:

  • (modified) clang/lib/Analysis/LifetimeSafety/Checker.cpp (+16-1)
  • (modified) clang/test/Sema/warn-lifetime-safety-suggestions.cpp (+12)
  • (modified) clang/test/Sema/warn-lifetime-safety.cpp (+15-1)
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 74792768e2c57..f5236f63da34a 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -55,13 +55,14 @@ class LifetimeChecker {
   const LiveOriginsAnalysis &LiveOrigins;
   const FactManager &FactMgr;
   LifetimeSafetyReporter *Reporter;
+  AnalysisDeclContext ∾
 
 public:
   LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
                   const LiveOriginsAnalysis &LiveOrigins, const FactManager &FM,
                   AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter)
       : LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM),
-        Reporter(Reporter) {
+        Reporter(Reporter), AC(ADC) {
     for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>())
       for (const Fact *F : FactMgr.getFacts(B))
         if (const auto *EF = F->getAs<ExpireFact>())
@@ -70,6 +71,7 @@ class LifetimeChecker {
           checkAnnotations(OEF);
     issuePendingWarnings();
     suggestAnnotations();
+    inferAnnotations();
   }
 
   /// Checks if an escaping origin holds a placeholder loan, indicating a
@@ -160,6 +162,19 @@ class LifetimeChecker {
     for (const auto &[PVD, EscapeExpr] : AnnotationWarningsMap)
       Reporter->suggestAnnotation(PVD, EscapeExpr);
   }
+
+  void inferAnnotations() {
+    /// NOTE: This currently only adds the attribute to the function definition
+    /// being analyzed. For full inter-procedural inference to work reliably
+    /// (e.g., with out-of-order definitions), this attribute would also need to
+    /// be added to all other redeclarations of the function.
+    for (const auto &[ConstPVD, EscapeExpr] : AnnotationWarningsMap) {
+      ParmVarDecl *PVD = const_cast<ParmVarDecl *>(ConstPVD);
+      ASTContext &Ctx = AC.getASTContext();
+      auto *Attr = LifetimeBoundAttr::CreateImplicit(Ctx, SourceLocation());
+      PVD->addAttr(Attr);
+    }
+  }
 };
 } // namespace
 
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index c0f675a301d14..087899b9f5d3f 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -89,6 +89,18 @@ void test_getView_on_temporary() {
   (void)sv;
 }
 
+//===----------------------------------------------------------------------===//
+// Annotation Inference Test Cases
+//===----------------------------------------------------------------------===//
+
+View return_view_by_func (View a) {    // expected-warning {{param should be marked [[clang::lifetimebound]]}}.
+  return return_view_directly(a);      // expected-note {{param returned here}}
+}
+
+MyObj* return_pointer_by_func (MyObj* a) {         // expected-warning {{param should be marked [[clang::lifetimebound]]}}.
+  return return_pointer_object(a);                 // expected-note {{param returned here}} 
+}
+
 //===----------------------------------------------------------------------===//
 // Negative Test Cases
 //===----------------------------------------------------------------------===//
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 1191469e23df1..251324f968acd 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -Wno-dangling -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -Wno-dangling -Wno-experimental-lifetime-safety-suggestions -verify %s
 
 struct MyObj {
   int id;
@@ -552,6 +552,20 @@ const int& get_ref_to_local() {
                       // expected-note@-1 {{returned here}}
 }
 
+View inference_callee_return_identity(View a) {
+  return a;
+}
+
+View inference_caller_forwards_callee(View a) {
+  return inference_callee_return_identity(a);
+}
+
+View inference_top_level_return_stack_view() {
+  MyObj local_stack;
+  return inference_caller_forwards_callee(local_stack);     // expected-warning {{address of stack memory is returned later}}
+                                                            // expected-note@-1 {{returned here}}
+}
+
 //===----------------------------------------------------------------------===//
 // Use-After-Scope & Use-After-Return (Return-Stack-Address) Combined
 // These are cases where the diagnostic kind is determined by location

@llvmbot
Copy link
Member

llvmbot commented Dec 8, 2025

@llvm/pr-subscribers-clang-analysis

Author: Kashika Akhouri (kashika0112)

Changes

Adding Annotation Inference in Lifetime Analysis.

This PR implicitly adds lifetime bound annotations to the AST which is then used by functions which are parsed later to detect UARs etc. Example:

std::string_view f1(std::string_view a) {
  return a;
}

std::string_view f2(std::string_view a) {
  return f1(a);
}

std::string_view ff(std::string_view a) {
  std::string stack = "something on stack";
  return f2(stack); // warning: return-stack-addr
}

Note:

  1. We only add lifetime bound annotations to the functions being analyzed currently.
  2. Currently, both annotation suggestion and inference work simultaneously. This can be modified based on requirements.
  3. The current approach works given that functions are already present in the correct order (callee-before-caller). For not so ideal cases, we can create a CallGraph prior to calling the analysis. This can be done in the next PR.

Full diff: https://github.com/llvm/llvm-project/pull/171081.diff

3 Files Affected:

  • (modified) clang/lib/Analysis/LifetimeSafety/Checker.cpp (+16-1)
  • (modified) clang/test/Sema/warn-lifetime-safety-suggestions.cpp (+12)
  • (modified) clang/test/Sema/warn-lifetime-safety.cpp (+15-1)
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 74792768e2c57..f5236f63da34a 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -55,13 +55,14 @@ class LifetimeChecker {
   const LiveOriginsAnalysis &LiveOrigins;
   const FactManager &FactMgr;
   LifetimeSafetyReporter *Reporter;
+  AnalysisDeclContext &AC;
 
 public:
   LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
                   const LiveOriginsAnalysis &LiveOrigins, const FactManager &FM,
                   AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter)
       : LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM),
-        Reporter(Reporter) {
+        Reporter(Reporter), AC(ADC) {
     for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>())
       for (const Fact *F : FactMgr.getFacts(B))
         if (const auto *EF = F->getAs<ExpireFact>())
@@ -70,6 +71,7 @@ class LifetimeChecker {
           checkAnnotations(OEF);
     issuePendingWarnings();
     suggestAnnotations();
+    inferAnnotations();
   }
 
   /// Checks if an escaping origin holds a placeholder loan, indicating a
@@ -160,6 +162,19 @@ class LifetimeChecker {
     for (const auto &[PVD, EscapeExpr] : AnnotationWarningsMap)
       Reporter->suggestAnnotation(PVD, EscapeExpr);
   }
+
+  void inferAnnotations() {
+    /// NOTE: This currently only adds the attribute to the function definition
+    /// being analyzed. For full inter-procedural inference to work reliably
+    /// (e.g., with out-of-order definitions), this attribute would also need to
+    /// be added to all other redeclarations of the function.
+    for (const auto &[ConstPVD, EscapeExpr] : AnnotationWarningsMap) {
+      ParmVarDecl *PVD = const_cast<ParmVarDecl *>(ConstPVD);
+      ASTContext &Ctx = AC.getASTContext();
+      auto *Attr = LifetimeBoundAttr::CreateImplicit(Ctx, SourceLocation());
+      PVD->addAttr(Attr);
+    }
+  }
 };
 } // namespace
 
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index c0f675a301d14..087899b9f5d3f 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -89,6 +89,18 @@ void test_getView_on_temporary() {
   (void)sv;
 }
 
+//===----------------------------------------------------------------------===//
+// Annotation Inference Test Cases
+//===----------------------------------------------------------------------===//
+
+View return_view_by_func (View a) {    // expected-warning {{param should be marked [[clang::lifetimebound]]}}.
+  return return_view_directly(a);      // expected-note {{param returned here}}
+}
+
+MyObj* return_pointer_by_func (MyObj* a) {         // expected-warning {{param should be marked [[clang::lifetimebound]]}}.
+  return return_pointer_object(a);                 // expected-note {{param returned here}} 
+}
+
 //===----------------------------------------------------------------------===//
 // Negative Test Cases
 //===----------------------------------------------------------------------===//
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 1191469e23df1..251324f968acd 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -Wno-dangling -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -Wno-dangling -Wno-experimental-lifetime-safety-suggestions -verify %s
 
 struct MyObj {
   int id;
@@ -552,6 +552,20 @@ const int& get_ref_to_local() {
                       // expected-note@-1 {{returned here}}
 }
 
+View inference_callee_return_identity(View a) {
+  return a;
+}
+
+View inference_caller_forwards_callee(View a) {
+  return inference_callee_return_identity(a);
+}
+
+View inference_top_level_return_stack_view() {
+  MyObj local_stack;
+  return inference_caller_forwards_callee(local_stack);     // expected-warning {{address of stack memory is returned later}}
+                                                            // expected-note@-1 {{returned here}}
+}
+
 //===----------------------------------------------------------------------===//
 // Use-After-Scope & Use-After-Return (Return-Stack-Address) Combined
 // These are cases where the diagnostic kind is determined by location

@usx95 usx95 changed the title Infer [[clang::lifetimebound]] annotation #170418 [LifetimeSafety] Infer [[clang::lifetimebound]] annotation Dec 8, 2025
@usx95 usx95 requested review from Xazax-hun, usx95 and ymand December 8, 2025 08:48
Copy link
Contributor

@usx95 usx95 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for trying this out. LGTM overall. Some nit picks and ideas for more tests.

Copy link
Collaborator

@Xazax-hun Xazax-hun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, looks good to me once the review comments from @usx95 are addressed. I am just wondering if we should keep this behind a flag initially. The main motivation for that would be the understandability of these diagnostics. These are very useful, but it might be hard to follow what is going on without some additional diagnostics explaining what is happening between the function calls.

Emitting some additional notes like "parameter N is inferred to be lifetimebound" for all the calls involved might make it easier to follow.

@kashika0112 kashika0112 requested a review from usx95 December 8, 2025 12:58
Copy link
Contributor

usx95 commented Dec 8, 2025

I see two parts here:

  1. Making the diagnostics helpful: Agreed that this would be very confusing atm. In that aspect we still have -Wexperimental-lifetime-suggestions which would give at least the locations of all inferred annotations. Also I think, in its most helpful form, the lifetime analysis in general should trace down all the origins involved in the loan propagation and not just the inferred annotations. This can be done at a later stage where we target to make the diagnostics more helpful in general.
  2. Inference behind a flag: I think it makes sense to do this behind a frontend flag in the short term. Longer term, the solution to 1 would by-design give us a way to differentiate between findings powered by inference vs explicit annotations and then this enablement can be done more precisely by separate warning-groups.

We would introduce -fexperimental-lifetime-safety-inference as a language option. Does that make sense @Xazax-hun ?

@llvmbot llvmbot added the clang:frontend Language frontend issues, e.g. anything involving "Sema" label Dec 9, 2025
@kashika0112
Copy link
Contributor Author

kashika0112 commented Dec 9, 2025

I see two parts here:

  1. Making the diagnostics helpful: Agreed that this would be very confusing atm. In that aspect we still have -Wexperimental-lifetime-suggestions which would give at least the locations of all inferred annotations. Also I think, in its most helpful form, the lifetime analysis in general should trace down all the origins involved in the loan propagation and not just the inferred annotations. This can be done at a later stage where we target to make the diagnostics more helpful in general.
  2. Inference behind a flag: I think it makes sense to do this behind a frontend flag in the short term. Longer term, the solution to 1 would by-design give us a way to differentiate between findings powered by inference vs explicit annotations and then this enablement can be done more precisely by separate warning-groups.

We would introduce -fexperimental-lifetime-safety-inference as a language option. Does that make sense @Xazax-hun ?

I have introduced the new -fexperimental-lifetime-safety-inference flag and the current annotation inference is being guarded by this. I think this flag can also be reused when we enable the new post-order approach in the next PR.

Copy link
Contributor

@usx95 usx95 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Copy link
Collaborator

@Xazax-hun Xazax-hun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am happy with the flag, thanks!

@usx95
Copy link
Contributor

usx95 commented Dec 11, 2025

I will land this for now. Feel free to drop comments post-commit.

@usx95 usx95 merged commit 86f8445 into llvm:main Dec 11, 2025
10 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 11, 2025

LLVM Buildbot has detected a new failure on builder clang-m68k-linux-cross running on suse-gary-m68k-cross while building clang at step 5 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/27/builds/20182

Here is the relevant piece of the build log for the reference
Step 5 (ninja check 1) failure: stage 1 checked (failure)
...
[47/449] Building CXX object tools/clang/tools/extra/unittests/clang-tidy/CMakeFiles/ClangTidyTests.dir/GoogleModuleTest.cpp.o
[48/449] Building CXX object tools/clang/tools/extra/unittests/clang-tidy/CMakeFiles/ClangTidyTests.dir/IncludeInserterTest.cpp.o
[49/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/ClangdTests.cpp.o
[50/449] Building CXX object tools/clang/tools/extra/unittests/clang-tidy/CMakeFiles/ClangTidyTests.dir/AddConstTest.cpp.o
[51/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/BackgroundIndexTests.cpp.o
[52/449] Building CXX object tools/clang/tools/extra/unittests/clang-doc/CMakeFiles/ClangDocTests.dir/SerializeTest.cpp.o
[53/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/FindTargetTests.cpp.o
[54/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/FileIndexTests.cpp.o
[55/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/FindSymbolsTests.cpp.o
[56/449] Building CXX object tools/clang/tools/extra/include-cleaner/unittests/CMakeFiles/ClangIncludeCleanerTests.dir/FindHeadersTest.cpp.o
FAILED: tools/clang/tools/extra/include-cleaner/unittests/CMakeFiles/ClangIncludeCleanerTests.dir/FindHeadersTest.cpp.o 
/usr/bin/c++ -DGTEST_HAS_RTTI=0 -DLLVM_BUILD_STATIC -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/tools/clang/tools/extra/include-cleaner/unittests -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/include-cleaner/unittests -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/tools/clang/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/include-cleaner/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/include-cleaner/unittests/../lib -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/third-party/unittest/googletest/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/third-party/unittest/googlemock/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wno-missing-field-initializers -pedantic -Wno-long-long -Wimplicit-fallthrough -Wno-uninitialized -Wno-nonnull -Wno-class-memaccess -Wno-dangling-reference -Wno-redundant-move -Wno-pessimizing-move -Wno-array-bounds -Wno-stringop-overread -Wno-noexcept-type -Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment -Wno-misleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -O3 -DNDEBUG -std=c++17  -Wno-variadic-macros -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -Wno-suggest-override -MD -MT tools/clang/tools/extra/include-cleaner/unittests/CMakeFiles/ClangIncludeCleanerTests.dir/FindHeadersTest.cpp.o -MF tools/clang/tools/extra/include-cleaner/unittests/CMakeFiles/ClangIncludeCleanerTests.dir/FindHeadersTest.cpp.o.d -o tools/clang/tools/extra/include-cleaner/unittests/CMakeFiles/ClangIncludeCleanerTests.dir/FindHeadersTest.cpp.o -c /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
c++: fatal error: Killed signal terminated program cc1plus
compilation terminated.
[57/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/ModulesTests.cpp.o
[58/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/SymbolDocumentationTests.cpp.o
[59/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/PrerequisiteModulesTest.cpp.o
[60/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/QualityTests.cpp.o
[61/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/InsertionPointTests.cpp.o
[62/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/SerializationTests.cpp.o
[63/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/SemanticHighlightingTests.cpp.o
[64/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/SemanticSelectionTests.cpp.o
[65/449] Building CXX object tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/SelectionTests.cpp.o
In file included from /usr/include/c++/14/string:51,
                 from /usr/include/c++/14/bits/locale_classes.h:40,
                 from /usr/include/c++/14/bits/ios_base.h:41,
                 from /usr/include/c++/14/streambuf:43,
                 from /usr/include/c++/14/bits/streambuf_iterator.h:35,
                 from /usr/include/c++/14/iterator:66,
                 from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/include/llvm/ADT/ADL.h:13,
                 from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/include/llvm/ADT/iterator_range.h:21,
                 from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/include/llvm/ADT/StringRef.h:14,
                 from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/clangd/URI.h:12,
                 from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/clangd/Protocol.h:26,
                 from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/clangd/unittests/Annotations.h:15,
                 from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/clangd/unittests/SelectionTests.cpp:8:
In static member function ‘static _Up* std::__copy_move<_IsMove, true, std::random_access_iterator_tag>::__copy_m(_Tp*, _Tp*, _Up*) [with _Tp = const clang::clangd::SelectionTree::Node* const; _Up = const clang::clangd::SelectionTree::Node*; bool _IsMove = false]’,
    inlined from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = const clang::clangd::SelectionTree::Node* const*; _OI = const clang::clangd::SelectionTree::Node**]’ at /usr/include/c++/14/bits/stl_algobase.h:521:30,
    inlined from ‘_OI std::__copy_move_a1(_II, _II, _OI) [with bool _IsMove = false; _II = const clang::clangd::SelectionTree::Node* const*; _OI = const clang::clangd::SelectionTree::Node**]’ at /usr/include/c++/14/bits/stl_algobase.h:548:42,
    inlined from ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = const clang::clangd::SelectionTree::Node* const*; _OI = const clang::clangd::SelectionTree::Node**]’ at /usr/include/c++/14/bits/stl_algobase.h:555:31,
    inlined from ‘_OI std::copy(_II, _II, _OI) [with _II = const clang::clangd::SelectionTree::Node* const*; _OI = const clang::clangd::SelectionTree::Node**]’ at /usr/include/c++/14/bits/stl_algobase.h:651:7,
    inlined from ‘static _ForwardIterator std::__uninitialized_copy<true>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const clang::clangd::SelectionTree::Node* const*; _ForwardIterator = const clang::clangd::SelectionTree::Node**]’ at /usr/include/c++/14/bits/stl_uninitialized.h:147:27,
    inlined from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const clang::clangd::SelectionTree::Node* const*; _ForwardIterator = const clang::clangd::SelectionTree::Node**]’ at /usr/include/c++/14/bits/stl_uninitialized.h:185:15,
    inlined from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, allocator<_Tp>&) [with _InputIterator = const clang::clangd::SelectionTree::Node* const*; _ForwardIterator = const clang::clangd::SelectionTree::Node**; _Tp = const clang::clangd::SelectionTree::Node*]’ at /usr/include/c++/14/bits/stl_uninitialized.h:373:37,
    inlined from ‘void std::vector<_Tp, _Alloc>::_M_range_insert(iterator, _ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const clang::clangd::SelectionTree::Node* const*; _Tp = const clang::clangd::SelectionTree::Node*; _Alloc = std::allocator<const clang::clangd::SelectionTree::Node*>]’ at /usr/include/c++/14/bits/vector.tcc:1022:38,
    inlined from ‘std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::insert(const_iterator, _InputIterator, _InputIterator) [with _InputIterator = const clang::clangd::SelectionTree::Node* const*; <template-parameter-2-2> = void; _Tp = const clang::clangd::SelectionTree::Node*; _Alloc = std::allocator<const clang::clangd::SelectionTree::Node*>]’ at /usr/include/c++/14/bits/stl_vector.h:1488:19,
    inlined from ‘std::vector<const clang::clangd::SelectionTree::Node*> clang::clangd::{anonymous}::allNodes(const clang::clangd::SelectionTree&)’ at /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/clangd/unittests/SelectionTests.cpp:72:18,
    inlined from ‘virtual void clang::clangd::{anonymous}::SelectionTest_Selected_Test::TestBody()’ at /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/clangd/unittests/SelectionTests.cpp:718:51:
/usr/include/c++/14/bits/stl_algobase.h:452:30: warning: ‘void* __builtin_memcpy(void*, const void*, long unsigned int)’ writing between 9 and 34359738360 bytes into a region of size 0 overflows the destination [-Wstringop-overflow=]

@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 11, 2025

LLVM Buildbot has detected a new failure on builder sanitizer-x86_64-linux running on sanitizer-buildbot2 while building clang at step 2 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/66/builds/23526

Here is the relevant piece of the build log for the reference
Step 2 (annotate) failure: 'python ../sanitizer_buildbot/sanitizers/zorg/buildbot/builders/sanitizers/buildbot_selector.py' (failure)
...
[229/235] Generating MSAN_INST_GTEST.gtest-all.cc.x86_64-with-call.o
[230/235] Generating MSAN_INST_GTEST.gtest-all.cc.x86_64.o
[231/235] Generating MSAN_INST_TEST_OBJECTS.msan_test.cpp.x86_64-with-call.o
[232/235] Generating Msan-x86_64-with-call-Test
[233/235] Generating MSAN_INST_TEST_OBJECTS.msan_test.cpp.x86_64.o
[234/235] Generating Msan-x86_64-Test
[234/235] Running compiler_rt regression tests
llvm-lit: /home/b/sanitizer-x86_64-linux/build/llvm-project/llvm/utils/lit/lit/main.py:74: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 900 seconds was requested on the command line. Forcing timeout to be 900 seconds.
-- Testing: 6156 tests, 64 workers --
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90
FAIL: XRay-x86_64-linux :: TestCases/Posix/fdr-mode.cpp (5877 of 6156)
******************** TEST 'XRay-x86_64-linux :: TestCases/Posix/fdr-mode.cpp' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 1
/home/b/sanitizer-x86_64-linux/build/build_default/bin/clang  --driver-mode=g++ -fxray-instrument  -m64 -nobuiltininc -I/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/include -idirafter /home/b/sanitizer-x86_64-linux/build/build_default/lib/clang/22/include -resource-dir=/home/b/sanitizer-x86_64-linux/build/compiler_rt_build -Wl,-rpath,/home/b/sanitizer-x86_64-linux/build/compiler_rt_build/lib/linux   -g -std=c++11 /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/xray/TestCases/Posix/fdr-mode.cpp -o /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp
# executed command: /home/b/sanitizer-x86_64-linux/build/build_default/bin/clang --driver-mode=g++ -fxray-instrument -m64 -nobuiltininc -I/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/include -idirafter /home/b/sanitizer-x86_64-linux/build/build_default/lib/clang/22/include -resource-dir=/home/b/sanitizer-x86_64-linux/build/compiler_rt_build -Wl,-rpath,/home/b/sanitizer-x86_64-linux/build/compiler_rt_build/lib/linux -g -std=c++11 /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/xray/TestCases/Posix/fdr-mode.cpp -o /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp
# note: command had no output on stdout or stderr
# RUN: at line 2
rm -f fdr-logging-test-*
# executed command: rm -f 'fdr-logging-test-*'
# note: command had no output on stdout or stderr
# RUN: at line 3
rm -f fdr-unwrite-test-*
# executed command: rm -f 'fdr-unwrite-test-*'
# note: command had no output on stdout or stderr
# RUN: at line 4
env XRAY_OPTIONS="patch_premain=false xray_logfile_base=fdr-logging-test-      xray_mode=xray-fdr verbosity=1"  env XRAY_FDR_OPTIONS="func_duration_threshold_us=0"       /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp 2>&1 | FileCheck /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/xray/TestCases/Posix/fdr-mode.cpp
# executed command: env 'XRAY_OPTIONS=patch_premain=false xray_logfile_base=fdr-logging-test-      xray_mode=xray-fdr verbosity=1' env XRAY_FDR_OPTIONS=func_duration_threshold_us=0 /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp
# note: command had no output on stdout or stderr
# executed command: FileCheck /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/xray/TestCases/Posix/fdr-mode.cpp
# note: command had no output on stdout or stderr
# RUN: at line 8
env XRAY_OPTIONS="patch_premain=false      xray_logfile_base=fdr-unwrite-test- xray_mode=xray-fdr      verbosity=1"  env XRAY_FDR_OPTIONS="func_duration_threshold_us=5000"       /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp 2>&1 | FileCheck /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/xray/TestCases/Posix/fdr-mode.cpp
# executed command: env 'XRAY_OPTIONS=patch_premain=false      xray_logfile_base=fdr-unwrite-test- xray_mode=xray-fdr      verbosity=1' env XRAY_FDR_OPTIONS=func_duration_threshold_us=5000 /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp
# note: command had no output on stdout or stderr
# executed command: FileCheck /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/xray/TestCases/Posix/fdr-mode.cpp
# note: command had no output on stdout or stderr
# RUN: at line 13
ls fdr-logging-test-* | head -1 | tr -d '\n' > /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp.log
# executed command: ls 'fdr-logging-test-*'
# note: command had no output on stdout or stderr
# executed command: head -1
# note: command had no output on stdout or stderr
# executed command: tr -d '\n'
# note: command had no output on stdout or stderr
# RUN: at line 14
Step 16 (test standalone compiler-rt) failure: test standalone compiler-rt (failure)
...
[229/235] Generating MSAN_INST_GTEST.gtest-all.cc.x86_64-with-call.o
[230/235] Generating MSAN_INST_GTEST.gtest-all.cc.x86_64.o
[231/235] Generating MSAN_INST_TEST_OBJECTS.msan_test.cpp.x86_64-with-call.o
[232/235] Generating Msan-x86_64-with-call-Test
[233/235] Generating MSAN_INST_TEST_OBJECTS.msan_test.cpp.x86_64.o
[234/235] Generating Msan-x86_64-Test
[234/235] Running compiler_rt regression tests
llvm-lit: /home/b/sanitizer-x86_64-linux/build/llvm-project/llvm/utils/lit/lit/main.py:74: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 900 seconds was requested on the command line. Forcing timeout to be 900 seconds.
-- Testing: 6156 tests, 64 workers --
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90
FAIL: XRay-x86_64-linux :: TestCases/Posix/fdr-mode.cpp (5877 of 6156)
******************** TEST 'XRay-x86_64-linux :: TestCases/Posix/fdr-mode.cpp' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 1
/home/b/sanitizer-x86_64-linux/build/build_default/bin/clang  --driver-mode=g++ -fxray-instrument  -m64 -nobuiltininc -I/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/include -idirafter /home/b/sanitizer-x86_64-linux/build/build_default/lib/clang/22/include -resource-dir=/home/b/sanitizer-x86_64-linux/build/compiler_rt_build -Wl,-rpath,/home/b/sanitizer-x86_64-linux/build/compiler_rt_build/lib/linux   -g -std=c++11 /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/xray/TestCases/Posix/fdr-mode.cpp -o /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp
# executed command: /home/b/sanitizer-x86_64-linux/build/build_default/bin/clang --driver-mode=g++ -fxray-instrument -m64 -nobuiltininc -I/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/include -idirafter /home/b/sanitizer-x86_64-linux/build/build_default/lib/clang/22/include -resource-dir=/home/b/sanitizer-x86_64-linux/build/compiler_rt_build -Wl,-rpath,/home/b/sanitizer-x86_64-linux/build/compiler_rt_build/lib/linux -g -std=c++11 /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/xray/TestCases/Posix/fdr-mode.cpp -o /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp
# note: command had no output on stdout or stderr
# RUN: at line 2
rm -f fdr-logging-test-*
# executed command: rm -f 'fdr-logging-test-*'
# note: command had no output on stdout or stderr
# RUN: at line 3
rm -f fdr-unwrite-test-*
# executed command: rm -f 'fdr-unwrite-test-*'
# note: command had no output on stdout or stderr
# RUN: at line 4
env XRAY_OPTIONS="patch_premain=false xray_logfile_base=fdr-logging-test-      xray_mode=xray-fdr verbosity=1"  env XRAY_FDR_OPTIONS="func_duration_threshold_us=0"       /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp 2>&1 | FileCheck /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/xray/TestCases/Posix/fdr-mode.cpp
# executed command: env 'XRAY_OPTIONS=patch_premain=false xray_logfile_base=fdr-logging-test-      xray_mode=xray-fdr verbosity=1' env XRAY_FDR_OPTIONS=func_duration_threshold_us=0 /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp
# note: command had no output on stdout or stderr
# executed command: FileCheck /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/xray/TestCases/Posix/fdr-mode.cpp
# note: command had no output on stdout or stderr
# RUN: at line 8
env XRAY_OPTIONS="patch_premain=false      xray_logfile_base=fdr-unwrite-test- xray_mode=xray-fdr      verbosity=1"  env XRAY_FDR_OPTIONS="func_duration_threshold_us=5000"       /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp 2>&1 | FileCheck /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/xray/TestCases/Posix/fdr-mode.cpp
# executed command: env 'XRAY_OPTIONS=patch_premain=false      xray_logfile_base=fdr-unwrite-test- xray_mode=xray-fdr      verbosity=1' env XRAY_FDR_OPTIONS=func_duration_threshold_us=5000 /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp
# note: command had no output on stdout or stderr
# executed command: FileCheck /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/xray/TestCases/Posix/fdr-mode.cpp
# note: command had no output on stdout or stderr
# RUN: at line 13
ls fdr-logging-test-* | head -1 | tr -d '\n' > /home/b/sanitizer-x86_64-linux/build/compiler_rt_build/test/xray/X86_64LinuxConfig/TestCases/Posix/Output/fdr-mode.cpp.tmp.log
# executed command: ls 'fdr-logging-test-*'
# note: command had no output on stdout or stderr
# executed command: head -1
# note: command had no output on stdout or stderr
# executed command: tr -d '\n'
# note: command had no output on stdout or stderr
# RUN: at line 14

Xazax-hun pushed a commit to Xazax-hun/llvm-project that referenced this pull request Dec 11, 2025
Adding Annotation Inference in Lifetime Analysis.

This PR implicitly adds lifetime bound annotations to the AST which is
then used by functions which are parsed later to detect UARs etc.
Example:

```cpp
std::string_view f1(std::string_view a) {
  return a;
}

std::string_view f2(std::string_view a) {
  return f1(a);
}

std::string_view ff(std::string_view a) {
  std::string stack = "something on stack";
  return f2(stack); // warning: address of stack memory is returned
}
```

Note:

1. We only add lifetime bound annotations to the functions being
analyzed currently.
2. Currently, both annotation suggestion and inference work
simultaneously. This can be modified based on requirements.
3. The current approach works given that functions are already present
in the correct order (callee-before-caller). For not so ideal cases, we
can create a CallGraph prior to calling the analysis. This can be done
in the next PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:analysis clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:temporal-safety Issue/FR relating to the lifetime analysis in Clang (-Wdangling, -Wreturn-local-addr) clang Clang issues not falling into any other category

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants