1*67e74705SXin Li //=== CastToStructChecker.cpp - Fixed address usage checker ----*- C++ -*--===// 2*67e74705SXin Li // 3*67e74705SXin Li // The LLVM Compiler Infrastructure 4*67e74705SXin Li // 5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source 6*67e74705SXin Li // License. See LICENSE.TXT for details. 7*67e74705SXin Li // 8*67e74705SXin Li //===----------------------------------------------------------------------===// 9*67e74705SXin Li // 10*67e74705SXin Li // This files defines CastToStructChecker, a builtin checker that checks for 11*67e74705SXin Li // cast from non-struct pointer to struct pointer. 12*67e74705SXin Li // This check corresponds to CWE-588. 13*67e74705SXin Li // 14*67e74705SXin Li //===----------------------------------------------------------------------===// 15*67e74705SXin Li 16*67e74705SXin Li #include "ClangSACheckers.h" 17*67e74705SXin Li #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 18*67e74705SXin Li #include "clang/StaticAnalyzer/Core/Checker.h" 19*67e74705SXin Li #include "clang/StaticAnalyzer/Core/CheckerManager.h" 20*67e74705SXin Li #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 21*67e74705SXin Li 22*67e74705SXin Li using namespace clang; 23*67e74705SXin Li using namespace ento; 24*67e74705SXin Li 25*67e74705SXin Li namespace { 26*67e74705SXin Li class CastToStructChecker : public Checker< check::PreStmt<CastExpr> > { 27*67e74705SXin Li mutable std::unique_ptr<BuiltinBug> BT; 28*67e74705SXin Li 29*67e74705SXin Li public: 30*67e74705SXin Li void checkPreStmt(const CastExpr *CE, CheckerContext &C) const; 31*67e74705SXin Li }; 32*67e74705SXin Li } 33*67e74705SXin Li checkPreStmt(const CastExpr * CE,CheckerContext & C) const34*67e74705SXin Livoid CastToStructChecker::checkPreStmt(const CastExpr *CE, 35*67e74705SXin Li CheckerContext &C) const { 36*67e74705SXin Li const Expr *E = CE->getSubExpr(); 37*67e74705SXin Li ASTContext &Ctx = C.getASTContext(); 38*67e74705SXin Li QualType OrigTy = Ctx.getCanonicalType(E->getType()); 39*67e74705SXin Li QualType ToTy = Ctx.getCanonicalType(CE->getType()); 40*67e74705SXin Li 41*67e74705SXin Li const PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr()); 42*67e74705SXin Li const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr()); 43*67e74705SXin Li 44*67e74705SXin Li if (!ToPTy || !OrigPTy) 45*67e74705SXin Li return; 46*67e74705SXin Li 47*67e74705SXin Li QualType OrigPointeeTy = OrigPTy->getPointeeType(); 48*67e74705SXin Li QualType ToPointeeTy = ToPTy->getPointeeType(); 49*67e74705SXin Li 50*67e74705SXin Li if (!ToPointeeTy->isStructureOrClassType()) 51*67e74705SXin Li return; 52*67e74705SXin Li 53*67e74705SXin Li // We allow cast from void*. 54*67e74705SXin Li if (OrigPointeeTy->isVoidType()) 55*67e74705SXin Li return; 56*67e74705SXin Li 57*67e74705SXin Li // Now the cast-to-type is struct pointer, the original type is not void*. 58*67e74705SXin Li if (!OrigPointeeTy->isRecordType()) { 59*67e74705SXin Li if (ExplodedNode *N = C.generateNonFatalErrorNode()) { 60*67e74705SXin Li if (!BT) 61*67e74705SXin Li BT.reset( 62*67e74705SXin Li new BuiltinBug(this, "Cast from non-struct type to struct type", 63*67e74705SXin Li "Casting a non-structure type to a structure type " 64*67e74705SXin Li "and accessing a field can lead to memory access " 65*67e74705SXin Li "errors or data corruption.")); 66*67e74705SXin Li auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N); 67*67e74705SXin Li R->addRange(CE->getSourceRange()); 68*67e74705SXin Li C.emitReport(std::move(R)); 69*67e74705SXin Li } 70*67e74705SXin Li } 71*67e74705SXin Li } 72*67e74705SXin Li registerCastToStructChecker(CheckerManager & mgr)73*67e74705SXin Livoid ento::registerCastToStructChecker(CheckerManager &mgr) { 74*67e74705SXin Li mgr.registerChecker<CastToStructChecker>(); 75*67e74705SXin Li } 76