summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp29
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h23
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp87
4 files changed, 126 insertions, 16 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index 30d4dd1bd8a..2b39ad6fa65 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -418,13 +418,18 @@ void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
}
// Consult the summary for the return value.
+ SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
RetEffect RE = Summ.getRetEffect();
- if (RE.getKind() == RetEffect::NoRetHard) {
- SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
- if (Sym)
- state = removeRefBinding(state, Sym);
+ if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) {
+ if (Optional<RefVal> updatedRefVal =
+ refValFromRetEffect(RE, MCall->getResultType())) {
+ state = setRefBinding(state, Sym, *updatedRefVal);
+ }
}
+ if (RE.getKind() == RetEffect::NoRetHard && Sym)
+ state = removeRefBinding(state, Sym);
+
C.addTransition(state);
}
@@ -490,11 +495,10 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
}
}
- // Evaluate the effect on the message receiver.
+ // Evaluate the effect on the message receiver / `this` argument.
bool ReceiverIsTracked = false;
if (!hasErr) {
- const ObjCMethodCall *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg);
- if (MsgInvocation) {
+ if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
if (const RefVal *T = getRefBinding(state, Sym)) {
ReceiverIsTracked = true;
@@ -506,6 +510,17 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
}
}
}
+ } else if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) {
+ if (SymbolRef Sym = MCall->getCXXThisVal().getAsLocSymbol()) {
+ if (const RefVal *T = getRefBinding(state, Sym)) {
+ state = updateSymbol(state, Sym, *T, Summ.getThisEffect(),
+ hasErr, C);
+ if (hasErr) {
+ ErrorRange = MCall->getOriginExpr()->getSourceRange();
+ ErrorSym = Sym;
+ }
+ }
+ }
}
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
index 6bd5379e5f4..8683b23dd96 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
@@ -98,7 +98,7 @@ private:
/// The kind of object being tracked (CF or ObjC), if known.
///
/// See the RetEffect::ObjKind enum for possible values.
- unsigned RawObjectKind : 2;
+ unsigned RawObjectKind : 3;
/// True if the current state and/or retain count may turn out to not be the
/// best possible approximation of the reference counting state.
@@ -268,6 +268,8 @@ class RetainCountChecker
mutable std::unique_ptr<RetainSummaryManager> Summaries;
mutable SummaryLogTy SummaryLog;
+
+ AnalyzerOptions &Options;
mutable bool ShouldResetSummaryLog;
/// Optional setting to indicate if leak reports should include
@@ -275,12 +277,17 @@ class RetainCountChecker
mutable bool IncludeAllocationLine;
public:
- RetainCountChecker(AnalyzerOptions &AO)
- : ShouldResetSummaryLog(false),
- IncludeAllocationLine(shouldIncludeAllocationSiteInLeakDiagnostics(AO)) {}
+ RetainCountChecker(AnalyzerOptions &Options)
+ : Options(Options), ShouldResetSummaryLog(false),
+ IncludeAllocationLine(
+ shouldIncludeAllocationSiteInLeakDiagnostics(Options)) {}
~RetainCountChecker() override { DeleteContainerSeconds(DeadSymbolTags); }
+ bool shouldCheckOSObjectRetainCount() const {
+ return Options.getBooleanOption("CheckOSObject", false, this);
+ }
+
void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng) const {
// FIXME: This is a hack to make sure the summary log gets cleared between
@@ -333,10 +340,12 @@ public:
// FIXME: We don't support ARC being turned on and off during one analysis.
// (nor, for that matter, do we support changing ASTContexts)
bool ARCEnabled = (bool)Ctx.getLangOpts().ObjCAutoRefCount;
- if (!Summaries)
- Summaries.reset(new RetainSummaryManager(Ctx, ARCEnabled));
- else
+ if (!Summaries) {
+ Summaries.reset(new RetainSummaryManager(
+ Ctx, ARCEnabled, shouldCheckOSObjectRetainCount()));
+ } else {
assert(Summaries->isARCEnabled() == ARCEnabled);
+ }
return *Summaries;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index ef03470f908..2d41c4526fb 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -120,6 +120,9 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN,
if (CurrV.getObjKind() == RetEffect::CF) {
os << " returns a Core Foundation object of type "
<< Sym->getType().getAsString() << " with a ";
+ } else if (CurrV.getObjKind() == RetEffect::OS) {
+ os << " returns an OSObject of type "
+ << Sym->getType().getAsString() << " with a ";
} else if (CurrV.getObjKind() == RetEffect::Generalized) {
os << " returns an object of type " << Sym->getType().getAsString()
<< " with a ";
diff --git a/clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp b/clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp
index a2e716f56f7..4370daa244e 100644
--- a/clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp
@@ -53,6 +53,31 @@ RetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) {
return Summ;
}
+static bool isOSObjectSubclass(QualType T);
+
+static bool isOSObjectSubclass(const CXXRecordDecl *RD) {
+ if (RD->getDeclName().getAsString() == "OSObject")
+ return true;
+
+ const CXXRecordDecl *RDD = RD->getDefinition();
+ if (!RDD)
+ return false;
+
+ for (const CXXBaseSpecifier Spec : RDD->bases()) {
+ if (isOSObjectSubclass(Spec.getType()))
+ return true;
+ }
+ return false;
+}
+
+/// \return Whether type represents an OSObject successor.
+static bool isOSObjectSubclass(QualType T) {
+ if (const auto *RD = T->getAsCXXRecordDecl()) {
+ return isOSObjectSubclass(RD);
+ }
+ return false;
+}
+
static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) {
for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) {
if (Ann->getAnnotation() == rcAnnotation)
@@ -196,6 +221,17 @@ RetainSummaryManager::generateSummary(const FunctionDecl *FD,
}
if (RetTy->isPointerType()) {
+ if (TrackOSObjects && isOSObjectSubclass(RetTy->getPointeeType())) {
+ if (const IdentifierInfo *II = FD->getIdentifier()) {
+ StringRef FuncName = II->getName();
+ if (FuncName.contains_lower("with")
+ || FuncName.contains_lower("create")
+ || FuncName.contains_lower("copy"))
+ return getOSSummaryCreateRule(FD);
+ }
+ return getOSSummaryGetRule(FD);
+ }
+
// For CoreFoundation ('CF') types.
if (cocoa::isRefType(RetTy, "CF", FName)) {
if (isRetain(FD, FName)) {
@@ -241,6 +277,17 @@ RetainSummaryManager::generateSummary(const FunctionDecl *FD,
}
}
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ const CXXRecordDecl *Parent = MD->getParent();
+ if (TrackOSObjects && isOSObjectSubclass(Parent)) {
+ if (isRelease(FD, FName))
+ return getOSSummaryReleaseRule(FD);
+
+ if (isRetain(FD, FName))
+ return getOSSummaryRetainRule(FD);
+ }
+ }
+
// Check for release functions, the only kind of functions that we care
// about that don't return a pointer type.
if (FName.size() >= 2 && FName[0] == 'C' &&
@@ -279,6 +326,14 @@ RetainSummaryManager::generateSummary(const FunctionDecl *FD,
}
}
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+
+ // Stop tracking arguments passed to C++ methods, as those might be
+ // wrapping smart pointers.
+ return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, StopTracking,
+ DoNothing);
+ }
+
return getDefaultSummary();
}
@@ -411,6 +466,8 @@ RetainSummaryManager::getSummary(const CallEvent &Call,
Summ = getFunctionSummary(cast<SimpleFunctionCall>(Call).getDecl());
break;
case CE_CXXMember:
+ Summ = getFunctionSummary(cast<CXXMemberCall>(Call).getDecl());
+ break;
case CE_CXXMemberOperator:
case CE_Block:
case CE_CXXConstructor:
@@ -514,6 +571,32 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT,
}
const RetainSummary *
+RetainSummaryManager::getOSSummaryRetainRule(const FunctionDecl *FD) {
+ return getPersistentSummary(RetEffect::MakeNoRet(),
+ /*ReceiverEff=*/DoNothing,
+ /*DefaultEff=*/DoNothing,
+ /*ThisEff=*/IncRef);
+}
+
+const RetainSummary *
+RetainSummaryManager::getOSSummaryReleaseRule(const FunctionDecl *FD) {
+ return getPersistentSummary(RetEffect::MakeNoRet(),
+ /*ReceiverEff=*/DoNothing,
+ /*DefaultEff=*/DoNothing,
+ /*ThisEff=*/DecRef);
+}
+
+const RetainSummary *
+RetainSummaryManager::getOSSummaryCreateRule(const FunctionDecl *FD) {
+ return getPersistentSummary(RetEffect::MakeOwned(RetEffect::OS));
+}
+
+const RetainSummary *
+RetainSummaryManager::getOSSummaryGetRule(const FunctionDecl *FD) {
+ return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::OS));
+}
+
+const RetainSummary *
RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) {
assert (ScratchArgs.isEmpty());
@@ -877,7 +960,7 @@ void RetainSummaryManager::InitializeMethodSummaries() {
CallEffects CallEffects::getEffect(const ObjCMethodDecl *MD) {
ASTContext &Ctx = MD->getASTContext();
LangOptions L = Ctx.getLangOpts();
- RetainSummaryManager M(Ctx, L.ObjCAutoRefCount);
+ RetainSummaryManager M(Ctx, L.ObjCAutoRefCount, /*TrackOSObjects=*/false);
const RetainSummary *S = M.getMethodSummary(MD);
CallEffects CE(S->getRetEffect());
CE.Receiver = S->getReceiverEffect();
@@ -891,7 +974,7 @@ CallEffects CallEffects::getEffect(const ObjCMethodDecl *MD) {
CallEffects CallEffects::getEffect(const FunctionDecl *FD) {
ASTContext &Ctx = FD->getASTContext();
LangOptions L = Ctx.getLangOpts();
- RetainSummaryManager M(Ctx, L.ObjCAutoRefCount);
+ RetainSummaryManager M(Ctx, L.ObjCAutoRefCount, /*TrackOSObjects=*/false);
const RetainSummary *S = M.getFunctionSummary(FD);
CallEffects CE(S->getRetEffect());
unsigned N = FD->param_size();
OpenPOWER on IntegriCloud