1d99bd55aSTed Kremenek //=== CastSizeChecker.cpp ---------------------------------------*- C++ -*-===// 2d99bd55aSTed Kremenek // 3d99bd55aSTed Kremenek // The LLVM Compiler Infrastructure 4d99bd55aSTed Kremenek // 5d99bd55aSTed Kremenek // This file is distributed under the University of Illinois Open Source 6d99bd55aSTed Kremenek // License. See LICENSE.TXT for details. 7d99bd55aSTed Kremenek // 8d99bd55aSTed Kremenek //===----------------------------------------------------------------------===// 9d99bd55aSTed Kremenek // 10d99bd55aSTed Kremenek // CastSizeChecker checks when casting a malloc'ed symbolic region to type T, 11d99bd55aSTed Kremenek // whether the size of the symbolic region is a multiple of the size of T. 12d99bd55aSTed Kremenek // 13d99bd55aSTed Kremenek //===----------------------------------------------------------------------===// 148b089064SArgyrios Kyrtzidis #include "ClangSACheckers.h" 153a02247dSChandler Carruth #include "clang/AST/CharUnits.h" 163a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 176a5674ffSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/Checker.h" 188b089064SArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/CheckerManager.h" 198b089064SArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 20d99bd55aSTed Kremenek 21d99bd55aSTed Kremenek using namespace clang; 22d99bd55aSTed Kremenek using namespace ento; 23d99bd55aSTed Kremenek 24d99bd55aSTed Kremenek namespace { 256a5674ffSArgyrios Kyrtzidis class CastSizeChecker : public Checker< check::PreStmt<CastExpr> > { 26e2778999SDylan Noblesmith mutable OwningPtr<BuiltinBug> BT; 27d99bd55aSTed Kremenek public: 288b089064SArgyrios Kyrtzidis void checkPreStmt(const CastExpr *CE, CheckerContext &C) const; 29d99bd55aSTed Kremenek }; 30d99bd55aSTed Kremenek } 31d99bd55aSTed Kremenek 32*97d2c9caSJordan Rose /// Check if we are casting to a struct with a flexible array at the end. 33*97d2c9caSJordan Rose /// \code 34*97d2c9caSJordan Rose /// struct foo { 35*97d2c9caSJordan Rose /// size_t len; 36*97d2c9caSJordan Rose /// struct bar data[]; 37*97d2c9caSJordan Rose /// }; 38*97d2c9caSJordan Rose /// \endcode 39*97d2c9caSJordan Rose /// or 40*97d2c9caSJordan Rose /// \code 41*97d2c9caSJordan Rose /// struct foo { 42*97d2c9caSJordan Rose /// size_t len; 43*97d2c9caSJordan Rose /// struct bar data[0]; 44*97d2c9caSJordan Rose /// } 45*97d2c9caSJordan Rose /// \endcode 46*97d2c9caSJordan Rose /// In these cases it is also valid to allocate size of struct foo + a multiple 47*97d2c9caSJordan Rose /// of struct bar. 48*97d2c9caSJordan Rose static bool evenFlexibleArraySize(ASTContext &Ctx, CharUnits RegionSize, 49*97d2c9caSJordan Rose CharUnits TypeSize, QualType ToPointeeTy) { 50*97d2c9caSJordan Rose const RecordType *RT = ToPointeeTy->getAs<RecordType>(); 51*97d2c9caSJordan Rose if (!RT) 52*97d2c9caSJordan Rose return false; 53*97d2c9caSJordan Rose 54*97d2c9caSJordan Rose const RecordDecl *RD = RT->getDecl(); 55*97d2c9caSJordan Rose RecordDecl::field_iterator Iter(RD->field_begin()); 56*97d2c9caSJordan Rose RecordDecl::field_iterator End(RD->field_end()); 57*97d2c9caSJordan Rose const FieldDecl *Last = 0; 58*97d2c9caSJordan Rose for (; Iter != End; ++Iter) 59*97d2c9caSJordan Rose Last = *Iter; 60*97d2c9caSJordan Rose assert(Last && "empty structs should already be handled"); 61*97d2c9caSJordan Rose 62*97d2c9caSJordan Rose const Type *ElemType = Last->getType()->getArrayElementTypeNoTypeQual(); 63*97d2c9caSJordan Rose CharUnits FlexSize; 64*97d2c9caSJordan Rose if (const ConstantArrayType *ArrayTy = 65*97d2c9caSJordan Rose Ctx.getAsConstantArrayType(Last->getType())) { 66*97d2c9caSJordan Rose FlexSize = Ctx.getTypeSizeInChars(ElemType); 67*97d2c9caSJordan Rose if (ArrayTy->getSize() == 1 && TypeSize > FlexSize) 68*97d2c9caSJordan Rose TypeSize -= FlexSize; 69*97d2c9caSJordan Rose else if (ArrayTy->getSize() != 0) 70*97d2c9caSJordan Rose return false; 71*97d2c9caSJordan Rose } else if (RD->hasFlexibleArrayMember()) { 72*97d2c9caSJordan Rose FlexSize = Ctx.getTypeSizeInChars(ElemType); 73*97d2c9caSJordan Rose } else { 74*97d2c9caSJordan Rose return false; 75*97d2c9caSJordan Rose } 76*97d2c9caSJordan Rose 77*97d2c9caSJordan Rose if (FlexSize.isZero()) 78*97d2c9caSJordan Rose return false; 79*97d2c9caSJordan Rose 80*97d2c9caSJordan Rose CharUnits Left = RegionSize - TypeSize; 81*97d2c9caSJordan Rose if (Left.isNegative()) 82*97d2c9caSJordan Rose return false; 83*97d2c9caSJordan Rose 84*97d2c9caSJordan Rose if (Left % FlexSize == 0) 85*97d2c9caSJordan Rose return true; 86*97d2c9caSJordan Rose 87*97d2c9caSJordan Rose return false; 88*97d2c9caSJordan Rose } 89*97d2c9caSJordan Rose 908b089064SArgyrios Kyrtzidis void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const { 91d99bd55aSTed Kremenek const Expr *E = CE->getSubExpr(); 92d99bd55aSTed Kremenek ASTContext &Ctx = C.getASTContext(); 93d99bd55aSTed Kremenek QualType ToTy = Ctx.getCanonicalType(CE->getType()); 94424cec97SJohn McCall const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr()); 95d99bd55aSTed Kremenek 96d99bd55aSTed Kremenek if (!ToPTy) 97d99bd55aSTed Kremenek return; 98d99bd55aSTed Kremenek 99d99bd55aSTed Kremenek QualType ToPointeeTy = ToPTy->getPointeeType(); 100d99bd55aSTed Kremenek 101d99bd55aSTed Kremenek // Only perform the check if 'ToPointeeTy' is a complete type. 102d99bd55aSTed Kremenek if (ToPointeeTy->isIncompleteType()) 103d99bd55aSTed Kremenek return; 104d99bd55aSTed Kremenek 10549b1e38eSTed Kremenek ProgramStateRef state = C.getState(); 106632e3b7eSTed Kremenek const MemRegion *R = state->getSVal(E, C.getLocationContext()).getAsRegion(); 107d99bd55aSTed Kremenek if (R == 0) 108d99bd55aSTed Kremenek return; 109d99bd55aSTed Kremenek 110d99bd55aSTed Kremenek const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R); 111d99bd55aSTed Kremenek if (SR == 0) 112d99bd55aSTed Kremenek return; 113d99bd55aSTed Kremenek 114d99bd55aSTed Kremenek SValBuilder &svalBuilder = C.getSValBuilder(); 115d99bd55aSTed Kremenek SVal extent = SR->getExtent(svalBuilder); 116d99bd55aSTed Kremenek const llvm::APSInt *extentInt = svalBuilder.getKnownValue(state, extent); 117d99bd55aSTed Kremenek if (!extentInt) 118d99bd55aSTed Kremenek return; 119d99bd55aSTed Kremenek 120d99bd55aSTed Kremenek CharUnits regionSize = CharUnits::fromQuantity(extentInt->getSExtValue()); 121d99bd55aSTed Kremenek CharUnits typeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy); 122d99bd55aSTed Kremenek 123d99bd55aSTed Kremenek // Ignore void, and a few other un-sizeable types. 124d99bd55aSTed Kremenek if (typeSize.isZero()) 125d99bd55aSTed Kremenek return; 126d99bd55aSTed Kremenek 127*97d2c9caSJordan Rose if (regionSize % typeSize == 0) 128*97d2c9caSJordan Rose return; 129*97d2c9caSJordan Rose 130*97d2c9caSJordan Rose if (evenFlexibleArraySize(Ctx, regionSize, typeSize, ToPointeeTy)) 131*97d2c9caSJordan Rose return; 132*97d2c9caSJordan Rose 133d99bd55aSTed Kremenek if (ExplodedNode *errorNode = C.generateSink()) { 134d99bd55aSTed Kremenek if (!BT) 135*97d2c9caSJordan Rose BT.reset(new BuiltinBug(this, "Cast region with wrong size.", 136*97d2c9caSJordan Rose "Cast a region whose size is not a multiple" 137*97d2c9caSJordan Rose " of the destination type size.")); 138*97d2c9caSJordan Rose BugReport *R = new BugReport(*BT, BT->getDescription(), errorNode); 139d99bd55aSTed Kremenek R->addRange(CE->getSourceRange()); 140e10d5a76SJordan Rose C.emitReport(R); 141d99bd55aSTed Kremenek } 142d99bd55aSTed Kremenek } 143d99bd55aSTed Kremenek 1448b089064SArgyrios Kyrtzidis void ento::registerCastSizeChecker(CheckerManager &mgr) { 1458b089064SArgyrios Kyrtzidis mgr.registerChecker<CastSizeChecker>(); 146d99bd55aSTed Kremenek } 147