CStringSyntaxChecker.cpp revision 8fe83e1df954d72c0f4ffc15d20a5222ec151c21
146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//== CStringSyntaxChecker.cpp - CoreFoundation containers API *- C++ -*-==//
246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//
346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//                     The LLVM Compiler Infrastructure
446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//
546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// This file is distributed under the University of Illinois Open Source
646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// License. See LICENSE.TXT for details.
746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//
846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//===----------------------------------------------------------------------===//
946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//
1046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// An AST checker that looks for common pitfalls when using C string APIs.
1146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//  - Identifies erroneous patterns in the last argument to strncat - the number
1246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//    of bytes to copy.
13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
1446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//===----------------------------------------------------------------------===//
1546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "ClangSACheckers.h"
1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "clang/Analysis/AnalysisContext.h"
1746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "clang/AST/Expr.h"
1846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "clang/AST/OperationKinds.h"
1946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "clang/AST/StmtVisitor.h"
2046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "clang/Basic/TargetInfo.h"
2146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "clang/Basic/TypeTraits.h"
2246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/Checker.h"
2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
2446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
2546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "llvm/ADT/SmallString.h"
2746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "llvm/Support/raw_ostream.h"
2846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
2946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)using namespace clang;
3046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)using namespace ento;
3146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
3246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace {
3346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)class WalkAST: public StmtVisitor<WalkAST> {
3446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  BugReporter &BR;
3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  AnalysisDeclContext* AC;
3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ASTContext &ASTC;
3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
3846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  /// Check if two expressions refer to the same declaration.
3946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  inline bool sameDecl(const Expr *A1, const Expr *A2) {
4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (const DeclRefExpr *D1 = dyn_cast<DeclRefExpr>(A1->IgnoreParenCasts()))
4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (const DeclRefExpr *D2 = dyn_cast<DeclRefExpr>(A2->IgnoreParenCasts()))
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        return D1->getDecl() == D2->getDecl();
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  /// Check if the expression E is a sizeof(WithArg).
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  inline bool isSizeof(const Expr *E, const Expr *WithArg) {
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (const UnaryExprOrTypeTraitExpr *UE =
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    dyn_cast<UnaryExprOrTypeTraitExpr>(E))
5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (UE->getKind() == UETT_SizeOf)
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        return sameDecl(UE->getArgumentExpr(), WithArg);
5246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
5346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
5446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  /// Check if the expression E is a strlen(WithArg).
5646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  inline bool isStrlen(const Expr *E, const Expr *WithArg) {
5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      const FunctionDecl *FD = CE->getDirectCallee();
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (!FD)
6046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        return false;
6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return (CheckerContext::isCLibraryFunction(FD, "strlen", ASTC)
6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          && sameDecl(CE->getArg(0), WithArg));
6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  /// Check if the expression is an integer literal with value 1.
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  inline bool isOne(const Expr *E) {
6946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E))
7046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return (IL->getValue().isIntN(1));
7146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
7246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
7346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
7446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  inline StringRef getPrintableName(const Expr *E) {
7546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (const DeclRefExpr *D = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
7646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return D->getDecl()->getName();
7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return StringRef();
7846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
7946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  /// Identify erroneous patterns in the last argument to strncat - the number
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  /// of bytes to copy.
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool containsBadStrncatPattern(const CallExpr *CE);
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
8446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)public:
8546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  WalkAST(BugReporter &br, AnalysisDeclContext* ac) :
8646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      BR(br), AC(ac), ASTC(AC->getASTContext()) {
8746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
8846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
8946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Statement visitor methods.
9046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void VisitChildren(Stmt *S);
9146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void VisitStmt(Stmt *S) {
9246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    VisitChildren(S);
9346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
9446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void VisitCallExpr(CallExpr *CE);
9546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
9646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} // end anonymous namespace
9746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
9846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// The correct size argument should look like following:
9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//   strncat(dst, src, sizeof(dst) - strlen(dest) - 1);
10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// We look for the following anti-patterns:
10146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//   - strncat(dst, src, sizeof(dst) - strlen(dst));
10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//   - strncat(dst, src, sizeof(dst) - 1);
10346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)//   - strncat(dst, src, sizeof(dst));
10446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool WalkAST::containsBadStrncatPattern(const CallExpr *CE) {
10546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const Expr *DstArg = CE->getArg(0);
10646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const Expr *SrcArg = CE->getArg(1);
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const Expr *LenArg = CE->getArg(2);
108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
10946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Identify wrong size expressions, which are commonly used instead.
110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (const BinaryOperator *BE =
11146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)              dyn_cast<BinaryOperator>(LenArg->IgnoreParenCasts())) {
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // - sizeof(dst) - strlen(dst)
11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (BE->getOpcode() == BO_Sub) {
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      const Expr *L = BE->getLHS();
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      const Expr *R = BE->getRHS();
116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (isSizeof(L, DstArg) && isStrlen(R, DstArg))
11746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        return true;
11846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // - sizeof(dst) - 1
12046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (isSizeof(L, DstArg) && isOne(R->IgnoreParenCasts()))
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return true;
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
12346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // - sizeof(dst)
12546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (isSizeof(LenArg, DstArg))
126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return true;
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // - sizeof(src)
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (isSizeof(LenArg, SrcArg))
13046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return true;
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return false;
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
13346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
13446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void WalkAST::VisitCallExpr(CallExpr *CE) {
13546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const FunctionDecl *FD = CE->getDirectCallee();
13646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!FD)
13746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
13846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
13946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (CheckerContext::isCLibraryFunction(FD, "strncat", ASTC)) {
14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (containsBadStrncatPattern(CE)) {
14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      const Expr *DstArg = CE->getArg(0);
14246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      const Expr *LenArg = CE->getArg(2);
14346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      SourceRange R = LenArg->getSourceRange();
14446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      PathDiagnosticLocation Loc =
14546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        PathDiagnosticLocation::createBegin(LenArg, BR.getSourceManager(), AC);
14646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
14746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      StringRef DstName = getPrintableName(DstArg);
148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
14946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      llvm::SmallString<256> S;
15046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      llvm::raw_svector_ostream os(S);
15146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      os << "Potential buffer overflow. ";
15246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (!DstName.empty()) {
15346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        os << "Replace with 'sizeof(" << DstName << ") "
15446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)              "- strlen(" << DstName <<") - 1'";
15546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        os << " or u";
15646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      } else
15746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        os << "U";
15846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      os << "se a safer 'strlcat' API";
15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
16046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      BR.EmitBasicReport("Anti-pattern in the argument", "C String API",
16146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         os.str(), Loc, &R, 1);
16246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
16346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
16546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Recurse and check children.
16646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  VisitChildren(CE);
16746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void WalkAST::VisitChildren(Stmt *S) {
17046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I != E;
17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ++I)
17246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (Stmt *child = *I)
17346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      Visit(child);
17446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
17546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
17646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace {
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class CStringSyntaxChecker: public Checker<check::ASTCodeBody> {
17846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)public:
17946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
18046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
18146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      BugReporter &BR) const {
18246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    WalkAST walker(BR, Mgr.getAnalysisDeclContext(D));
18346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    walker.Visit(D->getBody());
18446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
18546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
18646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
18746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
18846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ento::registerCStringSyntaxChecker(CheckerManager &mgr) {
18946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  mgr.registerChecker<CStringSyntaxChecker>();
19046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
19146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
19246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)