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
This commit is contained in:
Zhongxing Xu 2010-05-25 04:59:19 +00:00
Родитель 8b24233616
Коммит ab28099e3b
7 изменённых файлов: 122 добавлений и 16 удалений

Просмотреть файл

@ -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,

Просмотреть файл

@ -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)
add_dependencies(clangChecker ClangStmtNodes)

Просмотреть файл

@ -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());
}

Просмотреть файл

@ -36,5 +36,6 @@ void clang::RegisterExperimentalInternalChecks(GRExprEngine &Eng) {
RegisterPointerSubChecker(Eng);
RegisterPointerArithChecker(Eng);
RegisterCastToStructChecker(Eng);
RegisterCastSizeChecker(Eng);
RegisterArrayBoundChecker(Eng);
}

Просмотреть файл

@ -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);

Просмотреть файл

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

Просмотреть файл

@ -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
}