CastToStructChecker.cpp revision 23ade507cecd24b03f5e4b5ebaea48eb38060262
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/BugReporter/BugType.h"
18#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
19
20using namespace clang;
21using namespace ento;
22
23namespace {
24class CastToStructChecker
25  : public CheckerVisitor<CastToStructChecker> {
26  BuiltinBug *BT;
27public:
28  CastToStructChecker() : BT(0) {}
29  static void *getTag();
30  void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
31};
32}
33
34void *CastToStructChecker::getTag() {
35  static int x;
36  return &x;
37}
38
39void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
40                                           const CastExpr *CE) {
41  const Expr *E = CE->getSubExpr();
42  ASTContext &Ctx = C.getASTContext();
43  QualType OrigTy = Ctx.getCanonicalType(E->getType());
44  QualType ToTy = Ctx.getCanonicalType(CE->getType());
45
46  const PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr());
47  const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
48
49  if (!ToPTy || !OrigPTy)
50    return;
51
52  QualType OrigPointeeTy = OrigPTy->getPointeeType();
53  QualType ToPointeeTy = ToPTy->getPointeeType();
54
55  if (!ToPointeeTy->isStructureOrClassType())
56    return;
57
58  // We allow cast from void*.
59  if (OrigPointeeTy->isVoidType())
60    return;
61
62  // Now the cast-to-type is struct pointer, the original type is not void*.
63  if (!OrigPointeeTy->isRecordType()) {
64    if (ExplodedNode *N = C.generateNode()) {
65      if (!BT)
66        BT = new BuiltinBug("Cast from non-struct type to struct type",
67                            "Casting a non-structure type to a structure type "
68                            "and accessing a field can lead to memory access "
69                            "errors or data corruption.");
70      RangedBugReport *R = new RangedBugReport(*BT,BT->getDescription(), N);
71      R->addRange(CE->getSourceRange());
72      C.EmitReport(R);
73    }
74  }
75}
76
77void ento::registerCastToStructChecker(ExprEngine &Eng) {
78  Eng.registerCheck(new CastToStructChecker());
79}
80