blob: 85c8e8650050ff1edd4fc5182c498a46ea20acc6 [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 Kremenek05cbe1a2008-04-09 23:49:11 +000029//===----------------------------------------------------------------------===//
30// Symbolic Evaluation of Reference Counting Logic
31//===----------------------------------------------------------------------===//
32
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000033namespace {
34 enum ArgEffect { IncRef, DecRef, DoNothing };
35 typedef std::vector<ArgEffect> ArgEffects;
36}
Ted Kremenek2fff37e2008-03-06 00:08:09 +000037
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000038namespace llvm {
39 template <> struct FoldingSetTrait<ArgEffects> {
40 static void Profile(const ArgEffects& X, FoldingSetNodeID ID) {
41 for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I)
42 ID.AddInteger((unsigned) *I);
43 }
44
45 static void Profile(ArgEffects& X, FoldingSetNodeID ID) {
46 Profile(X, ID);
47 }
48 };
49} // end llvm namespace
50
51namespace {
Ted Kremenek2fff37e2008-03-06 00:08:09 +000052
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000053class RetEffect {
54public:
55 enum Kind { Alias = 0x0, OwnedSymbol = 0x1, NotOwnedSymbol = 0x2 };
56
57private:
58 unsigned Data;
59 RetEffect(Kind k, unsigned D) { Data = (Data << 2) | (unsigned) k; }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000060
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000061public:
62
63 Kind getKind() const { return (Kind) (Data & 0x3); }
64
65 unsigned getValue() const {
66 assert(getKind() == Alias);
67 return Data & ~0x3;
68 }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000069
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000070 static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000071
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000072 static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000073
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000074 static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
75
76 operator Kind() const { return getKind(); }
77
78 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
79};
80
81
82class CFRefSummary : public llvm::FoldingSetNode {
83 ArgEffects* Args;
84 RetEffect Ret;
85public:
86
87 CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
88
89 unsigned getNumArgs() const { return Args->size(); }
90
Ted Kremenek1ac08d62008-03-11 17:48:22 +000091 ArgEffect getArg(unsigned idx) const {
92 assert (idx < getNumArgs());
93 return (*Args)[idx];
94 }
95
Ted Kremenek00a3a5f2008-03-12 01:21:45 +000096 RetEffect getRet() const {
97 return Ret;
98 }
99
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000100 typedef ArgEffects::const_iterator arg_iterator;
101
102 arg_iterator begin_args() const { return Args->begin(); }
103 arg_iterator end_args() const { return Args->end(); }
104
105 static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) {
106 ID.AddPointer(A);
107 ID.Add(R);
108 }
109
110 void Profile(llvm::FoldingSetNodeID& ID) const {
111 Profile(ID, Args, Ret);
112 }
113};
114
115
116class CFRefSummaryManager {
117 typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
118 typedef llvm::FoldingSet<CFRefSummary> SummarySetTy;
119 typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*> SummaryMapTy;
120
121 SummarySetTy SummarySet;
122 SummaryMapTy SummaryMap;
123 AESetTy AESet;
124 llvm::BumpPtrAllocator BPAlloc;
125
126 ArgEffects ScratchArgs;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000127
128
129 ArgEffects* getArgEffects();
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000130
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000131 CFRefSummary* getCannedCFSummary(FunctionTypeProto* FT, bool isRetain);
132
133 CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName);
134
135 CFRefSummary* getCFSummaryCreateRule(FunctionTypeProto* FT);
136 CFRefSummary* getCFSummaryGetRule(FunctionTypeProto* FT);
137
138 CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
139
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000140public:
141 CFRefSummaryManager() {}
142 ~CFRefSummaryManager();
143
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000144 CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000145};
146
147} // end anonymous namespace
148
149//===----------------------------------------------------------------------===//
150// Implementation of checker data structures.
151//===----------------------------------------------------------------------===//
152
153CFRefSummaryManager::~CFRefSummaryManager() {
154
155 // FIXME: The ArgEffects could eventually be allocated from BPAlloc,
156 // mitigating the need to do explicit cleanup of the
157 // Argument-Effect summaries.
158
159 for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
160 I->getValue().~ArgEffects();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000161}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000162
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000163ArgEffects* CFRefSummaryManager::getArgEffects() {
164
165 assert (!ScratchArgs.empty());
166
167 llvm::FoldingSetNodeID profile;
168 profile.Add(ScratchArgs);
169 void* InsertPos;
170
171 llvm::FoldingSetNodeWrapper<ArgEffects>* E =
172 AESet.FindNodeOrInsertPos(profile, InsertPos);
173
174 if (E) {
175 ScratchArgs.clear();
176 return &E->getValue();
177 }
178
179 E = (llvm::FoldingSetNodeWrapper<ArgEffects>*)
180 BPAlloc.Allocate<llvm::FoldingSetNodeWrapper<ArgEffects> >();
181
182 new (E) llvm::FoldingSetNodeWrapper<ArgEffects>(ScratchArgs);
183 AESet.InsertNode(E, InsertPos);
184
185 ScratchArgs.clear();
186 return &E->getValue();
187}
188
189CFRefSummary* CFRefSummaryManager::getPersistentSummary(ArgEffects* AE,
190 RetEffect RE) {
191
192 llvm::FoldingSetNodeID profile;
193 CFRefSummary::Profile(profile, AE, RE);
194 void* InsertPos;
195
196 CFRefSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos);
197
198 if (Summ)
199 return Summ;
200
201 Summ = (CFRefSummary*) BPAlloc.Allocate<CFRefSummary>();
202 new (Summ) CFRefSummary(AE, RE);
203 SummarySet.InsertNode(Summ, InsertPos);
204
205 return Summ;
206}
207
208
209CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD,
210 ASTContext& Ctx) {
211
212 SourceLocation Loc = FD->getLocation();
213
214 if (!Loc.isFileID())
215 return NULL;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000216
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000217 { // Look into our cache of summaries to see if we have already computed
218 // a summary for this FunctionDecl.
219
220 SummaryMapTy::iterator I = SummaryMap.find(FD);
221
222 if (I != SummaryMap.end())
223 return I->second;
224 }
225
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000226#if 0
227 SourceManager& SrcMgr = Ctx.getSourceManager();
228 unsigned fid = Loc.getFileID();
229 const FileEntry* FE = SrcMgr.getFileEntryForID(fid);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000230
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000231 if (!FE)
232 return NULL;
233
234 const char* DirName = FE->getDir()->getName();
235 assert (DirName);
236 assert (strlen(DirName) > 0);
237
238 if (!strstr(DirName, "CoreFoundation")) {
239 SummaryMap[FD] = NULL;
240 return NULL;
241 }
242#endif
243
244 const char* FName = FD->getIdentifier()->getName();
245
246 if (FName[0] == 'C' && FName[1] == 'F') {
247 CFRefSummary* S = getCFSummary(FD, FName);
248 SummaryMap[FD] = S;
249 return S;
250 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000251
252 return NULL;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000253}
254
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000255CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD,
256 const char* FName) {
257
258 // For now, only generate summaries for functions that have a prototype.
259
260 FunctionTypeProto* FT =
261 dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
262
263 if (!FT)
264 return NULL;
265
266 FName += 2;
267
268 if (strcmp(FName, "Retain") == 0)
269 return getCannedCFSummary(FT, true);
270
271 if (strcmp(FName, "Release") == 0)
272 return getCannedCFSummary(FT, false);
273
274 assert (ScratchArgs.empty());
275 bool usesCreateRule = false;
276
277 if (strstr(FName, "Create"))
278 usesCreateRule = true;
279
280 if (!usesCreateRule && strstr(FName, "Copy"))
281 usesCreateRule = true;
282
283 if (usesCreateRule)
284 return getCFSummaryCreateRule(FT);
285
286 if (strstr(FName, "Get"))
287 return getCFSummaryGetRule(FT);
288
289 return NULL;
290}
291
292CFRefSummary* CFRefSummaryManager::getCannedCFSummary(FunctionTypeProto* FT,
293 bool isRetain) {
294
295 if (FT->getNumArgs() != 1)
296 return NULL;
297
298 TypedefType* ArgT = dyn_cast<TypedefType>(FT->getArgType(0).getTypePtr());
299
300 if (!ArgT)
301 return NULL;
302
303 // For CFRetain/CFRelease, the first (and only) argument is of type
304 // "CFTypeRef".
305
306 const char* TDName = ArgT->getDecl()->getIdentifier()->getName();
307 assert (TDName);
308
309 if (strcmp("CFTypeRef", TDName) == 0)
310 return NULL;
311
312 if (!ArgT->isPointerType())
313 return NULL;
314
315 // Check the return type. It should also be "CFTypeRef".
316
317 QualType RetTy = FT->getResultType();
318
319 if (RetTy.getTypePtr() != ArgT)
320 return NULL;
321
322 // The function's interface checks out. Generate a canned summary.
323
324 assert (ScratchArgs.empty());
325 ScratchArgs.push_back(isRetain ? IncRef : DecRef);
326
327 return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0));
328}
329
330static bool isCFRefType(QualType T) {
331
332 if (!T->isPointerType())
333 return false;
334
335 // Check the typedef for the name "CF" and the substring "Ref".
336
337 TypedefType* TD = dyn_cast<TypedefType>(T.getTypePtr());
338
339 if (!TD)
340 return false;
341
342 const char* TDName = TD->getDecl()->getIdentifier()->getName();
343 assert (TDName);
344
345 if (TDName[0] != 'C' || TDName[1] != 'F')
346 return false;
347
348 if (strstr(TDName, "Ref") == 0)
349 return false;
350
351 return true;
352}
353
354
355CFRefSummary*
356CFRefSummaryManager::getCFSummaryCreateRule(FunctionTypeProto* FT) {
357
358 if (!isCFRefType(FT->getResultType()))
359 return NULL;
360
361 assert (ScratchArgs.empty());
362
363 // FIXME: Add special-cases for functions that retain/release. For now
364 // just handle the default case.
365
366 for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
367 ScratchArgs.push_back(DoNothing);
368
369 return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned());
370}
371
372CFRefSummary*
373CFRefSummaryManager::getCFSummaryGetRule(FunctionTypeProto* FT) {
374
375 if (!isCFRefType(FT->getResultType()))
376 return NULL;
377
378 assert (ScratchArgs.empty());
379
380 // FIXME: Add special-cases for functions that retain/release. For now
381 // just handle the default case.
382
383 for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
384 ScratchArgs.push_back(DoNothing);
385
386 return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned());
387}
388
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000389//===----------------------------------------------------------------------===//
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000390// Bug Descriptions.
391//===----------------------------------------------------------------------===//
392
393namespace {
394
395 class CFRefCount;
396
397 class VISIBILITY_HIDDEN CFRefBug : public BugType {
398 protected:
399 CFRefCount& TF;
400
401 public:
402 CFRefBug(CFRefCount& tf) : TF(tf) {}
403 };
404
405 class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug {
406 public:
407 UseAfterRelease(CFRefCount& tf) : CFRefBug(tf) {}
408
409 virtual const char* getName() const {
410 return "(CoreFoundation) use-after-release";
411 }
412 virtual const char* getDescription() const {
413 return "(CoreFoundation) Reference-counted object is used"
414 " after it is released.";
415 }
416
417 virtual void EmitWarnings(BugReporter& BR);
418
419 };
420
421 class VISIBILITY_HIDDEN BadRelease : public CFRefBug {
422 public:
423 BadRelease(CFRefCount& tf) : CFRefBug(tf) {}
424
425 virtual const char* getName() const {
426 return "(CoreFoundation) release of non-owned object";
427 }
428 virtual const char* getDescription() const {
429 return "Incorrect decrement of the reference count of a "
430 "CoreFoundation object:\n"
431 "The object is not owned at this point by the caller.";
432 }
433
434 virtual void EmitWarnings(BugReporter& BR);
435 };
436
437} // end anonymous namespace
438
439//===----------------------------------------------------------------------===//
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000440// Transfer functions.
441//===----------------------------------------------------------------------===//
442
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000443namespace {
444
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000445class VISIBILITY_HIDDEN RefVal {
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000446 unsigned Data;
447
448 RefVal(unsigned K, unsigned D) : Data((D << 3) | K) {
449 assert ((K & ~0x5) == 0x0);
450 }
451
452 RefVal(unsigned K) : Data(K) {
453 assert ((K & ~0x5) == 0x0);
454 }
455
456public:
457 enum Kind { Owned = 0, AcqOwned = 1, NotOwned = 2, Released = 3,
458 ErrorUseAfterRelease = 4, ErrorReleaseNotOwned = 5 };
459
460
461 Kind getKind() const { return (Kind) (Data & 0x5); }
462
463 unsigned getCount() const {
464 assert (getKind() == Owned || getKind() == AcqOwned);
465 return Data >> 3;
466 }
467
Ted Kremenek73c750b2008-03-11 18:14:09 +0000468 static bool isError(Kind k) { return k >= ErrorUseAfterRelease; }
469
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000470 static RefVal makeOwned(unsigned Count) { return RefVal(Owned, Count); }
471 static RefVal makeAcqOwned(unsigned Count) { return RefVal(AcqOwned, Count); }
472 static RefVal makeNotOwned() { return RefVal(NotOwned); }
473 static RefVal makeReleased() { return RefVal(Released); }
474 static RefVal makeUseAfterRelease() { return RefVal(ErrorUseAfterRelease); }
475 static RefVal makeReleaseNotOwned() { return RefVal(ErrorReleaseNotOwned); }
476
477 bool operator==(const RefVal& X) const { return Data == X.Data; }
478 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
Ted Kremenekf3948042008-03-11 19:44:10 +0000479
480 void print(std::ostream& Out) const;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000481};
Ted Kremenekf3948042008-03-11 19:44:10 +0000482
483void RefVal::print(std::ostream& Out) const {
484 switch (getKind()) {
485 default: assert(false);
486 case Owned:
487 Out << "Owned(" << getCount() << ")";
488 break;
489
490 case AcqOwned:
491 Out << "Acquired-Owned(" << getCount() << ")";
492 break;
493
494 case NotOwned:
495 Out << "Not-Owned";
496 break;
497
498 case Released:
499 Out << "Released";
500 break;
501
502 case ErrorUseAfterRelease:
503 Out << "Use-After-Release [ERROR]";
504 break;
505
506 case ErrorReleaseNotOwned:
507 Out << "Release of Not-Owned [ERROR]";
508 break;
509 }
510}
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000511
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000512class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals {
Ted Kremenekf3948042008-03-11 19:44:10 +0000513
514 // Type definitions.
515
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000516 typedef llvm::ImmutableMap<SymbolID, RefVal> RefBindings;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000517 typedef RefBindings::Factory RefBFactoryTy;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000518
519 typedef llvm::SmallPtrSet<GRExprEngine::NodeTy*,2> UseAfterReleasesTy;
520 typedef llvm::SmallPtrSet<GRExprEngine::NodeTy*,2> ReleasesNotOwnedTy;
521
Ted Kremenekf3948042008-03-11 19:44:10 +0000522 class BindingsPrinter : public ValueState::CheckerStatePrinter {
523 public:
524 virtual void PrintCheckerState(std::ostream& Out, void* State,
525 const char* nl, const char* sep);
526 };
527
528 // Instance variables.
529
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000530 CFRefSummaryManager Summaries;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000531 RefBFactoryTy RefBFactory;
532
Ted Kremenek73c750b2008-03-11 18:14:09 +0000533 UseAfterReleasesTy UseAfterReleases;
534 ReleasesNotOwnedTy ReleasesNotOwned;
535
Ted Kremenekf3948042008-03-11 19:44:10 +0000536 BindingsPrinter Printer;
537
538 // Private methods.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000539
540 static RefBindings GetRefBindings(ValueState& StImpl) {
541 return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
542 }
543
544 static void SetRefBindings(ValueState& StImpl, RefBindings B) {
545 StImpl.CheckerState = B.getRoot();
546 }
547
548 RefBindings Remove(RefBindings B, SymbolID sym) {
549 return RefBFactory.Remove(B, sym);
550 }
551
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000552 RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E,
Ted Kremenek73c750b2008-03-11 18:14:09 +0000553 RefVal::Kind& hasError);
Ted Kremenekf3948042008-03-11 19:44:10 +0000554
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000555
556public:
557 CFRefCount() {}
558 virtual ~CFRefCount() {}
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000559
560 virtual void RegisterChecks(GRExprEngine& Eng);
Ted Kremenekf3948042008-03-11 19:44:10 +0000561
562 virtual ValueState::CheckerStatePrinter* getCheckerStatePrinter() {
563 return &Printer;
564 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000565
566 // Calls.
567
568 virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000569 GRExprEngine& Eng,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000570 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000571 CallExpr* CE, LVal L,
572 ExplodedNode<ValueState>* Pred);
Ted Kremenekfa34b332008-04-09 01:10:13 +0000573
574 // Error iterators.
575
576 typedef UseAfterReleasesTy::iterator use_after_iterator;
577 typedef ReleasesNotOwnedTy::iterator bad_release_iterator;
578
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000579 use_after_iterator use_after_begin() { return UseAfterReleases.begin(); }
580 use_after_iterator use_after_end() { return UseAfterReleases.end(); }
Ted Kremenekfa34b332008-04-09 01:10:13 +0000581
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000582 bad_release_iterator bad_release_begin() { return ReleasesNotOwned.begin(); }
583 bad_release_iterator bad_release_end() { return ReleasesNotOwned.end(); }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000584};
585
586} // end anonymous namespace
587
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000588void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
589 GRSimpleVals::RegisterChecks(Eng);
590 Eng.Register(new UseAfterRelease(*this));
591 Eng.Register(new BadRelease(*this));
592}
593
594
Ted Kremenekf3948042008-03-11 19:44:10 +0000595void CFRefCount::BindingsPrinter::PrintCheckerState(std::ostream& Out,
596 void* State, const char* nl,
597 const char* sep) {
598 RefBindings B((RefBindings::TreeTy*) State);
599
600 if (State)
601 Out << sep << nl;
602
603 for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
604 Out << (*I).first << " : ";
605 (*I).second.print(Out);
606 Out << nl;
607 }
608}
609
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000610void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000611 GRExprEngine& Eng,
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000612 GRStmtNodeBuilder<ValueState>& Builder,
613 CallExpr* CE, LVal L,
614 ExplodedNode<ValueState>* Pred) {
615
Ted Kremenek199e1a02008-03-12 21:06:49 +0000616 ValueStateManager& StateMgr = Eng.getStateManager();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000617
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000618 // FIXME: Support calls to things other than lval::FuncVal. At the very
619 // least we should stop tracking ref-state for ref-counted objects passed
620 // to these functions.
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000621
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000622 assert (isa<lval::FuncVal>(L) && "Not yet implemented.");
623
624 // Get the summary.
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000625
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000626 lval::FuncVal FV = cast<lval::FuncVal>(L);
627 FunctionDecl* FD = FV.getDecl();
Ted Kremenek199e1a02008-03-12 21:06:49 +0000628 CFRefSummary* Summ = Summaries.getSummary(FD, Eng.getContext());
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000629
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000630 // Get the state.
631
632 ValueState* St = Builder.GetState(Pred);
633
634 // Evaluate the effects of the call.
635
636 ValueState StVals = *St;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000637 RefVal::Kind hasError = (RefVal::Kind) 0;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000638
639 if (!Summ) {
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000640
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000641 // This function has no summary. Invalidate all reference-count state
642 // for arguments passed to this function, and also nuke the values of
643 // arguments passed-by-reference.
644
645 ValueState StVals = *St;
646
647 for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
648 I != E; ++I) {
649
650 RVal V = StateMgr.GetRVal(St, *I);
651
652 if (isa<lval::SymbolVal>(V)) {
653 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
654 RefBindings B = GetRefBindings(StVals);
655 SetRefBindings(StVals, Remove(B, Sym));
656 }
657
658 if (isa<LVal>(V))
659 StateMgr.Unbind(StVals, cast<LVal>(V));
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000660 }
661
662 St = StateMgr.getPersistentState(StVals);
Ted Kremenek199e1a02008-03-12 21:06:49 +0000663
664 // Make up a symbol for the return value of this function.
665
666 if (CE->getType() != Eng.getContext().VoidTy) {
667 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000668 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek199e1a02008-03-12 21:06:49 +0000669
670 RVal X = CE->getType()->isPointerType()
671 ? cast<RVal>(lval::SymbolVal(Sym))
672 : cast<RVal>(nonlval::SymbolVal(Sym));
673
674 St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false);
675 }
676
Ted Kremenek0e561a32008-03-21 21:30:14 +0000677 Builder.MakeNode(Dst, CE, Pred, St);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000678 return;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000679 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000680
681 // This function has a summary. Evaluate the effect of the arguments.
682
683 unsigned idx = 0;
684
685 for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end();
686 I!=E; ++I, ++idx) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000687
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000688 RVal V = StateMgr.GetRVal(St, *I);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000689
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000690 if (isa<lval::SymbolVal>(V)) {
691 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
692 RefBindings B = GetRefBindings(StVals);
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000693
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000694 if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
695 B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError);
696 SetRefBindings(StVals, B);
697 if (hasError) break;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000698 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000699 }
700 }
701
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000702 if (hasError) {
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000703 St = StateMgr.getPersistentState(StVals);
Ted Kremenek73c750b2008-03-11 18:14:09 +0000704 GRExprEngine::NodeTy* N = Builder.generateNode(CE, St, Pred);
705
706 if (N) {
707 N->markAsSink();
708
709 switch (hasError) {
710 default: assert(false);
711 case RefVal::ErrorUseAfterRelease:
712 UseAfterReleases.insert(N);
713 break;
714
715 case RefVal::ErrorReleaseNotOwned:
716 ReleasesNotOwned.insert(N);
717 break;
718 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000719 }
720
721 return;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000722 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000723
724 // Finally, consult the summary for the return value.
725
726 RetEffect RE = Summ->getRet();
727 St = StateMgr.getPersistentState(StVals);
728
729
730 switch (RE.getKind()) {
731 default:
732 assert (false && "Unhandled RetEffect."); break;
733
734 case RetEffect::Alias: {
735 unsigned idx = RE.getValue();
736 assert (idx < CE->getNumArgs());
737 RVal V = StateMgr.GetRVal(St, CE->getArg(idx));
Ted Kremenek199e1a02008-03-12 21:06:49 +0000738 St = StateMgr.SetRVal(St, CE, V, Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000739 break;
740 }
741
742 case RetEffect::OwnedSymbol: {
743 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000744 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000745
746 ValueState StImpl = *St;
747 RefBindings B = GetRefBindings(StImpl);
748 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned(1)));
749
750 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
751 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000752 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000753
754 break;
755 }
756
757 case RetEffect::NotOwnedSymbol: {
758 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000759 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000760
761 ValueState StImpl = *St;
762 RefBindings B = GetRefBindings(StImpl);
763 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned()));
764
765 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
766 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000767 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000768
769 break;
770 }
771 }
772
Ted Kremenek0e561a32008-03-21 21:30:14 +0000773 Builder.MakeNode(Dst, CE, Pred, St);
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000774}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000775
776
777CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000778 RefVal V, ArgEffect E,
Ted Kremenek73c750b2008-03-11 18:14:09 +0000779 RefVal::Kind& hasError) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000780
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000781 // FIXME: This dispatch can potentially be sped up by unifiying it into
782 // a single switch statement. Opt for simplicity for now.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000783
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000784 switch (E) {
785 default:
786 assert (false && "Unhandled CFRef transition.");
787
788 case DoNothing:
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000789 if (V.getKind() == RefVal::Released) {
790 V = RefVal::makeUseAfterRelease();
791 hasError = V.getKind();
792 break;
793 }
794
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000795 return B;
796
797 case IncRef:
798 switch (V.getKind()) {
799 default:
800 assert(false);
801
802 case RefVal::Owned:
803 V = RefVal::makeOwned(V.getCount()+1); break;
804
805 case RefVal::AcqOwned:
806 V = RefVal::makeAcqOwned(V.getCount()+1);
807 break;
808
809 case RefVal::NotOwned:
810 V = RefVal::makeAcqOwned(1);
811 break;
812
813 case RefVal::Released:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000814 V = RefVal::makeUseAfterRelease();
Ted Kremenek73c750b2008-03-11 18:14:09 +0000815 hasError = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000816 break;
817 }
818
819 case DecRef:
820 switch (V.getKind()) {
821 default:
822 assert (false);
823
824 case RefVal::Owned: {
825 unsigned Count = V.getCount() - 1;
826 V = Count ? RefVal::makeOwned(Count) : RefVal::makeReleased();
827 break;
828 }
829
830 case RefVal::AcqOwned: {
831 unsigned Count = V.getCount() - 1;
832 V = Count ? RefVal::makeAcqOwned(Count) : RefVal::makeNotOwned();
833 break;
834 }
835
836 case RefVal::NotOwned:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000837 V = RefVal::makeReleaseNotOwned();
Ted Kremenek73c750b2008-03-11 18:14:09 +0000838 hasError = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000839 break;
840
841 case RefVal::Released:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000842 V = RefVal::makeUseAfterRelease();
Ted Kremenek73c750b2008-03-11 18:14:09 +0000843 hasError = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000844 break;
845 }
846 }
847
848 return RefBFactory.Add(B, sym, V);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000849}
850
Ted Kremenekfa34b332008-04-09 01:10:13 +0000851
852//===----------------------------------------------------------------------===//
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000853// Error reporting.
Ted Kremenekfa34b332008-04-09 01:10:13 +0000854//===----------------------------------------------------------------------===//
855
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000856void UseAfterRelease::EmitWarnings(BugReporter& BR) {
Ted Kremenekfa34b332008-04-09 01:10:13 +0000857
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000858 for (CFRefCount::use_after_iterator I = TF.use_after_begin(),
859 E = TF.use_after_end(); I != E; ++I) {
860
861 BugReport report(*this);
862 BR.EmitPathWarning(report, *I);
Ted Kremenekfa34b332008-04-09 01:10:13 +0000863 }
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000864}
865
866void BadRelease::EmitWarnings(BugReporter& BR) {
Ted Kremenekfa34b332008-04-09 01:10:13 +0000867
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000868 for (CFRefCount::bad_release_iterator I = TF.bad_release_begin(),
869 E = TF.bad_release_end(); I != E; ++I) {
870
871 BugReport report(*this);
872 BR.EmitPathWarning(report, *I);
873 }
874}
Ted Kremenekfa34b332008-04-09 01:10:13 +0000875
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000876//===----------------------------------------------------------------------===//
Ted Kremenekd71ed262008-04-10 22:16:52 +0000877// Transfer function creation for external clients.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000878//===----------------------------------------------------------------------===//
879
Ted Kremenekd71ed262008-04-10 22:16:52 +0000880GRTransferFuncs* clang::MakeCFRefCountTF() { return new CFRefCount(); }