diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp | 101 |
1 files changed, 63 insertions, 38 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp index 6f8cb1432bb1..3f3267ff9391 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -12,12 +12,12 @@ //===----------------------------------------------------------------------===// #include "RetainCountChecker.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" using namespace clang; using namespace ento; using namespace retaincountchecker; -using llvm::StrInStrNoCase; REGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal) @@ -701,7 +701,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ, for (ProgramStateRef St : Out) { if (DeallocSent) { - C.addTransition(St, C.getPredecessor(), &DeallocSentTag); + C.addTransition(St, C.getPredecessor(), &getDeallocSentTag()); } else { C.addTransition(St); } @@ -844,13 +844,13 @@ RetainCountChecker::errorKindToBugKind(RefVal::Kind ErrorKind, SymbolRef Sym) const { switch (ErrorKind) { case RefVal::ErrorUseAfterRelease: - return useAfterRelease; + return *UseAfterRelease; case RefVal::ErrorReleaseNotOwned: - return releaseNotOwned; + return *ReleaseNotOwned; case RefVal::ErrorDeallocNotOwned: if (Sym->getType()->getPointeeCXXRecordDecl()) - return freeNotOwned; - return deallocNotOwned; + return *FreeNotOwned; + return *DeallocNotOwned; default: llvm_unreachable("Unhandled error."); } @@ -946,7 +946,7 @@ bool RetainCountChecker::evalCall(const CallEvent &Call, // Assume that output is zero on the other branch. NullOutputState = NullOutputState->BindExpr( CE, LCtx, C.getSValBuilder().makeNull(), /*Invalidate=*/false); - C.addTransition(NullOutputState, &CastFailTag); + C.addTransition(NullOutputState, &getCastFailTag()); // And on the original branch assume that both input and // output are non-zero. @@ -1095,7 +1095,7 @@ ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, if (N) { const LangOptions &LOpts = C.getASTContext().getLangOpts(); auto R = - std::make_unique<RefLeakReport>(leakAtReturn, LOpts, N, Sym, C); + std::make_unique<RefLeakReport>(*LeakAtReturn, LOpts, N, Sym, C); C.emitReport(std::move(R)); } return N; @@ -1120,7 +1120,7 @@ ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag); if (N) { auto R = std::make_unique<RefCountReport>( - returnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym); + *ReturnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym); C.emitReport(std::move(R)); } return N; @@ -1273,8 +1273,8 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, os << "has a +" << V.getCount() << " retain count"; const LangOptions &LOpts = Ctx.getASTContext().getLangOpts(); - auto R = std::make_unique<RefCountReport>(overAutorelease, LOpts, N, Sym, - os.str()); + auto R = std::make_unique<RefCountReport>(*OverAutorelease, LOpts, N, Sym, + os.str()); Ctx.emitReport(std::move(R)); } @@ -1320,7 +1320,7 @@ RetainCountChecker::processLeaks(ProgramStateRef state, if (N) { for (SymbolRef L : Leaked) { - const RefCountBug &BT = Pred ? leakWithinFunction : leakAtReturn; + const RefCountBug &BT = Pred ? *LeakWithinFunction : *LeakAtReturn; Ctx.emitReport(std::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx)); } } @@ -1473,48 +1473,73 @@ void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State, // Checker registration. //===----------------------------------------------------------------------===// +std::unique_ptr<CheckerProgramPointTag> RetainCountChecker::DeallocSentTag; +std::unique_ptr<CheckerProgramPointTag> RetainCountChecker::CastFailTag; + void ento::registerRetainCountBase(CheckerManager &Mgr) { - Mgr.registerChecker<RetainCountChecker>(); + auto *Chk = Mgr.registerChecker<RetainCountChecker>(); + Chk->DeallocSentTag = + std::make_unique<CheckerProgramPointTag>(Chk, "DeallocSent"); + Chk->CastFailTag = + std::make_unique<CheckerProgramPointTag>(Chk, "DynamicCastFail"); } -bool ento::shouldRegisterRetainCountBase(const LangOptions &LO) { +bool ento::shouldRegisterRetainCountBase(const CheckerManager &mgr) { return true; } - -// FIXME: remove this, hack for backwards compatibility: -// it should be possible to enable the NS/CF retain count checker as -// osx.cocoa.RetainCount, and it should be possible to disable -// osx.OSObjectRetainCount using osx.cocoa.RetainCount:CheckOSObject=false. -static bool getOption(AnalyzerOptions &Options, - StringRef Postfix, - StringRef Value) { - auto I = Options.Config.find( - (StringRef("osx.cocoa.RetainCount:") + Postfix).str()); - if (I != Options.Config.end()) - return I->getValue() == Value; - return false; -} - void ento::registerRetainCountChecker(CheckerManager &Mgr) { auto *Chk = Mgr.getChecker<RetainCountChecker>(); Chk->TrackObjCAndCFObjects = true; - Chk->TrackNSCFStartParam = getOption(Mgr.getAnalyzerOptions(), - "TrackNSCFStartParam", - "true"); + Chk->TrackNSCFStartParam = Mgr.getAnalyzerOptions().getCheckerBooleanOption( + Mgr.getCurrentCheckerName(), "TrackNSCFStartParam"); + +#define INIT_BUGTYPE(KIND) \ + Chk->KIND = std::make_unique<RefCountBug>(Mgr.getCurrentCheckerName(), \ + RefCountBug::KIND); + // TODO: Ideally, we should have a checker for each of these bug types. + INIT_BUGTYPE(UseAfterRelease) + INIT_BUGTYPE(ReleaseNotOwned) + INIT_BUGTYPE(DeallocNotOwned) + INIT_BUGTYPE(FreeNotOwned) + INIT_BUGTYPE(OverAutorelease) + INIT_BUGTYPE(ReturnNotOwnedForOwned) + INIT_BUGTYPE(LeakWithinFunction) + INIT_BUGTYPE(LeakAtReturn) +#undef INIT_BUGTYPE } -bool ento::shouldRegisterRetainCountChecker(const LangOptions &LO) { +bool ento::shouldRegisterRetainCountChecker(const CheckerManager &mgr) { return true; } void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) { auto *Chk = Mgr.getChecker<RetainCountChecker>(); - if (!getOption(Mgr.getAnalyzerOptions(), - "CheckOSObject", - "false")) - Chk->TrackOSObjects = true; + Chk->TrackOSObjects = true; + + // FIXME: We want bug reports to always have the same checker name associated + // with them, yet here, if RetainCountChecker is disabled but + // OSObjectRetainCountChecker is enabled, the checker names will be different. + // This hack will make it so that the checker name depends on which checker is + // enabled rather than on the registration order. + // For the most part, we want **non-hidden checkers** to be associated with + // diagnostics, and **hidden checker options** with the fine-tuning of + // modeling. Following this logic, OSObjectRetainCountChecker should be the + // latter, but we can't just remove it for backward compatibility reasons. +#define LAZY_INIT_BUGTYPE(KIND) \ + if (!Chk->KIND) \ + Chk->KIND = std::make_unique<RefCountBug>(Mgr.getCurrentCheckerName(), \ + RefCountBug::KIND); + LAZY_INIT_BUGTYPE(UseAfterRelease) + LAZY_INIT_BUGTYPE(ReleaseNotOwned) + LAZY_INIT_BUGTYPE(DeallocNotOwned) + LAZY_INIT_BUGTYPE(FreeNotOwned) + LAZY_INIT_BUGTYPE(OverAutorelease) + LAZY_INIT_BUGTYPE(ReturnNotOwnedForOwned) + LAZY_INIT_BUGTYPE(LeakWithinFunction) + LAZY_INIT_BUGTYPE(LeakAtReturn) +#undef LAZY_INIT_BUGTYPE } -bool ento::shouldRegisterOSObjectRetainCountChecker(const LangOptions &LO) { +bool ento::shouldRegisterOSObjectRetainCountChecker(const CheckerManager &mgr) { return true; } |