blob: 77bbba25ea39e6cfa4e9a14661c587957abdb356 [file] [log] [blame]
Chris Lattnerbda0b622008-03-15 23:59:48 +00001// CFRefCount.cpp - Transfer functions for tracking simple values -*- C++ -*--//
Ted Kremenek2fff37e2008-03-06 00:08:09 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
Gabor Greif843e9342008-03-06 10:40:09 +000010// This file defines the methods for CFRefCount, which implements
Ted Kremenek2fff37e2008-03-06 00:08:09 +000011// a reference count checker for Core Foundation (Mac OS X).
12//
13//===----------------------------------------------------------------------===//
14
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000015#include "GRSimpleVals.h"
Ted Kremenek2fff37e2008-03-06 00:08:09 +000016#include "clang/Analysis/PathSensitive/ValueState.h"
17#include "clang/Basic/Diagnostic.h"
18#include "clang/Analysis/LocalCheckers.h"
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000019#include "llvm/ADT/DenseMap.h"
20#include "llvm/ADT/FoldingSet.h"
21#include "llvm/ADT/ImmutableMap.h"
Ted Kremenekf3948042008-03-11 19:44:10 +000022#include <ostream>
Ted Kremenek2fff37e2008-03-06 00:08:09 +000023
24using namespace clang;
25
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000026namespace {
27 enum ArgEffect { IncRef, DecRef, DoNothing };
28 typedef std::vector<ArgEffect> ArgEffects;
29}
Ted Kremenek2fff37e2008-03-06 00:08:09 +000030
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000031namespace llvm {
32 template <> struct FoldingSetTrait<ArgEffects> {
33 static void Profile(const ArgEffects& X, FoldingSetNodeID ID) {
34 for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I)
35 ID.AddInteger((unsigned) *I);
36 }
37
38 static void Profile(ArgEffects& X, FoldingSetNodeID ID) {
39 Profile(X, ID);
40 }
41 };
42} // end llvm namespace
43
44namespace {
Ted Kremenek2fff37e2008-03-06 00:08:09 +000045
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000046class RetEffect {
47public:
48 enum Kind { Alias = 0x0, OwnedSymbol = 0x1, NotOwnedSymbol = 0x2 };
49
50private:
51 unsigned Data;
52 RetEffect(Kind k, unsigned D) { Data = (Data << 2) | (unsigned) k; }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000053
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000054public:
55
56 Kind getKind() const { return (Kind) (Data & 0x3); }
57
58 unsigned getValue() const {
59 assert(getKind() == Alias);
60 return Data & ~0x3;
61 }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000062
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000063 static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000064
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000065 static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000066
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000067 static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
68
69 operator Kind() const { return getKind(); }
70
71 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
72};
73
74
75class CFRefSummary : public llvm::FoldingSetNode {
76 ArgEffects* Args;
77 RetEffect Ret;
78public:
79
80 CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
81
82 unsigned getNumArgs() const { return Args->size(); }
83
Ted Kremenek1ac08d62008-03-11 17:48:22 +000084 ArgEffect getArg(unsigned idx) const {
85 assert (idx < getNumArgs());
86 return (*Args)[idx];
87 }
88
Ted Kremenek00a3a5f2008-03-12 01:21:45 +000089 RetEffect getRet() const {
90 return Ret;
91 }
92
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000093 typedef ArgEffects::const_iterator arg_iterator;
94
95 arg_iterator begin_args() const { return Args->begin(); }
96 arg_iterator end_args() const { return Args->end(); }
97
98 static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) {
99 ID.AddPointer(A);
100 ID.Add(R);
101 }
102
103 void Profile(llvm::FoldingSetNodeID& ID) const {
104 Profile(ID, Args, Ret);
105 }
106};
107
108
109class CFRefSummaryManager {
110 typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
111 typedef llvm::FoldingSet<CFRefSummary> SummarySetTy;
112 typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*> SummaryMapTy;
113
114 SummarySetTy SummarySet;
115 SummaryMapTy SummaryMap;
116 AESetTy AESet;
117 llvm::BumpPtrAllocator BPAlloc;
118
119 ArgEffects ScratchArgs;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000120
121
122 ArgEffects* getArgEffects();
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000123
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000124 CFRefSummary* getCannedCFSummary(FunctionTypeProto* FT, bool isRetain);
125
126 CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName);
127
128 CFRefSummary* getCFSummaryCreateRule(FunctionTypeProto* FT);
129 CFRefSummary* getCFSummaryGetRule(FunctionTypeProto* FT);
130
131 CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
132
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000133public:
134 CFRefSummaryManager() {}
135 ~CFRefSummaryManager();
136
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000137 CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000138};
139
140} // end anonymous namespace
141
142//===----------------------------------------------------------------------===//
143// Implementation of checker data structures.
144//===----------------------------------------------------------------------===//
145
146CFRefSummaryManager::~CFRefSummaryManager() {
147
148 // FIXME: The ArgEffects could eventually be allocated from BPAlloc,
149 // mitigating the need to do explicit cleanup of the
150 // Argument-Effect summaries.
151
152 for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
153 I->getValue().~ArgEffects();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000154}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000155
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000156ArgEffects* CFRefSummaryManager::getArgEffects() {
157
158 assert (!ScratchArgs.empty());
159
160 llvm::FoldingSetNodeID profile;
161 profile.Add(ScratchArgs);
162 void* InsertPos;
163
164 llvm::FoldingSetNodeWrapper<ArgEffects>* E =
165 AESet.FindNodeOrInsertPos(profile, InsertPos);
166
167 if (E) {
168 ScratchArgs.clear();
169 return &E->getValue();
170 }
171
172 E = (llvm::FoldingSetNodeWrapper<ArgEffects>*)
173 BPAlloc.Allocate<llvm::FoldingSetNodeWrapper<ArgEffects> >();
174
175 new (E) llvm::FoldingSetNodeWrapper<ArgEffects>(ScratchArgs);
176 AESet.InsertNode(E, InsertPos);
177
178 ScratchArgs.clear();
179 return &E->getValue();
180}
181
182CFRefSummary* CFRefSummaryManager::getPersistentSummary(ArgEffects* AE,
183 RetEffect RE) {
184
185 llvm::FoldingSetNodeID profile;
186 CFRefSummary::Profile(profile, AE, RE);
187 void* InsertPos;
188
189 CFRefSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos);
190
191 if (Summ)
192 return Summ;
193
194 Summ = (CFRefSummary*) BPAlloc.Allocate<CFRefSummary>();
195 new (Summ) CFRefSummary(AE, RE);
196 SummarySet.InsertNode(Summ, InsertPos);
197
198 return Summ;
199}
200
201
202CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD,
203 ASTContext& Ctx) {
204
205 SourceLocation Loc = FD->getLocation();
206
207 if (!Loc.isFileID())
208 return NULL;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000209
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000210 { // Look into our cache of summaries to see if we have already computed
211 // a summary for this FunctionDecl.
212
213 SummaryMapTy::iterator I = SummaryMap.find(FD);
214
215 if (I != SummaryMap.end())
216 return I->second;
217 }
218
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000219#if 0
220 SourceManager& SrcMgr = Ctx.getSourceManager();
221 unsigned fid = Loc.getFileID();
222 const FileEntry* FE = SrcMgr.getFileEntryForID(fid);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000223
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000224 if (!FE)
225 return NULL;
226
227 const char* DirName = FE->getDir()->getName();
228 assert (DirName);
229 assert (strlen(DirName) > 0);
230
231 if (!strstr(DirName, "CoreFoundation")) {
232 SummaryMap[FD] = NULL;
233 return NULL;
234 }
235#endif
236
237 const char* FName = FD->getIdentifier()->getName();
238
239 if (FName[0] == 'C' && FName[1] == 'F') {
240 CFRefSummary* S = getCFSummary(FD, FName);
241 SummaryMap[FD] = S;
242 return S;
243 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000244
245 return NULL;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000246}
247
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000248CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD,
249 const char* FName) {
250
251 // For now, only generate summaries for functions that have a prototype.
252
253 FunctionTypeProto* FT =
254 dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
255
256 if (!FT)
257 return NULL;
258
259 FName += 2;
260
261 if (strcmp(FName, "Retain") == 0)
262 return getCannedCFSummary(FT, true);
263
264 if (strcmp(FName, "Release") == 0)
265 return getCannedCFSummary(FT, false);
266
267 assert (ScratchArgs.empty());
268 bool usesCreateRule = false;
269
270 if (strstr(FName, "Create"))
271 usesCreateRule = true;
272
273 if (!usesCreateRule && strstr(FName, "Copy"))
274 usesCreateRule = true;
275
276 if (usesCreateRule)
277 return getCFSummaryCreateRule(FT);
278
279 if (strstr(FName, "Get"))
280 return getCFSummaryGetRule(FT);
281
282 return NULL;
283}
284
285CFRefSummary* CFRefSummaryManager::getCannedCFSummary(FunctionTypeProto* FT,
286 bool isRetain) {
287
288 if (FT->getNumArgs() != 1)
289 return NULL;
290
291 TypedefType* ArgT = dyn_cast<TypedefType>(FT->getArgType(0).getTypePtr());
292
293 if (!ArgT)
294 return NULL;
295
296 // For CFRetain/CFRelease, the first (and only) argument is of type
297 // "CFTypeRef".
298
299 const char* TDName = ArgT->getDecl()->getIdentifier()->getName();
300 assert (TDName);
301
302 if (strcmp("CFTypeRef", TDName) == 0)
303 return NULL;
304
305 if (!ArgT->isPointerType())
306 return NULL;
307
308 // Check the return type. It should also be "CFTypeRef".
309
310 QualType RetTy = FT->getResultType();
311
312 if (RetTy.getTypePtr() != ArgT)
313 return NULL;
314
315 // The function's interface checks out. Generate a canned summary.
316
317 assert (ScratchArgs.empty());
318 ScratchArgs.push_back(isRetain ? IncRef : DecRef);
319
320 return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0));
321}
322
323static bool isCFRefType(QualType T) {
324
325 if (!T->isPointerType())
326 return false;
327
328 // Check the typedef for the name "CF" and the substring "Ref".
329
330 TypedefType* TD = dyn_cast<TypedefType>(T.getTypePtr());
331
332 if (!TD)
333 return false;
334
335 const char* TDName = TD->getDecl()->getIdentifier()->getName();
336 assert (TDName);
337
338 if (TDName[0] != 'C' || TDName[1] != 'F')
339 return false;
340
341 if (strstr(TDName, "Ref") == 0)
342 return false;
343
344 return true;
345}
346
347
348CFRefSummary*
349CFRefSummaryManager::getCFSummaryCreateRule(FunctionTypeProto* FT) {
350
351 if (!isCFRefType(FT->getResultType()))
352 return NULL;
353
354 assert (ScratchArgs.empty());
355
356 // FIXME: Add special-cases for functions that retain/release. For now
357 // just handle the default case.
358
359 for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
360 ScratchArgs.push_back(DoNothing);
361
362 return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned());
363}
364
365CFRefSummary*
366CFRefSummaryManager::getCFSummaryGetRule(FunctionTypeProto* FT) {
367
368 if (!isCFRefType(FT->getResultType()))
369 return NULL;
370
371 assert (ScratchArgs.empty());
372
373 // FIXME: Add special-cases for functions that retain/release. For now
374 // just handle the default case.
375
376 for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
377 ScratchArgs.push_back(DoNothing);
378
379 return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned());
380}
381
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000382//===----------------------------------------------------------------------===//
383// Transfer functions.
384//===----------------------------------------------------------------------===//
385
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000386namespace {
387
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000388class RefVal {
389 unsigned Data;
390
391 RefVal(unsigned K, unsigned D) : Data((D << 3) | K) {
392 assert ((K & ~0x5) == 0x0);
393 }
394
395 RefVal(unsigned K) : Data(K) {
396 assert ((K & ~0x5) == 0x0);
397 }
398
399public:
400 enum Kind { Owned = 0, AcqOwned = 1, NotOwned = 2, Released = 3,
401 ErrorUseAfterRelease = 4, ErrorReleaseNotOwned = 5 };
402
403
404 Kind getKind() const { return (Kind) (Data & 0x5); }
405
406 unsigned getCount() const {
407 assert (getKind() == Owned || getKind() == AcqOwned);
408 return Data >> 3;
409 }
410
Ted Kremenek73c750b2008-03-11 18:14:09 +0000411 static bool isError(Kind k) { return k >= ErrorUseAfterRelease; }
412
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000413 static RefVal makeOwned(unsigned Count) { return RefVal(Owned, Count); }
414 static RefVal makeAcqOwned(unsigned Count) { return RefVal(AcqOwned, Count); }
415 static RefVal makeNotOwned() { return RefVal(NotOwned); }
416 static RefVal makeReleased() { return RefVal(Released); }
417 static RefVal makeUseAfterRelease() { return RefVal(ErrorUseAfterRelease); }
418 static RefVal makeReleaseNotOwned() { return RefVal(ErrorReleaseNotOwned); }
419
420 bool operator==(const RefVal& X) const { return Data == X.Data; }
421 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
Ted Kremenekf3948042008-03-11 19:44:10 +0000422
423 void print(std::ostream& Out) const;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000424};
Ted Kremenekf3948042008-03-11 19:44:10 +0000425
426void RefVal::print(std::ostream& Out) const {
427 switch (getKind()) {
428 default: assert(false);
429 case Owned:
430 Out << "Owned(" << getCount() << ")";
431 break;
432
433 case AcqOwned:
434 Out << "Acquired-Owned(" << getCount() << ")";
435 break;
436
437 case NotOwned:
438 Out << "Not-Owned";
439 break;
440
441 case Released:
442 Out << "Released";
443 break;
444
445 case ErrorUseAfterRelease:
446 Out << "Use-After-Release [ERROR]";
447 break;
448
449 case ErrorReleaseNotOwned:
450 Out << "Release of Not-Owned [ERROR]";
451 break;
452 }
453}
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000454
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000455class CFRefCount : public GRSimpleVals {
Ted Kremenekf3948042008-03-11 19:44:10 +0000456
457 // Type definitions.
458
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000459 typedef llvm::ImmutableMap<SymbolID, RefVal> RefBindings;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000460 typedef RefBindings::Factory RefBFactoryTy;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000461
462 typedef llvm::SmallPtrSet<GRExprEngine::NodeTy*,2> UseAfterReleasesTy;
463 typedef llvm::SmallPtrSet<GRExprEngine::NodeTy*,2> ReleasesNotOwnedTy;
464
Ted Kremenekf3948042008-03-11 19:44:10 +0000465 class BindingsPrinter : public ValueState::CheckerStatePrinter {
466 public:
467 virtual void PrintCheckerState(std::ostream& Out, void* State,
468 const char* nl, const char* sep);
469 };
470
471 // Instance variables.
472
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000473 CFRefSummaryManager Summaries;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000474 RefBFactoryTy RefBFactory;
475
Ted Kremenek73c750b2008-03-11 18:14:09 +0000476 UseAfterReleasesTy UseAfterReleases;
477 ReleasesNotOwnedTy ReleasesNotOwned;
478
Ted Kremenekf3948042008-03-11 19:44:10 +0000479 BindingsPrinter Printer;
480
481 // Private methods.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000482
483 static RefBindings GetRefBindings(ValueState& StImpl) {
484 return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
485 }
486
487 static void SetRefBindings(ValueState& StImpl, RefBindings B) {
488 StImpl.CheckerState = B.getRoot();
489 }
490
491 RefBindings Remove(RefBindings B, SymbolID sym) {
492 return RefBFactory.Remove(B, sym);
493 }
494
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000495 RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E,
Ted Kremenek73c750b2008-03-11 18:14:09 +0000496 RefVal::Kind& hasError);
Ted Kremenekf3948042008-03-11 19:44:10 +0000497
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000498
499public:
500 CFRefCount() {}
501 virtual ~CFRefCount() {}
Ted Kremenekf3948042008-03-11 19:44:10 +0000502
503 virtual ValueState::CheckerStatePrinter* getCheckerStatePrinter() {
504 return &Printer;
505 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000506
507 // Calls.
508
509 virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000510 GRExprEngine& Eng,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000511 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000512 CallExpr* CE, LVal L,
513 ExplodedNode<ValueState>* Pred);
514};
515
516} // end anonymous namespace
517
Ted Kremenekf3948042008-03-11 19:44:10 +0000518void CFRefCount::BindingsPrinter::PrintCheckerState(std::ostream& Out,
519 void* State, const char* nl,
520 const char* sep) {
521 RefBindings B((RefBindings::TreeTy*) State);
522
523 if (State)
524 Out << sep << nl;
525
526 for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
527 Out << (*I).first << " : ";
528 (*I).second.print(Out);
529 Out << nl;
530 }
531}
532
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000533void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000534 GRExprEngine& Eng,
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000535 GRStmtNodeBuilder<ValueState>& Builder,
536 CallExpr* CE, LVal L,
537 ExplodedNode<ValueState>* Pred) {
538
Ted Kremenek199e1a02008-03-12 21:06:49 +0000539 ValueStateManager& StateMgr = Eng.getStateManager();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000540
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000541 // FIXME: Support calls to things other than lval::FuncVal. At the very
542 // least we should stop tracking ref-state for ref-counted objects passed
543 // to these functions.
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000544
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000545 assert (isa<lval::FuncVal>(L) && "Not yet implemented.");
546
547 // Get the summary.
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000548
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000549 lval::FuncVal FV = cast<lval::FuncVal>(L);
550 FunctionDecl* FD = FV.getDecl();
Ted Kremenek199e1a02008-03-12 21:06:49 +0000551 CFRefSummary* Summ = Summaries.getSummary(FD, Eng.getContext());
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000552
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000553 // Get the state.
554
555 ValueState* St = Builder.GetState(Pred);
556
557 // Evaluate the effects of the call.
558
559 ValueState StVals = *St;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000560 RefVal::Kind hasError = (RefVal::Kind) 0;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000561
562 if (!Summ) {
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000563
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000564 // This function has no summary. Invalidate all reference-count state
565 // for arguments passed to this function, and also nuke the values of
566 // arguments passed-by-reference.
567
568 ValueState StVals = *St;
569
570 for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
571 I != E; ++I) {
572
573 RVal V = StateMgr.GetRVal(St, *I);
574
575 if (isa<lval::SymbolVal>(V)) {
576 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
577 RefBindings B = GetRefBindings(StVals);
578 SetRefBindings(StVals, Remove(B, Sym));
579 }
580
581 if (isa<LVal>(V))
582 StateMgr.Unbind(StVals, cast<LVal>(V));
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000583 }
584
585 St = StateMgr.getPersistentState(StVals);
Ted Kremenek199e1a02008-03-12 21:06:49 +0000586
587 // Make up a symbol for the return value of this function.
588
589 if (CE->getType() != Eng.getContext().VoidTy) {
590 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000591 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek199e1a02008-03-12 21:06:49 +0000592
593 RVal X = CE->getType()->isPointerType()
594 ? cast<RVal>(lval::SymbolVal(Sym))
595 : cast<RVal>(nonlval::SymbolVal(Sym));
596
597 St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false);
598 }
599
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000600 Builder.Nodify(Dst, CE, Pred, St);
601 return;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000602 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000603
604 // This function has a summary. Evaluate the effect of the arguments.
605
606 unsigned idx = 0;
607
608 for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end();
609 I!=E; ++I, ++idx) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000610
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000611 RVal V = StateMgr.GetRVal(St, *I);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000612
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000613 if (isa<lval::SymbolVal>(V)) {
614 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
615 RefBindings B = GetRefBindings(StVals);
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000616
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000617 if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
618 B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError);
619 SetRefBindings(StVals, B);
620 if (hasError) break;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000621 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000622 }
623 }
624
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000625 if (hasError) {
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000626 St = StateMgr.getPersistentState(StVals);
Ted Kremenek73c750b2008-03-11 18:14:09 +0000627 GRExprEngine::NodeTy* N = Builder.generateNode(CE, St, Pred);
628
629 if (N) {
630 N->markAsSink();
631
632 switch (hasError) {
633 default: assert(false);
634 case RefVal::ErrorUseAfterRelease:
635 UseAfterReleases.insert(N);
636 break;
637
638 case RefVal::ErrorReleaseNotOwned:
639 ReleasesNotOwned.insert(N);
640 break;
641 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000642 }
643
644 return;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000645 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000646
647 // Finally, consult the summary for the return value.
648
649 RetEffect RE = Summ->getRet();
650 St = StateMgr.getPersistentState(StVals);
651
652
653 switch (RE.getKind()) {
654 default:
655 assert (false && "Unhandled RetEffect."); break;
656
657 case RetEffect::Alias: {
658 unsigned idx = RE.getValue();
659 assert (idx < CE->getNumArgs());
660 RVal V = StateMgr.GetRVal(St, CE->getArg(idx));
Ted Kremenek199e1a02008-03-12 21:06:49 +0000661 St = StateMgr.SetRVal(St, CE, V, Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000662 break;
663 }
664
665 case RetEffect::OwnedSymbol: {
666 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000667 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000668
669 ValueState StImpl = *St;
670 RefBindings B = GetRefBindings(StImpl);
671 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned(1)));
672
673 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
674 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000675 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000676
677 break;
678 }
679
680 case RetEffect::NotOwnedSymbol: {
681 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000682 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000683
684 ValueState StImpl = *St;
685 RefBindings B = GetRefBindings(StImpl);
686 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned()));
687
688 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
689 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000690 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000691
692 break;
693 }
694 }
695
696 Builder.Nodify(Dst, CE, Pred, St);
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000697}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000698
699
700CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000701 RefVal V, ArgEffect E,
Ted Kremenek73c750b2008-03-11 18:14:09 +0000702 RefVal::Kind& hasError) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000703
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000704 // FIXME: This dispatch can potentially be sped up by unifiying it into
705 // a single switch statement. Opt for simplicity for now.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000706
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000707 switch (E) {
708 default:
709 assert (false && "Unhandled CFRef transition.");
710
711 case DoNothing:
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000712 if (V.getKind() == RefVal::Released) {
713 V = RefVal::makeUseAfterRelease();
714 hasError = V.getKind();
715 break;
716 }
717
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000718 return B;
719
720 case IncRef:
721 switch (V.getKind()) {
722 default:
723 assert(false);
724
725 case RefVal::Owned:
726 V = RefVal::makeOwned(V.getCount()+1); break;
727
728 case RefVal::AcqOwned:
729 V = RefVal::makeAcqOwned(V.getCount()+1);
730 break;
731
732 case RefVal::NotOwned:
733 V = RefVal::makeAcqOwned(1);
734 break;
735
736 case RefVal::Released:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000737 V = RefVal::makeUseAfterRelease();
Ted Kremenek73c750b2008-03-11 18:14:09 +0000738 hasError = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000739 break;
740 }
741
742 case DecRef:
743 switch (V.getKind()) {
744 default:
745 assert (false);
746
747 case RefVal::Owned: {
748 unsigned Count = V.getCount() - 1;
749 V = Count ? RefVal::makeOwned(Count) : RefVal::makeReleased();
750 break;
751 }
752
753 case RefVal::AcqOwned: {
754 unsigned Count = V.getCount() - 1;
755 V = Count ? RefVal::makeAcqOwned(Count) : RefVal::makeNotOwned();
756 break;
757 }
758
759 case RefVal::NotOwned:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000760 V = RefVal::makeReleaseNotOwned();
Ted Kremenek73c750b2008-03-11 18:14:09 +0000761 hasError = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000762 break;
763
764 case RefVal::Released:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000765 V = RefVal::makeUseAfterRelease();
Ted Kremenek73c750b2008-03-11 18:14:09 +0000766 hasError = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000767 break;
768 }
769 }
770
771 return RefBFactory.Add(B, sym, V);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000772}
773
774//===----------------------------------------------------------------------===//
775// Driver for the CFRefCount Checker.
776//===----------------------------------------------------------------------===//
777
778namespace clang {
779
Ted Kremenek63bbe532008-03-14 17:31:00 +0000780 void CheckCFRefCount(CFG& cfg, Decl& CD, ASTContext& Ctx,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000781 Diagnostic& Diag) {
782
783 if (Diag.hasErrorOccurred())
784 return;
785
786 // FIXME: Refactor some day so this becomes a single function invocation.
787
Ted Kremenek63bbe532008-03-14 17:31:00 +0000788 GRCoreEngine<GRExprEngine> Eng(cfg, CD, Ctx);
Ted Kremenek199e1a02008-03-12 21:06:49 +0000789 GRExprEngine* CS = &Eng.getCheckerState();
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000790 CFRefCount TF;
791 CS->setTransferFunctions(TF);
Ted Kremenek199e1a02008-03-12 21:06:49 +0000792 Eng.ExecuteWorkList(20000);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000793
794 }
795
796} // end clang namespace