Bug 1394724. P2 - mListener->Revoke() should happen after mChannel->Cancel() to avoid data race. draft
authorJW Wang <jwwang@mozilla.com>
Tue, 29 Aug 2017 15:55:20 +0800
changeset 656337 cb67004d0d50446104aa33819339693366d08c4c
parent 655572 b2d670ce416e2ed72db290d31269de2483205262
child 656338 6fe18257507f2f939fa24d03e69e1120ae1c0edb
push id77176
push userjwwang@mozilla.com
push dateThu, 31 Aug 2017 02:42:53 +0000
bugs1394724
milestone57.0a1
Bug 1394724. P2 - mListener->Revoke() should happen after mChannel->Cancel() to avoid data race. http://searchfox.org/mozilla-central/rev/cd82cacec2cf734768827ff85ba2dba90a534c5e/netwerk/base/nsIRequest.idl#56 All OnDataAvailable() calls should happen before Cancel(). It is safe to modify mResource after a call to Cancel(). MozReview-Commit-ID: KoeLth1zlZM
dom/media/MediaResource.cpp
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -147,18 +147,18 @@ ChannelMediaResource::Listener::OnStopRe
 
 nsresult
 ChannelMediaResource::Listener::OnDataAvailable(nsIRequest* aRequest,
                                                 nsISupports* aContext,
                                                 nsIInputStream* aStream,
                                                 uint64_t aOffset,
                                                 uint32_t aCount)
 {
-  if (!mResource)
-    return NS_OK;
+  // This might happen off the main thread.
+  MOZ_DIAGNOSTIC_ASSERT(mResource);
   return mResource->OnDataAvailable(aRequest, aStream, aCount);
 }
 
 nsresult
 ChannelMediaResource::Listener::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
                                                        nsIChannel* aNewChannel,
                                                        uint32_t aFlags,
                                                        nsIAsyncVerifyRedirectCallback* cb)
@@ -676,33 +676,33 @@ void ChannelMediaResource::CloseChannel(
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   {
     MutexAutoLock lock(mLock);
     mChannelStatistics.Stop();
   }
 
-  if (mListener) {
-    mListener->Revoke();
-    mListener = nullptr;
-  }
-
   if (mChannel) {
     mSuspendAgent.NotifyChannelClosing();
     // The status we use here won't be passed to the decoder, since
     // we've already revoked the listener. It can however be passed
     // to nsDocumentViewer::LoadComplete if our channel is the one
     // that kicked off creation of a video document. We don't want that
     // document load to think there was an error.
     // NS_ERROR_PARSED_DATA_CACHED is the best thing we have for that
     // at the moment.
     mChannel->Cancel(NS_ERROR_PARSED_DATA_CACHED);
     mChannel = nullptr;
   }
+
+  if (mListener) {
+    mListener->Revoke();
+    mListener = nullptr;
+  }
 }
 
 nsresult ChannelMediaResource::ReadFromCache(char* aBuffer,
                                              int64_t aOffset,
                                              uint32_t aCount)
 {
   return mCacheStream.ReadFromCache(aBuffer, aOffset, aCount);
 }