clang  14.0.0git
CastSizeChecker.cpp
Go to the documentation of this file.
1 //=== CastSizeChecker.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 // CastSizeChecker checks when casting a malloc'ed symbolic region to type T,
10 // whether the size of the symbolic region is a multiple of the size of T.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/AST/CharUnits.h"
21 
22 using namespace clang;
23 using namespace ento;
24 
25 namespace {
26 class CastSizeChecker : public Checker< check::PreStmt<CastExpr> > {
27  mutable std::unique_ptr<BuiltinBug> BT;
28 
29 public:
30  void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
31 };
32 }
33 
34 /// Check if we are casting to a struct with a flexible array at the end.
35 /// \code
36 /// struct foo {
37 /// size_t len;
38 /// struct bar data[];
39 /// };
40 /// \endcode
41 /// or
42 /// \code
43 /// struct foo {
44 /// size_t len;
45 /// struct bar data[0];
46 /// }
47 /// \endcode
48 /// In these cases it is also valid to allocate size of struct foo + a multiple
49 /// of struct bar.
50 static bool evenFlexibleArraySize(ASTContext &Ctx, CharUnits RegionSize,
51  CharUnits TypeSize, QualType ToPointeeTy) {
52  const RecordType *RT = ToPointeeTy->getAs<RecordType>();
53  if (!RT)
54  return false;
55 
56  const RecordDecl *RD = RT->getDecl();
59  const FieldDecl *Last = nullptr;
60  for (; Iter != End; ++Iter)
61  Last = *Iter;
62  assert(Last && "empty structs should already be handled");
63 
64  const Type *ElemType = Last->getType()->getArrayElementTypeNoTypeQual();
65  CharUnits FlexSize;
66  if (const ConstantArrayType *ArrayTy =
67  Ctx.getAsConstantArrayType(Last->getType())) {
68  FlexSize = Ctx.getTypeSizeInChars(ElemType);
69  if (ArrayTy->getSize() == 1 && TypeSize > FlexSize)
70  TypeSize -= FlexSize;
71  else if (ArrayTy->getSize() != 0)
72  return false;
73  } else if (RD->hasFlexibleArrayMember()) {
74  FlexSize = Ctx.getTypeSizeInChars(ElemType);
75  } else {
76  return false;
77  }
78 
79  if (FlexSize.isZero())
80  return false;
81 
82  CharUnits Left = RegionSize - TypeSize;
83  if (Left.isNegative())
84  return false;
85 
86  return Left % FlexSize == 0;
87 }
88 
89 void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
90  const Expr *E = CE->getSubExpr();
91  ASTContext &Ctx = C.getASTContext();
92  QualType ToTy = Ctx.getCanonicalType(CE->getType());
93  const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
94 
95  if (!ToPTy)
96  return;
97 
98  QualType ToPointeeTy = ToPTy->getPointeeType();
99 
100  // Only perform the check if 'ToPointeeTy' is a complete type.
101  if (ToPointeeTy->isIncompleteType())
102  return;
103 
104  ProgramStateRef state = C.getState();
105  const MemRegion *R = C.getSVal(E).getAsRegion();
106  if (!R)
107  return;
108 
109  const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
110  if (!SR)
111  return;
112 
113  SValBuilder &svalBuilder = C.getSValBuilder();
114 
115  DefinedOrUnknownSVal Size = getDynamicExtent(state, SR, svalBuilder);
116  const llvm::APSInt *SizeInt = svalBuilder.getKnownValue(state, Size);
117  if (!SizeInt)
118  return;
119 
120  CharUnits regionSize = CharUnits::fromQuantity(SizeInt->getZExtValue());
121  CharUnits typeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy);
122 
123  // Ignore void, and a few other un-sizeable types.
124  if (typeSize.isZero())
125  return;
126 
127  if (regionSize % typeSize == 0)
128  return;
129 
130  if (evenFlexibleArraySize(Ctx, regionSize, typeSize, ToPointeeTy))
131  return;
132 
133  if (ExplodedNode *errorNode = C.generateErrorNode()) {
134  if (!BT)
135  BT.reset(new BuiltinBug(this, "Cast region with wrong size.",
136  "Cast a region whose size is not a multiple"
137  " of the destination type size."));
138  auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(),
139  errorNode);
140  R->addRange(CE->getSourceRange());
141  C.emitReport(std::move(R));
142  }
143 }
144 
145 void ento::registerCastSizeChecker(CheckerManager &mgr) {
146  mgr.registerChecker<CastSizeChecker>();
147 }
148 
149 bool ento::shouldRegisterCastSizeChecker(const CheckerManager &mgr) {
150  // PR31226: C++ is more complicated than what this checker currently supports.
151  // There are derived-to-base casts, there are different rules for 0-size
152  // structures, no flexible arrays, etc.
153  // FIXME: Disabled on C++ for now.
154  const LangOptions &LO = mgr.getLangOpts();
155  return !LO.CPlusPlus;
156 }
clang::RecordDecl::hasFlexibleArrayMember
bool hasFlexibleArrayMember() const
Definition: Decl.h:3913
clang::ASTContext::getTypeSizeInChars
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
Definition: ASTContext.cpp:2450
clang::RecordDecl::field_begin
field_iterator field_begin() const
Definition: Decl.cpp:4605
DynamicExtent.h
clang::DeclContext::specific_decl_iterator
specific_decl_iterator - Iterates over a subrange of declarations stored in a DeclContext,...
Definition: DeclBase.h:2135
clang::ConstantArrayType
Represents the canonical version of C arrays with a specified constant size.
Definition: Type.h:2929
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::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:673
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:54
clang::FieldDecl
Represents a member of a struct/union/class.
Definition: Decl.h:2835
End
SourceLocation End
Definition: USRLocFinder.cpp:167
clang::Type
The base class of the type hierarchy.
Definition: Type.h:1490
APSInt
llvm::APSInt APSInt
Definition: ByteCodeEmitter.cpp:19
clang::RecordType
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:4613
BuiltinCheckerRegistration.h
clang::ASTContext::getAsConstantArrayType
const ConstantArrayType * getAsConstantArrayType(QualType T) const
Definition: ASTContext.h:2629
clang::CharUnits::fromQuantity
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition: CharUnits.h:63
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::Type::getAs
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:7162
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
clang::CharUnits::isNegative
bool isNegative() const
isNegative - Test whether the quantity is less than zero.
Definition: CharUnits.h:125
state
and static some checkers Checker The latter are built on top of the former via the Checker and CheckerVisitor and attempts to isolate them from much of the gore of the internal analysis the analyzer is basically a source code simulator that traces out possible paths of execution The state of the and the combination of state and program point is a node in an exploded which has the entry program point and initial state
Definition: README.txt:30
CharUnits.h
clang::syntax::NodeRole::Size
@ Size
BugType.h
clang::CharUnits::isZero
bool isZero() const
isZero - Test whether the quantity equals zero.
Definition: CharUnits.h:116
clang::RecordDecl::field_end
field_iterator field_end() const
Definition: Decl.h:4082
CheckerContext.h
clang::LangOptions
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:58
clang::ento::getDynamicExtent
DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State, const MemRegion *MR, SValBuilder &SVB)
Checker.h
clang::PointerType
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:2640
clang
Definition: CalledOnceCheck.h:17
clang::ComparisonCategoryType::Last
@ Last
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:6425
clang::RecordType::getDecl
RecordDecl * getDecl() const
Definition: Type.h:4623
clang::CharUnits
CharUnits - This is an opaque type for sizes expressed in character units.
Definition: CharUnits.h:38
clang::PointerType::getPointeeType
QualType getPointeeType() const
Definition: Type.h:2650
clang::Expr
This represents one expression.
Definition: Expr.h:109
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:2210
clang::CastExpr
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3473
evenFlexibleArraySize
static bool evenFlexibleArraySize(ASTContext &Ctx, CharUnits RegionSize, CharUnits TypeSize, QualType ToPointeeTy)
Check if we are casting to a struct with a flexible array at the end.
Definition: CastSizeChecker.cpp:50
clang::RecordDecl
Represents a struct/union/class.
Definition: Decl.h:3859