Skip to content

Commit d519e7d

Browse files
committed
[analyzer] Fix inf recursion in StackAddrEscapeChecker for self referencing blocks (llvm#169208)
Objective-C blocks are like lambdas. They have captures, just like lambdas. However, they can also implicitly capture themselves unlike lambdas. This means that when walking the captures of a block, we may end up in infinite recursion. This is not possible with lambdas, but happened in practice with blocks downstream. In this patch, I just use a set to keep track of the visited MemRegions. Note that theoretically, there is nothing preventing usual lambdas or functors from falling for the same trap, but probably slightly more difficult to do so. You would likely need a pointer to itself, etc. I'll not speculate here. This inf recursion was likely caused by llvm#126620, released in clang-21. rdar://162215172 (cherry picked from commit 30b1d14)
1 parent 629ce99 commit d519e7d

File tree

2 files changed

+18
-2
lines changed

2 files changed

+18
-2
lines changed

clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
2323
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
2424
#include "llvm/ADT/STLExtras.h"
25+
#include "llvm/ADT/SmallPtrSet.h"
2526
#include "llvm/Support/raw_ostream.h"
2627
using namespace clang;
2728
using namespace ento;
@@ -256,6 +257,7 @@ class FindStackRegionsSymbolVisitor final : public SymbolVisitor {
256257
CheckerContext &Ctxt;
257258
const StackFrameContext *PoppedStackFrame;
258259
SmallVectorImpl<const MemRegion *> &EscapingStackRegions;
260+
llvm::SmallPtrSet<const MemRegion *, 16> VisitedRegions;
259261

260262
public:
261263
explicit FindStackRegionsSymbolVisitor(
@@ -267,6 +269,9 @@ class FindStackRegionsSymbolVisitor final : public SymbolVisitor {
267269
bool VisitSymbol(SymbolRef sym) override { return true; }
268270

269271
bool VisitMemRegion(const MemRegion *MR) override {
272+
if (!VisitedRegions.insert(MR).second)
273+
return true;
274+
270275
SaveIfEscapes(MR);
271276

272277
if (const BlockDataRegion *BDR = MR->getAs<BlockDataRegion>())

clang/test/Analysis/stackaddrleak.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -verify -std=c99 -Dbool=_Bool -Wno-bool-conversion %s
2-
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -verify -x c++ -Wno-bool-conversion %s
1+
// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,unix.Malloc -verify -std=c99 -Dbool=_Bool -Wno-bool-conversion %s
2+
// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,unix.Malloc -verify -x c++ -Wno-bool-conversion %s
33

44
typedef __INTPTR_TYPE__ intptr_t;
55
char const *p;
@@ -90,3 +90,14 @@ struct child_stack_context_s return_child_stack_context_field() {
9090
}
9191
return s; // expected-warning {{Address of stack memory associated with local variable 'a' returned to caller}}
9292
}
93+
94+
// Returns an 'int' block taking an 'int'.
95+
int (^copy_self_referencing_block(void))(int) {
96+
// It is important that the 'fib' block captures itself.
97+
__block int (^fib)(int) = ^(int n) {
98+
if (n <= 1) return n;
99+
return fib(n - 1) + fib(n - 2);
100+
};
101+
return fib; // no-crash when copying a self-referencing 'fib'
102+
// expected-warning-re@-1 {{Address of stack-allocated block declared on line {{[0-9]+}} is captured by a returned block}}
103+
}

0 commit comments

Comments
 (0)