11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 using namespace clang::ast_matchers;
21 for (
size_t i = 0; i < Node.getLength(); ++i)
22 if (Node.getCodeUnit(i) ==
'\0')
27 void StringLiteralWithEmbeddedNulCheck::registerMatchers(MatchFinder *
Finder) {
30 Finder->addMatcher(stringLiteral(containsNul()).bind(
"strlit"),
this);
33 if (!getLangOpts().CPlusPlus)
36 const auto StrLitWithNul =
37 ignoringParenImpCasts(stringLiteral(containsNul()).bind(
"truncated"));
40 const auto StringConstructorExpr = expr(anyOf(
41 cxxConstructExpr(argumentCountIs(1),
42 hasDeclaration(cxxMethodDecl(hasName(
"basic_string")))),
45 cxxConstructExpr(argumentCountIs(2),
46 hasDeclaration(cxxMethodDecl(hasName(
"basic_string"))),
47 hasArgument(1, cxxDefaultArgExpr()))));
52 cxxConstructExpr(StringConstructorExpr, hasArgument(0, StrLitWithNul)),
56 Finder->addMatcher(cxxOperatorCallExpr(hasAnyArgument(StrLitWithNul)),
this);
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;
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");
75 if (
const auto *SL = Result.Nodes.getNodeAs<StringLiteral>(
"truncated")) {
76 diag(SL->getLocStart(),
77 "truncated string literal with embedded NUL character");
std::unique_ptr< ast_matchers::MatchFinder > Finder
AST_MATCHER(StringLiteral, containsNul)