Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td	(revision 106614)
+++ include/clang/Basic/Attr.td	(working copy)
@@ -297,6 +297,21 @@
   let Spellings = ["overloadable"];
 }
 
+def OwnershipReturns : Attr {
+  let Spellings = ["ownership_returns"];
+  let Args = [StringArgument<"Module">, IntArgument<"SizeIdx">];
+}
+
+def OwnershipTakes : Attr {
+  let Spellings = ["ownership_takes"];
+  let Args = [StringArgument<"Module">, IntArgument<"PtrIdx">];
+}
+
+def OwnershipHolds : Attr {
+  let Spellings = ["ownership_holds"];
+  let Args = [StringArgument<"Module">, IntArgument<"PtrIdx">];
+}
+
 def Packed : Attr {
   let Spellings = ["packed"];
 }
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 106614)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -831,6 +831,12 @@
   "attribute may only be applied to an Objective-C interface">;
 def err_nonnull_pointers_only : Error<
   "nonnull attribute only applies to pointer arguments">;
+def err_ownership_returns_integers_only : Error<
+  "ownership_returns attribute only applies to integer arguments">;
+def err_ownership_takes_pointers_only : Error<
+  "ownership_takes attribute only applies to pointer arguments">;
+def err_ownership_holds_pointers_only : Error<
+  "ownership_holds attribute only applies to pointer arguments">;
 def err_format_strftime_third_parameter : Error<
   "strftime format attribute requires 3rd parameter to be 0">;
 def err_format_attribute_requires_variadic : Error<
Index: include/clang/AST/Attr.h
===================================================================
--- include/clang/AST/Attr.h	(revision 106614)
+++ include/clang/AST/Attr.h	(working copy)
@@ -351,6 +351,93 @@
   static bool classof(const NonNullAttr *A) { return true; }
 };
 
+class OwnershipReturnsAttr : public AttrWithString {
+  unsigned* ArgNums;
+  unsigned Size;
+public:
+  OwnershipReturnsAttr(ASTContext &C, unsigned* arg_nums, unsigned size, llvm::StringRef module);
+
+  virtual void Destroy(ASTContext &C);
+
+  llvm::StringRef getModule() const { return getString(); }
+  void setModule(ASTContext &C, llvm::StringRef module);
+  typedef const unsigned *iterator;
+  iterator begin() const { return ArgNums; }
+  iterator end() const { return ArgNums + Size; }
+  unsigned size() const { return Size; }
+
+  bool isOwnershipReturns(unsigned arg) const {
+    return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true;
+  }
+
+  bool isModule(const char *m) const {
+	  return getModule().equals(m);
+  }
+
+  virtual Attr *clone(ASTContext &C) const;
+
+  static bool classof(const Attr *A) { return A->getKind() == attr::OwnershipReturns; }
+  static bool classof(const OwnershipReturnsAttr *A) { return true; }
+};
+
+class OwnershipTakesAttr : public AttrWithString {
+  unsigned* ArgNums;
+  unsigned Size;
+public:
+  OwnershipTakesAttr(ASTContext &C, unsigned* arg_nums, unsigned size, llvm::StringRef module);
+
+  virtual void Destroy(ASTContext &C);
+
+  llvm::StringRef getModule() const { return getString(); }
+  void setModule(ASTContext &C, llvm::StringRef module);
+  typedef const unsigned *iterator;
+  iterator begin() const { return ArgNums; }
+  iterator end() const { return ArgNums + Size; }
+  unsigned size() const { return Size; }
+
+  bool isOwnershipTakes(unsigned arg) const {
+    return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true;
+  }
+
+  bool isModule(const char *m) const {
+	  return getModule().equals(m);
+  }
+
+  virtual Attr *clone(ASTContext &C) const;
+
+  static bool classof(const Attr *A) { return A->getKind() == attr::OwnershipTakes; }
+  static bool classof(const OwnershipTakesAttr *A) { return true; }
+};
+
+class OwnershipHoldsAttr : public AttrWithString {
+  unsigned* ArgNums;
+  unsigned Size;
+public:
+  OwnershipHoldsAttr(ASTContext &C, unsigned* arg_nums, unsigned size, llvm::StringRef module);
+
+  virtual void Destroy(ASTContext &C);
+
+  llvm::StringRef getModule() const { return getString(); }
+  void setModule(ASTContext &C, llvm::StringRef module);
+  typedef const unsigned *iterator;
+  iterator begin() const { return ArgNums; }
+  iterator end() const { return ArgNums + Size; }
+  unsigned size() const { return Size; }
+
+  bool isOwnershipHolds(unsigned arg) const {
+    return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true;
+  }
+
+  bool isModule(const char *m) const {
+	  return getModule().equals(m);
+  }
+
+  virtual Attr *clone(ASTContext &C) const;
+
+  static bool classof(const Attr *A) { return A->getKind() == attr::OwnershipHolds; }
+  static bool classof(const OwnershipHoldsAttr *A) { return true; }
+};
+
 class FormatAttr : public AttrWithString {
   int formatIdx, firstArg;
 public:
Index: include/clang/Parse/AttributeList.h
===================================================================
--- include/clang/Parse/AttributeList.h	(revision 106614)
+++ include/clang/Parse/AttributeList.h	(working copy)
@@ -97,6 +97,9 @@
     AT_ns_returns_retained,     // Clang-specific.
     AT_objc_gc,
     AT_overloadable,       // Clang-specific.
+	AT_ownership_returns,  // Clang-specific.
+	AT_ownership_takes,    // Clang-specific.
+	AT_ownership_holds,    // Clang-specific.
     AT_packed,
     AT_pure,
     AT_regparm,
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp	(revision 106614)
+++ lib/Sema/SemaDeclAttr.cpp	(working copy)
@@ -350,6 +350,219 @@
   d->addAttr(::new (S.Context) NonNullAttr(S.Context, start, size));
 }
 
+static void HandleOwnershipReturnsAttr(Decl *d, const AttributeList &Attr,
+		Sema &S) {
+	// must be applied to a function declaration
+	// first argument to the attribute must be a string, the name of the resource
+	// for example "malloc"
+	// next argument must be an integer less than the number of function arguments
+	// this is an argument index, the argument must be of integer type
+
+	if (!Attr.getParameterName()) {
+		S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
+				<< "ownership_returns" << 1;
+		return;
+	}
+
+	if (Attr.getNumArgs() != 1) {
+		S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 2;
+		return;
+	}
+
+	if (!isFunctionOrMethodOrBlock(d) || !hasFunctionProto(d)) {
+		S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+				<< Attr.getName() << 0 /*function*/;
+		return;
+	}
+
+	unsigned NumArgs = getFunctionOrMethodNumArgs(d);
+
+	llvm::StringRef Module = Attr.getParameterName()->getName();
+
+	// Normalize the argument, __foo__ becomes foo.
+	if (Module.startswith("__") && Module.endswith("__"))
+		Module = Module.substr(2, Module.size() - 4);
+
+	// checks for the 2nd argument
+	Expr *IdxExpr = static_cast<Expr *> (Attr.getArg(0));
+    llvm::APSInt ArgNum(32);
+    if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
+        !IdxExpr->isIntegerConstantExpr(ArgNum, S.Context)) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+        << "ownership_returns" << IdxExpr->getSourceRange();
+      return;
+    }
+
+    unsigned x = (unsigned) ArgNum.getZExtValue();
+
+    if (x < 1 || x > NumArgs) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+       << "ownership_returns" << 1 << IdxExpr->getSourceRange();
+      return;
+    }
+    --x;
+    // Is the function argument an integer type?
+    QualType T = getFunctionOrMethodArgType(d, x);
+    if (!T->isUnsignedIntegerType()) {
+      // FIXME: Should also highlight argument in decl.
+      S.Diag(Attr.getLoc(), diag::err_ownership_returns_integers_only)
+        << "ownership_returns" << IdxExpr->getSourceRange();
+      return;
+    }
+
+	llvm::SmallVector<unsigned, 10> OwnershipReturnsArgs;
+
+	OwnershipReturnsArgs.push_back(x);
+
+	unsigned* start = &OwnershipReturnsArgs[0];
+	unsigned size = OwnershipReturnsArgs.size();
+	std::sort(start, start + size);
+	d->addAttr(::new (S.Context) OwnershipReturnsAttr(S.Context, start, size,
+			Module));
+}
+
+static void HandleOwnershipHoldsAttr(Decl *d, const AttributeList &Attr,
+		Sema &S) {
+	// must be applied to a function declaration
+	// first argument to the attribute must be a string, the name of the resource
+	// for example "malloc"
+	// next argument must be an integer less than the number of function arguments
+	// this is an argument index, the argument must be of pointer type
+
+	if (!Attr.getParameterName()) {
+		S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
+				<< "ownership_holds" << 1;
+		return;
+	}
+
+	if (Attr.getNumArgs() != 1) {
+		S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 2;
+		return;
+	}
+
+	if (!isFunctionOrMethodOrBlock(d) || !hasFunctionProto(d)) {
+		S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+				<< Attr.getName() << 0 /*function*/;
+		return;
+	}
+
+	unsigned NumArgs = getFunctionOrMethodNumArgs(d);
+
+	llvm::StringRef Module = Attr.getParameterName()->getName();
+
+	// Normalize the argument, __foo__ becomes foo.
+	if (Module.startswith("__") && Module.endswith("__"))
+		Module = Module.substr(2, Module.size() - 4);
+
+	// checks for the 2nd argument
+	Expr *IdxExpr = static_cast<Expr *> (Attr.getArg(0));
+    llvm::APSInt ArgNum(32);
+    if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
+        !IdxExpr->isIntegerConstantExpr(ArgNum, S.Context)) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+        << "ownership_holds" << IdxExpr->getSourceRange();
+      return;
+    }
+
+    unsigned x = (unsigned) ArgNum.getZExtValue();
+
+    if (x < 1 || x > NumArgs) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+       << "ownership_holds" << 1 << IdxExpr->getSourceRange();
+      return;
+    }
+    --x;
+    // Is the function argument a pointer type?
+    QualType T = getFunctionOrMethodArgType(d, x);
+    if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
+      // FIXME: Should also highlight argument in decl.
+      S.Diag(Attr.getLoc(), diag::err_ownership_holds_pointers_only)
+        << IdxExpr->getSourceRange();
+      return;
+    }
+
+	llvm::SmallVector<unsigned, 10> OwnershipHoldsArgs;
+
+	OwnershipHoldsArgs.push_back(x);
+
+	unsigned* start = &OwnershipHoldsArgs[0];
+	unsigned size = OwnershipHoldsArgs.size();
+	std::sort(start, start + size);
+	d->addAttr(::new (S.Context) OwnershipHoldsAttr(S.Context, start, size,
+			Module));
+}
+
+static void HandleOwnershipTakesAttr(Decl *d, const AttributeList &Attr,
+		Sema &S) {
+	// must be applied to a function declaration
+	// first argument to the attribute must be a string, the name of the resource
+	// for example "malloc"
+	// next argument must be an integer less than the number of function arguments
+	// this is an argument index, the argument must be of pointer type
+
+	if (!Attr.getParameterName()) {
+		S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
+				<< "ownership_takes" << 1;
+		return;
+	}
+
+	if (Attr.getNumArgs() != 1) {
+		S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 2;
+		return;
+	}
+
+	if (!isFunctionOrMethodOrBlock(d) || !hasFunctionProto(d)) {
+		S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+				<< Attr.getName() << 0 /*function*/;
+		return;
+	}
+
+	unsigned NumArgs = getFunctionOrMethodNumArgs(d);
+
+	llvm::StringRef Module = Attr.getParameterName()->getName();
+
+	// Normalize the argument, __foo__ becomes foo.
+	if (Module.startswith("__") && Module.endswith("__"))
+		Module = Module.substr(2, Module.size() - 4);
+
+	// checks for the 2nd argument
+	Expr *IdxExpr = static_cast<Expr *> (Attr.getArg(0));
+    llvm::APSInt ArgNum(32);
+    if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
+        !IdxExpr->isIntegerConstantExpr(ArgNum, S.Context)) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+        << "ownership_takes" << IdxExpr->getSourceRange();
+      return;
+    }
+
+    unsigned x = (unsigned) ArgNum.getZExtValue();
+
+    if (x < 1 || x > NumArgs) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+       << "ownership_takes" << x << IdxExpr->getSourceRange();
+      return;
+    }
+    --x;
+    // Is the function argument a pointer type?
+    QualType T = getFunctionOrMethodArgType(d, x);
+    if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
+      // FIXME: Should also highlight argument in decl.
+      S.Diag(Attr.getLoc(), diag::err_ownership_takes_pointers_only)
+        << IdxExpr->getSourceRange();
+      return;
+    }
+
+	llvm::SmallVector<unsigned, 10> OwnershipTakesArgs;
+
+	OwnershipTakesArgs.push_back(x);
+
+	unsigned* start = &OwnershipTakesArgs[0];
+	unsigned size = OwnershipTakesArgs.size();
+	std::sort(start, start + size);
+	d->addAttr(::new (S.Context) OwnershipTakesAttr(S.Context, start, size,
+			Module));
+}
+
 static bool isStaticVarOrStaticFunciton(Decl *D) {
   if (VarDecl *VD = dyn_cast<VarDecl>(D))
     return VD->getStorageClass() == VarDecl::Static;
@@ -2002,6 +2215,12 @@
   case AttributeList::AT_mode:        HandleModeAttr        (D, Attr, S); break;
   case AttributeList::AT_malloc:      HandleMallocAttr      (D, Attr, S); break;
   case AttributeList::AT_nonnull:     HandleNonNullAttr     (D, Attr, S); break;
+  case AttributeList::AT_ownership_returns:
+	  HandleOwnershipReturnsAttr     (D, Attr, S); break;
+  case AttributeList::AT_ownership_takes:
+	  HandleOwnershipTakesAttr     (D, Attr, S); break;
+  case AttributeList::AT_ownership_holds:
+	  HandleOwnershipHoldsAttr     (D, Attr, S); break;
   case AttributeList::AT_noreturn:    HandleNoReturnAttr    (D, Attr, S); break;
   case AttributeList::AT_nothrow:     HandleNothrowAttr     (D, Attr, S); break;
   case AttributeList::AT_override:    HandleOverrideAttr    (D, Attr, S); break;
Index: lib/AST/AttrImpl.cpp
===================================================================
--- lib/AST/AttrImpl.cpp	(revision 106614)
+++ lib/AST/AttrImpl.cpp	(working copy)
@@ -66,6 +66,66 @@
   Attr::Destroy(C);
 }
 
+OwnershipReturnsAttr::OwnershipReturnsAttr(ASTContext &C, unsigned* arg_nums, unsigned size, llvm::StringRef module)
+	: AttrWithString(attr::OwnershipReturns, C, module), ArgNums(0), Size(0) {
+  if (size == 0)
+    return;
+  assert(arg_nums);
+  ArgNums = new (C) unsigned[size];
+  Size = size;
+  memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size);
+}
+
+void OwnershipReturnsAttr::setModule(ASTContext &C, llvm::StringRef module) {
+  ReplaceString(C, module);
+}
+
+void OwnershipReturnsAttr::Destroy(ASTContext &C) {
+  if (ArgNums)
+    C.Deallocate(ArgNums);
+  Attr::Destroy(C);
+}
+
+OwnershipTakesAttr::OwnershipTakesAttr(ASTContext &C, unsigned* arg_nums, unsigned size, llvm::StringRef module)
+: AttrWithString(attr::OwnershipTakes, C, module), ArgNums(0), Size(0) {
+  if (size == 0)
+    return;
+  assert(arg_nums);
+  ArgNums = new (C) unsigned[size];
+  Size = size;
+  memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size);
+}
+
+void OwnershipTakesAttr::setModule(ASTContext &C, llvm::StringRef module) {
+  ReplaceString(C, module);
+}
+
+void OwnershipTakesAttr::Destroy(ASTContext &C) {
+  if (ArgNums)
+    C.Deallocate(ArgNums);
+  Attr::Destroy(C);
+}
+
+OwnershipHoldsAttr::OwnershipHoldsAttr(ASTContext &C, unsigned* arg_nums, unsigned size, llvm::StringRef module)
+: AttrWithString(attr::OwnershipHolds, C, module), ArgNums(0), Size(0) {
+  if (size == 0)
+    return;
+  assert(arg_nums);
+  ArgNums = new (C) unsigned[size];
+  Size = size;
+  memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size);
+}
+
+void OwnershipHoldsAttr::setModule(ASTContext &C, llvm::StringRef module) {
+  ReplaceString(C, module);
+}
+
+void OwnershipHoldsAttr::Destroy(ASTContext &C) {
+  if (ArgNums)
+    C.Deallocate(ArgNums);
+  Attr::Destroy(C);
+}
+
 #define DEF_SIMPLE_ATTR_CLONE(ATTR)                                     \
   Attr *ATTR##Attr::clone(ASTContext &C) const {                        \
     return ::new (C) ATTR##Attr;                                        \
@@ -165,6 +225,18 @@
   return ::new (C) NonNullAttr(C, ArgNums, Size);
 }
 
+Attr *OwnershipReturnsAttr::clone(ASTContext &C) const {
+  return ::new (C) OwnershipReturnsAttr(C, ArgNums, Size, getModule());
+}
+
+Attr *OwnershipTakesAttr::clone(ASTContext &C) const {
+  return ::new (C) OwnershipTakesAttr(C, ArgNums, Size, getModule());
+}
+
+Attr *OwnershipHoldsAttr::clone(ASTContext &C) const {
+  return ::new (C) OwnershipHoldsAttr(C, ArgNums, Size, getModule());
+}
+
 Attr *FormatAttr::clone(ASTContext &C) const {
   return ::new (C) FormatAttr(C, getType(), formatIdx, firstArg);
 }
Index: lib/Lex/PPMacroExpansion.cpp
===================================================================
--- lib/Lex/PPMacroExpansion.cpp	(revision 106614)
+++ lib/Lex/PPMacroExpansion.cpp	(working copy)
@@ -505,6 +505,9 @@
            .Case("cxx_static_assert", LangOpts.CPlusPlus0x)
            .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
            .Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
+           .Case("ownership_returns", true)
+           .Case("ownership_takes", true)
+           .Case("ownership_holds", true)
          //.Case("cxx_concepts", false)
          //.Case("cxx_lambdas", false)
          //.Case("cxx_nullptr", false)
Index: lib/Checker/MallocChecker.cpp
===================================================================
--- lib/Checker/MallocChecker.cpp	(revision 106614)
+++ lib/Checker/MallocChecker.cpp	(working copy)
@@ -76,6 +76,7 @@
 
 private:
   void MallocMem(CheckerContext &C, const CallExpr *CE);
+  void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, const OwnershipReturnsAttr* Att);
   const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
                               const Expr *SizeEx, SVal Init,
                               const GRState *state) {
@@ -86,8 +87,10 @@
                               const GRState *state);
 
   void FreeMem(CheckerContext &C, const CallExpr *CE);
+  void FreeMemTakesAttr(CheckerContext &C, const CallExpr *CE, const OwnershipTakesAttr* Att);
+  void FreeMemHoldsAttr(CheckerContext &C, const CallExpr *CE, const OwnershipHoldsAttr* Att);
   const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
-                            const GRState *state);
+                            const GRState *state, unsigned Num, bool Hold);
 
   void ReallocMem(CheckerContext &C, const CallExpr *CE);
   void CallocMem(CheckerContext &C, const CallExpr *CE);
@@ -156,6 +159,27 @@
     return true;
   }
 
+  {
+  	  const OwnershipReturnsAttr* Att = FD->getAttr<OwnershipReturnsAttr>();
+  	  if (Att) {
+			 MallocMemReturnsAttr(C, CE, Att);
+  			 return true;
+  	  }
+  }
+  {
+	  const OwnershipTakesAttr* Att = FD->getAttr<OwnershipTakesAttr>();
+	  if (Att) {
+			 FreeMemTakesAttr(C, CE, Att);
+			 return true;
+	  }
+  }
+  {
+	  const OwnershipHoldsAttr* Att = FD->getAttr<OwnershipHoldsAttr>();
+	  if (Att) {
+			 FreeMemHoldsAttr(C, CE, Att);
+			 return true;
+	  }
+  }
   return false;
 }
 
@@ -165,6 +189,21 @@
   C.addTransition(state);
 }
 
+void MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, const OwnershipReturnsAttr* Att) {
+    unsigned idx = 0;
+    if (not Att->isModule("malloc"))
+			return;
+
+    for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
+ 		   ++I, ++idx) {
+			if (Att->isOwnershipReturns(idx)) {
+				const GRState *state = MallocMemAux(C, CE, CE->getArg(idx), UndefinedVal(),
+													C.getState());
+				C.addTransition(state);
+			}
+    }
+}
+
 const GRState *MallocChecker::MallocMemAux(CheckerContext &C,  
                                            const CallExpr *CE,
                                            SVal Size, SVal Init,
@@ -188,15 +227,47 @@
 }
 
 void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
-  const GRState *state = FreeMemAux(C, CE, C.getState());
+  const GRState *state = FreeMemAux(C, CE, C.getState(), 0, false);
 
   if (state)
     C.addTransition(state);
 }
 
+void MallocChecker::FreeMemTakesAttr(CheckerContext &C, const CallExpr *CE, const OwnershipTakesAttr* Att) {
+       unsigned idx = 0;
+       if (not Att->isModule("malloc"))
+   			return;
+
+       for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
+    		   ++I, ++idx) {
+			if (Att->isOwnershipTakes(idx)) {
+				const GRState *state = FreeMemAux(C, CE, C.getState(), idx, false);
+				if (state)
+					C.addTransition(state);
+			}
+       }
+}
+
+void MallocChecker::FreeMemHoldsAttr(CheckerContext &C, const CallExpr *CE, const OwnershipHoldsAttr* Att) {
+       unsigned idx = 0;
+       if (not Att->isModule("malloc"))
+   			return;
+
+       for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
+    		   ++I, ++idx) {
+			if (Att->isOwnershipHolds(idx)) {
+				const GRState *state = FreeMemAux(C, CE, C.getState(), idx, true);
+
+
+				if (state)
+					C.addTransition(state);
+			}
+       }
+}
+
 const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
-                                         const GRState *state) {
-  const Expr *ArgExpr = CE->getArg(0);
+                                         const GRState *state, unsigned Num, bool Hold) {
+  const Expr *ArgExpr = CE->getArg(Num);
   SVal ArgVal = state->getSVal(ArgExpr);
 
   // If ptr is NULL, no operation is preformed.
@@ -258,7 +329,7 @@
     return state;
 
   // Check double free.
-  if (RS->isReleased()) {
+  if (RS->isReleased() && !Hold) {
     ExplodedNode *N = C.GenerateSink();
     if (N) {
       if (!BT_DoubleFree)
@@ -437,13 +508,13 @@
                                       ValMgr.makeIntValWithPtrWidth(0, false));
 
     if (const GRState *stateSizeZero = stateNotEqual->Assume(SizeZero, true)) {
-      const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero);
+      const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero, 0, false);
       if (stateFree)
         C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
     }
 
     if (const GRState *stateSizeNotZero=stateNotEqual->Assume(SizeZero,false)) {
-      const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero);
+      const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero, 0, false);
       if (stateFree) {
         // FIXME: We should copy the content of the original buffer.
         const GRState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1), 
Index: lib/Parse/AttributeList.cpp
===================================================================
--- lib/Parse/AttributeList.cpp	(revision 106614)
+++ lib/Parse/AttributeList.cpp	(working copy)
@@ -118,6 +118,9 @@
     .Case("ns_returns_retained", AT_ns_returns_retained)
     .Case("cf_returns_not_retained", AT_cf_returns_not_retained)
     .Case("cf_returns_retained", AT_cf_returns_retained)
+    .Case("ownership_returns", AT_ownership_returns)
+    .Case("ownership_holds", AT_ownership_holds)
+    .Case("ownership_takes", AT_ownership_takes)
     .Case("reqd_work_group_size", AT_reqd_wg_size)
     .Case("init_priority", AT_init_priority)
     .Case("no_instrument_function", AT_no_instrument_function)
