llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Utkarsh Saxena (usx95)

<details>
<summary>Changes</summary>

This PR enhances the CFG builder to properly handle function parameters in 
lifetime analysis:

1. Added code to include parameters in the initial scope during CFG 
construction for both `FunctionDecl` and `BlockDecl` types
2. Added a special case to skip reference parameters, as they don't need 
automatic destruction
3. Fixed several test cases that were previously marked as "FIXME" due to 
missing parameter lifetime tracking

Previously, Clang's lifetime analysis was not properly tracking the lifetime of 
function parameters, causing it to miss important use-after-return bugs when 
parameter values were returned by reference or address. This change ensures 
that parameters are properly tracked in the CFG, allowing the analyzer to 
correctly identify when stack memory associated with parameters is returned.

Fixes https://github.com/llvm/llvm-project/issues/169014

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


3 Files Affected:

- (modified) clang/lib/Analysis/CFG.cpp (+10) 
- (modified) clang/test/Analysis/scopes-cfg-output.cpp (+2) 
- (modified) clang/test/Sema/warn-lifetime-safety.cpp (+14-6) 


``````````diff
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index cdde849b0e026..c052af5e96b21 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -1666,6 +1666,13 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, 
Stmt *Statement) {
   assert(Succ == &cfg->getExit());
   Block = nullptr;  // the EXIT block is empty.  Create all other blocks 
lazily.
 
+  // Add parameters to the initial scope so to handle their dtos and lifetime
+  // ends.
+  LocalScope *paramScope = nullptr;
+  if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
+    for (ParmVarDecl *PD : FD->parameters())
+      paramScope = addLocalScopeForVarDecl(PD, paramScope);
+
   if (BuildOpts.AddImplicitDtors)
     if (const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D))
       addImplicitDtorsForDestructor(DD);
@@ -2246,6 +2253,9 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl 
*VD,
   if (!VD->hasLocalStorage())
     return Scope;
 
+  if (isa<ParmVarDecl>(VD) && VD->getType()->isReferenceType())
+    return Scope;
+
   if (!BuildOpts.AddLifetime && !BuildOpts.AddScopes &&
       !needsAutomaticDestruction(VD)) {
     assert(BuildOpts.AddImplicitDtors);
diff --git a/clang/test/Analysis/scopes-cfg-output.cpp 
b/clang/test/Analysis/scopes-cfg-output.cpp
index 6ed6f3638f75b..9c75492c33a42 100644
--- a/clang/test/Analysis/scopes-cfg-output.cpp
+++ b/clang/test/Analysis/scopes-cfg-output.cpp
@@ -1437,12 +1437,14 @@ void test_cleanup_functions() {
 // CHECK-NEXT:    4: return;
 // CHECK-NEXT:    5: CleanupFunction (cleanup_int)
 // CHECK-NEXT:    6: CFGScopeEnd(i)
+// CHECK-NEXT:    7: CFGScopeEnd(m)
 // CHECK-NEXT:    Preds (1): B3
 // CHECK-NEXT:    Succs (1): B0
 // CHECK:      [B2]
 // CHECK-NEXT:    1: return;
 // CHECK-NEXT:    2: CleanupFunction (cleanup_int)
 // CHECK-NEXT:    3: CFGScopeEnd(i)
+// CHECK-NEXT:    4: CFGScopeEnd(m)
 // CHECK-NEXT:    Preds (1): B3
 // CHECK-NEXT:    Succs (1): B0
 // CHECK:      [B3]
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index e80a05860389c..c08543c27778f 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -529,14 +529,14 @@ TriviallyDestructedClass* trivial_class_uar () {
   return ptr;     // expected-note {{returned here}}
 }
 
-// FIXME: No lifetime warning for this as no expire facts are generated for 
parameters
 const int& return_parameter(int a) { 
-  return a; 
+  return a; // expected-warning {{address of stack memory is returned later}}
+            // expected-note@-1 {{returned here}}
 }
 
-// FIXME: No lifetime warning for this as no expire facts are generated for 
parameters
 int* return_pointer_to_parameter(int a) {
-    return &a;
+    return &a;  // expected-warning {{address of stack memory is returned 
later}}
+                // expected-note@-1 {{returned here}}
 }
 
 const int& return_reference_to_parameter(int a)
@@ -788,9 +788,17 @@ const MyObj& lifetimebound_return_ref_to_local() {
                              // expected-note@-1 {{returned here}}
 }
 
-// FIXME: Fails to diagnose UAR when a reference to a by-value param escapes 
via the return value.
 View lifetimebound_return_of_by_value_param(MyObj stack_param) {
-  return Identity(stack_param); 
+  return Identity(stack_param); // expected-warning {{address of stack memory 
is returned later}}
+                                // expected-note@-1 {{returned here}}
+}
+
+void LambdaUARParam() {
+  auto lambda = [](MyObj stack_param) {
+    return Identity(stack_param); // expected-warning {{address of stack 
memory is returned later}}
+                                  // expected-note@-1 {{returned here}}
+  };
+  lambda(MyObj{});
 }
 
 // FIXME: Fails to diagnose UAF when a reference to a by-value param escapes 
via an out-param.

``````````

</details>


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

Reply via email to