Bug 1369354 - Avoid deadlock in IPCBlobInputStreamStorage::GetStream when IPCBlobInputStreamChild actor is used on the parent process, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 02 Jun 2017 11:05:27 +0200
changeset 410122 7ba5835bb00f43d5ef2e9c31d38b23a9094f5fdc
parent 410121 34b63eb52b4d4ee331ddb3f91f3feb06adfea5c2
child 410123 027f5f5b7221b39f5dbca2c2ca43c9e58587d301
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1369354
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1369354 - Avoid deadlock in IPCBlobInputStreamStorage::GetStream when IPCBlobInputStreamChild actor is used on the parent process, r=smaug
dom/file/ipc/IPCBlobInputStreamStorage.cpp
--- a/dom/file/ipc/IPCBlobInputStreamStorage.cpp
+++ b/dom/file/ipc/IPCBlobInputStreamStorage.cpp
@@ -117,37 +117,56 @@ IPCBlobInputStreamStorage::ForgetStream(
   mozilla::StaticMutexAutoLock lock(gMutex);
   mStorage.Remove(aID);
 }
 
 void
 IPCBlobInputStreamStorage::GetStream(const nsID& aID,
                                      nsIInputStream** aInputStream)
 {
-  mozilla::StaticMutexAutoLock lock(gMutex);
-  StreamData* data = mStorage.Get(aID);
-  if (!data) {
-    *aInputStream = nullptr;
-    return;
+  *aInputStream = nullptr;
+
+  nsCOMPtr<nsIInputStream> inputStream;
+
+  // NS_CloneInputStream cannot be called when the mutex is locked because it
+  // can, recursively call GetStream() in case the child actor lives on the
+  // parent process.
+  {
+    mozilla::StaticMutexAutoLock lock(gMutex);
+    StreamData* data = mStorage.Get(aID);
+    if (!data) {
+      return;
+    }
+
+    inputStream = data->mInputStream;
   }
 
+  MOZ_ASSERT(inputStream);
+
   // We cannot return always the same inputStream because not all of them are
   // able to be reused. Better to clone them.
 
   nsCOMPtr<nsIInputStream> clonedStream;
   nsCOMPtr<nsIInputStream> replacementStream;
 
   nsresult rv =
-    NS_CloneInputStream(data->mInputStream, getter_AddRefs(clonedStream),
+    NS_CloneInputStream(inputStream, getter_AddRefs(clonedStream),
                         getter_AddRefs(replacementStream));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   if (replacementStream) {
+    mozilla::StaticMutexAutoLock lock(gMutex);
+    StreamData* data = mStorage.Get(aID);
+    // data can be gone in the meantime.
+    if (!data) {
+      return;
+    }
+
     data->mInputStream = replacementStream;
   }
 
   clonedStream.forget(aInputStream);
 }
 
 void
 IPCBlobInputStreamStorage::StoreCallback(const nsID& aID,