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