[analyzer] Migrate MallocChecker to CheckerV2.

llvm-svn: 126606
This commit is contained in:
Argyrios Kyrtzidis 2011-02-28 01:26:35 +00:00
parent 4e23dbd0fd
commit 183f0fb4cf
12 changed files with 213 additions and 91 deletions

View File

@ -189,6 +189,12 @@ public:
const Stmt *S,
ExprEngine &Eng);
/// \brief Run checkers for binding of a value to a location.
void runCheckersForBind(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, SVal val,
const Stmt *S, ExprEngine &Eng);
/// \brief Run checkers for end of analysis.
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng);
@ -214,6 +220,10 @@ public:
const MemRegion * const *Begin,
const MemRegion * const *End);
/// \brief Run checkers for handling assumptions on symbolic values.
const GRState *runCheckersForEvalAssume(const GRState *state,
SVal Cond, bool Assumption);
/// \brief Run checkers for evaluating a call.
void runCheckersForEvalCall(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
@ -243,6 +253,8 @@ public:
typedef CheckerFn<const ObjCMessage &, CheckerContext &> CheckObjCMessageFunc;
typedef CheckerFn<const SVal &/*location*/, bool/*isLoad*/, CheckerContext &>
CheckLocationFunc;
typedef CheckerFn<const SVal &/*location*/, const SVal &/*val*/,
CheckerContext &> CheckBindFunc;
typedef CheckerFn<ExplodedGraph &, BugReporter &, ExprEngine &>
CheckEndAnalysisFunc;
typedef CheckerFn<EndOfFunctionNodeBuilder &, ExprEngine &> CheckEndPathFunc;
@ -260,6 +272,8 @@ public:
void _registerForLocation(CheckLocationFunc checkfn);
void _registerForBind(CheckBindFunc checkfn);
void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn);
void _registerForEndPath(CheckEndPathFunc checkfn);
@ -298,6 +312,21 @@ public:
void _registerForRegionChanges(CheckRegionChangesFunc checkfn,
WantsRegionChangeUpdateFunc wantUpdateFn);
class EvalAssumeFunc {
typedef const GRState * (*Func)(void *, const GRState *,
const SVal &/*cond*/, bool /*assumption*/);
Func Fn;
public:
void *Checker;
EvalAssumeFunc(void *checker, Func fn) : Fn(fn), Checker(checker) {}
const GRState *operator()(const GRState *state,
const SVal &cond, bool assumption) {
return Fn(Checker, state, cond, assumption);
}
};
void _registerForEvalAssume(EvalAssumeFunc checkfn);
class EvalCallFunc {
typedef bool (*Func)(void *, const CallExpr *, CheckerContext &);
Func Fn;
@ -380,6 +409,8 @@ private:
std::vector<CheckLocationFunc> LocationCheckers;
std::vector<CheckBindFunc> BindCheckers;
std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers;
std::vector<CheckEndPathFunc> EndPathCheckers;
@ -394,6 +425,8 @@ private:
};
std::vector<RegionChangesCheckerInfo> RegionChangesCheckers;
std::vector<EvalAssumeFunc> EvalAssumeCheckers;
std::vector<EvalCallFunc> EvalCallCheckers;
};

View File

@ -145,6 +145,21 @@ public:
}
};
class Bind {
template <typename CHECKER>
static void _checkBind(void *checker, const SVal &location, const SVal &val,
CheckerContext &C) {
((const CHECKER *)checker)->checkBind(location, val, C);
}
public:
template <typename CHECKER>
static void _register(CHECKER *checker, CheckerManager &mgr) {
mgr._registerForBind(
CheckerManager::CheckBindFunc(checker, _checkBind<CHECKER>));
}
};
class EndAnalysis {
template <typename CHECKER>
static void _checkEndAnalysis(void *checker, ExplodedGraph &G,
@ -232,6 +247,21 @@ public:
namespace eval {
class Assume {
template <typename CHECKER>
static const GRState *_evalAssume(void *checker, const GRState *state,
const SVal &cond, bool assumption) {
return ((const CHECKER *)checker)->evalAssume(state, cond, assumption);
}
public:
template <typename CHECKER>
static void _register(CHECKER *checker, CheckerManager &mgr) {
mgr._registerForEvalAssume(
CheckerManager::EvalAssumeFunc(checker, _evalAssume<CHECKER>));
}
};
class Call {
template <typename CHECKER>
static bool _evalCall(void *checker, const CallExpr *CE, CheckerContext &C) {

View File

@ -129,6 +129,11 @@ def CFGDumper : Checker<"DumpCFG">,
let Group = AllExperimental in {
def MallocChecker : Checker<"Malloc">,
InPackage<CoreExperimental>,
HelpText<"Check for potential memory leaks, double free, and use-after-free problems">,
DescFile<"MallocChecker.cpp">;
def CStringChecker : Checker<"CString">,
InPackage<CoreExperimental>,
HelpText<"Check calls to functions in <string.h>">,

View File

@ -22,5 +22,4 @@ using namespace ento;
void ento::RegisterExperimentalChecks(ExprEngine &Eng) {
// These are checks that never belong as internal checks
// within ExprEngine.
RegisterMallocChecker(Eng); // ArrayBoundChecker depends on this.
}

View File

@ -267,10 +267,12 @@ void ExprEngine::CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst,
SVal val, bool isPrevisit) {
if (Checkers.empty()) {
Dst.insert(Src);
getCheckerManager().runCheckersForBind(Dst, Src, location, val, StoreE,
*this);
return;
}
ExplodedNodeSet CheckerV1Tmp;
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
@ -278,7 +280,7 @@ void ExprEngine::CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst,
{
ExplodedNodeSet *CurrSet = 0;
if (I+1 == E)
CurrSet = &Dst;
CurrSet = &CheckerV1Tmp;
else {
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
@ -296,6 +298,9 @@ void ExprEngine::CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst,
PrevSet = CurrSet;
}
getCheckerManager().runCheckersForBind(Dst, CheckerV1Tmp, location, val,
StoreE, *this);
// Don't autotransition. The CheckerContext objects should do this
// automatically.
}
@ -493,6 +498,8 @@ const GRState *ExprEngine::processAssume(const GRState *state, SVal cond,
CO_Ref = NewCO.take();
}
state = getCheckerManager().runCheckersForEvalAssume(state, cond, assumption);
// If the state is infeasible at this point, bail out.
if (!state)
return NULL;

View File

@ -12,9 +12,11 @@
//
//===----------------------------------------------------------------------===//
#include "ExperimentalChecks.h"
#include "ClangSACheckers.h"
#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@ -62,55 +64,52 @@ public:
class RegionState {};
class MallocChecker : public CheckerVisitor<MallocChecker> {
BuiltinBug *BT_DoubleFree;
BuiltinBug *BT_Leak;
BuiltinBug *BT_UseFree;
BuiltinBug *BT_UseRelinquished;
BuiltinBug *BT_BadFree;
IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc;
class MallocChecker : public CheckerV2<eval::Call, check::DeadSymbols, check::EndPath, check::PreStmt<ReturnStmt>, check::Location,
check::Bind, eval::Assume> {
mutable llvm::OwningPtr<BuiltinBug> BT_DoubleFree;
mutable llvm::OwningPtr<BuiltinBug> BT_Leak;
mutable llvm::OwningPtr<BuiltinBug> BT_UseFree;
mutable llvm::OwningPtr<BuiltinBug> BT_UseRelinquished;
mutable llvm::OwningPtr<BuiltinBug> BT_BadFree;
mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc;
public:
MallocChecker()
: BT_DoubleFree(0), BT_Leak(0), BT_UseFree(0), BT_UseRelinquished(0),
BT_BadFree(0),
II_malloc(0), II_free(0), II_realloc(0), II_calloc(0) {}
static void *getTag();
bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper);
void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, ExprEngine &Eng);
void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
const GRState *evalAssume(const GRState *state, SVal Cond, bool Assumption,
bool *respondsToCallback);
void visitLocation(CheckerContext &C, const Stmt *S, SVal l, bool isLoad);
virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
SVal location, SVal val);
MallocChecker() : II_malloc(0), II_free(0), II_realloc(0), II_calloc(0) {}
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
const GRState *evalAssume(const GRState *state, SVal Cond,
bool Assumption) const;
void checkLocation(SVal l, bool isLoad, CheckerContext &C) const;
void checkBind(SVal location, SVal val, CheckerContext &C) const;
private:
void MallocMem(CheckerContext &C, const CallExpr *CE);
void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
static void MallocMem(CheckerContext &C, const CallExpr *CE);
static void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
const OwnershipAttr* Att);
const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
const Expr *SizeEx, SVal Init,
const GRState *state) {
return MallocMemAux(C, CE, state->getSVal(SizeEx), Init, state);
}
const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
SVal SizeEx, SVal Init,
const GRState *state);
void FreeMem(CheckerContext &C, const CallExpr *CE);
void FreeMem(CheckerContext &C, const CallExpr *CE) const;
void FreeMemAttr(CheckerContext &C, const CallExpr *CE,
const OwnershipAttr* Att);
const OwnershipAttr* Att) const;
const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
const GRState *state, unsigned Num, bool Hold);
const GRState *state, unsigned Num, bool Hold) const;
void ReallocMem(CheckerContext &C, const CallExpr *CE);
void CallocMem(CheckerContext &C, const CallExpr *CE);
void ReallocMem(CheckerContext &C, const CallExpr *CE) const;
static void CallocMem(CheckerContext &C, const CallExpr *CE);
bool SummarizeValue(llvm::raw_ostream& os, SVal V);
bool SummarizeRegion(llvm::raw_ostream& os, const MemRegion *MR);
void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range);
static bool SummarizeValue(llvm::raw_ostream& os, SVal V);
static bool SummarizeRegion(llvm::raw_ostream& os, const MemRegion *MR);
void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const;
};
} // end anonymous namespace
@ -121,21 +120,12 @@ namespace ento {
template <>
struct GRStateTrait<RegionState>
: public GRStatePartialTrait<RegionStateTy> {
static void *GDMIndex() { return MallocChecker::getTag(); }
static void *GDMIndex() { static int x; return &x; }
};
}
}
void ento::RegisterMallocChecker(ExprEngine &Eng) {
Eng.registerCheck(new MallocChecker());
}
void *MallocChecker::getTag() {
static int x;
return &x;
}
bool MallocChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
bool MallocChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@ -256,7 +246,7 @@ const GRState *MallocChecker::MallocMemAux(CheckerContext &C,
return state->set<RegionState>(Sym, RefState::getAllocateUnchecked(CE));
}
void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = FreeMemAux(C, CE, C.getState(), 0, false);
if (state)
@ -264,7 +254,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
}
void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE,
const OwnershipAttr* Att) {
const OwnershipAttr* Att) const {
if (Att->getModule() != "malloc")
return;
@ -279,7 +269,7 @@ void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE,
const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
const GRState *state, unsigned Num,
bool Hold) {
bool Hold) const {
const Expr *ArgExpr = CE->getArg(Num);
SVal ArgVal = state->getSVal(ArgExpr);
@ -357,9 +347,9 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
if (RS->isReleased()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_DoubleFree)
BT_DoubleFree
= new BuiltinBug("Double free",
"Try to free a memory block that has been released");
BT_DoubleFree.reset(
new BuiltinBug("Double free",
"Try to free a memory block that has been released"));
// FIXME: should find where it's freed last time.
BugReport *R = new BugReport(*BT_DoubleFree,
BT_DoubleFree->getDescription(), N);
@ -463,10 +453,10 @@ bool MallocChecker::SummarizeRegion(llvm::raw_ostream& os,
}
void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
SourceRange range) {
SourceRange range) const {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_BadFree)
BT_BadFree = new BuiltinBug("Bad free");
BT_BadFree.reset(new BuiltinBug("Bad free"));
llvm::SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
@ -500,7 +490,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
}
}
void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
const Expr *arg0Expr = CE->getArg(0);
DefinedOrUnknownSVal arg0Val
@ -562,7 +552,8 @@ void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) {
C.addTransition(MallocMemAux(C, CE, TotalSize, zeroVal, state));
}
void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper)
void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
CheckerContext &C) const
{
if (!SymReaper.hasDeadSymbols())
return;
@ -576,8 +567,8 @@ void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper)
if (I->second.isAllocated()) {
if (ExplodedNode *N = C.generateNode()) {
if (!BT_Leak)
BT_Leak = new BuiltinBug("Memory leak",
"Allocated memory never released. Potential memory leak.");
BT_Leak.reset(new BuiltinBug("Memory leak",
"Allocated memory never released. Potential memory leak."));
// FIXME: where it is allocated.
BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
C.EmitReport(R);
@ -591,8 +582,8 @@ void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper)
C.generateNode(state->set<RegionState>(RS));
}
void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
ExprEngine &Eng) {
void MallocChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
ExprEngine &Eng) const {
const GRState *state = B.getState();
RegionStateTy M = state->get<RegionState>();
@ -602,8 +593,8 @@ void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
ExplodedNode *N = B.generateNode(state);
if (N) {
if (!BT_Leak)
BT_Leak = new BuiltinBug("Memory leak",
"Allocated memory never released. Potential memory leak.");
BT_Leak.reset(new BuiltinBug("Memory leak",
"Allocated memory never released. Potential memory leak."));
BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
Eng.getBugReporter().EmitReport(R);
}
@ -611,7 +602,7 @@ void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
}
}
void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
const Expr *retExpr = S->getRetValue();
if (!retExpr)
return;
@ -634,8 +625,7 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
}
const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond,
bool Assumption,
bool * /* respondsToCallback */) {
bool Assumption) const {
// If a symblic region is assumed to NULL, set its state to AllocateFailed.
// FIXME: should also check symbols assumed to non-null.
@ -650,16 +640,15 @@ const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond,
}
// Check if the location is a freed symbolic region.
void MallocChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
bool isLoad) {
void MallocChecker::checkLocation(SVal l, bool isLoad,CheckerContext &C) const {
SymbolRef Sym = l.getLocSymbolInBase();
if (Sym) {
const RefState *RS = C.getState()->get<RegionState>(Sym);
if (RS && RS->isReleased()) {
if (ExplodedNode *N = C.generateNode()) {
if (!BT_UseFree)
BT_UseFree = new BuiltinBug("Use dynamically allocated memory after"
" it is freed.");
BT_UseFree.reset(new BuiltinBug("Use dynamically allocated memory "
"after it is freed."));
BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(),
N);
@ -669,10 +658,7 @@ void MallocChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
}
}
void MallocChecker::PreVisitBind(CheckerContext &C,
const Stmt *StoreE,
SVal location,
SVal val) {
void MallocChecker::checkBind(SVal location, SVal val,CheckerContext &C) const {
// The PreVisitBind implements the same algorithm as already used by the
// Objective C ownership checker: if the pointer escaped from this scope by
// assignment, let it go. However, assigning to fields of a stack-storage
@ -721,7 +707,7 @@ void MallocChecker::PreVisitBind(CheckerContext &C,
// We no longer own this pointer.
notNullState =
notNullState->set<RegionState>(Sym,
RefState::getRelinquished(StoreE));
RefState::getRelinquished(C.getStmt()));
}
while (false);
}
@ -729,3 +715,7 @@ void MallocChecker::PreVisitBind(CheckerContext &C,
}
}
}
void ento::registerMallocChecker(CheckerManager &mgr) {
mgr.registerChecker<MallocChecker>();
}

View File

@ -205,6 +205,40 @@ void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,
expandGraphWithCheckers(C, Dst, Src);
}
namespace {
struct CheckBindContext {
typedef std::vector<CheckerManager::CheckBindFunc> CheckersTy;
const CheckersTy &Checkers;
SVal Loc;
SVal Val;
const Stmt *S;
ExprEngine &Eng;
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
CheckBindContext(const CheckersTy &checkers,
SVal loc, SVal val, const Stmt *s, ExprEngine &eng)
: Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng) { }
void runChecker(CheckerManager::CheckBindFunc checkFn,
ExplodedNodeSet &Dst, ExplodedNode *Pred) {
CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
ProgramPoint::PreStmtKind, 0, S);
checkFn(Loc, Val, C);
}
};
}
/// \brief Run checkers for binding of a value to a location.
void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, SVal val,
const Stmt *S, ExprEngine &Eng) {
CheckBindContext C(BindCheckers, location, val, S, Eng);
expandGraphWithCheckers(C, Dst, Src);
}
void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
BugReporter &BR,
ExprEngine &Eng) {
@ -287,6 +321,20 @@ CheckerManager::runCheckersForRegionChanges(const GRState *state,
return state;
}
/// \brief Run checkers for handling assumptions on symbolic values.
const GRState *
CheckerManager::runCheckersForEvalAssume(const GRState *state,
SVal Cond, bool Assumption) {
for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) {
// If any checker declares the state infeasible (or if it starts that way),
// bail out.
if (!state)
return NULL;
state = EvalAssumeCheckers[i](state, Cond, Assumption);
}
return state;
}
/// \brief Run checkers for evaluating a call.
/// Only one checker will evaluate the call.
void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
@ -371,6 +419,10 @@ void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {
LocationCheckers.push_back(checkfn);
}
void CheckerManager::_registerForBind(CheckBindFunc checkfn) {
BindCheckers.push_back(checkfn);
}
void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {
EndAnalysisCheckers.push_back(checkfn);
}
@ -393,6 +445,10 @@ void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn,
RegionChangesCheckers.push_back(info);
}
void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) {
EvalAssumeCheckers.push_back(checkfn);
}
void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
EvalCallCheckers.push_back(checkfn);
}

View File

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-experimental-checks -analyzer-checker=core.experimental.UnreachableCode -verify -analyzer-constraints=basic %s
// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-experimental-checks -analyzer-checker=core.experimental.UnreachableCode -verify -analyzer-constraints=range %s
// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-checker=core.experimental.UnreachableCode,core.experimental.Malloc -verify -analyzer-constraints=basic %s
// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-checker=core.experimental.UnreachableCode,core.experimental.Malloc -verify -analyzer-constraints=range %s
// These are used to trigger warnings.
typedef typeof(sizeof(int)) size_t;

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -fblocks -verify %s
// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-checker=core.experimental.Malloc -fblocks -verify %s
void free(void *);
void t1 () {

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.UnreachableCode,core.experimental.CastSize -analyzer-check-objc-mem -analyzer-experimental-checks -analyzer-store=region -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.UnreachableCode,core.experimental.CastSize,core.experimental.Malloc -analyzer-check-objc-mem -analyzer-experimental-checks -analyzer-store=region -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
void free(void *);

View File

@ -1,10 +1,10 @@
// NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued.
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-disable-checker=core.experimental.Malloc -analyzer-check-objc-mem -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-disable-checker=core.experimental.Malloc -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-disable-checker=core.experimental.Malloc -analyzer-check-objc-mem -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-disable-checker=core.experimental.Malloc -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s

View File

@ -25,7 +25,9 @@ void free(void *);
void field() {
struct vec { size_t len; int data[0]; };
struct vec *a = malloc(sizeof(struct vec) + 10);
// FIXME: Not warn for this.
struct vec *a = malloc(sizeof(struct vec) + 10); // expected-warning {{Cast a region whose size is not a multiple of the destination type size}}
a->len = 10;
a->data[1] = 5; // no-warning
free(a);
}