blob: 501a3f5a05663a27e66d36cd64c41721eb5cc6db [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"
Ted Kremenek4dc41cc2008-03-31 18:26:32 +000017#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek2fff37e2008-03-06 00:08:09 +000018#include "clang/Analysis/LocalCheckers.h"
Ted Kremenekfa34b332008-04-09 01:10:13 +000019#include "clang/Analysis/PathDiagnostic.h"
20#include "clang/Analysis/PathSensitive/BugReporter.h"
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000021#include "llvm/ADT/DenseMap.h"
22#include "llvm/ADT/FoldingSet.h"
23#include "llvm/ADT/ImmutableMap.h"
Ted Kremenekfa34b332008-04-09 01:10:13 +000024#include "llvm/Support/Compiler.h"
Ted Kremenekf3948042008-03-11 19:44:10 +000025#include <ostream>
Ted Kremenek2fff37e2008-03-06 00:08:09 +000026
27using namespace clang;
28
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000029namespace {
30 enum ArgEffect { IncRef, DecRef, DoNothing };
31 typedef std::vector<ArgEffect> ArgEffects;
32}
Ted Kremenek2fff37e2008-03-06 00:08:09 +000033
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000034namespace llvm {
35 template <> struct FoldingSetTrait<ArgEffects> {
36 static void Profile(const ArgEffects& X, FoldingSetNodeID ID) {
37 for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I)
38 ID.AddInteger((unsigned) *I);
39 }
40
41 static void Profile(ArgEffects& X, FoldingSetNodeID ID) {
42 Profile(X, ID);
43 }
44 };
45} // end llvm namespace
46
47namespace {
Ted Kremenek2fff37e2008-03-06 00:08:09 +000048
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000049class RetEffect {
50public:
51 enum Kind { Alias = 0x0, OwnedSymbol = 0x1, NotOwnedSymbol = 0x2 };
52
53private:
54 unsigned Data;
55 RetEffect(Kind k, unsigned D) { Data = (Data << 2) | (unsigned) k; }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000056
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000057public:
58
59 Kind getKind() const { return (Kind) (Data & 0x3); }
60
61 unsigned getValue() const {
62 assert(getKind() == Alias);
63 return Data & ~0x3;
64 }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000065
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000066 static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000067
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000068 static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000069
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000070 static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
71
72 operator Kind() const { return getKind(); }
73
74 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
75};
76
77
78class CFRefSummary : public llvm::FoldingSetNode {
79 ArgEffects* Args;
80 RetEffect Ret;
81public:
82
83 CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
84
85 unsigned getNumArgs() const { return Args->size(); }
86
Ted Kremenek1ac08d62008-03-11 17:48:22 +000087 ArgEffect getArg(unsigned idx) const {
88 assert (idx < getNumArgs());
89 return (*Args)[idx];
90 }
91
Ted Kremenek00a3a5f2008-03-12 01:21:45 +000092 RetEffect getRet() const {
93 return Ret;
94 }
95
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000096 typedef ArgEffects::const_iterator arg_iterator;
97
98 arg_iterator begin_args() const { return Args->begin(); }
99 arg_iterator end_args() const { return Args->end(); }
100
101 static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) {
102 ID.AddPointer(A);
103 ID.Add(R);
104 }
105
106 void Profile(llvm::FoldingSetNodeID& ID) const {
107 Profile(ID, Args, Ret);
108 }
109};
110
111
112class CFRefSummaryManager {
113 typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
114 typedef llvm::FoldingSet<CFRefSummary> SummarySetTy;
115 typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*> SummaryMapTy;
116
117 SummarySetTy SummarySet;
118 SummaryMapTy SummaryMap;
119 AESetTy AESet;
120 llvm::BumpPtrAllocator BPAlloc;
121
122 ArgEffects ScratchArgs;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000123
124
125 ArgEffects* getArgEffects();
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000126
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000127 CFRefSummary* getCannedCFSummary(FunctionTypeProto* FT, bool isRetain);
128
129 CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName);
130
131 CFRefSummary* getCFSummaryCreateRule(FunctionTypeProto* FT);
132 CFRefSummary* getCFSummaryGetRule(FunctionTypeProto* FT);
133
134 CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
135
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000136public:
137 CFRefSummaryManager() {}
138 ~CFRefSummaryManager();
139
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000140 CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000141};
142
143} // end anonymous namespace
144
145//===----------------------------------------------------------------------===//
146// Implementation of checker data structures.
147//===----------------------------------------------------------------------===//
148
149CFRefSummaryManager::~CFRefSummaryManager() {
150
151 // FIXME: The ArgEffects could eventually be allocated from BPAlloc,
152 // mitigating the need to do explicit cleanup of the
153 // Argument-Effect summaries.
154
155 for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
156 I->getValue().~ArgEffects();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000157}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000158
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000159ArgEffects* CFRefSummaryManager::getArgEffects() {
160
161 assert (!ScratchArgs.empty());
162
163 llvm::FoldingSetNodeID profile;
164 profile.Add(ScratchArgs);
165 void* InsertPos;
166
167 llvm::FoldingSetNodeWrapper<ArgEffects>* E =
168 AESet.FindNodeOrInsertPos(profile, InsertPos);
169
170 if (E) {
171 ScratchArgs.clear();
172 return &E->getValue();
173 }
174
175 E = (llvm::FoldingSetNodeWrapper<ArgEffects>*)
176 BPAlloc.Allocate<llvm::FoldingSetNodeWrapper<ArgEffects> >();
177
178 new (E) llvm::FoldingSetNodeWrapper<ArgEffects>(ScratchArgs);
179 AESet.InsertNode(E, InsertPos);
180
181 ScratchArgs.clear();
182 return &E->getValue();
183}
184
185CFRefSummary* CFRefSummaryManager::getPersistentSummary(ArgEffects* AE,
186 RetEffect RE) {
187
188 llvm::FoldingSetNodeID profile;
189 CFRefSummary::Profile(profile, AE, RE);
190 void* InsertPos;
191
192 CFRefSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos);
193
194 if (Summ)
195 return Summ;
196
197 Summ = (CFRefSummary*) BPAlloc.Allocate<CFRefSummary>();
198 new (Summ) CFRefSummary(AE, RE);
199 SummarySet.InsertNode(Summ, InsertPos);
200
201 return Summ;
202}
203
204
205CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD,
206 ASTContext& Ctx) {
207
208 SourceLocation Loc = FD->getLocation();
209
210 if (!Loc.isFileID())
211 return NULL;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000212
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000213 { // Look into our cache of summaries to see if we have already computed
214 // a summary for this FunctionDecl.
215
216 SummaryMapTy::iterator I = SummaryMap.find(FD);
217
218 if (I != SummaryMap.end())
219 return I->second;
220 }
221
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000222#if 0
223 SourceManager& SrcMgr = Ctx.getSourceManager();
224 unsigned fid = Loc.getFileID();
225 const FileEntry* FE = SrcMgr.getFileEntryForID(fid);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000226
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000227 if (!FE)
228 return NULL;
229
230 const char* DirName = FE->getDir()->getName();
231 assert (DirName);
232 assert (strlen(DirName) > 0);
233
234 if (!strstr(DirName, "CoreFoundation")) {
235 SummaryMap[FD] = NULL;
236 return NULL;
237 }
238#endif
239
240 const char* FName = FD->getIdentifier()->getName();
241
242 if (FName[0] == 'C' && FName[1] == 'F') {
243 CFRefSummary* S = getCFSummary(FD, FName);
244 SummaryMap[FD] = S;
245 return S;
246 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000247
248 return NULL;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000249}
250
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000251CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD,
252 const char* FName) {
253
254 // For now, only generate summaries for functions that have a prototype.
255
256 FunctionTypeProto* FT =
257 dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
258
259 if (!FT)
260 return NULL;
261
262 FName += 2;
263
264 if (strcmp(FName, "Retain") == 0)
265 return getCannedCFSummary(FT, true);
266
267 if (strcmp(FName, "Release") == 0)
268 return getCannedCFSummary(FT, false);
269
270 assert (ScratchArgs.empty());
271 bool usesCreateRule = false;
272
273 if (strstr(FName, "Create"))
274 usesCreateRule = true;
275
276 if (!usesCreateRule && strstr(FName, "Copy"))
277 usesCreateRule = true;
278
279 if (usesCreateRule)
280 return getCFSummaryCreateRule(FT);
281
282 if (strstr(FName, "Get"))
283 return getCFSummaryGetRule(FT);
284
285 return NULL;
286}
287
288CFRefSummary* CFRefSummaryManager::getCannedCFSummary(FunctionTypeProto* FT,
289 bool isRetain) {
290
291 if (FT->getNumArgs() != 1)
292 return NULL;
293
294 TypedefType* ArgT = dyn_cast<TypedefType>(FT->getArgType(0).getTypePtr());
295
296 if (!ArgT)
297 return NULL;
298
299 // For CFRetain/CFRelease, the first (and only) argument is of type
300 // "CFTypeRef".
301
302 const char* TDName = ArgT->getDecl()->getIdentifier()->getName();
303 assert (TDName);
304
305 if (strcmp("CFTypeRef", TDName) == 0)
306 return NULL;
307
308 if (!ArgT->isPointerType())
309 return NULL;
310
311 // Check the return type. It should also be "CFTypeRef".
312
313 QualType RetTy = FT->getResultType();
314
315 if (RetTy.getTypePtr() != ArgT)
316 return NULL;
317
318 // The function's interface checks out. Generate a canned summary.
319
320 assert (ScratchArgs.empty());
321 ScratchArgs.push_back(isRetain ? IncRef : DecRef);
322
323 return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0));
324}
325
326static bool isCFRefType(QualType T) {
327
328 if (!T->isPointerType())
329 return false;
330
331 // Check the typedef for the name "CF" and the substring "Ref".
332
333 TypedefType* TD = dyn_cast<TypedefType>(T.getTypePtr());
334
335 if (!TD)
336 return false;
337
338 const char* TDName = TD->getDecl()->getIdentifier()->getName();
339 assert (TDName);
340
341 if (TDName[0] != 'C' || TDName[1] != 'F')
342 return false;
343
344 if (strstr(TDName, "Ref") == 0)
345 return false;
346
347 return true;
348}
349
350
351CFRefSummary*
352CFRefSummaryManager::getCFSummaryCreateRule(FunctionTypeProto* FT) {
353
354 if (!isCFRefType(FT->getResultType()))
355 return NULL;
356
357 assert (ScratchArgs.empty());
358
359 // FIXME: Add special-cases for functions that retain/release. For now
360 // just handle the default case.
361
362 for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
363 ScratchArgs.push_back(DoNothing);
364
365 return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned());
366}
367
368CFRefSummary*
369CFRefSummaryManager::getCFSummaryGetRule(FunctionTypeProto* FT) {
370
371 if (!isCFRefType(FT->getResultType()))
372 return NULL;
373
374 assert (ScratchArgs.empty());
375
376 // FIXME: Add special-cases for functions that retain/release. For now
377 // just handle the default case.
378
379 for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
380 ScratchArgs.push_back(DoNothing);
381
382 return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned());
383}
384
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000385//===----------------------------------------------------------------------===//
386// Transfer functions.
387//===----------------------------------------------------------------------===//
388
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000389namespace {
390
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000391class RefVal {
392 unsigned Data;
393
394 RefVal(unsigned K, unsigned D) : Data((D << 3) | K) {
395 assert ((K & ~0x5) == 0x0);
396 }
397
398 RefVal(unsigned K) : Data(K) {
399 assert ((K & ~0x5) == 0x0);
400 }
401
402public:
403 enum Kind { Owned = 0, AcqOwned = 1, NotOwned = 2, Released = 3,
404 ErrorUseAfterRelease = 4, ErrorReleaseNotOwned = 5 };
405
406
407 Kind getKind() const { return (Kind) (Data & 0x5); }
408
409 unsigned getCount() const {
410 assert (getKind() == Owned || getKind() == AcqOwned);
411 return Data >> 3;
412 }
413
Ted Kremenek73c750b2008-03-11 18:14:09 +0000414 static bool isError(Kind k) { return k >= ErrorUseAfterRelease; }
415
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000416 static RefVal makeOwned(unsigned Count) { return RefVal(Owned, Count); }
417 static RefVal makeAcqOwned(unsigned Count) { return RefVal(AcqOwned, Count); }
418 static RefVal makeNotOwned() { return RefVal(NotOwned); }
419 static RefVal makeReleased() { return RefVal(Released); }
420 static RefVal makeUseAfterRelease() { return RefVal(ErrorUseAfterRelease); }
421 static RefVal makeReleaseNotOwned() { return RefVal(ErrorReleaseNotOwned); }
422
423 bool operator==(const RefVal& X) const { return Data == X.Data; }
424 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
Ted Kremenekf3948042008-03-11 19:44:10 +0000425
426 void print(std::ostream& Out) const;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000427};
Ted Kremenekf3948042008-03-11 19:44:10 +0000428
429void RefVal::print(std::ostream& Out) const {
430 switch (getKind()) {
431 default: assert(false);
432 case Owned:
433 Out << "Owned(" << getCount() << ")";
434 break;
435
436 case AcqOwned:
437 Out << "Acquired-Owned(" << getCount() << ")";
438 break;
439
440 case NotOwned:
441 Out << "Not-Owned";
442 break;
443
444 case Released:
445 Out << "Released";
446 break;
447
448 case ErrorUseAfterRelease:
449 Out << "Use-After-Release [ERROR]";
450 break;
451
452 case ErrorReleaseNotOwned:
453 Out << "Release of Not-Owned [ERROR]";
454 break;
455 }
456}
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000457
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000458class CFRefCount : public GRSimpleVals {
Ted Kremenekf3948042008-03-11 19:44:10 +0000459
460 // Type definitions.
461
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000462 typedef llvm::ImmutableMap<SymbolID, RefVal> RefBindings;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000463 typedef RefBindings::Factory RefBFactoryTy;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000464
465 typedef llvm::SmallPtrSet<GRExprEngine::NodeTy*,2> UseAfterReleasesTy;
466 typedef llvm::SmallPtrSet<GRExprEngine::NodeTy*,2> ReleasesNotOwnedTy;
467
Ted Kremenekf3948042008-03-11 19:44:10 +0000468 class BindingsPrinter : public ValueState::CheckerStatePrinter {
469 public:
470 virtual void PrintCheckerState(std::ostream& Out, void* State,
471 const char* nl, const char* sep);
472 };
473
474 // Instance variables.
475
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000476 CFRefSummaryManager Summaries;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000477 RefBFactoryTy RefBFactory;
478
Ted Kremenek73c750b2008-03-11 18:14:09 +0000479 UseAfterReleasesTy UseAfterReleases;
480 ReleasesNotOwnedTy ReleasesNotOwned;
481
Ted Kremenekf3948042008-03-11 19:44:10 +0000482 BindingsPrinter Printer;
483
484 // Private methods.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000485
486 static RefBindings GetRefBindings(ValueState& StImpl) {
487 return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
488 }
489
490 static void SetRefBindings(ValueState& StImpl, RefBindings B) {
491 StImpl.CheckerState = B.getRoot();
492 }
493
494 RefBindings Remove(RefBindings B, SymbolID sym) {
495 return RefBFactory.Remove(B, sym);
496 }
497
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000498 RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E,
Ted Kremenek73c750b2008-03-11 18:14:09 +0000499 RefVal::Kind& hasError);
Ted Kremenekf3948042008-03-11 19:44:10 +0000500
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000501
502public:
503 CFRefCount() {}
504 virtual ~CFRefCount() {}
Ted Kremenekf3948042008-03-11 19:44:10 +0000505
506 virtual ValueState::CheckerStatePrinter* getCheckerStatePrinter() {
507 return &Printer;
508 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000509
510 // Calls.
511
512 virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000513 GRExprEngine& Eng,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000514 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000515 CallExpr* CE, LVal L,
516 ExplodedNode<ValueState>* Pred);
Ted Kremenekfa34b332008-04-09 01:10:13 +0000517
518 // Error iterators.
519
520 typedef UseAfterReleasesTy::iterator use_after_iterator;
521 typedef ReleasesNotOwnedTy::iterator bad_release_iterator;
522
523 use_after_iterator begin_use_after() { return UseAfterReleases.begin(); }
524 use_after_iterator end_use_after() { return UseAfterReleases.end(); }
525
526 bad_release_iterator begin_bad_release() { return ReleasesNotOwned.begin(); }
527 bad_release_iterator end_bad_release() { return ReleasesNotOwned.end(); }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000528};
529
530} // end anonymous namespace
531
Ted Kremenekf3948042008-03-11 19:44:10 +0000532void CFRefCount::BindingsPrinter::PrintCheckerState(std::ostream& Out,
533 void* State, const char* nl,
534 const char* sep) {
535 RefBindings B((RefBindings::TreeTy*) State);
536
537 if (State)
538 Out << sep << nl;
539
540 for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
541 Out << (*I).first << " : ";
542 (*I).second.print(Out);
543 Out << nl;
544 }
545}
546
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000547void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000548 GRExprEngine& Eng,
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000549 GRStmtNodeBuilder<ValueState>& Builder,
550 CallExpr* CE, LVal L,
551 ExplodedNode<ValueState>* Pred) {
552
Ted Kremenek199e1a02008-03-12 21:06:49 +0000553 ValueStateManager& StateMgr = Eng.getStateManager();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000554
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000555 // FIXME: Support calls to things other than lval::FuncVal. At the very
556 // least we should stop tracking ref-state for ref-counted objects passed
557 // to these functions.
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000558
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000559 assert (isa<lval::FuncVal>(L) && "Not yet implemented.");
560
561 // Get the summary.
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000562
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000563 lval::FuncVal FV = cast<lval::FuncVal>(L);
564 FunctionDecl* FD = FV.getDecl();
Ted Kremenek199e1a02008-03-12 21:06:49 +0000565 CFRefSummary* Summ = Summaries.getSummary(FD, Eng.getContext());
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000566
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000567 // Get the state.
568
569 ValueState* St = Builder.GetState(Pred);
570
571 // Evaluate the effects of the call.
572
573 ValueState StVals = *St;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000574 RefVal::Kind hasError = (RefVal::Kind) 0;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000575
576 if (!Summ) {
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000577
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000578 // This function has no summary. Invalidate all reference-count state
579 // for arguments passed to this function, and also nuke the values of
580 // arguments passed-by-reference.
581
582 ValueState StVals = *St;
583
584 for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
585 I != E; ++I) {
586
587 RVal V = StateMgr.GetRVal(St, *I);
588
589 if (isa<lval::SymbolVal>(V)) {
590 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
591 RefBindings B = GetRefBindings(StVals);
592 SetRefBindings(StVals, Remove(B, Sym));
593 }
594
595 if (isa<LVal>(V))
596 StateMgr.Unbind(StVals, cast<LVal>(V));
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000597 }
598
599 St = StateMgr.getPersistentState(StVals);
Ted Kremenek199e1a02008-03-12 21:06:49 +0000600
601 // Make up a symbol for the return value of this function.
602
603 if (CE->getType() != Eng.getContext().VoidTy) {
604 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000605 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek199e1a02008-03-12 21:06:49 +0000606
607 RVal X = CE->getType()->isPointerType()
608 ? cast<RVal>(lval::SymbolVal(Sym))
609 : cast<RVal>(nonlval::SymbolVal(Sym));
610
611 St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false);
612 }
613
Ted Kremenek0e561a32008-03-21 21:30:14 +0000614 Builder.MakeNode(Dst, CE, Pred, St);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000615 return;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000616 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000617
618 // This function has a summary. Evaluate the effect of the arguments.
619
620 unsigned idx = 0;
621
622 for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end();
623 I!=E; ++I, ++idx) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000624
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000625 RVal V = StateMgr.GetRVal(St, *I);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000626
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000627 if (isa<lval::SymbolVal>(V)) {
628 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
629 RefBindings B = GetRefBindings(StVals);
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000630
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000631 if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
632 B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError);
633 SetRefBindings(StVals, B);
634 if (hasError) break;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000635 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000636 }
637 }
638
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000639 if (hasError) {
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000640 St = StateMgr.getPersistentState(StVals);
Ted Kremenek73c750b2008-03-11 18:14:09 +0000641 GRExprEngine::NodeTy* N = Builder.generateNode(CE, St, Pred);
642
643 if (N) {
644 N->markAsSink();
645
646 switch (hasError) {
647 default: assert(false);
648 case RefVal::ErrorUseAfterRelease:
649 UseAfterReleases.insert(N);
650 break;
651
652 case RefVal::ErrorReleaseNotOwned:
653 ReleasesNotOwned.insert(N);
654 break;
655 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000656 }
657
658 return;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000659 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000660
661 // Finally, consult the summary for the return value.
662
663 RetEffect RE = Summ->getRet();
664 St = StateMgr.getPersistentState(StVals);
665
666
667 switch (RE.getKind()) {
668 default:
669 assert (false && "Unhandled RetEffect."); break;
670
671 case RetEffect::Alias: {
672 unsigned idx = RE.getValue();
673 assert (idx < CE->getNumArgs());
674 RVal V = StateMgr.GetRVal(St, CE->getArg(idx));
Ted Kremenek199e1a02008-03-12 21:06:49 +0000675 St = StateMgr.SetRVal(St, CE, V, Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000676 break;
677 }
678
679 case RetEffect::OwnedSymbol: {
680 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000681 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000682
683 ValueState StImpl = *St;
684 RefBindings B = GetRefBindings(StImpl);
685 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned(1)));
686
687 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
688 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000689 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000690
691 break;
692 }
693
694 case RetEffect::NotOwnedSymbol: {
695 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000696 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000697
698 ValueState StImpl = *St;
699 RefBindings B = GetRefBindings(StImpl);
700 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned()));
701
702 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
703 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000704 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000705
706 break;
707 }
708 }
709
Ted Kremenek0e561a32008-03-21 21:30:14 +0000710 Builder.MakeNode(Dst, CE, Pred, St);
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000711}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000712
713
714CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000715 RefVal V, ArgEffect E,
Ted Kremenek73c750b2008-03-11 18:14:09 +0000716 RefVal::Kind& hasError) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000717
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000718 // FIXME: This dispatch can potentially be sped up by unifiying it into
719 // a single switch statement. Opt for simplicity for now.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000720
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000721 switch (E) {
722 default:
723 assert (false && "Unhandled CFRef transition.");
724
725 case DoNothing:
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000726 if (V.getKind() == RefVal::Released) {
727 V = RefVal::makeUseAfterRelease();
728 hasError = V.getKind();
729 break;
730 }
731
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000732 return B;
733
734 case IncRef:
735 switch (V.getKind()) {
736 default:
737 assert(false);
738
739 case RefVal::Owned:
740 V = RefVal::makeOwned(V.getCount()+1); break;
741
742 case RefVal::AcqOwned:
743 V = RefVal::makeAcqOwned(V.getCount()+1);
744 break;
745
746 case RefVal::NotOwned:
747 V = RefVal::makeAcqOwned(1);
748 break;
749
750 case RefVal::Released:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000751 V = RefVal::makeUseAfterRelease();
Ted Kremenek73c750b2008-03-11 18:14:09 +0000752 hasError = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000753 break;
754 }
755
756 case DecRef:
757 switch (V.getKind()) {
758 default:
759 assert (false);
760
761 case RefVal::Owned: {
762 unsigned Count = V.getCount() - 1;
763 V = Count ? RefVal::makeOwned(Count) : RefVal::makeReleased();
764 break;
765 }
766
767 case RefVal::AcqOwned: {
768 unsigned Count = V.getCount() - 1;
769 V = Count ? RefVal::makeAcqOwned(Count) : RefVal::makeNotOwned();
770 break;
771 }
772
773 case RefVal::NotOwned:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000774 V = RefVal::makeReleaseNotOwned();
Ted Kremenek73c750b2008-03-11 18:14:09 +0000775 hasError = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000776 break;
777
778 case RefVal::Released:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000779 V = RefVal::makeUseAfterRelease();
Ted Kremenek73c750b2008-03-11 18:14:09 +0000780 hasError = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000781 break;
782 }
783 }
784
785 return RefBFactory.Add(B, sym, V);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000786}
787
Ted Kremenekfa34b332008-04-09 01:10:13 +0000788
789//===----------------------------------------------------------------------===//
790// Bug Descriptions.
791//===----------------------------------------------------------------------===//
792
793namespace {
794
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000795class VISIBILITY_HIDDEN UseAfterRelease : public BugType {
Ted Kremenekfa34b332008-04-09 01:10:13 +0000796
797public:
798 virtual const char* getName() const {
799 return "(CoreFoundation) use-after-release";
800 }
801 virtual const char* getDescription() const {
802 return "(CoreFoundation) Reference-counted object is used"
803 " after it is released.";
804 }
805};
806
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000807class VISIBILITY_HIDDEN BadRelease : public BugType {
Ted Kremenekfa34b332008-04-09 01:10:13 +0000808
809public:
810 virtual const char* getName() const {
811 return "(CoreFoundation) release of non-owned object";
812 }
813 virtual const char* getDescription() const {
814 return "Incorrect decrement of reference count of CoreFoundation object:\n"
815 "The object is not owned at this point by the caller.";
816 }
817};
818
819} // end anonymous namespace
820
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000821//===----------------------------------------------------------------------===//
822// Driver for the CFRefCount Checker.
823//===----------------------------------------------------------------------===//
824
825namespace clang {
826
Ted Kremenekfa34b332008-04-09 01:10:13 +0000827void CheckCFRefCount(CFG& cfg, Decl& CD, ASTContext& Ctx,
828 Diagnostic& Diag, PathDiagnosticClient* PD) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000829
Ted Kremenekfa34b332008-04-09 01:10:13 +0000830 if (Diag.hasErrorOccurred())
831 return;
832
833 // FIXME: Refactor some day so this becomes a single function invocation.
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000834 GRExprEngine Eng(cfg, CD, Ctx);
Ted Kremenekfa34b332008-04-09 01:10:13 +0000835 CFRefCount TF;
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000836 Eng.setTransferFunctions(TF);
Ted Kremenekfa34b332008-04-09 01:10:13 +0000837 Eng.ExecuteWorkList();
838
Ted Kremenek50a6d0c2008-04-09 21:41:14 +0000839 // FIXME: Emit warnings.
Ted Kremenekfa34b332008-04-09 01:10:13 +0000840
841}
842
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000843} // end clang namespace