blob: 1748e450a364e79b921e09c7bbe7fb0f55fb8995 [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> {
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +000040 static void Profile(const ArgEffects& X, FoldingSetNodeID& ID) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000041 for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I)
42 ID.AddInteger((unsigned) *I);
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +000043 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000044 };
45} // end llvm namespace
46
47namespace {
Ted Kremenek2fff37e2008-03-06 00:08:09 +000048
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000049class RetEffect {
50public:
Ted Kremenek940b1d82008-04-10 23:44:06 +000051 enum Kind { NoRet = 0x0, Alias = 0x1, OwnedSymbol = 0x2,
52 NotOwnedSymbol = 0x3 };
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000053
54private:
55 unsigned Data;
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +000056 RetEffect(Kind k, unsigned D) { Data = (D << 2) | (unsigned) k; }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000057
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000058public:
59
60 Kind getKind() const { return (Kind) (Data & 0x3); }
61
62 unsigned getValue() const {
63 assert(getKind() == Alias);
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +000064 return Data >> 2;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000065 }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000066
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000067 static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000068
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000069 static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
Ted Kremenek2fff37e2008-03-06 00:08:09 +000070
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000071 static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
72
Ted Kremenek940b1d82008-04-10 23:44:06 +000073 static RetEffect MakeNoRet() { return RetEffect(NoRet, 0); }
74
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000075 operator Kind() const { return getKind(); }
76
77 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
78};
79
80
81class CFRefSummary : public llvm::FoldingSetNode {
82 ArgEffects* Args;
83 RetEffect Ret;
84public:
85
86 CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
87
88 unsigned getNumArgs() const { return Args->size(); }
89
Ted Kremenek1ac08d62008-03-11 17:48:22 +000090 ArgEffect getArg(unsigned idx) const {
91 assert (idx < getNumArgs());
92 return (*Args)[idx];
93 }
94
Ted Kremenek00a3a5f2008-03-12 01:21:45 +000095 RetEffect getRet() const {
96 return Ret;
97 }
98
Ted Kremenek6b3a0f72008-03-11 06:39:11 +000099 typedef ArgEffects::const_iterator arg_iterator;
100
101 arg_iterator begin_args() const { return Args->begin(); }
102 arg_iterator end_args() const { return Args->end(); }
103
104 static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) {
105 ID.AddPointer(A);
106 ID.Add(R);
107 }
108
109 void Profile(llvm::FoldingSetNodeID& ID) const {
110 Profile(ID, Args, Ret);
111 }
112};
113
114
115class CFRefSummaryManager {
116 typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
117 typedef llvm::FoldingSet<CFRefSummary> SummarySetTy;
118 typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*> SummaryMapTy;
119
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000120 ASTContext& Ctx;
121 SummarySetTy SummarySet;
122 SummaryMapTy SummaryMap;
123 AESetTy AESet;
124 llvm::BumpPtrAllocator BPAlloc;
125 ArgEffects ScratchArgs;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000126
127
128 ArgEffects* getArgEffects();
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000129
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000130 CFRefSummary* getCannedCFSummary(FunctionTypeProto* FT, bool isRetain);
131
132 CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName);
133
134 CFRefSummary* getCFSummaryCreateRule(FunctionTypeProto* FT);
135 CFRefSummary* getCFSummaryGetRule(FunctionTypeProto* FT);
136
137 CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
138
Ted Kremenek940b1d82008-04-10 23:44:06 +0000139 CFRefSummary* getDoNothingSummary(unsigned Args);
140 void FillDoNothing(unsigned Args);
141
142
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000143public:
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000144 CFRefSummaryManager(ASTContext& ctx) : Ctx(ctx) {}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000145 ~CFRefSummaryManager();
146
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000147 CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000148};
149
150} // end anonymous namespace
151
152//===----------------------------------------------------------------------===//
153// Implementation of checker data structures.
154//===----------------------------------------------------------------------===//
155
156CFRefSummaryManager::~CFRefSummaryManager() {
157
158 // FIXME: The ArgEffects could eventually be allocated from BPAlloc,
159 // mitigating the need to do explicit cleanup of the
160 // Argument-Effect summaries.
161
162 for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
163 I->getValue().~ArgEffects();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000164}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000165
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000166ArgEffects* CFRefSummaryManager::getArgEffects() {
167
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000168 llvm::FoldingSetNodeID profile;
169 profile.Add(ScratchArgs);
170 void* InsertPos;
171
172 llvm::FoldingSetNodeWrapper<ArgEffects>* E =
173 AESet.FindNodeOrInsertPos(profile, InsertPos);
174
175 if (E) {
176 ScratchArgs.clear();
177 return &E->getValue();
178 }
179
180 E = (llvm::FoldingSetNodeWrapper<ArgEffects>*)
181 BPAlloc.Allocate<llvm::FoldingSetNodeWrapper<ArgEffects> >();
182
183 new (E) llvm::FoldingSetNodeWrapper<ArgEffects>(ScratchArgs);
184 AESet.InsertNode(E, InsertPos);
185
186 ScratchArgs.clear();
187 return &E->getValue();
188}
189
190CFRefSummary* CFRefSummaryManager::getPersistentSummary(ArgEffects* AE,
191 RetEffect RE) {
192
193 llvm::FoldingSetNodeID profile;
194 CFRefSummary::Profile(profile, AE, RE);
195 void* InsertPos;
196
197 CFRefSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos);
198
199 if (Summ)
200 return Summ;
201
202 Summ = (CFRefSummary*) BPAlloc.Allocate<CFRefSummary>();
203 new (Summ) CFRefSummary(AE, RE);
204 SummarySet.InsertNode(Summ, InsertPos);
205
206 return Summ;
207}
208
209
210CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD,
211 ASTContext& Ctx) {
212
213 SourceLocation Loc = FD->getLocation();
214
215 if (!Loc.isFileID())
216 return NULL;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000217
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000218 { // Look into our cache of summaries to see if we have already computed
219 // a summary for this FunctionDecl.
220
221 SummaryMapTy::iterator I = SummaryMap.find(FD);
222
223 if (I != SummaryMap.end())
224 return I->second;
225 }
226
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000227#if 0
228 SourceManager& SrcMgr = Ctx.getSourceManager();
229 unsigned fid = Loc.getFileID();
230 const FileEntry* FE = SrcMgr.getFileEntryForID(fid);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000231
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000232 if (!FE)
233 return NULL;
234
235 const char* DirName = FE->getDir()->getName();
236 assert (DirName);
237 assert (strlen(DirName) > 0);
238
239 if (!strstr(DirName, "CoreFoundation")) {
240 SummaryMap[FD] = NULL;
241 return NULL;
242 }
243#endif
244
245 const char* FName = FD->getIdentifier()->getName();
246
247 if (FName[0] == 'C' && FName[1] == 'F') {
248 CFRefSummary* S = getCFSummary(FD, FName);
249 SummaryMap[FD] = S;
250 return S;
251 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000252
253 return NULL;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000254}
255
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000256CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD,
257 const char* FName) {
258
259 // For now, only generate summaries for functions that have a prototype.
260
261 FunctionTypeProto* FT =
262 dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
263
264 if (!FT)
265 return NULL;
266
267 FName += 2;
268
269 if (strcmp(FName, "Retain") == 0)
270 return getCannedCFSummary(FT, true);
271
272 if (strcmp(FName, "Release") == 0)
273 return getCannedCFSummary(FT, false);
274
275 assert (ScratchArgs.empty());
276 bool usesCreateRule = false;
277
278 if (strstr(FName, "Create"))
279 usesCreateRule = true;
280
281 if (!usesCreateRule && strstr(FName, "Copy"))
282 usesCreateRule = true;
283
284 if (usesCreateRule)
285 return getCFSummaryCreateRule(FT);
286
287 if (strstr(FName, "Get"))
288 return getCFSummaryGetRule(FT);
289
290 return NULL;
291}
292
293CFRefSummary* CFRefSummaryManager::getCannedCFSummary(FunctionTypeProto* FT,
294 bool isRetain) {
295
296 if (FT->getNumArgs() != 1)
297 return NULL;
298
299 TypedefType* ArgT = dyn_cast<TypedefType>(FT->getArgType(0).getTypePtr());
300
301 if (!ArgT)
302 return NULL;
303
304 // For CFRetain/CFRelease, the first (and only) argument is of type
305 // "CFTypeRef".
306
307 const char* TDName = ArgT->getDecl()->getIdentifier()->getName();
308 assert (TDName);
309
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000310 if (strcmp("CFTypeRef", TDName) != 0)
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000311 return NULL;
312
313 if (!ArgT->isPointerType())
314 return NULL;
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000315
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000316 QualType RetTy = FT->getResultType();
317
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000318 if (isRetain) {
319 // CFRetain: the return type should also be "CFTypeRef".
320 if (RetTy.getTypePtr() != ArgT)
321 return NULL;
Ted Kremenek940b1d82008-04-10 23:44:06 +0000322
323 // The function's interface checks out. Generate a canned summary.
324 assert (ScratchArgs.empty());
325 ScratchArgs.push_back(IncRef);
326 return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0));
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000327 }
328 else {
329 // CFRelease: the return type should be void.
330
331 if (RetTy != Ctx.VoidTy)
332 return NULL;
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000333
Ted Kremenek940b1d82008-04-10 23:44:06 +0000334 assert (ScratchArgs.empty());
335 ScratchArgs.push_back(DecRef);
336 return getPersistentSummary(getArgEffects(), RetEffect::MakeNoRet());
337 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000338}
339
340static bool isCFRefType(QualType T) {
341
342 if (!T->isPointerType())
343 return false;
344
345 // Check the typedef for the name "CF" and the substring "Ref".
346
347 TypedefType* TD = dyn_cast<TypedefType>(T.getTypePtr());
348
349 if (!TD)
350 return false;
351
352 const char* TDName = TD->getDecl()->getIdentifier()->getName();
353 assert (TDName);
354
355 if (TDName[0] != 'C' || TDName[1] != 'F')
356 return false;
357
358 if (strstr(TDName, "Ref") == 0)
359 return false;
360
361 return true;
362}
363
Ted Kremenek940b1d82008-04-10 23:44:06 +0000364void CFRefSummaryManager::FillDoNothing(unsigned Args) {
365 for (unsigned i = 0; i != Args; ++i)
366 ScratchArgs.push_back(DoNothing);
367}
368
369CFRefSummary* CFRefSummaryManager::getDoNothingSummary(unsigned Args) {
370 FillDoNothing(Args);
371 return getPersistentSummary(getArgEffects(), RetEffect::MakeNoRet());
372}
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000373
374CFRefSummary*
375CFRefSummaryManager::getCFSummaryCreateRule(FunctionTypeProto* FT) {
376
377 if (!isCFRefType(FT->getResultType()))
Ted Kremenek940b1d82008-04-10 23:44:06 +0000378 return getDoNothingSummary(FT->getNumArgs());
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000379
380 assert (ScratchArgs.empty());
381
382 // FIXME: Add special-cases for functions that retain/release. For now
383 // just handle the default case.
384
Ted Kremenek940b1d82008-04-10 23:44:06 +0000385 FillDoNothing(FT->getNumArgs());
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000386 return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned());
387}
388
389CFRefSummary*
390CFRefSummaryManager::getCFSummaryGetRule(FunctionTypeProto* FT) {
391
392 if (!isCFRefType(FT->getResultType()))
Ted Kremenek940b1d82008-04-10 23:44:06 +0000393 return getDoNothingSummary(FT->getNumArgs());
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000394
395 assert (ScratchArgs.empty());
396
397 // FIXME: Add special-cases for functions that retain/release. For now
398 // just handle the default case.
399
Ted Kremenek940b1d82008-04-10 23:44:06 +0000400 FillDoNothing(FT->getNumArgs());
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000401 return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned());
402}
403
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000404//===----------------------------------------------------------------------===//
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000405// Bug Descriptions.
406//===----------------------------------------------------------------------===//
407
408namespace {
409
410 class CFRefCount;
411
412 class VISIBILITY_HIDDEN CFRefBug : public BugType {
413 protected:
414 CFRefCount& TF;
415
416 public:
417 CFRefBug(CFRefCount& tf) : TF(tf) {}
418 };
419
420 class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug {
421 public:
422 UseAfterRelease(CFRefCount& tf) : CFRefBug(tf) {}
423
424 virtual const char* getName() const {
425 return "(CoreFoundation) use-after-release";
426 }
427 virtual const char* getDescription() const {
428 return "(CoreFoundation) Reference-counted object is used"
429 " after it is released.";
430 }
431
432 virtual void EmitWarnings(BugReporter& BR);
433
434 };
435
436 class VISIBILITY_HIDDEN BadRelease : public CFRefBug {
437 public:
438 BadRelease(CFRefCount& tf) : CFRefBug(tf) {}
439
440 virtual const char* getName() const {
441 return "(CoreFoundation) release of non-owned object";
442 }
443 virtual const char* getDescription() const {
444 return "Incorrect decrement of the reference count of a "
445 "CoreFoundation object:\n"
446 "The object is not owned at this point by the caller.";
447 }
448
449 virtual void EmitWarnings(BugReporter& BR);
450 };
451
452} // end anonymous namespace
453
454//===----------------------------------------------------------------------===//
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000455// Transfer functions.
456//===----------------------------------------------------------------------===//
457
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000458namespace {
459
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000460class VISIBILITY_HIDDEN RefVal {
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000461 unsigned Data;
462
463 RefVal(unsigned K, unsigned D) : Data((D << 3) | K) {
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000464 assert ((K & ~0x7) == 0x0);
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000465 }
466
467 RefVal(unsigned K) : Data(K) {
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000468 assert ((K & ~0x7) == 0x0);
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000469 }
470
471public:
Ted Kremenek61b9f872008-04-10 23:09:18 +0000472 enum Kind { Owned = 0, NotOwned = 1, Released = 2,
473 ErrorUseAfterRelease = 3, ErrorReleaseNotOwned = 4 };
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000474
475
Ted Kremenek61b9f872008-04-10 23:09:18 +0000476 Kind getKind() const { return (Kind) (Data & 0x7); }
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000477
478 unsigned getCount() const {
Ted Kremenek61b9f872008-04-10 23:09:18 +0000479 assert (getKind() == Owned || getKind() == NotOwned);
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000480 return Data >> 3;
481 }
482
Ted Kremenek73c750b2008-03-11 18:14:09 +0000483 static bool isError(Kind k) { return k >= ErrorUseAfterRelease; }
484
Ted Kremenek61b9f872008-04-10 23:09:18 +0000485 static RefVal makeOwned(unsigned Count = 0) {
486 return RefVal(Owned, Count);
487 }
488
489 static RefVal makeNotOwned(unsigned Count = 0) {
490 return RefVal(NotOwned, Count);
491 }
492
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000493 static RefVal makeReleased() { return RefVal(Released); }
494 static RefVal makeUseAfterRelease() { return RefVal(ErrorUseAfterRelease); }
495 static RefVal makeReleaseNotOwned() { return RefVal(ErrorReleaseNotOwned); }
496
497 bool operator==(const RefVal& X) const { return Data == X.Data; }
498 void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
Ted Kremenekf3948042008-03-11 19:44:10 +0000499
500 void print(std::ostream& Out) const;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000501};
Ted Kremenekf3948042008-03-11 19:44:10 +0000502
503void RefVal::print(std::ostream& Out) const {
504 switch (getKind()) {
505 default: assert(false);
Ted Kremenek61b9f872008-04-10 23:09:18 +0000506 case Owned: {
507 Out << "Owned";
508 unsigned cnt = getCount();
509 if (cnt) Out << " (+ " << cnt << ")";
Ted Kremenekf3948042008-03-11 19:44:10 +0000510 break;
Ted Kremenek61b9f872008-04-10 23:09:18 +0000511 }
Ted Kremenekf3948042008-03-11 19:44:10 +0000512
Ted Kremenek61b9f872008-04-10 23:09:18 +0000513 case NotOwned: {
Ted Kremenekf3948042008-03-11 19:44:10 +0000514 Out << "Not-Owned";
Ted Kremenek61b9f872008-04-10 23:09:18 +0000515 unsigned cnt = getCount();
516 if (cnt) Out << " (+ " << cnt << ")";
Ted Kremenekf3948042008-03-11 19:44:10 +0000517 break;
Ted Kremenek61b9f872008-04-10 23:09:18 +0000518 }
Ted Kremenekf3948042008-03-11 19:44:10 +0000519
520 case Released:
521 Out << "Released";
522 break;
523
524 case ErrorUseAfterRelease:
525 Out << "Use-After-Release [ERROR]";
526 break;
527
528 case ErrorReleaseNotOwned:
529 Out << "Release of Not-Owned [ERROR]";
530 break;
531 }
532}
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000533
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000534class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals {
Ted Kremenekf3948042008-03-11 19:44:10 +0000535
536 // Type definitions.
537
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000538 typedef llvm::ImmutableMap<SymbolID, RefVal> RefBindings;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000539 typedef RefBindings::Factory RefBFactoryTy;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000540
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000541 typedef llvm::DenseMap<GRExprEngine::NodeTy*,Expr*> UseAfterReleasesTy;
542 typedef llvm::DenseMap<GRExprEngine::NodeTy*,Expr*> ReleasesNotOwnedTy;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000543
Ted Kremenekf3948042008-03-11 19:44:10 +0000544 class BindingsPrinter : public ValueState::CheckerStatePrinter {
545 public:
546 virtual void PrintCheckerState(std::ostream& Out, void* State,
547 const char* nl, const char* sep);
548 };
549
550 // Instance variables.
551
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000552 CFRefSummaryManager Summaries;
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000553 RefBFactoryTy RefBFactory;
554
Ted Kremenek73c750b2008-03-11 18:14:09 +0000555 UseAfterReleasesTy UseAfterReleases;
556 ReleasesNotOwnedTy ReleasesNotOwned;
557
Ted Kremenekf3948042008-03-11 19:44:10 +0000558 BindingsPrinter Printer;
559
560 // Private methods.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000561
562 static RefBindings GetRefBindings(ValueState& StImpl) {
563 return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState);
564 }
565
566 static void SetRefBindings(ValueState& StImpl, RefBindings B) {
567 StImpl.CheckerState = B.getRoot();
568 }
569
570 RefBindings Remove(RefBindings B, SymbolID sym) {
571 return RefBFactory.Remove(B, sym);
572 }
573
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000574 RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E,
Ted Kremenek73c750b2008-03-11 18:14:09 +0000575 RefVal::Kind& hasError);
Ted Kremenekf3948042008-03-11 19:44:10 +0000576
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000577
578public:
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000579 CFRefCount(ASTContext& Ctx) : Summaries(Ctx) {}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000580 virtual ~CFRefCount() {}
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000581
582 virtual void RegisterChecks(GRExprEngine& Eng);
Ted Kremenekf3948042008-03-11 19:44:10 +0000583
584 virtual ValueState::CheckerStatePrinter* getCheckerStatePrinter() {
585 return &Printer;
586 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000587
588 // Calls.
589
590 virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000591 GRExprEngine& Eng,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000592 GRStmtNodeBuilder<ValueState>& Builder,
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000593 CallExpr* CE, LVal L,
594 ExplodedNode<ValueState>* Pred);
Ted Kremenekfa34b332008-04-09 01:10:13 +0000595
596 // Error iterators.
597
598 typedef UseAfterReleasesTy::iterator use_after_iterator;
599 typedef ReleasesNotOwnedTy::iterator bad_release_iterator;
600
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000601 use_after_iterator use_after_begin() { return UseAfterReleases.begin(); }
602 use_after_iterator use_after_end() { return UseAfterReleases.end(); }
Ted Kremenekfa34b332008-04-09 01:10:13 +0000603
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000604 bad_release_iterator bad_release_begin() { return ReleasesNotOwned.begin(); }
605 bad_release_iterator bad_release_end() { return ReleasesNotOwned.end(); }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000606};
607
608} // end anonymous namespace
609
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000610void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
611 GRSimpleVals::RegisterChecks(Eng);
612 Eng.Register(new UseAfterRelease(*this));
613 Eng.Register(new BadRelease(*this));
614}
615
616
Ted Kremenekf3948042008-03-11 19:44:10 +0000617void CFRefCount::BindingsPrinter::PrintCheckerState(std::ostream& Out,
618 void* State, const char* nl,
619 const char* sep) {
620 RefBindings B((RefBindings::TreeTy*) State);
621
622 if (State)
623 Out << sep << nl;
624
625 for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
626 Out << (*I).first << " : ";
627 (*I).second.print(Out);
628 Out << nl;
629 }
630}
631
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000632void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
Ted Kremenek199e1a02008-03-12 21:06:49 +0000633 GRExprEngine& Eng,
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000634 GRStmtNodeBuilder<ValueState>& Builder,
635 CallExpr* CE, LVal L,
636 ExplodedNode<ValueState>* Pred) {
637
Ted Kremenek199e1a02008-03-12 21:06:49 +0000638 ValueStateManager& StateMgr = Eng.getStateManager();
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000639
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000640 // FIXME: Support calls to things other than lval::FuncVal. At the very
641 // least we should stop tracking ref-state for ref-counted objects passed
642 // to these functions.
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000643
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000644 assert (isa<lval::FuncVal>(L) && "Not yet implemented.");
645
646 // Get the summary.
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000647
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000648 lval::FuncVal FV = cast<lval::FuncVal>(L);
649 FunctionDecl* FD = FV.getDecl();
Ted Kremenek199e1a02008-03-12 21:06:49 +0000650 CFRefSummary* Summ = Summaries.getSummary(FD, Eng.getContext());
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000651
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000652 // Get the state.
653
654 ValueState* St = Builder.GetState(Pred);
655
656 // Evaluate the effects of the call.
657
658 ValueState StVals = *St;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000659 RefVal::Kind hasError = (RefVal::Kind) 0;
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000660
661 if (!Summ) {
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000662
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000663 // This function has no summary. Invalidate all reference-count state
664 // for arguments passed to this function, and also nuke the values of
665 // arguments passed-by-reference.
666
667 ValueState StVals = *St;
668
669 for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
670 I != E; ++I) {
671
672 RVal V = StateMgr.GetRVal(St, *I);
673
674 if (isa<lval::SymbolVal>(V)) {
675 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
676 RefBindings B = GetRefBindings(StVals);
677 SetRefBindings(StVals, Remove(B, Sym));
678 }
679
680 if (isa<LVal>(V))
681 StateMgr.Unbind(StVals, cast<LVal>(V));
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000682 }
683
684 St = StateMgr.getPersistentState(StVals);
Ted Kremenek199e1a02008-03-12 21:06:49 +0000685
686 // Make up a symbol for the return value of this function.
687
688 if (CE->getType() != Eng.getContext().VoidTy) {
689 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000690 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek199e1a02008-03-12 21:06:49 +0000691
692 RVal X = CE->getType()->isPointerType()
693 ? cast<RVal>(lval::SymbolVal(Sym))
694 : cast<RVal>(nonlval::SymbolVal(Sym));
695
696 St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false);
697 }
698
Ted Kremenek0e561a32008-03-21 21:30:14 +0000699 Builder.MakeNode(Dst, CE, Pred, St);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000700 return;
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000701 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000702
703 // This function has a summary. Evaluate the effect of the arguments.
704
705 unsigned idx = 0;
706
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000707 Expr* ErrorExpr = NULL;
708
709 for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
710 I != E; ++I, ++idx) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000711
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000712 RVal V = StateMgr.GetRVal(St, *I);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000713
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000714 if (isa<lval::SymbolVal>(V)) {
715 SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
716 RefBindings B = GetRefBindings(StVals);
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000717
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000718 if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
719 B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError);
720 SetRefBindings(StVals, B);
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000721
722 if (hasError) {
723 ErrorExpr = *I;
724 break;
725 }
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000726 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000727 }
728 }
729
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000730 if (hasError) {
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000731 St = StateMgr.getPersistentState(StVals);
Ted Kremenek940b1d82008-04-10 23:44:06 +0000732
733 Builder.BuildSinks = true;
734 GRExprEngine::NodeTy* N = Builder.MakeNode(Dst, CE, Pred, St);
Ted Kremenek73c750b2008-03-11 18:14:09 +0000735
736 if (N) {
Ted Kremenek73c750b2008-03-11 18:14:09 +0000737 switch (hasError) {
738 default: assert(false);
739 case RefVal::ErrorUseAfterRelease:
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000740 UseAfterReleases[N] = ErrorExpr;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000741 break;
742
743 case RefVal::ErrorReleaseNotOwned:
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000744 ReleasesNotOwned[N] = ErrorExpr;
Ted Kremenek73c750b2008-03-11 18:14:09 +0000745 break;
746 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000747 }
748
749 return;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000750 }
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000751
752 // Finally, consult the summary for the return value.
753
754 RetEffect RE = Summ->getRet();
755 St = StateMgr.getPersistentState(StVals);
756
757
758 switch (RE.getKind()) {
759 default:
760 assert (false && "Unhandled RetEffect."); break;
761
Ted Kremenek940b1d82008-04-10 23:44:06 +0000762 case RetEffect::NoRet:
763 break;
764
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000765 case RetEffect::Alias: {
766 unsigned idx = RE.getValue();
767 assert (idx < CE->getNumArgs());
768 RVal V = StateMgr.GetRVal(St, CE->getArg(idx));
Ted Kremenek199e1a02008-03-12 21:06:49 +0000769 St = StateMgr.SetRVal(St, CE, V, Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000770 break;
771 }
772
773 case RetEffect::OwnedSymbol: {
774 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000775 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000776
777 ValueState StImpl = *St;
778 RefBindings B = GetRefBindings(StImpl);
Ted Kremenek61b9f872008-04-10 23:09:18 +0000779 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned()));
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000780
781 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
782 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000783 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000784
785 break;
786 }
787
788 case RetEffect::NotOwnedSymbol: {
789 unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek361fa8e2008-03-12 21:45:47 +0000790 SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000791
792 ValueState StImpl = *St;
793 RefBindings B = GetRefBindings(StImpl);
794 SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned()));
795
796 St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
797 CE, lval::SymbolVal(Sym),
Ted Kremenek199e1a02008-03-12 21:06:49 +0000798 Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000799
800 break;
801 }
802 }
803
Ted Kremenek0e561a32008-03-21 21:30:14 +0000804 Builder.MakeNode(Dst, CE, Pred, St);
Ted Kremenek2fff37e2008-03-06 00:08:09 +0000805}
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000806
807
808CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000809 RefVal V, ArgEffect E,
Ted Kremenek73c750b2008-03-11 18:14:09 +0000810 RefVal::Kind& hasError) {
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000811
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000812 // FIXME: This dispatch can potentially be sped up by unifiying it into
813 // a single switch statement. Opt for simplicity for now.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000814
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000815 switch (E) {
816 default:
817 assert (false && "Unhandled CFRef transition.");
818
819 case DoNothing:
Ted Kremenek00a3a5f2008-03-12 01:21:45 +0000820 if (V.getKind() == RefVal::Released) {
821 V = RefVal::makeUseAfterRelease();
822 hasError = V.getKind();
823 break;
824 }
825
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000826 return B;
827
828 case IncRef:
829 switch (V.getKind()) {
830 default:
831 assert(false);
832
833 case RefVal::Owned:
Ted Kremenek940b1d82008-04-10 23:44:06 +0000834 V = RefVal::makeOwned(V.getCount()+1);
835 break;
Ted Kremenek61b9f872008-04-10 23:09:18 +0000836
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000837 case RefVal::NotOwned:
Ted Kremenek61b9f872008-04-10 23:09:18 +0000838 V = RefVal::makeNotOwned(V.getCount()+1);
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
Ted Kremenek940b1d82008-04-10 23:44:06 +0000847 break;
848
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000849 case DecRef:
850 switch (V.getKind()) {
851 default:
852 assert (false);
853
854 case RefVal::Owned: {
Ted Kremenek61b9f872008-04-10 23:09:18 +0000855 signed Count = ((signed) V.getCount()) - 1;
856 V = Count >= 0 ? RefVal::makeOwned(Count) : RefVal::makeReleased();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000857 break;
858 }
859
Ted Kremenek61b9f872008-04-10 23:09:18 +0000860 case RefVal::NotOwned: {
861 signed Count = ((signed) V.getCount()) - 1;
862
863 if (Count >= 0)
864 V = RefVal::makeNotOwned(Count);
865 else {
866 V = RefVal::makeReleaseNotOwned();
867 hasError = V.getKind();
868 }
869
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000870 break;
871 }
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000872
873 case RefVal::Released:
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000874 V = RefVal::makeUseAfterRelease();
Ted Kremenek73c750b2008-03-11 18:14:09 +0000875 hasError = V.getKind();
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000876 break;
877 }
Ted Kremenek940b1d82008-04-10 23:44:06 +0000878
879 break;
Ted Kremenek1ac08d62008-03-11 17:48:22 +0000880 }
881
882 return RefBFactory.Add(B, sym, V);
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000883}
884
Ted Kremenekfa34b332008-04-09 01:10:13 +0000885
886//===----------------------------------------------------------------------===//
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000887// Error reporting.
Ted Kremenekfa34b332008-04-09 01:10:13 +0000888//===----------------------------------------------------------------------===//
889
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000890void UseAfterRelease::EmitWarnings(BugReporter& BR) {
Ted Kremenekfa34b332008-04-09 01:10:13 +0000891
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000892 for (CFRefCount::use_after_iterator I = TF.use_after_begin(),
893 E = TF.use_after_end(); I != E; ++I) {
894
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000895 RangedBugReport report(*this);
896 report.addRange(I->second->getSourceRange());
897 BR.EmitPathWarning(report, I->first);
Ted Kremenekfa34b332008-04-09 01:10:13 +0000898 }
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000899}
900
901void BadRelease::EmitWarnings(BugReporter& BR) {
Ted Kremenekfa34b332008-04-09 01:10:13 +0000902
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000903 for (CFRefCount::bad_release_iterator I = TF.bad_release_begin(),
904 E = TF.bad_release_end(); I != E; ++I) {
905
Ted Kremenekbcf50ad2008-04-11 18:40:51 +0000906 RangedBugReport report(*this);
907 report.addRange(I->second->getSourceRange());
908 BR.EmitPathWarning(report, I->first);
909
Ted Kremenek05cbe1a2008-04-09 23:49:11 +0000910 }
911}
Ted Kremenekfa34b332008-04-09 01:10:13 +0000912
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000913//===----------------------------------------------------------------------===//
Ted Kremenekd71ed262008-04-10 22:16:52 +0000914// Transfer function creation for external clients.
Ted Kremenek6b3a0f72008-03-11 06:39:11 +0000915//===----------------------------------------------------------------------===//
916
Ted Kremenek3ea0b6a2008-04-10 22:58:08 +0000917GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx) {
918 return new CFRefCount(Ctx);
919}