1 //=======- UncountedCallArgsChecker.cpp --------------------------*- C++ -*-==//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #include "DiagOutputUtils.h"
11 #include "PtrTypesSemantics.h"
12 #include "clang/AST/CXXInheritance.h"
13 #include "clang/AST/Decl.h"
14 #include "clang/AST/DeclCXX.h"
15 #include "clang/AST/RecursiveASTVisitor.h"
16 #include "clang/Basic/SourceLocation.h"
17 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
19 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20 #include "clang/StaticAnalyzer/Core/Checker.h"
21 #include "llvm/ADT/DenseSet.h"
24 using namespace clang
;
29 class UncountedCallArgsChecker
30 : public Checker
<check::ASTDecl
<TranslationUnitDecl
>> {
32 "Uncounted call argument for a raw pointer/reference parameter",
33 "WebKit coding guidelines"};
34 mutable BugReporter
*BR
;
38 void checkASTDecl(const TranslationUnitDecl
*TUD
, AnalysisManager
&MGR
,
39 BugReporter
&BRArg
) const {
42 // The calls to checkAST* from AnalysisConsumer don't
43 // visit template instantiations or lambda classes. We
44 // want to visit those, so we make our own RecursiveASTVisitor.
45 struct LocalVisitor
: public RecursiveASTVisitor
<LocalVisitor
> {
46 const UncountedCallArgsChecker
*Checker
;
47 explicit LocalVisitor(const UncountedCallArgsChecker
*Checker
)
52 bool shouldVisitTemplateInstantiations() const { return true; }
53 bool shouldVisitImplicitCode() const { return false; }
55 bool VisitCallExpr(const CallExpr
*CE
) {
56 Checker
->visitCallExpr(CE
);
61 LocalVisitor
visitor(this);
62 visitor
.TraverseDecl(const_cast<TranslationUnitDecl
*>(TUD
));
65 void visitCallExpr(const CallExpr
*CE
) const {
66 if (shouldSkipCall(CE
))
69 if (auto *F
= CE
->getDirectCallee()) {
70 // Skip the first argument for overloaded member operators (e. g. lambda
71 // or std::function call operator).
72 unsigned ArgIdx
= isa
<CXXOperatorCallExpr
>(CE
) && isa_and_nonnull
<CXXMethodDecl
>(F
);
74 for (auto P
= F
->param_begin();
75 // FIXME: Also check variadic function parameters.
76 // FIXME: Also check default function arguments. Probably a different
77 // checker. In case there are default arguments the call can have
78 // fewer arguments than the callee has parameters.
79 P
< F
->param_end() && ArgIdx
< CE
->getNumArgs(); ++P
, ++ArgIdx
) {
81 // if ((*P)->hasAttr<SafeRefCntblRawPtrAttr>())
84 const auto *ArgType
= (*P
)->getType().getTypePtrOrNull();
86 continue; // FIXME? Should we bail?
88 // FIXME: more complex types (arrays, references to raw pointers, etc)
89 std::optional
<bool> IsUncounted
= isUncountedPtr(ArgType
);
90 if (!IsUncounted
|| !(*IsUncounted
))
93 const auto *Arg
= CE
->getArg(ArgIdx
);
95 std::pair
<const clang::Expr
*, bool> ArgOrigin
=
96 tryToFindPtrOrigin(Arg
, true);
98 // Temporary ref-counted object created as part of the call argument
99 // would outlive the call.
100 if (ArgOrigin
.second
)
103 if (isa
<CXXNullPtrLiteralExpr
>(ArgOrigin
.first
)) {
107 if (isa
<IntegerLiteral
>(ArgOrigin
.first
)) {
108 // FIXME: Check the value.
113 if (isASafeCallArg(ArgOrigin
.first
))
121 bool shouldSkipCall(const CallExpr
*CE
) const {
122 if (CE
->getNumArgs() == 0)
125 // If an assignment is problematic we should warn about the sole existence
127 if (auto *MemberOp
= dyn_cast
<CXXOperatorCallExpr
>(CE
)) {
128 // Note: assignemnt to built-in type isn't derived from CallExpr.
129 if (MemberOp
->isAssignmentOp())
133 const auto *Callee
= CE
->getDirectCallee();
137 auto overloadedOperatorType
= Callee
->getOverloadedOperator();
138 if (overloadedOperatorType
== OO_EqualEqual
||
139 overloadedOperatorType
== OO_ExclaimEqual
||
140 overloadedOperatorType
== OO_LessEqual
||
141 overloadedOperatorType
== OO_GreaterEqual
||
142 overloadedOperatorType
== OO_Spaceship
||
143 overloadedOperatorType
== OO_AmpAmp
||
144 overloadedOperatorType
== OO_PipePipe
)
147 if (isCtorOfRefCounted(Callee
))
150 auto name
= safeGetName(Callee
);
151 if (name
== "adoptRef" || name
== "getPtr" || name
== "WeakPtr" ||
152 name
== "dynamicDowncast" || name
== "downcast" || name
== "bitwise_cast" ||
153 name
== "is" || name
== "equal" || name
== "hash" ||
155 // FIXME: Most/all of these should be implemented via attributes.
156 || name
== "equalIgnoringASCIICase" ||
157 name
== "equalIgnoringASCIICaseCommon" ||
158 name
== "equalIgnoringNullity")
164 void reportBug(const Expr
*CallArg
, const ParmVarDecl
*Param
) const {
167 SmallString
<100> Buf
;
168 llvm::raw_svector_ostream
Os(Buf
);
170 const std::string paramName
= safeGetName(Param
);
171 Os
<< "Call argument";
172 if (!paramName
.empty()) {
173 Os
<< " for parameter ";
174 printQuotedQualifiedName(Os
, Param
);
176 Os
<< " is uncounted and unsafe.";
178 const SourceLocation SrcLocToReport
=
179 isa
<CXXDefaultArgExpr
>(CallArg
) ? Param
->getDefaultArg()->getExprLoc()
180 : CallArg
->getSourceRange().getBegin();
182 PathDiagnosticLocation
BSLoc(SrcLocToReport
, BR
->getSourceManager());
183 auto Report
= std::make_unique
<BasicBugReport
>(Bug
, Os
.str(), BSLoc
);
184 Report
->addRange(CallArg
->getSourceRange());
185 BR
->emitReport(std::move(Report
));
190 void ento::registerUncountedCallArgsChecker(CheckerManager
&Mgr
) {
191 Mgr
.registerChecker
<UncountedCallArgsChecker
>();
194 bool ento::shouldRegisterUncountedCallArgsChecker(const CheckerManager
&) {