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 #include "clang/Lex/Preprocessor.h"
39 static Preprocessor *
PP;
49 if (
const auto *DestVAT =
51 return DestVAT->getSizeExpr();
53 if (
const auto *DestVD = Result.Nodes.getNodeAs<VarDecl>(
DestVarDeclName))
54 if (
const TypeLoc DestTL = DestVD->getTypeSourceInfo()->getTypeLoc())
55 if (
const auto DestCTL = DestTL.getAs<ConstantArrayTypeLoc>())
56 return DestCTL.getSizeExpr();
64 const MatchFinder::MatchResult &Result) {
69 E =
E->IgnoreImpCasts();
71 if (
const auto *LengthDRE = dyn_cast<DeclRefExpr>(
E))
72 if (
const auto *LengthVD = dyn_cast<VarDecl>(LengthDRE->getDecl()))
73 if (!isa<ParmVarDecl>(LengthVD))
74 if (
const Expr *LengthInit = LengthVD->getInit())
75 if (LengthInit->EvaluateAsInt(
Length, *Result.Context))
76 return Length.Val.getInt().getZExtValue();
78 if (
const auto *LengthIL = dyn_cast<IntegerLiteral>(
E))
79 return LengthIL->getValue().getZExtValue();
81 if (
const auto *StrDRE = dyn_cast<DeclRefExpr>(
E))
82 if (
const auto *StrVD = dyn_cast<VarDecl>(StrDRE->getDecl()))
83 if (
const Expr *StrInit = StrVD->getInit())
84 if (
const auto *StrSL =
85 dyn_cast<StringLiteral>(StrInit->IgnoreImpCasts()))
86 return StrSL->getLength();
88 if (
const auto *SrcSL = dyn_cast<StringLiteral>(
E))
89 return SrcSL->getLength();
98 return getLength(DestCapacityExpr, Result);
104 static const CallExpr *
getStrlenExpr(
const MatchFinder::MatchResult &Result) {
105 if (
const auto *StrlenExpr =
107 if (
const Decl *D = StrlenExpr->getCalleeDecl())
108 if (
const FunctionDecl *FD = D->getAsFunction())
109 if (
const IdentifierInfo *II = FD->getIdentifier())
110 if (II->isStr(
"strlen") || II->isStr(
"wcslen"))
132 if (
const Expr *Arg = StrlenCE->getArg(0)->IgnoreImpCasts())
133 if (
int ArgLength =
getLength(Arg, Result))
141 const MatchFinder::MatchResult &Result) {
145 return Lexer::getSourceText(
146 CharSourceRange::getTokenRange(
E->getSourceRange()),
147 *Result.SourceManager, Result.Context->getLangOpts(), 0);
152 const MatchFinder::MatchResult &Result) {
153 return Lexer::getLocForEndOfToken(
E->getEndLoc(), 0, *Result.SourceManager,
154 Result.Context->getLangOpts());
164 static bool isInjectUL(
const MatchFinder::MatchResult &Result) {
176 StringRef DestCapacityExprStr =
178 StringRef LengthExprStr =
181 return DestCapacityExprStr !=
"" && LengthExprStr !=
"" &&
182 DestCapacityExprStr.contains(LengthExprStr);
187 if (
const auto *DestDRE = Result.Nodes.getNodeAs<DeclRefExpr>(
DestExprName))
188 if (
const auto *SrcDRE = Result.Nodes.getNodeAs<DeclRefExpr>(
SrcExprName))
189 return DestDRE->getDecl()->getCanonicalDecl() ==
190 SrcDRE->getDecl()->getCanonicalDecl();
197 const auto *DestExpr =
198 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
DestExprName);
199 const auto *SrcExpr = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
SrcExprName);
200 const auto *LengthExpr =
203 StringRef DestStr =
"", SrcStr =
"", LengthStr =
"";
205 if (
const CXXMethodDecl *DestMD = DestExpr->getMethodDecl())
206 DestStr = DestMD->getName();
209 if (
const CXXMethodDecl *SrcMD = SrcExpr->getMethodDecl())
210 SrcStr = SrcMD->getName();
213 if (
const CXXMethodDecl *LengthMD = LengthExpr->getMethodDecl())
214 LengthStr = LengthMD->getName();
216 return (LengthStr ==
"length" || LengthStr ==
"size") &&
217 (SrcStr ==
"data" || DestStr ==
"data");
231 if (GivenLength != 0 && SrcLength != 0 && GivenLength == SrcLength)
234 if (
const auto *LengthExpr = Result.Nodes.getNodeAs<Expr>(
LengthExprName))
235 if (dyn_cast<BinaryOperator>(LengthExpr->IgnoreParenImpCasts()))
240 if (
const auto *ArgDRE =
241 dyn_cast<DeclRefExpr>(StrlenCE->getArg(0)->IgnoreImpCasts()))
242 if (
const auto *SrcVD = Result.Nodes.getNodeAs<VarDecl>(
SrcVarDeclName))
243 return dyn_cast<VarDecl>(ArgDRE->getDecl()) == SrcVD;
263 int DestCapacity =
getLength(DestCapacityExpr, Result);
266 if (GivenLength != 0 && DestCapacity != 0)
271 StringRef DestCapacityExprStr =
exprToStr(DestCapacityExpr, Result);
272 if (DestCapacityExprStr.contains(
"+1") || DestCapacityExprStr.contains(
"+ 1"))
293 const MatchFinder::MatchResult &Result,
294 DiagnosticBuilder &Diag) {
295 LengthExpr = LengthExpr->IgnoreParenImpCasts();
298 bool IsMacroDefinition =
false;
299 StringRef LengthExprStr =
exprToStr(LengthExpr, Result);
300 Preprocessor::macro_iterator It =
PP->macro_begin();
301 while (It !=
PP->macro_end() && !IsMacroDefinition) {
302 if (It->first->getName() == LengthExprStr)
303 IsMacroDefinition =
true;
309 if (!IsMacroDefinition) {
310 if (
const auto *LengthIL = dyn_cast<IntegerLiteral>(LengthExpr)) {
311 size_t NewLength = LengthIL->getValue().getZExtValue() +
312 (LengthHandle == LengthHandleKind::Increase
316 const auto NewLengthFix = FixItHint::CreateReplacement(
317 LengthIL->getSourceRange(),
318 (Twine(NewLength) + (
isInjectUL(Result) ?
"UL" :
"")).str());
319 Diag << NewLengthFix;
325 const auto *BO = dyn_cast<BinaryOperator>(LengthExpr);
326 if (BO && BO->getOpcode() == BO_Add &&
327 LengthHandle == LengthHandleKind::Decrease) {
328 const Expr *LhsExpr = BO->getLHS()->IgnoreImpCasts();
329 const Expr *RhsExpr = BO->getRHS()->IgnoreImpCasts();
331 if (
const auto *LhsIL = dyn_cast<IntegerLiteral>(LhsExpr)) {
332 if (LhsIL->getValue().getZExtValue() == 1) {
333 Diag << FixItHint::CreateRemoval(
334 {LhsIL->getBeginLoc(),
335 RhsExpr->getBeginLoc().getLocWithOffset(-1)});
340 if (
const auto *RhsIL = dyn_cast<IntegerLiteral>(RhsExpr)) {
341 if (RhsIL->getValue().getZExtValue() == 1) {
342 Diag << FixItHint::CreateRemoval(
343 {LhsExpr->getEndLoc().getLocWithOffset(1), RhsIL->getEndLoc()});
350 bool NeedInnerParen = BO && BO->getOpcode() != BO_Add;
353 Diag << FixItHint::CreateInsertion(LengthExpr->getBeginLoc(),
"(");
355 SmallString<8> Injection;
358 Injection += LengthHandle == LengthHandleKind::Increase ?
" + 1" :
" - 1";
362 Diag << FixItHint::CreateInsertion(
exprLocEnd(LengthExpr, Result), Injection);
366 const MatchFinder::MatchResult &Result,
367 DiagnosticBuilder &Diag) {
368 const auto *LengthExpr = Result.Nodes.getNodeAs<Expr>(
LengthExprName);
373 const MatchFinder::MatchResult &Result,
374 DiagnosticBuilder &Diag) {
375 const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(
FunctionExprName);
382 DiagnosticBuilder &Diag) {
383 const auto *Dest = Result.Nodes.getNodeAs<Expr>(
DestExprName);
387 std::string TempTyStr = Dest->getType().getAsString();
388 StringRef TyStr = TempTyStr;
389 if (TyStr.startswith(
"char") || TyStr.startswith(
"wchar_t"))
392 Diag << FixItHint::CreateInsertion(Dest->getBeginLoc(),
"(char *)");
399 DiagnosticBuilder &Diag) {
408 static void removeArg(
int ArgPos,
const MatchFinder::MatchResult &Result,
409 DiagnosticBuilder &Diag) {
414 const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(
FunctionExprName);
415 const Expr *ArgToRemove = FunctionExpr->getArg(ArgPos);
416 const Expr *LHSArg = FunctionExpr->getArg(ArgPos - 1);
417 const auto RemoveArgFix = FixItHint::CreateRemoval(
419 exprLocEnd(ArgToRemove, Result).getLocWithOffset(-1)));
420 Diag << RemoveArgFix;
424 const MatchFinder::MatchResult &Result,
425 DiagnosticBuilder &Diag) {
426 const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(
FunctionExprName);
428 FunctionExpr->getDirectCallee()->getIdentifier()->getLength();
429 SourceRange FuncNameRange(
430 FunctionExpr->getBeginLoc(),
431 FunctionExpr->getBeginLoc().getLocWithOffset(FuncNameLength - 1));
433 const auto FuncNameFix =
434 FixItHint::CreateReplacement(FuncNameRange, NewFuncName);
439 const MatchFinder::MatchResult &Result,
440 DiagnosticBuilder &Diag) {
441 SmallString<10> NewFuncName;
442 NewFuncName = (
Name[0] !=
'w') ?
"str" :
"wcs";
443 NewFuncName += IsCopy ?
"cpy" :
"ncpy";
444 NewFuncName += IsSafe ?
"_s" :
"";
449 const MatchFinder::MatchResult &Result,
450 DiagnosticBuilder &Diag) {
451 const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(
FunctionExprName);
452 SmallString<64> NewSecondArg;
455 NewSecondArg = Twine(IsOverflows ? DestLength + 1 : DestLength).str();
459 (IsOverflows ? (!
isInjectUL(Result) ?
" + 1" :
" + 1UL") :
""))
463 NewSecondArg +=
", ";
464 const auto InsertNewArgFix = FixItHint::CreateInsertion(
465 FunctionExpr->getArg(1)->getBeginLoc(), NewSecondArg);
466 Diag << InsertNewArgFix;
470 const MatchFinder::MatchResult &Result,
471 DiagnosticBuilder &Diag) {
472 const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(
FunctionExprName);
473 int FuncLocStartColumn = Result.SourceManager->getPresumedColumnNumber(
474 FunctionExpr->getBeginLoc());
475 SourceRange SpaceRange(
476 FunctionExpr->getBeginLoc().getLocWithOffset(-FuncLocStartColumn + 1),
477 FunctionExpr->getBeginLoc());
478 StringRef SpaceBeforeStmtStr = Lexer::getSourceText(
479 CharSourceRange::getCharRange(SpaceRange), *Result.SourceManager,
480 Result.Context->getLangOpts(), 0);
482 SmallString<128> NewAddNullTermExprStr;
483 NewAddNullTermExprStr =
484 (Twine(
'\n') + SpaceBeforeStmtStr +
487 "] = " + ((
Name[0] !=
'w') ?
"\'\\0\';" :
"L\'\\0\';"))
490 const auto AddNullTerminatorExprFix = FixItHint::CreateInsertion(
491 exprLocEnd(FunctionExpr, Result).getLocWithOffset(1),
492 NewAddNullTermExprStr);
493 Diag << AddNullTerminatorExprFix;
500 NotNullTerminatedResultCheck::NotNullTerminatedResultCheck(
503 WantToUseSafeFunctions(Options.get(
"WantToUseSafeFunctions", true)) {}
507 Options.
store(Opts,
"WantToUseSafeFunctions", WantToUseSafeFunctions);
511 const SourceManager &SM, Preprocessor *pp, Preprocessor *ModuleExpanderPP) {
516 AST_MATCHER_P(Expr, hasDefinition, ast_matchers::internal::Matcher<Expr>,
518 const Expr *SimpleNode = &Node;
519 SimpleNode = SimpleNode->IgnoreParenImpCasts();
521 if (InnerMatcher.matches(*SimpleNode, Finder,
Builder))
524 auto DREHasInit = ignoringImpCasts(
525 declRefExpr(to(varDecl(hasInitializer(ignoringImpCasts(InnerMatcher))))));
527 if (DREHasInit.matches(*SimpleNode, Finder,
Builder))
530 const char *
const VarDeclName =
"variable-declaration";
531 auto DREHasDefinition = ignoringImpCasts(declRefExpr(
532 allOf(to(varDecl().bind(VarDeclName)),
533 hasAncestor(compoundStmt(hasDescendant(binaryOperator(
534 hasLHS(declRefExpr(to(varDecl(equalsBoundNode(VarDeclName))))),
535 hasRHS(ignoringImpCasts(InnerMatcher)))))))));
537 if (DREHasDefinition.matches(*SimpleNode, Finder,
Builder))
546 binaryOperator(hasOperatorName(
"+"),
547 hasEitherOperand(ignoringParenImpCasts(integerLiteral())));
550 binaryOperator(hasOperatorName(
"-"),
551 hasEitherOperand(ignoringParenImpCasts(integerLiteral())));
553 auto HasIncOp = anyOf(ignoringImpCasts(IncOp), hasDescendant(IncOp));
554 auto HasDecOp = anyOf(ignoringImpCasts(DecOp), hasDescendant(DecOp));
556 auto Container = ignoringImpCasts(cxxMemberCallExpr(hasDescendant(declRefExpr(
557 hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(recordDecl(
558 hasAnyName(
"::std::vector",
"::std::list",
"::std::deque"))))))))));
560 auto StringTy = type(hasUnqualifiedDesugaredType(recordType(
561 hasDeclaration(cxxRecordDecl(hasName(
"::std::basic_string"))))));
564 anyOf(hasType(StringTy), hasType(qualType(pointsTo(StringTy))));
566 auto CharTyArray = hasType(qualType(hasCanonicalType(
569 auto CharTyPointer = hasType(
570 qualType(hasCanonicalType(pointerType(pointee(isAnyCharacter())))));
572 auto AnyOfCharTy = anyOf(CharTyArray, CharTyPointer);
580 callExpr(callee(functionDecl(hasAnyName(
"::strlen",
"::wcslen"))))
586 allOf(on(expr(AnyOfStringTy).bind(
"Foo")),
587 has(memberExpr(member(hasAnyName(
"size",
"length"))))))
591 auto SizeOfCharExpr = unaryExprOrTypeTraitExpr(has(expr(AnyOfCharTy)));
594 ignoringImpCasts(anyOf(Strlen, SizeOrLength, hasDescendant(Strlen),
595 hasDescendant(SizeOrLength)));
599 ignoringImpCasts(declRefExpr(to(varDecl(hasInitializer(WrongLength)))));
601 auto AnyOfCallOrDREWithoutInc = anyOf(DREWithoutInc, WrongLength);
604 auto CallExprReturnWithoutInc = ignoringImpCasts(callExpr(callee(functionDecl(
605 hasBody(has(returnStmt(hasReturnValue(AnyOfCallOrDREWithoutInc))))))));
608 auto DREHasReturnWithoutInc = ignoringImpCasts(
609 declRefExpr(to(varDecl(hasInitializer(CallExprReturnWithoutInc)))));
611 auto AnyOfWrongLengthInit =
612 anyOf(WrongLength, AnyOfCallOrDREWithoutInc, CallExprReturnWithoutInc,
613 DREHasReturnWithoutInc);
621 auto SizeExpr = anyOf(SizeOfCharExpr, integerLiteral(equals(1)));
623 auto MallocLengthExpr = allOf(
625 hasAnyName(
"::alloca",
"::calloc",
"malloc",
"realloc"))),
629 auto DestMalloc = anyOf(callExpr(MallocLengthExpr),
630 hasDescendant(callExpr(MallocLengthExpr)));
633 auto DestCXXNewExpr = ignoringImpCasts(
636 auto AnyOfDestInit = anyOf(DestMalloc, DestCXXNewExpr);
639 auto DestArrayTyDecl = declRefExpr(
644 auto DestUnknownDecl =
649 auto AnyOfDestDecl = ignoringImpCasts(
650 anyOf(allOf(hasDefinition(anyOf(AnyOfDestInit, DestArrayTyDecl,
651 hasDescendant(DestArrayTyDecl))),
653 anyOf(DestUnknownDecl, hasDescendant(DestUnknownDecl))));
655 auto NullTerminatorExpr = binaryOperator(
656 hasLHS(anyOf(hasDescendant(declRefExpr(to(varDecl(
658 hasDescendant(declRefExpr(
660 hasRHS(ignoringImpCasts(
661 anyOf(characterLiteral(equals(0U)), integerLiteral(equals(0))))));
663 auto SrcDecl = declRefExpr(
665 anyOf(hasAncestor(cxxMemberCallExpr().bind(
SrcExprName)),
669 ignoringImpCasts(anyOf(stringLiteral().bind(
SrcExprName),
671 SrcDecl, hasDescendant(SrcDecl)));
678 CallContext(StringRef
Name, Optional<unsigned> DestinationPos,
679 Optional<unsigned> SourcePos,
unsigned LengthPos,
681 :
Name(
Name), DestinationPos(DestinationPos), SourcePos(SourcePos),
682 LengthPos(LengthPos), WithIncrease(WithIncrease){};
685 Optional<unsigned> DestinationPos;
686 Optional<unsigned> SourcePos;
691 auto MatchDestination = [=](CallContext CC) {
692 return hasArgument(*CC.DestinationPos,
694 unless(hasAncestor(compoundStmt(
695 hasDescendant(NullTerminatorExpr)))),
699 auto MatchSource = [=](CallContext CC) {
700 return hasArgument(*CC.SourcePos, AnyOfSrcDecl);
703 auto MatchGivenLength = [=](CallContext CC) {
709 allOf(unless(hasDefinition(SizeOfCharExpr)),
710 allOf(CC.WithIncrease
711 ? ignoringImpCasts(hasDefinition(HasIncOp))
712 : ignoringImpCasts(allOf(
713 unless(hasDefinition(HasIncOp)),
714 anyOf(hasDefinition(binaryOperator().bind(
716 hasDefinition(anything())))),
717 AnyOfWrongLengthInit))),
721 auto MatchCall = [=](CallContext CC) {
722 std::string CharHandlerFuncName =
"::" + CC.Name.str();
725 std::string WcharHandlerFuncName =
726 "::" + (CC.Name.startswith(
"mem") ?
"w" + CC.Name.str()
727 :
"wcs" + CC.Name.substr(3).str());
729 return allOf(callee(functionDecl(
730 hasAnyName(CharHandlerFuncName, WcharHandlerFuncName))),
731 MatchGivenLength(CC));
734 auto Match = [=](CallContext CC) {
735 if (CC.DestinationPos && CC.SourcePos)
736 return allOf(MatchCall(CC), MatchDestination(CC), MatchSource(CC));
738 if (CC.DestinationPos && !CC.SourcePos)
739 return allOf(MatchCall(CC), MatchDestination(CC),
740 hasArgument(*CC.DestinationPos, anything()));
742 if (!CC.DestinationPos && CC.SourcePos)
743 return allOf(MatchCall(CC), MatchSource(CC),
744 hasArgument(*CC.SourcePos, anything()));
746 llvm_unreachable(
"Unhandled match");
750 auto Memcpy = Match({
"memcpy", 0, 1, 2,
false});
753 auto Memcpy_s = Match({
"memcpy_s", 0, 2, 3,
false});
756 auto Memchr = Match({
"memchr", None, 0, 2,
false});
759 auto Memmove = Match({
"memmove", 0, 1, 2,
false});
762 auto Memmove_s = Match({
"memmove_s", 0, 2, 3,
false});
765 auto StrncmpRHS = Match({
"strncmp", None, 1, 2,
true});
766 auto StrncmpLHS = Match({
"strncmp", None, 0, 2,
true});
769 auto Strxfrm = Match({
"strxfrm", 0, 1, 2,
false});
772 auto Strerror_s = Match({
"strerror_s", 0, None, 1,
false});
774 auto AnyOfMatchers = anyOf(Memcpy, Memcpy_s, Memmove, Memmove_s, StrncmpRHS,
775 StrncmpLHS, Strxfrm, Strerror_s);
782 unless(hasAncestor(castExpr(unless(implicitCastExpr())))))
786 castExpr(allOf(unless(implicitCastExpr()),
793 const MatchFinder::MatchResult &Result) {
794 const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(
FunctionExprName);
795 if (FunctionExpr->getBeginLoc().isMacroID())
798 if (WantToUseSafeFunctions &&
PP->isMacroDefined(
"__STDC_LIB_EXT1__")) {
799 Optional<bool> AreSafeFunctionsWanted;
801 Preprocessor::macro_iterator It =
PP->macro_begin();
802 while (It !=
PP->macro_end() && !AreSafeFunctionsWanted.hasValue()) {
803 if (It->first->getName() ==
"__STDC_WANT_LIB_EXT1__") {
804 const auto *MI =
PP->getMacroInfo(It->first);
805 const auto &T = MI->tokens().back();
806 StringRef ValueStr = StringRef(T.getLiteralData(), T.getLength());
807 llvm::APInt IntValue;
808 ValueStr.getAsInteger(10, IntValue);
809 AreSafeFunctionsWanted = IntValue.getZExtValue();
815 if (AreSafeFunctionsWanted.hasValue())
816 UseSafeFunctions = AreSafeFunctionsWanted.getValue();
819 StringRef
Name = FunctionExpr->getDirectCallee()->getName();
820 if (
Name.startswith(
"mem") ||
Name.startswith(
"wmem"))
821 memoryHandlerFunctionFix(
Name, Result);
822 else if (
Name ==
"strerror_s")
823 strerror_sFix(Result);
824 else if (
Name.endswith(
"ncmp"))
825 ncmpFix(
Name, Result);
826 else if (
Name.endswith(
"xfrm"))
827 xfrmFix(
Name, Result);
830 void NotNullTerminatedResultCheck::memoryHandlerFunctionFix(
831 StringRef
Name,
const MatchFinder::MatchResult &Result) {
835 if (
Name.endswith(
"chr")) {
836 memchrFix(
Name, Result);
840 if ((
Name.contains(
"cpy") ||
Name.contains(
"move")) &&
846 "the result from calling '%0' is not null-terminated")
849 if (
Name.endswith(
"cpy")) {
850 memcpyFix(
Name, Result, Diag);
851 }
else if (
Name.endswith(
"cpy_s")) {
852 memcpy_sFix(
Name, Result, Diag);
853 }
else if (
Name.endswith(
"move")) {
854 memmoveFix(
Name, Result, Diag);
855 }
else if (
Name.endswith(
"move_s")) {
861 void NotNullTerminatedResultCheck::memcpyFix(
862 StringRef
Name,
const MatchFinder::MatchResult &Result,
863 DiagnosticBuilder &Diag) {
870 bool IsSafe = UseSafeFunctions && IsOverflows &&
isKnownDest(Result) &&
873 bool IsDestLengthNotRequired =
879 if (IsSafe && !IsDestLengthNotRequired)
885 if (!IsCopy && !IsSafe)
889 void NotNullTerminatedResultCheck::memcpy_sFix(
890 StringRef
Name,
const MatchFinder::MatchResult &Result,
891 DiagnosticBuilder &Diag) {
899 bool IsSafe = IsOverflows;
903 if (!IsSafe || (IsSafe && RemoveDestLength))
911 if (!IsCopy && !IsSafe)
915 void NotNullTerminatedResultCheck::memchrFix(
916 StringRef
Name,
const MatchFinder::MatchResult &Result) {
917 const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(
FunctionExprName);
918 if (
const auto GivenCL = dyn_cast<CharacterLiteral>(FunctionExpr->getArg(1)))
919 if (GivenCL->getValue() != 0)
922 auto Diag =
diag(FunctionExpr->getArg(2)->IgnoreParenCasts()->getBeginLoc(),
923 "the length is too short to include the null terminator");
925 if (
const auto *CastExpr = Result.Nodes.getNodeAs<Expr>(
CastExprName)) {
926 const auto CastRemoveFix = FixItHint::CreateRemoval(
927 SourceRange(CastExpr->getBeginLoc(),
928 FunctionExpr->getBeginLoc().getLocWithOffset(-1)));
929 Diag << CastRemoveFix;
932 StringRef NewFuncName = (
Name[0] !=
'w') ?
"strchr" :
"wcschr";
937 void NotNullTerminatedResultCheck::memmoveFix(
938 StringRef
Name,
const MatchFinder::MatchResult &Result,
939 DiagnosticBuilder &Diag) {
943 renameFunc((
Name[0] !=
'w') ?
"memmove_s" :
"wmemmove_s", Result, Diag);
950 void NotNullTerminatedResultCheck::strerror_sFix(
951 const MatchFinder::MatchResult &Result) {
954 "the result from calling 'strerror_s' is not null-terminated and "
955 "missing the last character of the error message");
961 void NotNullTerminatedResultCheck::ncmpFix(
962 StringRef
Name,
const MatchFinder::MatchResult &Result) {
963 const auto *FunctionExpr = Result.Nodes.getNodeAs<CallExpr>(
FunctionExprName);
964 const Expr *FirstArgExpr = FunctionExpr->getArg(0)->IgnoreImpCasts();
965 const Expr *SecondArgExpr = FunctionExpr->getArg(1)->IgnoreImpCasts();
966 bool IsLengthTooLong =
false;
969 const Expr *LengthExprArg = StrlenExpr->getArg(0);
970 StringRef FirstExprStr =
exprToStr(FirstArgExpr, Result).trim();
971 StringRef SecondExprStr =
exprToStr(SecondArgExpr, Result).trim();
972 StringRef LengthArgStr =
exprToStr(LengthExprArg, Result).trim();
974 LengthArgStr == FirstExprStr || LengthArgStr == SecondExprStr;
979 if (SrcLength != 0 && GivenLength != 0)
980 IsLengthTooLong = GivenLength > SrcLength;
986 auto Diag =
diag(FunctionExpr->getArg(2)->IgnoreParenCasts()->getBeginLoc(),
987 "comparison length is too long and might lead to a "
993 void NotNullTerminatedResultCheck::xfrmFix(
994 StringRef
Name,
const MatchFinder::MatchResult &Result) {
1000 "the result from calling '%0' is not null-terminated")