summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/StaticAnalyzer/Checkers/Checkers.td4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp27
-rw-r--r--clang/test/Analysis/stack-capture-leak-arc.mm16
-rw-r--r--clang/test/Analysis/stack-capture-leak-no-arc.mm2
4 files changed, 44 insertions, 5 deletions
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index be8b1494c87..e510e84e938 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -188,6 +188,10 @@ def DynamicTypeChecker : Checker<"DynamicTypeChecker">,
HelpText<"Check for cases where the dynamic and the static type of an object are unrelated.">,
DescFile<"DynamicTypeChecker.cpp">;
+def StackAddrAsyncEscapeChecker : Checker<"StackAddressAsyncEscape">,
+ HelpText<"Check that addresses to stack memory do not escape the function">,
+ DescFile<"StackAddrEscapeChecker.cpp">;
+
} // end "alpha.core"
let ParentPackage = Nullability in {
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 94cdd306800..25975628c55 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -37,6 +37,14 @@ class StackAddrEscapeChecker
mutable std::unique_ptr<BuiltinBug> BT_capturedstackret;
public:
+ enum CheckKind {
+ CK_StackAddrEscapeChecker,
+ CK_StackAddrAsyncEscapeChecker,
+ CK_NumCheckKinds
+ };
+
+ DefaultBool ChecksEnabled[CK_NumCheckKinds];
+
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
void checkEndFunction(CheckerContext &Ctx) const;
@@ -225,6 +233,8 @@ void StackAddrEscapeChecker::checkReturnedBlockCaptures(
void StackAddrEscapeChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
+ if (!ChecksEnabled[CK_StackAddrAsyncEscapeChecker])
+ return;
if (!Call.isGlobalCFunction("dispatch_after") &&
!Call.isGlobalCFunction("dispatch_async"))
return;
@@ -237,6 +247,8 @@ void StackAddrEscapeChecker::checkPreCall(const CallEvent &Call,
void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
CheckerContext &C) const {
+ if (!ChecksEnabled[CK_StackAddrEscapeChecker])
+ return;
const Expr *RetE = RS->getRetValue();
if (!RetE)
@@ -277,6 +289,9 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
}
void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const {
+ if (!ChecksEnabled[CK_StackAddrEscapeChecker])
+ return;
+
ProgramStateRef State = Ctx.getState();
// Iterate over all bindings to global variables and see if it contains
@@ -346,6 +361,12 @@ void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const {
}
}
-void ento::registerStackAddrEscapeChecker(CheckerManager &Mgr) {
- Mgr.registerChecker<StackAddrEscapeChecker>();
-}
+#define REGISTER_CHECKER(name) \
+ void ento::register##name(CheckerManager &Mgr) { \
+ StackAddrEscapeChecker *Chk = \
+ Mgr.registerChecker<StackAddrEscapeChecker>(); \
+ Chk->ChecksEnabled[StackAddrEscapeChecker::CK_##name] = true; \
+ }
+
+REGISTER_CHECKER(StackAddrEscapeChecker)
+REGISTER_CHECKER(StackAddrAsyncEscapeChecker)
diff --git a/clang/test/Analysis/stack-capture-leak-arc.mm b/clang/test/Analysis/stack-capture-leak-arc.mm
index 498f7e9b714..1ffee934c89 100644
--- a/clang/test/Analysis/stack-capture-leak-arc.mm
+++ b/clang/test/Analysis/stack-capture-leak-arc.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core -fblocks -fobjc-arc -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,alpha.core.StackAddressAsyncEscape -fblocks -fobjc-arc -verify %s
typedef struct dispatch_queue_s *dispatch_queue_t;
typedef void (^dispatch_block_t)(void);
@@ -7,6 +7,7 @@ typedef long dispatch_once_t;
void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
typedef long dispatch_time_t;
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
+void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);
extern dispatch_queue_t queue;
extern dispatch_once_t *predicate;
@@ -173,3 +174,16 @@ void test_no_leaks_on_semaphore_pattern() {
// Wait for the asynchronous work to finish
dispatch_semaphore_wait(semaphore, 1000);
}
+
+void test_dispatch_barrier_sync() {
+ int buf[16];
+ for (int n = 0; n < 16; ++n) {
+ int *ptr = &buf[n];
+ // FIXME: Should not warn. The dispatch_barrier_sync() call ensures
+ // that the block does not outlive 'buf'.
+ dispatch_async(queue, ^{ // expected-warning{{Address of stack memory associated with local variable 'buf' is captured by an asynchronously-executed block}}
+ (void)ptr;
+ });
+ }
+ dispatch_barrier_sync(queue, ^{});
+}
diff --git a/clang/test/Analysis/stack-capture-leak-no-arc.mm b/clang/test/Analysis/stack-capture-leak-no-arc.mm
index e14df09d55d..33829f52e72 100644
--- a/clang/test/Analysis/stack-capture-leak-no-arc.mm
+++ b/clang/test/Analysis/stack-capture-leak-no-arc.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,alpha.core.StackAddressAsyncEscape -fblocks -verify %s
typedef struct dispatch_queue_s *dispatch_queue_t;
typedef void (^dispatch_block_t)(void);
OpenPOWER on IntegriCloud