diff options
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); |