Skip to content

[LifetimeSafety] Extend suggestions for lifetimebound to also warn on canonical declarations #198784

Merged
usx95 merged 6 commits into
llvm:mainfrom
NeKon69:issue-198624-replace-old-cross-tu-method
May 24, 2026
Merged

[LifetimeSafety] Extend suggestions for lifetimebound to also warn on canonical declarations #198784
usx95 merged 6 commits into
llvm:mainfrom
NeKon69:issue-198624-replace-old-cross-tu-method

Conversation

@NeKon69
Copy link
Copy Markdown
Contributor

@NeKon69 NeKon69 commented May 20, 2026

With this patch, we suggest adding the clang::lifetimebound attribute on the canonical declaration and on the earliest redeclaration in each other file, preserving diagnostics for declarations visible from other translation units while avoiding duplicate suggestions within the same file.

Fixes #198624
Fixes #198628

@NeKon69
Copy link
Copy Markdown
Contributor Author

NeKon69 commented May 20, 2026

@usx95 Label was not added to this for some reason :(

edit: nvm, the bot just took longer this time.

@llvmorg-github-actions llvmorg-github-actions Bot 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 May 20, 2026
@llvmorg-github-actions
Copy link
Copy Markdown

llvmorg-github-actions Bot commented May 20, 2026

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

@llvm/pr-subscribers-clang

Author: NeKon69

Changes

With this patch, we suggest adding the clang::lifetimebound attribute on the canonical declaration instead of first trying to find a redeclaration of the function in another file and falling back to the definition when none is found.

Fixes #198624


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

3 Files Affected:

  • (modified) clang/lib/Analysis/LifetimeSafety/Checker.cpp (+11-46)
  • (modified) clang/test/Sema/warn-lifetime-safety-fixits.cpp (+4-5)
  • (modified) clang/test/Sema/warn-lifetime-safety-suggestions.cpp (+12-12)
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index d6a15139aa4ea..4b9d195411179 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -353,66 +353,31 @@ class LifetimeChecker {
             Scope};
   }
 
-  /// Returns the declaration of a function that is visible across translation
-  /// units, if such a declaration exists and is different from the definition.
-  static const FunctionDecl *getCrossTUDecl(const FunctionDecl &FD,
-                                            SourceManager &SM) {
-    if (!FD.isExternallyVisible())
-      return nullptr;
-    const FileID DefinitionFile = SM.getFileID(FD.getLocation());
-    for (const FunctionDecl *Redecl : FD.redecls())
-      if (SM.getFileID(Redecl->getLocation()) != DefinitionFile)
-        return Redecl;
-
-    return nullptr;
-  }
-
-  static const FunctionDecl *getCrossTUDecl(const ParmVarDecl &PVD,
-                                            SourceManager &SM) {
-    if (const auto *FD = dyn_cast<FunctionDecl>(PVD.getDeclContext()))
-      return getCrossTUDecl(*FD, SM);
-    return nullptr;
-  }
-
-  static void suggestWithScopeForParmVar(LifetimeSafetySemaHelper *SemaHelper,
-                                         const ParmVarDecl *PVD,
-                                         SourceManager &SM,
-                                         EscapingTarget EscapeTarget) {
+  void suggestWithScopeForParmVar(const ParmVarDecl *PVD,
+                                  EscapingTarget EscapeTarget) {
     if (llvm::isa<const VarDecl *>(EscapeTarget))
       return;
 
-    if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*PVD, SM))
-      SemaHelper->suggestLifetimeboundToParmVar(
-          WarningScope::CrossTU,
-          CrossTUDecl->getParamDecl(PVD->getFunctionScopeIndex()),
-          EscapeTarget);
-    else
-      SemaHelper->suggestLifetimeboundToParmVar(WarningScope::IntraTU, PVD,
-                                                EscapeTarget);
+    auto [Parm, Scope] = getCanonicalDeclForAttr(cast<FunctionDecl>(FD), PVD);
+    SemaHelper->suggestLifetimeboundToParmVar(Scope, Parm, EscapeTarget);
   }
 
-  static void
-  suggestWithScopeForImplicitThis(LifetimeSafetySemaHelper *SemaHelper,
-                                  const CXXMethodDecl *MD, SourceManager &SM,
-                                  const Expr *EscapeExpr) {
-    if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*MD, SM))
-      SemaHelper->suggestLifetimeboundToImplicitThis(
-          WarningScope::CrossTU, cast<CXXMethodDecl>(CrossTUDecl), EscapeExpr);
-    else
-      SemaHelper->suggestLifetimeboundToImplicitThis(WarningScope::IntraTU, MD,
-                                                     EscapeExpr);
+  void suggestWithScopeForImplicitThis(const CXXMethodDecl *MD,
+                                       const Expr *EscapeExpr) {
+    auto [MethodDecl, Scope] = getCanonicalDeclForAttr(MD);
+    SemaHelper->suggestLifetimeboundToImplicitThis(Scope, MethodDecl,
+                                                   EscapeExpr);
   }
 
   void suggestAnnotations() {
     if (!SemaHelper)
       return;
-    SourceManager &SM = AST.getSourceManager();
     for (auto [Target, EscapeTarget] : AnnotationWarningsMap) {
       if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>())
-        suggestWithScopeForParmVar(SemaHelper, PVD, SM, EscapeTarget);
+        suggestWithScopeForParmVar(PVD, EscapeTarget);
       else if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>()) {
         if (const auto *EscapeExpr = EscapeTarget.dyn_cast<const Expr *>())
-          suggestWithScopeForImplicitThis(SemaHelper, MD, SM, EscapeExpr);
+          suggestWithScopeForImplicitThis(MD, EscapeExpr);
         else
           llvm_unreachable("Implicit this can only escape via Expr (return)");
       }
diff --git a/clang/test/Sema/warn-lifetime-safety-fixits.cpp b/clang/test/Sema/warn-lifetime-safety-fixits.cpp
index 88d8bd379de8b..d9c7e8d3f0519 100644
--- a/clang/test/Sema/warn-lifetime-safety-fixits.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-fixits.cpp
@@ -69,12 +69,11 @@ int *arr_default(int a[2] = nullptr) {
   return a;
 }
 
-// FIXME: Iterate over redecls and add [[clang::lifetimebound]]
 View multi_decl(View a);
+// CHECK: :[[@LINE-1]]:17: warning: parameter in intra-TU function should be marked
+// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:23-[[@LINE-2]]:23}:" {{\[\[}}clang::lifetimebound]]"
 View multi_decl(View a);
 View multi_decl(View a) {
-  // CHECK: :[[@LINE-1]]:17: warning: parameter in intra-TU function should be marked
-  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:23-[[@LINE-2]]:23}:" {{\[\[}}clang::lifetimebound]]"
   return a;
 }
 
@@ -145,10 +144,10 @@ struct OutOfLine {
   OutOfLine() {}
   ~OutOfLine() {}
   const OutOfLine &get() const;
+  // CHECK: :[[@LINE-1]]:31: warning: implicit this in intra-TU function should be marked
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:31-[[@LINE-2]]:31}:" {{\[\[}}clang::lifetimebound]]"
 };
 const OutOfLine &OutOfLine::get() const {
-  // CHECK: :[[@LINE-1]]:40: warning: implicit this in intra-TU function should be marked
-  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:40-[[@LINE-2]]:40}:" {{\[\[}}clang::lifetimebound]]"
   return *this;
 }
 
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 973c610eb58ab..5122e634e594f 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -46,8 +46,8 @@ inline View inline_header_return_view(View a) {  // expected-warning {{parameter
   return a;                                      // expected-note {{param returned here}}
 }
 
-View redeclared_in_header(View a);
-inline View redeclared_in_header(View a) {  // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
+View redeclared_in_header(View a);          // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
+inline View redeclared_in_header(View a) {
   return a;                                 // expected-note {{param returned here}}
 }
 
@@ -177,8 +177,8 @@ View reassigned_to_another_parameter(
   return a;       // expected-note {{param returned here}} 
 }
 
-View intra_tu_func_redecl(View a);
-View intra_tu_func_redecl(View a) {   // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View intra_tu_func_redecl(View a);    // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View intra_tu_func_redecl(View a) {
   return a;                           // expected-note {{param returned here}} 
 }
 }
@@ -282,25 +282,25 @@ MyObj* return_pointer_by_func(MyObj* a) {         // expected-warning {{paramete
 } // namespace correct_order_inference
 
 namespace incorrect_order_inference_view {
-View return_view_callee(View a);
+View return_view_callee(View a);      // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
 
 View return_view_caller(View a) {     // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
   return return_view_callee(a);       // expected-note {{param returned here}}
 }
 
-View return_view_callee(View a) {     // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View return_view_callee(View a) {
   return a;                           // expected-note {{param returned here}}
 }   
 } // namespace incorrect_order_inference_view
 
 namespace incorrect_order_inference_object {
-MyObj* return_object_callee(MyObj* a);
+MyObj* return_object_callee(MyObj* a);       // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
 
 MyObj* return_object_caller(MyObj* a) {      // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
   return return_object_callee(a);            // expected-note {{param returned here}}
 }
 
-MyObj* return_object_callee(MyObj* a) {      // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+MyObj* return_object_callee(MyObj* a) {
   return a;                                  // expected-note {{param returned here}}
 }   
 } // namespace incorrect_order_inference_object
@@ -322,13 +322,13 @@ View inference_top_level_return_stack_view() {
 } // namespace simple_annotation_inference
 
 namespace inference_in_order_with_redecls {
-View inference_callee_return_identity(View a);
-View inference_callee_return_identity(View a) {   // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View inference_callee_return_identity(View a);    // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View inference_callee_return_identity(View a) {
   return a;                                       // expected-note {{param returned here}}
 }
 
-View inference_caller_forwards_callee(View a);
-View inference_caller_forwards_callee(View a) {   // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View inference_caller_forwards_callee(View a);    // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View inference_caller_forwards_callee(View a) {
   return inference_callee_return_identity(a);     // expected-note {{param returned here}}
 }
   

@Xazax-hun
Copy link
Copy Markdown
Contributor

Maybe I was missing something, but I am not sure if this is the right approach. The canonical declaration is the first declaration in the redecl chain. But this does not necessarily mean that the first declaration is the one that is visible to other TUs.

Consider:

// header.h:
void f();

// cpp file:
void f();
#include "header.h"
void f() { }

Here, the canonical decl would be the one before the include, but the cross-tu decl would be the one in the header file.

@NeKon69
Copy link
Copy Markdown
Contributor Author

NeKon69 commented May 20, 2026

Yes, but I think we will change that with #198628.

I can instead close that issue first, then work on this.

@Xazax-hun
Copy link
Copy Markdown
Contributor

Oh, as per the comment on the issue, we probably want users to both annotate the canonical decl and the decl that is visible from other TUs. In most cases these two are the same, but not always.

@NeKon69
Copy link
Copy Markdown
Contributor Author

NeKon69 commented May 20, 2026

Yeah, but that is a separate change from this one. If you would prefer, I can close the other issue first.

@Xazax-hun
Copy link
Copy Markdown
Contributor

If we still want to enforce that the declaration in the header needs the annotation, we still need getCrossTUDecl, so we cannot get rid of it.

@NeKon69
Copy link
Copy Markdown
Contributor Author

NeKon69 commented May 20, 2026

I am going to instead report both locations (if different), would that be better?

@Xazax-hun
Copy link
Copy Markdown
Contributor

Yeah, I think I would be happy with that!

@NeKon69 NeKon69 changed the title [LifetimeSafety] Replace getCrossTUDecl with getCanonicalDeclForAttr [LifetimeSafety] Extend suggestions for lifetimebound to also warn on canonical declarations May 20, 2026
@NeKon69
Copy link
Copy Markdown
Contributor Author

NeKon69 commented May 21, 2026

@Xazax-hun could you review this, please?

Copy link
Copy Markdown
Contributor

@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.

LG, thanks!

Copy link
Copy Markdown
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.

Functional/Policy changes:

getCrossTUDecl currently seems to give only the single last decl which is in a separate file.

  1. We should prefer the earliest decl in the file.
  2. It is possible that these are available across multiple such files.

So the final target list would be the canonical decl + all first decls in each different file. These would have repeated warnings but should be fine ?

Code structure.

getCanonicalFunctionDeclForAttr and getCrossTUDecl are also quite similar. I would prefer to have a single place dictating the annotation placement policy.
I would suggest to merge these functions to abstract this into a function getTargetDeclsForAttr which returns a "list of target decls" to be annotated given an input decl. The result could have other attributes like xTU/intra-TU, definition/decl, etc.

WDYT @Xazax-hun

Comment thread clang/lib/Analysis/LifetimeSafety/Checker.cpp Outdated
Comment thread clang/lib/Analysis/LifetimeSafety/Checker.cpp Outdated
Comment thread clang/lib/Analysis/LifetimeSafety/Checker.cpp Outdated
@Xazax-hun
Copy link
Copy Markdown
Contributor

So the final target list would be the canonical decl + all first decls in each different file. These would have repeated warnings but should be fine ?

This sounds great to me!

@NeKon69
Copy link
Copy Markdown
Contributor Author

NeKon69 commented May 21, 2026

getCanonicalFunctionDeclForAttr and getCrossTUDecl are also quite similar. I would prefer to have a single place dictating the annotation placement policy.

That's what I also had in mind originally for solving #198628, but I guess we could merge these issues together in this PR?

@NeKon69
Copy link
Copy Markdown
Contributor Author

NeKon69 commented May 21, 2026

I have implemented a single function that returns a vector of function decls to annotate.

@NeKon69 NeKon69 requested review from Xazax-hun and usx95 May 21, 2026 18:38
Comment thread clang/lib/Analysis/LifetimeSafety/Checker.cpp Outdated
Comment thread clang/lib/Analysis/LifetimeSafety/Checker.cpp Outdated
Comment thread clang/lib/Analysis/LifetimeSafety/Checker.cpp Outdated
@NeKon69
Copy link
Copy Markdown
Contributor Author

NeKon69 commented May 22, 2026

I updated the code. Unfortunately, you cannot directly iterate over reversed redeclarations because they are not bidirectional, so I had to store the redeclarations in a local vector first. I do not think this should be too expensive, though.

? WarningScope::CrossTU
: WarningScope::IntraTU;
auto GetLoc = [&SM](const FunctionDecl *FD) {
return SM.getExpansionLoc(FD->getLocation());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hmm. I think this is technically correct, expansion loc determines where is this declaration actually visible. But it is also a bit hard for the users to understand what is going on. Not for this PR, but whenever we use an expansion loc, it would be nice to have both the expansion and the spelling loc in the diagnostic via a note (when they differ). But this is absolutely a small thing for the future, should not block anything here.

Copy link
Copy Markdown
Contributor Author

@NeKon69 NeKon69 May 24, 2026

Choose a reason for hiding this comment

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

I just realized, do we not already attach a note when the expression was expended from a macro?

Example:
https://godbolt.org/z/r8W86M4Tj

Comment thread clang/lib/Analysis/LifetimeSafety/Checker.cpp Outdated
Comment thread clang/lib/Analysis/LifetimeSafety/Checker.cpp Outdated
Copy link
Copy Markdown
Contributor

@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.

LG!

Copy link
Copy Markdown
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.

Looks great. Thanks.

Last few nits.

Comment thread clang/lib/Analysis/LifetimeSafety/Checker.cpp Outdated
Comment thread clang/lib/Analysis/LifetimeSafety/Checker.cpp Outdated
Comment thread clang/lib/Analysis/LifetimeSafety/Checker.cpp Outdated
@NeKon69 NeKon69 requested a review from usx95 May 22, 2026 12:13
Copy link
Copy Markdown
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.

@usx95
Copy link
Copy Markdown
Contributor

usx95 commented May 24, 2026

I will land this as there are approvals with no blocking comments.

@usx95 usx95 merged commit 69a5cf5 into llvm:main May 24, 2026
10 checks passed
@thurstond
Copy link
Copy Markdown
Contributor

Some of the buildbots are failing after his commit (e.g., Arm MSan: https://lab.llvm.org/staging/#/builders/7/builds/1733; Arm ASan: https://lab.llvm.org/staging/#/builders/42/builds/4748). Could you please take a look?

e.g.,

==clang==1613352==ERROR: AddressSanitizer: stack-use-after-scope on address 0xe291ed500f50 at pc 0xb9034ab81a5c bp 0xffffc53e7790 sp 0xffffc53e7788
READ of size 8 at 0xe291ed500f50 thread T0
    #0 0xb9034ab81a58 in clang::lifetimes::internal::(anonymous namespace)::LifetimeChecker::getTargetDeclsForAttr(clang::FunctionDecl const*) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Analysis/LifetimeSafety/Checker.cpp:359:37
    #1 0xb9034ab797f8 in reportMisplacedLifetimebound /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Analysis/LifetimeSafety/Checker.cpp:442:24
    #2 0xb9034ab797f8 in clang::lifetimes::internal::(anonymous namespace)::LifetimeChecker::LifetimeChecker(clang::lifetimes::internal::LoanPropagationAnalysis const&, clang::lifetimes::internal::MovedLoansAnalysis const&, clang::lifetimes::internal::LiveOriginsAnalysis const&, clang::lifetimes::internal::FactManager&, clang::AnalysisDeclContext&, clang::lifetimes::LifetimeSafetySemaHelper*) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Analysis/LifetimeSafety/Checker.cpp:106:5
    #3 0xb9034ab73f30 in clang::lifetimes::internal::runLifetimeChecker(clang::lifetimes::internal::LoanPropagationAnalysis const&, clang::lifetimes::internal::MovedLoansAnalysis const&, clang::lifetimes::internal::LiveOriginsAnalysis const&, clang::lifetimes::internal::FactManager&, clang::AnalysisDeclContext&, clang::lifetimes::LifetimeSafetySemaHelper*) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Analysis/LifetimeSafety/Checker.cpp:496:19
    #4 0xb9034ab5d9dc in clang::lifetimes::internal::LifetimeSafetyAnalysis::run() /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp:98:3
    #5 0xb9034ab5e700 in clang::lifetimes::runLifetimeSafetyAnalysis(clang::AnalysisDeclContext&, clang::lifetimes::LifetimeSafetySemaHelper*, clang::lifetimes::LifetimeSafetyStats&, bool) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp:131:12
    #6 0xb903496b3b68 in clang::sema::AnalysisBasedWarnings::IssueWarnings(clang::sema::AnalysisBasedWarnings::Policy, clang::sema::FunctionScopeInfo*, clang::Decl const*, clang::QualType) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp:3159:7
    #7 0xb9034968d8b4 in clang::Sema::PopFunctionScopeInfo(clang::sema::AnalysisBasedWarnings::Policy const*, clang::Decl*, clang::QualType) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Sema/Sema.cpp:2546:22
    #8 0xb90349a85a80 in clang::Sema::ActOnFinishFunctionBody(clang::Decl*, clang::Stmt*, bool, bool) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Sema/SemaDecl.cpp:17152:5
    #9 0xb903494bfd00 in clang::Parser::ParseFunctionStatementBody(clang::Decl*, clang::Parser::ParseScope&) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Parse/ParseStmt.cpp:2454:18
    #10 0xb9034931d820 in clang::Parser::ParseFunctionDefinition(clang::ParsingDeclarator&, clang::Parser::ParsedTemplateInfo const&, clang::LateParsedAttrList*) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Parse/Parser.cpp:1415:10
    #11 0xb90349414e9c in clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec&, clang::DeclaratorContext, clang::ParsedAttributes&, clang::Parser::ParsedTemplateInfo&, clang::SourceLocation*, clang::Parser::ForRangeInit*) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Parse/ParseDecl.cpp:2291:17
    #12 0xb9034931ae58 in clang::Parser::ParseDeclOrFunctionDefInternal(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec&, clang::AccessSpecifier) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Parse/Parser.cpp:1153:10
    #13 0xb90349319dcc in clang::Parser::ParseDeclarationOrFunctionDefinition(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec*, clang::AccessSpecifier) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Parse/Parser.cpp:1175:12
    #14 0xb9034931755c in clang::Parser::ParseExternalDeclaration(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec*) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Parse/Parser.cpp:1003:14
    #15 0xb90349312fa0 in clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&, clang::Sema::ModuleImportState&) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Parse/Parser.cpp:711:12
    #16 0xb903492f30b0 in clang::ParseAST(clang::Sema&, bool, bool) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Parse/ParseAST.cpp:170:20
    #17 0xb9034646ea0c in clang::FrontendAction::Execute() /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Frontend/FrontendAction.cpp:1342:3
    #18 0xb90346349c34 in clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Frontend/CompilerInstance.cpp:1021:33
    #19 0xb903466bf808 in clang::ExecuteCompilerInvocation(clang::CompilerInstance*) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:318:25
    #20 0xb9033dc5624c in cc1_main(llvm::ArrayRef<char const*>, char const*, void*) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/tools/driver/cc1_main.cpp:296:13
    #21 0xb9033dc4e65c in ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/tools/driver/driver.cpp:229:12
    #22 0xb9033dc4ccdc in clang_main(int, char**, llvm::ToolContext const&) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/tools/driver/driver.cpp:277:12
    #23 0xb9033dc6d7dc in main /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm_build_asan/tools/clang/tools/driver/clang-driver.cpp:17:10
    #24 0xe691ef612f18  (/usr/lib/aarch64-linux-gnu/libc.so.6+0x22f18) (BuildId: b50ceafbd17dc6bceee344a66671c7eaa152bef4)
    #25 0xe691ef613058 in __libc_start_main (/usr/lib/aarch64-linux-gnu/libc.so.6+0x23058) (BuildId: b50ceafbd17dc6bceee344a66671c7eaa152bef4)
    #26 0xb9033db625ec in _start (/home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm_build_asan/bin/clang-23+0xdd425ec)
Address 0xe291ed500f50 is located in stack of thread T0 at offset 80 in frame
    #0 0xb9034ab81078 in clang::lifetimes::internal::(anonymous namespace)::LifetimeChecker::getTargetDeclsForAttr(clang::FunctionDecl const*) /home/b/sanitizer-aarch64-linux-bootstrap-asan/build/llvm-project/clang/lib/Analysis/LifetimeSafety/Checker.cpp:325
  This frame has 2 object(s):
    [32, 48) 'ref.tmp' (line 340)
    [64, 128) 'ref.tmp' (line 360) <== Memory access at offset 80 is inside this variable

@thurstond
Copy link
Copy Markdown
Contributor

I've drafted a small fix: #199455

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:analysis 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

4 participants