Skip to content

Commit 436504c

Browse files
authored
[webkit.UncountedLambdaCapturesChecker] Treat every argument of std::ranges functions as noescape. (#138995)
Functions in std::ranges namespace does not store the lambada passed-in as an arugment in heap so treat such an argument as if it has [[noescape]] in the WebKit lambda capture checker so that we don't emit warnings for capturing raw pointers or references to smart-pointer capable objects.
1 parent 984475d commit 436504c

File tree

2 files changed

+45
-3
lines changed

2 files changed

+45
-3
lines changed

clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,22 @@ class RawPtrRefLambdaCapturesChecker
127127
return true;
128128
}
129129

130-
// WTF::switchOn(T, F... f) is a variadic template function and couldn't
131-
// be annotated with NOESCAPE. We hard code it here to workaround that.
132130
bool shouldTreatAllArgAsNoEscape(FunctionDecl *Decl) {
133131
auto *NsDecl = Decl->getParent();
134132
if (!NsDecl || !isa<NamespaceDecl>(NsDecl))
135133
return false;
136-
return safeGetName(NsDecl) == "WTF" && safeGetName(Decl) == "switchOn";
134+
// WTF::switchOn(T, F... f) is a variadic template function and couldn't
135+
// be annotated with NOESCAPE. We hard code it here to workaround that.
136+
if (safeGetName(NsDecl) == "WTF" && safeGetName(Decl) == "switchOn")
137+
return true;
138+
// Treat every argument of functions in std::ranges as noescape.
139+
if (safeGetName(NsDecl) == "ranges") {
140+
if (auto *OuterDecl = NsDecl->getParent();
141+
OuterDecl && isa<NamespaceDecl>(OuterDecl) &&
142+
safeGetName(OuterDecl) == "std")
143+
return true;
144+
}
145+
return false;
137146
}
138147

139148
bool VisitCXXConstructExpr(CXXConstructExpr *CE) override {

clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ T&& move(T& t) {
99
return static_cast<T&&>(t);
1010
}
1111

12+
namespace ranges {
13+
14+
template<typename IteratorType, typename CallbackType>
15+
void for_each(IteratorType first, IteratorType last, CallbackType callback) {
16+
for (auto it = first; !(it == last); ++it)
17+
callback(*it);
18+
}
19+
20+
}
21+
1222
}
1323

1424
namespace WTF {
@@ -416,3 +426,26 @@ void capture_copy_in_lambda(CheckedObj& checked) {
416426
ptr->method();
417427
});
418428
}
429+
430+
class Iterator {
431+
public:
432+
Iterator(void* array, unsigned long sizeOfElement, unsigned int index);
433+
Iterator(const Iterator&);
434+
Iterator& operator=(const Iterator&);
435+
bool operator==(const Iterator&);
436+
437+
Iterator& operator++();
438+
void* operator*();
439+
440+
private:
441+
void* current { nullptr };
442+
unsigned long sizeOfElement { 0 };
443+
};
444+
445+
void ranges_for_each(RefCountable* obj) {
446+
int array[] = { 1, 2, 3, 4, 5 };
447+
std::ranges::for_each(Iterator(array, sizeof(*array), 0), Iterator(array, sizeof(*array), 5), [&](void* item) {
448+
obj->method();
449+
++(*static_cast<unsigned*>(item));
450+
});
451+
}

0 commit comments

Comments
 (0)