clang API Documentation
00001 //=== CastSizeChecker.cpp ---------------------------------------*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // CastSizeChecker checks when casting a malloc'ed symbolic region to type T, 00011 // whether the size of the symbolic region is a multiple of the size of T. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 #include "ClangSACheckers.h" 00015 #include "clang/StaticAnalyzer/Core/Checker.h" 00016 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00017 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00018 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00019 #include "clang/AST/CharUnits.h" 00020 00021 using namespace clang; 00022 using namespace ento; 00023 00024 namespace { 00025 class CastSizeChecker : public Checker< check::PreStmt<CastExpr> > { 00026 mutable OwningPtr<BuiltinBug> BT; 00027 public: 00028 void checkPreStmt(const CastExpr *CE, CheckerContext &C) const; 00029 }; 00030 } 00031 00032 void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const { 00033 const Expr *E = CE->getSubExpr(); 00034 ASTContext &Ctx = C.getASTContext(); 00035 QualType ToTy = Ctx.getCanonicalType(CE->getType()); 00036 const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr()); 00037 00038 if (!ToPTy) 00039 return; 00040 00041 QualType ToPointeeTy = ToPTy->getPointeeType(); 00042 00043 // Only perform the check if 'ToPointeeTy' is a complete type. 00044 if (ToPointeeTy->isIncompleteType()) 00045 return; 00046 00047 ProgramStateRef state = C.getState(); 00048 const MemRegion *R = state->getSVal(E, C.getLocationContext()).getAsRegion(); 00049 if (R == 0) 00050 return; 00051 00052 const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R); 00053 if (SR == 0) 00054 return; 00055 00056 SValBuilder &svalBuilder = C.getSValBuilder(); 00057 SVal extent = SR->getExtent(svalBuilder); 00058 const llvm::APSInt *extentInt = svalBuilder.getKnownValue(state, extent); 00059 if (!extentInt) 00060 return; 00061 00062 CharUnits regionSize = CharUnits::fromQuantity(extentInt->getSExtValue()); 00063 CharUnits typeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy); 00064 00065 // Ignore void, and a few other un-sizeable types. 00066 if (typeSize.isZero()) 00067 return; 00068 00069 if (regionSize % typeSize != 0) { 00070 if (ExplodedNode *errorNode = C.generateSink()) { 00071 if (!BT) 00072 BT.reset(new BuiltinBug("Cast region with wrong size.", 00073 "Cast a region whose size is not a multiple of the" 00074 " destination type size.")); 00075 BugReport *R = new BugReport(*BT, BT->getDescription(), 00076 errorNode); 00077 R->addRange(CE->getSourceRange()); 00078 C.EmitReport(R); 00079 } 00080 } 00081 } 00082 00083 00084 void ento::registerCastSizeChecker(CheckerManager &mgr) { 00085 mgr.registerChecker<CastSizeChecker>(); 00086 }