clang  15.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:3962
clang::ASTContext::getTypeSizeInChars
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
Definition: ASTContext.cpp:2471
clang::RecordDecl::field_begin
field_iterator field_begin() const
Definition: Decl.cpp:4683
DynamicExtent.h
clang::DeclContext::specific_decl_iterator
specific_decl_iterator - Iterates over a subrange of declarations stored in a DeclContext,...
Definition: DeclBase.h:2177
clang::ConstantArrayType
Represents the canonical version of C arrays with a specified constant size.
Definition: Type.h:3001
clang::CastExpr::getSubExpr
Expr * getSubExpr()
Definition: Expr.h:3525
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:731
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:55
clang::FieldDecl
Represents a member of a struct/union/class.
Definition: Decl.h:2862
End
SourceLocation End
Definition: USRLocFinder.cpp:167
clang::Type
The base class of the type hierarchy.
Definition: Type.h:1556
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:4706
BuiltinCheckerRegistration.h
clang::ASTContext::getAsConstantArrayType
const ConstantArrayType * getAsConstantArrayType(QualType T) const
Definition: ASTContext.h:2690
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:208
clang::Type::getAs
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:7302
clang::ASTContext::getCanonicalType
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:2508
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:4137
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:78
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:2712
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:6559
clang::RecordType::getDecl
RecordDecl * getDecl() const
Definition: Type.h:4716
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:2722
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:2234
clang::CastExpr
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3475
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:3908