1313#include " clang/AST/Decl.h"
1414#include " clang/AST/DeclCXX.h"
1515#include " clang/AST/RecursiveASTVisitor.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" ) {}
@@ -83,9 +87,22 @@ class RawPtrRefCallArgsChecker
8387 Checker->visitCallExpr (CE, DeclWithIssue);
8488 return true ;
8589 }
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+ }
86101 };
87102
88103 LocalVisitor visitor (this );
104+ if (RTC)
105+ RTC->visitTranslationUnitDecl (TUD);
89106 visitor.TraverseDecl (const_cast <TranslationUnitDecl *>(TUD));
90107 }
91108
@@ -125,7 +142,7 @@ class RawPtrRefCallArgsChecker
125142 // if ((*P)->hasAttr<SafeRefCntblRawPtrAttr>())
126143 // continue;
127144
128- QualType ArgType = (*P)->getType (). getCanonicalType () ;
145+ QualType ArgType = (*P)->getType ();
129146 // FIXME: more complex types (arrays, references to raw pointers, etc)
130147 std::optional<bool > IsUncounted = isUnsafePtr (ArgType);
131148 if (!IsUncounted || !(*IsUncounted))
@@ -141,6 +158,58 @@ class RawPtrRefCallArgsChecker
141158
142159 reportBug (Arg, *P, D);
143160 }
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);
144213 }
145214 }
146215
@@ -161,6 +230,8 @@ class RawPtrRefCallArgsChecker
161230 // foo(NULL)
162231 return true ;
163232 }
233+ if (isa<ObjCStringLiteral>(ArgOrigin))
234+ return true ;
164235 if (isASafeCallArg (ArgOrigin))
165236 return true ;
166237 if (EFA.isACallToEnsureFn (ArgOrigin))
@@ -215,7 +286,7 @@ class RawPtrRefCallArgsChecker
215286 overloadedOperatorType == OO_PipePipe)
216287 return true ;
217288
218- if (isCtorOfRefCounted (Callee))
289+ if (isCtorOfSafePtr (Callee))
219290 return true ;
220291
221292 auto name = safeGetName (Callee);
@@ -280,9 +351,10 @@ class RawPtrRefCallArgsChecker
280351 }
281352 Os << " is " << ptrKind () << " and unsafe." ;
282353
354+ bool usesDefaultArgValue = isa<CXXDefaultArgExpr>(CallArg) && Param;
283355 const SourceLocation SrcLocToReport =
284- isa<CXXDefaultArgExpr>(CallArg) ? Param->getDefaultArg ()->getExprLoc ()
285- : CallArg->getSourceRange ().getBegin ();
356+ usesDefaultArgValue ? Param->getDefaultArg ()->getExprLoc ()
357+ : CallArg->getSourceRange ().getBegin ();
286358
287359 PathDiagnosticLocation BSLoc (SrcLocToReport, BR->getSourceManager ());
288360 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str (), BSLoc);
@@ -307,6 +379,23 @@ class RawPtrRefCallArgsChecker
307379 Report->setDeclWithIssue (DeclWithIssue);
308380 BR->emitReport (std::move (Report));
309381 }
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+ }
310399};
311400
312401class UncountedCallArgsChecker final : public RawPtrRefCallArgsChecker {
@@ -320,7 +409,7 @@ class UncountedCallArgsChecker final : public RawPtrRefCallArgsChecker {
320409 }
321410
322411 std::optional<bool > isUnsafePtr (QualType QT) const final {
323- return isUncountedPtr (QT);
412+ return isUncountedPtr (QT. getCanonicalType () );
324413 }
325414
326415 bool isSafePtr (const CXXRecordDecl *Record) const final {
@@ -345,7 +434,7 @@ class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker {
345434 }
346435
347436 std::optional<bool > isUnsafePtr (QualType QT) const final {
348- return isUncheckedPtr (QT);
437+ return isUncheckedPtr (QT. getCanonicalType () );
349438 }
350439
351440 bool isSafePtr (const CXXRecordDecl *Record) const final {
@@ -359,6 +448,33 @@ class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker {
359448 const char *ptrKind () const final { return " unchecked" ; }
360449};
361450
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+
362478} // namespace
363479
364480void ento::registerUncountedCallArgsChecker (CheckerManager &Mgr) {
@@ -376,3 +492,11 @@ void ento::registerUncheckedCallArgsChecker(CheckerManager &Mgr) {
376492bool ento::shouldRegisterUncheckedCallArgsChecker (const CheckerManager &) {
377493 return true ;
378494}
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