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