gecko-dev/ipc/mscom/COMPtrHolder.h

219 строки
6.0 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_mscom_COMPtrHolder_h
#define mozilla_mscom_COMPtrHolder_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Move.h"
#include "mozilla/mscom/ProxyStream.h"
#include "mozilla/mscom/Ptr.h"
#if defined(MOZ_CONTENT_SANDBOX)
#include "mozilla/SandboxSettings.h"
#endif // defined(MOZ_CONTENT_SANDBOX)
#if defined(MOZ_CRASHREPORTER)
#include "nsExceptionHandler.h"
#endif // defined(MOZ_CRASHREPORTER)
namespace mozilla {
namespace mscom {
template<typename Interface, const IID& _IID>
class COMPtrHolder
{
public:
typedef ProxyUniquePtr<Interface> COMPtrType;
typedef COMPtrHolder<Interface, _IID> ThisType;
COMPtrHolder() {}
MOZ_IMPLICIT COMPtrHolder(decltype(nullptr))
{
}
explicit COMPtrHolder(COMPtrType&& aPtr)
: mPtr(Forward<COMPtrType>(aPtr))
{
}
Interface* Get() const
{
return mPtr.get();
}
MOZ_MUST_USE Interface* Release()
{
return mPtr.release();
}
void Set(COMPtrType&& aPtr)
{
mPtr = Forward<COMPtrType>(aPtr);
}
#if defined(MOZ_CONTENT_SANDBOX)
// This method is const because we need to call it during IPC write, where
// we are passed as a const argument. At higher sandboxing levels we need to
// save this artifact from the serialization process for later deletion.
void PreserveStream(PreservedStreamPtr aPtr) const
{
MOZ_ASSERT(!mMarshaledStream);
mMarshaledStream = Move(aPtr);
}
PreservedStreamPtr GetPreservedStream()
{
return Move(mMarshaledStream);
}
#endif // defined(MOZ_CONTENT_SANDBOX)
COMPtrHolder(const COMPtrHolder& aOther) = delete;
COMPtrHolder(COMPtrHolder&& aOther)
: mPtr(Move(aOther.mPtr))
#if defined(MOZ_CONTENT_SANDBOX)
, mMarshaledStream(Move(aOther.mMarshaledStream))
#endif // defined(MOZ_CONTENT_SANDBOX)
{
}
// COMPtrHolder is eventually added as a member of a struct that is declared
// in IPDL. The generated C++ code for that IPDL struct includes copy
// constructors and assignment operators that assume that all members are
// copyable. I don't think that those copy constructors and operator= are
// actually used by any generated code, but they are made available. Since no
// move semantics are available, this terrible hack makes COMPtrHolder build
// when used as a member of an IPDL struct.
ThisType& operator=(const ThisType& aOther)
{
Set(Move(aOther.mPtr));
#if defined(MOZ_CONTENT_SANDBOX)
mMarshaledStream = Move(aOther.mMarshaledStream);
#endif // defined(MOZ_CONTENT_SANDBOX)
return *this;
}
ThisType& operator=(ThisType&& aOther)
{
Set(Move(aOther.mPtr));
#if defined(MOZ_CONTENT_SANDBOX)
mMarshaledStream = Move(aOther.mMarshaledStream);
#endif // defined(MOZ_CONTENT_SANDBOX)
return *this;
}
bool operator==(const ThisType& aOther) const
{
return mPtr == aOther.mPtr;
}
bool IsNull() const
{
return !mPtr;
}
private:
// This is mutable to facilitate the above operator= hack
mutable COMPtrType mPtr;
#if defined(MOZ_CONTENT_SANDBOX)
// This is mutable so that we may optionally store a reference to a marshaled
// stream to be cleaned up later via PreserveStream().
mutable PreservedStreamPtr mMarshaledStream;
#endif // defined(MOZ_CONTENT_SANDBOX)
};
} // namespace mscom
} // namespace mozilla
namespace IPC {
template<typename Interface, const IID& _IID>
struct ParamTraits<mozilla::mscom::COMPtrHolder<Interface, _IID>>
{
typedef mozilla::mscom::COMPtrHolder<Interface, _IID> paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
#if defined(MOZ_CONTENT_SANDBOX)
static const bool sIsStreamPreservationNeeded =
XRE_IsParentProcess() && mozilla::GetEffectiveContentSandboxLevel() >= 3;
#else
const bool sIsStreamPreservationNeeded = false;
#endif // defined(MOZ_CONTENT_SANDBOX)
mozilla::mscom::ProxyStreamFlags flags = sIsStreamPreservationNeeded ?
mozilla::mscom::ProxyStreamFlags::ePreservable :
mozilla::mscom::ProxyStreamFlags::eDefault;
mozilla::mscom::ProxyStream proxyStream(_IID, aParam.Get(), flags);
int bufLen;
const BYTE* buf = proxyStream.GetBuffer(bufLen);
MOZ_ASSERT(buf || !bufLen);
aMsg->WriteInt(bufLen);
if (bufLen) {
aMsg->WriteBytes(reinterpret_cast<const char*>(buf), bufLen);
}
#if defined(MOZ_CONTENT_SANDBOX)
if (sIsStreamPreservationNeeded) {
/**
* When we're sending a ProxyStream from parent to content and the
* content sandboxing level is >= 3, content is unable to communicate
* its releasing of its reference to the proxied object. We preserve the
* marshaled proxy data here and later manually release it on content's
* behalf.
*/
aParam.PreserveStream(proxyStream.GetPreservedStream());
}
#endif // defined(MOZ_CONTENT_SANDBOX)
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
int length;
if (!aMsg->ReadLength(aIter, &length)) {
return false;
}
mozilla::UniquePtr<BYTE[]> buf;
if (length) {
buf = mozilla::MakeUnique<BYTE[]>(length);
if (!aMsg->ReadBytesInto(aIter, buf.get(), length)) {
return false;
}
}
mozilla::mscom::ProxyStream proxyStream(_IID, buf.get(), length);
if (!proxyStream.IsValid()) {
#if defined(MOZ_CRASHREPORTER)
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProxyStreamValid"),
NS_LITERAL_CSTRING("false"));
#endif // defined(MOZ_CRASHREPORTER)
return false;
}
typename paramType::COMPtrType ptr;
if (!proxyStream.GetInterface(mozilla::mscom::getter_AddRefs(ptr))) {
return false;
}
aResult->Set(mozilla::Move(ptr));
return true;
}
};
} // namespace IPC
#endif // mozilla_mscom_COMPtrHolder_h