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" 15*6a5674ffSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/Checker.h" 168b089064SArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/CheckerManager.h" 178b089064SArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 18f8cbac4bSTed Kremenek #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 198b089064SArgyrios Kyrtzidis #include "clang/AST/CharUnits.h" 20d99bd55aSTed Kremenek 21d99bd55aSTed Kremenek using namespace clang; 22d99bd55aSTed Kremenek using namespace ento; 23d99bd55aSTed Kremenek 24d99bd55aSTed Kremenek namespace { 25*6a5674ffSArgyrios Kyrtzidis class CastSizeChecker : public Checker< check::PreStmt<CastExpr> > { 268b089064SArgyrios Kyrtzidis mutable llvm::OwningPtr<BuiltinBug> BT; 27d99bd55aSTed Kremenek public: 288b089064SArgyrios Kyrtzidis void checkPreStmt(const CastExpr *CE, CheckerContext &C) const; 29d99bd55aSTed Kremenek }; 30d99bd55aSTed Kremenek } 31d99bd55aSTed Kremenek 328b089064SArgyrios Kyrtzidis void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const { 33d99bd55aSTed Kremenek const Expr *E = CE->getSubExpr(); 34d99bd55aSTed Kremenek ASTContext &Ctx = C.getASTContext(); 35d99bd55aSTed Kremenek QualType ToTy = Ctx.getCanonicalType(CE->getType()); 36424cec97SJohn McCall const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr()); 37d99bd55aSTed Kremenek 38d99bd55aSTed Kremenek if (!ToPTy) 39d99bd55aSTed Kremenek return; 40d99bd55aSTed Kremenek 41d99bd55aSTed Kremenek QualType ToPointeeTy = ToPTy->getPointeeType(); 42d99bd55aSTed Kremenek 43d99bd55aSTed Kremenek // Only perform the check if 'ToPointeeTy' is a complete type. 44d99bd55aSTed Kremenek if (ToPointeeTy->isIncompleteType()) 45d99bd55aSTed Kremenek return; 46d99bd55aSTed Kremenek 47d99bd55aSTed Kremenek const GRState *state = C.getState(); 48d99bd55aSTed Kremenek const MemRegion *R = state->getSVal(E).getAsRegion(); 49d99bd55aSTed Kremenek if (R == 0) 50d99bd55aSTed Kremenek return; 51d99bd55aSTed Kremenek 52d99bd55aSTed Kremenek const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R); 53d99bd55aSTed Kremenek if (SR == 0) 54d99bd55aSTed Kremenek return; 55d99bd55aSTed Kremenek 56d99bd55aSTed Kremenek SValBuilder &svalBuilder = C.getSValBuilder(); 57d99bd55aSTed Kremenek SVal extent = SR->getExtent(svalBuilder); 58d99bd55aSTed Kremenek const llvm::APSInt *extentInt = svalBuilder.getKnownValue(state, extent); 59d99bd55aSTed Kremenek if (!extentInt) 60d99bd55aSTed Kremenek return; 61d99bd55aSTed Kremenek 62d99bd55aSTed Kremenek CharUnits regionSize = CharUnits::fromQuantity(extentInt->getSExtValue()); 63d99bd55aSTed Kremenek CharUnits typeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy); 64d99bd55aSTed Kremenek 65d99bd55aSTed Kremenek // Ignore void, and a few other un-sizeable types. 66d99bd55aSTed Kremenek if (typeSize.isZero()) 67d99bd55aSTed Kremenek return; 68d99bd55aSTed Kremenek 69d99bd55aSTed Kremenek if (regionSize % typeSize != 0) { 70d99bd55aSTed Kremenek if (ExplodedNode *errorNode = C.generateSink()) { 71d99bd55aSTed Kremenek if (!BT) 728b089064SArgyrios Kyrtzidis BT.reset(new BuiltinBug("Cast region with wrong size.", 73d99bd55aSTed Kremenek "Cast a region whose size is not a multiple of the" 748b089064SArgyrios Kyrtzidis " destination type size.")); 75d99bd55aSTed Kremenek RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), 76d99bd55aSTed Kremenek errorNode); 77d99bd55aSTed Kremenek R->addRange(CE->getSourceRange()); 78d99bd55aSTed Kremenek C.EmitReport(R); 79d99bd55aSTed Kremenek } 80d99bd55aSTed Kremenek } 81d99bd55aSTed Kremenek } 82d99bd55aSTed Kremenek 83d99bd55aSTed Kremenek 848b089064SArgyrios Kyrtzidis void ento::registerCastSizeChecker(CheckerManager &mgr) { 858b089064SArgyrios Kyrtzidis mgr.registerChecker<CastSizeChecker>(); 86d99bd55aSTed Kremenek } 87