24class RawPtrRefLambdaCapturesChecker
25 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
28 mutable BugReporter *BR =
nullptr;
29 TrivialFunctionAnalysis TFA;
32 const std::unique_ptr<PtrRefSafetyModel> Model;
35 RawPtrRefLambdaCapturesChecker(
const char *description,
36 std::unique_ptr<PtrRefSafetyModel> Model)
37 : Bug(this, description,
"WebKit coding guidelines"),
38 Model(std::move(Model)) {}
40 std::optional<bool> isUnsafePtr(QualType QT)
const {
43 bool isPtrType(
const std::string &Name)
const {
44 return Model->isPtrType(Name);
47 void checkASTDecl(
const TranslationUnitDecl *TUD, AnalysisManager &MGR,
48 BugReporter &BRArg)
const {
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 *>>
66 explicit LocalVisitor(
const RawPtrRefLambdaCapturesChecker *Checker)
69 ShouldVisitTemplateInstantiations =
true;
70 ShouldVisitImplicitCode =
false;
73 bool TraverseCXXConstructorDecl(CXXConstructorDecl *Ctor)
override {
74 llvm::SaveAndRestore SavedDecl(ClsType);
76 return DynamicRecursiveASTVisitor::TraverseCXXConstructorDecl(Ctor);
79 bool TraverseCXXDestructorDecl(CXXDestructorDecl *Dtor)
override {
80 llvm::SaveAndRestore SavedDecl(ClsType);
81 ClsType =
Dtor->getThisType();
82 return DynamicRecursiveASTVisitor::TraverseCXXDestructorDecl(Dtor);
85 bool TraverseCXXMethodDecl(CXXMethodDecl *CXXMD)
override {
86 llvm::SaveAndRestore SavedDecl(ClsType);
89 return DynamicRecursiveASTVisitor::TraverseCXXMethodDecl(CXXMD);
92 bool TraverseObjCMethodDecl(ObjCMethodDecl *OCMD)
override {
93 llvm::SaveAndRestore SavedDecl(ClsType);
96 ClsType = ImplParamDecl->getType();
98 return DynamicRecursiveASTVisitor::TraverseObjCMethodDecl(OCMD);
101 bool VisitTypedefDecl(TypedefDecl *TD)
override {
102 if (
auto *RTC = Checker->Model->retainTypeChecker())
103 RTC->visitTypedef(TD);
107 bool shouldCheckThis() {
109 !ClsType.
isNull() ? Checker->isUnsafePtr(ClsType) : std::nullopt;
110 return result && *result;
113 bool VisitLambdaExpr(
LambdaExpr *L)
override {
114 if (LambdasToIgnore.contains(L))
116 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
121 bool VisitVarDecl(VarDecl *VD)
override {
125 if (
auto *L = dyn_cast_or_null<LambdaExpr>(
Init->IgnoreParenCasts())) {
126 LambdasToIgnore.insert(L);
131 if (
auto *E = dyn_cast<ExprWithCleanups>(
Init))
132 Init = E->getSubExpr();
133 if (
auto *E = dyn_cast<CXXBindTemporaryExpr>(
Init))
134 Init = E->getSubExpr();
135 if (
auto *CE = dyn_cast<CallExpr>(
Init)) {
136 if (
auto *Callee = CE->getDirectCallee()) {
138 unsigned ArgCnt = CE->getNumArgs();
139 if (FnName ==
"makeScopeExit" && ArgCnt == 1) {
140 auto *Arg = CE->getArg(0);
141 if (
auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
142 Arg = E->getSubExpr();
143 if (
auto *L = dyn_cast<LambdaExpr>(Arg))
144 addLambdaOwner(VD, CE, L);
145 }
else if (FnName ==
"makeVisitor") {
146 for (
unsigned ArgIndex = 0; ArgIndex < ArgCnt; ++ArgIndex) {
147 auto *Arg = CE->getArg(ArgIndex);
148 if (
auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
149 Arg = E->getSubExpr();
150 if (
auto *L = dyn_cast<LambdaExpr>(Arg))
151 addLambdaOwner(VD, CE, L);
155 }
else if (
auto *CE = dyn_cast<CXXConstructExpr>(
Init)) {
156 if (
auto *Ctor = CE->getConstructor()) {
159 unsigned ArgCnt = CE->getNumArgs();
160 if (FnName ==
"ScopeExit" && ArgCnt == 1) {
161 auto *Arg = CE->getArg(0);
162 if (
auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
163 Arg = E->getSubExpr();
164 if (
auto *L = dyn_cast<LambdaExpr>(Arg))
165 addLambdaOwner(VD, CE, L);
173 void addLambdaOwner(VarDecl *VD, CallExpr *CE,
LambdaExpr *L) {
174 auto result = LambdaOwnerMap.insert(
175 std::make_pair(VD, SmallVector<const LambdaExpr *>{L}));
177 result.first->second.push_back(L);
178 CallToIgnore.insert(CE);
179 LambdasToIgnore.insert(L);
182 void addLambdaOwner(VarDecl *VD, CXXConstructExpr *CE,
LambdaExpr *L) {
183 auto result = LambdaOwnerMap.insert(
184 std::make_pair(VD, SmallVector<const LambdaExpr *>{L}));
186 result.first->second.push_back(L);
187 ConstructToIgnore.insert(CE);
188 LambdasToIgnore.insert(L);
191 bool VisitDeclRefExpr(DeclRefExpr *DRE)
override {
192 if (DeclRefExprsToIgnore.contains(DRE))
194 auto *VD = dyn_cast_or_null<VarDecl>(DRE->
getDecl());
197 if (
auto It = LambdaOwnerMap.find(VD); It != LambdaOwnerMap.end()) {
198 for (
auto *L : It->second) {
199 Checker->visitLambdaExpr(
200 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
207 auto *L = dyn_cast_or_null<LambdaExpr>(
Init->IgnoreParenCasts());
210 LambdasToIgnore.insert(L);
211 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
216 bool shouldTreatAllArgAsNoEscape(FunctionDecl *FDecl) {
218 for (
auto *Decl = FDecl->
getParent(); Decl; Decl =
Decl->getParent()) {
221 if (
auto *NS = dyn_cast<NamespaceDecl>(Decl); NS && NS->isInline())
227 if (Name ==
"WTF" && PreviousName ==
"switchOn")
230 if (Name ==
"std" && PreviousName ==
"ranges")
237 bool VisitCXXConstructExpr(CXXConstructExpr *CE)
override {
238 if (ConstructToIgnore.contains(CE))
241 unsigned ArgIndex = 0;
242 for (
auto *Param :
Callee->parameters()) {
246 if (
auto *L = findLambdaInArg(Arg)) {
247 LambdasToIgnore.insert(L);
248 if (!Param->hasAttr<NoEscapeAttr>())
249 Checker->visitLambdaExpr(
250 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
258 bool VisitCallExpr(CallExpr *CE)
override {
259 if (CallToIgnore.contains(CE))
261 checkCalleeLambda(CE);
263 if (isVisitFunction(CE, Callee))
265 checkParameters(CE, Callee);
266 }
else if (
auto *CalleeE = CE->
getCallee()) {
267 if (
auto *DRE = dyn_cast<DeclRefExpr>(CalleeE->IgnoreParenCasts())) {
268 if (
auto *Callee = dyn_cast_or_null<FunctionDecl>(DRE->
getDecl()))
269 checkParameters(CE, Callee);
275 bool isVisitFunction(CallExpr *CallExpr, FunctionDecl *FnDecl) {
286 if (NsName !=
"WTF" && NsName !=
"std")
288 auto *Arg = CallExpr->
getArg(0);
291 auto *DRE = dyn_cast<DeclRefExpr>(Arg->IgnoreParenCasts());
294 auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
297 if (!LambdaOwnerMap.contains(VD))
299 DeclRefExprsToIgnore.insert(DRE);
303 void checkParameters(CallExpr *CE, FunctionDecl *Callee) {
305 bool TreatAllArgsAsNoEscape = shouldTreatAllArgAsNoEscape(Callee);
306 for (
auto *Param :
Callee->parameters()) {
310 if (
auto *L = findLambdaInArg(Arg)) {
311 LambdasToIgnore.insert(L);
312 if (!Param->hasAttr<NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
313 Checker->visitLambdaExpr(
314 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
321 if (
auto *Lambda = dyn_cast_or_null<LambdaExpr>(E))
323 auto *TempExpr = dyn_cast_or_null<CXXBindTemporaryExpr>(E);
329 if (
auto *Lambda = dyn_cast<LambdaExpr>(E))
331 auto *CE = dyn_cast_or_null<CXXConstructExpr>(E);
337 auto *InnerCE = dyn_cast_or_null<CXXConstructExpr>(CtorArg);
338 if (InnerCE && InnerCE->getNumArgs())
339 CtorArg = InnerCE->getArg(0)->IgnoreParenCasts();
340 auto updateIgnoreList = [&] {
341 ConstructToIgnore.insert(CE);
343 ConstructToIgnore.insert(InnerCE);
345 if (
auto *Lambda = dyn_cast<LambdaExpr>(CtorArg)) {
349 if (
auto *TempExpr = dyn_cast<CXXBindTemporaryExpr>(CtorArg)) {
351 if (
auto *Lambda = dyn_cast<LambdaExpr>(E)) {
356 auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
359 auto *VD = dyn_cast_or_null<VarDecl>(DRE->
getDecl());
365 if (
auto *Lambda = dyn_cast<LambdaExpr>(
Init)) {
366 DeclRefExprsToIgnore.insert(DRE);
373 void checkCalleeLambda(CallExpr *CE) {
378 if (
auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Callee)) {
379 Callee = MTE->getSubExpr();
384 if (
auto *L = dyn_cast<LambdaExpr>(Callee)) {
385 LambdasToIgnore.insert(L);
388 auto *DRE = dyn_cast<DeclRefExpr>(
Callee->IgnoreParenCasts());
391 auto *MD = dyn_cast_or_null<CXXMethodDecl>(DRE->
getDecl());
395 if (
auto *L = dyn_cast_or_null<LambdaExpr>(Arg)) {
396 LambdasToIgnore.insert(L);
399 auto *ArgRef = dyn_cast<DeclRefExpr>(Arg);
402 auto *VD = dyn_cast_or_null<VarDecl>(ArgRef->getDecl());
408 auto *L = dyn_cast_or_null<LambdaExpr>(
Init->IgnoreParenCasts());
411 DeclRefExprsToIgnore.insert(ArgRef);
412 LambdasToIgnore.insert(L);
416 for (
const LambdaCapture &OtherCapture : L->
captures()) {
417 if (!OtherCapture.capturesVariable())
419 if (
auto *ValueDecl = OtherCapture.getCapturedVar()) {
420 if (declProtectsThis(ValueDecl)) {
421 ProtectedThisDecls.insert(ValueDecl);
429 bool declProtectsThis(
const ValueDecl *ValueDecl)
const {
430 auto *VD = dyn_cast<VarDecl>(ValueDecl);
438 if (
auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg))
440 if (
auto *CE = dyn_cast<CXXConstructExpr>(Arg)) {
441 auto *Ctor = CE->getConstructor();
445 if (Checker->isPtrType(clsName) && CE->
getNumArgs()) {
450 if (
auto *CXXR =
Type->getPointeeCXXRecordDecl()) {
460 if (
auto *CE = dyn_cast<CallExpr>(Arg)) {
469 if (
auto *OpCE = dyn_cast<CXXOperatorCallExpr>(Arg)) {
470 auto OpCode = OpCE->getOperator();
471 if (OpCode == OO_Star || OpCode == OO_Amp) {
472 auto *
Callee = OpCE->getDirectCallee();
476 if (!Checker->isPtrType(clsName) || !OpCE->getNumArgs())
482 if (
auto *UO = dyn_cast<UnaryOperator>(Arg)) {
483 auto OpCode = UO->getOpcode();
484 if (OpCode == UO_Deref || OpCode == UO_AddrOf) {
491 if (
auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
493 if (
auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(Decl)) {
494 auto kind = ImplicitParam->getParameterKind();
495 return kind == ImplicitParamKind::ObjCSelf ||
496 kind == ImplicitParamKind::CXXThis;
498 return ProtectedThisDecls.contains(Decl);
504 LocalVisitor visitor(
this);
505 if (
auto *RTC = Model->retainTypeChecker())
506 RTC->visitTranslationUnitDecl(TUD);
507 visitor.TraverseDecl(
const_cast<TranslationUnitDecl *
>(TUD));
510 void visitLambdaExpr(
const LambdaExpr *L,
bool shouldCheckThis,
512 bool ignoreParamVarDecl =
false)
const {
513 if (TFA.isTrivial(L->
getBody()))
515 for (
const LambdaCapture &
C : L->
captures()) {
516 if (
C.capturesVariable()) {
517 ValueDecl *CapturedVar =
C.getCapturedVar();
520 if (
auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(CapturedVar)) {
521 auto kind = ImplicitParam->getParameterKind();
522 if ((
kind == ImplicitParamKind::ObjCSelf ||
523 kind == ImplicitParamKind::CXXThis) &&
527 QualType CapturedVarQualType = CapturedVar->
getType();
528 auto IsUncountedPtr = isUnsafePtr(CapturedVar->
getType());
532 if (IsUncountedPtr && *IsUncountedPtr)
533 reportBug(
C, CapturedVar, CapturedVarQualType, L);
534 }
else if (
C.capturesThis() && shouldCheckThis) {
535 if (ignoreParamVarDecl)
537 reportBugOnThisPtr(
C,
T);
542 void reportBug(
const LambdaCapture &
Capture, ValueDecl *CapturedVar,
546 auto Location =
Capture.getLocation();
550 SmallString<100> Buf;
551 llvm::raw_svector_ostream Os(Buf);
556 Os <<
"Implicitly captured ";
560 bool IsUnsafePtr = CapturedVar->
getType() ==
T;
564 Os <<
" contains a ";
565 auto *CapturedType =
T.getTypePtrOrNull();
566 printPointer(Os, CapturedType);
568 PathDiagnosticLocation BSLoc(Location, BR->getSourceManager());
569 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
570 BR->emitReport(std::move(
Report));
573 void reportBugOnThisPtr(
const LambdaCapture &
Capture,
574 const QualType
T)
const {
575 SmallString<100> Buf;
576 llvm::raw_svector_ostream Os(Buf);
581 Os <<
"Implicitly captured ";
584 Os <<
"variable 'this' is a raw pointer to " << Model->typeName();
590 PathDiagnosticLocation BSLoc(
Capture.getLocation(), BR->getSourceManager());
591 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
592 BR->emitReport(std::move(
Report));
595 void printPointer(llvm::raw_svector_ostream &Os,
const Type *
T)
const {
596 if (Model->retainTypeChecker()) {
599 if (
auto *ObjCPtr = dyn_cast<ObjCObjectPointerType>(
T)) {
600 for (ObjCProtocolDecl *P : ObjCPtr->quals()) {
601 if (
const auto *II = P->getIdentifier()) {
602 auto Name = II->getName();
603 if (Name.starts_with(
"OS_")) {
604 Os << Model->typeName() <<
" ";
616 Os << Model->typeName() <<
" ";
623 Os << (IsPtr ?
"raw pointer" :
"raw reference") <<
" to ";
624 Os << Model->typeName();
636class UncountedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
638 UncountedLambdaCapturesChecker()
639 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of uncounted variable",
643class UncheckedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
645 UncheckedLambdaCapturesChecker()
646 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of unchecked variable",
650class UnretainedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
652 UnretainedLambdaCapturesChecker()
653 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of unretained "
660void ento::registerUncountedLambdaCapturesChecker(
CheckerManager &Mgr) {
664bool ento::shouldRegisterUncountedLambdaCapturesChecker(
669void ento::registerUncheckedLambdaCapturesChecker(
CheckerManager &Mgr) {
673bool ento::shouldRegisterUncheckedLambdaCapturesChecker(
678void ento::registerUnretainedLambdaCapturesChecker(
CheckerManager &Mgr) {
682bool ento::shouldRegisterUnretainedLambdaCapturesChecker(
*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.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
bool isMoveConstructor(unsigned &TypeQuals) const
Determine whether this constructor is a move constructor (C++11 [class.copy]p3), which can be used to...
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
QualType getThisType() const
Return the type of the this pointer.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Stmt * getBody() const
Retrieve the body of the lambda.
SourceLocation getBeginLoc() const LLVM_READONLY
capture_range captures() const
Retrieve this lambda's captures.
ImplicitParamDecl * getSelfDecl() const
bool isInstanceMethod() const
bool isNull() const
Return true if this QualType doesn't point to a type yet.
const Type * getTypePtrOrNull() const
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
bool isReferenceType() const
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const T * getAs() const
Member-template getAs<specific type>'.
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
const Expr * getInit() const
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
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.
constexpr bool isPtrType(PrimType T)
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)
std::unique_ptr< PtrRefSafetyModel > makeCheckedPtrSafetyModel()
@ LCK_ByCopy
Capturing by copy (a.k.a., by value)
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
@ Type
The name was classified as a type.
std::string safeGetName(const T *ASTNode)
ObjCInterfaceDecl * getObjCDeclFromObjCPtr(const Type *TypePtr)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
bool isStdOrWTFMove(const clang::FunctionDecl *F)
std::unique_ptr< PtrRefSafetyModel > makeRefPtrSafetyModel()
std::unique_ptr< PtrRefSafetyModel > makeRetainPtrSafetyModel()