Skip to content
CFRefCount.cpp 83.4 KiB
Newer Older
// CFRefCount.cpp - Transfer functions for tracking simple values -*- C++ -*--//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
Gabor Greif's avatar
Gabor Greif committed
//  This file defines the methods for CFRefCount, which implements
//  a reference count checker for Core Foundation (Mac OS X).
//
//===----------------------------------------------------------------------===//

#include "GRSimpleVals.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Analysis/PathSensitive/GRState.h"
#include "clang/Analysis/PathSensitive/GRStateTrait.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
Daniel Dunbar's avatar
Daniel Dunbar committed
#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/STLExtras.h"
#include <sstream>
#include <stdarg.h>

//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//

// The "fundamental rule" for naming conventions of methods:
//  (url broken into two lines)
//  http://developer.apple.com/documentation/Cocoa/Conceptual/
//     MemoryMgmt/Tasks/MemoryManagementRules.html
//
// "You take ownership of an object if you create it using a method whose name
//  begins with “alloc” or “new” or contains “copy” (for example, alloc, 
//  newObject, or mutableCopy), or if you send it a retain message. You are
//  responsible for relinquishing ownership of objects you own using release
//  or autorelease. Any other time you receive an object, you must
//  not release it."
//
static bool followsFundamentalRule(const char* s) {
  return CStrInCStrNoCase(s, "copy")
      || CStrInCStrNoCase(s, "new") == s 
      || CStrInCStrNoCase(s, "alloc") == s;
}

static bool followsReturnRule(const char* s) {
  while (*s == '_') ++s;  
  return followsFundamentalRule(s) || CStrInCStrNoCase(s, "init") == s;
}
//===----------------------------------------------------------------------===//
Ted Kremenek's avatar
Ted Kremenek committed
// Selector creation functions.
//===----------------------------------------------------------------------===//

Ted Kremenek's avatar
Ted Kremenek committed
static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
  IdentifierInfo* II = &Ctx.Idents.get(name);
  return Ctx.Selectors.getSelector(0, &II);
}

static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) {
  IdentifierInfo* II = &Ctx.Idents.get(name);
  return Ctx.Selectors.getSelector(1, &II);
}

Ted Kremenek's avatar
Ted Kremenek committed
//===----------------------------------------------------------------------===//
// Type querying functions.
//===----------------------------------------------------------------------===//

Ted Kremenek's avatar
Ted Kremenek committed
static bool hasPrefix(const char* s, const char* prefix) {
  if (!prefix)
    return true;
Ted Kremenek's avatar
Ted Kremenek committed
  char c = *s;
  char cP = *prefix;
Ted Kremenek's avatar
Ted Kremenek committed
  while (c != '\0' && cP != '\0') {
    if (c != cP) break;
    c = *(++s);
    cP = *(++prefix);
  }
Ted Kremenek's avatar
Ted Kremenek committed
  return cP == '\0';
Ted Kremenek's avatar
Ted Kremenek committed
static bool hasSuffix(const char* s, const char* suffix) {
  const char* loc = strstr(s, suffix);
  return loc && strcmp(suffix, loc) == 0;
}

static bool isRefType(QualType RetTy, const char* prefix,
                      ASTContext* Ctx = 0, const char* name = 0) {
Ted Kremenek's avatar
Ted Kremenek committed
  if (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
    const char* TDName = TD->getDecl()->getIdentifier()->getName();
    return hasPrefix(TDName, prefix) && hasSuffix(TDName, "Ref");
  }

  if (!Ctx || !name)
Ted Kremenek's avatar
Ted Kremenek committed

  // Is the type void*?
  const PointerType* PT = RetTy->getAsPointerType();
  if (!(PT->getPointeeType().getUnqualifiedType() == Ctx->VoidTy))
Ted Kremenek's avatar
Ted Kremenek committed

  // Does the name start with the prefix?
  return hasPrefix(name, prefix);
//===----------------------------------------------------------------------===//
Ted Kremenek's avatar
Ted Kremenek committed
// Primitives used for constructing summaries for function/method calls.
//===----------------------------------------------------------------------===//

Ted Kremenek's avatar
Ted Kremenek committed
namespace {
/// ArgEffect is used to summarize a function/method call's effect on a
/// particular argument.
enum ArgEffect { IncRef, DecRef, DoNothing, DoNothingByRef,
                 StopTracking, MayEscape, SelfOwn, Autorelease };
Ted Kremenek's avatar
Ted Kremenek committed

/// ArgEffects summarizes the effects of a function/method call on all of
/// its arguments.
typedef std::vector<std::pair<unsigned,ArgEffect> > ArgEffects;
Ted Kremenek's avatar
Ted Kremenek committed
template <> struct FoldingSetTrait<ArgEffects> {
  static void Profile(const ArgEffects& X, FoldingSetNodeID& ID) {
    for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I) {
      ID.AddInteger(I->first);
      ID.AddInteger((unsigned) I->second);
    }
  }    
};
} // end llvm namespace

namespace {
Ted Kremenek's avatar
Ted Kremenek committed

///  RetEffect is used to summarize a function/method call's behavior with
///  respect to its return value.  
class VISIBILITY_HIDDEN RetEffect {
  enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol,
              NotOwnedSymbol, ReceiverAlias };
Ted Kremenek's avatar
Ted Kremenek committed
  
Ted Kremenek's avatar
Ted Kremenek committed
  RetEffect(Kind k, unsigned D = 0) { Data = (D << 3) | (unsigned) k; }
Ted Kremenek's avatar
Ted Kremenek committed
  
  Kind getKind() const { return (Kind) (Data & 0x7); }
Ted Kremenek's avatar
Ted Kremenek committed
  
  unsigned getIndex() const { 
    assert(getKind() == Alias);
Ted Kremenek's avatar
Ted Kremenek committed
  static RetEffect MakeAlias(unsigned Idx) {
    return RetEffect(Alias, Idx);
  }
  static RetEffect MakeReceiverAlias() {
    return RetEffect(ReceiverAlias);
  }  
  static RetEffect MakeOwned(bool isAllocated = false) {
Ted Kremenek's avatar
Ted Kremenek committed
    return RetEffect(isAllocated ? OwnedAllocatedSymbol : OwnedSymbol);
  }  
  static RetEffect MakeNotOwned() {
    return RetEffect(NotOwnedSymbol);
  }  
  static RetEffect MakeNoRet() {
    return RetEffect(NoRet);
Ted Kremenek's avatar
Ted Kremenek committed
  operator Kind() const {
    return getKind();
  }  
Ted Kremenek's avatar
Ted Kremenek committed
  void Profile(llvm::FoldingSetNodeID& ID) const {
    ID.AddInteger(Data);
  }
Ted Kremenek's avatar
Ted Kremenek committed
  
Loading
Loading full blame...