clang-tools  4.0.0
StringLiteralWithEmbeddedNulCheck.cpp
Go to the documentation of this file.
1 //===--- StringLiteralWithEmbeddedNulCheck.cpp - clang-tidy----------------===//
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 
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 
14 using namespace clang::ast_matchers;
15 
16 namespace clang {
17 namespace tidy {
18 namespace misc {
19 
20 AST_MATCHER(StringLiteral, containsNul) {
21  for (size_t i = 0; i < Node.getLength(); ++i)
22  if (Node.getCodeUnit(i) == '\0')
23  return true;
24  return false;
25 }
26 
27 void StringLiteralWithEmbeddedNulCheck::registerMatchers(MatchFinder *Finder) {
28  // Match a string that contains embedded NUL character. Extra-checks are
29  // applied in |check| to find incorectly escaped characters.
30  Finder->addMatcher(stringLiteral(containsNul()).bind("strlit"), this);
31 
32  // The remaining checks only apply to C++.
33  if (!getLangOpts().CPlusPlus)
34  return;
35 
36  const auto StrLitWithNul =
37  ignoringParenImpCasts(stringLiteral(containsNul()).bind("truncated"));
38 
39  // Match string constructor.
40  const auto StringConstructorExpr = expr(anyOf(
41  cxxConstructExpr(argumentCountIs(1),
42  hasDeclaration(cxxMethodDecl(hasName("basic_string")))),
43  // If present, the second argument is the alloc object which must not
44  // be present explicitly.
45  cxxConstructExpr(argumentCountIs(2),
46  hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
47  hasArgument(1, cxxDefaultArgExpr()))));
48 
49  // Detect passing a suspicious string literal to a string constructor.
50  // example: std::string str = "abc\0def";
51  Finder->addMatcher(
52  cxxConstructExpr(StringConstructorExpr, hasArgument(0, StrLitWithNul)),
53  this);
54 
55  // Detect passing a suspicious string literal through an overloaded operator.
56  Finder->addMatcher(cxxOperatorCallExpr(hasAnyArgument(StrLitWithNul)), this);
57 }
58 
59 void StringLiteralWithEmbeddedNulCheck::check(
60  const MatchFinder::MatchResult &Result) {
61  if (const auto *SL = Result.Nodes.getNodeAs<StringLiteral>("strlit")) {
62  for (size_t Offset = 0, Length = SL->getLength(); Offset < Length;
63  ++Offset) {
64  // Find a sequence of character like "\0x12".
65  if (Offset + 3 < Length && SL->getCodeUnit(Offset) == '\0' &&
66  SL->getCodeUnit(Offset + 1) == 'x' &&
67  isDigit(SL->getCodeUnit(Offset + 2)) &&
68  isDigit(SL->getCodeUnit(Offset + 3))) {
69  diag(SL->getLocStart(), "suspicious embedded NUL character");
70  return;
71  }
72  }
73  }
74 
75  if (const auto *SL = Result.Nodes.getNodeAs<StringLiteral>("truncated")) {
76  diag(SL->getLocStart(),
77  "truncated string literal with embedded NUL character");
78  }
79 }
80 
81 } // namespace misc
82 } // namespace tidy
83 } // namespace clang
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:262
AST_MATCHER(StringLiteral, containsNul)
const NamedDecl * Result
Definition: USRFinder.cpp:162