clang API Documentation
00001 //=== CastToStructChecker.cpp - Fixed address usage checker ----*- 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 // This files defines CastToStructChecker, a builtin checker that checks for 00011 // cast from non-struct pointer to struct pointer. 00012 // This check corresponds to CWE-588. 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #include "ClangSACheckers.h" 00017 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00018 #include "clang/StaticAnalyzer/Core/Checker.h" 00019 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00020 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00021 00022 using namespace clang; 00023 using namespace ento; 00024 00025 namespace { 00026 class CastToStructChecker : public Checker< check::PreStmt<CastExpr> > { 00027 mutable std::unique_ptr<BuiltinBug> BT; 00028 00029 public: 00030 void checkPreStmt(const CastExpr *CE, CheckerContext &C) const; 00031 }; 00032 } 00033 00034 void CastToStructChecker::checkPreStmt(const CastExpr *CE, 00035 CheckerContext &C) const { 00036 const Expr *E = CE->getSubExpr(); 00037 ASTContext &Ctx = C.getASTContext(); 00038 QualType OrigTy = Ctx.getCanonicalType(E->getType()); 00039 QualType ToTy = Ctx.getCanonicalType(CE->getType()); 00040 00041 const PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr()); 00042 const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr()); 00043 00044 if (!ToPTy || !OrigPTy) 00045 return; 00046 00047 QualType OrigPointeeTy = OrigPTy->getPointeeType(); 00048 QualType ToPointeeTy = ToPTy->getPointeeType(); 00049 00050 if (!ToPointeeTy->isStructureOrClassType()) 00051 return; 00052 00053 // We allow cast from void*. 00054 if (OrigPointeeTy->isVoidType()) 00055 return; 00056 00057 // Now the cast-to-type is struct pointer, the original type is not void*. 00058 if (!OrigPointeeTy->isRecordType()) { 00059 if (ExplodedNode *N = C.addTransition()) { 00060 if (!BT) 00061 BT.reset( 00062 new BuiltinBug(this, "Cast from non-struct type to struct type", 00063 "Casting a non-structure type to a structure type " 00064 "and accessing a field can lead to memory access " 00065 "errors or data corruption.")); 00066 BugReport *R = new BugReport(*BT,BT->getDescription(), N); 00067 R->addRange(CE->getSourceRange()); 00068 C.emitReport(R); 00069 } 00070 } 00071 } 00072 00073 void ento::registerCastToStructChecker(CheckerManager &mgr) { 00074 mgr.registerChecker<CastToStructChecker>(); 00075 }