1218887Sdim//=== CastSizeChecker.cpp ---------------------------------------*- C++ -*-===//
2218887Sdim//
3218887Sdim//                     The LLVM Compiler Infrastructure
4218887Sdim//
5218887Sdim// This file is distributed under the University of Illinois Open Source
6218887Sdim// License. See LICENSE.TXT for details.
7218887Sdim//
8218887Sdim//===----------------------------------------------------------------------===//
9218887Sdim//
10218887Sdim// CastSizeChecker checks when casting a malloc'ed symbolic region to type T,
11218887Sdim// whether the size of the symbolic region is a multiple of the size of T.
12218887Sdim//
13218887Sdim//===----------------------------------------------------------------------===//
14219077Sdim#include "ClangSACheckers.h"
15249423Sdim#include "clang/AST/CharUnits.h"
16249423Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17221345Sdim#include "clang/StaticAnalyzer/Core/Checker.h"
18219077Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19219077Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20218887Sdim
21218887Sdimusing namespace clang;
22218887Sdimusing namespace ento;
23218887Sdim
24218887Sdimnamespace {
25221345Sdimclass CastSizeChecker : public Checker< check::PreStmt<CastExpr> > {
26234353Sdim  mutable OwningPtr<BuiltinBug> BT;
27218887Sdimpublic:
28219077Sdim  void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
29218887Sdim};
30218887Sdim}
31218887Sdim
32219077Sdimvoid CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
33218887Sdim  const Expr *E = CE->getSubExpr();
34218887Sdim  ASTContext &Ctx = C.getASTContext();
35218887Sdim  QualType ToTy = Ctx.getCanonicalType(CE->getType());
36218887Sdim  const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
37218887Sdim
38218887Sdim  if (!ToPTy)
39218887Sdim    return;
40218887Sdim
41218887Sdim  QualType ToPointeeTy = ToPTy->getPointeeType();
42218887Sdim
43218887Sdim  // Only perform the check if 'ToPointeeTy' is a complete type.
44218887Sdim  if (ToPointeeTy->isIncompleteType())
45218887Sdim    return;
46218887Sdim
47234353Sdim  ProgramStateRef state = C.getState();
48234353Sdim  const MemRegion *R = state->getSVal(E, C.getLocationContext()).getAsRegion();
49218887Sdim  if (R == 0)
50218887Sdim    return;
51218887Sdim
52218887Sdim  const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
53218887Sdim  if (SR == 0)
54218887Sdim    return;
55218887Sdim
56218887Sdim  SValBuilder &svalBuilder = C.getSValBuilder();
57218887Sdim  SVal extent = SR->getExtent(svalBuilder);
58218887Sdim  const llvm::APSInt *extentInt = svalBuilder.getKnownValue(state, extent);
59218887Sdim  if (!extentInt)
60218887Sdim    return;
61218887Sdim
62218887Sdim  CharUnits regionSize = CharUnits::fromQuantity(extentInt->getSExtValue());
63218887Sdim  CharUnits typeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy);
64218887Sdim
65218887Sdim  // Ignore void, and a few other un-sizeable types.
66218887Sdim  if (typeSize.isZero())
67218887Sdim    return;
68218887Sdim
69218887Sdim  if (regionSize % typeSize != 0) {
70218887Sdim    if (ExplodedNode *errorNode = C.generateSink()) {
71218887Sdim      if (!BT)
72219077Sdim        BT.reset(new BuiltinBug("Cast region with wrong size.",
73218887Sdim                            "Cast a region whose size is not a multiple of the"
74219077Sdim                            " destination type size."));
75226633Sdim      BugReport *R = new BugReport(*BT, BT->getDescription(),
76218887Sdim                                               errorNode);
77218887Sdim      R->addRange(CE->getSourceRange());
78243830Sdim      C.emitReport(R);
79218887Sdim    }
80218887Sdim  }
81218887Sdim}
82218887Sdim
83218887Sdim
84219077Sdimvoid ento::registerCastSizeChecker(CheckerManager &mgr) {
85219077Sdim  mgr.registerChecker<CastSizeChecker>();
86218887Sdim}
87