diff options
author | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2018-08-18 03:22:11 +0000 |
---|---|---|
committer | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2018-08-18 03:22:11 +0000 |
commit | e6554b83e1b0d110f74b77594770e483dcc62e4f (patch) | |
tree | 2fe2ab90da7d1b889d4e210c5d6b85933eeeafea | |
parent | a786521fa66c72edd308baff0c08961b6d964fb1 (diff) |
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
^
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@340117 91177308-0d34-0410-b5e6-96231b3b80d8
14 files changed, 335 insertions, 270 deletions
diff --git a/include/clang/Analysis/ObjCRetainCount.h b/include/clang/Analysis/ObjCRetainCount.h new file mode 100644 index 0000000000..9dff1ea12a --- /dev/null +++ b/include/clang/Analysis/ObjCRetainCount.h @@ -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 + diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt index 619328ca5c..b716a20fe6 100644 --- a/lib/ARCMigrate/CMakeLists.txt +++ b/lib/ARCMigrate/CMakeLists.txt @@ -34,4 +34,5 @@ add_clang_library(clangARCMigrate clangRewrite clangSema clangSerialization + clangStaticAnalyzerCheckers ) diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp index 29cdb6f532..7353c8c479 100644 --- a/lib/ARCMigrate/ObjCMT.cpp +++ b/lib/ARCMigrate/ObjCMT.cpp @@ -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 { diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 818ea16aa7..432067d981 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -24,7 +24,6 @@ add_clang_library(clangAnalysis ProgramPoint.cpp PseudoConstantAnalysis.cpp ReachableCode.cpp - RetainSummaryManager.cpp ScanfFormatString.cpp ThreadSafety.cpp ThreadSafetyCommon.cpp diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 0e0dc76baf..cff0f0a29b 100644 --- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.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" diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt index 25cd526e5c..0b2aab94da 100644 --- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -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 diff --git a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp index 8a973bb6c1..8a5c769b6b 100644 --- a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.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" diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp index 9d6c8314d8..a8957e1704 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -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); @@ -1399,6 +1388,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. //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h index 6d90655d3d..9946591c4d 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h @@ -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 { diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h index 8634c37c34..cbdfe3a916 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h @@ -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" diff --git a/lib/Analysis/RetainSummaryManager.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountSummaries.cpp index ba2fce40c5..18813741f2 100644 --- a/lib/Analysis/RetainSummaryManager.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountSummaries.cpp @@ -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; -} diff --git a/include/clang/Analysis/RetainSummaryManager.h b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountSummaries.h index b13dc98637..dd56a44858 100644 --- a/include/clang/Analysis/RetainSummaryManager.h +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountSummaries.h @@ -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 diff --git a/include/clang/StaticAnalyzer/Checkers/SelectorExtras.h b/lib/StaticAnalyzer/Checkers/SelectorExtras.h index 093eea2279..b11d070c62 100644 --- a/include/clang/StaticAnalyzer/Checkers/SelectorExtras.h +++ b/lib/StaticAnalyzer/Checkers/SelectorExtras.h @@ -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 diff --git a/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp b/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp index b28e604b30..f42c78a769 100644 --- a/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp @@ -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" |