clang  3.7.0
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  if (Left % FlexSize == 0)
86  return true;
87 
88  return false;
89 }
90 
91 void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
92  const Expr *E = CE->getSubExpr();
93  ASTContext &Ctx = C.getASTContext();
94  QualType ToTy = Ctx.getCanonicalType(CE->getType());
95  const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
96 
97  if (!ToPTy)
98  return;
99 
100  QualType ToPointeeTy = ToPTy->getPointeeType();
101 
102  // Only perform the check if 'ToPointeeTy' is a complete type.
103  if (ToPointeeTy->isIncompleteType())
104  return;
105 
106  ProgramStateRef state = C.getState();
107  const MemRegion *R = state->getSVal(E, C.getLocationContext()).getAsRegion();
108  if (!R)
109  return;
110 
111  const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
112  if (!SR)
113  return;
114 
115  SValBuilder &svalBuilder = C.getSValBuilder();
116  SVal extent = SR->getExtent(svalBuilder);
117  const llvm::APSInt *extentInt = svalBuilder.getKnownValue(state, extent);
118  if (!extentInt)
119  return;
120 
121  CharUnits regionSize = CharUnits::fromQuantity(extentInt->getSExtValue());
122  CharUnits typeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy);
123 
124  // Ignore void, and a few other un-sizeable types.
125  if (typeSize.isZero())
126  return;
127 
128  if (regionSize % typeSize == 0)
129  return;
130 
131  if (evenFlexibleArraySize(Ctx, regionSize, typeSize, ToPointeeTy))
132  return;
133 
134  if (ExplodedNode *errorNode = C.generateSink()) {
135  if (!BT)
136  BT.reset(new BuiltinBug(this, "Cast region with wrong size.",
137  "Cast a region whose size is not a multiple"
138  " of the destination type size."));
139  auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), 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 }
bool isNegative() const
isNegative - Test whether the quantity is less than zero.
Definition: CharUnits.h:125
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:77
bool hasFlexibleArrayMember() const
Definition: Decl.h:3279
field_iterator field_begin() const
Definition: Decl.cpp:3629
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:89
Expr * getSubExpr()
Definition: Expr.h:2713
RecordDecl * getDecl() const
Definition: Type.h:3527
bool isIncompleteType(NamedDecl **Def=nullptr) const
Def If non-NULL, and the type refers to some kind of declaration that can be completed (such as a C s...
Definition: Type.cpp:1869
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
field_iterator field_end() const
Definition: Decl.h:3352
ExplodedNode * generateSink(ProgramStateRef State=nullptr, ExplodedNode *Pred=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a sink node. Generating a sink stops exploration of the given path.
const SmallVectorImpl< AnnotatedLine * >::const_iterator End
const ProgramStateRef & getState() const
DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override
getExtent - Returns the size of the region in bytes.
Definition: MemRegion.cpp:220
static bool evenFlexibleArraySize(ASTContext &Ctx, CharUnits RegionSize, CharUnits TypeSize, QualType ToPointeeTy)
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition: CharUnits.h:63
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
CHECKER * registerChecker()
Used to register checkers.
const Type * getTypePtr() const
Definition: Type.h:5016
const ConstantArrayType * getAsConstantArrayType(QualType T) const
Definition: ASTContext.h:2003
const Type * getArrayElementTypeNoTypeQual() const
Definition: Type.cpp:190
QualType getPointeeType() const
Definition: Type.h:2139
QualType getType() const
Definition: Expr.h:125
bool isZero() const
isZero - Test whether the quantity equals zero.
Definition: CharUnits.h:116
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:1855
const T * getAs() const
Definition: Type.h:5555
SValBuilder & getSValBuilder()
virtual const llvm::APSInt * getKnownValue(ProgramStateRef state, SVal val)=0
const LocationContext * getLocationContext() const