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