aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2012-08-29 01:11:59 +0000
committerJordan Rose <jordan_rose@apple.com>2012-08-29 01:11:59 +0000
commit73212dff6437d409e0c1b779fdcac2f4f98ca8b0 (patch)
treead0323fde92f022b1ca9bd2346c8c6c7f3c7ee5b
parent8a64bb58c3b24d7d97895e435bbc0965c99bd3be (diff)
[analyzer] C++ objects returned on the stack may be wrapped in ExprWithCleanups.
In C++, objects being returned on the stack are actually copy-constructed into the return value. That means that when a temporary is returned, it still has to be destroyed, i.e. the returned expression will be wrapped in an ExprWithCleanups node. Our "returning stack memory" checker needs to look through this node to see if we really are returning an object by value. PR13722 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162817 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp6
-rw-r--r--test/Analysis/temporaries.cpp30
2 files changed, 35 insertions, 1 deletions
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index b1f4f623e2..6a4b2d9ef8 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -118,6 +118,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
const Expr *RetE = RS->getRetValue();
if (!RetE)
return;
+ RetE = RetE->IgnoreParens();
const LocationContext *LCtx = C.getLocationContext();
SVal V = C.getState()->getSVal(RetE, LCtx);
@@ -144,7 +145,10 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
return;
// Returning a record by value is fine. (In this case, the returned
- // expression will be a copy-constructor.)
+ // expression will be a copy-constructor, possibly wrapped in an
+ // ExprWithCleanups node.)
+ if (const ExprWithCleanups *Cleanup = dyn_cast<ExprWithCleanups>(RetE))
+ RetE = Cleanup->getSubExpr();
if (isa<CXXConstructExpr>(RetE) && RetE->getType()->isRecordType())
return;
diff --git a/test/Analysis/temporaries.cpp b/test/Analysis/temporaries.cpp
new file mode 100644
index 0000000000..df1ab5a30b
--- /dev/null
+++ b/test/Analysis/temporaries.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -verify -w %s
+
+struct Trivial {
+ Trivial(int x) : value(x) {}
+ int value;
+};
+
+struct NonTrivial : public Trivial {
+ NonTrivial(int x) : Trivial(x) {}
+ ~NonTrivial();
+};
+
+
+Trivial getTrivial() {
+ return Trivial(42); // no-warning
+}
+
+const Trivial &getTrivialRef() {
+ return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'struct Trivial' returned to caller}}
+}
+
+
+NonTrivial getNonTrivial() {
+ return NonTrivial(42); // no-warning
+}
+
+const NonTrivial &getNonTrivialRef() {
+ return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'struct NonTrivial' returned to caller}}
+}
+