clang 24.0.0git
RawPtrRefLocalVarsChecker.cpp
Go to the documentation of this file.
1//=======- UncountedLocalVarsChecker.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"
14#include "clang/AST/Decl.h"
15#include "clang/AST/DeclCXX.h"
18#include "clang/AST/StmtObjC.h"
25#include <optional>
26
27using namespace clang;
28using namespace ento;
29
30namespace {
31
32// FIXME: should be defined by anotations in the future
33bool isRefcountedStringsHack(const VarDecl *V) {
34 assert(V);
35 auto safeClass = [](const std::string &className) {
36 return className == "String" || className == "AtomString" ||
37 className == "UniquedString" || className == "Identifier";
38 };
39 QualType QT = V->getType();
40 auto *T = QT.getTypePtr();
41 if (auto *CXXRD = T->getAsCXXRecordDecl()) {
42 if (safeClass(safeGetName(CXXRD)))
43 return true;
44 }
45 if (T->isPointerType() || T->isReferenceType()) {
46 if (auto *CXXRD = T->getPointeeCXXRecordDecl()) {
47 if (safeClass(safeGetName(CXXRD)))
48 return true;
49 }
50 }
51 return false;
52}
53
54struct GuardianVisitor : DynamicRecursiveASTVisitor {
55 const VarDecl *Guardian{nullptr};
56 bool GuardianIsRawPtrOrRef{false};
57
58 explicit GuardianVisitor(const VarDecl *Guardian,
59 bool GuardianIsRawPtrOrRef = false)
60 : Guardian(Guardian), GuardianIsRawPtrOrRef(GuardianIsRawPtrOrRef) {
61 assert(Guardian);
62 }
63
64 bool VisitBinaryOperator(BinaryOperator *BO) override {
65 if (BO->isAssignmentOp()) {
66 if (auto *VarRef = dyn_cast<DeclRefExpr>(BO->getLHS())) {
67 if (VarRef->getDecl() == Guardian)
68 return false;
69 }
70 }
71 return true;
72 }
73
74 bool VisitCXXConstructExpr(CXXConstructExpr *CE) override {
75 auto *Ctor = CE->getConstructor();
76 if (!Ctor)
77 return false;
78 unsigned ArgIndex = 0;
79 for (auto *Arg : CE->arguments()) {
80 ParmVarDecl *Parm = nullptr;
81 if (ArgIndex < Ctor->getNumParams())
82 Parm = Ctor->getParamDecl(ArgIndex);
83 if (mutatesGuardian(Arg, Parm))
84 return false;
85 ArgIndex++;
86 }
87 return true;
88 }
89
90 bool VisitCallExpr(CallExpr *CE) override {
91 auto *Callee = CE->getDirectCallee();
92 if (!Callee)
93 return false;
94 if (isPtrConversion(Callee))
95 return true;
96 if (auto *Method = dyn_cast<CXXMethodDecl>(Callee)) {
97 if (isGetterOfSafePtr(Method).value_or(false))
98 return true;
99 }
100 // For a member operator call, the first argument is the implicit object.
101 auto *OperatorMethod = dyn_cast<CXXMethodDecl>(Callee);
102 if (!isa<CXXOperatorCallExpr>(CE) || !OperatorMethod ||
103 !OperatorMethod->isImplicitObjectMemberFunction())
104 OperatorMethod = nullptr;
105 unsigned ArgIndex = 0;
106 unsigned ArgOffset = OperatorMethod ? 1 : 0;
107 for (auto *Arg : CE->arguments()) {
108 ParmVarDecl *Parm = nullptr;
109 if (ArgIndex >= ArgOffset) {
110 unsigned ParmIndex = ArgIndex - ArgOffset;
111 if (ParmIndex < Callee->getNumParams())
112 Parm = Callee->getParamDecl(ParmIndex);
113 } else if (OperatorMethod->isConst()) {
114 ArgIndex++;
115 continue;
116 }
117 if (mutatesGuardian(Arg, Parm))
118 return false;
119 ArgIndex++;
120 }
121 return true;
122 }
123
124 bool VisitCXXMemberCallExpr(CXXMemberCallExpr *MCE) override {
125 if (GuardianIsRawPtrOrRef)
126 return true;
127 auto *Method = MCE->getMethodDecl();
128 auto ObjType = MCE->getObjectType();
129 if (ObjType.isConstQualified())
130 return true;
131 auto *ThisArg = MCE->getImplicitObjectArgument()->IgnoreParenCasts();
132 if (auto *VarRef = dyn_cast<DeclRefExpr>(ThisArg)) {
133 if (!isa<CXXConversionDecl>(Method) && VarRef->getDecl() == Guardian)
134 return false;
135 }
136 return true;
137 }
138
139private:
140 bool mutatesGuardian(const Expr *Arg, const ParmVarDecl *ParmDecl) {
141 Arg = Arg->IgnoreParenCasts();
142 auto ArgType = ParmDecl ? ParmDecl->getType() : Arg->getType();
143 bool IsAddressOf = false;
144 if (auto *UO = dyn_cast<UnaryOperator>(Arg);
145 UO && UO->getOpcode() == UO_AddrOf) {
146 Arg = UO->getSubExpr()->IgnoreParenCasts();
147 IsAddressOf = true;
148 }
149 auto *VarRef = dyn_cast<DeclRefExpr>(Arg);
150 if (!VarRef || VarRef->getDecl() != Guardian)
151 return false;
152 if (GuardianIsRawPtrOrRef && !Guardian->getType()->isAnyPointerType())
153 return false;
154 if (IsAddressOf) {
155 if (!ArgType->isPointerType())
156 return false;
157 return !ArgType->getPointeeType().isConstQualified();
158 }
159 if (GuardianIsRawPtrOrRef) {
160 if (!ArgType->isReferenceType())
161 return false;
162 return !ArgType.getNonReferenceType().isConstQualified();
163 }
164 return !ArgType.getNonReferenceType().isConstQualified();
165 }
166};
167
168bool isGuardedScopeEmbeddedInGuardianScope(const VarDecl *Guarded,
169 const VarDecl *MaybeGuardian) {
170 assert(Guarded);
171 assert(MaybeGuardian);
172
173 if (!MaybeGuardian->isLocalVarDecl())
174 return false;
175
176 const CompoundStmt *guardiansClosestCompStmtAncestor = nullptr;
177
178 ASTContext &ctx = MaybeGuardian->getASTContext();
179
180 for (DynTypedNodeList guardianAncestors = ctx.getParents(*MaybeGuardian);
181 !guardianAncestors.empty();
182 guardianAncestors = ctx.getParents(
183 *guardianAncestors
184 .begin()) // FIXME - should we handle all of the parents?
185 ) {
186 for (auto &guardianAncestor : guardianAncestors) {
187 if (auto *CStmtParentAncestor = guardianAncestor.get<CompoundStmt>()) {
188 guardiansClosestCompStmtAncestor = CStmtParentAncestor;
189 break;
190 }
191 }
192 if (guardiansClosestCompStmtAncestor)
193 break;
194 }
195
196 if (!guardiansClosestCompStmtAncestor)
197 return false;
198
199 // We need to skip the first CompoundStmt to avoid situation when guardian is
200 // defined in the same scope as guarded variable.
201 const CompoundStmt *FirstCompondStmt = nullptr;
202 for (DynTypedNodeList guardedVarAncestors = ctx.getParents(*Guarded);
203 !guardedVarAncestors.empty();
204 guardedVarAncestors = ctx.getParents(
205 *guardedVarAncestors
206 .begin()) // FIXME - should we handle all of the parents?
207 ) {
208 for (auto &guardedVarAncestor : guardedVarAncestors) {
209 if (auto *CStmtAncestor = guardedVarAncestor.get<CompoundStmt>()) {
210 if (!FirstCompondStmt) {
211 FirstCompondStmt = CStmtAncestor;
212 continue;
213 }
214 if (CStmtAncestor == guardiansClosestCompStmtAncestor) {
215 GuardianVisitor guardianVisitor(MaybeGuardian);
216 auto *GuardedScope = const_cast<CompoundStmt *>(FirstCompondStmt);
217 return guardianVisitor.TraverseCompoundStmt(GuardedScope);
218 }
219 }
220 }
221 }
222
223 return false;
224}
225
226// Returns the fast enumeration statement whose element is declared as V as in
227// "for (T *V in Collection)".
228static const ObjCForCollectionStmt *
229findObjCForCollectionStmtOfElement(const VarDecl *V) {
230 ASTContext &Ctx = V->getASTContext();
231 for (auto &VarParent : Ctx.getParents(*V)) {
232 auto *DS = VarParent.get<DeclStmt>();
233 if (!DS || !DS->isSingleDecl())
234 continue;
235 for (auto &DeclStmtParent : Ctx.getParents(*DS)) {
236 auto *FCS = DeclStmtParent.get<ObjCForCollectionStmt>();
237 if (FCS && FCS->getElement() == DS)
238 return FCS;
239 }
240 }
241 return nullptr;
242}
243
244static const VarDecl *findAssignedVar(const Expr *DestExpr) {
245 while (DestExpr) {
246 DestExpr = DestExpr->IgnoreParenCasts();
247 if (auto *DRE = dyn_cast<DeclRefExpr>(DestExpr))
248 return dyn_cast_or_null<VarDecl>(DRE->getDecl());
249 if (auto *UO = dyn_cast<UnaryOperator>(DestExpr);
250 UO && UO->getOpcode() == UO_Deref) {
251 DestExpr = UO->getSubExpr();
252 continue;
253 }
254 if (auto *ASE = dyn_cast<ArraySubscriptExpr>(DestExpr)) {
255 DestExpr = ASE->getBase();
256 continue;
257 }
258 return nullptr;
259 }
260 return nullptr;
261}
262
263class RawPtrRefLocalVarsChecker
264 : public Checker<check::ASTDecl<TranslationUnitDecl>> {
265 BugType Bug;
266 EnsureFunctionAnalysis EFA;
267
268protected:
269 mutable BugReporter *BR;
270 const std::unique_ptr<PtrRefSafetyModel> Model;
271
272public:
273 RawPtrRefLocalVarsChecker(const char *description,
274 std::unique_ptr<PtrRefSafetyModel> Model)
275 : Bug(this, description, "WebKit coding guidelines"),
276 Model(std::move(Model)) {}
277
278 std::optional<bool> isUnsafePtr(QualType T) const {
279 return isUnsafePtrForStorage(*Model, T);
280 }
281
282 void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
283 BugReporter &BRArg) const {
284 BR = &BRArg;
285
286 // The calls to checkAST* from AnalysisConsumer don't
287 // visit template instantiations or lambda classes. We
288 // want to visit those, so we make our own RecursiveASTVisitor.
289 struct LocalVisitor : DynamicRecursiveASTVisitor {
290 const RawPtrRefLocalVarsChecker *Checker;
291 Decl *DeclWithIssue{nullptr};
292
293 TrivialFunctionAnalysis TFA;
294
295 explicit LocalVisitor(const RawPtrRefLocalVarsChecker *Checker)
296 : Checker(Checker) {
297 assert(Checker);
298 ShouldVisitTemplateInstantiations = true;
299 ShouldVisitImplicitCode = false;
300 }
301
302 bool TraverseDecl(Decl *D) override {
303 // A template pattern is checked through its instantiations, which are
304 // traversed from the TemplateDecl itself. In the pattern the callee of
305 // a call may still be an unresolved overload set and the type of an
306 // expression may still be dependent, neither of which can be reasoned
307 // about, so don't enter it at all.
308 if (D && !isa<TemplateDecl>(D) && D->isTemplated())
309 return true;
310 llvm::SaveAndRestore SavedDecl(DeclWithIssue);
311 if (D && (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)))
312 DeclWithIssue = D;
314 }
315
316 bool TraverseLambdaExpr(LambdaExpr *L) override {
318 if (!FTD)
319 return DynamicRecursiveASTVisitor::TraverseLambdaExpr(L);
320 // The body of a generic lambda is the pattern of its call operator,
321 // but it is reached from the LambdaExpr as a statement, so TraverseDecl
322 // never gets to skip it. Traverse the capture initializers, which are
323 // evaluated in the enclosing scope, and then the call operator itself,
324 // of which the pattern is skipped like any other and the instantiations
325 // are traversed. Going through TraverseDecl also makes an instantiation
326 // the decl with the issue, so that a guardian is looked up in it rather
327 // than in the pattern. The initializers are traversed as expressions
328 // because the variable of an init capture is declared in the pattern.
329 for (unsigned I = 0, N = L->capture_size(); I != N; ++I) {
330 if (!(L->capture_begin() + I)->isExplicit())
331 continue;
332 if (auto *Init = L->capture_init_begin()[I];
333 Init && !TraverseStmt(Init))
334 return false;
335 }
336 return TraverseDecl(FTD);
337 }
338
339 bool VisitTypedefDecl(TypedefDecl *TD) override {
340 if (auto *RTC = Checker->Model->retainTypeChecker())
341 RTC->visitTypedef(TD);
342 return true;
343 }
344
345 bool VisitVarDecl(VarDecl *V) override {
346 auto *Init = V->getInit();
347 if (V->isLocalVarDecl())
348 Checker->visitVarDecl(V, V->getType(), Init, DeclWithIssue);
349 return true;
350 }
351
352 bool VisitBinaryOperator(BinaryOperator *BO) override {
353 if (BO->isAssignmentOp()) {
354 if (Checker->Model->recognizesIndirectStores()) {
355 if (auto *V = findAssignedVar(BO->getLHS()))
356 Checker->visitVarDecl(V, BO->getLHS()->getType(), BO->getRHS(),
357 DeclWithIssue);
358 } else if (auto *VarRef = dyn_cast<DeclRefExpr>(BO->getLHS())) {
359 if (auto *V = dyn_cast<VarDecl>(VarRef->getDecl()))
360 Checker->visitVarDecl(V, V->getType(), BO->getRHS(),
361 DeclWithIssue);
362 }
363 }
364 return true;
365 }
366
367 bool TraverseIfStmt(IfStmt *IS) override {
368 if (IS->getConditionVariable()) {
369 // This code does not check the condition variable in the "else"
370 // statement since getConditionVariable returns nullptr when there
371 // is a condition defined after ";" as in "if (auto foo = ~; !foo)".
372 // If this semantics change, we should check it in "else" as well.
373 if (auto *Then = IS->getThen(); !Then || TFA.isTrivial(Then)) {
374 if (auto *Else = IS->getElse(); Else && !TFA.isTrivial(Else))
375 return TraverseStmt(Else);
376 return true;
377 }
378 }
379 if (!TFA.isTrivial(IS))
380 return DynamicRecursiveASTVisitor::TraverseIfStmt(IS);
381 return true;
382 }
383
384 bool TraverseForStmt(ForStmt *FS) override {
385 if (!TFA.isTrivial(FS))
386 return DynamicRecursiveASTVisitor::TraverseForStmt(FS);
387 return true;
388 }
389
390 bool TraverseCXXForRangeStmt(CXXForRangeStmt *FRS) override {
391 if (!TFA.isTrivial(FRS))
392 return DynamicRecursiveASTVisitor::TraverseCXXForRangeStmt(FRS);
393 return true;
394 }
395
396 bool TraverseWhileStmt(WhileStmt *WS) override {
397 if (!TFA.isTrivial(WS))
398 return DynamicRecursiveASTVisitor::TraverseWhileStmt(WS);
399 return true;
400 }
401
402 bool TraverseCompoundStmt(CompoundStmt *CS) override {
403 if (!TFA.isTrivial(CS))
404 return DynamicRecursiveASTVisitor::TraverseCompoundStmt(CS);
405 return true;
406 }
407
408 bool TraverseClassTemplateDecl(ClassTemplateDecl *Decl) override {
409 if (isSmartPtrClass(safeGetName(Decl)))
410 return true;
411 return DynamicRecursiveASTVisitor::TraverseClassTemplateDecl(Decl);
412 }
413 };
414
415 LocalVisitor visitor(this);
416 if (auto *RTC = Model->retainTypeChecker())
417 RTC->visitTranslationUnitDecl(TUD);
418 visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
419 }
420
421 void visitVarDecl(const VarDecl *V, QualType SinkType, const Expr *Value,
422 const Decl *DeclWithIssue) const {
423 if (shouldSkipVarDecl(V))
424 return;
425
426 if (auto *DD = dyn_cast<DecompositionDecl>(V)) {
427 const auto *InitList =
428 Value ? dyn_cast<InitListExpr>(Value->IgnoreParenCasts()) : nullptr;
429 if (InitList && InitList->getNumInits() != DD->bindings().size())
430 InitList = nullptr;
431
432 unsigned BindingIndex = 0;
433 for (auto *BD : DD->bindings()) {
434 const unsigned Index = BindingIndex++;
435 auto *Binding = BD->getBinding();
436 if (!Binding)
437 continue;
438 std::optional<bool> IsUncountedPtr = isUnsafePtr(Binding->getType());
439 if (!IsUncountedPtr || !*IsUncountedPtr)
440 continue;
441
442 const Expr *Origin = nullptr;
443 if (Model->checksForInteriorDestruction()) {
444 const Expr *Source = InitList ? InitList->getInit(Index) : Value;
445 if (isPtrOriginSafe(V, Source, DeclWithIssue, Origin,
446 Binding->getType()))
447 continue;
448 }
449 reportBug(V, V->getType(), nullptr, BD, DeclWithIssue, Origin);
450 }
451 }
452
453 std::optional<bool> IsUncountedPtr = isUnsafePtr(SinkType);
454 if (IsUncountedPtr && *IsUncountedPtr) {
455 const Expr *Origin = nullptr;
456 // The element of a fast enumeration is kept alive by the collection,
457 // which can't be mutated during the enumeration. Treat the collection as
458 // the initial value of the element.
459 if (!Value) {
460 if (auto *FCS = findObjCForCollectionStmtOfElement(V))
461 Value = FCS->getCollection();
462 }
463 if (Value) {
464 if (isPtrOriginSafe(V, Value, DeclWithIssue, Origin, SinkType))
465 return;
466 } else if (Model->checksForInteriorDestruction())
467 return;
468 reportBug(V, SinkType, Value, nullptr, DeclWithIssue, Origin);
469 }
470 }
471
472 bool isPtrOriginSafe(const VarDecl *V, const Expr *Value,
473 const Decl *DeclWithIssue, const Expr *&Origin,
474 QualType SinkType = QualType()) const {
475 return tryToFindPtrOrigin(
476 Value, /*StopAtFirstRefCountedObj=*/false,
477 Model->checksForInteriorDestruction(),
478 [&](const clang::CXXRecordDecl *Record) {
479 return Model->isSafePtr(Record);
480 },
481 [&](const clang::QualType Type) { return Model->isSafePtrType(Type); },
482 [&](const clang::Decl *D) {
483 return Model->isSafeDecl(D, BR->getSourceManager());
484 },
485 [&](const clang::Expr *InitArgOrigin, bool IsSafe,
486 bool OriginDependsOnFullExpressionTemporary,
487 bool PtrIsLifetimeBoundToOrigin) {
488 if (!InitArgOrigin)
489 return true;
490
491 if (IsSafe) {
492 if (!OriginDependsOnFullExpressionTemporary)
493 return true;
494 if (!Origin)
495 Origin = InitArgOrigin;
496 return false;
497 }
498
499 if (isa<CXXThisExpr>(InitArgOrigin))
500 return true;
501
502 if (isNullPtr(InitArgOrigin))
503 return true;
504
505 if (isa<IntegerLiteral>(InitArgOrigin))
506 return true;
507
508 if (isConstOwnerPtrMemberExpr(InitArgOrigin))
509 return true;
510
511 if (EFA.isACallToEnsureFn(InitArgOrigin))
512 return true;
513
514 if (Model->isSafeExpr(InitArgOrigin, PtrIsLifetimeBoundToOrigin,
515 SinkType, /*SinkMayEscape=*/false))
516 return true;
517
518 if (!Model->checksForInteriorDestruction() &&
519 hasGuardian(V, InitArgOrigin, DeclWithIssue))
520 return true;
521
522 if (!Origin)
523 Origin = InitArgOrigin;
524 return false;
525 });
526 }
527
528 bool hasGuardian(const VarDecl *V, const Expr *InitArgOrigin,
529 const Decl *DeclWithIssue) const {
530 auto *Ref = dyn_cast<DeclRefExpr>(InitArgOrigin);
531 if (!Ref)
532 return false;
533
534 auto *MaybeGuardian = dyn_cast_or_null<VarDecl>(Ref->getFoundDecl());
535 if (!MaybeGuardian)
536 return false;
537
538 QualType GuardianType = MaybeGuardian->getType();
539 // The collection of a fast enumeration is evaluated before the loop body is
540 // entered and keeps its elements alive. A raw pointer local variable or
541 // parameter holding the collection is checked on its own, so it only needs
542 // to be left untouched by the loop body.
543 if (auto *FCS = findObjCForCollectionStmtOfElement(V);
544 FCS && !GuardianType.isNull() && GuardianType->isAnyPointerType() &&
545 (MaybeGuardian->isLocalVarDecl() || isa<ParmVarDecl>(MaybeGuardian))) {
546 GuardianVisitor Visitor(MaybeGuardian, /*GuardianIsRawPtrOrRef=*/true);
547 return Visitor.TraverseStmt(const_cast<Stmt *>(FCS->getBody()));
548 }
549
550 if (!GuardianType.isNull()) {
551 if (auto *Record = GuardianType->getAsCXXRecordDecl()) {
552 if (MaybeGuardian->isLocalVarDecl() &&
553 (Model->isSafePtr(Record) ||
554 isRefcountedStringsHack(MaybeGuardian))) {
555 // The collection of a fast enumeration is evaluated before the loop
556 // body is entered so the guardian only needs to outlive the body.
557 if (auto *FCS = findObjCForCollectionStmtOfElement(V)) {
558 GuardianVisitor Visitor(MaybeGuardian);
559 return Visitor.TraverseStmt(const_cast<Stmt *>(FCS->getBody()));
560 }
561 if (isGuardedScopeEmbeddedInGuardianScope(V, MaybeGuardian))
562 return true;
563 }
564 }
565 }
566
567 if (isa<ParmVarDecl>(MaybeGuardian)) {
568 bool IsRawPtrOrRef = isUnsafePtr(GuardianType).value_or(false);
569 GuardianVisitor Visitor{MaybeGuardian, IsRawPtrOrRef};
570 if (auto *FD = dyn_cast<FunctionDecl>(DeclWithIssue))
571 return Visitor.TraverseStmt(FD->getBody());
572 if (auto *MD = dyn_cast<ObjCMethodDecl>(DeclWithIssue))
573 return Visitor.TraverseStmt(MD->getBody());
574 }
575
576 return false;
577 }
578
579 bool shouldSkipVarDecl(const VarDecl *V) const {
580 assert(V);
582 return true;
583 if (V->isInitCapture())
584 return true;
585 return BR->getSourceManager().isInSystemHeader(V->getLocation());
586 }
587
588 void reportBug(const VarDecl *V, QualType SinkType, const Expr *Value,
589 const Decl *BindingDecl, const Decl *DeclWithIssue,
590 const Expr *Origin) const {
591 assert(V);
593 llvm::raw_svector_ostream Os(Buf);
594
595 if (isa<ParmVarDecl>(V)) {
596 Os << "Parameter ";
598 Os << " is a ";
599 Model->describeHazard(Os, Origin, SinkType);
600
601 SourceLocation ExprLoc = (Value) ? Value->getExprLoc() : V->getLocation();
602 PathDiagnosticLocation BSLoc(ExprLoc, BR->getSourceManager());
603 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
604 if (Value)
605 Report->addRange(Value->getSourceRange());
606 Report->setDeclWithIssue(DeclWithIssue);
607 BR->emitReport(std::move(Report));
608 } else {
609 if (V->hasLocalStorage())
610 Os << "Local variable ";
611 else if (V->isStaticLocal())
612 Os << "Static local variable ";
613 else if (V->hasGlobalStorage())
614 Os << "Global variable ";
615 else
616 Os << "Variable ";
617 if (BindingDecl)
618 Os << "'" << safeGetName(BindingDecl) << "'";
619 else
621 Os << " is a ";
622 Model->describeHazard(Os, Origin, SinkType);
623
624 PathDiagnosticLocation BSLoc(V->getLocation(), BR->getSourceManager());
625 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
626 Report->addRange(V->getSourceRange());
627 Report->setDeclWithIssue(DeclWithIssue);
628 BR->emitReport(std::move(Report));
629 }
630 }
631};
632
633class UncountedLocalVarsChecker final : public RawPtrRefLocalVarsChecker {
634public:
635 UncountedLocalVarsChecker()
636 : RawPtrRefLocalVarsChecker("Uncounted raw pointer or reference not "
637 "provably backed by ref-counted variable",
639};
640
641class UncheckedLocalVarsChecker final : public RawPtrRefLocalVarsChecker {
642public:
643 UncheckedLocalVarsChecker()
644 : RawPtrRefLocalVarsChecker("Unchecked raw pointer or reference not "
645 "provably backed by checked variable",
647};
648
649class UnretainedLocalVarsChecker final : public RawPtrRefLocalVarsChecker {
650public:
651 UnretainedLocalVarsChecker()
652 : RawPtrRefLocalVarsChecker("Unretained raw pointer or reference not "
653 "provably backed by a RetainPtr",
655};
656
657class UnborrowedLocalVarsChecker final : public RawPtrRefLocalVarsChecker {
658public:
659 UnborrowedLocalVarsChecker()
660 : RawPtrRefLocalVarsChecker("Unborrowed raw pointer or reference not "
661 "provably backed by a Borrow",
663};
664
665} // namespace
666
667void ento::registerUncountedLocalVarsChecker(CheckerManager &Mgr) {
668 Mgr.registerChecker<UncountedLocalVarsChecker>();
669}
670
671bool ento::shouldRegisterUncountedLocalVarsChecker(const CheckerManager &) {
672 return true;
673}
674
675void ento::registerUncheckedLocalVarsChecker(CheckerManager &Mgr) {
676 Mgr.registerChecker<UncheckedLocalVarsChecker>();
677}
678
679bool ento::shouldRegisterUncheckedLocalVarsChecker(const CheckerManager &) {
680 return true;
681}
682
683void ento::registerUnretainedLocalVarsChecker(CheckerManager &Mgr) {
684 Mgr.registerChecker<UnretainedLocalVarsChecker>();
685}
686
687bool ento::shouldRegisterUnretainedLocalVarsChecker(const CheckerManager &) {
688 return true;
689}
690
691void ento::registerUnborrowedLocalVarsChecker(CheckerManager &Mgr) {
692 Mgr.registerChecker<UnborrowedLocalVarsChecker>();
693}
694
695bool ento::shouldRegisterUnborrowedLocalVarsChecker(const CheckerManager &) {
696 return true;
697}
#define V(N, I)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
llvm::MachO::Record Record
Definition MachO.h:31
Defines the clang::SourceLocation class and associated facilities.
Defines the Objective-C statement AST node classes.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:245
DynTypedNodeList getParents(const NodeT &Node)
Forwards to get node parents from the ParentMapContext.
Expr * getLHS() const
Definition Expr.h:4157
Expr * getRHS() const
Definition Expr.h:4159
static bool isAssignmentOp(Opcode Opc)
Definition Expr.h:4243
A binding in a decomposition declaration.
Definition DeclCXX.h:4215
arg_range arguments()
Definition ExprCXX.h:1677
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Definition ExprCXX.h:1616
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Definition ExprCXX.cpp:773
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
Definition ExprCXX.cpp:754
QualType getObjectType() const
Retrieve the type of the object argument.
Definition ExprCXX.cpp:766
FunctionTemplateDecl * getDependentLambdaCallOperator() const
Retrieve the dependent lambda call operator of the closure type if this is a templated closure type.
Definition DeclCXX.cpp:1739
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3195
arg_range arguments()
Definition Expr.h:3264
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition Stmt.h:1752
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1643
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
bool isTemplated() const
Determine whether this declaration is a templated entity (whether it is.
Definition DeclBase.cpp:308
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
This represents one expression.
Definition Expr.h:114
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3134
QualType getType() const
Definition Expr.h:146
Stmt * getThen()
Definition Stmt.h:2360
Stmt * getElse()
Definition Stmt.h:2369
VarDecl * getConditionVariable()
Retrieve the variable declared in this "if" statement, if any.
Definition Stmt.cpp:1068
capture_iterator capture_begin() const
Retrieve an iterator pointing to the first lambda capture.
Definition ExprCXX.cpp:1395
unsigned capture_size() const
Determine the number of captures in this lambda.
Definition ExprCXX.h:2054
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
Represents Objective-C's collection statement.
Definition StmtObjC.h:23
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 * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8446
Encodes a location in the source.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
Stmt - This represents one statement.
Definition Stmt.h:85
bool isTrivial(const Decl *D) const
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isAnyPointerType() const
Definition TypeBase.h:8691
QualType getType() const
Definition Decl.h:725
Represents a variable declaration or definition.
Definition Decl.h:934
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
Definition Decl.h:1276
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
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 isa(CodeGen::Address addr)
Definition Address.h:330
std::unique_ptr< PtrRefSafetyModel > makeBorrowSafetyModel()
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
bool isPtrConversion(const FunctionDecl *F)
std::unique_ptr< PtrRefSafetyModel > makeCheckedPtrSafetyModel()
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
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
bool isSmartPtrClass(const std::string &Name)
std::optional< bool > isGetterOfSafePtr(const CXXMethodDecl *M)
std::string safeGetName(const T *ASTNode)
Definition ASTUtils.h:109
bool isNullPtr(const clang::Expr *E)
Definition ASTUtils.cpp:535
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
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()
bool isConstOwnerPtrMemberExpr(const clang::Expr *E)
Definition ASTUtils.cpp:545