13
13
#include " clang/AST/Decl.h"
14
14
#include " clang/AST/DeclCXX.h"
15
15
#include " clang/AST/DynamicRecursiveASTVisitor.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" ) {}
@@ -80,9 +84,22 @@ class RawPtrRefCallArgsChecker
80
84
Checker->visitCallExpr (CE, DeclWithIssue);
81
85
return true ;
82
86
}
87
+
88
+ bool VisitTypedefDecl (TypedefDecl *TD) override {
89
+ if (Checker->RTC )
90
+ Checker->RTC ->visitTypedef (TD);
91
+ return true ;
92
+ }
93
+
94
+ bool VisitObjCMessageExpr (ObjCMessageExpr *ObjCMsgExpr) override {
95
+ Checker->visitObjCMessageExpr (ObjCMsgExpr, DeclWithIssue);
96
+ return true ;
97
+ }
83
98
};
84
99
85
100
LocalVisitor visitor (this );
101
+ if (RTC)
102
+ RTC->visitTranslationUnitDecl (TUD);
86
103
visitor.TraverseDecl (const_cast <TranslationUnitDecl *>(TUD));
87
104
}
88
105
@@ -122,7 +139,7 @@ class RawPtrRefCallArgsChecker
122
139
// if ((*P)->hasAttr<SafeRefCntblRawPtrAttr>())
123
140
// continue;
124
141
125
- QualType ArgType = (*P)->getType (). getCanonicalType () ;
142
+ QualType ArgType = (*P)->getType ();
126
143
// FIXME: more complex types (arrays, references to raw pointers, etc)
127
144
std::optional<bool > IsUncounted = isUnsafePtr (ArgType);
128
145
if (!IsUncounted || !(*IsUncounted))
@@ -138,6 +155,58 @@ class RawPtrRefCallArgsChecker
138
155
139
156
reportBug (Arg, *P, D);
140
157
}
158
+ for (; ArgIdx < CE->getNumArgs (); ++ArgIdx) {
159
+ const auto *Arg = CE->getArg (ArgIdx);
160
+ auto ArgType = Arg->getType ();
161
+ std::optional<bool > IsUncounted = isUnsafePtr (ArgType);
162
+ if (!IsUncounted || !(*IsUncounted))
163
+ continue ;
164
+
165
+ if (auto *defaultArg = dyn_cast<CXXDefaultArgExpr>(Arg))
166
+ Arg = defaultArg->getExpr ();
167
+
168
+ if (isPtrOriginSafe (Arg))
169
+ continue ;
170
+
171
+ reportBug (Arg, nullptr , D);
172
+ }
173
+ }
174
+ }
175
+
176
+ void visitObjCMessageExpr (const ObjCMessageExpr *E, const Decl *D) const {
177
+ if (BR->getSourceManager ().isInSystemHeader (E->getExprLoc ()))
178
+ return ;
179
+
180
+ auto Selector = E->getSelector ();
181
+ if (auto *Receiver = E->getInstanceReceiver ()) {
182
+ std::optional<bool > IsUnsafe = isUnsafePtr (E->getReceiverType ());
183
+ if (IsUnsafe && *IsUnsafe && !isPtrOriginSafe (Receiver)) {
184
+ if (auto *InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver)) {
185
+ auto InnerSelector = InnerMsg->getSelector ();
186
+ if (InnerSelector.getNameForSlot (0 ) == " alloc" &&
187
+ Selector.getNameForSlot (0 ).starts_with (" init" ))
188
+ return ;
189
+ }
190
+ reportBugOnReceiver (Receiver, D);
191
+ }
192
+ }
193
+
194
+ auto *MethodDecl = E->getMethodDecl ();
195
+ if (!MethodDecl)
196
+ return ;
197
+
198
+ auto ArgCount = E->getNumArgs ();
199
+ for (unsigned i = 0 ; i < ArgCount; ++i) {
200
+ auto *Arg = E->getArg (i);
201
+ bool hasParam = i < MethodDecl->param_size ();
202
+ auto *Param = hasParam ? MethodDecl->getParamDecl (i) : nullptr ;
203
+ auto ArgType = Arg->getType ();
204
+ std::optional<bool > IsUnsafe = isUnsafePtr (ArgType);
205
+ if (!IsUnsafe || !(*IsUnsafe))
206
+ continue ;
207
+ if (isPtrOriginSafe (Arg))
208
+ continue ;
209
+ reportBug (Arg, Param, D);
141
210
}
142
211
}
143
212
@@ -158,6 +227,8 @@ class RawPtrRefCallArgsChecker
158
227
// foo(NULL)
159
228
return true ;
160
229
}
230
+ if (isa<ObjCStringLiteral>(ArgOrigin))
231
+ return true ;
161
232
if (isASafeCallArg (ArgOrigin))
162
233
return true ;
163
234
if (EFA.isACallToEnsureFn (ArgOrigin))
@@ -212,7 +283,7 @@ class RawPtrRefCallArgsChecker
212
283
overloadedOperatorType == OO_PipePipe)
213
284
return true ;
214
285
215
- if (isCtorOfRefCounted (Callee))
286
+ if (isCtorOfSafePtr (Callee))
216
287
return true ;
217
288
218
289
auto name = safeGetName (Callee);
@@ -277,9 +348,10 @@ class RawPtrRefCallArgsChecker
277
348
}
278
349
Os << " is " << ptrKind () << " and unsafe." ;
279
350
351
+ bool usesDefaultArgValue = isa<CXXDefaultArgExpr>(CallArg) && Param;
280
352
const SourceLocation SrcLocToReport =
281
- isa<CXXDefaultArgExpr>(CallArg) ? Param->getDefaultArg ()->getExprLoc ()
282
- : CallArg->getSourceRange ().getBegin ();
353
+ usesDefaultArgValue ? Param->getDefaultArg ()->getExprLoc ()
354
+ : CallArg->getSourceRange ().getBegin ();
283
355
284
356
PathDiagnosticLocation BSLoc (SrcLocToReport, BR->getSourceManager ());
285
357
auto Report = std::make_unique<BasicBugReport>(Bug, Os.str (), BSLoc);
@@ -304,6 +376,23 @@ class RawPtrRefCallArgsChecker
304
376
Report->setDeclWithIssue (DeclWithIssue);
305
377
BR->emitReport (std::move (Report));
306
378
}
379
+
380
+ void reportBugOnReceiver (const Expr *CallArg,
381
+ const Decl *DeclWithIssue) const {
382
+ assert (CallArg);
383
+
384
+ const SourceLocation SrcLocToReport = CallArg->getSourceRange ().getBegin ();
385
+
386
+ SmallString<100 > Buf;
387
+ llvm::raw_svector_ostream Os (Buf);
388
+ Os << " Reciever is " << ptrKind () << " and unsafe." ;
389
+
390
+ PathDiagnosticLocation BSLoc (SrcLocToReport, BR->getSourceManager ());
391
+ auto Report = std::make_unique<BasicBugReport>(Bug, Os.str (), BSLoc);
392
+ Report->addRange (CallArg->getSourceRange ());
393
+ Report->setDeclWithIssue (DeclWithIssue);
394
+ BR->emitReport (std::move (Report));
395
+ }
307
396
};
308
397
309
398
class UncountedCallArgsChecker final : public RawPtrRefCallArgsChecker {
@@ -317,7 +406,7 @@ class UncountedCallArgsChecker final : public RawPtrRefCallArgsChecker {
317
406
}
318
407
319
408
std::optional<bool > isUnsafePtr (QualType QT) const final {
320
- return isUncountedPtr (QT);
409
+ return isUncountedPtr (QT. getCanonicalType () );
321
410
}
322
411
323
412
bool isSafePtr (const CXXRecordDecl *Record) const final {
@@ -342,7 +431,7 @@ class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker {
342
431
}
343
432
344
433
std::optional<bool > isUnsafePtr (QualType QT) const final {
345
- return isUncheckedPtr (QT);
434
+ return isUncheckedPtr (QT. getCanonicalType () );
346
435
}
347
436
348
437
bool isSafePtr (const CXXRecordDecl *Record) const final {
@@ -356,6 +445,33 @@ class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker {
356
445
const char *ptrKind () const final { return " unchecked" ; }
357
446
};
358
447
448
+ class UnretainedCallArgsChecker final : public RawPtrRefCallArgsChecker {
449
+ public:
450
+ UnretainedCallArgsChecker ()
451
+ : RawPtrRefCallArgsChecker(" Unretained call argument for a raw "
452
+ " pointer/reference parameter" ) {
453
+ RTC = RetainTypeChecker ();
454
+ }
455
+
456
+ std::optional<bool > isUnsafeType (QualType QT) const final {
457
+ return RTC->isUnretained (QT);
458
+ }
459
+
460
+ std::optional<bool > isUnsafePtr (QualType QT) const final {
461
+ return RTC->isUnretained (QT);
462
+ }
463
+
464
+ bool isSafePtr (const CXXRecordDecl *Record) const final {
465
+ return isRetainPtr (Record);
466
+ }
467
+
468
+ bool isSafePtrType (const QualType type) const final {
469
+ return isRetainPtrType (type);
470
+ }
471
+
472
+ const char *ptrKind () const final { return " unretained" ; }
473
+ };
474
+
359
475
} // namespace
360
476
361
477
void ento::registerUncountedCallArgsChecker (CheckerManager &Mgr) {
@@ -373,3 +489,11 @@ void ento::registerUncheckedCallArgsChecker(CheckerManager &Mgr) {
373
489
bool ento::shouldRegisterUncheckedCallArgsChecker (const CheckerManager &) {
374
490
return true ;
375
491
}
492
+
493
+ void ento::registerUnretainedCallArgsChecker (CheckerManager &Mgr) {
494
+ Mgr.registerChecker <UnretainedCallArgsChecker>();
495
+ }
496
+
497
+ bool ento::shouldRegisterUnretainedCallArgsChecker (const CheckerManager &) {
498
+ return true ;
499
+ }
0 commit comments