From: Argyrios Kyrtzidis Date: Mon, 28 Feb 2011 01:26:35 +0000 (+0000) Subject: [analyzer] Migrate MallocChecker to CheckerV2. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=312dbec867f6b8d6b86fd562c53352cd4db27468;p=clang [analyzer] Migrate MallocChecker to CheckerV2. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126606 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index 1ad85d2e42..f7ee2bed8d 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -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 CheckObjCMessageFunc; typedef CheckerFn CheckLocationFunc; + typedef CheckerFn CheckBindFunc; typedef CheckerFn CheckEndAnalysisFunc; typedef CheckerFn 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 LocationCheckers; + std::vector BindCheckers; + std::vector EndAnalysisCheckers; std::vector EndPathCheckers; @@ -394,6 +425,8 @@ private: }; std::vector RegionChangesCheckers; + std::vector EvalAssumeCheckers; + std::vector EvalCallCheckers; }; diff --git a/include/clang/StaticAnalyzer/Core/CheckerV2.h b/include/clang/StaticAnalyzer/Core/CheckerV2.h index e080d190ab..7dbbd32ae9 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerV2.h +++ b/include/clang/StaticAnalyzer/Core/CheckerV2.h @@ -145,6 +145,21 @@ public: } }; +class Bind { + template + static void _checkBind(void *checker, const SVal &location, const SVal &val, + CheckerContext &C) { + ((const CHECKER *)checker)->checkBind(location, val, C); + } + +public: + template + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForBind( + CheckerManager::CheckBindFunc(checker, _checkBind)); + } +}; + class EndAnalysis { template static void _checkEndAnalysis(void *checker, ExplodedGraph &G, @@ -232,6 +247,21 @@ public: namespace eval { +class Assume { + template + static const GRState *_evalAssume(void *checker, const GRState *state, + const SVal &cond, bool assumption) { + return ((const CHECKER *)checker)->evalAssume(state, cond, assumption); + } + +public: + template + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForEvalAssume( + CheckerManager::EvalAssumeFunc(checker, _evalAssume)); + } +}; + class Call { template static bool _evalCall(void *checker, const CallExpr *CE, CheckerContext &C) { diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td index 894b961f7d..3562c04d60 100644 --- a/lib/StaticAnalyzer/Checkers/Checkers.td +++ b/lib/StaticAnalyzer/Checkers/Checkers.td @@ -129,6 +129,11 @@ def CFGDumper : Checker<"DumpCFG">, let Group = AllExperimental in { +def MallocChecker : Checker<"Malloc">, + InPackage, + HelpText<"Check for potential memory leaks, double free, and use-after-free problems">, + DescFile<"MallocChecker.cpp">; + def CStringChecker : Checker<"CString">, InPackage, HelpText<"Check calls to functions in ">, diff --git a/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp b/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp index 990ba1c02b..b0a7f3559d 100644 --- a/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp +++ b/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp @@ -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. } diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp index c1b1e65698..afa97d0d97 100644 --- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp @@ -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; diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 794740ab72..6591d74932 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -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 { - 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, check::Location, + check::Bind, eval::Assume> { + mutable llvm::OwningPtr BT_DoubleFree; + mutable llvm::OwningPtr BT_Leak; + mutable llvm::OwningPtr BT_UseFree; + mutable llvm::OwningPtr BT_UseRelinquished; + mutable llvm::OwningPtr 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, - const OwnershipAttr* Att); - const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, - const Expr *SizeEx, SVal Init, - const GRState *state) { + static void MallocMem(CheckerContext &C, const CallExpr *CE); + static void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, + const OwnershipAttr* Att); + 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, - SVal SizeEx, SVal Init, - const GRState *state); + 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 : public GRStatePartialTrait { - 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(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(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(); @@ -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(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(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(); +} diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index 75d331a131..0a4e847ef4 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -205,6 +205,40 @@ void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, expandGraphWithCheckers(C, Dst, Src); } +namespace { + struct CheckBindContext { + typedef std::vector 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); } diff --git a/test/Analysis/additive-folding.c b/test/Analysis/additive-folding.c index 096ffb9a50..3b09506997 100644 --- a/test/Analysis/additive-folding.c +++ b/test/Analysis/additive-folding.c @@ -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; diff --git a/test/Analysis/free.c b/test/Analysis/free.c index 8aba4a05f0..78d3a2ed5f 100644 --- a/test/Analysis/free.c +++ b/test/Analysis/free.c @@ -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 () { diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c index 2ffa103359..1e8655e98c 100644 --- a/test/Analysis/malloc.c +++ b/test/Analysis/malloc.c @@ -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 *); diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m index db4fa02ff1..7cbc8f8bc8 100644 --- a/test/Analysis/misc-ps.m +++ b/test/Analysis/misc-ps.m @@ -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 diff --git a/test/Analysis/no-outofbounds.c b/test/Analysis/no-outofbounds.c index 92cb8b3271..4217eaf383 100644 --- a/test/Analysis/no-outofbounds.c +++ b/test/Analysis/no-outofbounds.c @@ -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); }