tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ProtocolUtils.h (31222B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_ipc_ProtocolUtils_h
      8 #define mozilla_ipc_ProtocolUtils_h
      9 
     10 #include <cstddef>
     11 #include <cstdint>
     12 #include <utility>
     13 #include "IPCMessageStart.h"
     14 #include "base/basictypes.h"
     15 #include "base/process.h"
     16 #include "chrome/common/ipc_message.h"
     17 #include "mojo/core/ports/port_ref.h"
     18 #include "mozilla/AlreadyAddRefed.h"
     19 #include "mozilla/Assertions.h"
     20 #include "mozilla/Attributes.h"
     21 #include "mozilla/FunctionRef.h"
     22 #include "mozilla/MoveOnlyFunction.h"
     23 #include "mozilla/Mutex.h"
     24 #include "mozilla/RefPtr.h"
     25 #include "mozilla/UniquePtr.h"
     26 #include "mozilla/ipc/MessageChannel.h"
     27 #include "mozilla/ipc/MessageLink.h"
     28 #include "mozilla/ipc/Shmem.h"
     29 #include "nsPrintfCString.h"
     30 #include "nsTHashMap.h"
     31 #include "nsDebug.h"
     32 #include "nsISupports.h"
     33 #include "nsTArrayForwardDeclare.h"
     34 #include "nsTHashSet.h"
     35 
     36 // XXX Things that could be moved to ProtocolUtils.cpp
     37 #include "base/process_util.h"  // for CloseProcessHandle
     38 #include "prenv.h"              // for PR_GetEnv
     39 
     40 #if defined(ANDROID) && defined(DEBUG)
     41 #  include <android/log.h>
     42 #endif
     43 
     44 template <typename T>
     45 class nsPtrHashKey;
     46 
     47 // WARNING: this takes into account the private, special-message-type
     48 // enum in ipc_channel.h.  They need to be kept in sync.
     49 namespace {
     50 // XXX the max message ID is actually kuint32max now ... when this
     51 // changed, the assumptions of the special message IDs changed in that
     52 // they're not carving out messages from likely-unallocated space, but
     53 // rather carving out messages from the end of space allocated to
     54 // protocol 0.  Oops!  We can get away with this until protocol 0
     55 // starts approaching its 65,536th message.
     56 enum {
     57  // Message types used by DataPipe
     58  DATA_PIPE_CLOSED_MESSAGE_TYPE = kuint16max - 18,
     59  DATA_PIPE_BYTES_CONSUMED_MESSAGE_TYPE = kuint16max - 17,
     60 
     61  // Message types used by NodeChannel
     62  ACCEPT_INVITE_MESSAGE_TYPE = kuint16max - 16,
     63  REQUEST_INTRODUCTION_MESSAGE_TYPE = kuint16max - 15,
     64  INTRODUCE_MESSAGE_TYPE = kuint16max - 14,
     65  BROADCAST_MESSAGE_TYPE = kuint16max - 13,
     66  EVENT_MESSAGE_TYPE = kuint16max - 12,
     67 
     68  // Message types used by MessageChannel
     69  MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE = kuint16max - 11,
     70  MANAGED_ENDPOINT_BOUND_MESSAGE_TYPE = kuint16max - 10,
     71  IMPENDING_SHUTDOWN_MESSAGE_TYPE = kuint16max - 9,
     72  BUILD_IDS_MATCH_MESSAGE_TYPE = kuint16max - 8,
     73  BUILD_ID_MESSAGE_TYPE = kuint16max - 7,  // unused
     74  CHANNEL_OPENED_MESSAGE_TYPE = kuint16max - 6,
     75  SHMEM_DESTROYED_MESSAGE_TYPE = kuint16max - 5,
     76  SHMEM_CREATED_MESSAGE_TYPE = kuint16max - 4,
     77  GOODBYE_MESSAGE_TYPE = kuint16max - 3,
     78  CANCEL_MESSAGE_TYPE = kuint16max - 2,
     79 
     80  // kuint16max - 1 is used by ipc_channel.h.
     81 };
     82 
     83 }  // namespace
     84 
     85 class MessageLoop;
     86 class PickleIterator;
     87 class nsISerialEventTarget;
     88 
     89 namespace mozilla {
     90 class SchedulerGroup;
     91 class UntypedManagedContainer;
     92 
     93 namespace dom {
     94 class ContentParent;
     95 }  // namespace dom
     96 
     97 namespace net {
     98 class NeckoParent;
     99 }  // namespace net
    100 
    101 namespace ipc {
    102 
    103 class ProtocolFdMapping;
    104 class ProtocolCloneContext;
    105 
    106 // Helper type used to specify process info when constructing endpoints for
    107 // [NeedsOtherPid] toplevel actors.
    108 struct EndpointProcInfo {
    109  base::ProcessId mPid = base::kInvalidProcessId;
    110  GeckoChildID mChildID = kInvalidGeckoChildID;
    111 
    112  bool operator==(const EndpointProcInfo& aOther) const {
    113    return mPid == aOther.mPid && mChildID == aOther.mChildID;
    114  }
    115  bool operator!=(const EndpointProcInfo& aOther) const {
    116    return !operator==(aOther);
    117  }
    118 
    119  static EndpointProcInfo Invalid() { return {}; }
    120  static EndpointProcInfo Current();
    121 };
    122 
    123 // Used to pass references to protocol actors across the wire.
    124 // Actors created on the parent-side have a positive ID, and actors
    125 // allocated on the child side have a negative ID.
    126 using ActorId = IPC::Message::routeid_t;
    127 
    128 enum class LinkStatus : uint8_t {
    129  // The actor has not established a link yet, or the actor is no longer in use
    130  // by IPC, and its 'Dealloc' method has been called or is being called.
    131  //
    132  // NOTE: This state is used instead of an explicit `Freed` state when IPC no
    133  // longer holds references to the current actor as we currently re-open
    134  // existing actors. Once we fix these poorly behaved actors, this loopback
    135  // state can be split to have the final state not be the same as the initial
    136  // state.
    137  Inactive,
    138 
    139  // A live link is connected to the other side of this actor.
    140  Connected,
    141 
    142  // The link has begun being destroyed. Messages may no longer be sent. The
    143  // ActorDestroy method is queued to be called, but has not been invoked yet,
    144  // as managed actors still need to be destroyed first.
    145  //
    146  // NOTE: While no new IPC can be received at this point, `CanRecv` will still
    147  // be true until `LinkStatus::Destroyed`.
    148  Doomed,
    149 
    150  // The actor has been destroyed, and ActorDestroy has been called, however an
    151  // ActorLifecycleProxy still holds a reference to the actor.
    152  Destroyed,
    153 };
    154 
    155 typedef IPCMessageStart ProtocolId;
    156 
    157 // Generated by IPDL compiler
    158 const char* ProtocolIdToName(IPCMessageStart aId);
    159 
    160 class IRefCountedProtocol;
    161 class IToplevelProtocol;
    162 class ActorLifecycleProxy;
    163 class WeakActorLifecycleProxy;
    164 class IPDLResolverInner;
    165 class UntypedManagedEndpoint;
    166 
    167 class IProtocol : public HasResultCodes {
    168 public:
    169  enum ActorDestroyReason {
    170    FailedConstructor,
    171    Deletion,
    172    AncestorDeletion,
    173    NormalShutdown,
    174    AbnormalShutdown,
    175    ManagedEndpointDropped
    176  };
    177 
    178  using ProcessId = base::ProcessId;
    179  using Message = IPC::Message;
    180 
    181  IProtocol(ProtocolId aProtoId, Side aSide)
    182      : mId(0),
    183        mProtocolId(aProtoId),
    184        mSide(aSide),
    185        mLinkStatus(LinkStatus::Inactive),
    186        mLifecycleProxy(nullptr),
    187        mManager(nullptr),
    188        mToplevel(nullptr) {}
    189 
    190  IToplevelProtocol* ToplevelProtocol() { return mToplevel; }
    191  const IToplevelProtocol* ToplevelProtocol() const { return mToplevel; }
    192 
    193  // Lookup() is forwarded directly to the toplevel protocol.
    194  IProtocol* Lookup(ActorId aId);
    195 
    196  Shmem CreateSharedMemory(size_t aSize, bool aUnsafe);
    197  Shmem::Segment* LookupSharedMemory(ActorId aId);
    198  bool IsTrackingSharedMemory(const Shmem::Segment* aSegment);
    199  bool DestroySharedMemory(Shmem& aShmem);
    200 
    201  MessageChannel* GetIPCChannel();
    202  const MessageChannel* GetIPCChannel() const;
    203 
    204  // Get the nsISerialEventTarget which all messages sent to this actor will be
    205  // processed on. Unless stated otherwise, all operations on IProtocol which
    206  // don't occur on this `nsISerialEventTarget` are unsafe.
    207  nsISerialEventTarget* GetActorEventTarget();
    208 
    209  // Actor lifecycle and other properties.
    210  ProtocolId GetProtocolId() const { return mProtocolId; }
    211  const char* GetProtocolName() const { return ProtocolIdToName(mProtocolId); }
    212 
    213  ActorId Id() const { return mId; }
    214  IRefCountedProtocol* Manager() const { return mManager; }
    215 
    216  uint32_t AllManagedActorsCount() const;
    217 
    218  ActorLifecycleProxy* GetLifecycleProxy() { return mLifecycleProxy; }
    219  WeakActorLifecycleProxy* GetWeakLifecycleProxy();
    220 
    221  Side GetSide() const { return mSide; }
    222  bool CanSend() const { return mLinkStatus == LinkStatus::Connected; }
    223 
    224  // Returns `true` for an active actor until the actor's `ActorDestroy` method
    225  // has been called.
    226  bool CanRecv() const {
    227    return mLinkStatus == LinkStatus::Connected ||
    228           mLinkStatus == LinkStatus::Doomed;
    229  }
    230 
    231  // Deallocate a managee given its type.
    232  virtual void DeallocManagee(ProtocolId, IProtocol*) = 0;
    233 
    234  virtual Result OnMessageReceived(const Message& aMessage) = 0;
    235  virtual Result OnMessageReceived(const Message& aMessage,
    236                                   UniquePtr<Message>& aReply) = 0;
    237  bool AllocShmem(size_t aSize, Shmem* aOutMem);
    238  bool AllocUnsafeShmem(size_t aSize, Shmem* aOutMem);
    239  bool DeallocShmem(Shmem& aMem);
    240 
    241  void FatalError(const char* const aErrorMsg);
    242  virtual void HandleFatalError(const char* aErrorMsg);
    243 
    244 protected:
    245  virtual ~IProtocol();
    246 
    247  friend class IToplevelProtocol;
    248  friend class ActorLifecycleProxy;
    249  friend class IPDLResolverInner;
    250  friend class UntypedManagedEndpoint;
    251  friend struct IPC::ParamTraits<IProtocol*>;
    252 
    253  // We have separate functions because the accessibility code and BrowserParent
    254  // manually calls SetManager.
    255  void SetManager(IRefCountedProtocol* aManager);
    256 
    257  // Clear `mManager` and `mToplevel` to nullptr. Only intended to be called
    258  // within the unlink implementation of cycle collected IPDL actors with cycle
    259  // collected managers.
    260  void UnlinkManager();
    261 
    262  // Sets the manager for the protocol and registers the protocol with
    263  // its manager, setting up channels for the protocol as well.  Not
    264  // for use outside of IPDL.
    265  bool SetManagerAndRegister(IRefCountedProtocol* aManager,
    266                             ActorId aId = kNullActorId);
    267 
    268  // Helpers for calling `Send` on our underlying IPC channel.
    269  bool ChannelSend(UniquePtr<IPC::Message> aMsg,
    270                   IPC::Message::seqno_t* aSeqno = nullptr);
    271  bool ChannelSend(UniquePtr<IPC::Message> aMsg,
    272                   UniquePtr<IPC::Message>* aReply);
    273 
    274  // Internal method called when the actor becomes connected.
    275  already_AddRefed<ActorLifecycleProxy> ActorConnected();
    276 
    277  // Internal method called when actor becomes disconnected.
    278  void ActorDisconnected(ActorDestroyReason aWhy);
    279 
    280  // Gets the list of ProtocolIds managed by this protocol.
    281  virtual Span<const ProtocolId> ManagedProtocolIds() const = 0;
    282 
    283  // Get the ManagedContainer for actors of the given protocol managed by this
    284  // protocol. This returns a container if and only if passed a ProtocolId in
    285  // `ManagedProtocolIds()`.
    286  virtual UntypedManagedContainer* GetManagedActors(ProtocolId aProtocol) = 0;
    287  const UntypedManagedContainer* GetManagedActors(ProtocolId aProtocol) const {
    288    return const_cast<IProtocol*>(this)->GetManagedActors(aProtocol);
    289  }
    290 
    291  // Called internally to reject the callbacks for all async-returns methods
    292  // in-progress on this actor with the given ResponseRejectReason.
    293  virtual void RejectPendingResponses(ResponseRejectReason aReason) {}
    294 
    295  // Called when the actor has been destroyed due to an error, a __delete__
    296  // message, or a __doom__ reply.
    297  virtual void ActorDestroy(ActorDestroyReason aWhy) {}
    298 
    299  // Called when IPC has acquired its first reference to the actor. This method
    300  // may take references which will later be freed by `ActorDealloc`.
    301  virtual void ActorAlloc() = 0;
    302 
    303  // Called when IPC has released its final reference to the actor. It will call
    304  // the dealloc method, causing the actor to be actually freed.
    305  //
    306  // The actor has been freed after this method returns.
    307  virtual void ActorDealloc() = 0;
    308 
    309  static const ActorId kNullActorId = 0;
    310 
    311 private:
    312 #ifdef DEBUG
    313  void WarnMessageDiscarded(IPC::Message* aMsg);
    314 #else
    315  void WarnMessageDiscarded(IPC::Message*) {}
    316 #endif
    317 
    318  void DoomSubtree();
    319 
    320  // Internal function returning an arbitrary directly managed actor. Used to
    321  // identify managed actors to destroy when tearing down an actor tree.
    322  IProtocol* PeekManagedActor() const;
    323 
    324  ActorId mId;
    325  const ProtocolId mProtocolId;
    326  const Side mSide;
    327  LinkStatus mLinkStatus;
    328  ActorLifecycleProxy* mLifecycleProxy;
    329  RefPtr<IRefCountedProtocol> mManager;
    330  IToplevelProtocol* mToplevel;
    331 };
    332 
    333 #define IPC_OK() mozilla::ipc::IPCResult::Ok()
    334 #define IPC_FAIL(actor, why) \
    335  mozilla::ipc::IPCResult::Fail(WrapNotNull(actor), __func__, (why))
    336 #define IPC_FAIL_NO_REASON(actor) \
    337  mozilla::ipc::IPCResult::Fail(WrapNotNull(actor), __func__)
    338 
    339 /*
    340 * IPC_FAIL_UNSAFE_PRINTF(actor, format, ...)
    341 *
    342 * Create a failure IPCResult with a dynamic reason-string.
    343 *
    344 * @note This macro causes data collection because IPC failure reasons may be
    345 * sent to crash-stats, where they are publicly visible. Firefox data stewards
    346 * must do data review on usages of this macro.
    347 */
    348 #define IPC_FAIL_UNSAFE_PRINTF(actor, format, ...) \
    349  mozilla::ipc::IPCResult::FailUnsafePrintfImpl(   \
    350      WrapNotNull(actor), __func__, nsPrintfCString(format, ##__VA_ARGS__))
    351 
    352 #define IPC_TEST_FAIL(actor) \
    353  mozilla::ipc::IPCResult::FailForTesting(WrapNotNull(actor), __func__, "")
    354 
    355 /**
    356 * All message deserializers and message handlers should return this type via
    357 * the above macros. We use a less generic name here to avoid conflict with
    358 * `mozilla::Result` because we have quite a few `using namespace mozilla::ipc;`
    359 * in the code base.
    360 *
    361 * Note that merely constructing a failure-result, whether directly or via the
    362 * IPC_FAIL macros, causes the associated error message to be processed
    363 * immediately.
    364 */
    365 class IPCResult {
    366 public:
    367  static IPCResult Ok() { return IPCResult(true); }
    368 
    369  // IPC failure messages can sometimes end up in telemetry. As such, to avoid
    370  // accidentally exfiltrating sensitive information without a data review, we
    371  // require that they be constant strings.
    372  template <size_t N, size_t M>
    373  static IPCResult Fail(NotNull<IProtocol*> aActor, const char (&aWhere)[N],
    374                        const char (&aWhy)[M]) {
    375    return FailImpl(aActor, aWhere, aWhy);
    376  }
    377  template <size_t N>
    378  static IPCResult Fail(NotNull<IProtocol*> aActor, const char (&aWhere)[N]) {
    379    return FailImpl(aActor, aWhere, "");
    380  }
    381 
    382  MOZ_IMPLICIT operator bool() const { return mSuccess; }
    383 
    384  // Only used by IPC_FAIL_UNSAFE_PRINTF (q.v.). Do not call this directly. (Or
    385  // at least get data-review's approval if you do.)
    386  template <size_t N>
    387  static IPCResult FailUnsafePrintfImpl(NotNull<IProtocol*> aActor,
    388                                        const char (&aWhere)[N],
    389                                        nsPrintfCString const& aWhy) {
    390    return FailImpl(aActor, aWhere, aWhy.get());
    391  }
    392 
    393  // Only used in testing.
    394  static IPCResult FailForTesting(NotNull<IProtocol*> aActor,
    395                                  const char* aWhere, const char* aWhy);
    396 
    397 private:
    398  static IPCResult FailImpl(NotNull<IProtocol*> aActor, const char* aWhere,
    399                            const char* aWhy);
    400 
    401  explicit IPCResult(bool aResult) : mSuccess(aResult) {}
    402  bool mSuccess;
    403 };
    404 
    405 class UntypedEndpoint;
    406 
    407 template <class PFooSide>
    408 class Endpoint;
    409 
    410 template <class PFooSide>
    411 class ManagedEndpoint;
    412 
    413 /**
    414 * All refcounted protocols should inherit this class.
    415 */
    416 class IRefCountedProtocol : public IProtocol {
    417 public:
    418  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
    419 
    420  using IProtocol::IProtocol;
    421 };
    422 
    423 /**
    424 * All top-level protocols should inherit this class.
    425 *
    426 * IToplevelProtocol tracks all top-level protocol actors created from
    427 * this protocol actor.
    428 */
    429 class IToplevelProtocol : public IRefCountedProtocol {
    430  friend class IProtocol;
    431  template <class PFooSide>
    432  friend class Endpoint;
    433 
    434 protected:
    435  explicit IToplevelProtocol(const char* aName, ProtocolId aProtoId,
    436                             Side aSide);
    437  ~IToplevelProtocol() = default;
    438 
    439 public:
    440  // Shadows the method on IProtocol, which will forward to the top.
    441  IProtocol* Lookup(Shmem::id_t aId);
    442 
    443  Shmem CreateSharedMemory(size_t aSize, bool aUnsafe);
    444  Shmem::Segment* LookupSharedMemory(Shmem::id_t aId);
    445  bool IsTrackingSharedMemory(const Shmem::Segment* aSegment);
    446  bool DestroySharedMemory(Shmem& aShmem);
    447 
    448  MessageChannel* GetIPCChannel() { return &mChannel; }
    449  const MessageChannel* GetIPCChannel() const { return &mChannel; }
    450 
    451  void SetOtherEndpointProcInfo(EndpointProcInfo aOtherProcInfo);
    452 
    453  virtual void ProcessingError(Result aError, const char* aMsgName) {}
    454 
    455  bool Open(ScopedPort aPort, const nsID& aMessageChannelId,
    456            EndpointProcInfo aOtherProcInfo,
    457            nsISerialEventTarget* aEventTarget = nullptr);
    458 
    459  bool Open(IToplevelProtocol* aTarget, nsISerialEventTarget* aEventTarget,
    460            mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
    461 
    462  // Open a toplevel actor such that both ends of the actor's channel are on
    463  // the same thread. This method should be called on the thread to perform
    464  // the link.
    465  //
    466  // WARNING: Attempting to send a sync message on the same thread will crash.
    467  bool OpenOnSameThread(IToplevelProtocol* aTarget,
    468                        mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
    469 
    470  /**
    471   * This sends a special message that is processed on the IO thread, so that
    472   * other actors can know that the process will soon shutdown.
    473   */
    474  void NotifyImpendingShutdown();
    475 
    476  void Close();
    477 
    478  void SetReplyTimeoutMs(int32_t aTimeoutMs);
    479 
    480  void DeallocShmems();
    481  bool ShmemCreated(const Message& aMsg);
    482  bool ShmemDestroyed(const Message& aMsg);
    483 
    484  virtual bool ShouldContinueFromReplyTimeout() { return false; }
    485 
    486  // WARNING: This function is called with the MessageChannel monitor held.
    487  virtual void IntentionalCrash() { MOZ_CRASH("Intentional IPDL crash"); }
    488 
    489  // The code here is only useful for fuzzing. It should not be used for any
    490  // other purpose.
    491 #ifdef DEBUG
    492  // Returns true if we should simulate a timeout.
    493  // WARNING: This is a testing-only function that is called with the
    494  // MessageChannel monitor held. Don't do anything fancy here or we could
    495  // deadlock.
    496  virtual bool ArtificialTimeout() { return false; }
    497 
    498  // Returns true if we want to cause the worker thread to sleep with the
    499  // monitor unlocked.
    500  virtual bool NeedArtificialSleep() { return false; }
    501 
    502  // This function should be implemented to sleep for some amount of time on
    503  // the worker thread. Will only be called if NeedArtificialSleep() returns
    504  // true.
    505  virtual void ArtificialSleep() {}
    506 #else
    507  bool ArtificialTimeout() { return false; }
    508  bool NeedArtificialSleep() { return false; }
    509  void ArtificialSleep() {}
    510 #endif
    511 
    512  bool IsOnCxxStack() const;
    513 
    514  virtual void ProcessRemoteNativeEventsInInterruptCall() {}
    515 
    516  virtual void OnChannelReceivedMessage(const Message& aMsg) {}
    517 
    518  // MessageChannel lifecycle callbacks.
    519  void OnIPCChannelOpened() {
    520    // Leak the returned ActorLifecycleProxy reference. It will be destroyed in
    521    // `OnChannelClose` or `OnChannelError`.
    522    ActorConnected().leak();
    523  }
    524  void OnChannelClose() {
    525    // Re-acquire the ActorLifecycleProxy reference acquired in
    526    // OnIPCChannelOpened.
    527    RefPtr<ActorLifecycleProxy> proxy = dont_AddRef(GetLifecycleProxy());
    528    ActorDisconnected(NormalShutdown);
    529    DeallocShmems();
    530  }
    531  void OnChannelError() {
    532    // Re-acquire the ActorLifecycleProxy reference acquired in
    533    // OnIPCChannelOpened.
    534    RefPtr<ActorLifecycleProxy> proxy = dont_AddRef(GetLifecycleProxy());
    535    ActorDisconnected(AbnormalShutdown);
    536    DeallocShmems();
    537  }
    538 
    539  base::ProcessId OtherPidMaybeInvalid() const { return mOtherPid; }
    540  GeckoChildID OtherChildIDMaybeInvalid() const { return mOtherChildID; }
    541 
    542 private:
    543  int64_t NextId();
    544 
    545  template <class T>
    546  using IDMap = nsTHashMap<int64_t, T>;
    547 
    548  base::ProcessId mOtherPid;
    549  GeckoChildID mOtherChildID;
    550 
    551  // NOTE NOTE NOTE
    552  // Used to be on mState
    553  int64_t mLastLocalId;
    554  IDMap<RefPtr<ActorLifecycleProxy>> mActorMap;
    555  IDMap<RefPtr<Shmem::Segment>> mShmemMap;
    556 
    557  MessageChannel mChannel;
    558 };
    559 
    560 class IShmemAllocator {
    561 public:
    562  virtual bool AllocShmem(size_t aSize, mozilla::ipc::Shmem* aShmem) = 0;
    563  virtual bool AllocUnsafeShmem(size_t aSize, mozilla::ipc::Shmem* aShmem) = 0;
    564  virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) = 0;
    565 };
    566 
    567 #define FORWARD_SHMEM_ALLOCATOR_TO(aImplClass)                             \
    568  virtual bool AllocShmem(size_t aSize, mozilla::ipc::Shmem* aShmem)       \
    569      override {                                                           \
    570    return aImplClass::AllocShmem(aSize, aShmem);                          \
    571  }                                                                        \
    572  virtual bool AllocUnsafeShmem(size_t aSize, mozilla::ipc::Shmem* aShmem) \
    573      override {                                                           \
    574    return aImplClass::AllocUnsafeShmem(aSize, aShmem);                    \
    575  }                                                                        \
    576  virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override {        \
    577    return aImplClass::DeallocShmem(aShmem);                               \
    578  }
    579 
    580 inline bool LoggingEnabled() {
    581 #if defined(DEBUG) || defined(FUZZING)
    582  return !!PR_GetEnv("MOZ_IPC_MESSAGE_LOG");
    583 #else
    584  return false;
    585 #endif
    586 }
    587 
    588 #if defined(DEBUG) || defined(FUZZING)
    589 bool LoggingEnabledFor(const char* aTopLevelProtocol, mozilla::ipc::Side aSide,
    590                       const char* aFilter);
    591 #endif
    592 
    593 inline bool LoggingEnabledFor(const char* aTopLevelProtocol,
    594                              mozilla::ipc::Side aSide) {
    595 #if defined(DEBUG) || defined(FUZZING)
    596  return LoggingEnabledFor(aTopLevelProtocol, aSide,
    597                           PR_GetEnv("MOZ_IPC_MESSAGE_LOG"));
    598 #else
    599  return false;
    600 #endif
    601 }
    602 
    603 MOZ_NEVER_INLINE void LogMessageForProtocol(const char* aTopLevelProtocol,
    604                                            base::ProcessId aOtherPid,
    605                                            const char* aContextDescription,
    606                                            uint32_t aMessageId,
    607                                            MessageDirection aDirection);
    608 
    609 MOZ_NEVER_INLINE void ProtocolErrorBreakpoint(const char* aMsg);
    610 
    611 // IPC::MessageReader and IPC::MessageWriter call this function for FatalError
    612 // calls which come from serialization/deserialization.
    613 MOZ_NEVER_INLINE void PickleFatalError(const char* aMsg, IProtocol* aActor);
    614 
    615 // The code generator calls this function for errors which come from the
    616 // methods of protocols.  Doing this saves codesize by making the error
    617 // cases significantly smaller.
    618 MOZ_NEVER_INLINE void FatalError(const char* aMsg, bool aIsParent);
    619 
    620 // The code generator calls this function for errors which are not
    621 // protocol-specific: errors in generated struct methods or errors in
    622 // transition functions, for instance.  Doing this saves codesize by
    623 // by making the error cases significantly smaller.
    624 MOZ_NEVER_INLINE void LogicError(const char* aMsg);
    625 
    626 MOZ_NEVER_INLINE void ActorIdReadError(const char* aActorDescription);
    627 
    628 MOZ_NEVER_INLINE void BadActorIdError(const char* aActorDescription);
    629 
    630 MOZ_NEVER_INLINE void ActorLookupError(const char* aActorDescription);
    631 
    632 MOZ_NEVER_INLINE void MismatchedActorTypeError(const char* aActorDescription);
    633 
    634 MOZ_NEVER_INLINE void UnionTypeReadError(const char* aUnionName);
    635 
    636 MOZ_NEVER_INLINE void ArrayLengthReadError(const char* aElementName);
    637 
    638 MOZ_NEVER_INLINE void SentinelReadError(const char* aElementName);
    639 
    640 /**
    641 * Annotate the crash reporter with the error code from the most recent system
    642 * call. Returns the system error.
    643 */
    644 void AnnotateSystemError();
    645 
    646 // The ActorLifecycleProxy is a helper type used internally by IPC to maintain a
    647 // maybe-owning reference to an IProtocol object. For well-behaved actors
    648 // which are not freed until after their `Dealloc` method is called, a
    649 // reference to an actor's `ActorLifecycleProxy` object is an owning one, as the
    650 // `Dealloc` method will only be called when all references to the
    651 // `ActorLifecycleProxy` are released.
    652 //
    653 // Unfortunately, some actors may be destroyed before their `Dealloc` method
    654 // is called. For these actors, `ActorLifecycleProxy` acts as a weak pointer,
    655 // and will begin to return `nullptr` from its `Get()` method once the
    656 // corresponding actor object has been destroyed.
    657 //
    658 // When calling a `Recv` method, IPC will hold a `ActorLifecycleProxy` reference
    659 // to the target actor, meaning that well-behaved actors can behave as though a
    660 // strong reference is being held.
    661 //
    662 // Generic IPC code MUST treat ActorLifecycleProxy references as weak
    663 // references!
    664 class ActorLifecycleProxy {
    665 public:
    666  NS_INLINE_DECL_REFCOUNTING_ONEVENTTARGET(ActorLifecycleProxy)
    667 
    668  IProtocol* Get() { return mActor; }
    669 
    670  WeakActorLifecycleProxy* GetWeakProxy();
    671 
    672 private:
    673  friend class IProtocol;
    674 
    675  explicit ActorLifecycleProxy(IProtocol* aActor);
    676  ~ActorLifecycleProxy();
    677 
    678  ActorLifecycleProxy(const ActorLifecycleProxy&) = delete;
    679  ActorLifecycleProxy& operator=(const ActorLifecycleProxy&) = delete;
    680 
    681  IProtocol* MOZ_NON_OWNING_REF mActor;
    682 
    683  // When requested, the current self-referencing weak reference for this
    684  // ActorLifecycleProxy.
    685  RefPtr<WeakActorLifecycleProxy> mWeakProxy;
    686 };
    687 
    688 // Unlike ActorLifecycleProxy, WeakActorLifecycleProxy only holds a weak
    689 // reference to both the proxy and the actual actor, meaning that holding this
    690 // type will not attempt to keep the actor object alive.
    691 //
    692 // This type is safe to hold on threads other than the actor's thread, but is
    693 // _NOT_ safe to access on other threads, as actors and ActorLifecycleProxy
    694 // objects are not threadsafe.
    695 class WeakActorLifecycleProxy final {
    696 public:
    697  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WeakActorLifecycleProxy)
    698 
    699  // May only be called on the actor's event target.
    700  // Will return `nullptr` if the actor has already been destroyed from IPC's
    701  // point of view.
    702  IProtocol* Get() const;
    703 
    704  // Safe to call on any thread.
    705  nsISerialEventTarget* ActorEventTarget() const { return mActorEventTarget; }
    706 
    707 private:
    708  friend class ActorLifecycleProxy;
    709 
    710  explicit WeakActorLifecycleProxy(ActorLifecycleProxy* aProxy);
    711  ~WeakActorLifecycleProxy();
    712 
    713  WeakActorLifecycleProxy(const WeakActorLifecycleProxy&) = delete;
    714  WeakActorLifecycleProxy& operator=(const WeakActorLifecycleProxy&) = delete;
    715 
    716  // This field may only be accessed on the actor's thread, and will be
    717  // automatically cleared when the ActorLifecycleProxy is destroyed.
    718  ActorLifecycleProxy* MOZ_NON_OWNING_REF mProxy;
    719 
    720  // The serial event target which owns the actor, and is the only thread where
    721  // it is OK to access the ActorLifecycleProxy.
    722  const nsCOMPtr<nsISerialEventTarget> mActorEventTarget;
    723 };
    724 
    725 class IPDLResolverInner final {
    726 public:
    727  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(IPDLResolverInner,
    728                                                     Destroy())
    729 
    730  explicit IPDLResolverInner(UniquePtr<IPC::Message> aReply, IProtocol* aActor);
    731 
    732  template <typename F>
    733  void Resolve(F&& aWrite) {
    734    ResolveOrReject(true, std::forward<F>(aWrite));
    735  }
    736 
    737 private:
    738  void ResolveOrReject(bool aResolve,
    739                       FunctionRef<void(IPC::Message*, IProtocol*)> aWrite);
    740 
    741  void Destroy();
    742  ~IPDLResolverInner();
    743 
    744  UniquePtr<IPC::Message> mReply;
    745  RefPtr<WeakActorLifecycleProxy> mWeakProxy;
    746 };
    747 
    748 // Member type added by the IPDL compiler to actors with async-returns messages.
    749 // Manages a table mapping outstanding async message seqnos to the corresponding
    750 // IPDL-generated callback which handles validating, deserializing, and
    751 // dispatching the reply.
    752 class IPDLAsyncReturnsCallbacks : public HasResultCodes {
    753 public:
    754  // Internal resolve callback signature. The callback should deserialize from
    755  // the IPC::MessageReader* argument.
    756  using Callback =
    757      mozilla::MoveOnlyFunction<Result(IPC::MessageReader* IProtocol)>;
    758  using seqno_t = IPC::Message::seqno_t;
    759  using msgid_t = IPC::Message::msgid_t;
    760 
    761  void AddCallback(seqno_t aSeqno, msgid_t aType, Callback aResolve,
    762                   RejectCallback aReject);
    763  Result GotReply(IProtocol* aActor, const IPC::Message& aMessage);
    764  void RejectPendingResponses(ResponseRejectReason aReason);
    765 
    766 private:
    767  struct EntryKey {
    768    seqno_t mSeqno;
    769    msgid_t mType;
    770 
    771    bool operator==(const EntryKey& aOther) const;
    772    bool operator<(const EntryKey& aOther) const;
    773  };
    774  struct Entry : EntryKey {
    775    Callback mResolve;
    776    RejectCallback mReject;
    777  };
    778 
    779  // NOTE: We expect this table to be quite small most of the time (usually 0-1
    780  // entries), so use a sorted array as backing storage to reduce unnecessary
    781  // overhead.
    782  nsTArray<Entry> mMap;
    783 };
    784 
    785 }  // namespace ipc
    786 
    787 // Base class for `ManagedContainer` - contains a series of IProtocol* instances
    788 // of the same type (as specified by the subclass), and allows iterating over
    789 // them.
    790 class UntypedManagedContainer {
    791 public:
    792  using iterator = nsTArray<mozilla::ipc::IProtocol*>::const_iterator;
    793 
    794  iterator begin() const { return mArray.cbegin(); }
    795  iterator end() const { return mArray.cend(); }
    796 
    797  bool IsEmpty() const { return mArray.IsEmpty(); }
    798  uint32_t Count() const { return mArray.Length(); }
    799 
    800 protected:
    801  explicit UntypedManagedContainer(mozilla::ipc::ProtocolId aProtocolId)
    802 #ifdef DEBUG
    803      : mProtocolId(aProtocolId)
    804 #endif
    805  {
    806  }
    807 
    808 private:
    809  friend class mozilla::ipc::IProtocol;
    810 
    811  bool EnsureRemoved(mozilla::ipc::IProtocol* aElement) {
    812    return mArray.RemoveElementSorted(aElement);
    813  }
    814 
    815  void Insert(mozilla::ipc::IProtocol* aElement) {
    816    MOZ_ASSERT(aElement->GetProtocolId() == mProtocolId,
    817               "ManagedContainer can only contain a single protocol");
    818    // Equivalent to `InsertElementSorted`, avoiding inserting a duplicate
    819    // element. See bug 1896166.
    820    size_t index = mArray.IndexOfFirstElementGt(aElement);
    821    if (index == 0 || mArray[index - 1] != aElement) {
    822      mArray.InsertElementAt(index, aElement);
    823    }
    824  }
    825 
    826  nsTArray<mozilla::ipc::IProtocol*> mArray;
    827 #ifdef DEBUG
    828  mozilla::ipc::ProtocolId mProtocolId;
    829 #endif
    830 };
    831 
    832 template <typename Protocol>
    833 class ManagedContainer : public UntypedManagedContainer {
    834 public:
    835  ManagedContainer() : UntypedManagedContainer(Protocol::kProtocolId) {}
    836 
    837  // Input iterator which downcasts to the protocol type while iterating over
    838  // the untyped container.
    839  class iterator {
    840   public:
    841    using value_type = Protocol*;
    842    using difference_type = ptrdiff_t;
    843    using pointer = value_type*;
    844    using reference = value_type;
    845    using iterator_category = std::input_iterator_tag;
    846 
    847   private:
    848    friend class ManagedContainer;
    849    explicit iterator(const UntypedManagedContainer::iterator& aIter)
    850        : mIter(aIter) {}
    851    UntypedManagedContainer::iterator mIter;
    852 
    853   public:
    854    iterator() = default;
    855 
    856    bool operator==(const iterator& aRhs) const { return mIter == aRhs.mIter; }
    857    bool operator!=(const iterator& aRhs) const { return mIter != aRhs.mIter; }
    858 
    859    // NOTE: operator->() cannot be implemented without a proxy type.
    860    // This is OK, and the same approach taken by C++20's transform_view.
    861    reference operator*() const { return static_cast<value_type>(*mIter); }
    862 
    863    iterator& operator++() {
    864      ++mIter;
    865      return *this;
    866    }
    867    iterator operator++(int) { return iterator{mIter++}; }
    868  };
    869 
    870  iterator begin() const { return iterator{UntypedManagedContainer::begin()}; }
    871  iterator end() const { return iterator{UntypedManagedContainer::end()}; }
    872 
    873  void ToArray(nsTArray<Protocol*>& aArray) const {
    874    aArray.SetCapacity(Count());
    875    for (Protocol* p : *this) {
    876      aArray.AppendElement(p);
    877    }
    878  }
    879 };
    880 
    881 template <typename Protocol>
    882 Protocol* LoneManagedOrNullAsserts(
    883    const ManagedContainer<Protocol>& aManagees) {
    884  if (aManagees.IsEmpty()) {
    885    return nullptr;
    886  }
    887  MOZ_ASSERT(aManagees.Count() == 1);
    888  return *aManagees.begin();
    889 }
    890 
    891 template <typename Protocol>
    892 Protocol* SingleManagedOrNull(const ManagedContainer<Protocol>& aManagees) {
    893  if (aManagees.Count() != 1) {
    894    return nullptr;
    895  }
    896  return *aManagees.begin();
    897 }
    898 
    899 }  // namespace mozilla
    900 
    901 #endif  // mozilla_ipc_ProtocolUtils_h