[clang] [analyzer] StackAddrEscapeChecker: also check return for child stack frames (PR #126986)
Michael Flanders via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 12 15:15:50 PST 2025
https://github.com/Flandini created https://github.com/llvm/llvm-project/pull/126986
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:
```
struct S { int *p; };
S f() {
S s;
{
int a = 1;
s.p = &a;
}
return s;
}
```
>From 3ca1363268deebb716c6481d1229eff210267b66 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 12 Feb 2025 17:09:07 -0600
Subject: [PATCH 1/3] [analyzer] StackAddrEscapeChecker: also check ret exprs
for child stack frames
---
.../Checkers/StackAddrEscapeChecker.cpp | 7 +++++-
clang/test/Analysis/stackaddrleak.c | 22 +++++++++++++++++++
2 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index c9df15ceb3b40..e6263e2edd552 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -274,7 +274,12 @@ 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/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}}
+}
>From 926edaada4cda523d1cf3f5556fd1fc8ea4dd272 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 12 Feb 2025 17:10:40 -0600
Subject: [PATCH 2/3] formatting
---
clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index e6263e2edd552..2a22e8e10efb0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -279,7 +279,8 @@ class FindStackRegionsSymbolVisitor final : public SymbolVisitor {
return;
const StackFrameContext *CapturedSFC = SSR->getStackFrame();
- if (CapturedSFC == PoppedStackFrame || PoppedStackFrame->isParentOf(CapturedSFC))
+ if (CapturedSFC == PoppedStackFrame ||
+ PoppedStackFrame->isParentOf(CapturedSFC))
EscapingStackRegions.push_back(MR);
}
>From 1cbfc19e0e70354b341e30d159af8a127e544d30 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 12 Feb 2025 17:10:52 -0600
Subject: [PATCH 3/3] C++ test cases
---
clang/test/Analysis/stack-addr-ps.cpp | 45 +++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
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; };
More information about the cfe-commits
mailing list