You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[webkit.UncountedLambdaCapturesChecker] Ignore trivial functions and [[clang::noescape]]. (#113845)
This PR makes webkit.UncountedLambdaCapturesChecker ignore trivial
functions as well as the one being passed to an argument with
[[clang::noescape]] attribute. This dramatically reduces the false
positive rate for this checker.
To do this, this PR replaces VisitLambdaExpr in favor of checking
lambdas via VisitDeclRefExpr and VisitCallExpr. The idea is that if a
lambda is defined but never called or stored somewhere, then capturing
whatever variable in such a lambda is harmless.
VisitCallExpr explicitly looks for direct invocation of lambdas and
registers its DeclRefExpr to be ignored in VisitDeclRefExpr. If a lambda
is being passed to a function, it checks whether its argument is
annotated with [[clang::noescape]]. If it's not annotated such, it
checks captures for their safety.
Because WTF::switchOn could not be annotated with [[clang::noescape]] as
function type parameters are variadic template function so we hard-code
this function into the checker.
Finally, this PR also converts the accompanying test to use -verify and
adds a bunch of tests.
// CHECK: warning: Implicitly captured raw-pointer 'ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]
23
+
RefCountable* ref_countable = make_obj();
24
+
auto foo1 = [ref_countable](){
25
+
// expected-warning@-1{{Captured raw-pointer 'ref_countable' to ref-counted / CheckedPtr capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}}
26
+
ref_countable->method();
27
+
};
28
+
auto foo2 = [&ref_countable](){
29
+
// expected-warning@-1{{Captured raw-pointer 'ref_countable' to ref-counted / CheckedPtr capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}}
30
+
ref_countable->method();
31
+
};
32
+
auto foo3 = [&](){
33
+
ref_countable->method();
34
+
// expected-warning@-1{{Implicitly captured raw-pointer 'ref_countable' to ref-counted / CheckedPtr capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}}
35
+
ref_countable = nullptr;
36
+
};
37
+
38
+
auto foo4 = [=](){
39
+
ref_countable->method();
40
+
// expected-warning@-1{{Implicitly captured raw-pointer 'ref_countable' to ref-counted / CheckedPtr capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}}
41
+
};
42
+
43
+
call(foo1);
44
+
call(foo2);
45
+
call(foo3);
46
+
call(foo4);
18
47
19
48
// Confirm that the checker respects [[clang::suppress]].
20
49
RefCountable* suppressed_ref_countable = nullptr;
21
50
[[clang::suppress]] auto foo5 = [suppressed_ref_countable](){};
22
-
// CHECK-NOT: warning: Captured raw-pointer 'suppressed_ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]
51
+
// no warning.
52
+
call(foo5);
23
53
}
24
54
25
55
voidreferences() {
26
56
RefCountable automatic;
27
57
RefCountable& ref_countable_ref = automatic;
58
+
auto foo1 = [ref_countable_ref](){ ref_countable_ref.constMethod(); };
59
+
// expected-warning@-1{{Captured reference 'ref_countable_ref' to ref-counted / CheckedPtr capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}}
60
+
auto foo2 = [&ref_countable_ref](){ ref_countable_ref.method(); };
61
+
// expected-warning@-1{{Captured reference 'ref_countable_ref' to ref-counted / CheckedPtr capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}}
62
+
auto foo3 = [&](){ ref_countable_ref.method(); };
63
+
// expected-warning@-1{{Implicitly captured reference 'ref_countable_ref' to ref-counted / CheckedPtr capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}}
64
+
auto foo4 = [=](){ ref_countable_ref.constMethod(); };
65
+
// expected-warning@-1{{Implicitly captured reference 'ref_countable_ref' to ref-counted / CheckedPtr capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}}
28
66
29
-
auto foo1 = [ref_countable_ref](){};
30
-
// CHECK: warning: Captured reference 'ref_countable_ref' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]
31
-
auto foo2 = [&ref_countable_ref](){};
32
-
// CHECK: warning: Captured reference 'ref_countable_ref' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]
33
-
auto foo3 = [&](){ (void) ref_countable_ref; };
34
-
// CHECK: warning: Implicitly captured reference 'ref_countable_ref' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]
35
-
auto foo4 = [=](){ (void) ref_countable_ref; };
36
-
// CHECK: warning: Implicitly captured reference 'ref_countable_ref' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker]
// expected-warning@-1{{Implicitly captured raw-pointer 'otherObj' to ref-counted / CheckedPtr capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}}
119
+
});
120
+
([&] {
121
+
someObj->method();
122
+
})();
123
+
}
124
+
125
+
voidlambda_capture_param(RefCountable* obj) {
126
+
auto someLambda = [&] {
127
+
obj->method();
128
+
};
129
+
someLambda();
130
+
someLambda();
131
+
}
132
+
133
+
structRefCountableWithLambdaCapturingThis {
134
+
voidref() const;
135
+
voidderef() const;
136
+
voidnonTrivial();
137
+
138
+
voidmethod_captures_this_safe() {
139
+
auto lambda = [&]() {
140
+
nonTrivial();
141
+
};
142
+
lambda();
143
+
}
144
+
145
+
voidmethod_captures_this_unsafe() {
146
+
auto lambda = [&]() {
147
+
nonTrivial();
148
+
// expected-warning@-1{{Implicitly captured raw-pointer 'this' to ref-counted / CheckedPtr capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}}
0 commit comments