diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h @@ -78,13 +78,16 @@ const char *description) : BugType(checker, name, categories::LogicError), desc(description) {} + BuiltinBug(class CheckerNameRef checker, const char *name) + : BugType(checker, name, categories::LogicError), desc(name) {} + BuiltinBug(const CheckerBase *checker, const char *name) : BugType(checker, name, categories::LogicError), desc(name) {} StringRef getDescription() const { return desc; } }; -} // end ento namespace +} // namespace ento } // end clang namespace #endif diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -43,6 +43,7 @@ }; DefaultBool ChecksEnabled[CK_NumCheckKinds]; + CheckerNameRef CheckNames[CK_NumCheckKinds]; void checkPreCall(const CallEvent &Call, CheckerContext &C) const; void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; @@ -156,7 +157,8 @@ return; if (!BT_returnstack) BT_returnstack = std::make_unique( - this, "Return of address to stack-allocated memory"); + CheckNames[CK_StackAddrEscapeChecker], + "Return of address to stack-allocated memory"); // Generate a report for this bug. SmallString<128> buf; llvm::raw_svector_ostream os(buf); @@ -195,7 +197,8 @@ continue; if (!BT_capturedstackasync) BT_capturedstackasync = std::make_unique( - this, "Address of stack-allocated memory is captured"); + CheckNames[CK_StackAddrAsyncEscapeChecker], + "Address of stack-allocated memory is captured"); SmallString<128> Buf; llvm::raw_svector_ostream Out(Buf); SourceRange Range = genName(Out, Region, C.getASTContext()); @@ -218,7 +221,8 @@ continue; if (!BT_capturedstackret) BT_capturedstackret = std::make_unique( - this, "Address of stack-allocated memory is captured"); + CheckNames[CK_StackAddrEscapeChecker], + "Address of stack-allocated memory is captured"); SmallString<128> Buf; llvm::raw_svector_ostream Out(Buf); SourceRange Range = genName(Out, Region, C.getASTContext()); @@ -277,7 +281,7 @@ // The CK_CopyAndAutoreleaseBlockObject cast causes the block to be copied // so the stack address is not escaping here. - if (auto *ICE = dyn_cast(RetE)) { + if (const auto *ICE = dyn_cast(RetE)) { if (isa(R) && ICE->getCastKind() == CK_CopyAndAutoreleaseBlockObject) { return; @@ -333,7 +337,8 @@ if (!BT_stackleak) BT_stackleak = std::make_unique( - this, "Stack address stored into global variable", + CheckNames[CK_StackAddrEscapeChecker], + "Stack address stored into global variable", "Stack address was saved into a global variable. " "This is dangerous because the address will become " "invalid after returning from the function"); @@ -371,14 +376,13 @@ #define REGISTER_CHECKER(name) \ void ento::register##name(CheckerManager &Mgr) { \ - StackAddrEscapeChecker *Chk = \ - Mgr.getChecker(); \ + StackAddrEscapeChecker *Chk = Mgr.getChecker(); \ Chk->ChecksEnabled[StackAddrEscapeChecker::CK_##name] = true; \ + Chk->CheckNames[StackAddrEscapeChecker::CK_##name] = \ + Mgr.getCurrentCheckerName(); \ } \ \ - bool ento::shouldRegister##name(const CheckerManager &mgr) { \ - return true; \ - } + bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } REGISTER_CHECKER(StackAddrEscapeChecker) REGISTER_CHECKER(StackAddrAsyncEscapeChecker) diff --git a/clang/test/Analysis/incorrect-checker-names.cpp b/clang/test/Analysis/incorrect-checker-names.cpp --- a/clang/test/Analysis/incorrect-checker-names.cpp +++ b/clang/test/Analysis/incorrect-checker-names.cpp @@ -5,9 +5,16 @@ int* stack_addr_escape_base() { int x = 0; // FIXME: This shouldn't be tied to a modeling checker. - return &x; // expected-warning{{Address of stack memory associated with local variable 'x' returned to caller [core.StackAddrEscapeBase]}} + return &x; // expected-warning{{Address of stack memory associated with local variable 'x' returned to caller [core.StackAddressEscape]}} // expected-note-re@-1{{{{^Address of stack memory associated with local variable 'x' returned to caller$}}}} // Just a regular compiler warning. // expected-warning@-3{{address of stack memory associated with local variable 'x' returned}} } +char const *p; + +void f0() { + char const str[] = "This will change"; + p = str; +} // expected-warning{{Address of stack memory associated with local variable 'str' is still referred to by the global variable 'p' upon returning to the caller. This will be a dangling reference [core.StackAddressEscape]}} +// expected-note@-1{{Address of stack memory associated with local variable 'str' is still referred to by the global variable 'p' upon returning to the caller. This will be a dangling reference}} diff --git a/clang/test/Analysis/incorrect-checker-names.mm b/clang/test/Analysis/incorrect-checker-names.mm --- a/clang/test/Analysis/incorrect-checker-names.mm +++ b/clang/test/Analysis/incorrect-checker-names.mm @@ -1,5 +1,6 @@ -// RUN: %clang_analyze_cc1 -fblocks -verify %s -Wno-objc-root-class \ +// RUN: %clang_analyze_cc1 -fblocks -fobjc-arc -verify %s -Wno-objc-root-class \ // RUN: -analyzer-checker=core \ +// RUN: -analyzer-checker=alpha.core.StackAddressAsyncEscape \ // RUN: -analyzer-checker=nullability \ // RUN: -analyzer-checker=osx @@ -126,3 +127,32 @@ // FIXME: This shouldn't be tied to a modeling checker. write_into_out_param_on_success(&obj); // expected-warning{{Potential leak of an object stored into 'obj' [osx.cocoa.RetainCountBase]}} } + +typedef struct dispatch_queue_s *dispatch_queue_t; +typedef void (^dispatch_block_t)(void); +void dispatch_async(dispatch_queue_t queue, dispatch_block_t block); +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; +extern dispatch_time_t when; + +dispatch_block_t get_leaking_block() { + int leaked_x = 791; + int *p = &leaked_x; + return ^void(void) { + *p = 1; + }; + // expected-warning@-3 {{Address of stack memory associated with local variable 'leaked_x' \ +is captured by a returned block [core.StackAddressEscape]}} +} + +void test_returned_from_func_block_async() { + dispatch_async(queue, get_leaking_block()); + // expected-warning@-1 {{Address of stack memory associated with local variable 'leaked_x' \ +is captured by an asynchronously-executed block [alpha.core.StackAddressAsyncEscape]}} +}