Bug 1418854 - Race condition in AutoClose. r=honzab, a=jcristau
authorMichal Novotny <michal.novotny@gmail.com>
Wed, 06 Dec 2017 20:48:06 -0500
changeset 445300 4186bb70043e1c56d2211d83273d47d631963891
parent 445299 06039747cf8690dfb42b90574c3a8743efda6a3e
child 445301 df5c32622c0aad4a465951b0ec248138f9113a0b
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershonzab, jcristau
bugs1418854
milestone58.0
Bug 1418854 - Race condition in AutoClose. r=honzab, a=jcristau
netwerk/base/AutoClose.h
--- a/netwerk/base/AutoClose.h
+++ b/netwerk/base/AutoClose.h
@@ -3,74 +3,75 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_net_AutoClose_h
 #define mozilla_net_AutoClose_h
 
 #include "nsCOMPtr.h"
+#include "mozilla/Mutex.h"
 
 namespace mozilla { namespace net {
 
 // Like an nsAutoPtr for XPCOM streams (e.g. nsIAsyncInputStream) and other
 // refcounted classes that need to have the Close() method called explicitly
 // before they are destroyed.
 template <typename T>
 class AutoClose
 {
 public:
-  AutoClose() { }
+  AutoClose() : mMutex("net::AutoClose.mMutex") { }
   ~AutoClose(){
-    Close();
+    CloseAndRelease();
   }
 
-  explicit operator bool() const
+  explicit operator bool()
   {
+    MutexAutoLock lock(mMutex);
     return mPtr;
   }
 
   already_AddRefed<T> forget()
   {
+    MutexAutoLock lock(mMutex);
     return mPtr.forget();
   }
 
   void takeOver(nsCOMPtr<T> & rhs)
   {
-    Close();
-    mPtr = rhs.forget();
-  }
-
-  void takeOver(AutoClose<T> & rhs)
-  {
-    Close();
-    mPtr = rhs.mPtr.forget();
+    already_AddRefed<T> other = rhs.forget();
+    TakeOverInternal(&other);
   }
 
   void CloseAndRelease()
   {
-    Close();
-    mPtr = nullptr;
-  }
-
-  T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
-  {
-    return mPtr.operator->();
+    TakeOverInternal(nullptr);
   }
 
 private:
-  void Close()
+  void TakeOverInternal(already_AddRefed<T> *aOther)
   {
-    if (mPtr) {
-      mPtr->Close();
+    nsCOMPtr<T> ptr;
+    {
+      MutexAutoLock lock(mMutex);
+      ptr.swap(mPtr);
+      if (aOther) {
+        mPtr = *aOther;
+      }
+    }
+
+    if (ptr) {
+      ptr->Close();
     }
   }
 
   void operator=(const AutoClose<T> &) = delete;
   AutoClose(const AutoClose<T> &) = delete;
 
   nsCOMPtr<T> mPtr;
+  Mutex mMutex;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_AutoClose_h