Bug 830704: Delete UnixSocketImpl instance after SocketReceiveTasks completed [r=qdot]
authorThomas Zimmermann <tdz@users.sourceforge.net>
Wed, 16 Jan 2013 10:21:49 +0800
changeset 118985 57bf5244f06c2806e6f29f89bce93fb329d12ab7
parent 118984 6937f97320301a4affd2858f5e50ca2b93850709
child 118986 5087e184f8ad559a800622b7291569975cded66d
push id21398
push userechou@mozilla.com
push dateWed, 16 Jan 2013 02:22:28 +0000
treeherdermozilla-inbound@57bf5244f06c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersqdot
bugs830704
milestone21.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 830704: Delete UnixSocketImpl instance after SocketReceiveTasks completed [r=qdot] The Bluetooth system internally uses UnixSocketImpl when transfering files. When Bluetooth gets disabled during a file transfer, the IPC code deletes any related instance of UnixSocketImpl. This can happen before all pending SocketReceiveTasks have been processed by the main thread. The implementation of SocketReceiveTask uses a reference to the instance of UnixSocketImpl that has just deen disabled. This results in a segmantation fault. This patch fixes the problem by scheduling the delete operation for UnixSocketImpl to be executed after any pending SocketReceiveTasks.
ipc/unixsocket/UnixSocket.cpp
--- a/ipc/unixsocket/UnixSocket.cpp
+++ b/ipc/unixsocket/UnixSocket.cpp
@@ -248,22 +248,34 @@ private:
 
   /**
    * Address struct of the socket currently in use
    */
   sockaddr mAddr;
 
 };
 
-static void
-DestroyImpl(UnixSocketImpl* impl)
+template<class T>
+class DeleteInstanceRunnable : public nsRunnable
 {
-  MOZ_ASSERT(impl);
-  delete impl;
-}
+public:
+  DeleteInstanceRunnable(T* aInstance)
+  : mInstance(aInstance)
+  { }
+
+  NS_IMETHOD Run()
+  {
+    delete mInstance;
+
+    return NS_OK;
+  }
+
+private:
+  T* mInstance;
+};
 
 class OnSocketEventTask : public nsRunnable
 {
 public:
   enum SocketEvent {
     CONNECT_SUCCESS,
     CONNECT_ERROR,
     DISCONNECT
@@ -607,19 +619,28 @@ UnixSocketConsumer::CloseSocket()
     return;
   }
   UnixSocketImpl* impl = mImpl;
   // To make sure the owner doesn't die on the IOThread, remove pointer here
   mImpl = nullptr;
   // Line it up to be destructed on the IO Thread
   impl->mConsumer.forget();
   impl->StopTask();
-  XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
-                                   NewRunnableFunction(DestroyImpl,
-                                                       impl));
+
+  // The receiver task should have been stopped at this point, but
+  // SocketReceiverTask runnables might still be pending the main
+  // thread. We enqueue the DeleteInstanceRunnable _after_ any pending
+  // SocketReceiverTask. Otherwise we might free 'impl' before those
+  // runnables have been executed.
+  nsRefPtr<nsIRunnable> t(new DeleteInstanceRunnable<UnixSocketImpl>(impl));
+  NS_ENSURE_TRUE_VOID(t);
+  nsresult rv = NS_DispatchToMainThread(t);
+  NS_ENSURE_SUCCESS_VOID(rv);
+  t.forget();
+
   NotifyDisconnect();
 }
 
 void
 UnixSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
 {
   // Keep reading data until either
   //