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.
This commit is contained in:
Thomas Zimmermann 2013-01-16 10:21:49 +08:00
parent 079048695a
commit dfe0efbdcd

View File

@ -253,12 +253,24 @@ private:
};
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
{
@ -612,9 +624,18 @@ UnixSocketConsumer::CloseSocket()
// 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();
}