https://github.com/benedekaibas updated https://github.com/llvm/llvm-project/pull/215651
>From 0c78792ca93f6a76ed460cbde327fdec9393a936 Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Tue, 11 Aug 2026 22:22:07 +0200 Subject: [PATCH 1/4] [analyzer] Only underline the parameter that is bound to the return value --- .../Checkers/UseAfterLifetimeEnd.cpp | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp b/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp index a9065352adae6..de89836ee5dc2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp @@ -43,20 +43,30 @@ class UseAfterLifetimeEndBRVisitor : public BugReporterVisitor { } // namespace -static const Expr *getLifetimeBoundArg(const Expr *RetExpr) { +static const Expr *getLifetimeBoundArg(const Expr *RetExpr, + const MemRegion *Region, + const ExplodedNode *N) { const CallExpr *Expr = dyn_cast_or_null<CallExpr>(RetExpr); if (!Expr) return nullptr; + const FunctionDecl *FD = Expr->getDirectCallee(); if (!FD) return nullptr; + const MemRegion *BaseReg = Region->getBaseRegion(); + for (const ParmVarDecl *PVD : FD->parameters()) { - if (PVD->hasAttr<LifetimeBoundAttr>()) { - unsigned Idx = PVD->getFunctionScopeIndex(); - if (Idx < Expr->getNumArgs()) - return Expr->getArg(Idx); - } + if (!PVD->hasAttr<LifetimeBoundAttr>()) + continue; + unsigned Idx = PVD->getFunctionScopeIndex(); + + if (Idx >= Expr->getNumArgs()) + continue; + + const MemRegion *R = N->getSVal(Expr->getArg(Idx)).getAsRegion(); + if (R && R->getBaseRegion() == BaseReg) + return Expr->getArg(Idx); } return nullptr; } @@ -117,7 +127,7 @@ PathDiagnosticPieceRef UseAfterLifetimeEndBRVisitor::createSourcePiece( return nullptr; const Expr *RetExpr = dyn_cast_or_null<Expr>(S); - const Expr *Arg = getLifetimeBoundArg(RetExpr); + const Expr *Arg = getLifetimeBoundArg(RetExpr, SourceRegion, N); PathDiagnosticLocation Pos; >From f103f33155dd64dc7ae0be45ce0f255318c61e61 Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Wed, 12 Aug 2026 14:41:57 +0200 Subject: [PATCH 2/4] Add test case for testing highlighting. --- clang/test/Analysis/lifetime-bound.cpp | 35 +++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/clang/test/Analysis/lifetime-bound.cpp b/clang/test/Analysis/lifetime-bound.cpp index d29c37f639993..e34796009c299 100644 --- a/clang/test/Analysis/lifetime-bound.cpp +++ b/clang/test/Analysis/lifetime-bound.cpp @@ -1,6 +1,7 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugLifetimeModeling \ // RUN: -analyzer-config cfg-lifetime=true -analyzer-output=text -verify %s - +// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugLifetimeModeling \ +// RUN: -analyzer-output=text %s 2>&1 | FileCheck %s struct A {}; struct Pair { @@ -410,3 +411,35 @@ void no_dangling_by_value_argument() { // The returned reference does not dangle. takes_by_value(BoundToSelf()); } + +int multi_params_annotated(int *p_one [[clang::lifetimebound]], int *p_two [[clang::lifetimebound]]); + +int test_multi_param_highlight() { + int local_one = 1, local_two = 2; + // expected-note@-1 {{'local_one' initialized here}} + // expected-note@-2 {{'local_two' initialized here}} + return multi_params_annotated(&local_one, &local_two); + // expected-warning@-1 {{address of stack memory associated with local variable 'local_one' returned}} + // expected-warning@-2 {{address of stack memory associated with local variable 'local_two' returned}} + // expected-warning@-3 {{Returning value bound to 'local_one' that will go out of scope}} + // expected-note@-4 {{Value's lifetime bound to the lifetime of 'local_one' here}} + // expected-note@-5 {{Lifetime of 'local_one' ended here}} + // expected-warning@-6 {{Returning value bound to 'local_two' that will go out of scope}} + // expected-note@-7 {{Value's lifetime bound to the lifetime of 'local_two' here}} + // expected-note@-8 {{Lifetime of 'local_two' ended here}} + + // CHECK: :[[@LINE-10]]:33: note: Value's lifetime bound to the lifetime of 'local_one' here + // CHECK-NEXT: [[@LINE-14]] | int local_one = 1, local_two = 2; + // CHECK-NEXT: ~~~~~~~~~~~~~~~~~ + // CHECK-NEXT: [[@LINE-15]] | // expected{{-}}note@-1 {{.*}} + // CHECK-NEXT: [[@LINE-15]] | // expected{{-}}note@-2 {{.*}} + // CHECK-NEXT: [[@LINE-15]] | return multi_params_annotated(&local_one, &local_two); + // CHECK-NEXT: ^~~~~~~~~~ + // CHECK: :[[@LINE-17]]:45: note: Value's lifetime bound to the lifetime of 'local_two' here + // CHECK-NEXT: [[@LINE-21]] | int local_one = 1, local_two = 2; + // CHECK-NEXT: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK-NEXT: [[@LINE-22]] | // expected{{-}}note@-1 {{.*}} + // CHECK-NEXT: [[@LINE-22]] | // expected{{-}}note@-2 {{.*}} + // CHECK-NEXT: [[@LINE-22]] | return multi_params_annotated(&local_one, &local_two); + // CHECK-NEXT: ^~~~~~~~~~ +} >From 8a6a4bf0d9c0f1316fa61697c0fbd76165a2c1fa Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Wed, 12 Aug 2026 23:17:15 +0200 Subject: [PATCH 3/4] Rewrite CHECK lines. --- clang/test/Analysis/lifetime-bound.cpp | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/clang/test/Analysis/lifetime-bound.cpp b/clang/test/Analysis/lifetime-bound.cpp index e34796009c299..d54116bc65314 100644 --- a/clang/test/Analysis/lifetime-bound.cpp +++ b/clang/test/Analysis/lifetime-bound.cpp @@ -428,18 +428,10 @@ int test_multi_param_highlight() { // expected-note@-7 {{Value's lifetime bound to the lifetime of 'local_two' here}} // expected-note@-8 {{Lifetime of 'local_two' ended here}} - // CHECK: :[[@LINE-10]]:33: note: Value's lifetime bound to the lifetime of 'local_one' here - // CHECK-NEXT: [[@LINE-14]] | int local_one = 1, local_two = 2; - // CHECK-NEXT: ~~~~~~~~~~~~~~~~~ - // CHECK-NEXT: [[@LINE-15]] | // expected{{-}}note@-1 {{.*}} - // CHECK-NEXT: [[@LINE-15]] | // expected{{-}}note@-2 {{.*}} - // CHECK-NEXT: [[@LINE-15]] | return multi_params_annotated(&local_one, &local_two); - // CHECK-NEXT: ^~~~~~~~~~ - // CHECK: :[[@LINE-17]]:45: note: Value's lifetime bound to the lifetime of 'local_two' here - // CHECK-NEXT: [[@LINE-21]] | int local_one = 1, local_two = 2; - // CHECK-NEXT: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK-NEXT: [[@LINE-22]] | // expected{{-}}note@-1 {{.*}} - // CHECK-NEXT: [[@LINE-22]] | // expected{{-}}note@-2 {{.*}} - // CHECK-NEXT: [[@LINE-22]] | return multi_params_annotated(&local_one, &local_two); - // CHECK-NEXT: ^~~~~~~~~~ + // CHECK: note: Value's lifetime bound to the lifetime of 'local_one' here + // CHECK: return multi_params_annotated(&local_one, &local_two); + // CHECK-NEXT: ^~~~~~~~~~ + // CHECK: note: Value's lifetime bound to the lifetime of 'local_two' here + // CHECK: return multi_params_annotated(&local_one, &local_two); + // CHECK-NEXT: ^~~~~~~~~~ } >From 6163d53ac079859ae65974b8c194c282b0145811 Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Thu, 13 Aug 2026 17:46:24 +0200 Subject: [PATCH 4/4] Add test case. --- clang/test/Analysis/lifetime-bound.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/clang/test/Analysis/lifetime-bound.cpp b/clang/test/Analysis/lifetime-bound.cpp index d54116bc65314..cd31c37aef16c 100644 --- a/clang/test/Analysis/lifetime-bound.cpp +++ b/clang/test/Analysis/lifetime-bound.cpp @@ -430,8 +430,23 @@ int test_multi_param_highlight() { // CHECK: note: Value's lifetime bound to the lifetime of 'local_one' here // CHECK: return multi_params_annotated(&local_one, &local_two); - // CHECK-NEXT: ^~~~~~~~~~ + // CHECK-NEXT:{{\| \^~~~~~~~~~$}} // CHECK: note: Value's lifetime bound to the lifetime of 'local_two' here // CHECK: return multi_params_annotated(&local_one, &local_two); - // CHECK-NEXT: ^~~~~~~~~~ + // CHECK-NEXT:{{\| \^~~~~~~~~~$}} +} + +int global_var; +int test_correct_param_highlight() { + int local_n = 5; + // expected-note@-1 {{'local_n' initialized here}} + return multi_params_annotated(&global_var, &local_n); + // expected-warning@-1 {{address of stack memory associated with local variable 'local_n' returned}} + // expected-warning@-2 {{Returning value bound to 'local_n' that will go out of scope}} + // expected-note@-3 {{Value's lifetime bound to the lifetime of 'local_n' here}} + // expected-note@-4 {{Lifetime of 'local_n' ended here}} + + // CHECK: note: Value's lifetime bound to the lifetime of 'local_n' here + // CHECK: return multi_params_annotated(&global_var, &local_n); + // CHECK-NEXT:{{\| \^~~~~~~~$}} } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
