clang  14.0.0git
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 CheckerManager &mgr) {
124  return true;
125 }
clang::Type::isRecordType
bool isRecordType() const
Definition: Type.h:6762
clang::SourceRange
A trivial tuple used to represent a source range.
Definition: SourceLocation.h:212
clang::CastExpr::getSubExpr
Expr * getSubExpr()
Definition: Expr.h:3524
clang::Stmt::getSourceRange
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:324
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:673
clang::AnalysisDeclContext
AnalysisDeclContext contains the context data for the function, method or block under analysis.
Definition: AnalysisDeclContext.h:72
clang::TypeInfo::Width
uint64_t Width
Definition: ASTContext.h:183
clang::Type::isVoidType
bool isVoidType() const
Definition: Type.h:6955
U
clang::Type::isReferenceType
bool isReferenceType() const
Definition: Type.h:6684
BuiltinCheckerRegistration.h
CheckerManager.h
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:212
clang::RecursiveASTVisitor
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Definition: RecursiveASTVisitor.h:164
clang::ASTContext::getCanonicalType
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:2468
BugType.h
clang::ValueDecl
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:676
clang::Decl
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:89
CheckerContext.h
clang::Type::isStructureOrClassType
bool isStructureOrClassType() const
Definition: Type.cpp:581
Checker.h
clang::PointerType
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:2640
clang::ento::categories::LogicError
const char *const LogicError
Definition: CommonBugCategories.cpp:17
clang
Definition: CalledOnceCheck.h:17
RecursiveASTVisitor.h
clang::Expr::getType
QualType getType() const
Definition: Expr.h:141
clang::QualType::getTypePtr
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:6424
clang::PointerType::getPointeeType
QualType getPointeeType() const
Definition: Type.h:2650
clang::ValueDecl::getType
QualType getType() const
Definition: Decl.h:687
clang::Expr
This represents one expression.
Definition: Expr.h:109
clang::ASTContext::getTypeInfo
TypeInfo getTypeInfo(const Type *T) const
Get the size and alignment of the specified complete type in bits.
Definition: ASTContext.cpp:1919
clang::Type::isIncompleteType
bool isIncompleteType(NamedDecl **Def=nullptr) const
Types are partitioned into 3 broad categories (C99 6.2.5p1): object types, function types,...
Definition: Type.cpp:2217
clang::CastExpr
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3473