10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 #include "clang/ASTMatchers/ASTMatchers.h" 13 #include "clang/Lex/Lexer.h" 14 #include "clang/Tooling/FixIt.h" 22 void SuspiciousMemsetUsageCheck::registerMatchers(MatchFinder *Finder) {
27 callee(functionDecl(hasName(
"::memset"))),
28 hasArgument(1, characterLiteral(equals(static_cast<unsigned>(
'0')))
29 .bind(
"char-zero-fill")),
31 eachOf(hasArgument(0, anyOf(hasType(pointsTo(isAnyCharacter())),
32 hasType(arrayType(hasElementType(
33 isAnyCharacter()))))),
34 isInTemplateInstantiation()))),
39 Finder->addMatcher(callExpr(callee(functionDecl(hasName(
"::memset"))),
40 hasArgument(1, integerLiteral().bind(
"num-fill")),
41 unless(isInTemplateInstantiation())),
46 callExpr(callee(functionDecl(hasName(
"::memset"))),
47 unless(hasArgument(1, anyOf(characterLiteral(equals(
48 static_cast<unsigned>(
'0'))),
50 unless(isInTemplateInstantiation()))
55 void SuspiciousMemsetUsageCheck::check(
const MatchFinder::MatchResult &
Result) {
56 if (
const auto *CharZeroFill =
57 Result.Nodes.getNodeAs<CharacterLiteral>(
"char-zero-fill")) {
61 SourceRange CharRange = CharZeroFill->getSourceRange();
63 diag(CharZeroFill->getBeginLoc(),
"memset fill value is char '0', " 64 "potentially mistaken for int 0");
67 if (CharRange.getBegin().isMacroID())
69 Diag << FixItHint::CreateReplacement(
73 else if (
const auto *NumFill =
74 Result.Nodes.getNodeAs<IntegerLiteral>(
"num-fill")) {
78 const auto UCharMax = (1 << Result.Context->getCharWidth()) - 1;
79 Expr::EvalResult EVResult;
80 if (!NumFill->EvaluateAsInt(EVResult, *Result.Context))
83 llvm::APSInt NumValue = EVResult.Val.getInt();
84 if (NumValue >= 0 && NumValue <= UCharMax)
87 diag(NumFill->getBeginLoc(),
"memset fill value is out of unsigned " 88 "character range, gets truncated");
91 else if (
const auto *Call = Result.Nodes.getNodeAs<CallExpr>(
"call")) {
95 const Expr *FillChar = Call->getArg(1);
96 const Expr *ByteCount = Call->getArg(2);
99 Expr::EvalResult Value2;
100 if (ByteCount->isValueDependent() ||
101 !ByteCount->EvaluateAsInt(Value2, *Result.Context) ||
102 Value2.Val.getInt() != 0)
108 Expr::EvalResult EVResult;
109 if (!FillChar->isValueDependent() &&
110 FillChar->EvaluateAsInt(EVResult, *Result.Context)) {
111 llvm::APSInt Value1 = EVResult.Val.getInt();
112 if (Value1 == 0 || Value1.isNegative())
119 auto D = diag(Call->getBeginLoc(),
120 "memset of size zero, potentially swapped arguments");
121 StringRef RHSString = tooling::fixit::getText(*ByteCount, *Result.Context);
122 StringRef LHSString = tooling::fixit::getText(*FillChar, *Result.Context);
123 if (LHSString.empty() || RHSString.empty())
126 D << tooling::fixit::createReplacement(*FillChar, RHSString)
127 << tooling::fixit::createReplacement(*ByteCount, LHSString);
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result