NotNullTerminatedResultCheck.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011
  1. //===--- NotNullTerminatedResultCheck.cpp - clang-tidy ----------*- 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. //===----------------------------------------------------------------------===//
  8. #include "NotNullTerminatedResultCheck.h"
  9. #include "clang/AST/ASTContext.h"
  10. #include "clang/ASTMatchers/ASTMatchFinder.h"
  11. #include "clang/Frontend/CompilerInstance.h"
  12. #include "clang/Lex/Lexer.h"
  13. #include "clang/Lex/PPCallbacks.h"
  14. #include "clang/Lex/Preprocessor.h"
  15. #include <optional>
  16. using namespace clang::ast_matchers;
  17. namespace clang::tidy::bugprone {
  18. constexpr llvm::StringLiteral FunctionExprName = "FunctionExpr";
  19. constexpr llvm::StringLiteral CastExprName = "CastExpr";
  20. constexpr llvm::StringLiteral UnknownDestName = "UnknownDest";
  21. constexpr llvm::StringLiteral DestArrayTyName = "DestArrayTy";
  22. constexpr llvm::StringLiteral DestVarDeclName = "DestVarDecl";
  23. constexpr llvm::StringLiteral DestMallocExprName = "DestMalloc";
  24. constexpr llvm::StringLiteral DestExprName = "DestExpr";
  25. constexpr llvm::StringLiteral SrcVarDeclName = "SrcVarDecl";
  26. constexpr llvm::StringLiteral SrcExprName = "SrcExpr";
  27. constexpr llvm::StringLiteral LengthExprName = "LengthExpr";
  28. constexpr llvm::StringLiteral WrongLengthExprName = "WrongLength";
  29. constexpr llvm::StringLiteral UnknownLengthName = "UnknownLength";
  30. enum class LengthHandleKind { Increase, Decrease };
  31. namespace {
  32. static Preprocessor *PP;
  33. } // namespace
  34. // Returns the expression of destination's capacity which is part of a
  35. // 'VariableArrayType', 'ConstantArrayTypeLoc' or an argument of a 'malloc()'
  36. // family function call.
  37. static const Expr *getDestCapacityExpr(const MatchFinder::MatchResult &Result) {
  38. if (const auto *DestMalloc = Result.Nodes.getNodeAs<Expr>(DestMallocExprName))
  39. return DestMalloc;
  40. if (const auto *DestVAT =
  41. Result.Nodes.getNodeAs<VariableArrayType>(DestArrayTyName))
  42. return DestVAT->getSizeExpr();
  43. if (const auto *DestVD = Result.Nodes.getNodeAs<VarDecl>(DestVarDeclName))
  44. if (const TypeLoc DestTL = DestVD->getTypeSourceInfo()->getTypeLoc())
  45. if (const auto DestCTL = DestTL.getAs<ConstantArrayTypeLoc>())
  46. return DestCTL.getSizeExpr();
  47. return nullptr;
  48. }
  49. // Returns the length of \p E as an 'IntegerLiteral' or a 'StringLiteral'
  50. // without the null-terminator.
  51. static unsigned getLength(const Expr *E,
  52. const MatchFinder::MatchResult &Result) {
  53. if (!E)
  54. return 0;
  55. Expr::EvalResult Length;
  56. E = E->IgnoreImpCasts();
  57. if (const auto *LengthDRE = dyn_cast<DeclRefExpr>(E))
  58. if (const auto *LengthVD = dyn_cast<VarDecl>(LengthDRE->getDecl()))
  59. if (!isa<ParmVarDecl>(LengthVD))
  60. if (const Expr *LengthInit = LengthVD->getInit())
  61. if (LengthInit->EvaluateAsInt(Length, *Result.Context))
  62. return Length.Val.getInt().getZExtValue();
  63. if (const auto *LengthIL = dyn_cast<IntegerLiteral>(E))
  64. return LengthIL->getValue().getZExtValue();
  65. if (const auto *StrDRE = dyn_cast<DeclRefExpr>(E))
  66. if (const auto *StrVD = dyn_cast<VarDecl>(StrDRE->getDecl()))
  67. if (const Expr *StrInit = StrVD->getInit())
  68. if (const auto *StrSL =
  69. dyn_cast<StringLiteral>(StrInit->IgnoreImpCasts()))
  70. return StrSL->getLength();
  71. if (const auto *SrcSL = dyn_cast<StringLiteral>(E))
  72. return SrcSL->getLength();
  73. return 0;
  74. }
  75. // Returns the capacity of the destination array.
  76. // For example in 'char dest[13]; memcpy(dest, ...)' it returns 13.
  77. static int getDestCapacity(const MatchFinder::MatchResult &Result) {
  78. if (const auto *DestCapacityExpr = getDestCapacityExpr(Result))
  79. return getLength(DestCapacityExpr, Result);
  80. return 0;
  81. }
  82. // Returns the 'strlen()' if it is the given length.
  83. static const CallExpr *getStrlenExpr(const MatchFinder::MatchResult &Result) {
  84. if (const auto *StrlenExpr =
  85. Result.Nodes.getNodeAs<CallExpr>(WrongLengthExprName))
  86. if (const Decl *D = StrlenExpr->getCalleeDecl())
  87. if (const FunctionDecl *FD = D->getAsFunction())
  88. if (const IdentifierInfo *II = FD->getIdentifier())
  89. if (II->isStr("strlen") || II->isStr("wcslen"))
  90. return StrlenExpr;
  91. return nullptr;
  92. }
  93. // Returns the length which is given in the memory/string handler function.
  94. // For example in 'memcpy(dest, "foobar", 3)' it returns 3.
  95. static int getGivenLength(const MatchFinder::MatchResult &Result) {
  96. if (Result.Nodes.getNodeAs<Expr>(UnknownLengthName))
  97. return 0;
  98. if (int Length =
  99. getLength(Result.Nodes.getNodeAs<Expr>(WrongLengthExprName), Result))
  100. return Length;
  101. if (int Length =
  102. getLength(Result.Nodes.getNodeAs<Expr>(LengthExprName), Result))
  103. return Length;
  104. // Special case, for example 'strlen("foo")'.
  105. if (const CallExpr *StrlenCE = getStrlenExpr(Result))
  106. if (const Expr *Arg = StrlenCE->getArg(0)->IgnoreImpCasts())
  107. if (int ArgLength = getLength(Arg, Result))
  108. return ArgLength;
  109. return 0;
  110. }
  111. // Returns a string representation of \p E.
  112. static StringRef exprToStr(const Expr *E,
  113. const MatchFinder::MatchResult &Result) {
  114. if (!E)
  115. return "";
  116. return Lexer::getSourceText(
  117. CharSourceRange::getTokenRange(E->getSourceRange()),
  118. *Result.SourceManager, Result.Context->getLangOpts(), nullptr);
  119. }
  120. // Returns the proper token based end location of \p E.
  121. static SourceLocation exprLocEnd(const Expr *E,
  122. const MatchFinder::MatchResult &Result) {
  123. return Lexer::getLocForEndOfToken(E->getEndLoc(), 0, *Result.SourceManager,
  124. Result.Context->getLangOpts());
  125. }
  126. //===----------------------------------------------------------------------===//
  127. // Rewrite decision helper functions.
  128. //===----------------------------------------------------------------------===//
  129. // Increment by integer '1' can result in overflow if it is the maximal value.
  130. // After that it would be extended to 'size_t' and its value would be wrong,
  131. // therefore we have to inject '+ 1UL' instead.
  132. static bool isInjectUL(const MatchFinder::MatchResult &Result) {
  133. return getGivenLength(Result) == std::numeric_limits<int>::max();
  134. }
  135. // If the capacity of the destination array is unknown it is denoted as unknown.
  136. static bool isKnownDest(const MatchFinder::MatchResult &Result) {
  137. return !Result.Nodes.getNodeAs<Expr>(UnknownDestName);
  138. }
  139. // True if the capacity of the destination array is based on the given length,
  140. // therefore we assume that it cannot overflow (e.g. 'malloc(given_length + 1)'
  141. static bool isDestBasedOnGivenLength(const MatchFinder::MatchResult &Result) {
  142. StringRef DestCapacityExprStr =
  143. exprToStr(getDestCapacityExpr(Result), Result).trim();
  144. StringRef LengthExprStr =
  145. exprToStr(Result.Nodes.getNodeAs<Expr>(LengthExprName), Result).trim();
  146. return DestCapacityExprStr != "" && LengthExprStr != "" &&
  147. DestCapacityExprStr.contains(LengthExprStr);
  148. }
  149. // Writing and reading from the same memory cannot remove the null-terminator.
  150. static bool isDestAndSrcEquals(const MatchFinder::MatchResult &Result) {
  151. if (const auto *DestDRE = Result.Nodes.getNodeAs<DeclRefExpr>(DestExprName))
  152. if (const auto *SrcDRE = Result.Nodes.getNodeAs<DeclRefExpr>(SrcExprName))
  153. return DestDRE->getDecl()->getCanonicalDecl() ==
  154. SrcDRE->getDecl()->getCanonicalDecl();
  155. return false;
  156. }
  157. // For example 'std::string str = "foo"; memcpy(dst, str.data(), str.length())'.
  158. static bool isStringDataAndLength(const MatchFinder::MatchResult &Result) {
  159. const auto *DestExpr =
  160. Result.Nodes.getNodeAs<CXXMemberCallExpr>(DestExprName);
  161. const auto *SrcExpr = Result.Nodes.getNodeAs<CXXMemberCallExpr>(SrcExprName);
  162. const auto *LengthExpr =
  163. Result.Nodes.getNodeAs<CXXMemberCallExpr>(WrongLengthExprName);
  164. StringRef DestStr = "", SrcStr = "", LengthStr = "";
  165. if (DestExpr)
  166. if (const CXXMethodDecl *DestMD = DestExpr->getMethodDecl())
  167. DestStr = DestMD->getName();
  168. if (SrcExpr)
  169. if (const CXXMethodDecl *SrcMD = SrcExpr->getMethodDecl())
  170. SrcStr = SrcMD->getName();
  171. if (LengthExpr)
  172. if (const CXXMethodDecl *LengthMD = LengthExpr->getMethodDecl())
  173. LengthStr = LengthMD->getName();
  174. return (LengthStr == "length" || LengthStr == "size") &&
  175. (SrcStr == "data" || DestStr == "data");
  176. }
  177. static bool
  178. isGivenLengthEqualToSrcLength(const MatchFinder::MatchResult &Result) {
  179. if (Result.Nodes.getNodeAs<Expr>(UnknownLengthName))
  180. return false;
  181. if (isStringDataAndLength(Result))
  182. return true;
  183. int GivenLength = getGivenLength(Result);
  184. int SrcLength = getLength(Result.Nodes.getNodeAs<Expr>(SrcExprName), Result);
  185. if (GivenLength != 0 && SrcLength != 0 && GivenLength == SrcLength)
  186. return true;
  187. if (const auto *LengthExpr = Result.Nodes.getNodeAs<Expr>(LengthExprName))
  188. if (isa<BinaryOperator>(LengthExpr->IgnoreParenImpCasts()))
  189. return false;
  190. // Check the strlen()'s argument's 'VarDecl' is equal to the source 'VarDecl'.
  191. if (const CallExpr *StrlenCE = getStrlenExpr(Result))
  192. if (const auto *ArgDRE =
  193. dyn_cast<DeclRefExpr>(StrlenCE->getArg(0)->IgnoreImpCasts()))
  194. if (const auto *SrcVD = Result.Nodes.getNodeAs<VarDecl>(SrcVarDeclName))
  195. return dyn_cast<VarDecl>(ArgDRE->getDecl()) == SrcVD;
  196. return false;
  197. }
  198. static bool isCorrectGivenLength(const MatchFinder::MatchResult &Result) {
  199. if (Result.Nodes.getNodeAs<Expr>(UnknownLengthName))
  200. return false;
  201. return !isGivenLengthEqualToSrcLength(Result);
  202. }
  203. // If we rewrite the function call we need to create extra space to hold the
  204. // null terminator. The new necessary capacity overflows without that '+ 1'
  205. // size and we need to correct the given capacity.
  206. static bool isDestCapacityOverflows(const MatchFinder::MatchResult &Result) {
  207. if (!isKnownDest(Result))
  208. return true;
  209. const Expr *DestCapacityExpr = getDestCapacityExpr(Result);
  210. int DestCapacity = getLength(DestCapacityExpr, Result);
  211. int GivenLength = getGivenLength(Result);
  212. if (GivenLength != 0 && DestCapacity != 0)
  213. return isGivenLengthEqualToSrcLength(Result) && DestCapacity == GivenLength;
  214. // Assume that the destination array's capacity cannot overflow if the
  215. // expression of the memory allocation contains '+ 1'.
  216. StringRef DestCapacityExprStr = exprToStr(DestCapacityExpr, Result);
  217. if (DestCapacityExprStr.contains("+1") || DestCapacityExprStr.contains("+ 1"))
  218. return false;
  219. return true;
  220. }
  221. static bool
  222. isFixedGivenLengthAndUnknownSrc(const MatchFinder::MatchResult &Result) {
  223. if (Result.Nodes.getNodeAs<IntegerLiteral>(WrongLengthExprName))
  224. return !getLength(Result.Nodes.getNodeAs<Expr>(SrcExprName), Result);
  225. return false;
  226. }
  227. //===----------------------------------------------------------------------===//
  228. // Code injection functions.
  229. //===----------------------------------------------------------------------===//
  230. // Increase or decrease \p LengthExpr by one.
  231. static void lengthExprHandle(const Expr *LengthExpr,
  232. LengthHandleKind LengthHandle,
  233. const MatchFinder::MatchResult &Result,
  234. DiagnosticBuilder &Diag) {
  235. LengthExpr = LengthExpr->IgnoreParenImpCasts();
  236. // See whether we work with a macro.
  237. bool IsMacroDefinition = false;
  238. StringRef LengthExprStr = exprToStr(LengthExpr, Result);
  239. Preprocessor::macro_iterator It = PP->macro_begin();
  240. while (It != PP->macro_end() && !IsMacroDefinition) {
  241. if (It->first->getName() == LengthExprStr)
  242. IsMacroDefinition = true;
  243. ++It;
  244. }
  245. // Try to obtain an 'IntegerLiteral' and adjust it.
  246. if (!IsMacroDefinition) {
  247. if (const auto *LengthIL = dyn_cast<IntegerLiteral>(LengthExpr)) {
  248. size_t NewLength = LengthIL->getValue().getZExtValue() +
  249. (LengthHandle == LengthHandleKind::Increase
  250. ? (isInjectUL(Result) ? 1UL : 1)
  251. : -1);
  252. const auto NewLengthFix = FixItHint::CreateReplacement(
  253. LengthIL->getSourceRange(),
  254. (Twine(NewLength) + (isInjectUL(Result) ? "UL" : "")).str());
  255. Diag << NewLengthFix;
  256. return;
  257. }
  258. }
  259. // Try to obtain and remove the '+ 1' string as a decrement fix.
  260. const auto *BO = dyn_cast<BinaryOperator>(LengthExpr);
  261. if (BO && BO->getOpcode() == BO_Add &&
  262. LengthHandle == LengthHandleKind::Decrease) {
  263. const Expr *LhsExpr = BO->getLHS()->IgnoreImpCasts();
  264. const Expr *RhsExpr = BO->getRHS()->IgnoreImpCasts();
  265. if (const auto *LhsIL = dyn_cast<IntegerLiteral>(LhsExpr)) {
  266. if (LhsIL->getValue().getZExtValue() == 1) {
  267. Diag << FixItHint::CreateRemoval(
  268. {LhsIL->getBeginLoc(),
  269. RhsExpr->getBeginLoc().getLocWithOffset(-1)});
  270. return;
  271. }
  272. }
  273. if (const auto *RhsIL = dyn_cast<IntegerLiteral>(RhsExpr)) {
  274. if (RhsIL->getValue().getZExtValue() == 1) {
  275. Diag << FixItHint::CreateRemoval(
  276. {LhsExpr->getEndLoc().getLocWithOffset(1), RhsIL->getEndLoc()});
  277. return;
  278. }
  279. }
  280. }
  281. // Try to inject the '+ 1'/'- 1' string.
  282. bool NeedInnerParen = BO && BO->getOpcode() != BO_Add;
  283. if (NeedInnerParen)
  284. Diag << FixItHint::CreateInsertion(LengthExpr->getBeginLoc(), "(");
  285. SmallString<8> Injection;
  286. if (NeedInnerParen)
  287. Injection += ')';
  288. Injection += LengthHandle == LengthHandleKind::Increase ? " + 1" : " - 1";
  289. if (isInjectUL(Result))
  290. Injection += "UL";
  291. Diag << FixItHint::CreateInsertion(exprLocEnd(LengthExpr, Result), Injection);
  292. }
  293. static void lengthArgHandle(LengthHandleKind LengthHandle,
  294. const MatchFinder::MatchResult &Result,
  295. DiagnosticBuilder &Diag) {
  296. const auto *LengthExpr = Result.Nodes.getNodeAs<Expr>(LengthExprName);
  297. lengthExprHandle(LengthExpr, LengthHandle, Result, Diag);
  298. }
  299. static void lengthArgPosHandle(unsigned ArgPos, LengthHandleKind LengthHandle,
  300. const MatchFinder::MatchResult &Result,
  301. DiagnosticBuilder &Diag) {
  302. const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(FunctionExprName);
  303. lengthExprHandle(FunctionExpr->getArg(ArgPos), LengthHandle, Result, Diag);
  304. }
  305. // The string handler functions are only operates with plain 'char'/'wchar_t'
  306. // without 'unsigned/signed', therefore we need to cast it.
  307. static bool isDestExprFix(const MatchFinder::MatchResult &Result,
  308. DiagnosticBuilder &Diag) {
  309. const auto *Dest = Result.Nodes.getNodeAs<Expr>(DestExprName);
  310. if (!Dest)
  311. return false;
  312. std::string TempTyStr = Dest->getType().getAsString();
  313. StringRef TyStr = TempTyStr;
  314. if (TyStr.startswith("char") || TyStr.startswith("wchar_t"))
  315. return false;
  316. Diag << FixItHint::CreateInsertion(Dest->getBeginLoc(), "(char *)");
  317. return true;
  318. }
  319. // If the destination array is the same length as the given length we have to
  320. // increase the capacity by one to create space for the null terminator.
  321. static bool isDestCapacityFix(const MatchFinder::MatchResult &Result,
  322. DiagnosticBuilder &Diag) {
  323. bool IsOverflows = isDestCapacityOverflows(Result);
  324. if (IsOverflows)
  325. if (const Expr *CapacityExpr = getDestCapacityExpr(Result))
  326. lengthExprHandle(CapacityExpr, LengthHandleKind::Increase, Result, Diag);
  327. return IsOverflows;
  328. }
  329. static void removeArg(int ArgPos, const MatchFinder::MatchResult &Result,
  330. DiagnosticBuilder &Diag) {
  331. // This is the following structure: (src, '\0', strlen(src))
  332. // ArgToRemove: ~~~~~~~~~~~
  333. // LHSArg: ~~~~
  334. // RemoveArgFix: ~~~~~~~~~~~~~
  335. const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(FunctionExprName);
  336. const Expr *ArgToRemove = FunctionExpr->getArg(ArgPos);
  337. const Expr *LHSArg = FunctionExpr->getArg(ArgPos - 1);
  338. const auto RemoveArgFix = FixItHint::CreateRemoval(
  339. SourceRange(exprLocEnd(LHSArg, Result),
  340. exprLocEnd(ArgToRemove, Result).getLocWithOffset(-1)));
  341. Diag << RemoveArgFix;
  342. }
  343. static void renameFunc(StringRef NewFuncName,
  344. const MatchFinder::MatchResult &Result,
  345. DiagnosticBuilder &Diag) {
  346. const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(FunctionExprName);
  347. int FuncNameLength =
  348. FunctionExpr->getDirectCallee()->getIdentifier()->getLength();
  349. SourceRange FuncNameRange(
  350. FunctionExpr->getBeginLoc(),
  351. FunctionExpr->getBeginLoc().getLocWithOffset(FuncNameLength - 1));
  352. const auto FuncNameFix =
  353. FixItHint::CreateReplacement(FuncNameRange, NewFuncName);
  354. Diag << FuncNameFix;
  355. }
  356. static void renameMemcpy(StringRef Name, bool IsCopy, bool IsSafe,
  357. const MatchFinder::MatchResult &Result,
  358. DiagnosticBuilder &Diag) {
  359. SmallString<10> NewFuncName;
  360. NewFuncName = (Name[0] != 'w') ? "str" : "wcs";
  361. NewFuncName += IsCopy ? "cpy" : "ncpy";
  362. NewFuncName += IsSafe ? "_s" : "";
  363. renameFunc(NewFuncName, Result, Diag);
  364. }
  365. static void insertDestCapacityArg(bool IsOverflows, StringRef Name,
  366. const MatchFinder::MatchResult &Result,
  367. DiagnosticBuilder &Diag) {
  368. const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(FunctionExprName);
  369. SmallString<64> NewSecondArg;
  370. if (int DestLength = getDestCapacity(Result)) {
  371. NewSecondArg = Twine(IsOverflows ? DestLength + 1 : DestLength).str();
  372. } else {
  373. NewSecondArg =
  374. (Twine(exprToStr(getDestCapacityExpr(Result), Result)) +
  375. (IsOverflows ? (!isInjectUL(Result) ? " + 1" : " + 1UL") : ""))
  376. .str();
  377. }
  378. NewSecondArg += ", ";
  379. const auto InsertNewArgFix = FixItHint::CreateInsertion(
  380. FunctionExpr->getArg(1)->getBeginLoc(), NewSecondArg);
  381. Diag << InsertNewArgFix;
  382. }
  383. static void insertNullTerminatorExpr(StringRef Name,
  384. const MatchFinder::MatchResult &Result,
  385. DiagnosticBuilder &Diag) {
  386. const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(FunctionExprName);
  387. int FuncLocStartColumn = Result.SourceManager->getPresumedColumnNumber(
  388. FunctionExpr->getBeginLoc());
  389. SourceRange SpaceRange(
  390. FunctionExpr->getBeginLoc().getLocWithOffset(-FuncLocStartColumn + 1),
  391. FunctionExpr->getBeginLoc());
  392. StringRef SpaceBeforeStmtStr = Lexer::getSourceText(
  393. CharSourceRange::getCharRange(SpaceRange), *Result.SourceManager,
  394. Result.Context->getLangOpts(), nullptr);
  395. SmallString<128> NewAddNullTermExprStr;
  396. NewAddNullTermExprStr =
  397. (Twine('\n') + SpaceBeforeStmtStr +
  398. exprToStr(Result.Nodes.getNodeAs<Expr>(DestExprName), Result) + "[" +
  399. exprToStr(Result.Nodes.getNodeAs<Expr>(LengthExprName), Result) +
  400. "] = " + ((Name[0] != 'w') ? "\'\\0\';" : "L\'\\0\';"))
  401. .str();
  402. const auto AddNullTerminatorExprFix = FixItHint::CreateInsertion(
  403. exprLocEnd(FunctionExpr, Result).getLocWithOffset(1),
  404. NewAddNullTermExprStr);
  405. Diag << AddNullTerminatorExprFix;
  406. }
  407. //===----------------------------------------------------------------------===//
  408. // Checker logic with the matchers.
  409. //===----------------------------------------------------------------------===//
  410. NotNullTerminatedResultCheck::NotNullTerminatedResultCheck(
  411. StringRef Name, ClangTidyContext *Context)
  412. : ClangTidyCheck(Name, Context),
  413. WantToUseSafeFunctions(Options.get("WantToUseSafeFunctions", true)) {}
  414. void NotNullTerminatedResultCheck::storeOptions(
  415. ClangTidyOptions::OptionMap &Opts) {
  416. Options.store(Opts, "WantToUseSafeFunctions", WantToUseSafeFunctions);
  417. }
  418. void NotNullTerminatedResultCheck::registerPPCallbacks(
  419. const SourceManager &SM, Preprocessor *Pp, Preprocessor *ModuleExpanderPP) {
  420. PP = Pp;
  421. }
  422. namespace {
  423. AST_MATCHER_P(Expr, hasDefinition, ast_matchers::internal::Matcher<Expr>,
  424. InnerMatcher) {
  425. const Expr *SimpleNode = &Node;
  426. SimpleNode = SimpleNode->IgnoreParenImpCasts();
  427. if (InnerMatcher.matches(*SimpleNode, Finder, Builder))
  428. return true;
  429. auto DREHasInit = ignoringImpCasts(
  430. declRefExpr(to(varDecl(hasInitializer(ignoringImpCasts(InnerMatcher))))));
  431. if (DREHasInit.matches(*SimpleNode, Finder, Builder))
  432. return true;
  433. const char *const VarDeclName = "variable-declaration";
  434. auto DREHasDefinition = ignoringImpCasts(declRefExpr(
  435. allOf(to(varDecl().bind(VarDeclName)),
  436. hasAncestor(compoundStmt(hasDescendant(binaryOperator(
  437. hasLHS(declRefExpr(to(varDecl(equalsBoundNode(VarDeclName))))),
  438. hasRHS(ignoringImpCasts(InnerMatcher)))))))));
  439. if (DREHasDefinition.matches(*SimpleNode, Finder, Builder))
  440. return true;
  441. return false;
  442. }
  443. } // namespace
  444. void NotNullTerminatedResultCheck::registerMatchers(MatchFinder *Finder) {
  445. auto IncOp =
  446. binaryOperator(hasOperatorName("+"),
  447. hasEitherOperand(ignoringParenImpCasts(integerLiteral())));
  448. auto DecOp =
  449. binaryOperator(hasOperatorName("-"),
  450. hasEitherOperand(ignoringParenImpCasts(integerLiteral())));
  451. auto HasIncOp = anyOf(ignoringImpCasts(IncOp), hasDescendant(IncOp));
  452. auto HasDecOp = anyOf(ignoringImpCasts(DecOp), hasDescendant(DecOp));
  453. auto Container = ignoringImpCasts(cxxMemberCallExpr(hasDescendant(declRefExpr(
  454. hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(recordDecl(
  455. hasAnyName("::std::vector", "::std::list", "::std::deque"))))))))));
  456. auto StringTy = type(hasUnqualifiedDesugaredType(recordType(
  457. hasDeclaration(cxxRecordDecl(hasName("::std::basic_string"))))));
  458. auto AnyOfStringTy =
  459. anyOf(hasType(StringTy), hasType(qualType(pointsTo(StringTy))));
  460. auto CharTyArray = hasType(qualType(hasCanonicalType(
  461. arrayType(hasElementType(isAnyCharacter())).bind(DestArrayTyName))));
  462. auto CharTyPointer = hasType(
  463. qualType(hasCanonicalType(pointerType(pointee(isAnyCharacter())))));
  464. auto AnyOfCharTy = anyOf(CharTyArray, CharTyPointer);
  465. //===--------------------------------------------------------------------===//
  466. // The following six cases match problematic length expressions.
  467. //===--------------------------------------------------------------------===//
  468. // - Example: char src[] = "foo"; strlen(src);
  469. auto Strlen =
  470. callExpr(callee(functionDecl(hasAnyName("::strlen", "::wcslen"))))
  471. .bind(WrongLengthExprName);
  472. // - Example: std::string str = "foo"; str.size();
  473. auto SizeOrLength =
  474. cxxMemberCallExpr(
  475. allOf(on(expr(AnyOfStringTy).bind("Foo")),
  476. has(memberExpr(member(hasAnyName("size", "length"))))))
  477. .bind(WrongLengthExprName);
  478. // - Example: char src[] = "foo"; sizeof(src);
  479. auto SizeOfCharExpr = unaryExprOrTypeTraitExpr(has(expr(AnyOfCharTy)));
  480. auto WrongLength =
  481. ignoringImpCasts(anyOf(Strlen, SizeOrLength, hasDescendant(Strlen),
  482. hasDescendant(SizeOrLength)));
  483. // - Example: length = strlen(src);
  484. auto DREWithoutInc =
  485. ignoringImpCasts(declRefExpr(to(varDecl(hasInitializer(WrongLength)))));
  486. auto AnyOfCallOrDREWithoutInc = anyOf(DREWithoutInc, WrongLength);
  487. // - Example: int getLength(const char *str) { return strlen(str); }
  488. auto CallExprReturnWithoutInc = ignoringImpCasts(callExpr(callee(functionDecl(
  489. hasBody(has(returnStmt(hasReturnValue(AnyOfCallOrDREWithoutInc))))))));
  490. // - Example: int length = getLength(src);
  491. auto DREHasReturnWithoutInc = ignoringImpCasts(
  492. declRefExpr(to(varDecl(hasInitializer(CallExprReturnWithoutInc)))));
  493. auto AnyOfWrongLengthInit =
  494. anyOf(WrongLength, AnyOfCallOrDREWithoutInc, CallExprReturnWithoutInc,
  495. DREHasReturnWithoutInc);
  496. //===--------------------------------------------------------------------===//
  497. // The following five cases match the 'destination' array length's
  498. // expression which is used in 'memcpy()' and 'memmove()' matchers.
  499. //===--------------------------------------------------------------------===//
  500. // Note: Sometimes the size of char is explicitly written out.
  501. auto SizeExpr = anyOf(SizeOfCharExpr, integerLiteral(equals(1)));
  502. auto MallocLengthExpr = allOf(
  503. callee(functionDecl(
  504. hasAnyName("::alloca", "::calloc", "malloc", "realloc"))),
  505. hasAnyArgument(allOf(unless(SizeExpr), expr().bind(DestMallocExprName))));
  506. // - Example: (char *)malloc(length);
  507. auto DestMalloc = anyOf(callExpr(MallocLengthExpr),
  508. hasDescendant(callExpr(MallocLengthExpr)));
  509. // - Example: new char[length];
  510. auto DestCXXNewExpr = ignoringImpCasts(
  511. cxxNewExpr(hasArraySize(expr().bind(DestMallocExprName))));
  512. auto AnyOfDestInit = anyOf(DestMalloc, DestCXXNewExpr);
  513. // - Example: char dest[13]; or char dest[length];
  514. auto DestArrayTyDecl = declRefExpr(
  515. to(anyOf(varDecl(CharTyArray).bind(DestVarDeclName),
  516. varDecl(hasInitializer(AnyOfDestInit)).bind(DestVarDeclName))));
  517. // - Example: foo[bar[baz]].qux; (or just ParmVarDecl)
  518. auto DestUnknownDecl =
  519. declRefExpr(allOf(to(varDecl(AnyOfCharTy).bind(DestVarDeclName)),
  520. expr().bind(UnknownDestName)))
  521. .bind(DestExprName);
  522. auto AnyOfDestDecl = ignoringImpCasts(
  523. anyOf(allOf(hasDefinition(anyOf(AnyOfDestInit, DestArrayTyDecl,
  524. hasDescendant(DestArrayTyDecl))),
  525. expr().bind(DestExprName)),
  526. anyOf(DestUnknownDecl, hasDescendant(DestUnknownDecl))));
  527. auto NullTerminatorExpr = binaryOperator(
  528. hasLHS(anyOf(hasDescendant(declRefExpr(to(varDecl(
  529. equalsBoundNode(std::string(DestVarDeclName)))))),
  530. hasDescendant(declRefExpr(
  531. equalsBoundNode(std::string(DestExprName)))))),
  532. hasRHS(ignoringImpCasts(
  533. anyOf(characterLiteral(equals(0U)), integerLiteral(equals(0))))));
  534. auto SrcDecl = declRefExpr(
  535. allOf(to(decl().bind(SrcVarDeclName)),
  536. anyOf(hasAncestor(cxxMemberCallExpr().bind(SrcExprName)),
  537. expr().bind(SrcExprName))));
  538. auto AnyOfSrcDecl =
  539. ignoringImpCasts(anyOf(stringLiteral().bind(SrcExprName),
  540. hasDescendant(stringLiteral().bind(SrcExprName)),
  541. SrcDecl, hasDescendant(SrcDecl)));
  542. //===--------------------------------------------------------------------===//
  543. // Match the problematic function calls.
  544. //===--------------------------------------------------------------------===//
  545. struct CallContext {
  546. CallContext(StringRef Name, std::optional<unsigned> DestinationPos,
  547. std::optional<unsigned> SourcePos, unsigned LengthPos,
  548. bool WithIncrease)
  549. : Name(Name), DestinationPos(DestinationPos), SourcePos(SourcePos),
  550. LengthPos(LengthPos), WithIncrease(WithIncrease){};
  551. StringRef Name;
  552. std::optional<unsigned> DestinationPos;
  553. std::optional<unsigned> SourcePos;
  554. unsigned LengthPos;
  555. bool WithIncrease;
  556. };
  557. auto MatchDestination = [=](CallContext CC) {
  558. return hasArgument(*CC.DestinationPos,
  559. allOf(AnyOfDestDecl,
  560. unless(hasAncestor(compoundStmt(
  561. hasDescendant(NullTerminatorExpr)))),
  562. unless(Container)));
  563. };
  564. auto MatchSource = [=](CallContext CC) {
  565. return hasArgument(*CC.SourcePos, AnyOfSrcDecl);
  566. };
  567. auto MatchGivenLength = [=](CallContext CC) {
  568. return hasArgument(
  569. CC.LengthPos,
  570. allOf(
  571. anyOf(
  572. ignoringImpCasts(integerLiteral().bind(WrongLengthExprName)),
  573. allOf(unless(hasDefinition(SizeOfCharExpr)),
  574. allOf(CC.WithIncrease
  575. ? ignoringImpCasts(hasDefinition(HasIncOp))
  576. : ignoringImpCasts(allOf(
  577. unless(hasDefinition(HasIncOp)),
  578. anyOf(hasDefinition(binaryOperator().bind(
  579. UnknownLengthName)),
  580. hasDefinition(anything())))),
  581. AnyOfWrongLengthInit))),
  582. expr().bind(LengthExprName)));
  583. };
  584. auto MatchCall = [=](CallContext CC) {
  585. std::string CharHandlerFuncName = "::" + CC.Name.str();
  586. // Try to match with 'wchar_t' based function calls.
  587. std::string WcharHandlerFuncName =
  588. "::" + (CC.Name.startswith("mem") ? "w" + CC.Name.str()
  589. : "wcs" + CC.Name.substr(3).str());
  590. return allOf(callee(functionDecl(
  591. hasAnyName(CharHandlerFuncName, WcharHandlerFuncName))),
  592. MatchGivenLength(CC));
  593. };
  594. auto Match = [=](CallContext CC) {
  595. if (CC.DestinationPos && CC.SourcePos)
  596. return allOf(MatchCall(CC), MatchDestination(CC), MatchSource(CC));
  597. if (CC.DestinationPos && !CC.SourcePos)
  598. return allOf(MatchCall(CC), MatchDestination(CC),
  599. hasArgument(*CC.DestinationPos, anything()));
  600. if (!CC.DestinationPos && CC.SourcePos)
  601. return allOf(MatchCall(CC), MatchSource(CC),
  602. hasArgument(*CC.SourcePos, anything()));
  603. llvm_unreachable("Unhandled match");
  604. };
  605. // void *memcpy(void *dest, const void *src, size_t count)
  606. auto Memcpy = Match({"memcpy", 0, 1, 2, false});
  607. // errno_t memcpy_s(void *dest, size_t ds, const void *src, size_t count)
  608. auto MemcpyS = Match({"memcpy_s", 0, 2, 3, false});
  609. // void *memchr(const void *src, int c, size_t count)
  610. auto Memchr = Match({"memchr", std::nullopt, 0, 2, false});
  611. // void *memmove(void *dest, const void *src, size_t count)
  612. auto Memmove = Match({"memmove", 0, 1, 2, false});
  613. // errno_t memmove_s(void *dest, size_t ds, const void *src, size_t count)
  614. auto MemmoveS = Match({"memmove_s", 0, 2, 3, false});
  615. // int strncmp(const char *str1, const char *str2, size_t count);
  616. auto StrncmpRHS = Match({"strncmp", std::nullopt, 1, 2, true});
  617. auto StrncmpLHS = Match({"strncmp", std::nullopt, 0, 2, true});
  618. // size_t strxfrm(char *dest, const char *src, size_t count);
  619. auto Strxfrm = Match({"strxfrm", 0, 1, 2, false});
  620. // errno_t strerror_s(char *buffer, size_t bufferSize, int errnum);
  621. auto StrerrorS = Match({"strerror_s", 0, std::nullopt, 1, false});
  622. auto AnyOfMatchers = anyOf(Memcpy, MemcpyS, Memmove, MemmoveS, StrncmpRHS,
  623. StrncmpLHS, Strxfrm, StrerrorS);
  624. Finder->addMatcher(callExpr(AnyOfMatchers).bind(FunctionExprName), this);
  625. // Need to remove the CastExpr from 'memchr()' as 'strchr()' returns 'char *'.
  626. Finder->addMatcher(
  627. callExpr(Memchr,
  628. unless(hasAncestor(castExpr(unless(implicitCastExpr())))))
  629. .bind(FunctionExprName),
  630. this);
  631. Finder->addMatcher(
  632. castExpr(allOf(unless(implicitCastExpr()),
  633. has(callExpr(Memchr).bind(FunctionExprName))))
  634. .bind(CastExprName),
  635. this);
  636. }
  637. void NotNullTerminatedResultCheck::check(
  638. const MatchFinder::MatchResult &Result) {
  639. const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(FunctionExprName);
  640. if (FunctionExpr->getBeginLoc().isMacroID())
  641. return;
  642. if (WantToUseSafeFunctions && PP->isMacroDefined("__STDC_LIB_EXT1__")) {
  643. std::optional<bool> AreSafeFunctionsWanted;
  644. Preprocessor::macro_iterator It = PP->macro_begin();
  645. while (It != PP->macro_end() && !AreSafeFunctionsWanted) {
  646. if (It->first->getName() == "__STDC_WANT_LIB_EXT1__") {
  647. const auto *MI = PP->getMacroInfo(It->first);
  648. // PP->getMacroInfo() returns nullptr if macro has no definition.
  649. if (MI) {
  650. const auto &T = MI->tokens().back();
  651. if (T.isLiteral() && T.getLiteralData()) {
  652. StringRef ValueStr = StringRef(T.getLiteralData(), T.getLength());
  653. llvm::APInt IntValue;
  654. ValueStr.getAsInteger(10, IntValue);
  655. AreSafeFunctionsWanted = IntValue.getZExtValue();
  656. }
  657. }
  658. }
  659. ++It;
  660. }
  661. if (AreSafeFunctionsWanted)
  662. UseSafeFunctions = *AreSafeFunctionsWanted;
  663. }
  664. StringRef Name = FunctionExpr->getDirectCallee()->getName();
  665. if (Name.startswith("mem") || Name.startswith("wmem"))
  666. memoryHandlerFunctionFix(Name, Result);
  667. else if (Name == "strerror_s")
  668. strerror_sFix(Result);
  669. else if (Name.endswith("ncmp"))
  670. ncmpFix(Name, Result);
  671. else if (Name.endswith("xfrm"))
  672. xfrmFix(Name, Result);
  673. }
  674. void NotNullTerminatedResultCheck::memoryHandlerFunctionFix(
  675. StringRef Name, const MatchFinder::MatchResult &Result) {
  676. if (isCorrectGivenLength(Result))
  677. return;
  678. if (Name.endswith("chr")) {
  679. memchrFix(Name, Result);
  680. return;
  681. }
  682. if ((Name.contains("cpy") || Name.contains("move")) &&
  683. (isDestAndSrcEquals(Result) || isFixedGivenLengthAndUnknownSrc(Result)))
  684. return;
  685. auto Diag =
  686. diag(Result.Nodes.getNodeAs<CallExpr>(FunctionExprName)->getBeginLoc(),
  687. "the result from calling '%0' is not null-terminated")
  688. << Name;
  689. if (Name.endswith("cpy")) {
  690. memcpyFix(Name, Result, Diag);
  691. } else if (Name.endswith("cpy_s")) {
  692. memcpy_sFix(Name, Result, Diag);
  693. } else if (Name.endswith("move")) {
  694. memmoveFix(Name, Result, Diag);
  695. } else if (Name.endswith("move_s")) {
  696. isDestCapacityFix(Result, Diag);
  697. lengthArgHandle(LengthHandleKind::Increase, Result, Diag);
  698. }
  699. }
  700. void NotNullTerminatedResultCheck::memcpyFix(
  701. StringRef Name, const MatchFinder::MatchResult &Result,
  702. DiagnosticBuilder &Diag) {
  703. bool IsOverflows = isDestCapacityFix(Result, Diag);
  704. bool IsDestFixed = isDestExprFix(Result, Diag);
  705. bool IsCopy =
  706. isGivenLengthEqualToSrcLength(Result) || isDestBasedOnGivenLength(Result);
  707. bool IsSafe = UseSafeFunctions && IsOverflows && isKnownDest(Result) &&
  708. !isDestBasedOnGivenLength(Result);
  709. bool IsDestLengthNotRequired =
  710. IsSafe && getLangOpts().CPlusPlus &&
  711. Result.Nodes.getNodeAs<ArrayType>(DestArrayTyName) && !IsDestFixed;
  712. renameMemcpy(Name, IsCopy, IsSafe, Result, Diag);
  713. if (IsSafe && !IsDestLengthNotRequired)
  714. insertDestCapacityArg(IsOverflows, Name, Result, Diag);
  715. if (IsCopy)
  716. removeArg(2, Result, Diag);
  717. if (!IsCopy && !IsSafe)
  718. insertNullTerminatorExpr(Name, Result, Diag);
  719. }
  720. void NotNullTerminatedResultCheck::memcpy_sFix(
  721. StringRef Name, const MatchFinder::MatchResult &Result,
  722. DiagnosticBuilder &Diag) {
  723. bool IsOverflows = isDestCapacityFix(Result, Diag);
  724. bool IsDestFixed = isDestExprFix(Result, Diag);
  725. bool RemoveDestLength = getLangOpts().CPlusPlus &&
  726. Result.Nodes.getNodeAs<ArrayType>(DestArrayTyName) &&
  727. !IsDestFixed;
  728. bool IsCopy = isGivenLengthEqualToSrcLength(Result);
  729. bool IsSafe = IsOverflows;
  730. renameMemcpy(Name, IsCopy, IsSafe, Result, Diag);
  731. if (!IsSafe || (IsSafe && RemoveDestLength))
  732. removeArg(1, Result, Diag);
  733. else if (IsOverflows && isKnownDest(Result))
  734. lengthArgPosHandle(1, LengthHandleKind::Increase, Result, Diag);
  735. if (IsCopy)
  736. removeArg(3, Result, Diag);
  737. if (!IsCopy && !IsSafe)
  738. insertNullTerminatorExpr(Name, Result, Diag);
  739. }
  740. void NotNullTerminatedResultCheck::memchrFix(
  741. StringRef Name, const MatchFinder::MatchResult &Result) {
  742. const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(FunctionExprName);
  743. if (const auto *GivenCL = dyn_cast<CharacterLiteral>(FunctionExpr->getArg(1)))
  744. if (GivenCL->getValue() != 0)
  745. return;
  746. auto Diag = diag(FunctionExpr->getArg(2)->IgnoreParenCasts()->getBeginLoc(),
  747. "the length is too short to include the null terminator");
  748. if (const auto *CastExpr = Result.Nodes.getNodeAs<Expr>(CastExprName)) {
  749. const auto CastRemoveFix = FixItHint::CreateRemoval(
  750. SourceRange(CastExpr->getBeginLoc(),
  751. FunctionExpr->getBeginLoc().getLocWithOffset(-1)));
  752. Diag << CastRemoveFix;
  753. }
  754. StringRef NewFuncName = (Name[0] != 'w') ? "strchr" : "wcschr";
  755. renameFunc(NewFuncName, Result, Diag);
  756. removeArg(2, Result, Diag);
  757. }
  758. void NotNullTerminatedResultCheck::memmoveFix(
  759. StringRef Name, const MatchFinder::MatchResult &Result,
  760. DiagnosticBuilder &Diag) {
  761. bool IsOverflows = isDestCapacityFix(Result, Diag);
  762. if (UseSafeFunctions && isKnownDest(Result)) {
  763. renameFunc((Name[0] != 'w') ? "memmove_s" : "wmemmove_s", Result, Diag);
  764. insertDestCapacityArg(IsOverflows, Name, Result, Diag);
  765. }
  766. lengthArgHandle(LengthHandleKind::Increase, Result, Diag);
  767. }
  768. void NotNullTerminatedResultCheck::strerror_sFix(
  769. const MatchFinder::MatchResult &Result) {
  770. auto Diag =
  771. diag(Result.Nodes.getNodeAs<CallExpr>(FunctionExprName)->getBeginLoc(),
  772. "the result from calling 'strerror_s' is not null-terminated and "
  773. "missing the last character of the error message");
  774. isDestCapacityFix(Result, Diag);
  775. lengthArgHandle(LengthHandleKind::Increase, Result, Diag);
  776. }
  777. void NotNullTerminatedResultCheck::ncmpFix(
  778. StringRef Name, const MatchFinder::MatchResult &Result) {
  779. const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(FunctionExprName);
  780. const Expr *FirstArgExpr = FunctionExpr->getArg(0)->IgnoreImpCasts();
  781. const Expr *SecondArgExpr = FunctionExpr->getArg(1)->IgnoreImpCasts();
  782. bool IsLengthTooLong = false;
  783. if (const CallExpr *StrlenExpr = getStrlenExpr(Result)) {
  784. const Expr *LengthExprArg = StrlenExpr->getArg(0);
  785. StringRef FirstExprStr = exprToStr(FirstArgExpr, Result).trim();
  786. StringRef SecondExprStr = exprToStr(SecondArgExpr, Result).trim();
  787. StringRef LengthArgStr = exprToStr(LengthExprArg, Result).trim();
  788. IsLengthTooLong =
  789. LengthArgStr == FirstExprStr || LengthArgStr == SecondExprStr;
  790. } else {
  791. int SrcLength =
  792. getLength(Result.Nodes.getNodeAs<Expr>(SrcExprName), Result);
  793. int GivenLength = getGivenLength(Result);
  794. if (SrcLength != 0 && GivenLength != 0)
  795. IsLengthTooLong = GivenLength > SrcLength;
  796. }
  797. if (!IsLengthTooLong && !isStringDataAndLength(Result))
  798. return;
  799. auto Diag = diag(FunctionExpr->getArg(2)->IgnoreParenCasts()->getBeginLoc(),
  800. "comparison length is too long and might lead to a "
  801. "buffer overflow");
  802. lengthArgHandle(LengthHandleKind::Decrease, Result, Diag);
  803. }
  804. void NotNullTerminatedResultCheck::xfrmFix(
  805. StringRef Name, const MatchFinder::MatchResult &Result) {
  806. if (!isDestCapacityOverflows(Result))
  807. return;
  808. auto Diag =
  809. diag(Result.Nodes.getNodeAs<CallExpr>(FunctionExprName)->getBeginLoc(),
  810. "the result from calling '%0' is not null-terminated")
  811. << Name;
  812. isDestCapacityFix(Result, Diag);
  813. lengthArgHandle(LengthHandleKind::Increase, Result, Diag);
  814. }
  815. } // namespace clang::tidy::bugprone