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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang-tools-extra/clang-tidy/bugprone/StringLiteralWithEmbeddedNulCheck.cpp