diff options
-rw-r--r-- | lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp | 28 | ||||
-rw-r--r-- | test/Analysis/inline.c | 19 |
2 files changed, 37 insertions, 10 deletions
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp index d071ef8c1f..8c76cc523d 100644 --- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -113,7 +113,7 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion * } void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, - CheckerContext &C) const { + CheckerContext &C) const { const Expr *RetE = RS->getRetValue(); if (!RetE) @@ -122,18 +122,26 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, SVal V = C.getState()->getSVal(RetE, C.getLocationContext()); const MemRegion *R = V.getAsRegion(); - if (!R || !R->hasStackStorage()) - return; + if (!R) + return; - if (R->hasStackStorage()) { - // Automatic reference counting automatically copies blocks. - if (C.getASTContext().getLangOptions().ObjCAutoRefCount && - isa<BlockDataRegion>(R)) - return; + const StackSpaceRegion *SS = + dyn_cast_or_null<StackSpaceRegion>(R->getMemorySpace()); + + if (!SS) + return; - EmitStackError(C, R, RetE); + // Return stack memory in an ancestor stack frame is fine. + const StackFrameContext *SFC = SS->getStackFrame(); + if (SFC != C.getLocationContext()->getCurrentStackFrame()) return; - } + + // Automatic reference counting automatically copies blocks. + if (C.getASTContext().getLangOptions().ObjCAutoRefCount && + isa<BlockDataRegion>(R)) + return; + + EmitStackError(C, R, RetE); } void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const { diff --git a/test/Analysis/inline.c b/test/Analysis/inline.c index de807fb3aa..9e64d33690 100644 --- a/test/Analysis/inline.c +++ b/test/Analysis/inline.c @@ -58,3 +58,22 @@ void test_factorial_2() { *p = 0xDEADBEEF; // no-warning } } + +// Test that returning stack memory from a parent stack frame does +// not trigger a warning. +static char *return_buf(char *buf) { + return buf + 10; +} + +void test_return_stack_memory_ok() { + char stack_buf[100]; + char *pos = return_buf(stack_buf); + (void) pos; +} + +char *test_return_stack_memory_bad() { + char stack_buf[100]; + char *x = stack_buf; + return x; // expected-warning {{stack memory associated}} +} + |