1*600a6133SYan Wang //===--- CloexecOpenCheck.cpp - clang-tidy---------------------------------===// 2*600a6133SYan Wang // 3*600a6133SYan Wang // The LLVM Compiler Infrastructure 4*600a6133SYan Wang // 5*600a6133SYan Wang // This file is distributed under the University of Illinois Open Source 6*600a6133SYan Wang // License. See LICENSE.TXT for details. 7*600a6133SYan Wang // 8*600a6133SYan Wang //===----------------------------------------------------------------------===// 9*600a6133SYan Wang 10*600a6133SYan Wang #include "CloexecOpenCheck.h" 11*600a6133SYan Wang #include "clang/AST/ASTContext.h" 12*600a6133SYan Wang #include "clang/ASTMatchers/ASTMatchFinder.h" 13*600a6133SYan Wang #include "clang/Lex/Lexer.h" 14*600a6133SYan Wang 15*600a6133SYan Wang using namespace clang::ast_matchers; 16*600a6133SYan Wang 17*600a6133SYan Wang namespace clang { 18*600a6133SYan Wang namespace tidy { 19*600a6133SYan Wang namespace android { 20*600a6133SYan Wang 21*600a6133SYan Wang namespace { 22*600a6133SYan Wang static constexpr const char *O_CLOEXEC = "O_CLOEXEC"; 23*600a6133SYan Wang 24*600a6133SYan Wang bool hasCloseOnExecFlag(const Expr *Flags, const SourceManager &SM, 25*600a6133SYan Wang const LangOptions &LangOpts) { 26*600a6133SYan Wang // If the Flag is an integer constant, check it. 27*600a6133SYan Wang if (isa<IntegerLiteral>(Flags)) { 28*600a6133SYan Wang if (!SM.isMacroBodyExpansion(Flags->getLocStart()) && 29*600a6133SYan Wang !SM.isMacroArgExpansion(Flags->getLocStart())) 30*600a6133SYan Wang return false; 31*600a6133SYan Wang 32*600a6133SYan Wang // Get the Marco name. 33*600a6133SYan Wang auto MacroName = Lexer::getSourceText( 34*600a6133SYan Wang CharSourceRange::getTokenRange(Flags->getSourceRange()), SM, LangOpts); 35*600a6133SYan Wang 36*600a6133SYan Wang return MacroName == O_CLOEXEC; 37*600a6133SYan Wang } 38*600a6133SYan Wang // If it's a binary OR operation. 39*600a6133SYan Wang if (const auto *BO = dyn_cast<BinaryOperator>(Flags)) 40*600a6133SYan Wang if (BO->getOpcode() == clang::BinaryOperatorKind::BO_Or) 41*600a6133SYan Wang return hasCloseOnExecFlag(BO->getLHS()->IgnoreParenCasts(), SM, 42*600a6133SYan Wang LangOpts) || 43*600a6133SYan Wang hasCloseOnExecFlag(BO->getRHS()->IgnoreParenCasts(), SM, LangOpts); 44*600a6133SYan Wang 45*600a6133SYan Wang // Otherwise, assume it has the flag. 46*600a6133SYan Wang return true; 47*600a6133SYan Wang } 48*600a6133SYan Wang } // namespace 49*600a6133SYan Wang 50*600a6133SYan Wang void CloexecOpenCheck::registerMatchers(MatchFinder *Finder) { 51*600a6133SYan Wang auto CharPointerType = hasType(pointerType(pointee(isAnyCharacter()))); 52*600a6133SYan Wang 53*600a6133SYan Wang Finder->addMatcher( 54*600a6133SYan Wang callExpr(callee(functionDecl(isExternC(), returns(isInteger()), 55*600a6133SYan Wang hasAnyName("open", "open64"), 56*600a6133SYan Wang hasParameter(0, CharPointerType), 57*600a6133SYan Wang hasParameter(1, hasType(isInteger()))) 58*600a6133SYan Wang .bind("funcDecl"))) 59*600a6133SYan Wang .bind("openFn"), 60*600a6133SYan Wang this); 61*600a6133SYan Wang Finder->addMatcher( 62*600a6133SYan Wang callExpr(callee(functionDecl(isExternC(), returns(isInteger()), 63*600a6133SYan Wang hasName("openat"), 64*600a6133SYan Wang hasParameter(0, hasType(isInteger())), 65*600a6133SYan Wang hasParameter(1, CharPointerType), 66*600a6133SYan Wang hasParameter(2, hasType(isInteger()))) 67*600a6133SYan Wang .bind("funcDecl"))) 68*600a6133SYan Wang .bind("openatFn"), 69*600a6133SYan Wang this); 70*600a6133SYan Wang } 71*600a6133SYan Wang 72*600a6133SYan Wang void CloexecOpenCheck::check(const MatchFinder::MatchResult &Result) { 73*600a6133SYan Wang const Expr *FlagArg = nullptr; 74*600a6133SYan Wang if (const auto *OpenFnCall = Result.Nodes.getNodeAs<CallExpr>("openFn")) 75*600a6133SYan Wang FlagArg = OpenFnCall->getArg(1); 76*600a6133SYan Wang else if (const auto *OpenFnCall = 77*600a6133SYan Wang Result.Nodes.getNodeAs<CallExpr>("openatFn")) 78*600a6133SYan Wang FlagArg = OpenFnCall->getArg(2); 79*600a6133SYan Wang assert(FlagArg); 80*600a6133SYan Wang 81*600a6133SYan Wang const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("funcDecl"); 82*600a6133SYan Wang 83*600a6133SYan Wang // Check the required flag. 84*600a6133SYan Wang SourceManager &SM = *Result.SourceManager; 85*600a6133SYan Wang if (hasCloseOnExecFlag(FlagArg->IgnoreParenCasts(), SM, 86*600a6133SYan Wang Result.Context->getLangOpts())) 87*600a6133SYan Wang return; 88*600a6133SYan Wang 89*600a6133SYan Wang SourceLocation EndLoc = 90*600a6133SYan Wang Lexer::getLocForEndOfToken(SM.getFileLoc(FlagArg->getLocEnd()), 0, SM, 91*600a6133SYan Wang Result.Context->getLangOpts()); 92*600a6133SYan Wang 93*600a6133SYan Wang diag(EndLoc, "%0 should use %1 where possible") 94*600a6133SYan Wang << FD << O_CLOEXEC 95*600a6133SYan Wang << FixItHint::CreateInsertion(EndLoc, (Twine(" | ") + O_CLOEXEC).str()); 96*600a6133SYan Wang } 97*600a6133SYan Wang 98*600a6133SYan Wang } // namespace android 99*600a6133SYan Wang } // namespace tidy 100*600a6133SYan Wang } // namespace clang 101