clang 24.0.0git
RawPtrRefLambdaCapturesChecker.cpp
Go to the documentation of this file.
1//=======- RawPtrRefLambdaCapturesChecker.cpp --------------------*- C++ -*-==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ASTUtils.h"
10#include "DiagOutputUtils.h"
11#include "PtrTypesSemantics.h"
19#include <optional>
20
21using namespace clang;
22using namespace ento;
23
24namespace {
25class RawPtrRefLambdaCapturesChecker
26 : public Checker<check::ASTDecl<TranslationUnitDecl>> {
27private:
28 BugType Bug;
29 mutable BugReporter *BR = nullptr;
30 TrivialFunctionAnalysis TFA;
31
32protected:
33 const std::unique_ptr<PtrRefSafetyModel> Model;
34
35public:
36 RawPtrRefLambdaCapturesChecker(const char *description,
37 std::unique_ptr<PtrRefSafetyModel> Model)
38 : Bug(this, description, "WebKit coding guidelines"),
39 Model(std::move(Model)) {}
40
41 std::optional<bool> isUnsafePtr(QualType QT) const {
42 return isUnsafePtrForStorage(*Model, QT);
43 }
44 bool isPtrType(const std::string &Name) const {
45 return Model->isPtrType(Name);
46 }
47
48 void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
49 BugReporter &BRArg) const {
50 BR = &BRArg;
51
52 // The calls to checkAST* from AnalysisConsumer don't
53 // visit template instantiations or lambda classes. We
54 // want to visit those, so we make our own RecursiveASTVisitor.
55 struct LocalVisitor : DynamicRecursiveASTVisitor {
56 const RawPtrRefLambdaCapturesChecker *Checker;
57 llvm::DenseSet<const DeclRefExpr *> DeclRefExprsToIgnore;
58 llvm::DenseSet<const LambdaExpr *> LambdasToIgnore;
59 llvm::DenseSet<const ValueDecl *> ProtectedThisDecls;
60 llvm::DenseSet<const CallExpr *> CallToIgnore;
61 llvm::DenseSet<const CXXConstructExpr *> ConstructToIgnore;
62 llvm::DenseMap<const VarDecl *, SmallVector<const LambdaExpr *>>
63 LambdaOwnerMap;
64
65 QualType ClsType;
66
67 explicit LocalVisitor(const RawPtrRefLambdaCapturesChecker *Checker)
68 : Checker(Checker) {
69 assert(Checker);
70 ShouldVisitTemplateInstantiations = true;
71 ShouldVisitImplicitCode = false;
72 }
73
74 bool TraverseDecl(Decl *D) override {
75 // A template pattern is checked through its instantiations, which are
76 // traversed from the TemplateDecl itself. In the pattern the callee of
77 // a call may still be an unresolved overload set, so whether a lambda
78 // argument can escape isn't known, and a lambda in a pattern which is
79 // never instantiated is never used. Don't enter it at all.
80 if (D && !isa<TemplateDecl>(D) && D->isTemplated())
81 return true;
83 }
84
85 bool TraverseCXXConstructorDecl(CXXConstructorDecl *Ctor) override {
86 llvm::SaveAndRestore SavedDecl(ClsType);
87 ClsType = Ctor->getThisType();
88 return DynamicRecursiveASTVisitor::TraverseCXXConstructorDecl(Ctor);
89 }
90
91 bool TraverseCXXDestructorDecl(CXXDestructorDecl *Dtor) override {
92 llvm::SaveAndRestore SavedDecl(ClsType);
93 ClsType = Dtor->getThisType();
94 return DynamicRecursiveASTVisitor::TraverseCXXDestructorDecl(Dtor);
95 }
96
97 bool TraverseCXXMethodDecl(CXXMethodDecl *CXXMD) override {
98 llvm::SaveAndRestore SavedDecl(ClsType);
99 // 'this' in the body of a lambda's call operator refers to the object
100 // of the enclosing method, so keep the class of that method. This
101 // matters for the instantiations of a generic lambda, which are
102 // traversed as declarations rather than as a body.
103 if (CXXMD->isInstance() && !CXXMD->getParent()->isLambda())
104 ClsType = CXXMD->getThisType();
105 return DynamicRecursiveASTVisitor::TraverseCXXMethodDecl(CXXMD);
106 }
107
108 bool TraverseObjCMethodDecl(ObjCMethodDecl *OCMD) override {
109 llvm::SaveAndRestore SavedDecl(ClsType);
110 if (OCMD && OCMD->isInstanceMethod()) {
111 if (auto *ImplParamDecl = OCMD->getSelfDecl())
112 ClsType = ImplParamDecl->getType();
113 }
114 return DynamicRecursiveASTVisitor::TraverseObjCMethodDecl(OCMD);
115 }
116
117 bool VisitTypedefDecl(TypedefDecl *TD) override {
118 if (auto *RTC = Checker->Model->retainTypeChecker())
119 RTC->visitTypedef(TD);
120 return true;
121 }
122
123 bool shouldCheckThis() {
124 // A pointer to the object itself is not a loan on its interior.
125 if (Checker->Model->checksForInteriorDestruction())
126 return false;
127 auto result =
128 !ClsType.isNull() ? Checker->isUnsafePtr(ClsType) : std::nullopt;
129 return result && *result;
130 }
131
132 bool VisitLambdaExpr(LambdaExpr *L) override {
133 if (LambdasToIgnore.contains(L))
134 return true;
135 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
136 ClsType);
137 return true;
138 }
139
140 bool TraverseLambdaExpr(LambdaExpr *L) override {
142 if (!FTD)
143 return DynamicRecursiveASTVisitor::TraverseLambdaExpr(L);
144 // The body of a generic lambda is the pattern of its call operator,
145 // but it is reached from the LambdaExpr as a statement, so TraverseDecl
146 // never gets to skip it. Visit the lambda itself, traverse the capture
147 // initializers, which are evaluated in the enclosing scope, and then
148 // the call operator, of which the pattern is skipped like any other and
149 // the instantiations are traversed. The initializers are traversed as
150 // expressions because the variable of an init capture is declared in
151 // the pattern.
152 if (!VisitLambdaExpr(L))
153 return false;
154 for (unsigned I = 0, N = L->capture_size(); I != N; ++I) {
155 if (!(L->capture_begin() + I)->isExplicit())
156 continue;
157 if (auto *Init = L->capture_init_begin()[I];
158 Init && !TraverseStmt(Init))
159 return false;
160 }
161 return TraverseDecl(FTD);
162 }
163
164 bool VisitVarDecl(VarDecl *VD) override {
165 auto *Init = VD->getInit();
166 if (!Init)
167 return true;
168 if (auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts())) {
169 LambdasToIgnore.insert(L); // Evaluate lambdas in VisitDeclRefExpr.
170 return true;
171 }
172 if (!VD->hasLocalStorage())
173 return true;
174 if (auto *E = dyn_cast<ExprWithCleanups>(Init))
175 Init = E->getSubExpr();
176 if (auto *E = dyn_cast<CXXBindTemporaryExpr>(Init))
177 Init = E->getSubExpr();
178 if (auto *CE = dyn_cast<CallExpr>(Init)) {
179 if (auto *Callee = CE->getDirectCallee()) {
180 auto FnName = safeGetName(Callee);
181 unsigned ArgCnt = CE->getNumArgs();
182 if (FnName == "makeScopeExit" && ArgCnt == 1) {
183 auto *Arg = CE->getArg(0);
184 if (auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
185 Arg = E->getSubExpr();
186 if (auto *L = dyn_cast<LambdaExpr>(Arg))
187 addLambdaOwner(VD, CE, L);
188 } else if (FnName == "makeVisitor") {
189 for (unsigned ArgIndex = 0; ArgIndex < ArgCnt; ++ArgIndex) {
190 auto *Arg = CE->getArg(ArgIndex);
191 if (auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
192 Arg = E->getSubExpr();
193 if (auto *L = dyn_cast<LambdaExpr>(Arg))
194 addLambdaOwner(VD, CE, L);
195 }
196 }
197 }
198 } else if (auto *CE = dyn_cast<CXXConstructExpr>(Init)) {
199 if (auto *Ctor = CE->getConstructor()) {
200 if (auto *Cls = Ctor->getParent()) {
201 auto FnName = safeGetName(Cls);
202 unsigned ArgCnt = CE->getNumArgs();
203 if (FnName == "ScopeExit" && ArgCnt == 1) {
204 auto *Arg = CE->getArg(0);
205 if (auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
206 Arg = E->getSubExpr();
207 if (auto *L = dyn_cast<LambdaExpr>(Arg))
208 addLambdaOwner(VD, CE, L);
209 }
210 }
211 }
212 }
213 return true;
214 }
215
216 void addLambdaOwner(VarDecl *VD, CallExpr *CE, LambdaExpr *L) {
217 auto result = LambdaOwnerMap.insert(
218 std::make_pair(VD, SmallVector<const LambdaExpr *>{L}));
219 if (!result.second)
220 result.first->second.push_back(L);
221 CallToIgnore.insert(CE);
222 LambdasToIgnore.insert(L);
223 }
224
225 void addLambdaOwner(VarDecl *VD, CXXConstructExpr *CE, LambdaExpr *L) {
226 auto result = LambdaOwnerMap.insert(
227 std::make_pair(VD, SmallVector<const LambdaExpr *>{L}));
228 if (!result.second)
229 result.first->second.push_back(L);
230 ConstructToIgnore.insert(CE);
231 LambdasToIgnore.insert(L);
232 }
233
234 bool VisitExplicitCastExpr(ExplicitCastExpr *CE) override {
235 // Discarding a variable with (void) doesn't let a lambda escape.
236 if (CE->getCastKind() != CK_ToVoid)
237 return true;
238 if (auto *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr()->IgnoreParens()))
239 DeclRefExprsToIgnore.insert(DRE);
240 return true;
241 }
242
243 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
244 if (DeclRefExprsToIgnore.contains(DRE))
245 return true;
246 auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl());
247 if (!VD)
248 return true;
249 if (auto It = LambdaOwnerMap.find(VD); It != LambdaOwnerMap.end()) {
250 for (auto *L : It->second) {
251 Checker->visitLambdaExpr(
252 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
253 }
254 return true;
255 }
256 auto *Init = VD->getInit();
257 if (!Init)
258 return true;
259 auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts());
260 if (!L)
261 return true;
262 LambdasToIgnore.insert(L);
263 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
264 ClsType);
265 return true;
266 }
267
268 bool shouldTreatAllArgAsNoEscape(FunctionDecl *FDecl) {
269 std::string PreviousName = safeGetName(FDecl);
270 for (auto *Decl = FDecl->getParent(); Decl; Decl = Decl->getParent()) {
271 if (!isa<NamespaceDecl>(Decl) && !isa<CXXRecordDecl>(Decl))
272 return false;
273 if (auto *NS = dyn_cast<NamespaceDecl>(Decl); NS && NS->isInline())
274 continue;
275 auto Name = safeGetName(Decl);
276 // WTF::switchOn(T, F... f) is a variadic template function and
277 // couldn't be annotated with NOESCAPE. We hard code it here to
278 // workaround that.
279 if (Name == "WTF" && PreviousName == "switchOn")
280 return true;
281 if (Name == "std") {
282 // Treat every argument of functions in std::ranges as noescape.
283 if (PreviousName == "ranges")
284 return true;
285 // Treat every argument of call_once as noescape even though only
286 // the second argument is lambda since we can't add annotation to
287 // a std function.
288 if (PreviousName == "call_once")
289 return true;
290 }
291 PreviousName = Name;
292 }
293 return false;
294 }
295
296 bool VisitCXXConstructExpr(CXXConstructExpr *CE) override {
297 if (ConstructToIgnore.contains(CE))
298 return true;
299 if (auto *Callee = CE->getConstructor()) {
300 unsigned ArgIndex = 0;
301 for (auto *Param : Callee->parameters()) {
302 if (ArgIndex >= CE->getNumArgs())
303 return true;
304 auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
305 if (auto *L = findLambdaInArg(Arg)) {
306 LambdasToIgnore.insert(L);
307 if (!Param->hasAttr<NoEscapeAttr>())
308 Checker->visitLambdaExpr(
309 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
310 }
311 ++ArgIndex;
312 }
313 }
314 return true;
315 }
316
317 bool VisitCallExpr(CallExpr *CE) override {
318 if (CallToIgnore.contains(CE))
319 return true;
320 checkCalleeLambda(CE);
321 if (auto *Callee = CE->getDirectCallee()) {
322 if (isVisitFunction(CE, Callee))
323 return true;
324 checkParameters(CE, Callee);
325 } else if (auto *CalleeE = CE->getCallee()) {
326 if (auto *DRE = dyn_cast<DeclRefExpr>(CalleeE->IgnoreParenCasts())) {
327 if (auto *Callee = dyn_cast_or_null<FunctionDecl>(DRE->getDecl()))
328 checkParameters(CE, Callee);
329 }
330 }
331 return true;
332 }
333
334 bool isVisitFunction(CallExpr *CallExpr, FunctionDecl *FnDecl) {
335 bool IsVisitFn = safeGetName(FnDecl) == "visit";
336 if (!IsVisitFn)
337 return false;
338 bool ArgCnt = CallExpr->getNumArgs();
339 if (!ArgCnt)
340 return false;
341 auto *Ns = FnDecl->getParent();
342 if (!Ns)
343 return false;
344 auto NsName = safeGetName(Ns);
345 if (NsName != "WTF" && NsName != "std")
346 return false;
347 auto *Arg = CallExpr->getArg(0);
348 if (!Arg)
349 return false;
350 auto *DRE = dyn_cast<DeclRefExpr>(Arg->IgnoreParenCasts());
351 if (!DRE)
352 return false;
353 auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
354 if (!VD)
355 return false;
356 if (!LambdaOwnerMap.contains(VD))
357 return false;
358 DeclRefExprsToIgnore.insert(DRE);
359 return true;
360 }
361
362 void checkParameters(CallExpr *CE, FunctionDecl *Callee) {
363 unsigned ArgIndex = isa<CXXOperatorCallExpr>(CE);
364 bool TreatAllArgsAsNoEscape = shouldTreatAllArgAsNoEscape(Callee);
365 for (auto *Param : Callee->parameters()) {
366 if (ArgIndex >= CE->getNumArgs())
367 return;
368 auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
369 if (auto *L = findLambdaInArg(Arg)) {
370 LambdasToIgnore.insert(L);
371 if (!Param->hasAttr<NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
372 Checker->visitLambdaExpr(
373 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
374 }
375 ++ArgIndex;
376 }
377 }
378
379 LambdaExpr *findLambdaInArg(Expr *E) {
380 if (auto *Lambda = dyn_cast_or_null<LambdaExpr>(E))
381 return Lambda;
382 auto *TempExpr = dyn_cast_or_null<CXXBindTemporaryExpr>(E);
383 if (!TempExpr)
384 return nullptr;
385 E = TempExpr->getSubExpr()->IgnoreParenCasts();
386 if (!E)
387 return nullptr;
388 if (auto *Lambda = dyn_cast<LambdaExpr>(E))
389 return Lambda;
390 auto *CE = dyn_cast_or_null<CXXConstructExpr>(E);
391 if (!CE || !CE->getNumArgs())
392 return nullptr;
393 auto *CtorArg = CE->getArg(0)->IgnoreParenCasts();
394 if (!CtorArg)
395 return nullptr;
396 auto *InnerCE = dyn_cast_or_null<CXXConstructExpr>(CtorArg);
397 if (InnerCE && InnerCE->getNumArgs())
398 CtorArg = InnerCE->getArg(0)->IgnoreParenCasts();
399 auto updateIgnoreList = [&] {
400 ConstructToIgnore.insert(CE);
401 if (InnerCE)
402 ConstructToIgnore.insert(InnerCE);
403 };
404 if (auto *Lambda = dyn_cast<LambdaExpr>(CtorArg)) {
405 updateIgnoreList();
406 return Lambda;
407 }
408 if (auto *TempExpr = dyn_cast<CXXBindTemporaryExpr>(CtorArg)) {
409 E = TempExpr->getSubExpr()->IgnoreParenCasts();
410 if (auto *Lambda = dyn_cast<LambdaExpr>(E)) {
411 updateIgnoreList();
412 return Lambda;
413 }
414 }
415 auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
416 if (!DRE)
417 return nullptr;
418 auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl());
419 if (!VD)
420 return nullptr;
421 auto *Init = VD->getInit();
422 if (!Init)
423 return nullptr;
424 if (auto *Lambda = dyn_cast<LambdaExpr>(Init)) {
425 DeclRefExprsToIgnore.insert(DRE);
426 updateIgnoreList();
427 return Lambda;
428 }
429 return nullptr;
430 }
431
432 void checkCalleeLambda(CallExpr *CE) {
433 auto *Callee = CE->getCallee();
434 if (!Callee)
435 return;
436 Callee = Callee->IgnoreParenCasts();
437 if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Callee)) {
438 Callee = MTE->getSubExpr();
439 if (!Callee)
440 return;
441 Callee = Callee->IgnoreParenCasts();
442 }
443 if (auto *L = dyn_cast<LambdaExpr>(Callee)) {
444 LambdasToIgnore.insert(L); // Calling a lambda upon creation is safe.
445 return;
446 }
447 auto *DRE = dyn_cast<DeclRefExpr>(Callee->IgnoreParenCasts());
448 if (!DRE)
449 return;
450 auto *MD = dyn_cast_or_null<CXXMethodDecl>(DRE->getDecl());
451 if (!MD || CE->getNumArgs() < 1)
452 return;
453 auto *Arg = CE->getArg(0)->IgnoreParenCasts();
454 if (auto *L = dyn_cast_or_null<LambdaExpr>(Arg)) {
455 LambdasToIgnore.insert(L); // Calling a lambda upon creation is safe.
456 return;
457 }
458 auto *ArgRef = dyn_cast<DeclRefExpr>(Arg);
459 if (!ArgRef)
460 return;
461 auto *VD = dyn_cast_or_null<VarDecl>(ArgRef->getDecl());
462 if (!VD)
463 return;
464 auto *Init = VD->getInit();
465 if (!Init)
466 return;
467 auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts());
468 if (!L)
469 return;
470 DeclRefExprsToIgnore.insert(ArgRef);
471 LambdasToIgnore.insert(L);
472 }
473
474 bool hasProtectedThis(const LambdaExpr *L) {
475 for (const LambdaCapture &OtherCapture : L->captures()) {
476 if (!OtherCapture.capturesVariable())
477 continue;
478 if (auto *ValueDecl = OtherCapture.getCapturedVar()) {
479 if (declProtectsThis(ValueDecl)) {
480 ProtectedThisDecls.insert(ValueDecl);
481 return true;
482 }
483 }
484 }
485 return false;
486 }
487
488 bool declProtectsThis(const ValueDecl *ValueDecl) const {
489 auto *VD = dyn_cast<VarDecl>(ValueDecl);
490 if (!VD)
491 return false;
492 auto *Init = VD->getInit();
493 if (!Init)
494 return false;
495 const Expr *Arg = Init->IgnoreParenCasts();
496 do {
497 if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg))
498 Arg = BTE->getSubExpr()->IgnoreParenCasts();
499 if (auto *CE = dyn_cast<CXXConstructExpr>(Arg)) {
500 auto *Ctor = CE->getConstructor();
501 if (!Ctor)
502 return false;
503 auto ArgClsTy = dyn_cast_or_null<CXXRecordDecl>(Ctor->getParent());
504 if (Checker->Model->isSafePtr(ArgClsTy) && CE->getNumArgs()) {
505 Arg = CE->getArg(0)->IgnoreParenCasts();
506 continue;
507 }
508 if (auto *Type = ClsType.getTypePtrOrNull()) {
509 if (auto *CXXR = Type->getPointeeCXXRecordDecl()) {
510 if (CXXR == Ctor->getParent() && Ctor->isMoveConstructor() &&
511 CE->getNumArgs() == 1) {
512 Arg = CE->getArg(0)->IgnoreParenCasts();
513 continue;
514 }
515 }
516 }
517 return false;
518 }
519 if (auto *CE = dyn_cast<CallExpr>(Arg)) {
520 if (auto *Callee = CE->getDirectCallee()) {
521 if ((isStdOrWTFMove(Callee) || isCtorOfSafePtr(Callee)) &&
522 CE->getNumArgs() == 1) {
523 Arg = CE->getArg(0)->IgnoreParenCasts();
524 continue;
525 }
526 }
527 }
528 if (auto *OpCE = dyn_cast<CXXOperatorCallExpr>(Arg)) {
529 auto OpCode = OpCE->getOperator();
530 if (OpCode == OO_Star || OpCode == OO_Amp) {
531 auto *Callee = OpCE->getDirectCallee();
532 if (!Callee)
533 return false;
534 auto clsName = safeGetName(Callee->getParent());
535 if (!Checker->isPtrType(clsName) || !OpCE->getNumArgs())
536 return false;
537 Arg = OpCE->getArg(0)->IgnoreParenCasts();
538 continue;
539 }
540 }
541 if (auto *UO = dyn_cast<UnaryOperator>(Arg)) {
542 auto OpCode = UO->getOpcode();
543 if (OpCode == UO_Deref || OpCode == UO_AddrOf) {
544 Arg = UO->getSubExpr()->IgnoreParenCasts();
545 continue;
546 }
547 }
548 break;
549 } while (Arg);
550 if (auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
551 auto *Decl = DRE->getDecl();
552 if (auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(Decl)) {
553 auto kind = ImplicitParam->getParameterKind();
554 return kind == ImplicitParamKind::ObjCSelf ||
555 kind == ImplicitParamKind::CXXThis;
556 }
557 return ProtectedThisDecls.contains(Decl);
558 }
559 return isa<CXXThisExpr>(Arg);
560 }
561 };
562
563 LocalVisitor visitor(this);
564 if (auto *RTC = Model->retainTypeChecker())
565 RTC->visitTranslationUnitDecl(TUD);
566 visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
567 }
568
569 void visitLambdaExpr(const LambdaExpr *L, bool shouldCheckThis,
570 const QualType T,
571 bool ignoreParamVarDecl = false) const {
572 if (BR->getSourceManager().isInSystemHeader(L->getBeginLoc()))
573 return;
574 // FIXME: This check is unsound. Destruction can happen in three places,
575 // and a capture is only safe when all three are trivial: the lambda's
576 // body, the callee that receives it, and the scope that creates it.
577 if (TFA.isTrivial(L->getBody()))
578 return;
579 for (auto [C, CaptureInit] :
580 llvm::zip_equal(L->captures(), L->capture_inits())) {
581 if (C.capturesVariable()) {
582 ValueDecl *CapturedVar = C.getCapturedVar();
583 if (ignoreParamVarDecl && isa<ParmVarDecl>(CapturedVar))
584 continue;
585 if (auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(CapturedVar)) {
586 auto kind = ImplicitParam->getParameterKind();
587 if ((kind == ImplicitParamKind::ObjCSelf ||
588 kind == ImplicitParamKind::CXXThis) &&
589 !shouldCheckThis)
590 continue;
591 }
592 QualType CapturedVarQualType = CapturedVar->getType();
593 auto IsUncountedPtr = isUnsafePtr(CapturedVarQualType);
594 if (C.getCaptureKind() == LCK_ByCopy &&
595 CapturedVarQualType->isReferenceType())
596 continue;
597 if (!IsUncountedPtr || !*IsUncountedPtr)
598 continue;
599 const Expr *Origin = nullptr;
600 if (Model->checksForInteriorDestruction()) {
601 if (!CaptureInit)
602 continue;
603 if (isCaptureOriginSafeToEscape(CaptureInit, Origin,
604 CapturedVarQualType))
605 continue;
606 }
607 reportBug(C, CapturedVar, CapturedVarQualType, L, Origin);
608 } else if (C.capturesThis() && shouldCheckThis) {
609 if (ignoreParamVarDecl)
610 continue;
611 reportBugOnThisPtr(C, T);
612 }
613 }
614 }
615
616 bool isCaptureOriginSafeToEscape(const Expr *CaptureInit, const Expr *&Origin,
617 QualType SinkType) const {
618 return tryToFindPtrOrigin(
619 CaptureInit, /*StopAtFirstRefCountedObj=*/false,
620 Model->checksForInteriorDestruction(),
621
622 // A smart pointer, even if safe, has shorter lifetime than an
623 // escaping lambda, so we do not treat it as a guarantee of safety.
624 /*isSafePtr=*/[](const clang::CXXRecordDecl *) { return false; },
625 /*isSafePtrType=*/[](const clang::QualType) { return false; },
626
627 // A global has longer lifetime, and can be safe.
628 /*isSafeGlobalDecl=*/
629 [&](const clang::Decl *D) {
630 return Model->isSafeDecl(D, BR->getSourceManager());
631 },
632
633 [&](const clang::Expr *CaptureOrigin, bool IsSafe,
634 bool /*OriginDependsOnFullExpressionTemporary*/,
635 bool PtrIsLifetimeBoundToOrigin) {
636 if (!CaptureOrigin)
637 return true;
638 if (isa<CXXThisExpr>(CaptureOrigin))
639 return true;
640 if (IsSafe)
641 return true;
642 if (Model->isSafeExpr(CaptureOrigin, PtrIsLifetimeBoundToOrigin,
643 SinkType, /*SinkMayEscape=*/true))
644 return true;
645 if (!Origin)
646 Origin = CaptureOrigin;
647 return false;
648 });
649 }
650
651 void reportBug(const LambdaCapture &Capture, ValueDecl *CapturedVar,
652 const QualType T, const LambdaExpr *L,
653 const Expr *Origin) const {
654 assert(CapturedVar);
655
656 auto Location = Capture.getLocation();
657 if (isa<ImplicitParamDecl>(CapturedVar) && !Location.isValid())
658 Location = L->getBeginLoc();
659
660 SmallString<100> Buf;
661 llvm::raw_svector_ostream Os(Buf);
662
663 if (Capture.isExplicit())
664 Os << "Captured ";
665 else
666 Os << "Implicitly captured ";
667 Os << "variable ";
668 printQuotedQualifiedName(Os, CapturedVar);
669
670 bool IsUnsafePtr = CapturedVar->getType() == T;
671 if (IsUnsafePtr)
672 Os << " is a ";
673 else
674 Os << " contains a ";
675 if (Model->checksForInteriorDestruction())
676 Model->describeHazard(Os, Origin, T);
677 else
678 printPointer(Os, T.getTypePtrOrNull());
679
680 PathDiagnosticLocation BSLoc(Location, BR->getSourceManager());
681 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
682 BR->emitReport(std::move(Report));
683 }
684
685 void reportBugOnThisPtr(const LambdaCapture &Capture,
686 const QualType T) const {
687 SmallString<100> Buf;
688 llvm::raw_svector_ostream Os(Buf);
689
690 if (Capture.isExplicit()) {
691 Os << "Captured ";
692 } else {
693 Os << "Implicitly captured ";
694 }
695
696 Os << "variable 'this' is a raw pointer to " << Model->typeName();
697 if (auto *RD = T->getPointeeCXXRecordDecl()) {
698 Os << " ";
700 }
701
702 PathDiagnosticLocation BSLoc(Capture.getLocation(), BR->getSourceManager());
703 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
704 BR->emitReport(std::move(Report));
705 }
706
707 void printPointer(llvm::raw_svector_ostream &Os, const Type *T) const {
708 if (Model->retainTypeChecker()) {
709 // An OS object may be spelled as an id qualified by an OS_-prefixed
710 // protocol; print that protocol name.
711 if (auto *ObjCPtr = dyn_cast<ObjCObjectPointerType>(T)) {
712 for (ObjCProtocolDecl *P : ObjCPtr->quals()) {
713 if (const auto *II = P->getIdentifier()) {
714 auto Name = II->getName();
715 if (Name.starts_with("OS_")) {
716 Os << Model->typeName() << " ";
718 return;
719 }
720 }
721 }
722 }
723 // Retain/OS types are frequently spelled through a typedef (e.g.
724 // CFXXXRef); print the typedef name rather than desugaring.
725 if (!isa<ObjCObjectPointerType>(T) && T->getAs<TypedefType>()) {
726 auto Typedef = T->getAs<TypedefType>();
727 assert(Typedef);
728 Os << Model->typeName() << " ";
729 printQuotedQualifiedName(Os, Typedef->getDecl());
730 return;
731 }
732 }
735 Os << (IsPtr ? "raw pointer" : "raw reference") << " to ";
736 Os << Model->typeName();
737
738 if (auto *RD = T->getPointeeType()->getAsRecordDecl()) {
739 Os << " ";
741 } else if (auto *ObjCDecl = getObjCDeclFromObjCPtr(T)) {
742 Os << " ";
743 printQuotedQualifiedName(Os, ObjCDecl);
744 }
745 }
746};
747
748class UncountedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
749public:
750 UncountedLambdaCapturesChecker()
751 : RawPtrRefLambdaCapturesChecker("Lambda capture of uncounted variable",
753};
754
755class UncheckedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
756public:
757 UncheckedLambdaCapturesChecker()
758 : RawPtrRefLambdaCapturesChecker("Lambda capture of unchecked variable",
760};
761
762class UnretainedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
763public:
764 UnretainedLambdaCapturesChecker()
765 : RawPtrRefLambdaCapturesChecker("Lambda capture of unretained "
766 "variables",
768};
769
770class UnborrowedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
771public:
772 UnborrowedLambdaCapturesChecker()
773 : RawPtrRefLambdaCapturesChecker("Lambda capture of a loan on a "
774 "CanBorrow object",
776};
777
778} // namespace
779
780void ento::registerUncountedLambdaCapturesChecker(CheckerManager &Mgr) {
781 Mgr.registerChecker<UncountedLambdaCapturesChecker>();
782}
783
784bool ento::shouldRegisterUncountedLambdaCapturesChecker(
785 const CheckerManager &mgr) {
786 return true;
787}
788
789void ento::registerUncheckedLambdaCapturesChecker(CheckerManager &Mgr) {
790 Mgr.registerChecker<UncheckedLambdaCapturesChecker>();
791}
792
793bool ento::shouldRegisterUncheckedLambdaCapturesChecker(
794 const CheckerManager &mgr) {
795 return true;
796}
797
798void ento::registerUnretainedLambdaCapturesChecker(CheckerManager &Mgr) {
799 Mgr.registerChecker<UnretainedLambdaCapturesChecker>();
800}
801
802bool ento::shouldRegisterUnretainedLambdaCapturesChecker(
803 const CheckerManager &mgr) {
804 return true;
805}
806
807void ento::registerUnborrowedLambdaCapturesChecker(CheckerManager &Mgr) {
808 Mgr.registerChecker<UnborrowedLambdaCapturesChecker>();
809}
810
811bool ento::shouldRegisterUnborrowedLambdaCapturesChecker(
812 const CheckerManager &mgr) {
813 return true;
814}
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
Defines the SourceManager interface.
Expr * getArg(unsigned Arg)
Return the specified argument.
Definition ExprCXX.h:1696
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Definition ExprCXX.h:1616
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
Definition ExprCXX.h:1693
bool isMoveConstructor(unsigned &TypeQuals) const
Determine whether this constructor is a move constructor (C++11 [class.copy]p3), which can be used to...
Definition DeclCXX.cpp:3063
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2296
QualType getThisType() const
Return the type of the this pointer.
Definition DeclCXX.cpp:2859
bool isInstance() const
Definition DeclCXX.h:2180
bool isLambda() const
Determine whether this class describes a lambda function object.
Definition DeclCXX.h:1028
FunctionTemplateDecl * getDependentLambdaCallOperator() const
Retrieve the dependent lambda call operator of the closure type if this is a templated closure type.
Definition DeclCXX.cpp:1739
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3216
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3195
Expr * getCallee()
Definition Expr.h:3159
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3203
CastKind getCastKind() const
Definition Expr.h:3789
Expr * getSubExpr()
Definition Expr.h:3795
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2108
ValueDecl * getDecl()
Definition Expr.h:1383
bool isTemplated() const
Determine whether this declaration is a templated entity (whether it is.
Definition DeclBase.cpp:308
virtual bool TraverseDecl(MaybeConst< Decl > *D)
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3134
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3125
capture_iterator capture_begin() const
Retrieve an iterator pointing to the first lambda capture.
Definition ExprCXX.cpp:1395
Stmt * getBody() const
Retrieve the body of the lambda.
Definition ExprCXX.cpp:1378
unsigned capture_size() const
Determine the number of captures in this lambda.
Definition ExprCXX.h:2054
llvm::iterator_range< capture_init_iterator > capture_inits()
Retrieve the initialization expressions for this lambda's captures.
Definition ExprCXX.h:2088
SourceLocation getBeginLoc() const LLVM_READONLY
Definition ExprCXX.h:2187
capture_range captures() const
Retrieve this lambda's captures.
Definition ExprCXX.cpp:1403
capture_init_iterator capture_init_begin()
Retrieve the first initialization argument for this lambda expression (which initializes the first ca...
Definition ExprCXX.h:2099
CXXRecordDecl * getLambdaClass() const
Retrieve the class that corresponds to the lambda.
Definition ExprCXX.cpp:1432
ImplicitParamDecl * getSelfDecl() const
Definition DeclObjC.h:421
bool isInstanceMethod() const
Definition DeclObjC.h:429
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
const Type * getTypePtrOrNull() const
Definition TypeBase.h:8582
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isReferenceType() const
Definition TypeBase.h:8839
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
Definition Type.cpp:2080
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:885
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9431
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition Type.cpp:786
QualType getType() const
Definition Decl.h:725
const Expr * getInit() const
Definition Decl.h:1393
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Definition Decl.h:1192
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
Definition Checker.h:565
constexpr bool isPtrType(PrimType T)
Definition PrimType.h:57
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
Top level wrappers for InstallAPI frontend operations.
bool isCtorOfSafePtr(const clang::FunctionDecl *F)
bool isa(CodeGen::Address addr)
Definition Address.h:330
std::unique_ptr< PtrRefSafetyModel > makeBorrowSafetyModel()
std::unique_ptr< PtrRefSafetyModel > makeCheckedPtrSafetyModel()
@ LCK_ByCopy
Capturing by copy (a.k.a., by value)
Definition Lambda.h:36
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
std::optional< bool > isUnsafePtrForStorage(const PtrRefSafetyModel &Model, QualType T, bool IgnoreARC=false)
Applies the memory-management exemptions that hold for a variable, member, or lambda capture (but not...
const FunctionProtoType * T
std::string safeGetName(const T *ASTNode)
Definition ASTUtils.h:109
ObjCInterfaceDecl * getObjCDeclFromObjCPtr(const Type *TypePtr)
Definition ASTUtils.cpp:639
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
bool isStdOrWTFMove(const clang::FunctionDecl *F)
std::unique_ptr< PtrRefSafetyModel > makeRefPtrSafetyModel()
bool tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj, bool FollowLifetimeBound, std::function< bool(const clang::CXXRecordDecl *)> isSafePtr, std::function< bool(const clang::QualType)> isSafePtrType, std::function< bool(const clang::Decl *)> isSafeGlobalDecl, std::function< bool(const clang::Expr *, bool, bool, bool)> callback)
This function de-facto defines a set of transformations that we consider safe (in heuristical sense).
Definition ASTUtils.cpp:478
std::unique_ptr< PtrRefSafetyModel > makeRetainPtrSafetyModel()