summaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp101
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;
}