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 314465 a706f77e10af2581704ac160d7b687c58f231570
parent 314464 ad7f61e0eed2a43712cb860a94f386edd72c18ac
child 314466 4ee6bf23101a20376d82db9a8daa13ebb2662e9e
push id30729
push usercbook@mozilla.com
push dateTue, 20 Sep 2016 10:01:39 +0000
treeherdermozilla-central@62f79d676e0e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1301481
milestone52.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
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;