brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.0 KiB · b3e0673 Raw
82 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//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) == '\0')21      return true;22  return false;23}24} // namespace25 26void StringLiteralWithEmbeddedNulCheck::registerMatchers(MatchFinder *Finder) {27  // Match a string that contains embedded NUL character. Extra-checks are28  // applied in |check| to find incorrectly escaped characters.29  Finder->addMatcher(stringLiteral(containsNul()).bind("strlit"), this);30 31  // The remaining checks only apply to C++.32  if (!getLangOpts().CPlusPlus)33    return;34 35  const auto StrLitWithNul =36      ignoringParenImpCasts(stringLiteral(containsNul()).bind("truncated"));37 38  // Match string constructor.39  const auto StringConstructorExpr = expr(anyOf(40      cxxConstructExpr(argumentCountIs(1),41                       hasDeclaration(cxxMethodDecl(hasName("basic_string")))),42      // If present, the second argument is the alloc object which must not43      // be present explicitly.44      cxxConstructExpr(argumentCountIs(2),45                       hasDeclaration(cxxMethodDecl(hasName("basic_string"))),46                       hasArgument(1, cxxDefaultArgExpr()))));47 48  // Detect passing a suspicious string literal to a string constructor.49  // example: std::string str = "abc\0def";50  Finder->addMatcher(51      traverse(TK_AsIs, cxxConstructExpr(StringConstructorExpr,52                                         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 59void 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->getBeginLoc(), "suspicious embedded NUL character");70        return;71      }72    }73  }74 75  if (const auto *SL = Result.Nodes.getNodeAs<StringLiteral>("truncated")) {76    diag(SL->getBeginLoc(),77         "truncated string literal with embedded NUL character");78  }79}80 81} // namespace clang::tidy::bugprone82