34 #include "llvm/ADT/DenseMap.h" 35 #include "llvm/ADT/FoldingSet.h" 36 #include "llvm/ADT/ImmutableList.h" 37 #include "llvm/ADT/ImmutableMap.h" 38 #include "llvm/ADT/STLExtras.h" 39 #include "llvm/ADT/SmallString.h" 40 #include "llvm/ADT/StringExtras.h" 44 using namespace clang;
46 using namespace objc_retain;
47 using llvm::StrInStrNoCase;
56 ID.AddInteger((
unsigned) X);
61 ID.AddInteger((
unsigned) X.
getKind());
102 enum class IvarAccessHistory {
105 ReleasedAfterDirectAccess
119 unsigned RawKind : 5;
124 unsigned RawObjectKind : 2;
135 unsigned RawIvarAccessHistory : 2;
138 IvarAccessHistory IvarAccess)
139 : Cnt(cnt), ACnt(acnt),
T(t), RawKind(static_cast<unsigned>(k)),
140 RawObjectKind(static_cast<unsigned>(o)),
141 RawIvarAccessHistory(static_cast<unsigned>(IvarAccess)) {
142 assert(
getKind() == k &&
"not enough bits for the kind");
143 assert(getObjKind() == o &&
"not enough bits for the object kind");
144 assert(getIvarAccessHistory() == IvarAccess &&
"not enough bits");
154 unsigned getCount()
const {
return Cnt; }
155 unsigned getAutoreleaseCount()
const {
return ACnt; }
156 unsigned getCombinedCounts()
const {
return Cnt + ACnt; }
161 void setCount(
unsigned i) {
164 void setAutoreleaseCount(
unsigned i) {
175 IvarAccessHistory getIvarAccessHistory()
const {
176 return static_cast<IvarAccessHistory
>(RawIvarAccessHistory);
179 bool isOwned()
const {
183 bool isNotOwned()
const {
187 bool isReturnedOwned()
const {
188 return getKind() == ReturnedOwned;
191 bool isReturnedNotOwned()
const {
192 return getKind() == ReturnedNotOwned;
200 unsigned Count = 1) {
209 unsigned Count = 0) {
213 RefVal operator-(
size_t i)
const {
214 return RefVal(
getKind(), getObjKind(), getCount() - i,
215 getAutoreleaseCount(), getType(), getIvarAccessHistory());
218 RefVal operator+(
size_t i)
const {
219 return RefVal(
getKind(), getObjKind(), getCount() + i,
220 getAutoreleaseCount(), getType(), getIvarAccessHistory());
223 RefVal operator^(
Kind k)
const {
224 return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(),
225 getType(), getIvarAccessHistory());
228 RefVal autorelease()
const {
229 return RefVal(
getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1,
230 getType(), getIvarAccessHistory());
233 RefVal withIvarAccess()
const {
235 return RefVal(
getKind(), getObjKind(), getCount(), getAutoreleaseCount(),
236 getType(), IvarAccessHistory::AccessedDirectly);
239 RefVal releaseViaIvar()
const {
240 assert(getIvarAccessHistory() == IvarAccessHistory::AccessedDirectly);
241 return RefVal(
getKind(), getObjKind(), getCount(), getAutoreleaseCount(),
242 getType(), IvarAccessHistory::ReleasedAfterDirectAccess);
247 bool hasSameState(
const RefVal &
X)
const {
248 return getKind() == X.getKind() && Cnt == X.Cnt && ACnt == X.ACnt &&
249 getIvarAccessHistory() == X.getIvarAccessHistory();
253 return T == X.T && hasSameState(X) && getObjKind() == X.getObjKind();
256 void Profile(llvm::FoldingSetNodeID&
ID)
const {
258 ID.AddInteger(RawKind);
261 ID.AddInteger(RawObjectKind);
262 ID.AddInteger(RawIvarAccessHistory);
265 void print(raw_ostream &Out)
const;
268 void RefVal::print(raw_ostream &Out)
const {
270 Out <<
"Tracked " <<
T.getAsString() <<
'/';
273 default: llvm_unreachable(
"Invalid RefVal kind");
276 unsigned cnt = getCount();
277 if (cnt) Out <<
" (+ " << cnt <<
")";
283 unsigned cnt = getCount();
284 if (cnt) Out <<
" (+ " << cnt <<
")";
288 case ReturnedOwned: {
289 Out <<
"ReturnedOwned";
290 unsigned cnt = getCount();
291 if (cnt) Out <<
" (+ " << cnt <<
")";
295 case ReturnedNotOwned: {
296 Out <<
"ReturnedNotOwned";
297 unsigned cnt = getCount();
298 if (cnt) Out <<
" (+ " << cnt <<
")";
307 Out <<
"-dealloc (GC)";
310 case ErrorDeallocNotOwned:
311 Out <<
"-dealloc (not-owned)";
318 case ErrorLeakReturned:
319 Out <<
"Leaked (Bad naming)";
322 case ErrorGCLeakReturned:
323 Out <<
"Leaked (GC-ed at return)";
326 case ErrorUseAfterRelease:
327 Out <<
"Use-After-Release [ERROR]";
330 case ErrorReleaseNotOwned:
331 Out <<
"Release of Not-Owned [ERROR]";
334 case RefVal::ErrorOverAutorelease:
335 Out <<
"Over-autoreleased";
338 case RefVal::ErrorReturnedNotOwned:
339 Out <<
"Non-owned object returned instead of owned";
343 switch (getIvarAccessHistory()) {
346 case IvarAccessHistory::AccessedDirectly:
347 Out <<
" [direct ivar access]";
349 case IvarAccessHistory::ReleasedAfterDirectAccess:
350 Out <<
" [released after direct ivar access]";
354 Out <<
" [autorelease -" << ACnt <<
']';
367 return State->get<RefBindings>(Sym);
372 return State->set<RefBindings>(Sym, Val);
376 return State->remove<RefBindings>(Sym);
384 class RetainSummary {
405 : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), Ret(R) {}
410 if (
const ArgEffect *AE = Args.lookup(idx))
413 return DefaultArgEffect;
416 void addArg(ArgEffects::Factory &af,
unsigned idx,
ArgEffect e) {
417 Args = af.add(Args, idx, e);
422 DefaultArgEffect = E;
426 RetEffect getRetEffect()
const {
return Ret; }
429 void setRetEffect(
RetEffect E) { Ret = E; }
433 void setReceiverEffect(
ArgEffect e) { Receiver = e; }
437 ArgEffect getReceiverEffect()
const {
return Receiver; }
442 bool operator==(
const RetainSummary &Other)
const {
443 return Args == Other.Args && DefaultArgEffect == Other.DefaultArgEffect &&
444 Receiver == Other.Receiver && Ret == Other.Ret;
448 void Profile(llvm::FoldingSetNodeID&
ID)
const {
450 ID.Add(DefaultArgEffect);
456 bool isSimple()
const {
457 return Args.isEmpty();
461 ArgEffects getArgEffects()
const {
return Args; }
462 ArgEffect getDefaultArgEffect()
const {
return DefaultArgEffect; }
464 friend class RetainSummaryManager;
465 friend class RetainCountChecker;
474 class ObjCSummaryKey {
485 : II(
nullptr), S(s) {}
488 Selector getSelector()
const {
return S; }
505 typedef std::pair<IdentifierInfo*, Selector> PairTy;
510 static bool isEqual(
const ObjCSummaryKey& LHS,
const ObjCSummaryKey& RHS) {
511 return LHS.getIdentifier() == RHS.getIdentifier() &&
512 LHS.getSelector() == RHS.getSelector();
519 class ObjCSummaryCache {
520 typedef llvm::DenseMap<ObjCSummaryKey, const RetainSummary *>
MapTy;
523 ObjCSummaryCache() {}
528 ObjCSummaryKey K(D, S);
529 MapTy::iterator I = M.find(K);
543 if ((I = M.find(ObjCSummaryKey(C, S))) != M.end())
552 const RetainSummary *Summ = I->second;
560 MapTy::iterator I = M.find(ObjCSummaryKey(II, S));
563 I = M.find(ObjCSummaryKey(S));
565 return I == M.end() ? nullptr : I->second;
568 const RetainSummary *& operator[](ObjCSummaryKey K) {
572 const RetainSummary *& operator[](
Selector S) {
573 return M[ ObjCSummaryKey(S) ];
583 class RetainSummaryManager {
589 typedef llvm::DenseMap<const FunctionDecl*, const RetainSummary *>
592 typedef ObjCSummaryCache ObjCMethodSummariesTy;
594 typedef llvm::FoldingSetNodeWrapper<RetainSummary> CachedSummaryNode;
604 const bool GCEnabled;
607 const bool ARCEnabled;
610 FuncSummariesTy FuncSummaries;
614 ObjCMethodSummariesTy ObjCClassMethodSummaries;
617 ObjCMethodSummariesTy ObjCMethodSummaries;
621 llvm::BumpPtrAllocator BPAlloc;
624 ArgEffects::Factory AF;
639 llvm::FoldingSet<CachedSummaryNode> SimpleSummaries;
649 enum UnaryFuncKind { cfretain, cfrelease, cfautorelease, cfmakecollectable };
651 const RetainSummary *getUnarySummary(
const FunctionType* FT,
654 const RetainSummary *getCFSummaryCreateRule(
const FunctionDecl *FD);
655 const RetainSummary *getCFSummaryGetRule(
const FunctionDecl *FD);
656 const RetainSummary *getCFCreateGetRuleSummary(
const FunctionDecl *FD);
658 const RetainSummary *getPersistentSummary(
const RetainSummary &OldSumm);
660 const RetainSummary *getPersistentSummary(
RetEffect RetEff,
663 RetainSummary Summ(getArgEffects(), RetEff, DefaultEff, ReceiverEff);
664 return getPersistentSummary(Summ);
667 const RetainSummary *getDoNothingSummary() {
671 const RetainSummary *getDefaultSummary() {
676 const RetainSummary *getPersistentStopSummary() {
681 void InitializeClassMethodSummaries();
682 void InitializeMethodSummaries();
684 void addNSObjectClsMethSummary(
Selector S,
const RetainSummary *Summ) {
685 ObjCClassMethodSummaries[S] = Summ;
688 void addNSObjectMethSummary(
Selector S,
const RetainSummary *Summ) {
689 ObjCMethodSummaries[S] = Summ;
692 void addClassMethSummary(
const char* Cls,
const char* name,
693 const RetainSummary *Summ,
bool isNullary =
true) {
697 ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
700 void addInstMethSummary(
const char* Cls,
const char* nullaryName,
701 const RetainSummary *Summ) {
704 ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
707 template <
typename... Keywords>
708 void addMethodSummary(
IdentifierInfo *ClsII, ObjCMethodSummariesTy &Summaries,
709 const RetainSummary *Summ, Keywords *... Kws) {
711 Summaries[ObjCSummaryKey(ClsII, S)] = Summ;
714 template <
typename... Keywords>
715 void addInstMethSummary(
const char *Cls,
const RetainSummary *Summ,
717 addMethodSummary(&Ctx.
Idents.
get(Cls), ObjCMethodSummaries, Summ, Kws...);
720 template <
typename... Keywords>
721 void addClsMethSummary(
const char *Cls,
const RetainSummary *Summ,
723 addMethodSummary(&Ctx.
Idents.
get(Cls), ObjCClassMethodSummaries, Summ,
727 template <
typename... Keywords>
728 void addClsMethSummary(
IdentifierInfo *II,
const RetainSummary *Summ,
730 addMethodSummary(II, ObjCClassMethodSummaries, Summ, Kws...);
735 RetainSummaryManager(
ASTContext &ctx,
bool gcenabled,
bool usesARC)
737 GCEnabled(gcenabled),
739 AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
740 ObjCAllocRetE(gcenabled
744 ObjCInitRetE(gcenabled
748 InitializeClassMethodSummaries();
749 InitializeMethodSummaries();
752 const RetainSummary *getSummary(
const CallEvent &Call,
755 const RetainSummary *getFunctionSummary(
const FunctionDecl *FD);
760 ObjCMethodSummariesTy &CachedSummaries);
762 const RetainSummary *getInstanceMethodSummary(
const ObjCMethodCall &M,
765 const RetainSummary *getClassMethodSummary(
const ObjCMethodCall &M) {
770 M.getResultType(), ObjCClassMethodSummaries);
780 ObjCMethodSummariesTy *CachedSummaries;
782 CachedSummaries = &ObjCMethodSummaries;
784 CachedSummaries = &ObjCClassMethodSummaries;
786 return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries);
789 const RetainSummary *getStandardMethodSummary(
const ObjCMethodDecl *MD,
796 void updateSummaryFromAnnotations(
const RetainSummary *&Summ,
799 void updateSummaryFromAnnotations(
const RetainSummary *&Summ,
802 void updateSummaryForCall(
const RetainSummary *&Summ,
805 bool isGCEnabled()
const {
return GCEnabled; }
807 bool isARCEnabled()
const {
return ARCEnabled; }
809 bool isARCorGCEnabled()
const {
return GCEnabled || ARCEnabled; }
811 RetEffect getObjAllocRetEffect()
const {
return ObjCAllocRetE; }
813 friend class RetainSummaryTemplate;
820 class RetainSummaryTemplate {
821 RetainSummaryManager &Manager;
822 const RetainSummary *&RealSummary;
823 RetainSummary ScratchSummary;
826 RetainSummaryTemplate(
const RetainSummary *&real, RetainSummaryManager &mgr)
827 : Manager(mgr), RealSummary(real), ScratchSummary(*real), Accessed(
false) {}
829 ~RetainSummaryTemplate() {
831 RealSummary = Manager.getPersistentSummary(ScratchSummary);
836 return ScratchSummary;
839 RetainSummary *operator->() {
841 return &ScratchSummary;
851 ArgEffects RetainSummaryManager::getArgEffects() {
853 ScratchArgs = AF.getEmptyMap();
857 const RetainSummary *
858 RetainSummaryManager::getPersistentSummary(
const RetainSummary &OldSumm) {
860 if (OldSumm.isSimple()) {
861 llvm::FoldingSetNodeID
ID;
865 CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos);
868 N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>();
869 new (N) CachedSummaryNode(OldSumm);
870 SimpleSummaries.InsertNode(N, Pos);
873 return &N->getValue();
876 RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();
877 new (Summ) RetainSummary(OldSumm);
886 return FName.endswith(
"Retain");
890 return FName.endswith(
"Release");
894 return FName.endswith(
"Autorelease");
900 return FName.find(
"MakeCollectable") != StringRef::npos;
927 llvm_unreachable(
"Unknown ArgEffect kind");
930 void RetainSummaryManager::updateSummaryForCall(
const RetainSummary *&S,
938 ArgEffects CustomArgEffects = S->getArgEffects();
939 for (ArgEffects::iterator I = CustomArgEffects.begin(),
940 E = CustomArgEffects.end();
943 if (Translated != DefEffect)
944 ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
958 if (Name->isStr(
"CGBitmapContextCreateWithData") ||
959 Name->isStr(
"dispatch_data_create"))
960 RE = S->getRetEffect();
964 S = getPersistentSummary(RE, RecEffect, DefEffect);
980 if (MC->getMethodFamily() ==
OMF_init && MC->isReceiverSelfOrSuper()) {
984 const Expr *ME = MC->getOriginExpr();
988 RetainSummaryTemplate ModifiableSummaryTemplate(S, *
this);
989 ModifiableSummaryTemplate->setReceiverEffect(
DoNothing);
996 const RetainSummary *
997 RetainSummaryManager::getSummary(
const CallEvent &Call,
999 const RetainSummary *Summ;
1002 Summ = getFunctionSummary(cast<SimpleFunctionCall>(Call).getDecl());
1011 return getPersistentStopSummary();
1015 Summ = getInstanceMethodSummary(Msg, State);
1017 Summ = getClassMethodSummary(Msg);
1022 updateSummaryForCall(Summ, Call);
1024 assert(Summ &&
"Unknown call type?");
1028 const RetainSummary *
1029 RetainSummaryManager::getFunctionSummary(
const FunctionDecl *FD) {
1032 return getDefaultSummary();
1035 FuncSummariesTy::iterator I = FuncSummaries.find(FD);
1036 if (I != FuncSummaries.end())
1040 const RetainSummary *S =
nullptr;
1041 bool AllowAnnotations =
true;
1046 S = getPersistentStopSummary();
1057 StringRef FName = II->
getName();
1061 FName = FName.substr(FName.find_first_not_of(
'_'));
1069 assert(ScratchArgs.isEmpty());
1071 if (FName ==
"pthread_create" || FName ==
"pthread_setspecific") {
1074 S = getPersistentStopSummary();
1075 }
else if (FName ==
"NSMakeCollectable") {
1078 ? getUnarySummary(FT, cfmakecollectable)
1079 : getPersistentStopSummary();
1082 AllowAnnotations =
false;
1083 }
else if (FName ==
"CFPlugInInstanceCreate") {
1085 }
else if (FName ==
"IORegistryEntrySearchCFProperty" 1086 || (RetTyName ==
"CFMutableDictionaryRef" && (
1087 FName ==
"IOBSDNameMatching" ||
1088 FName ==
"IOServiceMatching" ||
1089 FName ==
"IOServiceNameMatching" ||
1090 FName ==
"IORegistryEntryIDMatching" ||
1091 FName ==
"IOOpenFirmwarePathMatching" 1097 }
else if (FName ==
"IOServiceGetMatchingService" ||
1098 FName ==
"IOServiceGetMatchingServices") {
1102 ScratchArgs = AF.add(ScratchArgs, 1,
DecRef);
1104 }
else if (FName ==
"IOServiceAddNotification" ||
1105 FName ==
"IOServiceAddMatchingNotification") {
1108 ScratchArgs = AF.add(ScratchArgs, 2,
DecRef);
1110 }
else if (FName ==
"CVPixelBufferCreateWithBytes") {
1119 }
else if (FName ==
"CGBitmapContextCreateWithData") {
1127 }
else if (FName ==
"CVPixelBufferCreateWithPlanarBytes") {
1135 }
else if (FName ==
"VTCompressionSessionEncodeFrame") {
1143 }
else if (FName ==
"dispatch_set_context" ||
1144 FName ==
"xpc_connection_set_context") {
1153 }
else if (FName.startswith(
"NSLog")) {
1154 S = getDoNothingSummary();
1155 }
else if (FName.startswith(
"NS") &&
1156 (FName.find(
"Insert") != StringRef::npos)) {
1172 S = getUnarySummary(FT, cfretain);
1177 AllowAnnotations =
false;
1179 S = getUnarySummary(FT, cfautorelease);
1182 AllowAnnotations =
false;
1184 S = getUnarySummary(FT, cfmakecollectable);
1185 AllowAnnotations =
false;
1187 S = getCFCreateGetRuleSummary(FD);
1197 S = getUnarySummary(FT, cfretain);
1199 S = getCFCreateGetRuleSummary(FD);
1208 S = getCFCreateGetRuleSummary(FD);
1212 if (FD->
hasAttr<CFAuditedTransferAttr>()) {
1213 S = getCFCreateGetRuleSummary(FD);
1222 if (FName.size() >= 2 &&
1223 FName[0] ==
'C' && (FName[1] ==
'F' || FName[1] ==
'G')) {
1225 FName = FName.substr(FName.startswith(
"CGCF") ? 4 : 2);
1228 S = getUnarySummary(FT, cfrelease);
1230 assert (ScratchArgs.isEmpty());
1246 ArgEffect E = (StrInStrNoCase(FName,
"InsertValue") != StringRef::npos||
1247 StrInStrNoCase(FName,
"AddValue") != StringRef::npos ||
1248 StrInStrNoCase(FName,
"SetValue") != StringRef::npos ||
1249 StrInStrNoCase(FName,
"AppendValue") != StringRef::npos||
1250 StrInStrNoCase(FName,
"SetAttribute") != StringRef::npos)
1261 S = getDefaultSummary();
1264 if (AllowAnnotations)
1265 updateSummaryFromAnnotations(S, FD);
1267 FuncSummaries[FD] = S;
1271 const RetainSummary *
1272 RetainSummaryManager::getCFCreateGetRuleSummary(
const FunctionDecl *FD) {
1274 return getCFSummaryCreateRule(FD);
1276 return getCFSummaryGetRule(FD);
1279 const RetainSummary *
1280 RetainSummaryManager::getUnarySummary(
const FunctionType* FT,
1281 UnaryFuncKind func) {
1287 return getPersistentStopSummary();
1289 assert (ScratchArgs.isEmpty());
1293 case cfretain: Effect =
IncRef;
break;
1294 case cfrelease: Effect =
DecRef;
break;
1299 ScratchArgs = AF.add(ScratchArgs, 0, Effect);
1303 const RetainSummary *
1304 RetainSummaryManager::getCFSummaryCreateRule(
const FunctionDecl *FD) {
1305 assert (ScratchArgs.isEmpty());
1310 const RetainSummary *
1311 RetainSummaryManager::getCFSummaryGetRule(
const FunctionDecl *FD) {
1312 assert (ScratchArgs.isEmpty());
1320 if (Ann->getAnnotation() == rcAnnotation)
1344 RetainSummaryManager::getRetEffectFromAnnotations(
QualType RetTy,
1347 if (D->
hasAttr<NSReturnsRetainedAttr>())
1348 return ObjCAllocRetE;
1350 if (D->
hasAttr<NSReturnsNotRetainedAttr>() ||
1351 D->
hasAttr<NSReturnsAutoreleasedAttr>())
1358 if (D->
hasAttr<CFReturnsRetainedAttr>())
1363 if (D->
hasAttr<CFReturnsNotRetainedAttr>())
1370 RetainSummaryManager::updateSummaryFromAnnotations(
const RetainSummary *&Summ,
1375 assert(Summ &&
"Must have a summary to add annotations to.");
1376 RetainSummaryTemplate Template(Summ, *
this);
1379 unsigned parm_idx = 0;
1381 pe = FD->
param_end(); pi != pe; ++pi, ++parm_idx) {
1383 if (pd->
hasAttr<NSConsumedAttr>())
1384 Template->addArg(AF, parm_idx,
DecRefMsg);
1385 else if (pd->
hasAttr<CFConsumedAttr>() ||
1387 Template->addArg(AF, parm_idx,
DecRef);
1388 else if (pd->
hasAttr<CFReturnsRetainedAttr>() ||
1394 }
else if (pd->
hasAttr<CFReturnsNotRetainedAttr>()) {
1404 Template->setRetEffect(*RetE);
1408 RetainSummaryManager::updateSummaryFromAnnotations(
const RetainSummary *&Summ,
1413 assert(Summ &&
"Must have a valid summary to add annotations to");
1414 RetainSummaryTemplate Template(Summ, *
this);
1417 if (MD->
hasAttr<NSConsumesSelfAttr>())
1421 unsigned parm_idx = 0;
1424 pi != pe; ++pi, ++parm_idx) {
1426 if (pd->
hasAttr<NSConsumedAttr>())
1427 Template->addArg(AF, parm_idx,
DecRefMsg);
1428 else if (pd->
hasAttr<CFConsumedAttr>()) {
1429 Template->addArg(AF, parm_idx,
DecRef);
1430 }
else if (pd->
hasAttr<CFReturnsRetainedAttr>()) {
1435 }
else if (pd->
hasAttr<CFReturnsNotRetainedAttr>()) {
1445 Template->setRetEffect(*RetE);
1448 const RetainSummary *
1449 RetainSummaryManager::getStandardMethodSummary(
const ObjCMethodDecl *MD,
1488 ResultEff = ObjCInitRetE;
1496 ResultEff = ObjCAllocRetE;
1526 for (
unsigned i = 0, e = S.
getNumArgs(); i != e; ++i) {
1528 if (Slot.substr(Slot.size() - 8).equals_lower(
"delegate")) {
1529 if (ResultEff == ObjCInitRetE)
1537 if (ScratchArgs.isEmpty() && ReceiverEff ==
DoNothing &&
1539 return getDefaultSummary();
1541 return getPersistentSummary(ResultEff, ReceiverEff,
MayEscape);
1544 const RetainSummary *
1545 RetainSummaryManager::getInstanceMethodSummary(
const ObjCMethodCall &Msg,
1559 ReceiverClass = PT->getInterfaceDecl();
1571 if (!Method && ReceiverClass)
1574 return getMethodSummary(S, ReceiverClass, Method, Msg.getResultType(),
1575 ObjCMethodSummaries);
1578 const RetainSummary *
1581 ObjCMethodSummariesTy &CachedSummaries) {
1584 const RetainSummary *Summ = CachedSummaries.find(ID, S);
1587 Summ = getStandardMethodSummary(MD, S, RetTy);
1590 updateSummaryFromAnnotations(Summ, MD);
1593 CachedSummaries[ObjCSummaryKey(ID, S)] = Summ;
1599 void RetainSummaryManager::InitializeClassMethodSummaries() {
1600 assert(ScratchArgs.isEmpty());
1602 addClassMethSummary(
"NSAssertionHandler",
"currentHandler",
1606 ScratchArgs = AF.add(ScratchArgs, 0,
Autorelease);
1607 addClassMethSummary(
"NSAutoreleasePool",
"addObject",
1612 void RetainSummaryManager::InitializeMethodSummaries() {
1614 assert (ScratchArgs.isEmpty());
1618 const RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE,
DecRefMsg);
1627 const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE);
1628 const RetainSummary *CFAllocSumm =
1633 const RetainSummary *Summ = getPersistentSummary(NoRet,
IncRefMsg);
1637 Summ = getPersistentSummary(NoRet,
DecRefMsg);
1641 Summ = getPersistentSummary(NoRet,
Dealloc);
1658 addClassMethSummary(
"NSWindow",
"alloc", NoTrackYet);
1664 addClassMethSummary(
"NSPanel",
"alloc", NoTrackYet);
1669 addClassMethSummary(
"NSNull",
"null", NoTrackYet);
1673 addClassMethSummary(
"NSAutoreleasePool",
"alloc", NoTrackYet);
1674 addClassMethSummary(
"NSAutoreleasePool",
"allocWithZone", NoTrackYet,
false);
1675 addClassMethSummary(
"NSAutoreleasePool",
"new", NoTrackYet);
1678 addInstMethSummary(
"QCRenderer", AllocSumm,
"createSnapshotImageOfType");
1679 addInstMethSummary(
"QCView", AllocSumm,
"createSnapshotImageOfType");
1684 addInstMethSummary(
"CIContext", CFAllocSumm,
"createCGImage",
"fromRect");
1685 addInstMethSummary(
"CIContext", CFAllocSumm,
"createCGImage",
"fromRect",
1686 "format",
"colorSpace");
1687 addInstMethSummary(
"CIContext", CFAllocSumm,
"createCGLayerWithSize",
"info");
1694 typedef llvm::DenseMap<const ExplodedNode *, const RetainSummary *>
1701 class CFRefBug :
public BugType {
1703 CFRefBug(
const CheckerBase *checker, StringRef name)
1709 virtual const char *getDescription()
const = 0;
1711 virtual bool isLeak()
const {
return false; }
1714 class UseAfterRelease :
public CFRefBug {
1717 : CFRefBug(checker,
"Use-after-release") {}
1719 const char *getDescription()
const override {
1720 return "Reference-counted object is used after it is released";
1724 class BadRelease :
public CFRefBug {
1726 BadRelease(
const CheckerBase *checker) : CFRefBug(checker,
"Bad release") {}
1728 const char *getDescription()
const override {
1729 return "Incorrect decrement of the reference count of an object that is " 1730 "not owned at this point by the caller";
1734 class DeallocGC :
public CFRefBug {
1737 : CFRefBug(checker,
"-dealloc called while using garbage collection") {}
1739 const char *getDescription()
const override {
1740 return "-dealloc called while using garbage collection";
1744 class DeallocNotOwned :
public CFRefBug {
1747 : CFRefBug(checker,
"-dealloc sent to non-exclusively owned object") {}
1749 const char *getDescription()
const override {
1750 return "-dealloc sent to object that may be referenced elsewhere";
1754 class OverAutorelease :
public CFRefBug {
1757 : CFRefBug(checker,
"Object autoreleased too many times") {}
1759 const char *getDescription()
const override {
1760 return "Object autoreleased too many times";
1764 class ReturnedNotOwnedForOwned :
public CFRefBug {
1766 ReturnedNotOwnedForOwned(
const CheckerBase *checker)
1767 : CFRefBug(checker,
"Method should return an owned object") {}
1769 const char *getDescription()
const override {
1770 return "Object with a +0 retain count returned to caller where a +1 " 1771 "(owning) retain count is expected";
1775 class Leak :
public CFRefBug {
1777 Leak(
const CheckerBase *checker, StringRef name) : CFRefBug(checker, name) {
1779 setSuppressOnSink(
true);
1782 const char *getDescription()
const override {
return ""; }
1784 bool isLeak()
const override {
return true; }
1794 const SummaryLogTy &SummaryLog;
1798 CFRefReportVisitor(
SymbolRef sym,
bool gcEnabled,
const SummaryLogTy &
log)
1799 : Sym(sym), SummaryLog(log), GCEnabled(gcEnabled) {}
1801 void Profile(llvm::FoldingSetNodeID &ID)
const override {
1807 std::shared_ptr<PathDiagnosticPiece> VisitNode(
const ExplodedNode *N,
1817 class CFRefLeakReportVisitor :
public CFRefReportVisitor {
1819 CFRefLeakReportVisitor(
SymbolRef sym,
bool GCEnabled,
1820 const SummaryLogTy &
log)
1821 : CFRefReportVisitor(sym, GCEnabled, log) {}
1827 std::unique_ptr<BugReporterVisitor> clone()
const override {
1833 return llvm::make_unique<CFRefLeakReportVisitor>(*this);
1838 void addGCModeDescription(
const LangOptions &LOpts,
bool GCEnabled);
1841 CFRefReport(CFRefBug &D,
const LangOptions &LOpts,
bool GCEnabled,
1843 bool registerVisitor =
true)
1845 if (registerVisitor)
1846 addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, GCEnabled, Log));
1847 addGCModeDescription(LOpts, GCEnabled);
1850 CFRefReport(CFRefBug &D,
const LangOptions &LOpts,
bool GCEnabled,
1853 :
BugReport(D, D.getDescription(), endText, n) {
1854 addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, GCEnabled, Log));
1855 addGCModeDescription(LOpts, GCEnabled);
1858 llvm::iterator_range<ranges_iterator> getRanges()
override {
1859 const CFRefBug& BugTy =
static_cast<CFRefBug&
>(getBugType());
1860 if (!BugTy.isLeak())
1862 return llvm::make_range(ranges_iterator(), ranges_iterator());
1866 class CFRefLeakReport :
public CFRefReport {
1868 const Stmt *AllocStmt;
1875 void createDescription(
CheckerContext &Ctx,
bool GCEnabled,
bool IncludeAllocationLine);
1878 CFRefLeakReport(CFRefBug &D,
const LangOptions &LOpts,
bool GCEnabled,
1881 bool IncludeAllocationLine);
1884 assert(Location.isValid());
1890 void CFRefReport::addGCModeDescription(
const LangOptions &LOpts,
1892 const char *GCModeDescription =
nullptr;
1894 switch (LOpts.getGC()) {
1897 GCModeDescription =
"Code is compiled to only use garbage collection";
1902 GCModeDescription =
"Code is compiled to use reference counts";
1907 GCModeDescription =
"Code is compiled to use either garbage collection " 1908 "(GC) or reference counts (non-GC). The bug occurs " 1912 GCModeDescription =
"Code is compiled to use either garbage collection " 1913 "(GC) or reference counts (non-GC). The bug occurs " 1919 assert(GCModeDescription &&
"invalid/unknown GC mode");
1920 addExtraText(GCModeDescription);
1925 return isa<IntegerLiteral>(E) ||
1926 isa<CharacterLiteral>(E) ||
1927 isa<FloatingLiteral>(E) ||
1928 isa<ObjCBoolLiteralExpr>(E) ||
1929 isa<CXXBoolLiteralExpr>(E);
1935 auto Method = dyn_cast_or_null<ObjCMethodDecl>(SFC->
getDecl());
1936 if (!Method || !Method->isPropertyAccessor())
1942 std::shared_ptr<PathDiagnosticPiece>
1956 if (!CurrT)
return nullptr;
1958 const RefVal &CurrV = *CurrT;
1964 llvm::raw_string_ostream os(sbuf);
1971 if (isa<ObjCIvarRefExpr>(S) &&
1976 if (isa<ObjCArrayLiteral>(S)) {
1977 os <<
"NSArray literal is an object with a +0 retain count";
1979 else if (isa<ObjCDictionaryLiteral>(S)) {
1980 os <<
"NSDictionary literal is an object with a +0 retain count";
1982 else if (
const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) {
1984 os <<
"NSNumber literal is an object with a +0 retain count";
1988 BoxClass = Method->getClassInterface();
1993 os << *BoxClass <<
" b";
1997 os <<
"oxed expression produces an object with a +0 retain count";
2000 else if (isa<ObjCIvarRefExpr>(S)) {
2001 os <<
"Object loaded from instance variable";
2004 if (
const CallExpr *CE = dyn_cast<CallExpr>(S)) {
2006 SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
2008 os <<
"Call to function '" << *FD <<
'\'';
2010 os <<
"function call";
2013 assert(isa<ObjCMessageExpr>(S));
2018 switch (Call->getMessageKind()) {
2032 os <<
" returns a Core Foundation object of type " 2033 << Sym->getType().getAsString() <<
" with a ";
2035 os <<
" returns an object of type " << Sym->getType().getAsString()
2040 if (!isa<ObjCObjectPointerType>(T)) {
2041 os <<
" returns an Objective-C object with a ";
2044 os <<
" returns an instance of " 2049 if (CurrV.isOwned()) {
2050 os <<
"+1 retain count";
2055 "Core Foundation objects are not automatically garbage collected.";
2059 assert (CurrV.isNotOwned());
2060 os <<
"+0 retain count";
2066 return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
2074 if (
const RetainSummary *Summ = SummaryLog.lookup(OrigNode)) {
2079 if (
const CallExpr *CE = dyn_cast<CallExpr>(S)) {
2085 AI!=AE; ++AI, ++i) {
2089 if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym)
2093 AEffects.push_back(Summ->getArg(i));
2097 if (
const Expr *receiver = ME->getInstanceReceiver())
2098 if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx)
2099 .getAsLocSymbol() == Sym) {
2101 AEffects.push_back(Summ->getReceiverEffect());
2108 RefVal PrevV = *PrevT;
2111 if (!GCEnabled && std::find(AEffects.begin(), AEffects.end(),
Dealloc) !=
2114 assert(!PrevV.hasSameState(CurrV) &&
"The state should have changed.");
2117 if (CurrV.getKind() == RefVal::Released) {
2118 assert(CurrV.getCombinedCounts() == 0);
2119 os <<
"Object released by directly sending the '-dealloc' message";
2130 CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee(), LCtx);
2135 assert(!PrevV.hasSameState(CurrV) &&
"The state should have changed.");
2137 os <<
"In GC mode a call to '" << *FD
2138 <<
"' decrements an object's retain count and registers the " 2139 "object with the garbage collector. ";
2141 if (CurrV.getKind() == RefVal::Released) {
2142 assert(CurrV.getCount() == 0);
2143 os <<
"Since it now has a 0 retain count the object can be " 2144 "automatically collected by the garbage collector.";
2147 os <<
"An object must have a 0 retain count to be garbage collected. " 2148 "After this call its retain count is +" << CurrV.getCount()
2152 os <<
"When GC is not enabled a call to '" << *FD
2153 <<
"' has no effect on its argument.";
2160 if (!PrevV.hasSameState(CurrV))
2161 switch (CurrV.getKind()) {
2163 case RefVal::NotOwned:
2164 if (PrevV.getCount() == CurrV.getCount()) {
2166 if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount())
2169 assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount());
2170 os <<
"Object autoreleased";
2174 if (PrevV.getCount() > CurrV.getCount())
2175 os <<
"Reference count decremented.";
2177 os <<
"Reference count incremented.";
2179 if (
unsigned Count = CurrV.getCount())
2180 os <<
" The object now has a +" << Count <<
" retain count.";
2182 if (PrevV.getKind() == RefVal::Released) {
2183 assert(GCEnabled && CurrV.getCount() > 0);
2184 os <<
" The object is not eligible for garbage collection until " 2185 "the retain count reaches 0 again.";
2190 case RefVal::Released:
2191 if (CurrV.getIvarAccessHistory() ==
2192 RefVal::IvarAccessHistory::ReleasedAfterDirectAccess &&
2193 CurrV.getIvarAccessHistory() != PrevV.getIvarAccessHistory()) {
2194 os <<
"Strong instance variable relinquished. ";
2196 os <<
"Object released.";
2199 case RefVal::ReturnedOwned:
2201 if (CurrV.getAutoreleaseCount())
2204 os <<
"Object returned to caller as an owning reference (single " 2205 "retain count transferred to caller)";
2208 case RefVal::ReturnedNotOwned:
2209 os <<
"Object returned to caller with a +0 retain count";
2218 E=AEffects.end(); I != E; ++I) {
2225 os <<
"In GC mode an 'autorelease' has no effect.";
2228 os <<
"In GC mode the 'retain' message has no effect.";
2231 os <<
"In GC mode the 'release' message has no effect.";
2237 if (os.str().empty())
2243 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
2248 if (
const Expr *Exp = dyn_cast_or_null<Expr>(Child))
2249 if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) {
2250 P->addRange(Exp->getSourceRange());
2254 return std::move(P);
2263 struct AllocationInfo {
2270 N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {}
2274 static AllocationInfo
2278 const ExplodedNode *AllocationNodeInCurrentOrParentContext = N;
2279 const MemRegion *FirstBinding =
nullptr;
2315 if (NContext == LeakContext || NContext->
isParentOf(LeakContext))
2316 AllocationNodeInCurrentOrParentContext = N;
2320 if (!InitMethodContext)
2322 const Stmt *CE = CEP->getCallExpr();
2323 if (
const ObjCMessageExpr *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) {
2324 const Stmt *RecExpr = ME->getInstanceReceiver();
2326 SVal RecV = St->getSVal(RecExpr, NContext);
2328 InitMethodContext = CEP->getCalleeContext();
2339 if (InitMethodContext) {
2344 InterestingMethodContext = InitMethodContext;
2349 assert(N &&
"Could not find allocation node");
2351 FirstBinding =
nullptr;
2354 return AllocationInfo(AllocationNodeInCurrentOrParentContext,
2356 InterestingMethodContext);
2359 std::unique_ptr<PathDiagnosticPiece>
2366 std::unique_ptr<PathDiagnosticPiece>
2377 AllocationInfo AllocI =
2380 const MemRegion* FirstBinding = AllocI.R;
2392 llvm::raw_string_ostream os(sbuf);
2394 os <<
"Object leaked: ";
2397 os <<
"object allocated and stored into '" 2398 << FirstBinding->getString() <<
'\'';
2401 os <<
"allocated object";
2407 if (RV->getKind() == RefVal::ErrorLeakReturned) {
2413 os << (isa<ObjCMethodDecl>(D) ?
" is returned from a method " 2414 :
" is returned from a function ");
2416 if (D->
hasAttr<CFReturnsNotRetainedAttr>())
2417 os <<
"that is annotated as CF_RETURNS_NOT_RETAINED";
2418 else if (D->
hasAttr<NSReturnsNotRetainedAttr>())
2419 os <<
"that is annotated as NS_RETURNS_NOT_RETAINED";
2423 os <<
"managed by Automatic Reference Counting";
2426 <<
"') does not start with " 2427 "'copy', 'mutableCopy', 'alloc' or 'new'." 2428 " This violates the naming convention rules" 2429 " given in the Memory Management Guide for Cocoa";
2434 os <<
"whose name ('" << *FD
2435 <<
"') does not contain 'Copy' or 'Create'. This violates the naming" 2436 " convention rules given in the Memory Management Guide for Core" 2441 else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
2444 <<
"' is potentially leaked when using garbage collection. Callers " 2445 "of this method do not expect a returned object with a +1 retain " 2446 "count since they expect the object to be managed by the garbage " 2450 os <<
" is not referenced later in this execution path and has a retain " 2451 "count of +" << RV->getCount();
2453 return llvm::make_unique<PathDiagnosticEventPiece>(L, os.str());
2464 const Decl *PDecl = Region->getDecl();
2465 if (PDecl && isa<ParmVarDecl>(PDecl)) {
2467 Location = ParamLocation;
2468 UniqueingLocation = ParamLocation;
2487 AllocationInfo AllocI =
2490 AllocNode = AllocI.N;
2491 AllocBinding = AllocI.R;
2492 markInteresting(AllocI.InterestingMethodContext);
2501 AllocBinding =
nullptr;
2507 AllocNode->getLocationContext());
2508 Location = AllocLocation;
2512 UniqueingLocation = AllocLocation;
2513 UniqueingDecl = AllocNode->getLocationContext()->getDecl();
2516 void CFRefLeakReport::createDescription(
CheckerContext &Ctx,
bool GCEnabled,
bool IncludeAllocationLine) {
2517 assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid());
2518 Description.clear();
2519 llvm::raw_string_ostream os(Description);
2520 os <<
"Potential leak ";
2522 os <<
"(when using garbage collection) ";
2523 os <<
"of an object";
2526 os <<
" stored into '" << AllocBinding->getString() <<
'\'';
2527 if (IncludeAllocationLine) {
2534 CFRefLeakReport::CFRefLeakReport(CFRefBug &D,
const LangOptions &LOpts,
2535 bool GCEnabled,
const SummaryLogTy &Log,
2538 bool IncludeAllocationLine)
2539 : CFRefReport(D, LOpts, GCEnabled, Log, n, sym,
false) {
2541 deriveAllocLocation(Ctx, sym);
2543 deriveParamLocation(Ctx, sym);
2545 createDescription(Ctx, GCEnabled, IncludeAllocationLine);
2547 addVisitor(llvm::make_unique<CFRefLeakReportVisitor>(sym, GCEnabled, Log));
2555 class RetainCountChecker
2556 :
public Checker< check::Bind,
2559 check::BeginFunction,
2561 check::PostStmt<BlockExpr>,
2562 check::PostStmt<CastExpr>,
2563 check::PostStmt<ObjCArrayLiteral>,
2564 check::PostStmt<ObjCDictionaryLiteral>,
2565 check::PostStmt<ObjCBoxedExpr>,
2566 check::PostStmt<ObjCIvarRefExpr>,
2568 check::PreStmt<ReturnStmt>,
2569 check::RegionChanges,
2572 mutable std::unique_ptr<CFRefBug> useAfterRelease, releaseNotOwned;
2573 mutable std::unique_ptr<CFRefBug> deallocGC, deallocNotOwned;
2574 mutable std::unique_ptr<CFRefBug> overAutorelease, returnNotOwnedForOwned;
2575 mutable std::unique_ptr<CFRefBug> leakWithinFunction, leakAtReturn;
2576 mutable std::unique_ptr<CFRefBug> leakWithinFunctionGC, leakAtReturnGC;
2578 typedef llvm::DenseMap<SymbolRef, const CheckerProgramPointTag *> SymbolTagMap;
2581 mutable SymbolTagMap DeadSymbolTags;
2583 mutable std::unique_ptr<RetainSummaryManager> Summaries;
2584 mutable std::unique_ptr<RetainSummaryManager> SummariesGC;
2585 mutable SummaryLogTy SummaryLog;
2586 mutable bool ShouldResetSummaryLog;
2590 mutable bool IncludeAllocationLine;
2594 : ShouldResetSummaryLog(
false),
2597 ~RetainCountChecker()
override { DeleteContainerSeconds(DeadSymbolTags); }
2629 if (ShouldResetSummaryLog)
2632 ShouldResetSummaryLog = !SummaryLog.empty();
2635 CFRefBug *getLeakWithinFunctionBug(
const LangOptions &LOpts,
2636 bool GCEnabled)
const {
2638 if (!leakWithinFunctionGC)
2639 leakWithinFunctionGC.reset(
new Leak(
this,
"Leak of object when using " 2640 "garbage collection"));
2641 return leakWithinFunctionGC.get();
2643 if (!leakWithinFunction) {
2645 leakWithinFunction.reset(
new Leak(
this,
2646 "Leak of object when not using " 2647 "garbage collection (GC) in " 2648 "dual GC/non-GC code"));
2650 leakWithinFunction.reset(
new Leak(
this,
"Leak"));
2653 return leakWithinFunction.get();
2657 CFRefBug *getLeakAtReturnBug(
const LangOptions &LOpts,
bool GCEnabled)
const {
2659 if (!leakAtReturnGC)
2660 leakAtReturnGC.reset(
new Leak(
this,
2661 "Leak of returned object when using " 2662 "garbage collection"));
2663 return leakAtReturnGC.get();
2665 if (!leakAtReturn) {
2667 leakAtReturn.reset(
new Leak(
this,
2668 "Leak of returned object when not using " 2669 "garbage collection (GC) in dual " 2672 leakAtReturn.reset(
new Leak(
this,
"Leak of returned object"));
2675 return leakAtReturn.get();
2679 RetainSummaryManager &getSummaryManager(
ASTContext &Ctx,
2680 bool GCEnabled)
const {
2686 SummariesGC.reset(
new RetainSummaryManager(Ctx,
true, ARCEnabled));
2688 assert(SummariesGC->isARCEnabled() == ARCEnabled);
2689 return *SummariesGC;
2692 Summaries.reset(
new RetainSummaryManager(Ctx,
false, ARCEnabled));
2694 assert(Summaries->isARCEnabled() == ARCEnabled);
2699 RetainSummaryManager &getSummaryManager(
CheckerContext &C)
const {
2704 const char *NL,
const char *Sep)
const override;
2718 void checkSummary(
const RetainSummary &Summ,
const CallEvent &Call,
2721 void processSummaryOfInlined(
const RetainSummary &Summ,
2728 bool Assumption)
const;
2748 RefVal V,
ArgEffect E, RefVal::Kind &hasErr,
2782 bool VisitSymbol(
SymbolRef sym)
override {
2783 state = state->remove<RefBindings>(sym);
2793 void RetainCountChecker::checkPostStmt(
const BlockExpr *BE,
2803 cast<BlockDataRegion>(state->getSVal(BE,
2819 for ( ; I != E; ++I) {
2820 const VarRegion *VR = I.getCapturedRegion();
2824 Regions.push_back(VR);
2828 state->scanReachableSymbols<StopTrackingCallback>(Regions.data(),
2829 Regions.data() + Regions.size()).getState();
2833 void RetainCountChecker::checkPostStmt(
const CastExpr *CE,
2862 state = updateSymbol(state, Sym, *T, AE, hasErr, C);
2873 const Expr *Ex)
const {
2881 state = updateSymbol(state, sym, *
T,
MayEscape, hasErr, C);
2883 processNonLeakError(state, Child->getSourceRange(), hasErr, sym, C);
2904 processObjCLiterals(C, AL);
2910 processObjCLiterals(C, DL);
2913 void RetainCountChecker::checkPostStmt(
const ObjCBoxedExpr *Ex,
2919 if (
SymbolRef Sym = State->getSVal(Ex, LCtx).getAsSymbol()) {
2935 SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol();
2936 if (!Sym || !dyn_cast_or_null<ObjCIvarRegion>(Sym->
getOriginRegion()))
2969 RefVal PlusZero = RefVal::makeNotOwned(Kind, Ty);
2977 State =
setRefBinding(State, Sym, PlusZero.withIvarAccess());
2981 void RetainCountChecker::checkPostCall(
const CallEvent &Call,
2983 RetainSummaryManager &Summaries = getSummaryManager(C);
2984 const RetainSummary *Summ = Summaries.getSummary(Call, C.
getState());
2987 processSummaryOfInlined(*Summ, Call, C);
2990 checkSummary(*Summ, Call, C);
3007 if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() ||
3008 PT->isObjCClassType()) {
3024 void RetainCountChecker::processSummaryOfInlined(
const RetainSummary &Summ,
3030 for (
unsigned idx = 0, e = CallOrMsg.
getNumArgs(); idx != e; ++idx) {
3041 if (MsgInvocation) {
3063 auto *ArgRegion = dyn_cast_or_null<TypedValueRegion>(ArgVal.
getAsRegion());
3067 QualType PointeeTy = ArgRegion->getValueType();
3071 SVal PointeeVal = State->getSVal(ArgRegion);
3088 llvm_unreachable(
"only for out parameters");
3094 void RetainCountChecker::checkSummary(
const RetainSummary &Summ,
3104 for (
unsigned idx = 0, e = CallOrMsg.
getNumArgs(); idx != e; ++idx) {
3112 state = updateSymbol(state, Sym, *
T, Effect, hasErr, C);
3123 bool ReceiverIsTracked =
false;
3126 if (MsgInvocation) {
3129 ReceiverIsTracked =
true;
3130 state = updateSymbol(state, Sym, *
T, Summ.getReceiverEffect(),
3143 processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C);
3151 if (ReceiverIsTracked)
3152 RE = getSummaryManager(C).getObjAllocRetEffect();
3159 llvm_unreachable(
"Unhandled RetEffect.");
3210 if (ShouldResetSummaryLog) {
3212 ShouldResetSummaryLog =
false;
3214 SummaryLog[NewNode] = &Summ;
3220 RefVal V,
ArgEffect E, RefVal::Kind &hasErr,
3225 if (!IgnoreRetainMsg)
3247 V = V ^ RefVal::ErrorUseAfterRelease;
3248 hasErr = V.getKind();
3257 llvm_unreachable(
"DecRefMsg/IncRefMsg/MakeCollectable already converted");
3261 llvm_unreachable(
"Applies to pointer-to-pointer parameters, which should " 3262 "not have ref state.");
3267 V = V ^ RefVal::ErrorDeallocGC;
3268 hasErr = V.getKind();
3272 switch (V.getKind()) {
3274 llvm_unreachable(
"Invalid RefVal state for an explicit dealloc.");
3277 V = V ^ RefVal::Released;
3280 case RefVal::NotOwned:
3281 V = V ^ RefVal::ErrorDeallocNotOwned;
3282 hasErr = V.getKind();
3288 if (V.getKind() == RefVal::Owned) {
3289 V = V ^ RefVal::NotOwned;
3302 V = V.autorelease();
3310 switch (V.getKind()) {
3312 llvm_unreachable(
"Invalid RefVal state for a retain.");
3314 case RefVal::NotOwned:
3317 case RefVal::Released:
3320 V = (V ^ RefVal::Owned) + 1;
3328 switch (V.getKind()) {
3331 llvm_unreachable(
"Invalid RefVal state for a release.");
3334 assert(V.getCount() > 0);
3335 if (V.getCount() == 1) {
3337 V.getIvarAccessHistory() ==
3338 RefVal::IvarAccessHistory::AccessedDirectly)
3339 V = V ^ RefVal::NotOwned;
3341 V = V ^ RefVal::Released;
3349 case RefVal::NotOwned:
3350 if (V.getCount() > 0) {
3354 }
else if (V.getIvarAccessHistory() ==
3355 RefVal::IvarAccessHistory::AccessedDirectly) {
3360 V = V.releaseViaIvar() ^ RefVal::Released;
3362 V = V ^ RefVal::ErrorReleaseNotOwned;
3363 hasErr = V.getKind();
3367 case RefVal::Released:
3370 V = V ^ RefVal::ErrorUseAfterRelease;
3371 hasErr = V.getKind();
3401 llvm_unreachable(
"Unhandled error.");
3402 case RefVal::ErrorUseAfterRelease:
3403 if (!useAfterRelease)
3404 useAfterRelease.reset(
new UseAfterRelease(
this));
3405 BT = useAfterRelease.get();
3407 case RefVal::ErrorReleaseNotOwned:
3408 if (!releaseNotOwned)
3409 releaseNotOwned.reset(
new BadRelease(
this));
3410 BT = releaseNotOwned.get();
3412 case RefVal::ErrorDeallocGC:
3414 deallocGC.reset(
new DeallocGC(
this));
3415 BT = deallocGC.get();
3417 case RefVal::ErrorDeallocNotOwned:
3418 if (!deallocNotOwned)
3419 deallocNotOwned.reset(
new DeallocNotOwned(
this));
3420 BT = deallocNotOwned.get();
3425 auto report = std::unique_ptr<BugReport>(
3427 SummaryLog, N, Sym));
3428 report->addRange(ErrorRange);
3455 StringRef FName = II->
getName();
3456 FName = FName.substr(FName.find_first_not_of(
'_'));
3459 bool canEval =
false;
3462 bool hasTrustedImplementationAnnotation =
false;
3467 canEval = II->
isStr(
"NSMakeCollectable");
3481 hasTrustedImplementationAnnotation = canEval;
3491 SVal RetVal = state->getSVal(CE->
getArg(0), LCtx);
3493 (hasTrustedImplementationAnnotation && !ResultTy.
isNull())) {
3500 state = state->BindExpr(CE, LCtx, RetVal,
false);
3507 const RefVal *Binding =
nullptr;
3512 state = state->invalidateRegions(
3514 hasTrustedImplementationAnnotation);
3529 void RetainCountChecker::checkPreStmt(
const ReturnStmt *S,
3558 switch (X.getKind()) {
3559 case RefVal::Owned: {
3560 unsigned cnt = X.getCount();
3562 X.setCount(cnt - 1);
3563 X = X ^ RefVal::ReturnedOwned;
3567 case RefVal::NotOwned: {
3568 unsigned cnt = X.getCount();
3570 X.setCount(cnt - 1);
3571 X = X ^ RefVal::ReturnedOwned;
3574 X = X ^ RefVal::ReturnedNotOwned;
3597 state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X);
3609 RetainSummaryManager &Summaries = getSummaryManager(C);
3615 const RetainSummary *Summ = Summaries.getMethodSummary(MD);
3616 RE = Summ->getRetEffect();
3617 }
else if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
3618 if (!isa<CXXMethodDecl>(FD)) {
3619 const RetainSummary *Summ = Summaries.getFunctionSummary(FD);
3620 RE = Summ->getRetEffect();
3624 checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state);
3627 void RetainCountChecker::checkReturnWithRetEffect(
const ReturnStmt *S,
3643 if (X.isReturnedOwned() && X.getCount() == 0) {
3645 bool hasError =
false;
3652 X = X ^ RefVal::ErrorGCLeakReturned;
3659 X = X ^ RefVal::ErrorLeakReturned;
3671 C.
emitReport(std::unique_ptr<BugReport>(
new CFRefLeakReport(
3672 *getLeakAtReturnBug(LOpts, GCEnabled), LOpts, GCEnabled,
3673 SummaryLog, N, Sym, C, IncludeAllocationLine)));
3677 }
else if (X.isReturnedNotOwned()) {
3679 if (X.getIvarAccessHistory() ==
3680 RefVal::IvarAccessHistory::AccessedDirectly) {
3684 X.releaseViaIvar() ^ RefVal::ReturnedOwned);
3688 state =
setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned);
3691 ReturnNotOwnedTag(
this,
"ReturnNotOwnedForOwned");
3695 if (!returnNotOwnedForOwned)
3696 returnNotOwnedForOwned.reset(
new ReturnedNotOwnedForOwned(
this));
3698 C.
emitReport(std::unique_ptr<BugReport>(
new CFRefReport(
3711 void RetainCountChecker::checkBind(
SVal loc,
SVal val,
const Stmt *S,
3714 bool escapes =
true;
3725 escapes = !regionLoc->getRegion()->hasStackStorage();
3733 SVal StoredVal = state->getSVal(regionLoc->getRegion());
3734 if (StoredVal != val)
3741 escapes = !isa<VarRegion>(regionLoc->getRegion());
3749 const VarDecl *VD = LVR->getDecl();
3750 if (VD->
hasAttr<CleanupAttr>()) {
3763 state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
3769 bool Assumption)
const {
3776 RefBindingsTy B = state->get<RefBindings>();
3781 bool changed =
false;
3782 RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>();
3784 for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
3790 B = RefBFactory.remove(B, I.getKey());
3795 state = state->set<RefBindings>(B);
3810 llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
3812 E = ExplicitRegions.end(); I != E; ++I) {
3814 WhitelistedSymbols.insert(SR->getSymbol());
3817 for (InvalidatedSymbols::const_iterator I=invalidated->begin(),
3818 E = invalidated->end(); I!=E; ++I) {
3820 if (WhitelistedSymbols.count(sym))
3838 unsigned ACnt = V.getAutoreleaseCount();
3845 unsigned Cnt = V.getCount();
3849 if (V.getKind() == RefVal::ReturnedOwned)
3855 V.getIvarAccessHistory() == RefVal::IvarAccessHistory::AccessedDirectly) {
3856 V = V.releaseViaIvar();
3863 if (V.getKind() == RefVal::ReturnedOwned)
3864 V = V ^ RefVal::ReturnedNotOwned;
3866 V = V ^ RefVal::NotOwned;
3868 V.setCount(V.getCount() - ACnt);
3869 V.setAutoreleaseCount(0);
3885 V = V ^ RefVal::ErrorOverAutorelease;
3891 llvm::raw_svector_ostream os(sbuf);
3892 os <<
"Object was autoreleased ";
3893 if (V.getAutoreleaseCount() > 1)
3894 os << V.getAutoreleaseCount() <<
" times but the object ";
3897 os <<
"has a +" << V.getCount() <<
" retain count";
3899 if (!overAutorelease)
3900 overAutorelease.reset(
new OverAutorelease(
this));
3904 new CFRefReport(*overAutorelease, LOpts,
false,
3905 SummaryLog, N, Sym, os.str())));
3925 else if (V.isOwned())
3927 else if (V.isNotOwned() || V.isReturnedOwned())
3928 hasLeak = (V.getCount() > 0);
3935 Leaked.push_back(sid);
3949 I = Leaked.begin(), E = Leaked.end(); I != E; ++I) {
3953 CFRefBug *BT = Pred ? getLeakWithinFunctionBug(LOpts, GCEnabled)
3954 : getLeakAtReturnBug(LOpts, GCEnabled);
3955 assert(BT &&
"BugType not initialized.");
3958 new CFRefLeakReport(*BT, LOpts, GCEnabled, SummaryLog, N, *I, Ctx,
3959 IncludeAllocationLine)));
3966 void RetainCountChecker::checkBeginFunction(
CheckerContext &Ctx)
const {
3978 const RetainSummary *FunctionSummary = getSummaryManager(Ctx).getFunctionSummary(FD);
3979 ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects();
3981 for (
unsigned idx = 0, e = FD->
getNumParams(); idx != e; ++idx) {
3983 SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol();
3986 const ArgEffect *AE = CalleeSideArgEffects.lookup(idx);
3988 state =
setRefBinding(state, Sym, RefVal::makeOwned(RetEffect::ObjKind::Generalized, Ty));
3990 state =
setRefBinding(state, Sym, RefVal::makeNotOwned(RetEffect::ObjKind::Generalized, Ty));
3996 void RetainCountChecker::checkEndFunction(
CheckerContext &Ctx)
const {
3998 RefBindingsTy B = state->get<RefBindings>();
4008 for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
4009 state = handleAutoreleaseCounts(state, Pred,
nullptr, Ctx,
4010 I->first, I->second);
4022 B = state->get<RefBindings>();
4025 for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I)
4026 state = handleSymbolDeath(state, I->first, I->second, Leaked);
4028 processLeaks(state, Leaked, Ctx, Pred);
4032 RetainCountChecker::getDeadSymbolTag(
SymbolRef sym)
const {
4036 llvm::raw_svector_ostream out(buf);
4037 out <<
"Dead Symbol : ";
4044 void RetainCountChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
4049 RefBindingsTy B = state->get<RefBindings>();
4054 E = SymReaper.
dead_end(); I != E; ++I) {
4056 if (
const RefVal *
T = B.lookup(Sym)){
4060 state = handleAutoreleaseCounts(state, Pred, Tag, C, Sym, *
T);
4066 state = handleSymbolDeath(state, *I, *
getRefBinding(state, Sym), Leaked);
4070 if (Leaked.empty()) {
4075 Pred = processLeaks(state, Leaked, C, Pred);
4083 RefBindingsTy::Factory &F = state->get_context<RefBindings>();
4084 B = state->get<RefBindings>();
4089 B = F.remove(B, *I);
4091 state = state->set<RefBindings>(B);
4095 void RetainCountChecker::printState(raw_ostream &Out,
ProgramStateRef State,
4096 const char *NL,
const char *Sep)
const {
4098 RefBindingsTy B = State->get<RefBindings>();
4105 for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
4106 Out << I->first <<
" : ";
4107 I->second.print(Out);
4126 namespace objc_retain {
4131 #define createCallEffect(D, KIND)\ 4132 ASTContext &Ctx = D->getASTContext();\ 4133 LangOptions L = Ctx.getLangOpts();\ 4134 RetainSummaryManager M(Ctx, L.GCOnly, L.ObjCAutoRefCount);\ 4135 const RetainSummary *S = M.get ## KIND ## Summary(D);\ 4136 CallEffects CE(S->getRetEffect());\ 4137 CE.Receiver = S->getReceiverEffect();\ 4138 unsigned N = D->param_size();\ 4139 for (unsigned i = 0; i < N; ++i) {\ 4140 CE.Args.push_back(S->getArg(i));\ 4153 #undef createCallEffect
const BlockDecl * getBlockDecl() const
FunctionDecl * getDefinition()
Get the definition for this declaration.
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
An instance of this class is created to represent a function declaration or definition.
Smart pointer class that efficiently represents Objective-C method names.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
A (possibly-)qualified type.
MemRegion - The root abstract class for all memory regions.
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
static RetEffect MakeOwnedWhenTrackedReceiver()
ASTContext & getASTContext()
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
bool hasCaptures() const
hasCaptures - True if this block (or its nested blocks) captures anything of local storage from its e...
ObjCInterfaceDecl * getClassInterface()
bool operator==(CanQual< T > x, CanQual< U > y)
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
Stmt - This represents one statement.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
FunctionType - C99 6.7.5.3 - Function Declarators.
Bridging via __bridge, which does nothing but reinterpret the bits.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
static ProgramStateRef removeRefBinding(ProgramStateRef State, SymbolRef Sym)
Defines the SourceManager interface.
The argument acts as if has been passed to CFMakeCollectable, which transfers the object to the Garba...
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
Decl - This represents one declaration (or definition), e.g.
Represents a point when we begin processing an inlined call.
Manages the lifetime of CallEvent objects.
The argument has its reference count decreased by 1.
Indicates that the tracked object is an Objective-C object.
bool isCocoaObjectRef(QualType T)
llvm::DenseMap< Stmt *, Stmt * > MapTy
Indicates that the tracked object is a generalized object.
const ProgramStateRef & getState() const
ArrayRef< ParmVarDecl * >::const_iterator param_const_iterator
param_const_iterator param_end() const
static RetEffect MakeNoRet()
const Expr * getOriginExpr() const
Returns the expression whose value will be the result of this call.
bool isConsumedExpr(Expr *E) const
VarDecl - An instance of this class is created to represent a variable declaration or definition...
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
QualType getReturnType() const
unsigned getNumParams() const
const T * getAs() const
Member-template getAs<specific type>'.
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +1 v...
const FunctionDecl * getCalleeDecl(const CallExpr *CE) const
Get the declaration of the called function (path-sensitive).
const Decl & getCodeDecl() const
ObjCMethodDecl - Represents an instance or class method declaration.
ExplodedNode * getPredecessor()
Returns the previous node in the exploded graph, which includes the state of the program before the c...
virtual const MemRegion * getOriginRegion() const
Find the region from which this symbol originates.
SVal getSVal(const Stmt *S) const
Get the value of arbitrary expressions at this point in the path.
ParmVarDecl - Represents a parameter to a function.
const bool wasInlined
If we are post visiting a call, this flag will be set if the call was inlined.
const char *const MemoryCoreFoundationObjectiveC
bool isParentOf(const LocationContext *LC) const
IdentifierInfo * getIdentifier() const
getIdentifier - Get the identifier that names this declaration, if there is one.
const MemRegion * getSuperRegion() const
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)
Convenience method to query the state to see if a symbol is null or not null, or if neither assumptio...
One of these records is kept for each identifier that is lexed.
static RetEffect MakeNoRetHard()
MemRegionManager & getRegionManager()
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
static Selector getKeywordSelector(ASTContext &Ctx, IdentifierInfos *... IIs)
const ParmVarDecl *const * param_const_iterator
bool isObjCIdType() const
This class provides a convenience implementation for clone() using the Curiously-Recurring Template P...
The argument is treated as if an -autorelease message had been sent to the referenced object...
unsigned getSpellingLineNumber(bool *Invalid=nullptr) const
const Expr * getRetValue() const
const MemRegion * getRegion()
const ObjCInterfaceDecl * getReceiverInterface() const
Get the interface for the receiver.
clang::CharUnits operator*(clang::CharUnits::QuantityType Scale, const clang::CharUnits &CU)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
ObjCArrayLiteral - used for objective-c array containers; as in: @["Hello", NSApp, [NSNumber numberWithInt:42]];.
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
static ObjCSummaryKey getTombstoneKey()
static bool isRetain(const FunctionDecl *FD, StringRef FName)
static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr, const ExplodedNode *N, SymbolRef Sym)
virtual llvm::iterator_range< ranges_iterator > getRanges()
Get the SourceRanges associated with the report.
static bool isEqual(const ObjCSummaryKey &LHS, const ObjCSummaryKey &RHS)
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
bool followsCreateRule(const FunctionDecl *FD)
BlockDataRegion - A region that represents a block instance.
Represents any expression that calls an Objective-C method.
virtual Kind getKind() const =0
Returns the kind of call this is.
bool hasNonZeroCallbackArg() const
Returns true if any of the arguments appear to represent callbacks.
static void Profile(const ArgEffect X, FoldingSetNodeID &ID)
ProgramStateManager & getStateManager()
The argument has its reference count increased by 1.
virtual void dumpToStream(raw_ostream &os) const
const StackFrameContext * getCurrentStackFrame() const
const LocationContext * getLocationContext() const
virtual bool inTopFrame() const
Return true if the current LocationContext has no caller context.
Selector GetNullarySelector(StringRef name, ASTContext &Ctx)
Utility function for constructing a nullary selector.
const LocationContext * getParent() const
SVal getReturnValue() const
Returns the return value of the call.
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
referenced_vars_iterator referenced_vars_end() const
Represents an ObjC class declaration.
Bridging via __bridge_transfer, which transfers ownership of an Objective-C pointer into ARC...
static bool isNumericLiteralExpression(const Expr *E)
QualType getReturnType() const
virtual BugReport::NodeResolver & getNodeResolver()=0
virtual QualType getType() const =0
param_iterator param_begin()
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
ArgEffect
An ArgEffect summarizes the retain count behavior on an argument or receiver to a function or method...
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
Const iterator for iterating over Stmt * arrays that contain only Expr *.
Indicates that the returned value is an owned (+1) symbol.
Represents a prototype with parameter type info, e.g.
const Stmt * getCallSite() const
Indicates that the return value is an owned object when the receiver is also a tracked object...
static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation)
Returns true if the declaration 'D' is annotated with 'rcAnnotation'.
The argument is treated as potentially escaping, meaning that even when its reference count hits 0 it...
llvm::ImmutableMap< unsigned, ArgEffect > ArgEffects
ArgEffects summarizes the effects of a function/method call on all of its arguments.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
const RegionTy * getAs() const
SymbolicRegion - A special, "non-concrete" region.
ObjKind getObjKind() const
Expr - This represents one expression.
Defines the clang::LangOptions interface.
Indicates that the tracked object is a CF object.
const FunctionProtoType * T
Indicates that the object is not owned and controlled by the Garbage collector.
bool isObjCRetainableType() const
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
bool shouldIncludeAllocationSiteInLeakDiagnostics(AnalyzerOptions &AOpts)
Returns true if leak diagnostics should directly reference the allocatin site (where possible)...
SymbolSetTy::const_iterator dead_iterator
static CallEffects getEffect(const ObjCMethodDecl *MD)
Return the CallEfect for a given Objective-C method.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
ObjCDictionaryLiteral - AST node to represent objective-c dictionary literals; as in:"name" : NSUserN...
ObjCInterfaceDecl * getSuperClass() const
static bool isRelease(const FunctionDecl *FD, StringRef FName)
ObjKind
Determines the object kind of a tracked object.
static bool isAutorelease(const FunctionDecl *FD, StringRef FName)
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
bool isCFObjectRef(QualType T)
An expression that sends a message to the given Objective-C object or class.
QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl, ObjCInterfaceDecl *PrevDecl=nullptr) const
getObjCInterfaceType - Return the unique reference to the type for the specified ObjC interface decl...
bool isBodyAutosynthesized() const
Checks if the body of the Decl is generated by the BodyFarm.
bool isInstanceMethod() const
unsigned getNumArgs() const
static RetEffect MakeGCNotOwned()
void markInteresting(SymbolRef sym)
Selector getSelector() const
ObjCBridgeCastKind getBridgeKind() const
Determine which kind of bridge is being performed via this cast.
CallEventRef< ObjCMethodCall > getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State, const LocationContext *LCtx)
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Represents a C function or static C++ member function call.
static StringRef getIdentifier(const Token &Tok)
static bool isSynthesizedAccessor(const StackFrameContext *SFC)
Returns true if this stack frame is for an Objective-C method that is a property getter or setter who...
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
const VarDecl * getDecl() const
static RetEffect MakeNotOwned(ObjKind o)
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
BugReporter is a utility class for generating PathDiagnostics for analysis.
static const Stmt * getStmt(const ExplodedNode *N)
Given an exploded node, retrieve the statement that should be used for the diagnostic location...
const MemRegion * StripCasts(bool StripBaseCasts=true) const
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
std::string getAsString() const
Derive the full selector name (e.g.
static std::unique_ptr< PathDiagnosticPiece > getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR)
Generates the default final diagnostic piece.
CHECKER * registerChecker()
Used to register checkers.
The argument has its reference count increased by 1.
ObjCMethodFamily getMethodFamily() const
Derive the conventional family of this method.
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Expr *expr, const LocationContext *LCtx, unsigned count)
Create a new symbol with a unique 'name'.
QualType getReturnType() const
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
static ObjCSummaryKey getEmptyKey()
ExplodedNode * generateSink(ProgramStateRef State, ExplodedNode *Pred, const ProgramPointTag *Tag=nullptr)
Generate a sink node.
The argument has its reference count decreased by 1 to model a transferred bridge cast under ARC...
T castAs() const
Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type...
ProgramPoints can be "tagged" as representing points specific to a given analysis entity...
const MemRegion * getAsRegion() const
static ProgramStateRef updateOutParameter(ProgramStateRef State, SVal ArgVal, ArgEffect Effect)
static const RefVal * getRefBinding(ProgramStateRef State, SymbolRef Sym)
static void Profile(const RetEffect &X, FoldingSetNodeID &ID)
const ParmVarDecl * getParamDecl(unsigned i) const
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
static bool isGeneralizedObjectRef(QualType Ty)
const StackFrameContext * getStackFrame() const
A class responsible for cleaning up unused symbols.
referenced_vars_iterator referenced_vars_begin() const
ObjCBoxedExpr - used for generalized expression boxing.
const ObjCMethodDecl * getDecl() const override
unsigned blockCount() const
Returns the number of times the current block has been visited along the analyzed path...
StringRef getName() const
Return the actual identifier string.
virtual const ObjCMessageExpr * getOriginExpr() const
An Objective-C "bridged" cast expression, which casts between Objective-C pointers and C pointers...
Selector getSelector() const
static ProgramStateRef setRefBinding(ProgramStateRef State, SymbolRef Sym, RefVal Val)
All typestate tracking of the object ceases.
Dataflow Directional Tag Classes.
bool isRefType(QualType RetTy, StringRef Prefix, StringRef Name=StringRef())
ASTContext & getASTContext()
virtual SourceRange getArgSourceRange(unsigned Index) const
Returns the source range for errors associated with this argument.
The argument is treated as if an -dealloc message had been sent to the referenced object...
const VarRegion * getVarRegion(const VarDecl *D, const LocationContext *LC)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and LocationC...
Performs the combined functionality of DecRef and StopTrackingHard.
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
bool isKeywordSelector() const
static bool isTrustedReferenceCountImplementation(const FunctionDecl *FD)
Returns true if the function declaration 'FD' contains 'rc_ownership_trusted_implementation' annotate...
QualType getCallReturnType(const ASTContext &Ctx) const
getCallReturnType - Get the return type of the call expr.
Represents an abstract call to a function or method along a particular path.
Bridging via __bridge_retain, which makes an ARC object available as a +1 C pointer.
AnalyzerOptions & getAnalyzerOptions()
RetEffect summarizes a call's retain/release behavior with respect to its return value.
const Decl * getDecl() const
dead_iterator dead_begin() const
param_iterator param_end()
static ArgEffect getStopTrackingHardEquivalent(ArgEffect E)
SourceRange getReceiverRange() const
Source range of the receiver.
Represents a pointer to an Objective C object.
bool isInstanceMessage() const
const StackFrameContext * getStackFrame() const
const FunctionDecl * getAsFunctionDecl() const
getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a CodeTextRegion wrapping a FunctionDecl...
#define createCallEffect(D, KIND)
const ProgramStateRef & getState() const
Performs the combined functionality of DecRefMsg and StopTrackingHard.
ProgramStateManager & getStateManager()
param_const_iterator param_begin() const
dead_iterator dead_end() const
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +0 v...
static bool isMakeCollectable(const FunctionDecl *FD, StringRef FName)
ObjCIvarRefExpr - A reference to an ObjC instance variable.
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
QualType getResultType() const
Returns the result type, adjusted for references.
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
No particular method family.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
Indicates that no retain count information is tracked for the return value.
Selector GetUnarySelector(StringRef name, ASTContext &Ctx)
Utility function for constructing an unary selector.
pred_iterator pred_begin()
SourceManager & getSourceManager()
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
static PathDiagnosticLocation createEndOfPath(const ExplodedNode *N, const SourceManager &SM)
Create a location corresponding to the next valid ExplodedNode as end of path location.
static RetEffect MakeOwned(ObjKind o)
const MemRegion * getBaseRegion() const
SValBuilder & getSValBuilder()
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
A SourceLocation and its associated SourceManager.
static Decl::Kind getKind(const Decl *D)
virtual const ExplodedNode * getOriginalNode(const ExplodedNode *N)=0
bool isPointerType() const
All typestate tracking of the object ceases.
void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler &F)
The argument has its reference count decreased by 1.
Encapsulates the retain count semantics on the arguments, return value, and receiver (if any) of a fu...
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
ParentMap & getParentMap()
A trivial tuple used to represent a source range.
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
QualType getObjCObjectPointerType(QualType OIT) const
Return a ObjCObjectPointerType type for the given ObjCObjectType.
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
This class provides an interface through which checkers can create individual bug reports...
bool inTopFrame() const
Return true if the current LocationContext has no caller context.
static unsigned getHashValue(const ObjCSummaryKey &V)
ObjCMethodDecl * getInstanceMethod(Selector Sel, bool AllowHidden=false) const
AnalysisDeclContext * getAnalysisDeclContext() const
const LocationContext * getLocationContext() const
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Indicates that the returned value is an object with retain count semantics but that it is not owned (...
const LangOptions & getLangOpts() const
This class handles loading and caching of source files into memory.
SourceManager & getSourceManager()
static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx)
GetReturnType - Used to get the return type of a message expression or function call with the intenti...
bool isObjCGCEnabled() const
QualType getPointeeType() const
Gets the type pointed to by this ObjC pointer.