diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp index 019e81f91400d..027bf780273cc 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -22,6 +22,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/raw_ostream.h" using namespace clang; using namespace ento; @@ -247,6 +248,7 @@ class FindStackRegionsSymbolVisitor final : public SymbolVisitor { CheckerContext &Ctxt; const StackFrameContext *PoppedStackFrame; SmallVectorImpl &EscapingStackRegions; + llvm::SmallPtrSet VisitedRegions; public: explicit FindStackRegionsSymbolVisitor( @@ -258,6 +260,9 @@ class FindStackRegionsSymbolVisitor final : public SymbolVisitor { bool VisitSymbol(SymbolRef sym) override { return true; } bool VisitMemRegion(const MemRegion *MR) override { + if (!VisitedRegions.insert(MR).second) + return true; + SaveIfEscapes(MR); if (const BlockDataRegion *BDR = MR->getAs()) diff --git a/clang/test/Analysis/stackaddrleak.c b/clang/test/Analysis/stackaddrleak.c index 95175996e8274..96bd4e4ea19e5 100644 --- a/clang/test/Analysis/stackaddrleak.c +++ b/clang/test/Analysis/stackaddrleak.c @@ -1,5 +1,5 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -verify -std=c99 -Dbool=_Bool -Wno-bool-conversion %s -// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -verify -x c++ -Wno-bool-conversion %s +// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,unix.Malloc -verify -std=c99 -Dbool=_Bool -Wno-bool-conversion %s +// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,unix.Malloc -verify -x c++ -Wno-bool-conversion %s typedef __INTPTR_TYPE__ intptr_t; char const *p; @@ -90,3 +90,14 @@ struct child_stack_context_s return_child_stack_context_field() { } return s; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}} } + +// Returns an 'int' block taking an 'int'. +int (^copy_self_referencing_block(void))(int) { + // It is important that the 'fib' block captures itself. + __block int (^fib)(int) = ^(int n) { + if (n <= 1) return n; + return fib(n - 1) + fib(n - 2); + }; + return fib; // no-crash when copying a self-referencing 'fib' + // expected-warning-re@-1 {{Address of stack-allocated block declared on line {{[0-9]+}} is captured by a returned block}} +}