15ffd83dbSDimitry Andric //=======- UncountedCallArgsChecker.cpp --------------------------*- C++ -*-==// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric 95ffd83dbSDimitry Andric #include "ASTUtils.h" 105ffd83dbSDimitry Andric #include "DiagOutputUtils.h" 115ffd83dbSDimitry Andric #include "PtrTypesSemantics.h" 125ffd83dbSDimitry Andric #include "clang/AST/CXXInheritance.h" 135ffd83dbSDimitry Andric #include "clang/AST/Decl.h" 145ffd83dbSDimitry Andric #include "clang/AST/DeclCXX.h" 155ffd83dbSDimitry Andric #include "clang/AST/RecursiveASTVisitor.h" 165ffd83dbSDimitry Andric #include "clang/Basic/SourceLocation.h" 175ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 185ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 195ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 205ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 215ffd83dbSDimitry Andric #include "llvm/ADT/DenseSet.h" 225ffd83dbSDimitry Andric 235ffd83dbSDimitry Andric using namespace clang; 245ffd83dbSDimitry Andric using namespace ento; 255ffd83dbSDimitry Andric 265ffd83dbSDimitry Andric namespace { 275ffd83dbSDimitry Andric 285ffd83dbSDimitry Andric class UncountedCallArgsChecker 295ffd83dbSDimitry Andric : public Checker<check::ASTDecl<TranslationUnitDecl>> { 305ffd83dbSDimitry Andric BugType Bug{this, 315ffd83dbSDimitry Andric "Uncounted call argument for a raw pointer/reference parameter", 325ffd83dbSDimitry Andric "WebKit coding guidelines"}; 335ffd83dbSDimitry Andric mutable BugReporter *BR; 345ffd83dbSDimitry Andric 355ffd83dbSDimitry Andric public: 365ffd83dbSDimitry Andric 375ffd83dbSDimitry Andric void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR, 385ffd83dbSDimitry Andric BugReporter &BRArg) const { 395ffd83dbSDimitry Andric BR = &BRArg; 405ffd83dbSDimitry Andric 415ffd83dbSDimitry Andric // The calls to checkAST* from AnalysisConsumer don't 425ffd83dbSDimitry Andric // visit template instantiations or lambda classes. We 435ffd83dbSDimitry Andric // want to visit those, so we make our own RecursiveASTVisitor. 445ffd83dbSDimitry Andric struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> { 455ffd83dbSDimitry Andric const UncountedCallArgsChecker *Checker; 465ffd83dbSDimitry Andric explicit LocalVisitor(const UncountedCallArgsChecker *Checker) 475ffd83dbSDimitry Andric : Checker(Checker) { 485ffd83dbSDimitry Andric assert(Checker); 495ffd83dbSDimitry Andric } 505ffd83dbSDimitry Andric 515ffd83dbSDimitry Andric bool shouldVisitTemplateInstantiations() const { return true; } 525ffd83dbSDimitry Andric bool shouldVisitImplicitCode() const { return false; } 535ffd83dbSDimitry Andric 545ffd83dbSDimitry Andric bool VisitCallExpr(const CallExpr *CE) { 555ffd83dbSDimitry Andric Checker->visitCallExpr(CE); 565ffd83dbSDimitry Andric return true; 575ffd83dbSDimitry Andric } 585ffd83dbSDimitry Andric }; 595ffd83dbSDimitry Andric 605ffd83dbSDimitry Andric LocalVisitor visitor(this); 615ffd83dbSDimitry Andric visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD)); 625ffd83dbSDimitry Andric } 635ffd83dbSDimitry Andric 645ffd83dbSDimitry Andric void visitCallExpr(const CallExpr *CE) const { 655ffd83dbSDimitry Andric if (shouldSkipCall(CE)) 665ffd83dbSDimitry Andric return; 675ffd83dbSDimitry Andric 685ffd83dbSDimitry Andric if (auto *F = CE->getDirectCallee()) { 695ffd83dbSDimitry Andric // Skip the first argument for overloaded member operators (e. g. lambda 705ffd83dbSDimitry Andric // or std::function call operator). 715ffd83dbSDimitry Andric unsigned ArgIdx = 725ffd83dbSDimitry Andric isa<CXXOperatorCallExpr>(CE) && dyn_cast_or_null<CXXMethodDecl>(F); 735ffd83dbSDimitry Andric 745ffd83dbSDimitry Andric for (auto P = F->param_begin(); 755ffd83dbSDimitry Andric // FIXME: Also check variadic function parameters. 765ffd83dbSDimitry Andric // FIXME: Also check default function arguments. Probably a different 775ffd83dbSDimitry Andric // checker. In case there are default arguments the call can have 785ffd83dbSDimitry Andric // fewer arguments than the callee has parameters. 795ffd83dbSDimitry Andric P < F->param_end() && ArgIdx < CE->getNumArgs(); ++P, ++ArgIdx) { 805ffd83dbSDimitry Andric // TODO: attributes. 815ffd83dbSDimitry Andric // if ((*P)->hasAttr<SafeRefCntblRawPtrAttr>()) 825ffd83dbSDimitry Andric // continue; 835ffd83dbSDimitry Andric 845ffd83dbSDimitry Andric const auto *ArgType = (*P)->getType().getTypePtrOrNull(); 855ffd83dbSDimitry Andric if (!ArgType) 865ffd83dbSDimitry Andric continue; // FIXME? Should we bail? 875ffd83dbSDimitry Andric 885ffd83dbSDimitry Andric // FIXME: more complex types (arrays, references to raw pointers, etc) 89*e8d8bef9SDimitry Andric Optional<bool> IsUncounted = isUncountedPtr(ArgType); 90*e8d8bef9SDimitry Andric if (!IsUncounted || !(*IsUncounted)) 915ffd83dbSDimitry Andric continue; 925ffd83dbSDimitry Andric 935ffd83dbSDimitry Andric const auto *Arg = CE->getArg(ArgIdx); 945ffd83dbSDimitry Andric 955ffd83dbSDimitry Andric std::pair<const clang::Expr *, bool> ArgOrigin = 965ffd83dbSDimitry Andric tryToFindPtrOrigin(Arg, true); 975ffd83dbSDimitry Andric 985ffd83dbSDimitry Andric // Temporary ref-counted object created as part of the call argument 995ffd83dbSDimitry Andric // would outlive the call. 1005ffd83dbSDimitry Andric if (ArgOrigin.second) 1015ffd83dbSDimitry Andric continue; 1025ffd83dbSDimitry Andric 1035ffd83dbSDimitry Andric if (isa<CXXNullPtrLiteralExpr>(ArgOrigin.first)) { 1045ffd83dbSDimitry Andric // foo(nullptr) 1055ffd83dbSDimitry Andric continue; 1065ffd83dbSDimitry Andric } 1075ffd83dbSDimitry Andric if (isa<IntegerLiteral>(ArgOrigin.first)) { 1085ffd83dbSDimitry Andric // FIXME: Check the value. 1095ffd83dbSDimitry Andric // foo(NULL) 1105ffd83dbSDimitry Andric continue; 1115ffd83dbSDimitry Andric } 1125ffd83dbSDimitry Andric 1135ffd83dbSDimitry Andric if (isASafeCallArg(ArgOrigin.first)) 1145ffd83dbSDimitry Andric continue; 1155ffd83dbSDimitry Andric 1165ffd83dbSDimitry Andric reportBug(Arg, *P); 1175ffd83dbSDimitry Andric } 1185ffd83dbSDimitry Andric } 1195ffd83dbSDimitry Andric } 1205ffd83dbSDimitry Andric 1215ffd83dbSDimitry Andric bool shouldSkipCall(const CallExpr *CE) const { 1225ffd83dbSDimitry Andric if (CE->getNumArgs() == 0) 1235ffd83dbSDimitry Andric return false; 1245ffd83dbSDimitry Andric 1255ffd83dbSDimitry Andric // If an assignment is problematic we should warn about the sole existence 1265ffd83dbSDimitry Andric // of object on LHS. 1275ffd83dbSDimitry Andric if (auto *MemberOp = dyn_cast<CXXOperatorCallExpr>(CE)) { 1285ffd83dbSDimitry Andric // Note: assignemnt to built-in type isn't derived from CallExpr. 1295ffd83dbSDimitry Andric if (MemberOp->isAssignmentOp()) 1305ffd83dbSDimitry Andric return false; 1315ffd83dbSDimitry Andric } 1325ffd83dbSDimitry Andric 1335ffd83dbSDimitry Andric const auto *Callee = CE->getDirectCallee(); 1345ffd83dbSDimitry Andric if (!Callee) 1355ffd83dbSDimitry Andric return false; 1365ffd83dbSDimitry Andric 1375ffd83dbSDimitry Andric auto overloadedOperatorType = Callee->getOverloadedOperator(); 1385ffd83dbSDimitry Andric if (overloadedOperatorType == OO_EqualEqual || 1395ffd83dbSDimitry Andric overloadedOperatorType == OO_ExclaimEqual || 1405ffd83dbSDimitry Andric overloadedOperatorType == OO_LessEqual || 1415ffd83dbSDimitry Andric overloadedOperatorType == OO_GreaterEqual || 1425ffd83dbSDimitry Andric overloadedOperatorType == OO_Spaceship || 1435ffd83dbSDimitry Andric overloadedOperatorType == OO_AmpAmp || 1445ffd83dbSDimitry Andric overloadedOperatorType == OO_PipePipe) 1455ffd83dbSDimitry Andric return true; 1465ffd83dbSDimitry Andric 1475ffd83dbSDimitry Andric if (isCtorOfRefCounted(Callee)) 1485ffd83dbSDimitry Andric return true; 1495ffd83dbSDimitry Andric 1505ffd83dbSDimitry Andric auto name = safeGetName(Callee); 1515ffd83dbSDimitry Andric if (name == "adoptRef" || name == "getPtr" || name == "WeakPtr" || 1525ffd83dbSDimitry Andric name == "makeWeakPtr" || name == "downcast" || name == "bitwise_cast" || 1535ffd83dbSDimitry Andric name == "is" || name == "equal" || name == "hash" || 1545ffd83dbSDimitry Andric name == "isType" 1555ffd83dbSDimitry Andric // FIXME: Most/all of these should be implemented via attributes. 1565ffd83dbSDimitry Andric || name == "equalIgnoringASCIICase" || 1575ffd83dbSDimitry Andric name == "equalIgnoringASCIICaseCommon" || 1585ffd83dbSDimitry Andric name == "equalIgnoringNullity") 1595ffd83dbSDimitry Andric return true; 1605ffd83dbSDimitry Andric 1615ffd83dbSDimitry Andric return false; 1625ffd83dbSDimitry Andric } 1635ffd83dbSDimitry Andric 1645ffd83dbSDimitry Andric void reportBug(const Expr *CallArg, const ParmVarDecl *Param) const { 1655ffd83dbSDimitry Andric assert(CallArg); 1665ffd83dbSDimitry Andric 1675ffd83dbSDimitry Andric SmallString<100> Buf; 1685ffd83dbSDimitry Andric llvm::raw_svector_ostream Os(Buf); 1695ffd83dbSDimitry Andric 1705ffd83dbSDimitry Andric const std::string paramName = safeGetName(Param); 1715ffd83dbSDimitry Andric Os << "Call argument"; 1725ffd83dbSDimitry Andric if (!paramName.empty()) { 1735ffd83dbSDimitry Andric Os << " for parameter "; 1745ffd83dbSDimitry Andric printQuotedQualifiedName(Os, Param); 1755ffd83dbSDimitry Andric } 1765ffd83dbSDimitry Andric Os << " is uncounted and unsafe."; 1775ffd83dbSDimitry Andric 1785ffd83dbSDimitry Andric const SourceLocation SrcLocToReport = 1795ffd83dbSDimitry Andric isa<CXXDefaultArgExpr>(CallArg) ? Param->getDefaultArg()->getExprLoc() 1805ffd83dbSDimitry Andric : CallArg->getSourceRange().getBegin(); 1815ffd83dbSDimitry Andric 1825ffd83dbSDimitry Andric PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager()); 1835ffd83dbSDimitry Andric auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc); 1845ffd83dbSDimitry Andric Report->addRange(CallArg->getSourceRange()); 1855ffd83dbSDimitry Andric BR->emitReport(std::move(Report)); 1865ffd83dbSDimitry Andric } 1875ffd83dbSDimitry Andric }; 1885ffd83dbSDimitry Andric } // namespace 1895ffd83dbSDimitry Andric 1905ffd83dbSDimitry Andric void ento::registerUncountedCallArgsChecker(CheckerManager &Mgr) { 1915ffd83dbSDimitry Andric Mgr.registerChecker<UncountedCallArgsChecker>(); 1925ffd83dbSDimitry Andric } 1935ffd83dbSDimitry Andric 1945ffd83dbSDimitry Andric bool ento::shouldRegisterUncountedCallArgsChecker(const CheckerManager &) { 1955ffd83dbSDimitry Andric return true; 1965ffd83dbSDimitry Andric } 197