clang  6.0.0svn
CStringSyntaxChecker.cpp
Go to the documentation of this file.
1 //== CStringSyntaxChecker.cpp - CoreFoundation containers API *- C++ -*-==//
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 //
10 // An AST checker that looks for common pitfalls when using C string APIs.
11 // - Identifies erroneous patterns in the last argument to strncat - the number
12 // of bytes to copy.
13 //
14 //===----------------------------------------------------------------------===//
15 #include "ClangSACheckers.h"
16 #include "clang/AST/Expr.h"
18 #include "clang/AST/StmtVisitor.h"
20 #include "clang/Basic/TargetInfo.h"
21 #include "clang/Basic/TypeTraits.h"
26 #include "llvm/ADT/SmallString.h"
27 #include "llvm/Support/raw_ostream.h"
28 
29 using namespace clang;
30 using namespace ento;
31 
32 namespace {
33 class WalkAST: public StmtVisitor<WalkAST> {
34  const CheckerBase *Checker;
35  BugReporter &BR;
37 
38  /// Check if two expressions refer to the same declaration.
39  bool sameDecl(const Expr *A1, const Expr *A2) {
40  if (const auto *D1 = dyn_cast<DeclRefExpr>(A1->IgnoreParenCasts()))
41  if (const auto *D2 = dyn_cast<DeclRefExpr>(A2->IgnoreParenCasts()))
42  return D1->getDecl() == D2->getDecl();
43  return false;
44  }
45 
46  /// Check if the expression E is a sizeof(WithArg).
47  bool isSizeof(const Expr *E, const Expr *WithArg) {
48  if (const auto *UE = dyn_cast<UnaryExprOrTypeTraitExpr>(E))
49  if (UE->getKind() == UETT_SizeOf && !UE->isArgumentType())
50  return sameDecl(UE->getArgumentExpr(), WithArg);
51  return false;
52  }
53 
54  /// Check if the expression E is a strlen(WithArg).
55  bool isStrlen(const Expr *E, const Expr *WithArg) {
56  if (const auto *CE = dyn_cast<CallExpr>(E)) {
57  const FunctionDecl *FD = CE->getDirectCallee();
58  if (!FD)
59  return false;
60  return (CheckerContext::isCLibraryFunction(FD, "strlen") &&
61  sameDecl(CE->getArg(0), WithArg));
62  }
63  return false;
64  }
65 
66  /// Check if the expression is an integer literal with value 1.
67  bool isOne(const Expr *E) {
68  if (const auto *IL = dyn_cast<IntegerLiteral>(E))
69  return (IL->getValue().isIntN(1));
70  return false;
71  }
72 
73  StringRef getPrintableName(const Expr *E) {
74  if (const auto *D = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
75  return D->getDecl()->getName();
76  return StringRef();
77  }
78 
79  /// Identify erroneous patterns in the last argument to strncat - the number
80  /// of bytes to copy.
81  bool containsBadStrncatPattern(const CallExpr *CE);
82 
83 public:
84  WalkAST(const CheckerBase *Checker, BugReporter &BR, AnalysisDeclContext *AC)
85  : Checker(Checker), BR(BR), AC(AC) {}
86 
87  // Statement visitor methods.
88  void VisitChildren(Stmt *S);
89  void VisitStmt(Stmt *S) {
90  VisitChildren(S);
91  }
92  void VisitCallExpr(CallExpr *CE);
93 };
94 } // end anonymous namespace
95 
96 // The correct size argument should look like following:
97 // strncat(dst, src, sizeof(dst) - strlen(dest) - 1);
98 // We look for the following anti-patterns:
99 // - strncat(dst, src, sizeof(dst) - strlen(dst));
100 // - strncat(dst, src, sizeof(dst) - 1);
101 // - strncat(dst, src, sizeof(dst));
102 bool WalkAST::containsBadStrncatPattern(const CallExpr *CE) {
103  if (CE->getNumArgs() != 3)
104  return false;
105  const Expr *DstArg = CE->getArg(0);
106  const Expr *SrcArg = CE->getArg(1);
107  const Expr *LenArg = CE->getArg(2);
108 
109  // Identify wrong size expressions, which are commonly used instead.
110  if (const auto *BE = dyn_cast<BinaryOperator>(LenArg->IgnoreParenCasts())) {
111  // - sizeof(dst) - strlen(dst)
112  if (BE->getOpcode() == BO_Sub) {
113  const Expr *L = BE->getLHS();
114  const Expr *R = BE->getRHS();
115  if (isSizeof(L, DstArg) && isStrlen(R, DstArg))
116  return true;
117 
118  // - sizeof(dst) - 1
119  if (isSizeof(L, DstArg) && isOne(R->IgnoreParenCasts()))
120  return true;
121  }
122  }
123  // - sizeof(dst)
124  if (isSizeof(LenArg, DstArg))
125  return true;
126 
127  // - sizeof(src)
128  if (isSizeof(LenArg, SrcArg))
129  return true;
130  return false;
131 }
132 
133 void WalkAST::VisitCallExpr(CallExpr *CE) {
134  const FunctionDecl *FD = CE->getDirectCallee();
135  if (!FD)
136  return;
137 
138  if (CheckerContext::isCLibraryFunction(FD, "strncat")) {
139  if (containsBadStrncatPattern(CE)) {
140  const Expr *DstArg = CE->getArg(0);
141  const Expr *LenArg = CE->getArg(2);
144 
145  StringRef DstName = getPrintableName(DstArg);
146 
148  llvm::raw_svector_ostream os(S);
149  os << "Potential buffer overflow. ";
150  if (!DstName.empty()) {
151  os << "Replace with 'sizeof(" << DstName << ") "
152  "- strlen(" << DstName <<") - 1'";
153  os << " or u";
154  } else
155  os << "U";
156  os << "se a safer 'strlcat' API";
157 
158  BR.EmitBasicReport(FD, Checker, "Anti-pattern in the argument",
159  "C String API", os.str(), Loc,
160  LenArg->getSourceRange());
161  }
162  }
163 
164  // Recurse and check children.
165  VisitChildren(CE);
166 }
167 
168 void WalkAST::VisitChildren(Stmt *S) {
169  for (Stmt *Child : S->children())
170  if (Child)
171  Visit(Child);
172 }
173 
174 namespace {
175 class CStringSyntaxChecker: public Checker<check::ASTCodeBody> {
176 public:
177 
178  void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
179  BugReporter &BR) const {
180  WalkAST walker(this, BR, Mgr.getAnalysisDeclContext(D));
181  walker.Visit(D->getBody());
182  }
183 };
184 }
185 
186 void ento::registerCStringSyntaxChecker(CheckerManager &mgr) {
187  mgr.registerChecker<CStringSyntaxChecker>();
188 }
189 
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Definition: Decl.h:1698
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2278
Defines enumerations for the type traits support.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition: DeclBase.h:974
Stmt - This represents one statement.
Definition: Stmt.h:66
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2266
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
AnalysisDeclContext contains the context data for the function or method under analysis.
child_range children()
Definition: Stmt.cpp:226
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
Definition: Expr.cpp:2463
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
Expr - This represents one expression.
Definition: Expr.h:106
static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name=StringRef())
Returns true if the callee is an externally-visible function in the top-level namespace, such as malloc.
BugReporter is a utility class for generating PathDiagnostics for analysis.
Definition: BugReporter.h:403
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
CHECKER * registerChecker()
Used to register checkers.
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=None)
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:183
const Decl * getDecl() const
Dataflow Directional Tag Classes.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return 0.
Definition: Expr.cpp:1216
SourceManager & getSourceManager()
Definition: BugReporter.h:463
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:265
Defines the clang::TargetInfo interface.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2209
StringRef getName() const
getName - Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:270