forked from mirrors/gecko-dev
This patch prevents the following error: AltDataOutputStreamChild::Close -> SendClose() AltDataOutputStreamChild::Release -> Send__delete__() AltDataOutputStreamParent::RecvClose() -> SendError() AltDataOutputStreamParent::ActorDestroy -> mIPCOpen = false AltDataOutputStreamChild::RecvError -> === Crash - object was deleted === We introduce the DeleteSelf message. AltDataOutputStreamChild::Release -> SendDeleteSelf() AltDataOutputStreamParent::RecvDeleteSelf -> mIPCOpen = false; SendDeleteSelf() AltDataOutputStreamChild::RecvDeleteSelf -> Send__delete__() The parent will not send any more messages after receiving the DeleteSelf message. MozReview-Commit-ID: I9RQ5I7eSt9 --HG-- extra : rebase_source : 8f918d24595248149ebd3857e05e38dc5237059b
158 lines
3.4 KiB
C++
158 lines
3.4 KiB
C++
#include "mozilla/net/AltDataOutputStreamChild.h"
|
|
#include "mozilla/Unused.h"
|
|
#include "nsIInputStream.h"
|
|
|
|
namespace mozilla {
|
|
namespace net {
|
|
|
|
NS_IMPL_ADDREF(AltDataOutputStreamChild)
|
|
|
|
NS_IMETHODIMP_(MozExternalRefCountType) AltDataOutputStreamChild::Release()
|
|
{
|
|
NS_PRECONDITION(0 != mRefCnt, "dup release");
|
|
MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
|
|
--mRefCnt;
|
|
NS_LOG_RELEASE(this, mRefCnt, "AltDataOutputStreamChild");
|
|
|
|
if (mRefCnt == 1 && mIPCOpen) {
|
|
// The only reference left is the IPDL one. After the parent replies back
|
|
// with a DeleteSelf message, the child will call Send__delete__(this),
|
|
// decrementing the ref count and triggering the destructor.
|
|
SendDeleteSelf();
|
|
return 1;
|
|
}
|
|
|
|
if (mRefCnt == 0) {
|
|
mRefCnt = 1; /* stabilize */
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return mRefCnt;
|
|
}
|
|
|
|
NS_INTERFACE_MAP_BEGIN(AltDataOutputStreamChild)
|
|
NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
AltDataOutputStreamChild::AltDataOutputStreamChild()
|
|
: mIPCOpen(false)
|
|
, mError(NS_OK)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
|
|
}
|
|
|
|
AltDataOutputStreamChild::~AltDataOutputStreamChild()
|
|
{
|
|
}
|
|
|
|
void
|
|
AltDataOutputStreamChild::AddIPDLReference()
|
|
{
|
|
MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference");
|
|
mIPCOpen = true;
|
|
AddRef();
|
|
}
|
|
|
|
void
|
|
AltDataOutputStreamChild::ReleaseIPDLReference()
|
|
{
|
|
MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference");
|
|
mIPCOpen = false;
|
|
Release();
|
|
}
|
|
|
|
bool
|
|
AltDataOutputStreamChild::WriteDataInChunks(const nsCString& data)
|
|
{
|
|
const uint32_t kChunkSize = 128*1024;
|
|
uint32_t next = std::min(data.Length(), kChunkSize);
|
|
for (uint32_t i = 0; i < data.Length();
|
|
i = next, next = std::min(data.Length(), next + kChunkSize)) {
|
|
nsCString chunk(Substring(data, i, kChunkSize));
|
|
if (mIPCOpen && !SendWriteData(chunk)) {
|
|
mIPCOpen = false;
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
AltDataOutputStreamChild::Close()
|
|
{
|
|
if (!mIPCOpen) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
if (NS_FAILED(mError)) {
|
|
return mError;
|
|
}
|
|
Unused << SendClose();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
AltDataOutputStreamChild::Flush()
|
|
{
|
|
if (!mIPCOpen) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
if (NS_FAILED(mError)) {
|
|
return mError;
|
|
}
|
|
|
|
// This is a no-op
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
AltDataOutputStreamChild::Write(const char * aBuf, uint32_t aCount, uint32_t *_retval)
|
|
{
|
|
if (!mIPCOpen) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
if (NS_FAILED(mError)) {
|
|
return mError;
|
|
}
|
|
if (WriteDataInChunks(nsCString(aBuf, aCount))) {
|
|
*_retval = aCount;
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
AltDataOutputStreamChild::WriteFrom(nsIInputStream *aFromStream, uint32_t aCount, uint32_t *_retval)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
AltDataOutputStreamChild::WriteSegments(nsReadSegmentFun aReader, void *aClosure, uint32_t aCount, uint32_t *_retval)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
AltDataOutputStreamChild::IsNonBlocking(bool *_retval)
|
|
{
|
|
*_retval = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
AltDataOutputStreamChild::RecvError(const nsresult& err)
|
|
{
|
|
mError = err;
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
AltDataOutputStreamChild::RecvDeleteSelf()
|
|
{
|
|
PAltDataOutputStreamChild::Send__delete__(this);
|
|
return IPC_OK();
|
|
}
|
|
|
|
} // namespace net
|
|
} // namespace mozilla
|