clang  6.0.0svn
CastSizeChecker.cpp
Go to the documentation of this file.
1 //=== CastSizeChecker.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 // CastSizeChecker checks when casting a malloc'ed symbolic region to type T,
11 // whether the size of the symbolic region is a multiple of the size of T.
12 //
13 //===----------------------------------------------------------------------===//
14 #include "ClangSACheckers.h"
15 #include "clang/AST/CharUnits.h"
20 
21 using namespace clang;
22 using namespace ento;
23 
24 namespace {
25 class CastSizeChecker : public Checker< check::PreStmt<CastExpr> > {
26  mutable std::unique_ptr<BuiltinBug> BT;
27 
28 public:
29  void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
30 };
31 }
32 
33 /// Check if we are casting to a struct with a flexible array at the end.
34 /// \code
35 /// struct foo {
36 /// size_t len;
37 /// struct bar data[];
38 /// };
39 /// \endcode
40 /// or
41 /// \code
42 /// struct foo {
43 /// size_t len;
44 /// struct bar data[0];
45 /// }
46 /// \endcode
47 /// In these cases it is also valid to allocate size of struct foo + a multiple
48 /// of struct bar.
49 static bool evenFlexibleArraySize(ASTContext &Ctx, CharUnits RegionSize,
50  CharUnits TypeSize, QualType ToPointeeTy) {
51  const RecordType *RT = ToPointeeTy->getAs<RecordType>();
52  if (!RT)
53  return false;
54 
55  const RecordDecl *RD = RT->getDecl();
58  const FieldDecl *Last = nullptr;
59  for (; Iter != End; ++Iter)
60  Last = *Iter;
61  assert(Last && "empty structs should already be handled");
62 
63  const Type *ElemType = Last->getType()->getArrayElementTypeNoTypeQual();
64  CharUnits FlexSize;
65  if (const ConstantArrayType *ArrayTy =
66  Ctx.getAsConstantArrayType(Last->getType())) {
67  FlexSize = Ctx.getTypeSizeInChars(ElemType);
68  if (ArrayTy->getSize() == 1 && TypeSize > FlexSize)
69  TypeSize -= FlexSize;
70  else if (ArrayTy->getSize() != 0)
71  return false;
72  } else if (RD->hasFlexibleArrayMember()) {
73  FlexSize = Ctx.getTypeSizeInChars(ElemType);
74  } else {
75  return false;
76  }
77 
78  if (FlexSize.isZero())
79  return false;
80 
81  CharUnits Left = RegionSize - TypeSize;
82  if (Left.isNegative())
83  return false;
84 
85  return Left % FlexSize == 0;
86 }
87 
88 void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
89  const Expr *E = CE->getSubExpr();
90  ASTContext &Ctx = C.getASTContext();
91  QualType ToTy = Ctx.getCanonicalType(CE->getType());
92  const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
93 
94  if (!ToPTy)
95  return;
96 
97  QualType ToPointeeTy = ToPTy->getPointeeType();
98 
99  // Only perform the check if 'ToPointeeTy' is a complete type.
100  if (ToPointeeTy->isIncompleteType())
101  return;
102 
104  const MemRegion *R = state->getSVal(E, C.getLocationContext()).getAsRegion();
105  if (!R)
106  return;
107 
108  const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
109  if (!SR)
110  return;
111 
112  SValBuilder &svalBuilder = C.getSValBuilder();
113  SVal extent = SR->getExtent(svalBuilder);
114  const llvm::APSInt *extentInt = svalBuilder.getKnownValue(state, extent);
115  if (!extentInt)
116  return;
117 
118  CharUnits regionSize = CharUnits::fromQuantity(extentInt->getSExtValue());
119  CharUnits typeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy);
120 
121  // Ignore void, and a few other un-sizeable types.
122  if (typeSize.isZero())
123  return;
124 
125  if (regionSize % typeSize == 0)
126  return;
127 
128  if (evenFlexibleArraySize(Ctx, regionSize, typeSize, ToPointeeTy))
129  return;
130 
131  if (ExplodedNode *errorNode = C.generateErrorNode()) {
132  if (!BT)
133  BT.reset(new BuiltinBug(this, "Cast region with wrong size.",
134  "Cast a region whose size is not a multiple"
135  " of the destination type size."));
136  auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), errorNode);
137  R->addRange(CE->getSourceRange());
138  C.emitReport(std::move(R));
139  }
140 }
141 
142 void ento::registerCastSizeChecker(CheckerManager &mgr) {
143  // PR31226: C++ is more complicated than what this checker currently supports.
144  // There are derived-to-base casts, there are different rules for 0-size
145  // structures, no flexible arrays, etc.
146  // FIXME: Disabled on C++ for now.
147  if (!mgr.getLangOpts().CPlusPlus)
148  mgr.registerChecker<CastSizeChecker>();
149 }
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
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:79
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
The base class of the type hierarchy.
Definition: Type.h:1353
bool isZero() const
isZero - Test whether the quantity equals zero.
Definition: CharUnits.h:116
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:6307
RecordDecl - Represents a struct/union/class.
Definition: Decl.h:3482
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:149
FieldDecl - An instance of this class is created by Sema::ActOnField to represent a member of a struc...
Definition: Decl.h:2461
Expr * getSubExpr()
Definition: Expr.h:2761
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
CharUnits - This is an opaque type for sizes expressed in character units.
Definition: CharUnits.h:38
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:5720
field_iterator field_begin() const
Definition: Decl.cpp:3937
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:2710
bool isNegative() const
isNegative - Test whether the quantity is less than zero.
Definition: CharUnits.h:125
SymbolicRegion - A special, "non-concrete" region.
Definition: MemRegion.h:742
Expr - This represents one expression.
Definition: Expr.h:106
SourceLocation End
DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override
getExtent - Returns the size of the region in bytes.
Definition: MemRegion.cpp:176
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.
field_iterator field_end() const
Definition: Decl.h:3616
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition: CharUnits.h:63
QualType getType() const
Definition: Expr.h:128
RecordDecl * getDecl() const
Definition: Type.h:3988
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
CHECKER * registerChecker()
Used to register checkers.
const ConstantArrayType * getAsConstantArrayType(QualType T) const
Definition: ASTContext.h:2321
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:63
bool hasFlexibleArrayMember() const
Definition: Decl.h:3535
Dataflow Directional Tag Classes.
const Type * getArrayElementTypeNoTypeQual() const
If this is an array type, return the element type of the array, potentially with type qualifiers miss...
Definition: Type.cpp:229
specific_decl_iterator - Iterates over a subrange of declarations stored in a DeclContext, providing only those that are of type SpecificDecl (or a class derived from it).
Definition: DeclBase.h:1596
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:3978
const ProgramStateRef & getState() const
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
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:265
SValBuilder & getSValBuilder()
virtual const llvm::APSInt * getKnownValue(ProgramStateRef state, SVal val)=0
Evaluates a given SVal.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
const LangOptions & getLangOpts() const
const LocationContext * getLocationContext() const
Represents the canonical version of C arrays with a specified constant size.
Definition: Type.h:2620