DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (c221a75fbf29)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
/* -*- 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_SANDBOX)
#  include "mozilla/SandboxSettings.h"
#endif  // defined(MOZ_SANDBOX)
#include "nsExceptionHandler.h"

namespace mozilla {
namespace mscom {

template <typename Interface, const IID& _IID>
class COMPtrHolder {
 public:
  typedef ProxyUniquePtr<Interface> COMPtrType;
  typedef COMPtrHolder<Interface, _IID> ThisType;
  typedef typename detail::EnvironmentSelector<Interface>::Type EnvType;

  COMPtrHolder() {}

  MOZ_IMPLICIT COMPtrHolder(decltype(nullptr)) {}

  explicit COMPtrHolder(COMPtrType&& aPtr)
      : mPtr(std::forward<COMPtrType>(aPtr)) {}

  COMPtrHolder(COMPtrType&& aPtr, const ActivationContext& aActCtx)
      : mPtr(std::forward<COMPtrType>(aPtr)), mActCtx(aActCtx) {}

  Interface* Get() const { return mPtr.get(); }

  MOZ_MUST_USE Interface* Release() { return mPtr.release(); }

  void Set(COMPtrType&& aPtr) { mPtr = std::forward<COMPtrType>(aPtr); }

  void SetActCtx(const ActivationContext& aActCtx) { mActCtx = aActCtx; }

#if defined(MOZ_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 = std::move(aPtr);
  }

  PreservedStreamPtr GetPreservedStream() {
    return std::move(mMarshaledStream);
  }
#endif  // defined(MOZ_SANDBOX)

  COMPtrHolder(const COMPtrHolder& aOther) = delete;

  COMPtrHolder(COMPtrHolder&& aOther)
      : mPtr(std::move(aOther.mPtr))
#if defined(MOZ_SANDBOX)
        ,
        mMarshaledStream(std::move(aOther.mMarshaledStream))
#endif  // defined(MOZ_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(std::move(aOther.mPtr));

#if defined(MOZ_SANDBOX)
    mMarshaledStream = std::move(aOther.mMarshaledStream);
#endif  // defined(MOZ_SANDBOX)

    return *this;
  }

  ThisType& operator=(ThisType&& aOther) {
    Set(std::move(aOther.mPtr));

#if defined(MOZ_SANDBOX)
    mMarshaledStream = std::move(aOther.mMarshaledStream);
#endif  // defined(MOZ_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;
  ActivationContext mActCtx;

#if defined(MOZ_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_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_SANDBOX)
    static const bool sIsStreamPreservationNeeded =
        XRE_IsParentProcess() &&
        mozilla::GetEffectiveContentSandboxLevel() >= 3;
#else
    const bool sIsStreamPreservationNeeded = false;
#endif  // defined(MOZ_SANDBOX)

    typename paramType::EnvType env;

    mozilla::mscom::ProxyStreamFlags flags =
        sIsStreamPreservationNeeded
            ? mozilla::mscom::ProxyStreamFlags::ePreservable
            : mozilla::mscom::ProxyStreamFlags::eDefault;

    mozilla::mscom::ProxyStream proxyStream(_IID, aParam.Get(), &env, 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_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_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;
      }
    }

    typename paramType::EnvType env;

    mozilla::mscom::ProxyStream proxyStream(_IID, buf.get(), length, &env);
    if (!proxyStream.IsValid()) {
      CrashReporter::AnnotateCrashReport(
          CrashReporter::Annotation::ProxyStreamValid,
          NS_LITERAL_CSTRING("false"));
      return false;
    }

    typename paramType::COMPtrType ptr;
    if (!proxyStream.GetInterface(mozilla::mscom::getter_AddRefs(ptr))) {
      return false;
    }

    aResult->Set(std::move(ptr));
    return true;
  }
};

}  // namespace IPC

#endif  // mozilla_mscom_COMPtrHolder_h