1218887Sdim//==- CheckSizeofPointer.cpp - Check for sizeof on pointers ------*- C++ -*-==//
2218887Sdim//
3218887Sdim//                     The LLVM Compiler Infrastructure
4218887Sdim//
5218887Sdim// This file is distributed under the University of Illinois Open Source
6218887Sdim// License. See LICENSE.TXT for details.
7218887Sdim//
8218887Sdim//===----------------------------------------------------------------------===//
9218887Sdim//
10218887Sdim//  This file defines a check for unintended use of sizeof() on pointer
11218887Sdim//  expressions.
12218887Sdim//
13218887Sdim//===----------------------------------------------------------------------===//
14218887Sdim
15218887Sdim#include "ClangSACheckers.h"
16226633Sdim#include "clang/AST/StmtVisitor.h"
17249423Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
18221345Sdim#include "clang/StaticAnalyzer/Core/Checker.h"
19226633Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
20218887Sdim
21218887Sdimusing namespace clang;
22218887Sdimusing namespace ento;
23218887Sdim
24218887Sdimnamespace {
25218887Sdimclass WalkAST : public StmtVisitor<WalkAST> {
26218887Sdim  BugReporter &BR;
27234353Sdim  AnalysisDeclContext* AC;
28218887Sdim
29218887Sdimpublic:
30234353Sdim  WalkAST(BugReporter &br, AnalysisDeclContext* ac) : BR(br), AC(ac) {}
31221345Sdim  void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
32218887Sdim  void VisitStmt(Stmt *S) { VisitChildren(S); }
33218887Sdim  void VisitChildren(Stmt *S);
34218887Sdim};
35218887Sdim}
36218887Sdim
37218887Sdimvoid WalkAST::VisitChildren(Stmt *S) {
38218887Sdim  for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
39218887Sdim    if (Stmt *child = *I)
40218887Sdim      Visit(child);
41218887Sdim}
42218887Sdim
43218887Sdim// CWE-467: Use of sizeof() on a Pointer Type
44221345Sdimvoid WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
45221345Sdim  if (E->getKind() != UETT_SizeOf)
46218887Sdim    return;
47218887Sdim
48218887Sdim  // If an explicit type is used in the code, usually the coder knows what he is
49218887Sdim  // doing.
50218887Sdim  if (E->isArgumentType())
51218887Sdim    return;
52218887Sdim
53218887Sdim  QualType T = E->getTypeOfArgument();
54218887Sdim  if (T->isPointerType()) {
55218887Sdim
56218887Sdim    // Many false positives have the form 'sizeof *p'. This is reasonable
57218887Sdim    // because people know what they are doing when they intentionally
58218887Sdim    // dereference the pointer.
59218887Sdim    Expr *ArgEx = E->getArgumentExpr();
60218887Sdim    if (!isa<DeclRefExpr>(ArgEx->IgnoreParens()))
61218887Sdim      return;
62218887Sdim
63218887Sdim    SourceRange R = ArgEx->getSourceRange();
64226633Sdim    PathDiagnosticLocation ELoc =
65226633Sdim      PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC);
66234353Sdim    BR.EmitBasicReport(AC->getDecl(),
67234353Sdim                       "Potential unintended use of sizeof() on pointer type",
68218887Sdim                       "Logic",
69218887Sdim                       "The code calls sizeof() on a pointer type. "
70218887Sdim                       "This can produce an unexpected result.",
71226633Sdim                       ELoc, &R, 1);
72218887Sdim  }
73218887Sdim}
74218887Sdim
75218887Sdim//===----------------------------------------------------------------------===//
76218887Sdim// SizeofPointerChecker
77218887Sdim//===----------------------------------------------------------------------===//
78218887Sdim
79218887Sdimnamespace {
80221345Sdimclass SizeofPointerChecker : public Checker<check::ASTCodeBody> {
81218887Sdimpublic:
82218887Sdim  void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
83218887Sdim                        BugReporter &BR) const {
84234353Sdim    WalkAST walker(BR, mgr.getAnalysisDeclContext(D));
85218887Sdim    walker.Visit(D->getBody());
86218887Sdim  }
87218887Sdim};
88218887Sdim}
89218887Sdim
90218887Sdimvoid ento::registerSizeofPointerChecker(CheckerManager &mgr) {
91218887Sdim  mgr.registerChecker<SizeofPointerChecker>();
92218887Sdim}
93