зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
8b24233616
Коммит
ab28099e3b
|
@ -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
|
||||
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче