13
13
#include " clang/AST/Decl.h"
14
14
#include " clang/AST/DeclCXX.h"
15
15
#include " clang/AST/RecursiveASTVisitor.h"
16
+ #include " clang/Analysis/DomainSpecific/CocoaConventions.h"
16
17
#include " clang/Basic/SourceLocation.h"
17
18
#include " clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18
19
#include " clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
@@ -35,6 +36,9 @@ class RawPtrRefCallArgsChecker
35
36
TrivialFunctionAnalysis TFA;
36
37
EnsureFunctionAnalysis EFA;
37
38
39
+ protected:
40
+ mutable std::optional<RetainTypeChecker> RTC;
41
+
38
42
public:
39
43
RawPtrRefCallArgsChecker (const char *description)
40
44
: Bug(this , description, " WebKit coding guidelines" ) {}
@@ -83,9 +87,22 @@ class RawPtrRefCallArgsChecker
83
87
Checker->visitCallExpr (CE, DeclWithIssue);
84
88
return true ;
85
89
}
90
+
91
+ bool VisitTypedefDecl (TypedefDecl *TD) {
92
+ if (Checker->RTC )
93
+ Checker->RTC ->visitTypedef (TD);
94
+ return true ;
95
+ }
96
+
97
+ bool VisitObjCMessageExpr (ObjCMessageExpr *ObjCMsgExpr) {
98
+ Checker->visitObjCMessageExpr (ObjCMsgExpr, DeclWithIssue);
99
+ return true ;
100
+ }
86
101
};
87
102
88
103
LocalVisitor visitor (this );
104
+ if (RTC)
105
+ RTC->visitTranslationUnitDecl (TUD);
89
106
visitor.TraverseDecl (const_cast <TranslationUnitDecl *>(TUD));
90
107
}
91
108
@@ -125,7 +142,7 @@ class RawPtrRefCallArgsChecker
125
142
// if ((*P)->hasAttr<SafeRefCntblRawPtrAttr>())
126
143
// continue;
127
144
128
- QualType ArgType = (*P)->getType (). getCanonicalType () ;
145
+ QualType ArgType = (*P)->getType ();
129
146
// FIXME: more complex types (arrays, references to raw pointers, etc)
130
147
std::optional<bool > IsUncounted = isUnsafePtr (ArgType);
131
148
if (!IsUncounted || !(*IsUncounted))
@@ -141,6 +158,58 @@ class RawPtrRefCallArgsChecker
141
158
142
159
reportBug (Arg, *P, D);
143
160
}
161
+ for (; ArgIdx < CE->getNumArgs (); ++ArgIdx) {
162
+ const auto *Arg = CE->getArg (ArgIdx);
163
+ auto ArgType = Arg->getType ();
164
+ std::optional<bool > IsUncounted = isUnsafePtr (ArgType);
165
+ if (!IsUncounted || !(*IsUncounted))
166
+ continue ;
167
+
168
+ if (auto *defaultArg = dyn_cast<CXXDefaultArgExpr>(Arg))
169
+ Arg = defaultArg->getExpr ();
170
+
171
+ if (isPtrOriginSafe (Arg))
172
+ continue ;
173
+
174
+ reportBug (Arg, nullptr , D);
175
+ }
176
+ }
177
+ }
178
+
179
+ void visitObjCMessageExpr (const ObjCMessageExpr *E, const Decl *D) const {
180
+ if (BR->getSourceManager ().isInSystemHeader (E->getExprLoc ()))
181
+ return ;
182
+
183
+ auto Selector = E->getSelector ();
184
+ if (auto *Receiver = E->getInstanceReceiver ()) {
185
+ std::optional<bool > IsUnsafe = isUnsafePtr (E->getReceiverType ());
186
+ if (IsUnsafe && *IsUnsafe && !isPtrOriginSafe (Receiver)) {
187
+ if (auto *InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver)) {
188
+ auto InnerSelector = InnerMsg->getSelector ();
189
+ if (InnerSelector.getNameForSlot (0 ) == " alloc" &&
190
+ Selector.getNameForSlot (0 ).starts_with (" init" ))
191
+ return ;
192
+ }
193
+ reportBugOnReceiver (Receiver, D);
194
+ }
195
+ }
196
+
197
+ auto *MethodDecl = E->getMethodDecl ();
198
+ if (!MethodDecl)
199
+ return ;
200
+
201
+ auto ArgCount = E->getNumArgs ();
202
+ for (unsigned i = 0 ; i < ArgCount; ++i) {
203
+ auto *Arg = E->getArg (i);
204
+ bool hasParam = i < MethodDecl->param_size ();
205
+ auto *Param = hasParam ? MethodDecl->getParamDecl (i) : nullptr ;
206
+ auto ArgType = Arg->getType ();
207
+ std::optional<bool > IsUnsafe = isUnsafePtr (ArgType);
208
+ if (!IsUnsafe || !(*IsUnsafe))
209
+ continue ;
210
+ if (isPtrOriginSafe (Arg))
211
+ continue ;
212
+ reportBug (Arg, Param, D);
144
213
}
145
214
}
146
215
@@ -161,6 +230,8 @@ class RawPtrRefCallArgsChecker
161
230
// foo(NULL)
162
231
return true ;
163
232
}
233
+ if (isa<ObjCStringLiteral>(ArgOrigin))
234
+ return true ;
164
235
if (isASafeCallArg (ArgOrigin))
165
236
return true ;
166
237
if (EFA.isACallToEnsureFn (ArgOrigin))
@@ -215,7 +286,7 @@ class RawPtrRefCallArgsChecker
215
286
overloadedOperatorType == OO_PipePipe)
216
287
return true ;
217
288
218
- if (isCtorOfRefCounted (Callee))
289
+ if (isCtorOfSafePtr (Callee))
219
290
return true ;
220
291
221
292
auto name = safeGetName (Callee);
@@ -280,9 +351,10 @@ class RawPtrRefCallArgsChecker
280
351
}
281
352
Os << " is " << ptrKind () << " and unsafe." ;
282
353
354
+ bool usesDefaultArgValue = isa<CXXDefaultArgExpr>(CallArg) && Param;
283
355
const SourceLocation SrcLocToReport =
284
- isa<CXXDefaultArgExpr>(CallArg) ? Param->getDefaultArg ()->getExprLoc ()
285
- : CallArg->getSourceRange ().getBegin ();
356
+ usesDefaultArgValue ? Param->getDefaultArg ()->getExprLoc ()
357
+ : CallArg->getSourceRange ().getBegin ();
286
358
287
359
PathDiagnosticLocation BSLoc (SrcLocToReport, BR->getSourceManager ());
288
360
auto Report = std::make_unique<BasicBugReport>(Bug, Os.str (), BSLoc);
@@ -307,6 +379,23 @@ class RawPtrRefCallArgsChecker
307
379
Report->setDeclWithIssue (DeclWithIssue);
308
380
BR->emitReport (std::move (Report));
309
381
}
382
+
383
+ void reportBugOnReceiver (const Expr *CallArg,
384
+ const Decl *DeclWithIssue) const {
385
+ assert (CallArg);
386
+
387
+ const SourceLocation SrcLocToReport = CallArg->getSourceRange ().getBegin ();
388
+
389
+ SmallString<100 > Buf;
390
+ llvm::raw_svector_ostream Os (Buf);
391
+ Os << " Reciever is " << ptrKind () << " and unsafe." ;
392
+
393
+ PathDiagnosticLocation BSLoc (SrcLocToReport, BR->getSourceManager ());
394
+ auto Report = std::make_unique<BasicBugReport>(Bug, Os.str (), BSLoc);
395
+ Report->addRange (CallArg->getSourceRange ());
396
+ Report->setDeclWithIssue (DeclWithIssue);
397
+ BR->emitReport (std::move (Report));
398
+ }
310
399
};
311
400
312
401
class UncountedCallArgsChecker final : public RawPtrRefCallArgsChecker {
@@ -320,7 +409,7 @@ class UncountedCallArgsChecker final : public RawPtrRefCallArgsChecker {
320
409
}
321
410
322
411
std::optional<bool > isUnsafePtr (QualType QT) const final {
323
- return isUncountedPtr (QT);
412
+ return isUncountedPtr (QT. getCanonicalType () );
324
413
}
325
414
326
415
bool isSafePtr (const CXXRecordDecl *Record) const final {
@@ -345,7 +434,7 @@ class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker {
345
434
}
346
435
347
436
std::optional<bool > isUnsafePtr (QualType QT) const final {
348
- return isUncheckedPtr (QT);
437
+ return isUncheckedPtr (QT. getCanonicalType () );
349
438
}
350
439
351
440
bool isSafePtr (const CXXRecordDecl *Record) const final {
@@ -359,6 +448,33 @@ class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker {
359
448
const char *ptrKind () const final { return " unchecked" ; }
360
449
};
361
450
451
+ class UnretainedCallArgsChecker final : public RawPtrRefCallArgsChecker {
452
+ public:
453
+ UnretainedCallArgsChecker ()
454
+ : RawPtrRefCallArgsChecker(" Unretained call argument for a raw "
455
+ " pointer/reference parameter" ) {
456
+ RTC = RetainTypeChecker ();
457
+ }
458
+
459
+ std::optional<bool > isUnsafeType (QualType QT) const final {
460
+ return RTC->isUnretained (QT);
461
+ }
462
+
463
+ std::optional<bool > isUnsafePtr (QualType QT) const final {
464
+ return RTC->isUnretained (QT);
465
+ }
466
+
467
+ bool isSafePtr (const CXXRecordDecl *Record) const final {
468
+ return isRetainPtr (Record);
469
+ }
470
+
471
+ bool isSafePtrType (const QualType type) const final {
472
+ return isRetainPtrType (type);
473
+ }
474
+
475
+ const char *ptrKind () const final { return " unretained" ; }
476
+ };
477
+
362
478
} // namespace
363
479
364
480
void ento::registerUncountedCallArgsChecker (CheckerManager &Mgr) {
@@ -376,3 +492,11 @@ void ento::registerUncheckedCallArgsChecker(CheckerManager &Mgr) {
376
492
bool ento::shouldRegisterUncheckedCallArgsChecker (const CheckerManager &) {
377
493
return true ;
378
494
}
495
+
496
+ void ento::registerUnretainedCallArgsChecker (CheckerManager &Mgr) {
497
+ Mgr.registerChecker <UnretainedCallArgsChecker>();
498
+ }
499
+
500
+ bool ento::shouldRegisterUnretainedCallArgsChecker (const CheckerManager &) {
501
+ return true ;
502
+ }
0 commit comments