diff options
author | Zhongxing Xu <xuzhongxing@gmail.com> | 2010-05-25 04:59:19 +0000 |
---|---|---|
committer | Zhongxing Xu <xuzhongxing@gmail.com> | 2010-05-25 04:59:19 +0000 |
commit | 658dd8b176f9fd34d63b0fe329d585a709c40759 (patch) | |
tree | 3219db406d67c173a58b63f922cf2a9a63abac71 | |
parent | 4f48499d2c7dc257b341bc988d6e716e57ae554a (diff) | |
download | bcm5719-llvm-658dd8b176f9fd34d63b0fe329d585a709c40759.tar.gz bcm5719-llvm-658dd8b176f9fd34d63b0fe329d585a709c40759.zip |
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.
llvm-svn: 104584
-rw-r--r-- | clang/include/clang/Checker/PathSensitive/Store.h | 8 | ||||
-rw-r--r-- | clang/lib/Checker/CMakeLists.txt | 3 | ||||
-rw-r--r-- | clang/lib/Checker/CastSizeChecker.cpp | 82 | ||||
-rw-r--r-- | clang/lib/Checker/GRExprEngineExperimentalChecks.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Checker/GRExprEngineInternalChecks.h | 1 | ||||
-rw-r--r-- | clang/lib/Checker/RegionStore.cpp | 19 | ||||
-rw-r--r-- | clang/test/Analysis/malloc.c | 24 |
7 files changed, 122 insertions, 16 deletions
diff --git a/clang/include/clang/Checker/PathSensitive/Store.h b/clang/include/clang/Checker/PathSensitive/Store.h index 41d7c2bd713..8c6c36daa0a 100644 --- a/clang/include/clang/Checker/PathSensitive/Store.h +++ b/clang/include/clang/Checker/PathSensitive/Store.h @@ -18,6 +18,7 @@ #include "clang/Checker/PathSensitive/SVals.h" #include "clang/Checker/PathSensitive/ValueManager.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" namespace clang { @@ -167,10 +168,15 @@ public: // FIXME: Make out-of-line. virtual const GRState *setExtent(const GRState *state, - const MemRegion *region, SVal extent) { + const MemRegion *region, SVal extent) { return state; } + virtual llvm::Optional<SVal> getExtent(const GRState *state, + const MemRegion *R) { + return llvm::Optional<SVal>(); + } + /// EnterStackFrame - Let the StoreManager to do something when execution /// engine is about to execute into a callee. virtual const GRState *EnterStackFrame(const GRState *state, diff --git a/clang/lib/Checker/CMakeLists.txt b/clang/lib/Checker/CMakeLists.txt index ce5a7361b92..9c6adc6bf2e 100644 --- a/clang/lib/Checker/CMakeLists.txt +++ b/clang/lib/Checker/CMakeLists.txt @@ -14,6 +14,7 @@ add_clang_library(clangChecker BuiltinFunctionChecker.cpp CallAndMessageChecker.cpp CallInliner.cpp + CastSizeChecker.cpp CastToStructChecker.cpp CFRefCount.cpp CheckDeadStores.cpp @@ -70,4 +71,4 @@ add_clang_library(clangChecker VLASizeChecker.cpp ) -add_dependencies(clangChecker ClangStmtNodes)
\ No newline at end of file +add_dependencies(clangChecker ClangStmtNodes) diff --git a/clang/lib/Checker/CastSizeChecker.cpp b/clang/lib/Checker/CastSizeChecker.cpp new file mode 100644 index 00000000000..754d775a65d --- /dev/null +++ b/clang/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/clang/lib/Checker/GRExprEngineExperimentalChecks.cpp b/clang/lib/Checker/GRExprEngineExperimentalChecks.cpp index 89b4e4b6392..6066a1c74d3 100644 --- a/clang/lib/Checker/GRExprEngineExperimentalChecks.cpp +++ b/clang/lib/Checker/GRExprEngineExperimentalChecks.cpp @@ -36,5 +36,6 @@ void clang::RegisterExperimentalInternalChecks(GRExprEngine &Eng) { RegisterPointerSubChecker(Eng); RegisterPointerArithChecker(Eng); RegisterCastToStructChecker(Eng); + RegisterCastSizeChecker(Eng); RegisterArrayBoundChecker(Eng); } diff --git a/clang/lib/Checker/GRExprEngineInternalChecks.h b/clang/lib/Checker/GRExprEngineInternalChecks.h index d1176001cac..335b85e308e 100644 --- a/clang/lib/Checker/GRExprEngineInternalChecks.h +++ b/clang/lib/Checker/GRExprEngineInternalChecks.h @@ -26,6 +26,7 @@ void RegisterAttrNonNullChecker(GRExprEngine &Eng); 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/clang/lib/Checker/RegionStore.cpp b/clang/lib/Checker/RegionStore.cpp index 1e15d43a5ac..0e4c4439f34 100644 --- a/clang/lib/Checker/RegionStore.cpp +++ b/clang/lib/Checker/RegionStore.cpp @@ -364,7 +364,18 @@ public: // Part of public interface to class. // 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 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, return UnknownVal(); } -const GRState *RegionStoreManager::setExtent(const GRState *state, - const MemRegion *region, - SVal extent) { - return state->set<RegionExtents>(region, extent); -} - //===----------------------------------------------------------------------===// // Location and region casting. //===----------------------------------------------------------------------===// diff --git a/clang/test/Analysis/malloc.c b/clang/test/Analysis/malloc.c index 21b6d46a245..fe24bc19e61 100644 --- a/clang/test/Analysis/malloc.c +++ b/clang/test/Analysis/malloc.c @@ -6,16 +6,16 @@ void *realloc(void *ptr, size_t size); void *calloc(size_t nmemb, size_t size); void f1() { - int *p = malloc(10); + int *p = malloc(12); return; // expected-warning{{Allocated memory never released. Potential memory leak.}} } void f1_b() { - int *p = malloc(10); // expected-warning{{Allocated memory never released. Potential memory leak.}} + int *p = malloc(12); // expected-warning{{Allocated memory never released. Potential memory leak.}} } void f2() { - int *p = malloc(10); + int *p = malloc(12); free(p); free(p); // expected-warning{{Try to free a memory block that has been released}} } @@ -25,7 +25,7 @@ void f2() { // or inter-procedural analysis, this is a conservative answer. int *f3() { static int *p = 0; - p = malloc(10); + p = malloc(12); return p; // no-warning } @@ -34,18 +34,18 @@ int *f3() { // functions or inter-procedural analysis, this is a conservative answer. static int *p_f4 = 0; int *f4() { - p_f4 = malloc(10); + p_f4 = malloc(12); return p_f4; // no-warning } int *f5() { - int *q = malloc(10); + int *q = malloc(12); q = realloc(q, 20); return q; // no-warning } void f6() { - int *p = malloc(10); + int *p = malloc(12); if (!p) return; // no-warning else @@ -67,3 +67,13 @@ void f7() { free(x); x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}} } + +void PR6123() { + int *x = malloc(11); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}} +} + +void PR7217() { + int *buf = malloc(2); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}} + buf[1] = 'c'; // not crash + +} |