1313#include " clang/AST/Decl.h"
1414#include " clang/AST/DeclCXX.h"
1515#include " clang/AST/DynamicRecursiveASTVisitor.h"
16+ #include " clang/Analysis/DomainSpecific/CocoaConventions.h"
1617#include " clang/Basic/SourceLocation.h"
1718#include " clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
1819#include " clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
@@ -35,6 +36,9 @@ class RawPtrRefCallArgsChecker
3536 TrivialFunctionAnalysis TFA;
3637 EnsureFunctionAnalysis EFA;
3738
39+ protected:
40+ mutable std::optional<RetainTypeChecker> RTC;
41+
3842public:
3943 RawPtrRefCallArgsChecker (const char *description)
4044 : Bug(this , description, " WebKit coding guidelines" ) {}
@@ -80,9 +84,22 @@ class RawPtrRefCallArgsChecker
8084 Checker->visitCallExpr (CE, DeclWithIssue);
8185 return true ;
8286 }
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+ }
8398 };
8499
85100 LocalVisitor visitor (this );
101+ if (RTC)
102+ RTC->visitTranslationUnitDecl (TUD);
86103 visitor.TraverseDecl (const_cast <TranslationUnitDecl *>(TUD));
87104 }
88105
@@ -122,7 +139,7 @@ class RawPtrRefCallArgsChecker
122139 // if ((*P)->hasAttr<SafeRefCntblRawPtrAttr>())
123140 // continue;
124141
125- QualType ArgType = (*P)->getType (). getCanonicalType () ;
142+ QualType ArgType = (*P)->getType ();
126143 // FIXME: more complex types (arrays, references to raw pointers, etc)
127144 std::optional<bool > IsUncounted = isUnsafePtr (ArgType);
128145 if (!IsUncounted || !(*IsUncounted))
@@ -138,6 +155,58 @@ class RawPtrRefCallArgsChecker
138155
139156 reportBug (Arg, *P, D);
140157 }
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);
141210 }
142211 }
143212
@@ -158,6 +227,8 @@ class RawPtrRefCallArgsChecker
158227 // foo(NULL)
159228 return true ;
160229 }
230+ if (isa<ObjCStringLiteral>(ArgOrigin))
231+ return true ;
161232 if (isASafeCallArg (ArgOrigin))
162233 return true ;
163234 if (EFA.isACallToEnsureFn (ArgOrigin))
@@ -212,7 +283,7 @@ class RawPtrRefCallArgsChecker
212283 overloadedOperatorType == OO_PipePipe)
213284 return true ;
214285
215- if (isCtorOfRefCounted (Callee))
286+ if (isCtorOfSafePtr (Callee))
216287 return true ;
217288
218289 auto name = safeGetName (Callee);
@@ -277,9 +348,10 @@ class RawPtrRefCallArgsChecker
277348 }
278349 Os << " is " << ptrKind () << " and unsafe." ;
279350
351+ bool usesDefaultArgValue = isa<CXXDefaultArgExpr>(CallArg) && Param;
280352 const SourceLocation SrcLocToReport =
281- isa<CXXDefaultArgExpr>(CallArg) ? Param->getDefaultArg ()->getExprLoc ()
282- : CallArg->getSourceRange ().getBegin ();
353+ usesDefaultArgValue ? Param->getDefaultArg ()->getExprLoc ()
354+ : CallArg->getSourceRange ().getBegin ();
283355
284356 PathDiagnosticLocation BSLoc (SrcLocToReport, BR->getSourceManager ());
285357 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str (), BSLoc);
@@ -304,6 +376,23 @@ class RawPtrRefCallArgsChecker
304376 Report->setDeclWithIssue (DeclWithIssue);
305377 BR->emitReport (std::move (Report));
306378 }
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+ }
307396};
308397
309398class UncountedCallArgsChecker final : public RawPtrRefCallArgsChecker {
@@ -317,7 +406,7 @@ class UncountedCallArgsChecker final : public RawPtrRefCallArgsChecker {
317406 }
318407
319408 std::optional<bool > isUnsafePtr (QualType QT) const final {
320- return isUncountedPtr (QT);
409+ return isUncountedPtr (QT. getCanonicalType () );
321410 }
322411
323412 bool isSafePtr (const CXXRecordDecl *Record) const final {
@@ -342,7 +431,7 @@ class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker {
342431 }
343432
344433 std::optional<bool > isUnsafePtr (QualType QT) const final {
345- return isUncheckedPtr (QT);
434+ return isUncheckedPtr (QT. getCanonicalType () );
346435 }
347436
348437 bool isSafePtr (const CXXRecordDecl *Record) const final {
@@ -356,6 +445,33 @@ class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker {
356445 const char *ptrKind () const final { return " unchecked" ; }
357446};
358447
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+
359475} // namespace
360476
361477void ento::registerUncountedCallArgsChecker (CheckerManager &Mgr) {
@@ -373,3 +489,11 @@ void ento::registerUncheckedCallArgsChecker(CheckerManager &Mgr) {
373489bool ento::shouldRegisterUncheckedCallArgsChecker (const CheckerManager &) {
374490 return true ;
375491}
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