forked from OSchip/llvm-project
Revert "[analyzer] [NFC] Split up RetainSummaryManager from RetainCountChecker"
This reverts commit a786521fa66c72edd308baff0c08961b6d964fb1. Bots haven't caught up yet, but broke modules build with: ../tools/clang/include/clang/StaticAnalyzer/Checkers/MPIFunctionClassifier.h:18:10: fatal error: cyclic dependency in module 'Clang_StaticAnalyzer_Core': Clang_StaticAnalyzer_Core -> Clang_Analysis -> Clang_StaticAnalyzer_Checkers -> Clang_StaticAnalyzer_Core ^ llvm-svn: 340117
This commit is contained in:
parent
6ac2be0a98
commit
bb3b7cff96
|
@ -0,0 +1,231 @@
|
|||
//==-- ObjCRetainCount.h - Retain count summaries for Cocoa -------*- C++ -*--//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the core data structures for retain count "summaries"
|
||||
// for Objective-C and Core Foundation APIs. These summaries are used
|
||||
// by the static analyzer to summarize the retain/release effects of
|
||||
// function and method calls. This drives a path-sensitive typestate
|
||||
// analysis in the static analyzer, but can also potentially be used by
|
||||
// other clients.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_OBJCRETAINCOUNT_H
|
||||
#define LLVM_CLANG_STATICANALYZER_CHECKERS_OBJCRETAINCOUNT_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
class FunctionDecl;
|
||||
class ObjCMethodDecl;
|
||||
|
||||
namespace ento { namespace objc_retain {
|
||||
|
||||
/// An ArgEffect summarizes the retain count behavior on an argument or receiver
|
||||
/// to a function or method.
|
||||
enum ArgEffect {
|
||||
/// There is no effect.
|
||||
DoNothing,
|
||||
|
||||
/// The argument is treated as if an -autorelease message had been sent to
|
||||
/// the referenced object.
|
||||
Autorelease,
|
||||
|
||||
/// The argument is treated as if an -dealloc message had been sent to
|
||||
/// the referenced object.
|
||||
Dealloc,
|
||||
|
||||
/// The argument has its reference count decreased by 1. This is as
|
||||
/// if CFRelease has been called on the argument.
|
||||
DecRef,
|
||||
|
||||
/// The argument has its reference count decreased by 1. This is as
|
||||
/// if a -release message has been sent to the argument. This differs
|
||||
/// in behavior from DecRef when GC is enabled.
|
||||
DecRefMsg,
|
||||
|
||||
/// The argument has its reference count decreased by 1 to model
|
||||
/// a transferred bridge cast under ARC.
|
||||
DecRefBridgedTransferred,
|
||||
|
||||
/// The argument has its reference count increased by 1. This is as
|
||||
/// if a -retain message has been sent to the argument. This differs
|
||||
/// in behavior from IncRef when GC is enabled.
|
||||
IncRefMsg,
|
||||
|
||||
/// The argument has its reference count increased by 1. This is as
|
||||
/// if CFRetain has been called on the argument.
|
||||
IncRef,
|
||||
|
||||
/// Used to mark an argument as collectible in GC mode, currently a noop.
|
||||
MakeCollectable,
|
||||
|
||||
/// The argument is a pointer to a retain-counted object; on exit, the new
|
||||
/// value of the pointer is a +0 value or NULL.
|
||||
UnretainedOutParameter,
|
||||
|
||||
/// The argument is a pointer to a retain-counted object; on exit, the new
|
||||
/// value of the pointer is a +1 value or NULL.
|
||||
RetainedOutParameter,
|
||||
|
||||
/// The argument is treated as potentially escaping, meaning that
|
||||
/// even when its reference count hits 0 it should be treated as still
|
||||
/// possibly being alive as someone else *may* be holding onto the object.
|
||||
MayEscape,
|
||||
|
||||
/// All typestate tracking of the object ceases. This is usually employed
|
||||
/// when the effect of the call is completely unknown.
|
||||
StopTracking,
|
||||
|
||||
/// All typestate tracking of the object ceases. Unlike StopTracking,
|
||||
/// this is also enforced when the method body is inlined.
|
||||
///
|
||||
/// In some cases, we obtain a better summary for this checker
|
||||
/// by looking at the call site than by inlining the function.
|
||||
/// Signifies that we should stop tracking the symbol even if
|
||||
/// the function is inlined.
|
||||
StopTrackingHard,
|
||||
|
||||
/// Performs the combined functionality of DecRef and StopTrackingHard.
|
||||
///
|
||||
/// The models the effect that the called function decrements the reference
|
||||
/// count of the argument and all typestate tracking on that argument
|
||||
/// should cease.
|
||||
DecRefAndStopTrackingHard,
|
||||
|
||||
/// Performs the combined functionality of DecRefMsg and StopTrackingHard.
|
||||
///
|
||||
/// The models the effect that the called function decrements the reference
|
||||
/// count of the argument and all typestate tracking on that argument
|
||||
/// should cease.
|
||||
DecRefMsgAndStopTrackingHard
|
||||
};
|
||||
|
||||
/// RetEffect summarizes a call's retain/release behavior with respect
|
||||
/// to its return value.
|
||||
class RetEffect {
|
||||
public:
|
||||
enum Kind {
|
||||
/// Indicates that no retain count information is tracked for
|
||||
/// the return value.
|
||||
NoRet,
|
||||
/// Indicates that the returned value is an owned (+1) symbol.
|
||||
OwnedSymbol,
|
||||
/// Indicates that the returned value is an object with retain count
|
||||
/// semantics but that it is not owned (+0). This is the default
|
||||
/// for getters, etc.
|
||||
NotOwnedSymbol,
|
||||
/// Indicates that the object is not owned and controlled by the
|
||||
/// Garbage collector.
|
||||
GCNotOwnedSymbol,
|
||||
/// Indicates that the return value is an owned object when the
|
||||
/// receiver is also a tracked object.
|
||||
OwnedWhenTrackedReceiver,
|
||||
// Treat this function as returning a non-tracked symbol even if
|
||||
// the function has been inlined. This is used where the call
|
||||
// site summary is more presise than the summary indirectly produced
|
||||
// by inlining the function
|
||||
NoRetHard
|
||||
};
|
||||
|
||||
/// Determines the object kind of a tracked object.
|
||||
enum ObjKind {
|
||||
/// Indicates that the tracked object is a CF object. This is
|
||||
/// important between GC and non-GC code.
|
||||
CF,
|
||||
/// Indicates that the tracked object is an Objective-C object.
|
||||
ObjC,
|
||||
/// Indicates that the tracked object could be a CF or Objective-C object.
|
||||
AnyObj,
|
||||
/// Indicates that the tracked object is a generalized object.
|
||||
Generalized
|
||||
};
|
||||
|
||||
private:
|
||||
Kind K;
|
||||
ObjKind O;
|
||||
|
||||
RetEffect(Kind k, ObjKind o = AnyObj) : K(k), O(o) {}
|
||||
|
||||
public:
|
||||
Kind getKind() const { return K; }
|
||||
|
||||
ObjKind getObjKind() const { return O; }
|
||||
|
||||
bool isOwned() const {
|
||||
return K == OwnedSymbol || K == OwnedWhenTrackedReceiver;
|
||||
}
|
||||
|
||||
bool notOwned() const {
|
||||
return K == NotOwnedSymbol;
|
||||
}
|
||||
|
||||
bool operator==(const RetEffect &Other) const {
|
||||
return K == Other.K && O == Other.O;
|
||||
}
|
||||
|
||||
static RetEffect MakeOwnedWhenTrackedReceiver() {
|
||||
return RetEffect(OwnedWhenTrackedReceiver, ObjC);
|
||||
}
|
||||
|
||||
static RetEffect MakeOwned(ObjKind o) {
|
||||
return RetEffect(OwnedSymbol, o);
|
||||
}
|
||||
static RetEffect MakeNotOwned(ObjKind o) {
|
||||
return RetEffect(NotOwnedSymbol, o);
|
||||
}
|
||||
static RetEffect MakeGCNotOwned() {
|
||||
return RetEffect(GCNotOwnedSymbol, ObjC);
|
||||
}
|
||||
static RetEffect MakeNoRet() {
|
||||
return RetEffect(NoRet);
|
||||
}
|
||||
static RetEffect MakeNoRetHard() {
|
||||
return RetEffect(NoRetHard);
|
||||
}
|
||||
};
|
||||
|
||||
/// Encapsulates the retain count semantics on the arguments, return value,
|
||||
/// and receiver (if any) of a function/method call.
|
||||
///
|
||||
/// Note that construction of these objects is not highly efficient. That
|
||||
/// is okay for clients where creating these objects isn't really a bottleneck.
|
||||
/// The purpose of the API is to provide something simple. The actual
|
||||
/// static analyzer checker that implements retain/release typestate
|
||||
/// tracking uses something more efficient.
|
||||
class CallEffects {
|
||||
llvm::SmallVector<ArgEffect, 10> Args;
|
||||
RetEffect Ret;
|
||||
ArgEffect Receiver;
|
||||
|
||||
CallEffects(const RetEffect &R) : Ret(R) {}
|
||||
|
||||
public:
|
||||
/// Returns the argument effects for a call.
|
||||
ArrayRef<ArgEffect> getArgs() const { return Args; }
|
||||
|
||||
/// Returns the effects on the receiver.
|
||||
ArgEffect getReceiver() const { return Receiver; }
|
||||
|
||||
/// Returns the effect on the return value.
|
||||
RetEffect getReturnValue() const { return Ret; }
|
||||
|
||||
/// Return the CallEfect for a given Objective-C method.
|
||||
static CallEffects getEffect(const ObjCMethodDecl *MD);
|
||||
|
||||
/// Return the CallEfect for a given C/C++ function.
|
||||
static CallEffects getEffect(const FunctionDecl *FD);
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
|
|
@ -34,4 +34,5 @@ add_clang_library(clangARCMigrate
|
|||
clangRewrite
|
||||
clangSema
|
||||
clangSerialization
|
||||
clangStaticAnalyzerCheckers
|
||||
)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Transforms.h"
|
||||
#include "clang/Analysis/RetainSummaryManager.h"
|
||||
#include "clang/Analysis/ObjCRetainCount.h"
|
||||
#include "clang/ARCMigrate/ARCMT.h"
|
||||
#include "clang/ARCMigrate/ARCMTActions.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
|
@ -35,8 +35,8 @@
|
|||
#include "llvm/Support/YAMLParser.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
using namespace arcmt;
|
||||
using namespace ento::objc_retain;
|
||||
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ add_clang_library(clangAnalysis
|
|||
ProgramPoint.cpp
|
||||
PseudoConstantAnalysis.cpp
|
||||
ReachableCode.cpp
|
||||
RetainSummaryManager.cpp
|
||||
ScanfFormatString.cpp
|
||||
ThreadSafety.cpp
|
||||
ThreadSafetyCommon.cpp
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangSACheckers.h"
|
||||
#include "SelectorExtras.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
|
||||
#include "clang/StaticAnalyzer/Checkers/SelectorExtras.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
|
||||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
||||
|
|
|
@ -77,6 +77,7 @@ add_clang_library(clangStaticAnalyzerCheckers
|
|||
PointerSubChecker.cpp
|
||||
PthreadLockChecker.cpp
|
||||
RetainCountChecker/RetainCountChecker.cpp
|
||||
RetainCountChecker/RetainCountSummaries.cpp
|
||||
RetainCountChecker/RetainCountDiagnostics.cpp
|
||||
ReturnPointerRangeChecker.cpp
|
||||
ReturnUndefChecker.cpp
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangSACheckers.h"
|
||||
#include "SelectorExtras.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/StaticAnalyzer/Checkers/SelectorExtras.h"
|
||||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
using namespace objc_retain;
|
||||
using namespace retaincountchecker;
|
||||
using llvm::StrInStrNoCase;
|
||||
|
||||
|
@ -330,19 +331,7 @@ void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
|
|||
void RetainCountChecker::checkPostCall(const CallEvent &Call,
|
||||
CheckerContext &C) const {
|
||||
RetainSummaryManager &Summaries = getSummaryManager(C);
|
||||
|
||||
// Leave null if no receiver.
|
||||
QualType ReceiverType;
|
||||
if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) {
|
||||
if (MC->isInstanceMessage()) {
|
||||
SVal ReceiverV = MC->getReceiverSVal();
|
||||
if (SymbolRef Sym = ReceiverV.getAsLocSymbol())
|
||||
if (const RefVal *T = getRefBinding(C.getState(), Sym))
|
||||
ReceiverType = T->getType();
|
||||
}
|
||||
}
|
||||
|
||||
const RetainSummary *Summ = Summaries.getSummary(Call, ReceiverType);
|
||||
const RetainSummary *Summ = Summaries.getSummary(Call, C.getState());
|
||||
|
||||
if (C.wasInlined) {
|
||||
processSummaryOfInlined(*Summ, Call, C);
|
||||
|
@ -1398,6 +1387,45 @@ void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
|
|||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementation of the CallEffects API.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace clang {
|
||||
namespace ento {
|
||||
namespace objc_retain {
|
||||
|
||||
// This is a bit gross, but it allows us to populate CallEffects without
|
||||
// creating a bunch of accessors. This kind is very localized, so the
|
||||
// damage of this macro is limited.
|
||||
#define createCallEffect(D, KIND)\
|
||||
ASTContext &Ctx = D->getASTContext();\
|
||||
LangOptions L = Ctx.getLangOpts();\
|
||||
RetainSummaryManager M(Ctx, L.ObjCAutoRefCount);\
|
||||
const RetainSummary *S = M.get ## KIND ## Summary(D);\
|
||||
CallEffects CE(S->getRetEffect());\
|
||||
CE.Receiver = S->getReceiverEffect();\
|
||||
unsigned N = D->param_size();\
|
||||
for (unsigned i = 0; i < N; ++i) {\
|
||||
CE.Args.push_back(S->getArg(i));\
|
||||
}
|
||||
|
||||
CallEffects CallEffects::getEffect(const ObjCMethodDecl *MD) {
|
||||
createCallEffect(MD, Method);
|
||||
return CE;
|
||||
}
|
||||
|
||||
CallEffects CallEffects::getEffect(const FunctionDecl *FD) {
|
||||
createCallEffect(FD, Function);
|
||||
return CE;
|
||||
}
|
||||
|
||||
#undef createCallEffect
|
||||
|
||||
} // end namespace objc_retain
|
||||
} // end namespace ento
|
||||
} // end namespace clang
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Checker registration.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -17,16 +17,17 @@
|
|||
|
||||
#include "../ClangSACheckers.h"
|
||||
#include "../AllocationDiagnostics.h"
|
||||
#include "../SelectorExtras.h"
|
||||
#include "RetainCountSummaries.h"
|
||||
#include "RetainCountDiagnostics.h"
|
||||
#include "clang/Analysis/ObjCRetainCount.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/ParentMap.h"
|
||||
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
|
||||
#include "clang/Analysis/RetainSummaryManager.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/StaticAnalyzer/Checkers/SelectorExtras.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
|
||||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
|
@ -45,6 +46,7 @@
|
|||
#include <cstdarg>
|
||||
#include <utility>
|
||||
|
||||
using namespace objc_retain;
|
||||
using llvm::StrInStrNoCase;
|
||||
|
||||
namespace clang {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H
|
||||
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H
|
||||
|
||||
#include "clang/Analysis/RetainSummaryManager.h"
|
||||
#include "RetainCountSummaries.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//== RetainSummaryManager.cpp - Summaries for reference counting --*- C++ -*--//
|
||||
//== RetainCountSummaries.cpp - Checks for leaks and other issues -*- C++ -*--//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -7,21 +7,25 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines summaries implementation for retain counting, which
|
||||
// This file defines summaries implementation for RetainCountChecker, which
|
||||
// implements a reference count checker for Core Foundation and Cocoa
|
||||
// on (Mac OS X).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/RetainSummaryManager.h"
|
||||
#include "RetainCountSummaries.h"
|
||||
#include "RetainCountChecker.h"
|
||||
|
||||
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/ParentMap.h"
|
||||
|
||||
using namespace objc_retain;
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
using namespace retaincountchecker;
|
||||
|
||||
ArgEffects RetainSummaryManager::getArgEffects() {
|
||||
ArgEffects AE = ScratchArgs;
|
||||
|
@ -404,7 +408,7 @@ void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S,
|
|||
|
||||
const RetainSummary *
|
||||
RetainSummaryManager::getSummary(const CallEvent &Call,
|
||||
QualType ReceiverType) {
|
||||
ProgramStateRef State) {
|
||||
const RetainSummary *Summ;
|
||||
switch (Call.getKind()) {
|
||||
case CE_Function:
|
||||
|
@ -421,7 +425,7 @@ RetainSummaryManager::getSummary(const CallEvent &Call,
|
|||
case CE_ObjCMessage: {
|
||||
const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
|
||||
if (Msg.isInstanceMessage())
|
||||
Summ = getInstanceMethodSummary(Msg, ReceiverType);
|
||||
Summ = getInstanceMethodSummary(Msg, State);
|
||||
else
|
||||
Summ = getClassMethodSummary(Msg);
|
||||
break;
|
||||
|
@ -735,15 +739,22 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
|
|||
return getPersistentSummary(ResultEff, ReceiverEff, MayEscape);
|
||||
}
|
||||
|
||||
const RetainSummary *RetainSummaryManager::getInstanceMethodSummary(
|
||||
const ObjCMethodCall &Msg, QualType ReceiverType) {
|
||||
const RetainSummary *
|
||||
RetainSummaryManager::getInstanceMethodSummary(const ObjCMethodCall &Msg,
|
||||
ProgramStateRef State) {
|
||||
const ObjCInterfaceDecl *ReceiverClass = nullptr;
|
||||
|
||||
// We do better tracking of the type of the object than the core ExprEngine.
|
||||
// See if we have its type in our private state.
|
||||
if (!ReceiverType.isNull())
|
||||
if (const auto *PT = ReceiverType->getAs<ObjCObjectPointerType>())
|
||||
ReceiverClass = PT->getInterfaceDecl();
|
||||
// FIXME: Eventually replace the use of state->get<RefBindings> with
|
||||
// a generic API for reasoning about the Objective-C types of symbolic
|
||||
// objects.
|
||||
SVal ReceiverV = Msg.getReceiverSVal();
|
||||
if (SymbolRef Sym = ReceiverV.getAsLocSymbol())
|
||||
if (const RefVal *T = getRefBinding(State, Sym))
|
||||
if (const ObjCObjectPointerType *PT =
|
||||
T->getType()->getAs<ObjCObjectPointerType>())
|
||||
ReceiverClass = PT->getInterfaceDecl();
|
||||
|
||||
// If we don't know what kind of object this is, fall back to its static type.
|
||||
if (!ReceiverClass)
|
||||
|
@ -873,30 +884,3 @@ void RetainSummaryManager::InitializeMethodSummaries() {
|
|||
"format", "colorSpace");
|
||||
addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info");
|
||||
}
|
||||
|
||||
CallEffects CallEffects::getEffect(const ObjCMethodDecl *MD) {
|
||||
ASTContext &Ctx = MD->getASTContext();
|
||||
LangOptions L = Ctx.getLangOpts();
|
||||
RetainSummaryManager M(Ctx, L.ObjCAutoRefCount);
|
||||
const RetainSummary *S = M.getMethodSummary(MD);
|
||||
CallEffects CE(S->getRetEffect());
|
||||
CE.Receiver = S->getReceiverEffect();
|
||||
unsigned N = MD->param_size();
|
||||
for (unsigned i = 0; i < N; ++i) {
|
||||
CE.Args.push_back(S->getArg(i));
|
||||
}
|
||||
return CE;
|
||||
}
|
||||
|
||||
CallEffects CallEffects::getEffect(const FunctionDecl *FD) {
|
||||
ASTContext &Ctx = FD->getASTContext();
|
||||
LangOptions L = Ctx.getLangOpts();
|
||||
RetainSummaryManager M(Ctx, L.ObjCAutoRefCount);
|
||||
const RetainSummary *S = M.getFunctionSummary(FD);
|
||||
CallEffects CE(S->getRetEffect());
|
||||
unsigned N = FD->param_size();
|
||||
for (unsigned i = 0; i < N; ++i) {
|
||||
CE.Args.push_back(S->getArg(i));
|
||||
}
|
||||
return CE;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
//=== RetainSummaryManager.h - Summaries for reference counting ---*- C++ -*--//
|
||||
//=== RetainCountSummaries.h - Checks for leaks and other issues -*- C++ -*--//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -7,22 +7,25 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines summaries implementation for retain counting, which
|
||||
// This file defines summaries implementation for RetainCountChecker, which
|
||||
// implements a reference count checker for Core Foundation and Cocoa
|
||||
// on (Mac OS X).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LIB_ANALYSIS_RETAINSUMMARYMANAGER
|
||||
#define LLVM_CLANG_LIB_ANALYSIS_RETAINSUMMARYMANAGER
|
||||
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_SUMMARY_H
|
||||
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_SUMMARY_H
|
||||
|
||||
#include "../ClangSACheckers.h"
|
||||
#include "../AllocationDiagnostics.h"
|
||||
#include "../SelectorExtras.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "clang/Analysis/ObjCRetainCount.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/ParentMap.h"
|
||||
#include "clang/StaticAnalyzer/Checkers/SelectorExtras.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
|
||||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
|
@ -41,206 +44,11 @@
|
|||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
using namespace objc_retain;
|
||||
|
||||
namespace clang {
|
||||
namespace ento {
|
||||
|
||||
/// An ArgEffect summarizes the retain count behavior on an argument or receiver
|
||||
/// to a function or method.
|
||||
enum ArgEffect {
|
||||
/// There is no effect.
|
||||
DoNothing,
|
||||
|
||||
/// The argument is treated as if an -autorelease message had been sent to
|
||||
/// the referenced object.
|
||||
Autorelease,
|
||||
|
||||
/// The argument is treated as if an -dealloc message had been sent to
|
||||
/// the referenced object.
|
||||
Dealloc,
|
||||
|
||||
/// The argument has its reference count decreased by 1. This is as
|
||||
/// if CFRelease has been called on the argument.
|
||||
DecRef,
|
||||
|
||||
/// The argument has its reference count decreased by 1. This is as
|
||||
/// if a -release message has been sent to the argument. This differs
|
||||
/// in behavior from DecRef when GC is enabled.
|
||||
DecRefMsg,
|
||||
|
||||
/// The argument has its reference count decreased by 1 to model
|
||||
/// a transferred bridge cast under ARC.
|
||||
DecRefBridgedTransferred,
|
||||
|
||||
/// The argument has its reference count increased by 1. This is as
|
||||
/// if a -retain message has been sent to the argument. This differs
|
||||
/// in behavior from IncRef when GC is enabled.
|
||||
IncRefMsg,
|
||||
|
||||
/// The argument has its reference count increased by 1. This is as
|
||||
/// if CFRetain has been called on the argument.
|
||||
IncRef,
|
||||
|
||||
/// The argument acts as if has been passed to CFMakeCollectable, which
|
||||
/// transfers the object to the Garbage Collector under GC.
|
||||
MakeCollectable,
|
||||
|
||||
/// The argument is a pointer to a retain-counted object; on exit, the new
|
||||
/// value of the pointer is a +0 value or NULL.
|
||||
UnretainedOutParameter,
|
||||
|
||||
/// The argument is a pointer to a retain-counted object; on exit, the new
|
||||
/// value of the pointer is a +1 value or NULL.
|
||||
RetainedOutParameter,
|
||||
|
||||
/// The argument is treated as potentially escaping, meaning that
|
||||
/// even when its reference count hits 0 it should be treated as still
|
||||
/// possibly being alive as someone else *may* be holding onto the object.
|
||||
MayEscape,
|
||||
|
||||
/// All typestate tracking of the object ceases. This is usually employed
|
||||
/// when the effect of the call is completely unknown.
|
||||
StopTracking,
|
||||
|
||||
/// All typestate tracking of the object ceases. Unlike StopTracking,
|
||||
/// this is also enforced when the method body is inlined.
|
||||
///
|
||||
/// In some cases, we obtain a better summary for this checker
|
||||
/// by looking at the call site than by inlining the function.
|
||||
/// Signifies that we should stop tracking the symbol even if
|
||||
/// the function is inlined.
|
||||
StopTrackingHard,
|
||||
|
||||
/// Performs the combined functionality of DecRef and StopTrackingHard.
|
||||
///
|
||||
/// The models the effect that the called function decrements the reference
|
||||
/// count of the argument and all typestate tracking on that argument
|
||||
/// should cease.
|
||||
DecRefAndStopTrackingHard,
|
||||
|
||||
/// Performs the combined functionality of DecRefMsg and StopTrackingHard.
|
||||
///
|
||||
/// The models the effect that the called function decrements the reference
|
||||
/// count of the argument and all typestate tracking on that argument
|
||||
/// should cease.
|
||||
DecRefMsgAndStopTrackingHard
|
||||
};
|
||||
|
||||
/// RetEffect summarizes a call's retain/release behavior with respect
|
||||
/// to its return value.
|
||||
class RetEffect {
|
||||
public:
|
||||
enum Kind {
|
||||
/// Indicates that no retain count information is tracked for
|
||||
/// the return value.
|
||||
NoRet,
|
||||
/// Indicates that the returned value is an owned (+1) symbol.
|
||||
OwnedSymbol,
|
||||
/// Indicates that the returned value is an object with retain count
|
||||
/// semantics but that it is not owned (+0). This is the default
|
||||
/// for getters, etc.
|
||||
NotOwnedSymbol,
|
||||
/// Indicates that the object is not owned and controlled by the
|
||||
/// Garbage collector.
|
||||
GCNotOwnedSymbol,
|
||||
/// Indicates that the return value is an owned object when the
|
||||
/// receiver is also a tracked object.
|
||||
OwnedWhenTrackedReceiver,
|
||||
// Treat this function as returning a non-tracked symbol even if
|
||||
// the function has been inlined. This is used where the call
|
||||
// site summary is more presise than the summary indirectly produced
|
||||
// by inlining the function
|
||||
NoRetHard
|
||||
};
|
||||
|
||||
/// Determines the object kind of a tracked object.
|
||||
enum ObjKind {
|
||||
/// Indicates that the tracked object is a CF object. This is
|
||||
/// important between GC and non-GC code.
|
||||
CF,
|
||||
/// Indicates that the tracked object is an Objective-C object.
|
||||
ObjC,
|
||||
/// Indicates that the tracked object could be a CF or Objective-C object.
|
||||
AnyObj,
|
||||
/// Indicates that the tracked object is a generalized object.
|
||||
Generalized
|
||||
};
|
||||
|
||||
private:
|
||||
Kind K;
|
||||
ObjKind O;
|
||||
|
||||
RetEffect(Kind k, ObjKind o = AnyObj) : K(k), O(o) {}
|
||||
|
||||
public:
|
||||
Kind getKind() const { return K; }
|
||||
|
||||
ObjKind getObjKind() const { return O; }
|
||||
|
||||
bool isOwned() const {
|
||||
return K == OwnedSymbol || K == OwnedWhenTrackedReceiver;
|
||||
}
|
||||
|
||||
bool notOwned() const {
|
||||
return K == NotOwnedSymbol;
|
||||
}
|
||||
|
||||
bool operator==(const RetEffect &Other) const {
|
||||
return K == Other.K && O == Other.O;
|
||||
}
|
||||
|
||||
static RetEffect MakeOwnedWhenTrackedReceiver() {
|
||||
return RetEffect(OwnedWhenTrackedReceiver, ObjC);
|
||||
}
|
||||
|
||||
static RetEffect MakeOwned(ObjKind o) {
|
||||
return RetEffect(OwnedSymbol, o);
|
||||
}
|
||||
static RetEffect MakeNotOwned(ObjKind o) {
|
||||
return RetEffect(NotOwnedSymbol, o);
|
||||
}
|
||||
static RetEffect MakeGCNotOwned() {
|
||||
return RetEffect(GCNotOwnedSymbol, ObjC);
|
||||
}
|
||||
static RetEffect MakeNoRet() {
|
||||
return RetEffect(NoRet);
|
||||
}
|
||||
static RetEffect MakeNoRetHard() {
|
||||
return RetEffect(NoRetHard);
|
||||
}
|
||||
};
|
||||
|
||||
/// Encapsulates the retain count semantics on the arguments, return value,
|
||||
/// and receiver (if any) of a function/method call.
|
||||
///
|
||||
/// Note that construction of these objects is not highly efficient. That
|
||||
/// is okay for clients where creating these objects isn't really a bottleneck.
|
||||
/// The purpose of the API is to provide something simple. The actual
|
||||
/// static analyzer checker that implements retain/release typestate
|
||||
/// tracking uses something more efficient.
|
||||
class CallEffects {
|
||||
llvm::SmallVector<ArgEffect, 10> Args;
|
||||
RetEffect Ret;
|
||||
ArgEffect Receiver;
|
||||
|
||||
CallEffects(const RetEffect &R) : Ret(R) {}
|
||||
|
||||
public:
|
||||
/// Returns the argument effects for a call.
|
||||
ArrayRef<ArgEffect> getArgs() const { return Args; }
|
||||
|
||||
/// Returns the effects on the receiver.
|
||||
ArgEffect getReceiver() const { return Receiver; }
|
||||
|
||||
/// Returns the effect on the return value.
|
||||
RetEffect getReturnValue() const { return Ret; }
|
||||
|
||||
/// Return the CallEfect for a given Objective-C method.
|
||||
static CallEffects getEffect(const ObjCMethodDecl *MD);
|
||||
|
||||
/// Return the CallEfect for a given C/C++ function.
|
||||
static CallEffects getEffect(const FunctionDecl *FD);
|
||||
};
|
||||
namespace retaincountchecker {
|
||||
|
||||
/// A key identifying a summary.
|
||||
class ObjCSummaryKey {
|
||||
|
@ -260,10 +68,12 @@ public:
|
|||
Selector getSelector() const { return S; }
|
||||
};
|
||||
|
||||
} // end namespace retaincountchecker
|
||||
} // end namespace ento
|
||||
} // end namespace clang
|
||||
|
||||
namespace llvm {
|
||||
using namespace retaincountchecker;
|
||||
|
||||
template <> struct FoldingSetTrait<ArgEffect> {
|
||||
static inline void Profile(const ArgEffect X, FoldingSetNodeID &ID) {
|
||||
|
@ -306,6 +116,7 @@ template <> struct DenseMapInfo<ObjCSummaryKey> {
|
|||
|
||||
namespace clang {
|
||||
namespace ento {
|
||||
namespace retaincountchecker {
|
||||
|
||||
/// ArgEffects summarizes the effects of a function/method call on all of
|
||||
/// its arguments.
|
||||
|
@ -388,12 +199,12 @@ public:
|
|||
return Args.isEmpty();
|
||||
}
|
||||
|
||||
ArgEffects getArgEffects() const { return Args; }
|
||||
|
||||
private:
|
||||
ArgEffects getArgEffects() const { return Args; }
|
||||
ArgEffect getDefaultArgEffect() const { return DefaultArgEffect; }
|
||||
|
||||
friend class RetainSummaryManager;
|
||||
friend class RetainCountChecker;
|
||||
};
|
||||
|
||||
class ObjCSummaryCache {
|
||||
|
@ -588,9 +399,6 @@ class RetainSummaryManager {
|
|||
addMethodSummary(II, ObjCClassMethodSummaries, Summ, Kws...);
|
||||
}
|
||||
|
||||
const RetainSummary * generateSummary(const FunctionDecl *FD,
|
||||
bool &AllowAnnotations);
|
||||
|
||||
public:
|
||||
RetainSummaryManager(ASTContext &ctx, bool usesARC)
|
||||
: Ctx(ctx),
|
||||
|
@ -611,7 +419,7 @@ public:
|
|||
bool isTrustedReferenceCountImplementation(const FunctionDecl *FD);
|
||||
|
||||
const RetainSummary *getSummary(const CallEvent &Call,
|
||||
QualType ReceiverType=QualType());
|
||||
ProgramStateRef State = nullptr);
|
||||
|
||||
const RetainSummary *getFunctionSummary(const FunctionDecl *FD);
|
||||
|
||||
|
@ -620,9 +428,8 @@ public:
|
|||
QualType RetTy,
|
||||
ObjCMethodSummariesTy &CachedSummaries);
|
||||
|
||||
const RetainSummary *
|
||||
getInstanceMethodSummary(const ObjCMethodCall &M,
|
||||
QualType ReceiverType);
|
||||
const RetainSummary *getInstanceMethodSummary(const ObjCMethodCall &M,
|
||||
ProgramStateRef State);
|
||||
|
||||
const RetainSummary *getClassMethodSummary(const ObjCMethodCall &M) {
|
||||
assert(!M.isInstanceMessage());
|
||||
|
@ -668,6 +475,10 @@ public:
|
|||
|
||||
RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
|
||||
|
||||
private:
|
||||
const RetainSummary * generateSummary(const FunctionDecl *FD,
|
||||
bool &AllowAnnotations);
|
||||
|
||||
friend class RetainSummaryTemplate;
|
||||
};
|
||||
|
||||
|
@ -700,6 +511,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
} // end namespace retaincountchecker
|
||||
} // end namespace ento
|
||||
} // end namespace clang
|
||||
|
|
@ -33,6 +33,13 @@ static inline void lazyInitKeywordSelector(Selector &Sel, ASTContext &Ctx,
|
|||
Sel = getKeywordSelector(Ctx, IIs...);
|
||||
}
|
||||
|
||||
static inline void lazyInitNullarySelector(Selector &Sel, ASTContext &Ctx,
|
||||
const char *Name) {
|
||||
if (!Sel.isNull())
|
||||
return;
|
||||
Sel = GetNullarySelector(Name, Ctx);
|
||||
}
|
||||
|
||||
} // end namespace ento
|
||||
} // end namespace clang
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangSACheckers.h"
|
||||
#include "clang/StaticAnalyzer/Checkers/SelectorExtras.h"
|
||||
#include "SelectorExtras.h"
|
||||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
|
||||
|
|
Loading…
Reference in New Issue