Don't allow double-closing of IPC channels. (bug 1301481, r=billm)
authorDavid Anderson <danderson@mozilla.com>
Mon, 19 Sep 2016 19:17:09 -0700
changeset 314466 a706f77e10af2581704ac160d7b687c58f231570
parent 314465 ad7f61e0eed2a43712cb860a94f386edd72c18ac
child 314467 4ee6bf23101a20376d82db9a8daa13ebb2662e9e
push id20574
push usercbook@mozilla.com
push dateTue, 20 Sep 2016 10:05:16 +0000
treeherderfx-team@14705f779a46 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1301481
milestone52.0a1
Don't allow double-closing of IPC channels. (bug 1301481, r=billm)
ipc/glue/MessageChannel.cpp
ipc/glue/MessageChannel.h
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -483,16 +483,17 @@ MessageChannel::MessageChannel(MessageLi
     mDispatchingAsyncMessagePriority(0),
     mTransactionStack(nullptr),
     mTimedOutMessageSeqno(0),
     mTimedOutMessagePriority(0),
     mRemoteStackDepthGuess(false),
     mSawInterruptOutMsg(false),
     mIsWaitingForIncoming(false),
     mAbortOnError(false),
+    mNotifiedChannelDone(false),
     mFlags(REQUIRE_DEFAULT),
     mPeerPidSet(false),
     mPeerPid(-1)
 #if defined(MOZ_CRASHREPORTER) && defined(OS_WIN)
     , mPending(AnnotateAllocator<Message>(*this))
 #endif
 {
     MOZ_COUNT_CTOR(ipc::MessageChannel);
@@ -2076,16 +2077,23 @@ MessageChannel::NotifyMaybeChannelError(
         return;
     }
 
     Clear();
 
     // Oops, error!  Let the listener know about it.
     mChannelState = ChannelError;
 
+    // IPDL assumes these notifications do not fire twice, so we do not let
+    // that happen.
+    if (mNotifiedChannelDone) {
+      return;
+    }
+    mNotifiedChannelDone = true;
+
     // After this, the channel may be deleted.  Based on the premise that
     // mListener owns this channel, any calls back to this class that may
     // work with mListener should still work on living objects.
     mListener->OnChannelError();
 }
 
 void
 MessageChannel::OnNotifyMaybeChannelError()
@@ -2233,16 +2241,23 @@ MessageChannel::NotifyChannelClosed()
 {
     mMonitor->AssertNotCurrentThreadOwns();
 
     if (ChannelClosed != mChannelState)
         NS_RUNTIMEABORT("channel should have been closed!");
 
     Clear();
 
+    // IPDL assumes these notifications do not fire twice, so we do not let
+    // that happen.
+    if (mNotifiedChannelDone) {
+      return;
+    }
+    mNotifiedChannelDone = true;
+
     // OK, the IO thread just closed the channel normally.  Let the
     // listener know about it. After this point the channel may be
     // deleted.
     mListener->OnChannelClose();
 }
 
 void
 MessageChannel::DebugAbort(const char* file, int line, const char* cond,
--- a/ipc/glue/MessageChannel.h
+++ b/ipc/glue/MessageChannel.h
@@ -778,16 +778,20 @@ class MessageChannel : HasResultCodes
 #ifdef OS_WIN
     HANDLE mEvent;
 #endif
 
     // Should the channel abort the process from the I/O thread when
     // a channel error occurs?
     bool mAbortOnError;
 
+    // True if the listener has already been notified of a channel close or
+    // error.
+    bool mNotifiedChannelDone;
+
     // See SetChannelFlags
     ChannelFlags mFlags;
 
     // Task and state used to asynchronously notify channel has been connected
     // safely.  This is necessary to be able to cancel notification if we are
     // closed at the same time.
     RefPtr<RefCountedTask> mOnChannelConnectedTask;
     bool mPeerPidSet;