-
Notifications
You must be signed in to change notification settings - Fork 15.5k
[LifetimeSafety] Infer [[clang::lifetimebound]] annotation #171081
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-temporal-safety Author: Kashika Akhouri (kashika0112) ChangesAdding 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: Note:
Full diff: https://github.com/llvm/llvm-project/pull/171081.diff 3 Files Affected:
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
|
|
@llvm/pr-subscribers-clang-analysis Author: Kashika Akhouri (kashika0112) ChangesAdding 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: Note:
Full diff: https://github.com/llvm/llvm-project/pull/171081.diff 3 Files Affected:
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
left a comment
There was a problem hiding this 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.
Xazax-hun
left a comment
There was a problem hiding this 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.
|
I see two parts here:
We would introduce |
I have introduced the new |
usx95
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Xazax-hun
left a comment
There was a problem hiding this 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!
|
I will land this for now. Feel free to drop comments post-commit. |
|
LLVM Buildbot has detected a new failure on builder 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 |
|
LLVM Buildbot has detected a new failure on builder 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 |
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.
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:
Note: