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