clang  10.0.0svn
CastToStructChecker.cpp
Go to the documentation of this file.
1 //=== CastToStructChecker.cpp ----------------------------------*- C++ -*--===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This files defines CastToStructChecker, a builtin checker that checks for
10 // cast from non-struct pointer to struct pointer and widening struct data cast.
11 // This check corresponds to CWE-588.
12 //
13 //===----------------------------------------------------------------------===//
14 
21 
22 using namespace clang;
23 using namespace ento;
24 
25 namespace {
26 class CastToStructVisitor : public RecursiveASTVisitor<CastToStructVisitor> {
27  BugReporter &BR;
28  const CheckerBase *Checker;
30 
31 public:
32  explicit CastToStructVisitor(BugReporter &B, const CheckerBase *Checker,
34  : BR(B), Checker(Checker), AC(A) {}
35  bool VisitCastExpr(const CastExpr *CE);
36 };
37 }
38 
39 bool CastToStructVisitor::VisitCastExpr(const CastExpr *CE) {
40  const Expr *E = CE->getSubExpr();
41  ASTContext &Ctx = AC->getASTContext();
42  QualType OrigTy = Ctx.getCanonicalType(E->getType());
43  QualType ToTy = Ctx.getCanonicalType(CE->getType());
44 
45  const PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr());
46  const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
47 
48  if (!ToPTy || !OrigPTy)
49  return true;
50 
51  QualType OrigPointeeTy = OrigPTy->getPointeeType();
52  QualType ToPointeeTy = ToPTy->getPointeeType();
53 
54  if (!ToPointeeTy->isStructureOrClassType())
55  return true;
56 
57  // We allow cast from void*.
58  if (OrigPointeeTy->isVoidType())
59  return true;
60 
61  // Now the cast-to-type is struct pointer, the original type is not void*.
62  if (!OrigPointeeTy->isRecordType()) {
63  SourceRange Sr[1] = {CE->getSourceRange()};
64  PathDiagnosticLocation Loc(CE, BR.getSourceManager(), AC);
65  BR.EmitBasicReport(
66  AC->getDecl(), Checker, "Cast from non-struct type to struct type",
67  categories::LogicError, "Casting a non-structure type to a structure "
68  "type and accessing a field can lead to memory "
69  "access errors or data corruption.",
70  Loc, Sr);
71  } else {
72  // Don't warn when size of data is unknown.
73  const auto *U = dyn_cast<UnaryOperator>(E);
74  if (!U || U->getOpcode() != UO_AddrOf)
75  return true;
76 
77  // Don't warn for references
78  const ValueDecl *VD = nullptr;
79  if (const auto *SE = dyn_cast<DeclRefExpr>(U->getSubExpr()))
80  VD = SE->getDecl();
81  else if (const auto *SE = dyn_cast<MemberExpr>(U->getSubExpr()))
82  VD = SE->getMemberDecl();
83  if (!VD || VD->getType()->isReferenceType())
84  return true;
85 
86  if (ToPointeeTy->isIncompleteType() ||
87  OrigPointeeTy->isIncompleteType())
88  return true;
89 
90  // Warn when there is widening cast.
91  unsigned ToWidth = Ctx.getTypeInfo(ToPointeeTy).Width;
92  unsigned OrigWidth = Ctx.getTypeInfo(OrigPointeeTy).Width;
93  if (ToWidth <= OrigWidth)
94  return true;
95 
96  PathDiagnosticLocation Loc(CE, BR.getSourceManager(), AC);
97  BR.EmitBasicReport(AC->getDecl(), Checker, "Widening cast to struct type",
99  "Casting data to a larger structure type and accessing "
100  "a field can lead to memory access errors or data "
101  "corruption.",
102  Loc, CE->getSourceRange());
103  }
104 
105  return true;
106 }
107 
108 namespace {
109 class CastToStructChecker : public Checker<check::ASTCodeBody> {
110 public:
111  void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
112  BugReporter &BR) const {
113  CastToStructVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D));
114  Visitor.TraverseDecl(const_cast<Decl *>(D));
115  }
116 };
117 } // end anonymous namespace
118 
119 void ento::registerCastToStructChecker(CheckerManager &mgr) {
120  mgr.registerChecker<CastToStructChecker>();
121 }
122 
123 bool ento::shouldRegisterCastToStructChecker(const LangOptions &LO) {
124  return true;
125 }
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:2585
QualType getPointeeType() const
Definition: Type.h:2598
A (possibly-)qualified type.
Definition: Type.h:643
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:557
bool isRecordType() const
Definition: Type.h:6471
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:88
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:160
AnalysisDeclContext contains the context data for the function or method under analysis.
bool isReferenceType() const
Definition: Type.h:6403
Expr * getSubExpr()
Definition: Expr.h:3177
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:49
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:6148
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3125
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:644
This represents one expression.
Definition: Expr.h:108
QualType getType() const
Definition: Expr.h:137
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:2021
bool isStructureOrClassType() const
Definition: Type.cpp:513
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:2118
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:2289
bool isVoidType() const
Definition: Type.h:6650
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:262
uint64_t Width
Definition: ASTContext.h:149
QualType getType() const
Definition: Decl.h:655
A trivial tuple used to represent a source range.