clang-tools 3.8.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

MemsetZeroLengthCheck.cpp
Go to the documentation of this file.
1 //===--- MemsetZeroLengthCheck.cpp - clang-tidy -------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "MemsetZeroLengthCheck.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/Lex/Lexer.h"
15
16 using namespace clang::ast_matchers;
17
18 namespace clang {
19 namespace tidy {
20 namespace google {
21 namespace runtime {
22
23 void
24 MemsetZeroLengthCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
25 // Look for memset(x, y, 0) as those is most likely an argument swap.
26 // TODO: Also handle other standard functions that suffer from the same
27 // problem, e.g. memchr.
28 Finder->addMatcher(
29 callExpr(callee(functionDecl(hasName("::memset"))), argumentCountIs(3),
30 unless(isInTemplateInstantiation())).bind("decl"),
31 this);
32 }
33
34 /// \brief Get a StringRef representing a SourceRange.
35 static StringRef getAsString(const MatchFinder::MatchResult &Result,
36 SourceRange R) {
37 const SourceManager &SM = *Result.SourceManager;
38 // Don't even try to resolve macro or include contraptions. Not worth emitting
39 // a fixit for.
40 if (R.getBegin().isMacroID() ||
41 !SM.isWrittenInSameFile(R.getBegin(), R.getEnd()))
42 return StringRef();
43
44 const char *Begin = SM.getCharacterData(R.getBegin());
45 const char *End = SM.getCharacterData(Lexer::getLocForEndOfToken(
46 R.getEnd(), 0, SM, Result.Context->getLangOpts()));
47
48 return StringRef(Begin, End - Begin);
49 }
50
51 void MemsetZeroLengthCheck::check(const MatchFinder::MatchResult &Result) {
52 const auto *Call = Result.Nodes.getNodeAs<CallExpr>("decl");
53
54 // Note, this is:
55 // void *memset(void *buffer, int fill_char, size_t byte_count);
56 // Arg1 is fill_char, Arg2 is byte_count.
57 const Expr *Arg1 = Call->getArg(1);
58 const Expr *Arg2 = Call->getArg(2);
59
60 // Return if `byte_count` is not zero at compile time.
61 llvm::APSInt Value1, Value2;
62 if (Arg2->isValueDependent() ||
63 !Arg2->EvaluateAsInt(Value2, *Result.Context) || Value2 != 0)
64 return;
65
66 // Return if `fill_char` is known to be zero or negative at compile
67 // time. In these cases, swapping the args would be a nop, or
68 // introduce a definite bug. The code is likely correct.
69 if (!Arg1->isValueDependent() &&
70 Arg1->EvaluateAsInt(Value1, *Result.Context) &&
71 (Value1 == 0 || Value1.isNegative()))
72 return;
73
74 // `byte_count` is known to be zero at compile time, and `fill_char` is
75 // either not known or known to be a positive integer. Emit a warning
76 // and fix-its to swap the arguments.
77 auto D = diag(Call->getLocStart(),
78 "memset of size zero, potentially swapped arguments");
79 SourceRange LHSRange = Arg1->getSourceRange();
80 SourceRange RHSRange = Arg2->getSourceRange();
81 StringRef RHSString = getAsString(Result, RHSRange);
82 StringRef LHSString = getAsString(Result, LHSRange);
83 if (LHSString.empty() || RHSString.empty())
84 return;
85
86 D << FixItHint::CreateReplacement(CharSourceRange::getTokenRange(LHSRange),
87 RHSString)
88 << FixItHint::CreateReplacement(CharSourceRange::getTokenRange(RHSRange),
89 LHSString);
90 }
91
92 } // namespace runtime
93 } // namespace google
94 } // namespace tidy
95 } // namespace clang
Finder
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:188
SM
SourceManager & SM
Definition: IncludeOrderCheck.cpp:44
clang::tidy::google::runtime::getAsString
static StringRef getAsString(const MatchFinder::MatchResult &Result, SourceRange R)
Get a StringRef representing a SourceRange.
Definition: MemsetZeroLengthCheck.cpp:35
MemsetZeroLengthCheck.h
Result
const NamedDecl * Result
Definition: USRFinder.cpp:121