CastSizeChecker checks when casting a malloc'ed symbolic region to type T,
whether the size of the symbolic region is a multiple of the size of T.
Fixes PR6123 and PR7217.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104584 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt
index ce5a736..9c6adc6 100644
--- a/lib/Checker/CMakeLists.txt
+++ b/lib/Checker/CMakeLists.txt
@@ -14,6 +14,7 @@
   BuiltinFunctionChecker.cpp
   CallAndMessageChecker.cpp
   CallInliner.cpp
+  CastSizeChecker.cpp
   CastToStructChecker.cpp
   CFRefCount.cpp
   CheckDeadStores.cpp
@@ -70,4 +71,4 @@
   VLASizeChecker.cpp
   )
 
-add_dependencies(clangChecker ClangStmtNodes)
\ No newline at end of file
+add_dependencies(clangChecker ClangStmtNodes)
diff --git a/lib/Checker/CastSizeChecker.cpp b/lib/Checker/CastSizeChecker.cpp
new file mode 100644
index 0000000..754d775
--- /dev/null
+++ b/lib/Checker/CastSizeChecker.cpp
@@ -0,0 +1,82 @@
+//=== CastSizeChecker.cpp ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// CastSizeChecker checks when casting a malloc'ed symbolic region to type T,
+// whether the size of the symbolic region is a multiple of the size of T.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/CharUnits.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class CastSizeChecker : public CheckerVisitor<CastSizeChecker> {
+  BuiltinBug *BT;
+public:
+  CastSizeChecker() : BT(0) {}
+  static void *getTag();
+  void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
+};
+}
+
+void *CastSizeChecker::getTag() {
+  static int x;
+  return &x;
+}
+
+void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) {
+  const Expr *E = CE->getSubExpr();
+  ASTContext &Ctx = C.getASTContext();
+  QualType ToTy = Ctx.getCanonicalType(CE->getType());
+  PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
+
+  if (!ToPTy)
+    return;
+
+  QualType ToPointeeTy = ToPTy->getPointeeType();
+
+  const MemRegion *R = C.getState()->getSVal(E).getAsRegion();
+  if (R == 0)
+    return;
+
+  const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
+  if (SR == 0)
+    return;
+
+  llvm::Optional<SVal> V = 
+                    C.getEngine().getStoreManager().getExtent(C.getState(), SR);
+  if (!V)
+    return;
+
+  const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(V);
+  if (!CI)
+    return;
+
+  CharUnits RegionSize = CharUnits::fromQuantity(CI->getValue().getSExtValue());
+  CharUnits TypeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy);
+  if (RegionSize % TypeSize != 0) {
+    if (ExplodedNode *N = C.GenerateSink()) {
+      if (!BT)
+        BT = new BuiltinBug("Cast region with wrong size.",
+                            "Cast a region whose size is not a multiple of the"
+                            " destination type size.");
+      RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+      R->addRange(CE->getSourceRange());
+      C.EmitReport(R);
+    }
+  }
+}
+
+
+void clang::RegisterCastSizeChecker(GRExprEngine &Eng) {
+  Eng.registerCheck(new CastSizeChecker());
+}
diff --git a/lib/Checker/GRExprEngineExperimentalChecks.cpp b/lib/Checker/GRExprEngineExperimentalChecks.cpp
index 89b4e4b..6066a1c 100644
--- a/lib/Checker/GRExprEngineExperimentalChecks.cpp
+++ b/lib/Checker/GRExprEngineExperimentalChecks.cpp
@@ -36,5 +36,6 @@
   RegisterPointerSubChecker(Eng);
   RegisterPointerArithChecker(Eng);
   RegisterCastToStructChecker(Eng);
+  RegisterCastSizeChecker(Eng);
   RegisterArrayBoundChecker(Eng);
 }
diff --git a/lib/Checker/GRExprEngineInternalChecks.h b/lib/Checker/GRExprEngineInternalChecks.h
index d117600..335b85e 100644
--- a/lib/Checker/GRExprEngineInternalChecks.h
+++ b/lib/Checker/GRExprEngineInternalChecks.h
@@ -26,6 +26,7 @@
 void RegisterBuiltinFunctionChecker(GRExprEngine &Eng);
 void RegisterCallAndMessageChecker(GRExprEngine &Eng);
 void RegisterCastToStructChecker(GRExprEngine &Eng);
+void RegisterCastSizeChecker(GRExprEngine &Eng);
 void RegisterDereferenceChecker(GRExprEngine &Eng);
 void RegisterDivZeroChecker(GRExprEngine &Eng);
 void RegisterFixedAddressChecker(GRExprEngine &Eng);
diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index 1e15d43..0e4c443 100644
--- a/lib/Checker/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -364,7 +364,18 @@
   // Region "extents".
   //===------------------------------------------------------------------===//
 
-  const GRState *setExtent(const GRState *state,const MemRegion* R,SVal Extent);
+  const GRState *setExtent(const GRState *state,const MemRegion* R,SVal Extent){
+    return state->set<RegionExtents>(R, Extent);
+  }
+
+  Optional<SVal> getExtent(const GRState *state, const MemRegion *R) {
+    const SVal *V = state->get<RegionExtents>(R);
+    if (V)
+      return *V;
+    else
+      return Optional<SVal>();
+  }
+
   DefinedOrUnknownSVal getSizeInElements(const GRState *state,
                                          const MemRegion* R, QualType EleTy);
 
@@ -798,12 +809,6 @@
   return UnknownVal();
 }
 
-const GRState *RegionStoreManager::setExtent(const GRState *state,
-                                             const MemRegion *region,
-                                             SVal extent) {
-  return state->set<RegionExtents>(region, extent);
-}
-
 //===----------------------------------------------------------------------===//
 // Location and region casting.
 //===----------------------------------------------------------------------===//