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