[DFAJumpThreading] Remove incoming StartBlock from all phis when unfolding select...
[llvm-project.git] / clang / lib / StaticAnalyzer / Checkers / WebKit / UncountedCallArgsChecker.cpp
blob407b6ba7a76428c72af39d6993fffd882c74ca24
1 //=======- UncountedCallArgsChecker.cpp --------------------------*- C++ -*-==//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
9 #include "ASTUtils.h"
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"
22 #include <optional>
24 using namespace clang;
25 using namespace ento;
27 namespace {
29 class UncountedCallArgsChecker
30 : public Checker<check::ASTDecl<TranslationUnitDecl>> {
31 BugType Bug{this,
32 "Uncounted call argument for a raw pointer/reference parameter",
33 "WebKit coding guidelines"};
34 mutable BugReporter *BR;
36 public:
38 void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
39 BugReporter &BRArg) const {
40 BR = &BRArg;
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)
48 : Checker(Checker) {
49 assert(Checker);
52 bool shouldVisitTemplateInstantiations() const { return true; }
53 bool shouldVisitImplicitCode() const { return false; }
55 bool VisitCallExpr(const CallExpr *CE) {
56 Checker->visitCallExpr(CE);
57 return true;
61 LocalVisitor visitor(this);
62 visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
65 void visitCallExpr(const CallExpr *CE) const {
66 if (shouldSkipCall(CE))
67 return;
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) {
80 // TODO: attributes.
81 // if ((*P)->hasAttr<SafeRefCntblRawPtrAttr>())
82 // continue;
84 const auto *ArgType = (*P)->getType().getTypePtrOrNull();
85 if (!ArgType)
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))
91 continue;
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)
101 continue;
103 if (isa<CXXNullPtrLiteralExpr>(ArgOrigin.first)) {
104 // foo(nullptr)
105 continue;
107 if (isa<IntegerLiteral>(ArgOrigin.first)) {
108 // FIXME: Check the value.
109 // foo(NULL)
110 continue;
113 if (isASafeCallArg(ArgOrigin.first))
114 continue;
116 reportBug(Arg, *P);
121 bool shouldSkipCall(const CallExpr *CE) const {
122 if (CE->getNumArgs() == 0)
123 return false;
125 // If an assignment is problematic we should warn about the sole existence
126 // of object on LHS.
127 if (auto *MemberOp = dyn_cast<CXXOperatorCallExpr>(CE)) {
128 // Note: assignemnt to built-in type isn't derived from CallExpr.
129 if (MemberOp->isAssignmentOp())
130 return false;
133 const auto *Callee = CE->getDirectCallee();
134 if (!Callee)
135 return false;
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)
145 return true;
147 if (isCtorOfRefCounted(Callee))
148 return true;
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" ||
154 name == "isType"
155 // FIXME: Most/all of these should be implemented via attributes.
156 || name == "equalIgnoringASCIICase" ||
157 name == "equalIgnoringASCIICaseCommon" ||
158 name == "equalIgnoringNullity")
159 return true;
161 return false;
164 void reportBug(const Expr *CallArg, const ParmVarDecl *Param) const {
165 assert(CallArg);
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));
188 } // namespace
190 void ento::registerUncountedCallArgsChecker(CheckerManager &Mgr) {
191 Mgr.registerChecker<UncountedCallArgsChecker>();
194 bool ento::shouldRegisterUncountedCallArgsChecker(const CheckerManager &) {
195 return true;