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.
//===----------------------------------------------------------------------===//