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.micha...@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.micha...@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.micha...@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; }; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits