1*e038c9c4Sjoerg //=======- UncountedCallArgsChecker.cpp --------------------------*- C++ -*-==//
2*e038c9c4Sjoerg //
3*e038c9c4Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*e038c9c4Sjoerg // See https://llvm.org/LICENSE.txt for license information.
5*e038c9c4Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*e038c9c4Sjoerg //
7*e038c9c4Sjoerg //===----------------------------------------------------------------------===//
8*e038c9c4Sjoerg 
9*e038c9c4Sjoerg #include "ASTUtils.h"
10*e038c9c4Sjoerg #include "DiagOutputUtils.h"
11*e038c9c4Sjoerg #include "PtrTypesSemantics.h"
12*e038c9c4Sjoerg #include "clang/AST/CXXInheritance.h"
13*e038c9c4Sjoerg #include "clang/AST/Decl.h"
14*e038c9c4Sjoerg #include "clang/AST/DeclCXX.h"
15*e038c9c4Sjoerg #include "clang/AST/RecursiveASTVisitor.h"
16*e038c9c4Sjoerg #include "clang/Basic/SourceLocation.h"
17*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
19*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
21*e038c9c4Sjoerg #include "llvm/ADT/DenseSet.h"
22*e038c9c4Sjoerg 
23*e038c9c4Sjoerg using namespace clang;
24*e038c9c4Sjoerg using namespace ento;
25*e038c9c4Sjoerg 
26*e038c9c4Sjoerg namespace {
27*e038c9c4Sjoerg 
28*e038c9c4Sjoerg class UncountedCallArgsChecker
29*e038c9c4Sjoerg     : public Checker<check::ASTDecl<TranslationUnitDecl>> {
30*e038c9c4Sjoerg   BugType Bug{this,
31*e038c9c4Sjoerg             "Uncounted call argument for a raw pointer/reference parameter",
32*e038c9c4Sjoerg             "WebKit coding guidelines"};
33*e038c9c4Sjoerg   mutable BugReporter *BR;
34*e038c9c4Sjoerg 
35*e038c9c4Sjoerg public:
36*e038c9c4Sjoerg 
checkASTDecl(const TranslationUnitDecl * TUD,AnalysisManager & MGR,BugReporter & BRArg) const37*e038c9c4Sjoerg   void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
38*e038c9c4Sjoerg                     BugReporter &BRArg) const {
39*e038c9c4Sjoerg     BR = &BRArg;
40*e038c9c4Sjoerg 
41*e038c9c4Sjoerg     // The calls to checkAST* from AnalysisConsumer don't
42*e038c9c4Sjoerg     // visit template instantiations or lambda classes. We
43*e038c9c4Sjoerg     // want to visit those, so we make our own RecursiveASTVisitor.
44*e038c9c4Sjoerg     struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
45*e038c9c4Sjoerg       const UncountedCallArgsChecker *Checker;
46*e038c9c4Sjoerg       explicit LocalVisitor(const UncountedCallArgsChecker *Checker)
47*e038c9c4Sjoerg           : Checker(Checker) {
48*e038c9c4Sjoerg         assert(Checker);
49*e038c9c4Sjoerg       }
50*e038c9c4Sjoerg 
51*e038c9c4Sjoerg       bool shouldVisitTemplateInstantiations() const { return true; }
52*e038c9c4Sjoerg       bool shouldVisitImplicitCode() const { return false; }
53*e038c9c4Sjoerg 
54*e038c9c4Sjoerg       bool VisitCallExpr(const CallExpr *CE) {
55*e038c9c4Sjoerg         Checker->visitCallExpr(CE);
56*e038c9c4Sjoerg         return true;
57*e038c9c4Sjoerg       }
58*e038c9c4Sjoerg     };
59*e038c9c4Sjoerg 
60*e038c9c4Sjoerg     LocalVisitor visitor(this);
61*e038c9c4Sjoerg     visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
62*e038c9c4Sjoerg   }
63*e038c9c4Sjoerg 
visitCallExpr(const CallExpr * CE) const64*e038c9c4Sjoerg   void visitCallExpr(const CallExpr *CE) const {
65*e038c9c4Sjoerg     if (shouldSkipCall(CE))
66*e038c9c4Sjoerg       return;
67*e038c9c4Sjoerg 
68*e038c9c4Sjoerg     if (auto *F = CE->getDirectCallee()) {
69*e038c9c4Sjoerg       // Skip the first argument for overloaded member operators (e. g. lambda
70*e038c9c4Sjoerg       // or std::function call operator).
71*e038c9c4Sjoerg       unsigned ArgIdx =
72*e038c9c4Sjoerg           isa<CXXOperatorCallExpr>(CE) && dyn_cast_or_null<CXXMethodDecl>(F);
73*e038c9c4Sjoerg 
74*e038c9c4Sjoerg       for (auto P = F->param_begin();
75*e038c9c4Sjoerg            // FIXME: Also check variadic function parameters.
76*e038c9c4Sjoerg            // FIXME: Also check default function arguments. Probably a different
77*e038c9c4Sjoerg            // checker. In case there are default arguments the call can have
78*e038c9c4Sjoerg            // fewer arguments than the callee has parameters.
79*e038c9c4Sjoerg            P < F->param_end() && ArgIdx < CE->getNumArgs(); ++P, ++ArgIdx) {
80*e038c9c4Sjoerg         // TODO: attributes.
81*e038c9c4Sjoerg         // if ((*P)->hasAttr<SafeRefCntblRawPtrAttr>())
82*e038c9c4Sjoerg         //  continue;
83*e038c9c4Sjoerg 
84*e038c9c4Sjoerg         const auto *ArgType = (*P)->getType().getTypePtrOrNull();
85*e038c9c4Sjoerg         if (!ArgType)
86*e038c9c4Sjoerg           continue; // FIXME? Should we bail?
87*e038c9c4Sjoerg 
88*e038c9c4Sjoerg         // FIXME: more complex types (arrays, references to raw pointers, etc)
89*e038c9c4Sjoerg         Optional<bool> IsUncounted = isUncountedPtr(ArgType);
90*e038c9c4Sjoerg         if (!IsUncounted || !(*IsUncounted))
91*e038c9c4Sjoerg           continue;
92*e038c9c4Sjoerg 
93*e038c9c4Sjoerg         const auto *Arg = CE->getArg(ArgIdx);
94*e038c9c4Sjoerg 
95*e038c9c4Sjoerg         std::pair<const clang::Expr *, bool> ArgOrigin =
96*e038c9c4Sjoerg             tryToFindPtrOrigin(Arg, true);
97*e038c9c4Sjoerg 
98*e038c9c4Sjoerg         // Temporary ref-counted object created as part of the call argument
99*e038c9c4Sjoerg         // would outlive the call.
100*e038c9c4Sjoerg         if (ArgOrigin.second)
101*e038c9c4Sjoerg           continue;
102*e038c9c4Sjoerg 
103*e038c9c4Sjoerg         if (isa<CXXNullPtrLiteralExpr>(ArgOrigin.first)) {
104*e038c9c4Sjoerg           // foo(nullptr)
105*e038c9c4Sjoerg           continue;
106*e038c9c4Sjoerg         }
107*e038c9c4Sjoerg         if (isa<IntegerLiteral>(ArgOrigin.first)) {
108*e038c9c4Sjoerg           // FIXME: Check the value.
109*e038c9c4Sjoerg           // foo(NULL)
110*e038c9c4Sjoerg           continue;
111*e038c9c4Sjoerg         }
112*e038c9c4Sjoerg 
113*e038c9c4Sjoerg         if (isASafeCallArg(ArgOrigin.first))
114*e038c9c4Sjoerg           continue;
115*e038c9c4Sjoerg 
116*e038c9c4Sjoerg         reportBug(Arg, *P);
117*e038c9c4Sjoerg       }
118*e038c9c4Sjoerg     }
119*e038c9c4Sjoerg   }
120*e038c9c4Sjoerg 
shouldSkipCall(const CallExpr * CE) const121*e038c9c4Sjoerg   bool shouldSkipCall(const CallExpr *CE) const {
122*e038c9c4Sjoerg     if (CE->getNumArgs() == 0)
123*e038c9c4Sjoerg       return false;
124*e038c9c4Sjoerg 
125*e038c9c4Sjoerg     // If an assignment is problematic we should warn about the sole existence
126*e038c9c4Sjoerg     // of object on LHS.
127*e038c9c4Sjoerg     if (auto *MemberOp = dyn_cast<CXXOperatorCallExpr>(CE)) {
128*e038c9c4Sjoerg       // Note: assignemnt to built-in type isn't derived from CallExpr.
129*e038c9c4Sjoerg       if (MemberOp->isAssignmentOp())
130*e038c9c4Sjoerg         return false;
131*e038c9c4Sjoerg     }
132*e038c9c4Sjoerg 
133*e038c9c4Sjoerg     const auto *Callee = CE->getDirectCallee();
134*e038c9c4Sjoerg     if (!Callee)
135*e038c9c4Sjoerg       return false;
136*e038c9c4Sjoerg 
137*e038c9c4Sjoerg     auto overloadedOperatorType = Callee->getOverloadedOperator();
138*e038c9c4Sjoerg     if (overloadedOperatorType == OO_EqualEqual ||
139*e038c9c4Sjoerg         overloadedOperatorType == OO_ExclaimEqual ||
140*e038c9c4Sjoerg         overloadedOperatorType == OO_LessEqual ||
141*e038c9c4Sjoerg         overloadedOperatorType == OO_GreaterEqual ||
142*e038c9c4Sjoerg         overloadedOperatorType == OO_Spaceship ||
143*e038c9c4Sjoerg         overloadedOperatorType == OO_AmpAmp ||
144*e038c9c4Sjoerg         overloadedOperatorType == OO_PipePipe)
145*e038c9c4Sjoerg       return true;
146*e038c9c4Sjoerg 
147*e038c9c4Sjoerg     if (isCtorOfRefCounted(Callee))
148*e038c9c4Sjoerg       return true;
149*e038c9c4Sjoerg 
150*e038c9c4Sjoerg     auto name = safeGetName(Callee);
151*e038c9c4Sjoerg     if (name == "adoptRef" || name == "getPtr" || name == "WeakPtr" ||
152*e038c9c4Sjoerg         name == "makeWeakPtr" || name == "downcast" || name == "bitwise_cast" ||
153*e038c9c4Sjoerg         name == "is" || name == "equal" || name == "hash" ||
154*e038c9c4Sjoerg         name == "isType"
155*e038c9c4Sjoerg         // FIXME: Most/all of these should be implemented via attributes.
156*e038c9c4Sjoerg         || name == "equalIgnoringASCIICase" ||
157*e038c9c4Sjoerg         name == "equalIgnoringASCIICaseCommon" ||
158*e038c9c4Sjoerg         name == "equalIgnoringNullity")
159*e038c9c4Sjoerg       return true;
160*e038c9c4Sjoerg 
161*e038c9c4Sjoerg     return false;
162*e038c9c4Sjoerg   }
163*e038c9c4Sjoerg 
reportBug(const Expr * CallArg,const ParmVarDecl * Param) const164*e038c9c4Sjoerg   void reportBug(const Expr *CallArg, const ParmVarDecl *Param) const {
165*e038c9c4Sjoerg     assert(CallArg);
166*e038c9c4Sjoerg 
167*e038c9c4Sjoerg     SmallString<100> Buf;
168*e038c9c4Sjoerg     llvm::raw_svector_ostream Os(Buf);
169*e038c9c4Sjoerg 
170*e038c9c4Sjoerg     const std::string paramName = safeGetName(Param);
171*e038c9c4Sjoerg     Os << "Call argument";
172*e038c9c4Sjoerg     if (!paramName.empty()) {
173*e038c9c4Sjoerg       Os << " for parameter ";
174*e038c9c4Sjoerg       printQuotedQualifiedName(Os, Param);
175*e038c9c4Sjoerg     }
176*e038c9c4Sjoerg     Os << " is uncounted and unsafe.";
177*e038c9c4Sjoerg 
178*e038c9c4Sjoerg     const SourceLocation SrcLocToReport =
179*e038c9c4Sjoerg         isa<CXXDefaultArgExpr>(CallArg) ? Param->getDefaultArg()->getExprLoc()
180*e038c9c4Sjoerg                                         : CallArg->getSourceRange().getBegin();
181*e038c9c4Sjoerg 
182*e038c9c4Sjoerg     PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager());
183*e038c9c4Sjoerg     auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
184*e038c9c4Sjoerg     Report->addRange(CallArg->getSourceRange());
185*e038c9c4Sjoerg     BR->emitReport(std::move(Report));
186*e038c9c4Sjoerg   }
187*e038c9c4Sjoerg };
188*e038c9c4Sjoerg } // namespace
189*e038c9c4Sjoerg 
registerUncountedCallArgsChecker(CheckerManager & Mgr)190*e038c9c4Sjoerg void ento::registerUncountedCallArgsChecker(CheckerManager &Mgr) {
191*e038c9c4Sjoerg   Mgr.registerChecker<UncountedCallArgsChecker>();
192*e038c9c4Sjoerg }
193*e038c9c4Sjoerg 
shouldRegisterUncountedCallArgsChecker(const CheckerManager &)194*e038c9c4Sjoerg bool ento::shouldRegisterUncountedCallArgsChecker(const CheckerManager &) {
195*e038c9c4Sjoerg   return true;
196*e038c9c4Sjoerg }
197