r351575 - Revert "Fix failing MSan bots"

George Karpenkov via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 18 11:24:55 PST 2019


Author: george.karpenkov
Date: Fri Jan 18 11:24:55 2019
New Revision: 351575

URL: http://llvm.org/viewvc/llvm-project?rev=351575&view=rev
Log:
Revert "Fix failing MSan bots"

This reverts commit 2cedaaef383d8d6142046074ffebc2bb5a914778.

Revert with a fix.

Added:
    cfe/trunk/test/Analysis/os_object_base.h
    cfe/trunk/test/Analysis/os_smart_ptr.h
Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp
    cfe/trunk/test/Analysis/osobject-retain-release.cpp
    cfe/trunk/test/Analysis/test-separate-retaincount.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h Fri Jan 18 11:24:55 2019
@@ -95,7 +95,7 @@ protected:
   friend class BugReportEquivClass;
   friend class BugReporter;
 
-  BugType& BT;
+  const BugType& BT;
   const Decl *DeclWithIssue = nullptr;
   std::string ShortDescription;
   std::string Description;
@@ -164,15 +164,15 @@ private:
   void popInterestingSymbolsAndRegions();
 
 public:
-  BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode)
+  BugReport(const BugType& bt, StringRef desc, const ExplodedNode *errornode)
       : BT(bt), Description(desc), ErrorNode(errornode) {}
 
-  BugReport(BugType& bt, StringRef shortDesc, StringRef desc,
+  BugReport(const BugType& bt, StringRef shortDesc, StringRef desc,
             const ExplodedNode *errornode)
       : BT(bt), ShortDescription(shortDesc), Description(desc),
         ErrorNode(errornode) {}
 
-  BugReport(BugType &bt, StringRef desc, PathDiagnosticLocation l)
+  BugReport(const BugType &bt, StringRef desc, PathDiagnosticLocation l)
       : BT(bt), Description(desc), Location(l) {}
 
   /// Create a BugReport with a custom uniqueing location.
@@ -190,7 +190,7 @@ public:
   virtual ~BugReport();
 
   const BugType& getBugType() const { return BT; }
-  BugType& getBugType() { return BT; }
+  //BugType& getBugType() { return BT; }
 
   /// True when the report has an execution path associated with it.
   ///
@@ -481,7 +481,7 @@ public:
     return {};
   }
 
-  void Register(BugType *BT);
+  void Register(const BugType *BT);
 
   /// Add the given report to the set of reports tracked by BugReporter.
   ///

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h Fri Jan 18 11:24:55 2019
@@ -38,12 +38,14 @@ private:
   virtual void anchor();
 
 public:
-  BugType(CheckName Check, StringRef Name, StringRef Cat)
+  BugType(CheckName Check, StringRef Name, StringRef Cat,
+          bool SuppressOnSink=false)
       : Check(Check), Name(Name), Category(Cat), Checker(nullptr),
-        SuppressOnSink(false) {}
-  BugType(const CheckerBase *Checker, StringRef Name, StringRef Cat)
+        SuppressOnSink(SuppressOnSink) {}
+  BugType(const CheckerBase *Checker, StringRef Name, StringRef Cat,
+          bool SuppressOnSink=false)
       : Check(Checker->getCheckName()), Name(Name), Category(Cat),
-        Checker(Checker), SuppressOnSink(false) {}
+        Checker(Checker), SuppressOnSink(SuppressOnSink) {}
   virtual ~BugType() = default;
 
   StringRef getName() const { return Name; }
@@ -64,7 +66,6 @@ public:
   ///  type should be suppressed if the end node of the report is post-dominated
   ///  by a sink node.
   bool isSuppressOnSink() const { return SuppressOnSink; }
-  void setSuppressOnSink(bool x) { SuppressOnSink = x; }
 };
 
 class BuiltinBug : public BugType {

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h Fri Jan 18 11:24:55 2019
@@ -685,6 +685,10 @@ public:
   Optional<BehaviorSummary> canEval(const CallExpr *CE, const FunctionDecl *FD,
                                     bool &hasTrustedImplementationAnnotation);
 
+  /// \return Whether the type corresponds to a known smart pointer
+  /// implementation (that is, everything about it is inlineable).
+  static bool isKnownSmartPointer(QualType QT);
+
   bool isTrustedReferenceCountImplementation(const FunctionDecl *FD);
 
   const RetainSummary *getSummary(const CallEvent &Call,

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp Fri Jan 18 11:24:55 2019
@@ -399,14 +399,14 @@ bool isZero(ProgramStateRef State, const
 
 IteratorChecker::IteratorChecker() {
   OutOfRangeBugType.reset(
-      new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
-  OutOfRangeBugType->setSuppressOnSink(true);
+      new BugType(this, "Iterator out of range", "Misuse of STL APIs",
+                  /*SuppressOnSink=*/true));
   MismatchedBugType.reset(
-      new BugType(this, "Iterator(s) mismatched", "Misuse of STL APIs"));
-  MismatchedBugType->setSuppressOnSink(true);
+      new BugType(this, "Iterator(s) mismatched", "Misuse of STL APIs",
+                  /*SuppressOnSink=*/true));
   InvalidatedBugType.reset(
-      new BugType(this, "Iterator invalidated", "Misuse of STL APIs"));
-  InvalidatedBugType->setSuppressOnSink(true);
+      new BugType(this, "Iterator invalidated", "Misuse of STL APIs",
+                  /*SuppressOnSink=*/true));
 }
 
 void IteratorChecker::checkPreCall(const CallEvent &Call,

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Fri Jan 18 11:24:55 2019
@@ -2301,14 +2301,14 @@ void MallocChecker::reportLeak(SymbolRef
 
   assert(N);
   if (!BT_Leak[*CheckKind]) {
-    BT_Leak[*CheckKind].reset(new BugType(CheckNames[*CheckKind], "Memory leak",
-                                          categories::MemoryError));
     // Leaks should not be reported if they are post-dominated by a sink:
     // (1) Sinks are higher importance bugs.
     // (2) NoReturnFunctionChecker uses sink nodes to represent paths ending
     //     with __noreturn functions such as assert() or exit(). We choose not
     //     to report leaks on such paths.
-    BT_Leak[*CheckKind]->setSuppressOnSink(true);
+    BT_Leak[*CheckKind].reset(new BugType(CheckNames[*CheckKind], "Memory leak",
+                                          categories::MemoryError,
+                                          /*SuppressOnSink=*/true));
   }
 
   // Most bug reports are cached at the location where they occurred.

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp Fri Jan 18 11:24:55 2019
@@ -29,6 +29,10 @@ const RefVal *getRefBinding(ProgramState
   return State->get<RefBindings>(Sym);
 }
 
+} // end namespace retaincountchecker
+} // end namespace ento
+} // end namespace clang
+
 static ProgramStateRef setRefBinding(ProgramStateRef State, SymbolRef Sym,
                                      RefVal Val) {
   assert(Sym != nullptr);
@@ -39,73 +43,6 @@ static ProgramStateRef removeRefBinding(
   return State->remove<RefBindings>(Sym);
 }
 
-class UseAfterRelease : public RefCountBug {
-public:
-  UseAfterRelease(const CheckerBase *checker)
-      : RefCountBug(checker, "Use-after-release") {}
-
-  const char *getDescription() const override {
-    return "Reference-counted object is used after it is released";
-  }
-};
-
-class BadRelease : public RefCountBug {
-public:
-  BadRelease(const CheckerBase *checker) : RefCountBug(checker, "Bad release") {}
-
-  const char *getDescription() const override {
-    return "Incorrect decrement of the reference count of an object that is "
-           "not owned at this point by the caller";
-  }
-};
-
-class DeallocNotOwned : public RefCountBug {
-public:
-  DeallocNotOwned(const CheckerBase *checker)
-      : RefCountBug(checker, "-dealloc sent to non-exclusively owned object") {}
-
-  const char *getDescription() const override {
-    return "-dealloc sent to object that may be referenced elsewhere";
-  }
-};
-
-class OverAutorelease : public RefCountBug {
-public:
-  OverAutorelease(const CheckerBase *checker)
-      : RefCountBug(checker, "Object autoreleased too many times") {}
-
-  const char *getDescription() const override {
-    return "Object autoreleased too many times";
-  }
-};
-
-class ReturnedNotOwnedForOwned : public RefCountBug {
-public:
-  ReturnedNotOwnedForOwned(const CheckerBase *checker)
-      : RefCountBug(checker, "Method should return an owned object") {}
-
-  const char *getDescription() const override {
-    return "Object with a +0 retain count returned to caller where a +1 "
-           "(owning) retain count is expected";
-  }
-};
-
-class Leak : public RefCountBug {
-public:
-  Leak(const CheckerBase *checker, StringRef name) : RefCountBug(checker, name) {
-    // Leaks should not be reported if they are post-dominated by a sink.
-    setSuppressOnSink(true);
-  }
-
-  const char *getDescription() const override { return ""; }
-
-  bool isLeak() const override { return true; }
-};
-
-} // end namespace retaincountchecker
-} // end namespace ento
-} // end namespace clang
-
 void RefVal::print(raw_ostream &Out) const {
   if (!T.isNull())
     Out << "Tracked " << T.getAsString() << " | ";
@@ -414,20 +351,6 @@ void RetainCountChecker::checkPostCall(c
   checkSummary(*Summ, Call, C);
 }
 
-RefCountBug *
-RetainCountChecker::getLeakWithinFunctionBug(const LangOptions &LOpts) const {
-  if (!leakWithinFunction)
-    leakWithinFunction.reset(new Leak(this, "Leak"));
-  return leakWithinFunction.get();
-}
-
-RefCountBug *
-RetainCountChecker::getLeakAtReturnBug(const LangOptions &LOpts) const {
-  if (!leakAtReturn)
-    leakAtReturn.reset(new Leak(this, "Leak of returned object"));
-  return leakAtReturn.get();
-}
-
 /// GetReturnType - Used to get the return type of a message expression or
 ///  function call with the intention of affixing that type to a tracked symbol.
 ///  While the return type can be queried directly from RetEx, when
@@ -529,6 +452,13 @@ void RetainCountChecker::processSummaryO
   C.addTransition(state);
 }
 
+static bool isSmartPtrField(const MemRegion *MR) {
+  const auto *TR = dyn_cast<TypedValueRegion>(
+    cast<SubRegion>(MR)->getSuperRegion());
+  return TR && RetainSummaryManager::isKnownSmartPointer(TR->getValueType());
+}
+
+
 /// A value escapes in these possible cases:
 ///
 /// - binding to something that is not a memory region.
@@ -536,10 +466,15 @@ void RetainCountChecker::processSummaryO
 /// - binding to a variable that has a destructor attached using CleanupAttr
 ///
 /// We do not currently model what happens when a symbol is
-/// assigned to a struct field, so be conservative here and let the symbol go.
+/// assigned to a struct field, unless it is a known smart pointer
+/// implementation, about which we know that it is inlined.
 /// FIXME: This could definitely be improved upon.
 static bool shouldEscapeRegion(const MemRegion *R) {
+  if (isSmartPtrField(R))
+    return false;
+
   const auto *VR = dyn_cast<VarRegion>(R);
+
   if (!R->hasStackStorage() || !VR)
     return true;
 
@@ -867,6 +802,23 @@ ProgramStateRef RetainCountChecker::upda
   return setRefBinding(state, sym, V);
 }
 
+const RefCountBug &
+RetainCountChecker::errorKindToBugKind(RefVal::Kind ErrorKind,
+                                       SymbolRef Sym) const {
+  switch (ErrorKind) {
+    case RefVal::ErrorUseAfterRelease:
+      return useAfterRelease;
+    case RefVal::ErrorReleaseNotOwned:
+      return releaseNotOwned;
+    case RefVal::ErrorDeallocNotOwned:
+      if (Sym->getType()->getPointeeCXXRecordDecl())
+        return freeNotOwned;
+      return deallocNotOwned;
+    default:
+      llvm_unreachable("Unhandled error.");
+  }
+}
+
 void RetainCountChecker::processNonLeakError(ProgramStateRef St,
                                              SourceRange ErrorRange,
                                              RefVal::Kind ErrorKind,
@@ -886,30 +838,9 @@ void RetainCountChecker::processNonLeakE
   if (!N)
     return;
 
-  RefCountBug *BT;
-  switch (ErrorKind) {
-    default:
-      llvm_unreachable("Unhandled error.");
-    case RefVal::ErrorUseAfterRelease:
-      if (!useAfterRelease)
-        useAfterRelease.reset(new UseAfterRelease(this));
-      BT = useAfterRelease.get();
-      break;
-    case RefVal::ErrorReleaseNotOwned:
-      if (!releaseNotOwned)
-        releaseNotOwned.reset(new BadRelease(this));
-      BT = releaseNotOwned.get();
-      break;
-    case RefVal::ErrorDeallocNotOwned:
-      if (!deallocNotOwned)
-        deallocNotOwned.reset(new DeallocNotOwned(this));
-      BT = deallocNotOwned.get();
-      break;
-  }
-
-  assert(BT);
   auto report = llvm::make_unique<RefCountReport>(
-      *BT, C.getASTContext().getLangOpts(), N, Sym);
+      errorKindToBugKind(ErrorKind, Sym),
+      C.getASTContext().getLangOpts(), N, Sym);
   report->addRange(ErrorRange);
   C.emitReport(std::move(report));
 }
@@ -1112,8 +1043,8 @@ ExplodedNode * RetainCountChecker::check
         ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag);
         if (N) {
           const LangOptions &LOpts = C.getASTContext().getLangOpts();
-          auto R = llvm::make_unique<RefLeakReport>(
-              *getLeakAtReturnBug(LOpts), LOpts, N, Sym, C);
+          auto R =
+              llvm::make_unique<RefLeakReport>(leakAtReturn, LOpts, N, Sym, C);
           C.emitReport(std::move(R));
         }
         return N;
@@ -1137,11 +1068,8 @@ ExplodedNode * RetainCountChecker::check
 
         ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag);
         if (N) {
-          if (!returnNotOwnedForOwned)
-            returnNotOwnedForOwned.reset(new ReturnedNotOwnedForOwned(this));
-
           auto R = llvm::make_unique<RefCountReport>(
-              *returnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym);
+              returnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym);
           C.emitReport(std::move(R));
         }
         return N;
@@ -1293,12 +1221,9 @@ RetainCountChecker::handleAutoreleaseCou
       os << "but ";
     os << "has a +" << V.getCount() << " retain count";
 
-    if (!overAutorelease)
-      overAutorelease.reset(new OverAutorelease(this));
-
     const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
-    auto R = llvm::make_unique<RefCountReport>(*overAutorelease, LOpts, N, Sym,
-                                            os.str());
+    auto R = llvm::make_unique<RefCountReport>(overAutorelease, LOpts, N, Sym,
+                                               os.str());
     Ctx.emitReport(std::move(R));
   }
 
@@ -1344,11 +1269,8 @@ RetainCountChecker::processLeaks(Program
 
   if (N) {
     for (SymbolRef L : Leaked) {
-      RefCountBug *BT = Pred ? getLeakWithinFunctionBug(LOpts)
-                          : getLeakAtReturnBug(LOpts);
-      assert(BT && "BugType not initialized.");
-
-      Ctx.emitReport(llvm::make_unique<RefLeakReport>(*BT, LOpts, N, L, Ctx));
+      const RefCountBug &BT = Pred ? leakWithinFunction : leakAtReturn;
+      Ctx.emitReport(llvm::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx));
     }
   }
 

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h Fri Jan 18 11:24:55 2019
@@ -251,10 +251,15 @@ class RetainCountChecker
                     check::RegionChanges,
                     eval::Assume,
                     eval::Call > {
-  mutable std::unique_ptr<RefCountBug> useAfterRelease, releaseNotOwned;
-  mutable std::unique_ptr<RefCountBug> deallocNotOwned;
-  mutable std::unique_ptr<RefCountBug> overAutorelease, returnNotOwnedForOwned;
-  mutable std::unique_ptr<RefCountBug> leakWithinFunction, leakAtReturn;
+
+  RefCountBug useAfterRelease{this, RefCountBug::UseAfterRelease};
+  RefCountBug releaseNotOwned{this, RefCountBug::ReleaseNotOwned};
+  RefCountBug deallocNotOwned{this, RefCountBug::DeallocNotOwned};
+  RefCountBug freeNotOwned{this, RefCountBug::FreeNotOwned};
+  RefCountBug overAutorelease{this, RefCountBug::OverAutorelease};
+  RefCountBug returnNotOwnedForOwned{this, RefCountBug::ReturnNotOwnedForOwned};
+  RefCountBug leakWithinFunction{this, RefCountBug::LeakWithinFunction};
+  RefCountBug leakAtReturn{this, RefCountBug::LeakAtReturn};
 
   mutable std::unique_ptr<RetainSummaryManager> Summaries;
 public:
@@ -266,11 +271,7 @@ public:
   /// Track sublcasses of OSObject.
   bool TrackOSObjects = false;
 
-  RetainCountChecker() {}
-
-  RefCountBug *getLeakWithinFunctionBug(const LangOptions &LOpts) const;
-
-  RefCountBug *getLeakAtReturnBug(const LangOptions &LOpts) const;
+  RetainCountChecker() {};
 
   RetainSummaryManager &getSummaryManager(ASTContext &Ctx) const {
     // FIXME: We don't support ARC being turned on and off during one analysis.
@@ -336,6 +337,9 @@ public:
                                RefVal V, ArgEffect E, RefVal::Kind &hasErr,
                                CheckerContext &C) const;
 
+  const RefCountBug &errorKindToBugKind(RefVal::Kind ErrorKind,
+                                        SymbolRef Sym) const;
+
   void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange,
                            RefVal::Kind ErrorKind, SymbolRef Sym,
                            CheckerContext &C) const;

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp Fri Jan 18 11:24:55 2019
@@ -19,6 +19,54 @@ using namespace clang;
 using namespace ento;
 using namespace retaincountchecker;
 
+StringRef RefCountBug::bugTypeToName(RefCountBug::RefCountBugType BT) {
+  switch (BT) {
+  case UseAfterRelease:
+    return "Use-after-release";
+  case ReleaseNotOwned:
+    return "Bad release";
+  case DeallocNotOwned:
+    return "-dealloc sent to non-exclusively owned object";
+  case FreeNotOwned:
+    return "freeing non-exclusively owned object";
+  case OverAutorelease:
+    return "Object autoreleased too many times";
+  case ReturnNotOwnedForOwned:
+    return "Method should return an owned object";
+  case LeakWithinFunction:
+    return "Leak";
+  case LeakAtReturn:
+    return "Leak of returned object";
+  }
+}
+
+StringRef RefCountBug::getDescription() const {
+  switch (BT) {
+  case UseAfterRelease:
+    return "Reference-counted object is used after it is released";
+  case ReleaseNotOwned:
+    return "Incorrect decrement of the reference count of an object that is "
+           "not owned at this point by the caller";
+  case DeallocNotOwned:
+    return "-dealloc sent to object that may be referenced elsewhere";
+  case FreeNotOwned:
+    return  "'free' called on an object that may be referenced elsewhere";
+  case OverAutorelease:
+    return "Object autoreleased too many times";
+  case ReturnNotOwnedForOwned:
+    return "Object with a +0 retain count returned to caller where a +1 "
+           "(owning) retain count is expected";
+  case LeakWithinFunction:
+  case LeakAtReturn:
+    return "";
+  }
+}
+
+RefCountBug::RefCountBug(const CheckerBase *Checker, RefCountBugType BT)
+    : BugType(Checker, bugTypeToName(BT), categories::MemoryRefCount,
+              /*SupressOnSink=*/BT == LeakWithinFunction || BT == LeakAtReturn),
+      BT(BT) {}
+
 static bool isNumericLiteralExpression(const Expr *E) {
   // FIXME: This set of cases was copied from SemaExprObjC.
   return isa<IntegerLiteral>(E) ||
@@ -42,7 +90,8 @@ static std::string getPrettyTypeName(Qua
 /// Write information about the type state change to {@code os},
 /// return whether the note should be generated.
 static bool shouldGenerateNote(llvm::raw_string_ostream &os,
-                               const RefVal *PrevT, const RefVal &CurrV,
+                               const RefVal *PrevT,
+                               const RefVal &CurrV,
                                bool DeallocSent) {
   // Get the previous type state.
   RefVal PrevV = *PrevT;
@@ -132,6 +181,32 @@ static Optional<unsigned> findArgIdxOfSy
   return None;
 }
 
+Optional<std::string> findMetaClassAlloc(const Expr *Callee) {
+  if (const auto *ME = dyn_cast<MemberExpr>(Callee)) {
+    if (ME->getMemberDecl()->getNameAsString() != "alloc")
+      return None;
+    const Expr *This = ME->getBase()->IgnoreParenImpCasts();
+    if (const auto *DRE = dyn_cast<DeclRefExpr>(This)) {
+      const ValueDecl *VD = DRE->getDecl();
+      if (VD->getNameAsString() != "metaClass")
+        return None;
+
+      if (const auto *RD = dyn_cast<CXXRecordDecl>(VD->getDeclContext()))
+        return RD->getNameAsString();
+
+    }
+  }
+  return None;
+}
+
+std::string findAllocatedObjectName(const Stmt *S,
+                                    QualType QT) {
+  if (const auto *CE = dyn_cast<CallExpr>(S))
+    if (auto Out = findMetaClassAlloc(CE->getCallee()))
+      return *Out;
+  return getPrettyTypeName(QT);
+}
+
 static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
                                            const LocationContext *LCtx,
                                            const RefVal &CurrV, SymbolRef &Sym,
@@ -189,7 +264,7 @@ static void generateDiagnosticsForCallLi
     os << "a Core Foundation object of type '"
        << Sym->getType().getAsString() << "' with a ";
   } else if (CurrV.getObjKind() == ObjKind::OS) {
-    os << "an OSObject of type '" << getPrettyTypeName(Sym->getType())
+    os << "an OSObject of type '" << findAllocatedObjectName(S, Sym->getType())
        << "' with a ";
   } else if (CurrV.getObjKind() == ObjKind::Generalized) {
     os << "an object of type '" << Sym->getType().getAsString()
@@ -338,15 +413,7 @@ annotateConsumedSummaryMismatch(const Ex
   if (os.str().empty())
     return nullptr;
 
-  // FIXME: remove the code duplication with NoStoreFuncVisitor.
-  PathDiagnosticLocation L;
-  if (const ReturnStmt *RS = CallExitLoc.getReturnStmt()) {
-    L = PathDiagnosticLocation::createBegin(RS, SM, N->getLocationContext());
-  } else {
-    L = PathDiagnosticLocation(
-        Call->getRuntimeDefinition().getDecl()->getSourceRange().getEnd(), SM);
-  }
-
+  PathDiagnosticLocation L = PathDiagnosticLocation::create(CallExitLoc, SM);
   return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
 }
 
@@ -354,6 +421,11 @@ std::shared_ptr<PathDiagnosticPiece>
 RefCountReportVisitor::VisitNode(const ExplodedNode *N,
                               BugReporterContext &BRC, BugReport &BR) {
 
+  const auto &BT = static_cast<const RefCountBug&>(BR.getBugType());
+
+  bool IsFreeUnowned = BT.getBugType() == RefCountBug::FreeNotOwned ||
+                       BT.getBugType() == RefCountBug::DeallocNotOwned;
+
   const SourceManager &SM = BRC.getSourceManager();
   CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
   if (auto CE = N->getLocationAs<CallExitBegin>())
@@ -372,7 +444,8 @@ RefCountReportVisitor::VisitNode(const E
   const LocationContext *LCtx = N->getLocationContext();
 
   const RefVal* CurrT = getRefBinding(CurrSt, Sym);
-  if (!CurrT) return nullptr;
+  if (!CurrT)
+    return nullptr;
 
   const RefVal &CurrV = *CurrT;
   const RefVal *PrevT = getRefBinding(PrevSt, Sym);
@@ -382,6 +455,12 @@ RefCountReportVisitor::VisitNode(const E
   std::string sbuf;
   llvm::raw_string_ostream os(sbuf);
 
+  if (PrevT && IsFreeUnowned && CurrV.isNotOwned() && PrevT->isOwned()) {
+    os << "Object is now not exclusively owned";
+    auto Pos = PathDiagnosticLocation::create(N->getLocation(), SM);
+    return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
+  }
+
   // This is the allocation site since the previous node had no bindings
   // for this symbol.
   if (!PrevT) {
@@ -428,9 +507,9 @@ RefCountReportVisitor::VisitNode(const E
   // program point
   bool DeallocSent = false;
 
-  if (N->getLocation().getTag() &&
-      N->getLocation().getTag()->getTagDescription().contains(
-          RetainCountChecker::DeallocTagDescription)) {
+  const ProgramPointTag *Tag = N->getLocation().getTag();
+  if (Tag && Tag->getTagDescription().contains(
+                 RetainCountChecker::DeallocTagDescription)) {
     // We only have summaries attached to nodes after evaluating CallExpr and
     // ObjCMessageExprs.
     const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
@@ -685,15 +764,15 @@ RefLeakReportVisitor::getEndPath(BugRepo
   return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
 }
 
-RefCountReport::RefCountReport(RefCountBug &D, const LangOptions &LOpts,
+RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
                                ExplodedNode *n, SymbolRef sym,
-                               bool registerVisitor)
-    : BugReport(D, D.getDescription(), n), Sym(sym) {
-  if (registerVisitor)
+                               bool isLeak)
+    : BugReport(D, D.getDescription(), n), Sym(sym), isLeak(isLeak) {
+  if (!isLeak)
     addVisitor(llvm::make_unique<RefCountReportVisitor>(sym));
 }
 
-RefCountReport::RefCountReport(RefCountBug &D, const LangOptions &LOpts,
+RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
                                ExplodedNode *n, SymbolRef sym,
                                StringRef endText)
     : BugReport(D, D.getDescription(), endText, n) {
@@ -779,10 +858,10 @@ void RefLeakReport::createDescription(Ch
   }
 }
 
-RefLeakReport::RefLeakReport(RefCountBug &D, const LangOptions &LOpts,
+RefLeakReport::RefLeakReport(const RefCountBug &D, const LangOptions &LOpts,
                              ExplodedNode *n, SymbolRef sym,
                              CheckerContext &Ctx)
-    : RefCountReport(D, LOpts, n, sym, false) {
+    : RefCountReport(D, LOpts, n, sym, /*isLeak=*/true) {
 
   deriveAllocLocation(Ctx, sym);
   if (!AllocBinding)

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h Fri Jan 18 11:24:55 2019
@@ -25,32 +25,44 @@ namespace ento {
 namespace retaincountchecker {
 
 class RefCountBug : public BugType {
-protected:
-  RefCountBug(const CheckerBase *checker, StringRef name)
-      : BugType(checker, name, categories::MemoryRefCount) {}
-
 public:
-  virtual const char *getDescription() const = 0;
+  enum RefCountBugType {
+    UseAfterRelease,
+    ReleaseNotOwned,
+    DeallocNotOwned,
+    FreeNotOwned,
+    OverAutorelease,
+    ReturnNotOwnedForOwned,
+    LeakWithinFunction,
+    LeakAtReturn,
+  };
+  RefCountBug(const CheckerBase *checker, RefCountBugType BT);
+  StringRef getDescription() const;
+  RefCountBugType getBugType() const {
+    return BT;
+  }
 
-  virtual bool isLeak() const { return false; }
+private:
+  RefCountBugType BT;
+  static StringRef bugTypeToName(RefCountBugType BT);
 };
 
 class RefCountReport : public BugReport {
 protected:
   SymbolRef Sym;
+  bool isLeak = false;
 
 public:
-  RefCountReport(RefCountBug &D, const LangOptions &LOpts,
+  RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
               ExplodedNode *n, SymbolRef sym,
-              bool registerVisitor = true);
+              bool isLeak=false);
 
-  RefCountReport(RefCountBug &D, const LangOptions &LOpts,
+  RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
               ExplodedNode *n, SymbolRef sym,
               StringRef endText);
 
   llvm::iterator_range<ranges_iterator> getRanges() override {
-    const RefCountBug& BugTy = static_cast<RefCountBug&>(getBugType());
-    if (!BugTy.isLeak())
+    if (!isLeak)
       return BugReport::getRanges();
     return llvm::make_range(ranges_iterator(), ranges_iterator());
   }
@@ -69,7 +81,7 @@ class RefLeakReport : public RefCountRep
   void createDescription(CheckerContext &Ctx);
 
 public:
-  RefLeakReport(RefCountBug &D, const LangOptions &LOpts, ExplodedNode *n,
+  RefLeakReport(const RefCountBug &D, const LangOptions &LOpts, ExplodedNode *n,
                 SymbolRef sym, CheckerContext &Ctx);
 
   PathDiagnosticLocation getLocation(const SourceManager &SM) const override {

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp Fri Jan 18 11:24:55 2019
@@ -109,10 +109,10 @@ SimpleStreamChecker::SimpleStreamChecker
   DoubleCloseBugType.reset(
       new BugType(this, "Double fclose", "Unix Stream API Error"));
 
-  LeakBugType.reset(
-      new BugType(this, "Resource Leak", "Unix Stream API Error"));
   // Sinks are higher importance bugs as well as calls to assert() or exit(0).
-  LeakBugType->setSuppressOnSink(true);
+  LeakBugType.reset(
+      new BugType(this, "Resource Leak", "Unix Stream API Error",
+                  /*SuppressOnSink=*/true));
 }
 
 void SimpleStreamChecker::checkPostCall(const CallEvent &Call,

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ValistChecker.cpp?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/ValistChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/ValistChecker.cpp Fri Jan 18 11:24:55 2019
@@ -276,8 +276,8 @@ void ValistChecker::reportLeakedVALists(
           new BugType(CheckNames[CK_Unterminated].getName().empty()
                           ? CheckNames[CK_Uninitialized]
                           : CheckNames[CK_Unterminated],
-                      "Leaked va_list", categories::MemoryError));
-      BT_leakedvalist->setSuppressOnSink(true);
+                      "Leaked va_list", categories::MemoryError,
+                      /*SuppressOnSink=*/true));
     }
 
     const ExplodedNode *StartNode = getStartCallSite(N, Reg);

Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp Fri Jan 18 11:24:55 2019
@@ -1247,7 +1247,7 @@ static void generatePathDiagnosticsForNo
 
 static std::unique_ptr<PathDiagnostic>
 generateEmptyDiagnosticForReport(BugReport *R, SourceManager &SM) {
-  BugType &BT = R->getBugType();
+  const BugType &BT = R->getBugType();
   return llvm::make_unique<PathDiagnostic>(
       R->getBugType().getCheckName(), R->getDeclWithIssue(),
       R->getBugType().getName(), R->getDescription(),
@@ -2684,7 +2684,7 @@ GRBugReporter::generatePathDiagnostics(
   return Out;
 }
 
-void BugReporter::Register(BugType *BT) {
+void BugReporter::Register(const BugType *BT) {
   BugTypes = F.add(BugTypes, BT);
 }
 
@@ -2718,7 +2718,7 @@ void BugReporter::emitReport(std::unique
   R->Profile(ID);
 
   // Lookup the equivance class.  If there isn't one, create it.
-  BugType& BT = R->getBugType();
+  const BugType& BT = R->getBugType();
   Register(&BT);
   void *InsertPos;
   BugReportEquivClass* EQ = EQClasses.FindNodeOrInsertPos(ID, InsertPos);
@@ -2836,7 +2836,7 @@ FindReportInEquivalenceClass(BugReportEq
                              SmallVectorImpl<BugReport*> &bugReports) {
   BugReportEquivClass::iterator I = EQ.begin(), E = EQ.end();
   assert(I != E);
-  BugType& BT = I->getBugType();
+  const BugType& BT = I->getBugType();
 
   // If we don't need to suppress any of the nodes because they are
   // post-dominated by a sink, simply add all the nodes in the equivalence class

Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp Fri Jan 18 11:24:55 2019
@@ -308,9 +308,8 @@ public:
         if (RegionOfInterest->isSubRegionOf(SelfRegion) &&
             potentiallyWritesIntoIvar(Call->getRuntimeDefinition().getDecl(),
                                       IvarR->getDecl()))
-          return notModifiedDiagnostics(Ctx, *CallExitLoc, Call, {}, SelfRegion,
-                                        "self", /*FirstIsReferenceType=*/false,
-                                        1);
+          return notModifiedDiagnostics(N, {}, SelfRegion, "self",
+                                        /*FirstIsReferenceType=*/false, 1);
       }
     }
 
@@ -318,8 +317,7 @@ public:
       const MemRegion *ThisR = CCall->getCXXThisVal().getAsRegion();
       if (RegionOfInterest->isSubRegionOf(ThisR)
           && !CCall->getDecl()->isImplicit())
-        return notModifiedDiagnostics(Ctx, *CallExitLoc, Call, {}, ThisR,
-                                      "this",
+        return notModifiedDiagnostics(N, {}, ThisR, "this",
                                       /*FirstIsReferenceType=*/false, 1);
 
       // Do not generate diagnostics for not modified parameters in
@@ -338,18 +336,17 @@ public:
       QualType T = PVD->getType();
       while (const MemRegion *R = S.getAsRegion()) {
         if (RegionOfInterest->isSubRegionOf(R) && !isPointerToConst(T))
-          return notModifiedDiagnostics(Ctx, *CallExitLoc, Call, {}, R,
-                                        ParamName, ParamIsReferenceType,
-                                        IndirectionLevel);
+          return notModifiedDiagnostics(N, {}, R, ParamName,
+                                        ParamIsReferenceType, IndirectionLevel);
 
         QualType PT = T->getPointeeType();
         if (PT.isNull() || PT->isVoidType()) break;
 
         if (const RecordDecl *RD = PT->getAsRecordDecl())
           if (auto P = findRegionOfInterestInRecord(RD, State, R))
-            return notModifiedDiagnostics(
-              Ctx, *CallExitLoc, Call, *P, RegionOfInterest, ParamName,
-              ParamIsReferenceType, IndirectionLevel);
+            return notModifiedDiagnostics(N, *P, RegionOfInterest, ParamName,
+                                          ParamIsReferenceType,
+                                          IndirectionLevel);
 
         S = State->getSVal(R, PT);
         T = PT;
@@ -523,19 +520,12 @@ private:
 
   /// \return Diagnostics piece for region not modified in the current function.
   std::shared_ptr<PathDiagnosticPiece>
-  notModifiedDiagnostics(const LocationContext *Ctx, CallExitBegin &CallExitLoc,
-                         CallEventRef<> Call, const RegionVector &FieldChain,
+  notModifiedDiagnostics(const ExplodedNode *N, const RegionVector &FieldChain,
                          const MemRegion *MatchedRegion, StringRef FirstElement,
                          bool FirstIsReferenceType, unsigned IndirectionLevel) {
 
-    PathDiagnosticLocation L;
-    if (const ReturnStmt *RS = CallExitLoc.getReturnStmt()) {
-      L = PathDiagnosticLocation::createBegin(RS, SM, Ctx);
-    } else {
-      L = PathDiagnosticLocation(
-          Call->getRuntimeDefinition().getDecl()->getSourceRange().getEnd(),
-          SM);
-    }
+    PathDiagnosticLocation L =
+        PathDiagnosticLocation::create(N->getLocation(), SM);
 
     SmallString<256> sbuf;
     llvm::raw_svector_ostream os(sbuf);

Modified: cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp Fri Jan 18 11:24:55 2019
@@ -735,6 +735,12 @@ PathDiagnosticLocation::create(const Pro
     return getLocationForCaller(CEE->getCalleeContext(),
                                 CEE->getLocationContext(),
                                 SMng);
+  } else if (auto CEB = P.getAs<CallExitBegin>()) {
+    if (const ReturnStmt *RS = CEB->getReturnStmt())
+      return PathDiagnosticLocation::createBegin(RS, SMng,
+                                                 CEB->getLocationContext());
+    return PathDiagnosticLocation(
+        CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng);
   } else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
     CFGElement BlockFront = BE->getBlock()->front();
     if (auto StmtElt = BlockFront.getAs<CFGStmt>()) {

Modified: cfe/trunk/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp Fri Jan 18 11:24:55 2019
@@ -146,7 +146,7 @@ static bool isSubclass(const Decl *D,
 }
 
 static bool isOSObjectSubclass(const Decl *D) {
-  return isSubclass(D, "OSObject");
+  return isSubclass(D, "OSMetaClassBase");
 }
 
 static bool isOSObjectDynamicCast(StringRef S) {
@@ -199,6 +199,20 @@ static bool isOSObjectRelated(const CXXM
   return false;
 }
 
+bool
+RetainSummaryManager::isKnownSmartPointer(QualType QT) {
+  QT = QT.getCanonicalType();
+  const auto *RD = QT->getAsCXXRecordDecl();
+  if (!RD)
+    return false;
+  const IdentifierInfo *II = RD->getIdentifier();
+  if (II && II->getName() == "smart_ptr")
+    if (const auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext()))
+      if (ND->getNameAsString() == "os")
+        return true;
+  return false;
+}
+
 const RetainSummary *
 RetainSummaryManager::getSummaryForOSObject(const FunctionDecl *FD,
                                             StringRef FName, QualType RetTy) {

Added: cfe/trunk/test/Analysis/os_object_base.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/os_object_base.h?rev=351575&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/os_object_base.h (added)
+++ cfe/trunk/test/Analysis/os_object_base.h Fri Jan 18 11:24:55 2019
@@ -0,0 +1,54 @@
+#ifndef _OS_BASE_H
+#define _OS_BASE_H
+
+#define OS_CONSUME __attribute__((os_consumed))
+#define OS_RETURNS_RETAINED __attribute__((os_returns_retained))
+#define OS_RETURNS_RETAINED_ON_ZERO __attribute__((os_returns_retained_on_zero))
+#define OS_RETURNS_RETAINED_ON_NONZERO __attribute__((os_returns_retained_on_non_zero))
+#define OS_RETURNS_NOT_RETAINED __attribute__((os_returns_not_retained))
+#define OS_CONSUMES_THIS __attribute__((os_consumes_this))
+
+#define OSTypeID(type)   (type::metaClass)
+
+#define OSDynamicCast(type, inst)   \
+    ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
+
+#define OSTypeAlloc(type)   ((type *) ((type::metaClass)->alloc()))
+
+using size_t = decltype(sizeof(int));
+
+struct OSMetaClass;
+
+struct OSMetaClassBase {
+  static OSMetaClassBase *safeMetaCast(const OSMetaClassBase *inst,
+                                       const OSMetaClass *meta);
+
+  virtual void retain() const;
+  virtual void release() const;
+  virtual void free();
+  virtual ~OSMetaClassBase(){};
+};
+
+struct OSObject : public OSMetaClassBase {
+  virtual ~OSObject(){}
+
+  unsigned int foo() { return 42; }
+
+  virtual OS_RETURNS_NOT_RETAINED OSObject *identity();
+
+  static OSObject *generateObject(int);
+
+  static OSObject *getObject();
+  static OSObject *GetObject();
+
+  static void * operator new(size_t size);
+
+  static const OSMetaClass * const metaClass;
+};
+
+struct OSMetaClass : public OSMetaClassBase {
+  virtual OSObject * alloc() const;
+  virtual ~OSMetaClass(){}
+};
+
+#endif /* _OS_BASE_H */

Added: cfe/trunk/test/Analysis/os_smart_ptr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/os_smart_ptr.h?rev=351575&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/os_smart_ptr.h (added)
+++ cfe/trunk/test/Analysis/os_smart_ptr.h Fri Jan 18 11:24:55 2019
@@ -0,0 +1,89 @@
+#ifndef _OS_SMART_POINTER_H
+#define _OS_SMART_POINTER_H
+
+#include "os_object_base.h"
+
+namespace os {
+
+template<class T>
+struct smart_ptr {
+  smart_ptr() : pointer(nullptr) {}
+
+  explicit smart_ptr(T *&p) : pointer(p) {
+    if (pointer) {
+      _retain(pointer);
+    }
+  }
+
+  smart_ptr(smart_ptr const &rhs) : pointer(rhs.pointer) {
+    if (pointer) {
+      _retain(pointer);
+    }
+  }
+
+  smart_ptr & operator=(T *&rhs) {
+    smart_ptr(rhs).swap(*this);
+    return *this;
+  }
+
+  smart_ptr & operator=(smart_ptr &rhs) {
+    smart_ptr(rhs).swap(*this);
+    return *this;
+  }
+
+  ~smart_ptr() {
+    if (pointer) {
+      _release(pointer);
+    }
+  }
+
+  void reset() {
+    smart_ptr().swap(*this);
+  }
+
+  T *get() const {
+    return pointer;
+  }
+
+  T ** get_for_out_param() {
+    reset();
+    return &pointer;
+  }
+
+  T * operator->() const {
+    OSPTR_LOG("Dereference smart_ptr with %p\n", pointer);
+    return pointer;
+  }
+
+  explicit
+  operator bool() const {
+    return pointer != nullptr;
+  }
+
+  inline void
+  swap(smart_ptr &p) {
+    T *temp = pointer;
+    pointer = p.pointer;
+    p.pointer = temp;
+  }
+
+  static inline void
+  _retain(T *obj) {
+    obj->retain();
+  }
+
+  static inline void
+  _release(T *obj) {
+    obj->release();
+  }
+
+  static inline T *
+  _alloc() {
+    return new T;
+  }
+
+  T *pointer;
+};
+}
+
+#endif /* _OS_SMART_POINTER_H */

Modified: cfe/trunk/test/Analysis/osobject-retain-release.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/osobject-retain-release.cpp?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/osobject-retain-release.cpp (original)
+++ cfe/trunk/test/Analysis/osobject-retain-release.cpp Fri Jan 18 11:24:55 2019
@@ -1,44 +1,10 @@
 // RUN: %clang_analyze_cc1 -fblocks -analyze -analyzer-output=text\
 // RUN:                    -analyzer-checker=core,osx -verify %s
 
-struct OSMetaClass;
-
-#define OS_CONSUME __attribute__((os_consumed))
-#define OS_RETURNS_RETAINED __attribute__((os_returns_retained))
-#define OS_RETURNS_RETAINED_ON_ZERO __attribute__((os_returns_retained_on_zero))
-#define OS_RETURNS_RETAINED_ON_NONZERO __attribute__((os_returns_retained_on_non_zero))
-#define OS_RETURNS_NOT_RETAINED __attribute__((os_returns_not_retained))
-#define OS_CONSUMES_THIS __attribute__((os_consumes_this))
-
-#define OSTypeID(type)   (type::metaClass)
-
-#define OSDynamicCast(type, inst)   \
-    ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
-
-using size_t = decltype(sizeof(int));
-
-struct OSObject {
-  virtual void retain();
-  virtual void release() {};
-  virtual void free();
-  virtual ~OSObject(){}
-
-  unsigned int foo() { return 42; }
-
-  virtual OS_RETURNS_NOT_RETAINED OSObject *identity();
-
-  static OSObject *generateObject(int);
-
-  static OSObject *getObject();
-  static OSObject *GetObject();
-
-  static void * operator new(size_t size);
-
-  static const OSMetaClass * const metaClass;
-};
+#include "os_object_base.h"
+#include "os_smart_ptr.h"
 
 struct OSIterator : public OSObject {
-
   static const OSMetaClass * const metaClass;
 };
 
@@ -88,9 +54,6 @@ struct OtherStruct {
   OtherStruct(OSArray *arr);
 };
 
-struct OSMetaClassBase {
-  static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
-};
 
 void escape(void *);
 void escape_with_source(void *p) {}
@@ -616,3 +579,68 @@ typedef bool (^Blk)(OSObject *);
 void test_escape_to_unknown_block(Blk blk) {
   blk(getObject()); // no-crash
 }
+
+using OSObjectPtr = os::smart_ptr<OSObject>;
+
+void test_smart_ptr_uaf() {
+  OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
+  {
+    OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}
+   // expected-note at -1{{Returning from constructor for 'smart_ptr<OSObject>'}}
+    // expected-note at os_smart_ptr.h:13{{Taking true branch}}
+    // expected-note at os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
+    // expected-note at os_smart_ptr.h:72{{Reference count incremented. The object now has a +2 retain count}}
+    // expected-note at os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
+  } // expected-note{{Calling '~smart_ptr'}}
+  // expected-note at os_smart_ptr.h:35{{Taking true branch}}
+  // expected-note at os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
+  // expected-note at os_smart_ptr.h:77{{Reference count decremented. The object now has a +1 retain count}}
+  // expected-note at os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
+ // expected-note at -5{{Returning from '~smart_ptr'}}
+  obj->release(); // expected-note{{Object released}}
+  obj->release(); // expected-warning{{Reference-counted object is used after it is released}}
+// expected-note at -1{{Reference-counted object is used after it is released}}
+}
+
+void test_smart_ptr_leak() {
+  OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
+  {
+    OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}
+   // expected-note at -1{{Returning from constructor for 'smart_ptr<OSObject>'}}
+    // expected-note at os_smart_ptr.h:13{{Taking true branch}}
+    // expected-note at os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
+    // expected-note at os_smart_ptr.h:72{{Reference count incremented. The object now has a +2 retain count}}
+    // expected-note at os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
+  } // expected-note{{Calling '~smart_ptr'}}
+  // expected-note at os_smart_ptr.h:35{{Taking true branch}}
+  // expected-note at os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
+  // expected-note at os_smart_ptr.h:77{{Reference count decremented. The object now has a +1 retain count}}
+  // expected-note at os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
+ // expected-note at -5{{Returning from '~smart_ptr'}}
+} // expected-warning{{Potential leak of an object stored into 'obj'}}
+// expected-note at -1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}
+
+void test_smart_ptr_no_leak() {
+  OSObject *obj = new OSObject;
+  {
+    OSObjectPtr p(obj);
+  }
+  obj->release();
+}
+
+void test_ostypealloc_correct_diagnostic_name() {
+  OSArray *arr = OSTypeAlloc(OSArray); // expected-note{{Call to method 'OSMetaClass::alloc' returns an OSObject of type 'OSArray' with a +1 retain count}}
+  arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
+  arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
+} // expected-note{{Object leaked: object allocated and stored into 'arr' is not referenced later in this execution path and has a retain count of +1}}
+  // expected-warning at -1{{Potential leak of an object stored into 'arr'}}
+
+void escape_elsewhere(OSObject *obj);
+
+void test_free_on_escaped_object_diagnostics() {
+  OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
+  escape_elsewhere(obj); // expected-note{{Object is now not exclusively owned}}
+  obj->free(); // expected-note{{'free' called on an object that may be referenced elsewhere}}
+  // expected-warning at -1{{'free' called on an object that may be referenced elsewhere}}
+}
+

Modified: cfe/trunk/test/Analysis/test-separate-retaincount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/test-separate-retaincount.cpp?rev=351575&r1=351574&r2=351575&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/test-separate-retaincount.cpp (original)
+++ cfe/trunk/test/Analysis/test-separate-retaincount.cpp Fri Jan 18 11:24:55 2019
@@ -2,6 +2,8 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-disable-checker osx.OSObjectRetainCount -DNO_OS_OBJECT -verify %s
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-config "osx.cocoa.RetainCount:CheckOSObject=false" -DNO_OS_OBJECT -verify %s
 
+#include "os_object_base.h"
+
 typedef const void * CFTypeRef;
 extern CFTypeRef CFRetain(CFTypeRef cf);
 extern void CFRelease(CFTypeRef cf);
@@ -11,14 +13,6 @@ extern CFTypeRef CFCreate() CF_RETURNS_R
 
 using size_t = decltype(sizeof(int));
 
-struct OSObject {
-  virtual void retain();
-  virtual void release();
-
-  static void * operator new(size_t size);
-  virtual ~OSObject(){}
-};
-
 void cf_overrelease() {
   CFTypeRef cf = CFCreate();
   CFRelease(cf);




More information about the cfe-commits mailing list