1 //===--- MisplacedPointerArithmeticInAllocCheck.cpp - clang-tidy-----------===// 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 //===----------------------------------------------------------------------===// 8 9 #include "MisplacedPointerArithmeticInAllocCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 #include "clang/Lex/Lexer.h" 13 14 using namespace clang::ast_matchers; 15 16 namespace clang { 17 namespace tidy { 18 namespace bugprone { 19 20 void MisplacedPointerArithmeticInAllocCheck::registerMatchers( 21 MatchFinder *Finder) { 22 const auto AllocFunc = 23 functionDecl(hasAnyName("::malloc", "std::malloc", "::alloca", "::calloc", 24 "std::calloc", "::realloc", "std::realloc")); 25 26 const auto AllocFuncPtr = 27 varDecl(hasType(isConstQualified()), 28 hasInitializer(ignoringParenImpCasts( 29 declRefExpr(hasDeclaration(AllocFunc))))); 30 31 const auto AdditiveOperator = binaryOperator(hasAnyOperatorName("+", "-")); 32 33 const auto IntExpr = expr(hasType(isInteger())); 34 35 const auto AllocCall = callExpr(callee(decl(anyOf(AllocFunc, AllocFuncPtr)))); 36 37 Finder->addMatcher( 38 binaryOperator( 39 AdditiveOperator, 40 hasLHS(anyOf(AllocCall, castExpr(hasSourceExpression(AllocCall)))), 41 hasRHS(IntExpr)) 42 .bind("PtrArith"), 43 this); 44 45 const auto New = cxxNewExpr(unless(isArray())); 46 47 Finder->addMatcher(binaryOperator(AdditiveOperator, 48 hasLHS(anyOf(New, castExpr(New))), 49 hasRHS(IntExpr)) 50 .bind("PtrArith"), 51 this); 52 53 const auto ArrayNew = cxxNewExpr(isArray()); 54 55 Finder->addMatcher(binaryOperator(AdditiveOperator, 56 hasLHS(anyOf(ArrayNew, castExpr(ArrayNew))), 57 hasRHS(IntExpr)) 58 .bind("PtrArith"), 59 this); 60 } 61 62 void MisplacedPointerArithmeticInAllocCheck::check( 63 const MatchFinder::MatchResult &Result) { 64 const auto *PtrArith = Result.Nodes.getNodeAs<BinaryOperator>("PtrArith"); 65 const Expr *AllocExpr = PtrArith->getLHS()->IgnoreParenCasts(); 66 std::string CallName; 67 68 if (const auto *Call = dyn_cast<CallExpr>(AllocExpr)) { 69 const NamedDecl *Func = Call->getDirectCallee(); 70 if (!Func) { 71 Func = cast<NamedDecl>(Call->getCalleeDecl()); 72 } 73 CallName = Func->getName().str(); 74 } else { 75 const auto *New = cast<CXXNewExpr>(AllocExpr); 76 if (New->isArray()) { 77 CallName = "operator new[]"; 78 } else { 79 const auto *CtrE = New->getConstructExpr(); 80 if (!CtrE || !CtrE->getArg(CtrE->getNumArgs() - 1) 81 ->getType() 82 ->isIntegralOrEnumerationType()) 83 return; 84 CallName = "operator new"; 85 } 86 } 87 88 const SourceRange OldRParen = SourceRange(PtrArith->getLHS()->getEndLoc()); 89 const StringRef RParen = 90 Lexer::getSourceText(CharSourceRange::getTokenRange(OldRParen), 91 *Result.SourceManager, getLangOpts()); 92 const SourceLocation NewRParen = Lexer::getLocForEndOfToken( 93 PtrArith->getEndLoc(), 0, *Result.SourceManager, getLangOpts()); 94 95 diag(PtrArith->getBeginLoc(), 96 "arithmetic operation is applied to the result of %0() instead of its " 97 "size-like argument") 98 << CallName << FixItHint::CreateRemoval(OldRParen) 99 << FixItHint::CreateInsertion(NewRParen, RParen); 100 } 101 102 } // namespace bugprone 103 } // namespace tidy 104 } // namespace clang 105