mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-03 02:25:34 +00:00
Bug 887029 - 'DeviceStorage: addNamed() crashes when invoked from an inline activity'. r=khuey.
This commit is contained in:
parent
b4bbf21bd8
commit
4c78215f62
184
dom/ipc/Blob.cpp
184
dom/ipc/Blob.cpp
@ -14,6 +14,7 @@
|
|||||||
#include "nsIDOMFile.h"
|
#include "nsIDOMFile.h"
|
||||||
#include "nsIInputStream.h"
|
#include "nsIInputStream.h"
|
||||||
#include "nsIIPCSerializableInputStream.h"
|
#include "nsIIPCSerializableInputStream.h"
|
||||||
|
#include "nsIMultiplexInputStream.h"
|
||||||
#include "nsIRemoteBlob.h"
|
#include "nsIRemoteBlob.h"
|
||||||
#include "nsISeekableStream.h"
|
#include "nsISeekableStream.h"
|
||||||
|
|
||||||
@ -21,6 +22,7 @@
|
|||||||
#include "mozilla/unused.h"
|
#include "mozilla/unused.h"
|
||||||
#include "mozilla/ipc/InputStreamUtils.h"
|
#include "mozilla/ipc/InputStreamUtils.h"
|
||||||
#include "nsDOMFile.h"
|
#include "nsDOMFile.h"
|
||||||
|
#include "nsProxyRelease.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
|
||||||
#include "ContentChild.h"
|
#include "ContentChild.h"
|
||||||
@ -35,6 +37,24 @@ using namespace mozilla::ipc;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure that a nsCOMPtr/nsRefPtr is released on the main thread.
|
||||||
|
*/
|
||||||
|
template <template <class> class SmartPtr, class T>
|
||||||
|
void
|
||||||
|
ProxyReleaseToMainThread(SmartPtr<T>& aDoomed)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
|
|
||||||
|
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||||
|
NS_ENSURE_TRUE_VOID(mainThread);
|
||||||
|
|
||||||
|
if (NS_FAILED(NS_ProxyRelease(mainThread, aDoomed, true))) {
|
||||||
|
NS_WARNING("Failed to proxy release to main thread!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class NS_NO_VTABLE IPrivateRemoteInputStream : public nsISupports
|
class NS_NO_VTABLE IPrivateRemoteInputStream : public nsISupports
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -48,15 +68,89 @@ public:
|
|||||||
NS_DEFINE_STATIC_IID_ACCESSOR(IPrivateRemoteInputStream,
|
NS_DEFINE_STATIC_IID_ACCESSOR(IPrivateRemoteInputStream,
|
||||||
PRIVATE_REMOTE_INPUT_STREAM_IID)
|
PRIVATE_REMOTE_INPUT_STREAM_IID)
|
||||||
|
|
||||||
|
// This class exists to keep a blob alive at least as long as its internal
|
||||||
|
// stream.
|
||||||
|
class BlobInputStreamTether : public nsIMultiplexInputStream,
|
||||||
|
public nsISeekableStream,
|
||||||
|
public nsIIPCSerializableInputStream
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIInputStream> mStream;
|
||||||
|
nsCOMPtr<nsIDOMBlob> mSourceBlob;
|
||||||
|
|
||||||
|
nsIMultiplexInputStream* mWeakMultiplexStream;
|
||||||
|
nsISeekableStream* mWeakSeekableStream;
|
||||||
|
nsIIPCSerializableInputStream* mWeakSerializableStream;
|
||||||
|
|
||||||
|
public:
|
||||||
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
NS_FORWARD_NSIINPUTSTREAM(mStream->)
|
||||||
|
NS_FORWARD_SAFE_NSIMULTIPLEXINPUTSTREAM(mWeakMultiplexStream)
|
||||||
|
NS_FORWARD_SAFE_NSISEEKABLESTREAM(mWeakSeekableStream)
|
||||||
|
NS_FORWARD_SAFE_NSIIPCSERIALIZABLEINPUTSTREAM(mWeakSerializableStream)
|
||||||
|
|
||||||
|
BlobInputStreamTether(nsIInputStream* aStream, nsIDOMBlob* aSourceBlob)
|
||||||
|
: mStream(aStream), mSourceBlob(aSourceBlob), mWeakMultiplexStream(nullptr),
|
||||||
|
mWeakSeekableStream(nullptr), mWeakSerializableStream(nullptr)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aStream);
|
||||||
|
MOZ_ASSERT(aSourceBlob);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIMultiplexInputStream> multiplexStream =
|
||||||
|
do_QueryInterface(aStream);
|
||||||
|
if (multiplexStream) {
|
||||||
|
MOZ_ASSERT(SameCOMIdentity(aStream, multiplexStream));
|
||||||
|
mWeakMultiplexStream = multiplexStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream);
|
||||||
|
if (seekableStream) {
|
||||||
|
MOZ_ASSERT(SameCOMIdentity(aStream, seekableStream));
|
||||||
|
mWeakSeekableStream = seekableStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIIPCSerializableInputStream> serializableStream =
|
||||||
|
do_QueryInterface(aStream);
|
||||||
|
if (serializableStream) {
|
||||||
|
MOZ_ASSERT(SameCOMIdentity(aStream, serializableStream));
|
||||||
|
mWeakSerializableStream = serializableStream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~BlobInputStreamTether()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mStream);
|
||||||
|
MOZ_ASSERT(mSourceBlob);
|
||||||
|
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
mStream = nullptr;
|
||||||
|
ProxyReleaseToMainThread(mSourceBlob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ADDREF(BlobInputStreamTether)
|
||||||
|
NS_IMPL_RELEASE(BlobInputStreamTether)
|
||||||
|
|
||||||
|
NS_INTERFACE_MAP_BEGIN(BlobInputStreamTether)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMultiplexInputStream,
|
||||||
|
mWeakMultiplexStream)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, mWeakSeekableStream)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
|
||||||
|
mWeakSerializableStream)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
|
||||||
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
class RemoteInputStream : public nsIInputStream,
|
class RemoteInputStream : public nsIInputStream,
|
||||||
public nsISeekableStream,
|
public nsISeekableStream,
|
||||||
public nsIIPCSerializableInputStream,
|
public nsIIPCSerializableInputStream,
|
||||||
public IPrivateRemoteInputStream
|
public IPrivateRemoteInputStream
|
||||||
{
|
{
|
||||||
mozilla::Monitor mMonitor;
|
mozilla::Monitor mMonitor;
|
||||||
nsCOMPtr<nsIDOMBlob> mSourceBlob;
|
|
||||||
nsCOMPtr<nsIInputStream> mStream;
|
nsCOMPtr<nsIInputStream> mStream;
|
||||||
nsCOMPtr<nsISeekableStream> mSeekableStream;
|
nsCOMPtr<nsIDOMBlob> mSourceBlob;
|
||||||
|
nsISeekableStream* mWeakSeekableStream;
|
||||||
ActorFlavorEnum mOrigin;
|
ActorFlavorEnum mOrigin;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -64,7 +158,7 @@ public:
|
|||||||
|
|
||||||
RemoteInputStream(nsIDOMBlob* aSourceBlob, ActorFlavorEnum aOrigin)
|
RemoteInputStream(nsIDOMBlob* aSourceBlob, ActorFlavorEnum aOrigin)
|
||||||
: mMonitor("RemoteInputStream.mMonitor"), mSourceBlob(aSourceBlob),
|
: mMonitor("RemoteInputStream.mMonitor"), mSourceBlob(aSourceBlob),
|
||||||
mOrigin(aOrigin)
|
mWeakSeekableStream(nullptr), mOrigin(aOrigin)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(aSourceBlob);
|
MOZ_ASSERT(aSourceBlob);
|
||||||
@ -102,14 +196,16 @@ public:
|
|||||||
nsCOMPtr<nsIInputStream> stream = aStream;
|
nsCOMPtr<nsIInputStream> stream = aStream;
|
||||||
nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream);
|
nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream);
|
||||||
|
|
||||||
|
MOZ_ASSERT_IF(seekableStream, SameCOMIdentity(aStream, seekableStream));
|
||||||
|
|
||||||
{
|
{
|
||||||
mozilla::MonitorAutoLock lock(mMonitor);
|
mozilla::MonitorAutoLock lock(mMonitor);
|
||||||
|
|
||||||
MOZ_ASSERT(!mStream);
|
MOZ_ASSERT(!mStream);
|
||||||
MOZ_ASSERT(!mSeekableStream);
|
MOZ_ASSERT(!mWeakSeekableStream);
|
||||||
|
|
||||||
mStream.swap(stream);
|
mStream.swap(stream);
|
||||||
mSeekableStream.swap(seekableStream);
|
mWeakSeekableStream = seekableStream;
|
||||||
|
|
||||||
mMonitor.Notify();
|
mMonitor.Notify();
|
||||||
}
|
}
|
||||||
@ -187,12 +283,12 @@ public:
|
|||||||
nsresult rv = BlockAndWaitForStream();
|
nsresult rv = BlockAndWaitForStream();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!mSeekableStream) {
|
if (!mWeakSeekableStream) {
|
||||||
NS_WARNING("Underlying blob stream is not seekable!");
|
NS_WARNING("Underlying blob stream is not seekable!");
|
||||||
return NS_ERROR_NO_INTERFACE;
|
return NS_ERROR_NO_INTERFACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = mSeekableStream->Seek(aWhence, aOffset);
|
rv = mWeakSeekableStream->Seek(aWhence, aOffset);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -212,12 +308,12 @@ public:
|
|||||||
nsresult rv = BlockAndWaitForStream();
|
nsresult rv = BlockAndWaitForStream();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!mSeekableStream) {
|
if (!mWeakSeekableStream) {
|
||||||
NS_WARNING("Underlying blob stream is not seekable!");
|
NS_WARNING("Underlying blob stream is not seekable!");
|
||||||
return NS_ERROR_NO_INTERFACE;
|
return NS_ERROR_NO_INTERFACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = mSeekableStream->Tell(aResult);
|
rv = mWeakSeekableStream->Tell(aResult);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -229,12 +325,12 @@ public:
|
|||||||
nsresult rv = BlockAndWaitForStream();
|
nsresult rv = BlockAndWaitForStream();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!mSeekableStream) {
|
if (!mWeakSeekableStream) {
|
||||||
NS_WARNING("Underlying blob stream is not seekable!");
|
NS_WARNING("Underlying blob stream is not seekable!");
|
||||||
return NS_ERROR_NO_INTERFACE;
|
return NS_ERROR_NO_INTERFACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = mSeekableStream->SetEOF();
|
rv = mWeakSeekableStream->SetEOF();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -253,7 +349,13 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
virtual ~RemoteInputStream()
|
virtual ~RemoteInputStream()
|
||||||
{ }
|
{
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
mStream = nullptr;
|
||||||
|
mWeakSeekableStream = nullptr;
|
||||||
|
ProxyReleaseToMainThread(mSourceBlob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ReallyBlockAndWaitForStream()
|
ReallyBlockAndWaitForStream()
|
||||||
@ -273,9 +375,9 @@ private:
|
|||||||
MOZ_ASSERT(mStream);
|
MOZ_ASSERT(mStream);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (waited && mSeekableStream) {
|
if (waited && mWeakSeekableStream) {
|
||||||
int64_t position;
|
int64_t position;
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(mSeekableStream->Tell(&position)),
|
MOZ_ASSERT(NS_SUCCEEDED(mWeakSeekableStream->Tell(&position)),
|
||||||
"Failed to determine initial stream position!");
|
"Failed to determine initial stream position!");
|
||||||
MOZ_ASSERT(!position, "Stream not starting at 0!");
|
MOZ_ASSERT(!position, "Stream not starting at 0!");
|
||||||
}
|
}
|
||||||
@ -308,7 +410,7 @@ private:
|
|||||||
ReallyBlockAndWaitForStream();
|
ReallyBlockAndWaitForStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!mSeekableStream;
|
return !!mWeakSeekableStream;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -655,6 +757,24 @@ public:
|
|||||||
private:
|
private:
|
||||||
ActorType* mActor;
|
ActorType* mActor;
|
||||||
|
|
||||||
|
virtual ~RemoteBlob()
|
||||||
|
{
|
||||||
|
if (mActor) {
|
||||||
|
mActor->NoteDyingRemoteBlob();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
GetInternalStreamViaHelper(nsIInputStream** aStream)
|
||||||
|
{
|
||||||
|
if (!mActor) {
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
|
||||||
|
return helper->GetStream(aStream);
|
||||||
|
}
|
||||||
|
|
||||||
class StreamHelper : public nsRunnable
|
class StreamHelper : public nsRunnable
|
||||||
{
|
{
|
||||||
typedef Blob<ActorFlavor> ActorType;
|
typedef Blob<ActorFlavor> ActorType;
|
||||||
@ -893,13 +1013,6 @@ public:
|
|||||||
mImmutable = true;
|
mImmutable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~RemoteBlob()
|
|
||||||
{
|
|
||||||
if (mActor) {
|
|
||||||
mActor->NoteDyingRemoteBlob();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SetActor(ActorType* aActor)
|
SetActor(ActorType* aActor)
|
||||||
{
|
{
|
||||||
@ -938,7 +1051,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHOD
|
NS_IMETHOD
|
||||||
GetLastModifiedDate(JSContext* cx, JS::Value* aLastModifiedDate)
|
GetLastModifiedDate(JSContext* cx, JS::Value* aLastModifiedDate) MOZ_OVERRIDE
|
||||||
{
|
{
|
||||||
if (IsDateUnknown()) {
|
if (IsDateUnknown()) {
|
||||||
aLastModifiedDate->setNull();
|
aLastModifiedDate->setNull();
|
||||||
@ -980,34 +1093,27 @@ NS_IMETHODIMP
|
|||||||
RemoteBlob<Parent>::GetInternalStream(nsIInputStream** aStream)
|
RemoteBlob<Parent>::GetInternalStream(nsIInputStream** aStream)
|
||||||
{
|
{
|
||||||
if (mInputStreamParams.type() != InputStreamParams::T__None) {
|
if (mInputStreamParams.type() != InputStreamParams::T__None) {
|
||||||
nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(mInputStreamParams);
|
nsCOMPtr<nsIInputStream> realStream =
|
||||||
if (!stream) {
|
DeserializeInputStream(mInputStreamParams);
|
||||||
|
if (!realStream) {
|
||||||
NS_WARNING("Failed to deserialize stream!");
|
NS_WARNING("Failed to deserialize stream!");
|
||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIInputStream> stream =
|
||||||
|
new BlobInputStreamTether(realStream, this);
|
||||||
stream.forget(aStream);
|
stream.forget(aStream);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mActor) {
|
return GetInternalStreamViaHelper(aStream);
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
|
|
||||||
return helper->GetStream(aStream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
RemoteBlob<Child>::GetInternalStream(nsIInputStream** aStream)
|
RemoteBlob<Child>::GetInternalStream(nsIInputStream** aStream)
|
||||||
{
|
{
|
||||||
if (!mActor) {
|
return GetInternalStreamViaHelper(aStream);
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
|
|
||||||
return helper->GetStream(aStream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <ActorFlavorEnum ActorFlavor>
|
template <ActorFlavorEnum ActorFlavor>
|
||||||
@ -1226,6 +1332,7 @@ Blob<ActorFlavor>::NoteDyingRemoteBlob()
|
|||||||
|
|
||||||
// Must do this before calling Send__delete__ or we'll crash there trying to
|
// Must do this before calling Send__delete__ or we'll crash there trying to
|
||||||
// access a dangling pointer.
|
// access a dangling pointer.
|
||||||
|
mBlob = nullptr;
|
||||||
mRemoteBlob = nullptr;
|
mRemoteBlob = nullptr;
|
||||||
|
|
||||||
mozilla::unused << ProtocolType::Send__delete__(this);
|
mozilla::unused << ProtocolType::Send__delete__(this);
|
||||||
@ -1236,13 +1343,12 @@ void
|
|||||||
Blob<ActorFlavor>::ActorDestroy(ActorDestroyReason aWhy)
|
Blob<ActorFlavor>::ActorDestroy(ActorDestroyReason aWhy)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(mBlob);
|
|
||||||
|
|
||||||
if (mRemoteBlob) {
|
if (mRemoteBlob) {
|
||||||
mRemoteBlob->SetActor(nullptr);
|
mRemoteBlob->SetActor(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mOwnsBlob) {
|
if (mBlob && mOwnsBlob) {
|
||||||
mBlob->Release();
|
mBlob->Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user