-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[analyzer] StackAddrEscapeChecker: also check return for child stack frames #126986
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 Author: Michael Flanders (Flandini) ChangesFixes #123459. This changes checking of the returned expr to also look for memory regions whose stack frame context was a child of the current stack frame context, e.g., for cases like this given in #123459: Full diff: https://github.com/llvm/llvm-project/pull/126986.diff 3 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index c9df15ceb3b40..2a22e8e10efb0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -274,7 +274,13 @@ class FindStackRegionsSymbolVisitor final : public SymbolVisitor {
void SaveIfEscapes(const MemRegion *MR) {
const StackSpaceRegion *SSR =
MR->getMemorySpace()->getAs<StackSpaceRegion>();
- if (SSR && SSR->getStackFrame() == PoppedStackFrame)
+
+ if (!SSR)
+ return;
+
+ const StackFrameContext *CapturedSFC = SSR->getStackFrame();
+ if (CapturedSFC == PoppedStackFrame ||
+ PoppedStackFrame->isParentOf(CapturedSFC))
EscapingStackRegions.push_back(MR);
}
diff --git a/clang/test/Analysis/stack-addr-ps.cpp b/clang/test/Analysis/stack-addr-ps.cpp
index bf988d0a16959..2e509f358b49f 100644
--- a/clang/test/Analysis/stack-addr-ps.cpp
+++ b/clang/test/Analysis/stack-addr-ps.cpp
@@ -982,6 +982,51 @@ int& ret_local_field_ref() {
}
} //namespace return_address_of_true_positives
+namespace return_from_child_block_scope {
+struct S {
+ int *p;
+};
+
+S return_child_stack_context() {
+ S s;
+ {
+ int a = 1;
+ s = (S){ &a };
+ }
+ return s; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}
+}
+
+S return_child_stack_context_field() {
+ S s;
+ {
+ int a = 1;
+ s.p = &a;
+ }
+ return s; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}
+}
+
+// The below are reproducers from Issue #123459
+template <typename V>
+struct T {
+ V* q{};
+ T() = default;
+ T(T&& rhs) { q = rhs.q; rhs.q = nullptr;}
+ T& operator=(T&& rhs) { q = rhs.q; rhs.q = nullptr;}
+ void push_back(const V& v) { if (q == nullptr) q = new V(v); }
+ ~T() { delete q; }
+};
+
+T<S> f() {
+ T<S> t;
+ {
+ int a = 1;
+ t.push_back({ &a });
+ }
+ return t; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}
+}
+
+} // namespace return_from_child_block_scope
+
namespace true_negatives_return_expressions {
struct Container { int *x; };
diff --git a/clang/test/Analysis/stackaddrleak.c b/clang/test/Analysis/stackaddrleak.c
index f8101525401b0..95175996e8274 100644
--- a/clang/test/Analysis/stackaddrleak.c
+++ b/clang/test/Analysis/stackaddrleak.c
@@ -68,3 +68,25 @@ int *g_no_lifetime_bound() {
int i = 0;
return f_no_lifetime_bound(&i); // no-warning
}
+
+struct child_stack_context_s {
+ int *p;
+};
+
+struct child_stack_context_s return_child_stack_context() {
+ struct child_stack_context_s s;
+ {
+ int a = 1;
+ s = (struct child_stack_context_s){ &a };
+ }
+ return s; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}
+}
+
+struct child_stack_context_s return_child_stack_context_field() {
+ struct child_stack_context_s s;
+ {
+ int a = 1;
+ s.p = &a;
+ }
+ return s; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}
+}
|
|
@llvm/pr-subscribers-clang-static-analyzer-1 Author: Michael Flanders (Flandini) ChangesFixes #123459. This changes checking of the returned expr to also look for memory regions whose stack frame context was a child of the current stack frame context, e.g., for cases like this given in #123459: Full diff: https://github.com/llvm/llvm-project/pull/126986.diff 3 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index c9df15ceb3b40..2a22e8e10efb0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -274,7 +274,13 @@ class FindStackRegionsSymbolVisitor final : public SymbolVisitor {
void SaveIfEscapes(const MemRegion *MR) {
const StackSpaceRegion *SSR =
MR->getMemorySpace()->getAs<StackSpaceRegion>();
- if (SSR && SSR->getStackFrame() == PoppedStackFrame)
+
+ if (!SSR)
+ return;
+
+ const StackFrameContext *CapturedSFC = SSR->getStackFrame();
+ if (CapturedSFC == PoppedStackFrame ||
+ PoppedStackFrame->isParentOf(CapturedSFC))
EscapingStackRegions.push_back(MR);
}
diff --git a/clang/test/Analysis/stack-addr-ps.cpp b/clang/test/Analysis/stack-addr-ps.cpp
index bf988d0a16959..2e509f358b49f 100644
--- a/clang/test/Analysis/stack-addr-ps.cpp
+++ b/clang/test/Analysis/stack-addr-ps.cpp
@@ -982,6 +982,51 @@ int& ret_local_field_ref() {
}
} //namespace return_address_of_true_positives
+namespace return_from_child_block_scope {
+struct S {
+ int *p;
+};
+
+S return_child_stack_context() {
+ S s;
+ {
+ int a = 1;
+ s = (S){ &a };
+ }
+ return s; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}
+}
+
+S return_child_stack_context_field() {
+ S s;
+ {
+ int a = 1;
+ s.p = &a;
+ }
+ return s; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}
+}
+
+// The below are reproducers from Issue #123459
+template <typename V>
+struct T {
+ V* q{};
+ T() = default;
+ T(T&& rhs) { q = rhs.q; rhs.q = nullptr;}
+ T& operator=(T&& rhs) { q = rhs.q; rhs.q = nullptr;}
+ void push_back(const V& v) { if (q == nullptr) q = new V(v); }
+ ~T() { delete q; }
+};
+
+T<S> f() {
+ T<S> t;
+ {
+ int a = 1;
+ t.push_back({ &a });
+ }
+ return t; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}
+}
+
+} // namespace return_from_child_block_scope
+
namespace true_negatives_return_expressions {
struct Container { int *x; };
diff --git a/clang/test/Analysis/stackaddrleak.c b/clang/test/Analysis/stackaddrleak.c
index f8101525401b0..95175996e8274 100644
--- a/clang/test/Analysis/stackaddrleak.c
+++ b/clang/test/Analysis/stackaddrleak.c
@@ -68,3 +68,25 @@ int *g_no_lifetime_bound() {
int i = 0;
return f_no_lifetime_bound(&i); // no-warning
}
+
+struct child_stack_context_s {
+ int *p;
+};
+
+struct child_stack_context_s return_child_stack_context() {
+ struct child_stack_context_s s;
+ {
+ int a = 1;
+ s = (struct child_stack_context_s){ &a };
+ }
+ return s; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}
+}
+
+struct child_stack_context_s return_child_stack_context_field() {
+ struct child_stack_context_s s;
+ {
+ int a = 1;
+ s.p = &a;
+ }
+ return s; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}
+}
|
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.
LG, thanks!
|
Could you merge this for me? |
|
I want to review this. |
steakhal
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, thanks for your patience!
…frames (llvm#126986) Fixes llvm#123459. This changes checking of the returned expr to also look for memory regions whose stack frame context was a child of the current stack frame context, e.g., for cases like this given in llvm#123459: ``` struct S { int *p; }; S f() { S s; { int a = 1; s.p = &a; } return s; } ```
Fixes #123459.
This changes checking of the returned expr to also look for memory regions whose stack frame context was a child of the current stack frame context, e.g., for cases like this given in #123459: