[analyzer] [RetainSummaryManager] [NFC] Split one function into two, as it's really doing two things

Differential Revision: https://reviews.llvm.org/D57201

llvm-svn: 352533
This commit is contained in:
George Karpenkov 2019-01-29 19:29:45 +00:00
parent 2e46667853
commit b0fc58b57c
2 changed files with 58 additions and 60 deletions

View File

@ -693,10 +693,22 @@ private:
void updateSummaryFromAnnotations(const RetainSummary *&Summ, void updateSummaryFromAnnotations(const RetainSummary *&Summ,
const FunctionDecl *FD); const FunctionDecl *FD);
void updateSummaryForCall(const RetainSummary *&Summ, const RetainSummary *updateSummaryForNonZeroCallbackArg(const RetainSummary *S,
AnyCall C, AnyCall &C);
bool HasNonZeroCallbackArg,
bool IsReceiverUnconsumedSelf); /// Special case '[super init];' and '[self init];'
///
/// Even though calling '[super init]' without assigning the result to self
/// and checking if the parent returns 'nil' is a bad pattern, it is common.
/// Additionally, our Self Init checker already warns about it. To avoid
/// overwhelming the user with messages from both checkers, we model the case
/// of '[super init]' in cases when it is not consumed by another expression
/// as if the call preserves the value of 'self'; essentially, assuming it can
/// never fail and return 'nil'.
/// Note, we don't want to just stop tracking the value since we want the
/// RetainCount checker to report leaks and use-after-free if SelfInit checker
/// is turned off.
void updateSummaryForReceiverUnconsumedSelf(const RetainSummary *&S);
/// Determine whether a declaration {@code D} of correspondent type (return /// Determine whether a declaration {@code D} of correspondent type (return
/// type for functions/methods) {@code QT} has any of the given attributes, /// type for functions/methods) {@code QT} has any of the given attributes,

View File

@ -557,64 +557,47 @@ static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
llvm_unreachable("Unknown ArgEffect kind"); llvm_unreachable("Unknown ArgEffect kind");
} }
void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S, const RetainSummary *
AnyCall C, RetainSummaryManager::updateSummaryForNonZeroCallbackArg(const RetainSummary *S,
bool HasNonZeroCallbackArg, AnyCall &C) {
bool IsReceiverUnconsumedSelf) { ArgEffect RecEffect = getStopTrackingHardEquivalent(S->getReceiverEffect());
ArgEffect DefEffect = getStopTrackingHardEquivalent(S->getDefaultArgEffect());
if (HasNonZeroCallbackArg) { ArgEffects ScratchArgs(AF.getEmptyMap());
ArgEffect RecEffect = ArgEffects CustomArgEffects = S->getArgEffects();
getStopTrackingHardEquivalent(S->getReceiverEffect()); for (ArgEffects::iterator I = CustomArgEffects.begin(),
ArgEffect DefEffect = E = CustomArgEffects.end();
getStopTrackingHardEquivalent(S->getDefaultArgEffect()); I != E; ++I) {
ArgEffect Translated = getStopTrackingHardEquivalent(I->second);
ArgEffects ScratchArgs(AF.getEmptyMap()); if (Translated.getKind() != DefEffect.getKind())
ArgEffects CustomArgEffects = S->getArgEffects(); ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
for (ArgEffects::iterator I = CustomArgEffects.begin(),
E = CustomArgEffects.end();
I != E; ++I) {
ArgEffect Translated = getStopTrackingHardEquivalent(I->second);
if (Translated.getKind() != DefEffect.getKind())
ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
}
RetEffect RE = RetEffect::MakeNoRetHard();
// Special cases where the callback argument CANNOT free the return value.
// This can generally only happen if we know that the callback will only be
// called when the return value is already being deallocated.
if (C.getKind() == AnyCall::Function) {
if (const IdentifierInfo *Name = C.getIdentifier()) {
// When the CGBitmapContext is deallocated, the callback here will free
// the associated data buffer.
// The callback in dispatch_data_create frees the buffer, but not
// the data object.
if (Name->isStr("CGBitmapContextCreateWithData") ||
Name->isStr("dispatch_data_create"))
RE = S->getRetEffect();
}
}
S = getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect);
} }
// Special case '[super init];' and '[self init];' RetEffect RE = RetEffect::MakeNoRetHard();
//
// Even though calling '[super init]' without assigning the result to self // Special cases where the callback argument CANNOT free the return value.
// and checking if the parent returns 'nil' is a bad pattern, it is common. // This can generally only happen if we know that the callback will only be
// Additionally, our Self Init checker already warns about it. To avoid // called when the return value is already being deallocated.
// overwhelming the user with messages from both checkers, we model the case if (const IdentifierInfo *Name = C.getIdentifier()) {
// of '[super init]' in cases when it is not consumed by another expression // When the CGBitmapContext is deallocated, the callback here will free
// as if the call preserves the value of 'self'; essentially, assuming it can // the associated data buffer.
// never fail and return 'nil'. // The callback in dispatch_data_create frees the buffer, but not
// Note, we don't want to just stop tracking the value since we want the // the data object.
// RetainCount checker to report leaks and use-after-free if SelfInit checker if (Name->isStr("CGBitmapContextCreateWithData") ||
// is turned off. Name->isStr("dispatch_data_create"))
if (IsReceiverUnconsumedSelf) { RE = S->getRetEffect();
RetainSummaryTemplate ModifiableSummaryTemplate(S, *this);
ModifiableSummaryTemplate->setReceiverEffect(ArgEffect(DoNothing));
ModifiableSummaryTemplate->setRetEffect(RetEffect::MakeNoRet());
} }
return getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect);
}
void RetainSummaryManager::updateSummaryForReceiverUnconsumedSelf(
const RetainSummary *&S) {
RetainSummaryTemplate Template(S, *this);
Template->setReceiverEffect(ArgEffect(DoNothing));
Template->setRetEffect(RetEffect::MakeNoRet());
} }
const RetainSummary * const RetainSummary *
@ -647,8 +630,11 @@ RetainSummaryManager::getSummary(AnyCall C,
} }
} }
updateSummaryForCall(Summ, C, HasNonZeroCallbackArg, if (HasNonZeroCallbackArg)
IsReceiverUnconsumedSelf); Summ = updateSummaryForNonZeroCallbackArg(Summ, C);
if (IsReceiverUnconsumedSelf)
updateSummaryForReceiverUnconsumedSelf(Summ);
assert(Summ && "Unknown call type?"); assert(Summ && "Unknown call type?");
return Summ; return Summ;