clang API Documentation

CastToStructChecker.cpp
Go to the documentation of this file.
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 }