clang  6.0.0svn
CastToStructChecker.cpp
Go to the documentation of this file.
1 //=== CastToStructChecker.cpp ----------------------------------*- 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 // This files defines CastToStructChecker, a builtin checker that checks for
11 // cast from non-struct pointer to struct pointer and widening struct data cast.
12 // This check corresponds to CWE-588.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "ClangSACheckers.h"
22 
23 using namespace clang;
24 using namespace ento;
25 
26 namespace {
27 class CastToStructVisitor : public RecursiveASTVisitor<CastToStructVisitor> {
28  BugReporter &BR;
29  const CheckerBase *Checker;
31 
32 public:
33  explicit CastToStructVisitor(BugReporter &B, const CheckerBase *Checker,
35  : BR(B), Checker(Checker), AC(A) {}
36  bool VisitCastExpr(const CastExpr *CE);
37 };
38 }
39 
40 bool CastToStructVisitor::VisitCastExpr(const CastExpr *CE) {
41  const Expr *E = CE->getSubExpr();
42  ASTContext &Ctx = AC->getASTContext();
43  QualType OrigTy = Ctx.getCanonicalType(E->getType());
44  QualType ToTy = Ctx.getCanonicalType(CE->getType());
45 
46  const PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr());
47  const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
48 
49  if (!ToPTy || !OrigPTy)
50  return true;
51 
52  QualType OrigPointeeTy = OrigPTy->getPointeeType();
53  QualType ToPointeeTy = ToPTy->getPointeeType();
54 
55  if (!ToPointeeTy->isStructureOrClassType())
56  return true;
57 
58  // We allow cast from void*.
59  if (OrigPointeeTy->isVoidType())
60  return true;
61 
62  // Now the cast-to-type is struct pointer, the original type is not void*.
63  if (!OrigPointeeTy->isRecordType()) {
64  SourceRange Sr[1] = {CE->getSourceRange()};
65  PathDiagnosticLocation Loc(CE, BR.getSourceManager(), AC);
66  BR.EmitBasicReport(
67  AC->getDecl(), Checker, "Cast from non-struct type to struct type",
68  categories::LogicError, "Casting a non-structure type to a structure "
69  "type and accessing a field can lead to memory "
70  "access errors or data corruption.",
71  Loc, Sr);
72  } else {
73  // Don't warn when size of data is unknown.
74  const auto *U = dyn_cast<UnaryOperator>(E);
75  if (!U || U->getOpcode() != UO_AddrOf)
76  return true;
77 
78  // Don't warn for references
79  const ValueDecl *VD = nullptr;
80  if (const auto *SE = dyn_cast<DeclRefExpr>(U->getSubExpr()))
81  VD = dyn_cast<ValueDecl>(SE->getDecl());
82  else if (const auto *SE = dyn_cast<MemberExpr>(U->getSubExpr()))
83  VD = SE->getMemberDecl();
84  if (!VD || VD->getType()->isReferenceType())
85  return true;
86 
87  if (ToPointeeTy->isIncompleteType() ||
88  OrigPointeeTy->isIncompleteType())
89  return true;
90 
91  // Warn when there is widening cast.
92  unsigned ToWidth = Ctx.getTypeInfo(ToPointeeTy).Width;
93  unsigned OrigWidth = Ctx.getTypeInfo(OrigPointeeTy).Width;
94  if (ToWidth <= OrigWidth)
95  return true;
96 
97  PathDiagnosticLocation Loc(CE, BR.getSourceManager(), AC);
98  BR.EmitBasicReport(AC->getDecl(), Checker, "Widening cast to struct type",
100  "Casting data to a larger structure type and accessing "
101  "a field can lead to memory access errors or data "
102  "corruption.",
103  Loc, CE->getSourceRange());
104  }
105 
106  return true;
107 }
108 
109 namespace {
110 class CastToStructChecker : public Checker<check::ASTCodeBody> {
111 public:
112  void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
113  BugReporter &BR) const {
114  CastToStructVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D));
115  Visitor.TraverseDecl(const_cast<Decl *>(D));
116  }
117 };
118 } // end anonymous namespace
119 
120 void ento::registerCastToStructChecker(CheckerManager &mgr) {
121  mgr.registerChecker<CastToStructChecker>();
122 }
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:2285
QualType getPointeeType() const
Definition: Type.h:2298
A (possibly-)qualified type.
Definition: Type.h:653
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:456
bool isRecordType() const
Definition: Type.h:6017
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:149
AnalysisDeclContext contains the context data for the function or method under analysis.
bool isReferenceType() const
Definition: Type.h:5956
Expr * getSubExpr()
Definition: Expr.h:2761
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:5720
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:2710
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
ValueDecl - Represent the declaration of a variable (in which case it is an lvalue) a function (in wh...
Definition: Decl.h:628
Expr - This represents one expression.
Definition: Expr.h:106
QualType getType() const
Definition: Expr.h:128
UnaryOperator - This represents the unary-expression&#39;s (except sizeof and alignof), the postinc/postdec operators from postfix-expression, and various extensions.
Definition: Expr.h:1717
BugReporter is a utility class for generating PathDiagnostics for analysis.
Definition: BugReporter.h:403
bool isStructureOrClassType() const
Definition: Type.cpp:418
CHECKER * registerChecker()
Used to register checkers.
Dataflow Directional Tag Classes.
bool isIncompleteType(NamedDecl **Def=nullptr) const
Types are partitioned into 3 broad categories (C99 6.2.5p1): object types, function types...
Definition: Type.cpp:1986
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:2174
bool isVoidType() const
Definition: Type.h:6171
TypeInfo getTypeInfo(const Type *T) const
Get the size and alignment of the specified complete type in bits.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:265
uint64_t Width
Definition: ASTContext.h:138
QualType getType() const
Definition: Decl.h:639
A trivial tuple used to represent a source range.