Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/ipc/MessageChannel.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
 * vim: sw=4 ts=4 et :
3
 */
4
/* This Source Code Form is subject to the terms of the Mozilla Public
5
 * License, v. 2.0. If a copy of the MPL was not distributed with this
6
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8
#ifndef ipc_glue_MessageChannel_h
9
#define ipc_glue_MessageChannel_h 1
10
11
#include "base/basictypes.h"
12
#include "base/message_loop.h"
13
14
#include "nsIMemoryReporter.h"
15
#include "mozilla/Atomics.h"
16
#include "mozilla/DebugOnly.h"
17
#include "mozilla/Monitor.h"
18
#include "mozilla/MozPromise.h"
19
#include "mozilla/Vector.h"
20
#if defined(OS_WIN)
21
#include "mozilla/ipc/Neutering.h"
22
#endif // defined(OS_WIN)
23
#include "mozilla/ipc/Transport.h"
24
#include "MessageLink.h"
25
#include "nsILabelableRunnable.h"
26
#include "nsThreadUtils.h"
27
28
#include <deque>
29
#include <functional>
30
#include <map>
31
#include <math.h>
32
#include <stack>
33
#include <vector>
34
35
class nsIEventTarget;
36
37
namespace mozilla {
38
namespace ipc {
39
40
class MessageChannel;
41
class IToplevelProtocol;
42
43
class RefCountedMonitor : public Monitor
44
{
45
  public:
46
    RefCountedMonitor()
47
        : Monitor("mozilla.ipc.MessageChannel.mMonitor")
48
0
    {}
49
50
    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMonitor)
51
52
  private:
53
0
    ~RefCountedMonitor() {}
54
};
55
56
enum class SyncSendError {
57
    SendSuccess,
58
    PreviousTimeout,
59
    SendingCPOWWhileDispatchingSync,
60
    SendingCPOWWhileDispatchingUrgent,
61
    NotConnectedBeforeSend,
62
    DisconnectedDuringSend,
63
    CancelledBeforeSend,
64
    CancelledAfterSend,
65
    TimedOut,
66
    ReplyError,
67
};
68
69
enum class ResponseRejectReason {
70
    SendError,
71
    ChannelClosed,
72
    HandlerRejected,
73
    ActorDestroyed,
74
    EndGuard_,
75
};
76
77
template<typename T>
78
using ResolveCallback = std::function<void (T&&)>;
79
80
using RejectCallback = std::function<void (ResponseRejectReason)>;
81
82
enum ChannelState {
83
    ChannelClosed,
84
    ChannelOpening,
85
    ChannelConnected,
86
    ChannelTimeout,
87
    ChannelClosing,
88
    ChannelError
89
};
90
91
class AutoEnterTransaction;
92
93
class MessageChannel : HasResultCodes, MessageLoop::DestructionObserver
94
{
95
    friend class ProcessLink;
96
    friend class ThreadLink;
97
#ifdef FUZZING
98
    friend class ProtocolFuzzerHelper;
99
#endif
100
101
    class CxxStackFrame;
102
    class InterruptFrame;
103
104
    typedef mozilla::Monitor Monitor;
105
106
    // We could templatize the actor type but it would unnecessarily
107
    // expand the code size. Using the actor address as the
108
    // identifier is already good enough.
109
    typedef void* ActorIdType;
110
111
public:
112
    struct UntypedCallbackHolder
113
    {
114
        UntypedCallbackHolder(ActorIdType aActorId,
115
                              RejectCallback&& aReject)
116
            : mActorId(aActorId)
117
            , mReject(std::move(aReject))
118
0
        {}
119
120
0
        virtual ~UntypedCallbackHolder() {}
121
122
0
        void Reject(ResponseRejectReason aReason) {
123
0
            mReject(aReason);
124
0
        }
125
126
        ActorIdType mActorId;
127
        RejectCallback mReject;
128
    };
129
130
    template<typename Value>
131
    struct CallbackHolder : public UntypedCallbackHolder
132
    {
133
        CallbackHolder(ActorIdType aActorId,
134
                       ResolveCallback<Value>&& aResolve,
135
                       RejectCallback&& aReject)
136
            : UntypedCallbackHolder(aActorId, std::move(aReject))
137
            , mResolve(std::move(aResolve))
138
0
        {}
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::wr::MemoryReport>::CallbackHolder(void*, std::__1::function<void (mozilla::wr::MemoryReport&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::ipc::Endpoint<mozilla::extensions::PStreamFilterChild> >::CallbackHolder(void*, std::__1::function<void (mozilla::ipc::Endpoint<mozilla::extensions::PStreamFilterChild>&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::ipc::FileDescriptor>::CallbackHolder(void*, std::__1::function<void (mozilla::ipc::FileDescriptor&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::dom::CreatedWindowInfo>::CallbackHolder(void*, std::__1::function<void (mozilla::dom::CreatedWindowInfo&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<bool>::CallbackHolder(void*, std::__1::function<void (bool&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<RefPtr<nsIInputStream> >::CallbackHolder(void*, std::__1::function<void (RefPtr<nsIInputStream>&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::ipc::Shmem>::CallbackHolder(void*, std::__1::function<void (mozilla::ipc::Shmem&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::Tuple<bool, nsTString<char16_t> > >::CallbackHolder(void*, std::__1::function<void (mozilla::Tuple<bool, nsTString<char16_t> >&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::dom::IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult>::CallbackHolder(void*, std::__1::function<void (mozilla::dom::IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::dom::IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult>::CallbackHolder(void*, std::__1::function<void (mozilla::dom::IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::Tuple<bool, mozilla::CopyableErrorResult> >::CallbackHolder(void*, std::__1::function<void (mozilla::Tuple<bool, mozilla::CopyableErrorResult>&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::widget::IMENotificationRequests>::CallbackHolder(void*, std::__1::function<void (mozilla::widget::IMENotificationRequests&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
139
140
0
        void Resolve(Value&& aReason) {
141
0
            mResolve(std::move(aReason));
142
0
        }
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::wr::MemoryReport>::Resolve(mozilla::wr::MemoryReport&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::ipc::Endpoint<mozilla::extensions::PStreamFilterChild> >::Resolve(mozilla::ipc::Endpoint<mozilla::extensions::PStreamFilterChild>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::ipc::FileDescriptor>::Resolve(mozilla::ipc::FileDescriptor&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::dom::CreatedWindowInfo>::Resolve(mozilla::dom::CreatedWindowInfo&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<bool>::Resolve(bool&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<RefPtr<nsIInputStream> >::Resolve(RefPtr<nsIInputStream>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::ipc::Shmem>::Resolve(mozilla::ipc::Shmem&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::Tuple<bool, nsTString<char16_t> > >::Resolve(mozilla::Tuple<bool, nsTString<char16_t> >&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::dom::IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult>::Resolve(mozilla::dom::IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::dom::IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult>::Resolve(mozilla::dom::IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::Tuple<bool, mozilla::CopyableErrorResult> >::Resolve(mozilla::Tuple<bool, mozilla::CopyableErrorResult>&&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::CallbackHolder<mozilla::widget::IMENotificationRequests>::Resolve(mozilla::widget::IMENotificationRequests&&)
143
144
        ResolveCallback<Value> mResolve;
145
    };
146
147
private:
148
    static Atomic<size_t> gUnresolvedResponses;
149
    friend class PendingResponseReporter;
150
151
  public:
152
    static const int32_t kNoTimeout;
153
154
    typedef IPC::Message Message;
155
    typedef IPC::MessageInfo MessageInfo;
156
    typedef mozilla::ipc::Transport Transport;
157
158
    explicit MessageChannel(const char *aName,
159
                            IToplevelProtocol *aListener);
160
    ~MessageChannel();
161
162
0
    IToplevelProtocol *Listener() const {
163
0
        return mListener;
164
0
    }
165
166
    // "Open" from the perspective of the transport layer; the underlying
167
    // socketpair/pipe should already be created.
168
    //
169
    // Returns true if the transport layer was successfully connected,
170
    // i.e., mChannelState == ChannelConnected.
171
    bool Open(Transport* aTransport, MessageLoop* aIOLoop=0, Side aSide=UnknownSide);
172
173
    // "Open" a connection to another thread in the same process.
174
    //
175
    // Returns true if the transport layer was successfully connected,
176
    // i.e., mChannelState == ChannelConnected.
177
    //
178
    // For more details on the process of opening a channel between
179
    // threads, see the extended comment on this function
180
    // in MessageChannel.cpp.
181
    bool Open(MessageChannel *aTargetChan, nsIEventTarget *aEventTarget, Side aSide);
182
183
    // Close the underlying transport channel.
184
    void Close();
185
186
    // Force the channel to behave as if a channel error occurred. Valid
187
    // for process links only, not thread links.
188
    void CloseWithError();
189
190
    void CloseWithTimeout();
191
192
    void SetAbortOnError(bool abort)
193
0
    {
194
0
        mAbortOnError = abort;
195
0
    }
196
197
    // Call aInvoke for each pending message until it returns false.
198
    // XXX: You must get permission from an IPC peer to use this function
199
    //      since it requires custom deserialization and re-orders events.
200
    void PeekMessages(const std::function<bool(const Message& aMsg)>& aInvoke);
201
202
    // Misc. behavioral traits consumers can request for this channel
203
    enum ChannelFlags {
204
      REQUIRE_DEFAULT                         = 0,
205
      // Windows: if this channel operates on the UI thread, indicates
206
      // WindowsMessageLoop code should enable deferred native message
207
      // handling to prevent deadlocks. Should only be used for protocols
208
      // that manage child processes which might create native UI, like
209
      // plugins.
210
      REQUIRE_DEFERRED_MESSAGE_PROTECTION     = 1 << 0,
211
      // Windows: When this flag is specified, any wait that occurs during
212
      // synchronous IPC will be alertable, thus allowing a11y code in the
213
      // chrome process to reenter content while content is waiting on a
214
      // synchronous call.
215
      REQUIRE_A11Y_REENTRY                    = 1 << 1,
216
    };
217
0
    void SetChannelFlags(ChannelFlags aFlags) { mFlags = aFlags; }
218
0
    ChannelFlags GetChannelFlags() { return mFlags; }
219
220
    // Asynchronously send a message to the other side of the channel
221
    bool Send(Message* aMsg);
222
223
    // Asynchronously send a message to the other side of the channel
224
    // and wait for asynchronous reply.
225
    template<typename Value>
226
    void Send(Message* aMsg,
227
              ActorIdType aActorId,
228
              ResolveCallback<Value>&& aResolve,
229
0
              RejectCallback&& aReject) {
230
0
        int32_t seqno = NextSeqno();
231
0
        aMsg->set_seqno(seqno);
232
0
        if (!Send(aMsg)) {
233
0
            aReject(ResponseRejectReason::SendError);
234
0
            return;
235
0
        }
236
0
237
0
        UniquePtr<UntypedCallbackHolder> callback =
238
0
            MakeUnique<CallbackHolder<Value>>(
239
0
                aActorId, std::move(aResolve), std::move(aReject));
240
0
        mPendingResponses.insert(std::make_pair(seqno, std::move(callback)));
241
0
        gUnresolvedResponses++;
242
0
    }
Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::wr::MemoryReport>(IPC::Message*, void*, std::__1::function<void (mozilla::wr::MemoryReport&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::ipc::Endpoint<mozilla::extensions::PStreamFilterChild> >(IPC::Message*, void*, std::__1::function<void (mozilla::ipc::Endpoint<mozilla::extensions::PStreamFilterChild>&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::ipc::FileDescriptor>(IPC::Message*, void*, std::__1::function<void (mozilla::ipc::FileDescriptor&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::dom::CreatedWindowInfo>(IPC::Message*, void*, std::__1::function<void (mozilla::dom::CreatedWindowInfo&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<bool>(IPC::Message*, void*, std::__1::function<void (bool&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<RefPtr<nsIInputStream> >(IPC::Message*, void*, std::__1::function<void (RefPtr<nsIInputStream>&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::ipc::Shmem>(IPC::Message*, void*, std::__1::function<void (mozilla::ipc::Shmem&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::Tuple<bool, nsTString<char16_t> > >(IPC::Message*, void*, std::__1::function<void (mozilla::Tuple<bool, nsTString<char16_t> >&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::dom::IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult>(IPC::Message*, void*, std::__1::function<void (mozilla::dom::IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::dom::IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult>(IPC::Message*, void*, std::__1::function<void (mozilla::dom::IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::Tuple<bool, mozilla::CopyableErrorResult> >(IPC::Message*, void*, std::__1::function<void (mozilla::Tuple<bool, mozilla::CopyableErrorResult>&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
Unexecuted instantiation: void mozilla::ipc::MessageChannel::Send<mozilla::widget::IMENotificationRequests>(IPC::Message*, void*, std::__1::function<void (mozilla::widget::IMENotificationRequests&&)>&&, std::__1::function<void (mozilla::ipc::ResponseRejectReason)>&&)
243
244
    bool SendBuildIDsMatchMessage(const char* aParentBuildI);
245
0
    bool DoBuildIDsMatch() { return mBuildIDsConfirmedMatch; }
246
247
    // Asynchronously deliver a message back to this side of the
248
    // channel
249
    bool Echo(Message* aMsg);
250
251
    // Synchronously send |msg| (i.e., wait for |reply|)
252
    bool Send(Message* aMsg, Message* aReply);
253
254
    // Make an Interrupt call to the other side of the channel
255
    bool Call(Message* aMsg, Message* aReply);
256
257
    // Wait until a message is received
258
    bool WaitForIncomingMessage();
259
260
    bool CanSend() const;
261
262
    // Remove and return a callback that needs reply
263
    UniquePtr<UntypedCallbackHolder> PopCallback(const Message& aMsg);
264
265
    // Used to reject and remove pending responses owned by the given
266
    // actor when it's about to be destroyed.
267
    void RejectPendingResponsesForActor(ActorIdType aActorId);
268
269
    // If sending a sync message returns an error, this function gives a more
270
    // descriptive error message.
271
0
    SyncSendError LastSendError() const {
272
0
        AssertWorkerThread();
273
0
        return mLastSendError;
274
0
    }
275
276
    // Currently only for debugging purposes, doesn't aquire mMonitor.
277
0
    ChannelState GetChannelState__TotallyRacy() const {
278
0
        return mChannelState;
279
0
    }
280
281
    void SetReplyTimeoutMs(int32_t aTimeoutMs);
282
283
0
    bool IsOnCxxStack() const {
284
0
        return !mCxxStackFrames.empty();
285
0
    }
286
287
    bool IsInTransaction() const;
288
    void CancelCurrentTransaction();
289
290
    // Force all calls to Send to defer actually sending messages. This will
291
    // cause sync messages to block until another thread calls
292
    // StopPostponingSends.
293
    //
294
    // This must be called from the worker thread.
295
    void BeginPostponingSends();
296
297
    // Stop postponing sent messages, and immediately flush all postponed
298
    // messages to the link. This may be called from any thread.
299
    //
300
    // Note that there are no ordering guarantees between two different
301
    // MessageChannels. If channel B sends a message, then stops postponing
302
    // channel A, messages from A may arrive before B. The easiest way to order
303
    // this, if needed, is to make B send a sync message.
304
    void StopPostponingSends();
305
306
    /**
307
     * This function is used by hang annotation code to determine which IPDL
308
     * actor is highest in the call stack at the time of the hang. It should
309
     * be called from the main thread when a sync or intr message is about to
310
     * be sent.
311
     */
312
    int32_t GetTopmostMessageRoutingId() const;
313
314
    // Unsound_IsClosed and Unsound_NumQueuedMessages are safe to call from any
315
    // thread, but they make no guarantees about whether you'll get an
316
    // up-to-date value; the values are written on one thread and read without
317
    // locking, on potentially different threads.  Thus you should only use
318
    // them when you don't particularly care about getting a recent value (e.g.
319
    // in a memory report).
320
0
    bool Unsound_IsClosed() const {
321
0
        return mLink ? mLink->Unsound_IsClosed() : true;
322
0
    }
323
0
    uint32_t Unsound_NumQueuedMessages() const {
324
0
        return mLink ? mLink->Unsound_NumQueuedMessages() : 0;
325
0
    }
326
327
0
    static bool IsPumpingMessages() {
328
0
        return sIsPumpingMessages;
329
0
    }
330
0
    static void SetIsPumpingMessages(bool aIsPumping) {
331
0
        sIsPumpingMessages = aIsPumping;
332
0
    }
333
334
0
    void SetInKillHardShutdown() {
335
0
        mInKillHardShutdown = true;
336
0
    }
337
338
#ifdef OS_WIN
339
    struct MOZ_STACK_CLASS SyncStackFrame
340
    {
341
        SyncStackFrame(MessageChannel* channel, bool interrupt);
342
        ~SyncStackFrame();
343
344
        bool mInterrupt;
345
        bool mSpinNestedEvents;
346
        bool mListenerNotified;
347
        MessageChannel* mChannel;
348
349
        // The previous stack frame for this channel.
350
        SyncStackFrame* mPrev;
351
352
        // The previous stack frame on any channel.
353
        SyncStackFrame* mStaticPrev;
354
    };
355
    friend struct MessageChannel::SyncStackFrame;
356
357
    static bool IsSpinLoopActive() {
358
        for (SyncStackFrame* frame = sStaticTopFrame; frame; frame = frame->mPrev) {
359
            if (frame->mSpinNestedEvents)
360
                return true;
361
        }
362
        return false;
363
    }
364
365
  protected:
366
    // The deepest sync stack frame for this channel.
367
    SyncStackFrame* mTopFrame;
368
369
    bool mIsSyncWaitingOnNonMainThread;
370
371
    // The deepest sync stack frame on any channel.
372
    static SyncStackFrame* sStaticTopFrame;
373
374
  public:
375
    void ProcessNativeEventsInInterruptCall();
376
    static void NotifyGeckoEventDispatch();
377
378
  private:
379
    void SpinInternalEventLoop();
380
#if defined(ACCESSIBILITY)
381
    bool WaitForSyncNotifyWithA11yReentry();
382
#endif // defined(ACCESSIBILITY)
383
#endif // defined(OS_WIN)
384
385
  private:
386
    void CommonThreadOpenInit(MessageChannel *aTargetChan, Side aSide);
387
    void OnOpenAsSlave(MessageChannel *aTargetChan, Side aSide);
388
389
    void PostErrorNotifyTask();
390
    void OnNotifyMaybeChannelError();
391
    void ReportConnectionError(const char* aChannelName, Message* aMsg = nullptr) const;
392
    void ReportMessageRouteError(const char* channelName) const;
393
    bool MaybeHandleError(Result code, const Message& aMsg, const char* channelName);
394
395
    void Clear();
396
397
    // Send OnChannelConnected notification to listeners.
398
    void DispatchOnChannelConnected();
399
400
    bool InterruptEventOccurred();
401
    bool HasPendingEvents();
402
403
    void ProcessPendingRequests(AutoEnterTransaction& aTransaction);
404
    bool ProcessPendingRequest(Message &&aUrgent);
405
406
    void MaybeUndeferIncall();
407
    void EnqueuePendingMessages();
408
409
    // Dispatches an incoming message to its appropriate handler.
410
    void DispatchMessage(Message &&aMsg);
411
412
    // DispatchMessage will route to one of these functions depending on the
413
    // protocol type of the message.
414
    void DispatchSyncMessage(const Message &aMsg, Message*& aReply);
415
    void DispatchUrgentMessage(const Message &aMsg);
416
    void DispatchAsyncMessage(const Message &aMsg);
417
    void DispatchRPCMessage(const Message &aMsg);
418
    void DispatchInterruptMessage(Message &&aMsg, size_t aStackDepth);
419
420
    // Return true if the wait ended because a notification was received.
421
    //
422
    // Return false if the time elapsed from when we started the process of
423
    // waiting until afterwards exceeded the currently allotted timeout.
424
    // That *DOES NOT* mean false => "no event" (== timeout); there are many
425
    // circumstances that could cause the measured elapsed time to exceed the
426
    // timeout EVEN WHEN we were notified.
427
    //
428
    // So in sum: true is a meaningful return value; false isn't,
429
    // necessarily.
430
    bool WaitForSyncNotify(bool aHandleWindowsMessages);
431
    bool WaitForInterruptNotify();
432
433
    bool WaitResponse(bool aWaitTimedOut);
434
435
    bool ShouldContinueFromTimeout();
436
437
    void EndTimeout();
438
    void CancelTransaction(int transaction);
439
440
    void RepostAllMessages();
441
442
    // The "remote view of stack depth" can be different than the
443
    // actual stack depth when there are out-of-turn replies.  When we
444
    // receive one, our actual Interrupt stack depth doesn't decrease, but
445
    // the other side (that sent the reply) thinks it has.  So, the
446
    // "view" returned here is |stackDepth| minus the number of
447
    // out-of-turn replies.
448
    //
449
    // Only called from the worker thread.
450
0
    size_t RemoteViewOfStackDepth(size_t stackDepth) const {
451
0
        AssertWorkerThread();
452
0
        return stackDepth - mOutOfTurnReplies.size();
453
0
    }
454
455
0
    int32_t NextSeqno() {
456
0
        AssertWorkerThread();
457
0
        return (mSide == ChildSide) ? --mNextSeqno : ++mNextSeqno;
458
0
    }
459
460
    // This helper class manages mCxxStackDepth on behalf of MessageChannel.
461
    // When the stack depth is incremented from zero to non-zero, it invokes
462
    // a callback, and similarly for when the depth goes from non-zero to zero.
463
    void EnteredCxxStack();
464
    void ExitedCxxStack();
465
466
    void EnteredCall();
467
    void ExitedCall();
468
469
    void EnteredSyncSend();
470
    void ExitedSyncSend();
471
472
    void DebugAbort(const char* file, int line, const char* cond,
473
                    const char* why,
474
                    bool reply=false);
475
476
    // This method is only safe to call on the worker thread, or in a
477
    // debugger with all threads paused.
478
    void DumpInterruptStack(const char* const pfx="") const;
479
480
  private:
481
    // Called from both threads
482
0
    size_t InterruptStackDepth() const {
483
0
        mMonitor->AssertCurrentThreadOwns();
484
0
        return mInterruptStack.size();
485
0
    }
486
487
0
    bool AwaitingInterruptReply() const {
488
0
        mMonitor->AssertCurrentThreadOwns();
489
0
        return !mInterruptStack.empty();
490
0
    }
491
0
    bool AwaitingIncomingMessage() const {
492
0
        mMonitor->AssertCurrentThreadOwns();
493
0
        return mIsWaitingForIncoming;
494
0
    }
495
496
    class MOZ_STACK_CLASS AutoEnterWaitForIncoming
497
    {
498
    public:
499
        explicit AutoEnterWaitForIncoming(MessageChannel& aChannel)
500
            : mChannel(aChannel)
501
0
        {
502
0
            aChannel.mMonitor->AssertCurrentThreadOwns();
503
0
            aChannel.mIsWaitingForIncoming = true;
504
0
        }
505
506
        ~AutoEnterWaitForIncoming()
507
0
        {
508
0
            mChannel.mIsWaitingForIncoming = false;
509
0
        }
510
511
    private:
512
        MessageChannel& mChannel;
513
    };
514
    friend class AutoEnterWaitForIncoming;
515
516
    // Returns true if we're dispatching an async message's callback.
517
0
    bool DispatchingAsyncMessage() const {
518
0
        AssertWorkerThread();
519
0
        return mDispatchingAsyncMessage;
520
0
    }
521
522
0
    int DispatchingAsyncMessageNestedLevel() const {
523
0
        AssertWorkerThread();
524
0
        return mDispatchingAsyncMessageNestedLevel;
525
0
    }
526
527
    bool Connected() const;
528
529
  private:
530
    // Executed on the IO thread.
531
    void NotifyWorkerThread();
532
533
    // Return true if |aMsg| is a special message targeted at the IO
534
    // thread, in which case it shouldn't be delivered to the worker.
535
    bool MaybeInterceptSpecialIOMessage(const Message& aMsg);
536
537
    void OnChannelConnected(int32_t peer_id);
538
539
    // Tell the IO thread to close the channel and wait for it to ACK.
540
    void SynchronouslyClose();
541
542
    // Returns true if ShouldDeferMessage(aMsg) is guaranteed to return true.
543
    // Otherwise, the result of ShouldDeferMessage(aMsg) may be true or false,
544
    // depending on context.
545
    static bool IsAlwaysDeferred(const Message& aMsg);
546
547
    // Helper for sending a message via the link. This should only be used for
548
    // non-special messages that might have to be postponed.
549
    void SendMessageToLink(Message* aMsg);
550
551
    bool WasTransactionCanceled(int transaction);
552
    bool ShouldDeferMessage(const Message& aMsg);
553
    bool ShouldDeferInterruptMessage(const Message& aMsg, size_t aStackDepth);
554
    void OnMessageReceivedFromLink(Message&& aMsg);
555
    void OnChannelErrorFromLink();
556
557
  private:
558
    // Run on the not current thread.
559
    void NotifyChannelClosed();
560
    void NotifyMaybeChannelError();
561
562
  private:
563
    // Can be run on either thread
564
    void AssertWorkerThread() const
565
0
    {
566
0
        MOZ_ASSERT(mWorkerThread, "Channel hasn't been opened yet");
567
0
        MOZ_RELEASE_ASSERT(mWorkerThread == GetCurrentVirtualThread(),
568
0
                           "not on worker thread!");
569
0
    }
570
571
    // The "link" thread is either the I/O thread (ProcessLink) or the
572
    // other actor's work thread (ThreadLink).  In either case, it is
573
    // NOT our worker thread.
574
    void AssertLinkThread() const
575
0
    {
576
0
        MOZ_ASSERT(mWorkerThread, "Channel hasn't been opened yet");
577
0
        MOZ_RELEASE_ASSERT(mWorkerThread != GetCurrentVirtualThread(),
578
0
                           "on worker thread but should not be!");
579
0
    }
580
581
  private:
582
    class MessageTask :
583
        public CancelableRunnable,
584
        public LinkedListElement<RefPtr<MessageTask>>,
585
        public nsIRunnablePriority,
586
        public nsILabelableRunnable
587
    {
588
    public:
589
        explicit MessageTask(MessageChannel* aChannel, Message&& aMessage);
590
591
        NS_DECL_ISUPPORTS_INHERITED
592
593
        NS_IMETHOD Run() override;
594
        nsresult Cancel() override;
595
        NS_IMETHOD GetPriority(uint32_t* aPriority) override;
596
        void Post();
597
        void Clear();
598
599
0
        bool IsScheduled() const { return mScheduled; }
600
601
0
        Message& Msg() { return mMessage; }
602
0
        const Message& Msg() const { return mMessage; }
603
604
        bool GetAffectedSchedulerGroups(SchedulerGroupSet& aGroups) override;
605
606
    private:
607
        MessageTask() = delete;
608
        MessageTask(const MessageTask&) = delete;
609
0
        ~MessageTask() {}
610
611
        MessageChannel* mChannel;
612
        Message mMessage;
613
        bool mScheduled : 1;
614
    };
615
616
    bool ShouldRunMessage(const Message& aMsg);
617
    void RunMessage(MessageTask& aTask);
618
619
    typedef LinkedList<RefPtr<MessageTask>> MessageQueue;
620
    typedef std::map<size_t, Message> MessageMap;
621
    typedef std::map<size_t, UniquePtr<UntypedCallbackHolder>> CallbackMap;
622
    typedef IPC::Message::msgid_t msgid_t;
623
624
    void WillDestroyCurrentMessageLoop() override;
625
626
  private:
627
    // This will be a string literal, so lifetime is not an issue.
628
    const char* mName;
629
630
    // Based on presumption the listener owns and overlives the channel,
631
    // this is never nullified.
632
    IToplevelProtocol* mListener;
633
    ChannelState mChannelState;
634
    RefPtr<RefCountedMonitor> mMonitor;
635
    Side mSide;
636
    bool mIsCrossProcess;
637
    MessageLink* mLink;
638
    MessageLoop* mWorkerLoop;           // thread where work is done
639
    RefPtr<CancelableRunnable> mChannelErrorTask;  // NotifyMaybeChannelError runnable
640
641
    // Thread we are allowed to send and receive on. This persists even after
642
    // mWorkerLoop is cleared during channel shutdown.
643
    PRThread* mWorkerThread;
644
645
    // Timeout periods are broken up in two to prevent system suspension from
646
    // triggering an abort. This method (called by WaitForEvent with a 'did
647
    // timeout' flag) decides if we should wait again for half of mTimeoutMs
648
    // or give up.
649
    int32_t mTimeoutMs;
650
    bool mInTimeoutSecondHalf;
651
652
    // Worker-thread only; sequence numbers for messages that require
653
    // replies.
654
    int32_t mNextSeqno;
655
656
    static bool sIsPumpingMessages;
657
658
    // If ::Send returns false, this gives a more descriptive error.
659
    SyncSendError mLastSendError;
660
661
    template<class T>
662
    class AutoSetValue {
663
      public:
664
        explicit AutoSetValue(T &var, const T &newValue)
665
          : mVar(var), mPrev(var), mNew(newValue)
666
0
        {
667
0
            mVar = newValue;
668
0
        }
Unexecuted instantiation: mozilla::ipc::MessageChannel::AutoSetValue<mozilla::ipc::MessageChannel*>::AutoSetValue(mozilla::ipc::MessageChannel*&, mozilla::ipc::MessageChannel* const&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::AutoSetValue<bool>::AutoSetValue(bool&, bool const&)
Unexecuted instantiation: mozilla::ipc::MessageChannel::AutoSetValue<int>::AutoSetValue(int&, int const&)
669
0
        ~AutoSetValue() {
670
0
            // The value may have been zeroed if the transaction was
671
0
            // canceled. In that case we shouldn't return it to its previous
672
0
            // value.
673
0
            if (mVar == mNew) {
674
0
                mVar = mPrev;
675
0
            }
676
0
        }
Unexecuted instantiation: mozilla::ipc::MessageChannel::AutoSetValue<mozilla::ipc::MessageChannel*>::~AutoSetValue()
Unexecuted instantiation: mozilla::ipc::MessageChannel::AutoSetValue<bool>::~AutoSetValue()
Unexecuted instantiation: mozilla::ipc::MessageChannel::AutoSetValue<int>::~AutoSetValue()
677
      private:
678
        T& mVar;
679
        T mPrev;
680
        T mNew;
681
    };
682
683
    bool mDispatchingAsyncMessage;
684
    int mDispatchingAsyncMessageNestedLevel;
685
686
    // When we send an urgent request from the parent process, we could race
687
    // with an RPC message that was issued by the child beforehand. In this
688
    // case, if the parent were to wake up while waiting for the urgent reply,
689
    // and process the RPC, it could send an additional urgent message. The
690
    // child would wake up to process the urgent message (as it always will),
691
    // then send a reply, which could be received by the parent out-of-order
692
    // with respect to the first urgent reply.
693
    //
694
    // To address this problem, urgent or RPC requests are associated with a
695
    // "transaction". Whenever one side of the channel wishes to start a
696
    // chain of RPC/urgent messages, it allocates a new transaction ID. Any
697
    // messages the parent receives, not apart of this transaction, are
698
    // deferred. When issuing RPC/urgent requests on top of a started
699
    // transaction, the initiating transaction ID is used.
700
    //
701
    // To ensure IDs are unique, we use sequence numbers for transaction IDs,
702
    // which grow in opposite directions from child to parent.
703
704
    friend class AutoEnterTransaction;
705
    AutoEnterTransaction *mTransactionStack;
706
707
    int32_t CurrentNestedInsideSyncTransaction() const;
708
709
    bool AwaitingSyncReply() const;
710
    int AwaitingSyncReplyNestedLevel() const;
711
712
    bool DispatchingSyncMessage() const;
713
    int DispatchingSyncMessageNestedLevel() const;
714
715
#ifdef DEBUG
716
    void AssertMaybeDeferredCountCorrect();
717
#else
718
0
    void AssertMaybeDeferredCountCorrect() {}
719
#endif
720
721
    // If a sync message times out, we store its sequence number here. Any
722
    // future sync messages will fail immediately. Once the reply for original
723
    // sync message is received, we allow sync messages again.
724
    //
725
    // When a message times out, nothing is done to inform the other side. The
726
    // other side will eventually dispatch the message and send a reply. Our
727
    // side is responsible for replying to all sync messages sent by the other
728
    // side when it dispatches the timed out message. The response is always an
729
    // error.
730
    //
731
    // A message is only timed out if it initiated a transaction. This avoids
732
    // hitting a lot of corner cases with message nesting that we don't really
733
    // care about.
734
    int32_t mTimedOutMessageSeqno;
735
    int mTimedOutMessageNestedLevel;
736
737
    // Queue of all incoming messages.
738
    //
739
    // If both this side and the other side are functioning correctly, the queue
740
    // can only be in certain configurations.  Let
741
    //
742
    //   |A<| be an async in-message,
743
    //   |S<| be a sync in-message,
744
    //   |C<| be an Interrupt in-call,
745
    //   |R<| be an Interrupt reply.
746
    //
747
    // The queue can only match this configuration
748
    //
749
    //  A<* (S< | C< | R< (?{mInterruptStack.size() == 1} A<* (S< | C<)))
750
    //
751
    // The other side can send as many async messages |A<*| as it wants before
752
    // sending us a blocking message.
753
    //
754
    // The first case is |S<|, a sync in-msg.  The other side must be blocked,
755
    // and thus can't send us any more messages until we process the sync
756
    // in-msg.
757
    //
758
    // The second case is |C<|, an Interrupt in-call; the other side must be blocked.
759
    // (There's a subtlety here: this in-call might have raced with an
760
    // out-call, but we detect that with the mechanism below,
761
    // |mRemoteStackDepth|, and races don't matter to the queue.)
762
    //
763
    // Final case, the other side replied to our most recent out-call |R<|.
764
    // If that was the *only* out-call on our stack, |?{mInterruptStack.size() == 1}|,
765
    // then other side "finished with us," and went back to its own business.
766
    // That business might have included sending any number of async message
767
    // |A<*| until sending a blocking message |(S< | C<)|.  If we had more than
768
    // one Interrupt call on our stack, the other side *better* not have sent us
769
    // another blocking message, because it's blocked on a reply from us.
770
    //
771
    MessageQueue mPending;
772
773
    // The number of messages in mPending for which IsAlwaysDeferred is false
774
    // (i.e., the number of messages that might not be deferred, depending on
775
    // context).
776
    size_t mMaybeDeferredPendingCount;
777
778
    // Stack of all the out-calls on which this channel is awaiting responses.
779
    // Each stack refers to a different protocol and the stacks are mutually
780
    // exclusive: multiple outcalls of the same kind cannot be initiated while
781
    // another is active.
782
    std::stack<MessageInfo> mInterruptStack;
783
784
    // This is what we think the Interrupt stack depth is on the "other side" of this
785
    // Interrupt channel.  We maintain this variable so that we can detect racy Interrupt
786
    // calls.  With each Interrupt out-call sent, we send along what *we* think the
787
    // stack depth of the remote side is *before* it will receive the Interrupt call.
788
    //
789
    // After sending the out-call, our stack depth is "incremented" by pushing
790
    // that pending message onto mPending.
791
    //
792
    // Then when processing an in-call |c|, it must be true that
793
    //
794
    //   mInterruptStack.size() == c.remoteDepth
795
    //
796
    // I.e., my depth is actually the same as what the other side thought it
797
    // was when it sent in-call |c|.  If this fails to hold, we have detected
798
    // racy Interrupt calls.
799
    //
800
    // We then increment mRemoteStackDepth *just before* processing the
801
    // in-call, since we know the other side is waiting on it, and decrement
802
    // it *just after* finishing processing that in-call, since our response
803
    // will pop the top of the other side's |mPending|.
804
    //
805
    // One nice aspect of this race detection is that it is symmetric; if one
806
    // side detects a race, then the other side must also detect the same race.
807
    size_t mRemoteStackDepthGuess;
808
809
    // Approximation of code frames on the C++ stack. It can only be
810
    // interpreted as the implication:
811
    //
812
    //  !mCxxStackFrames.empty() => MessageChannel code on C++ stack
813
    //
814
    // This member is only accessed on the worker thread, and so is not
815
    // protected by mMonitor.  It is managed exclusively by the helper
816
    // |class CxxStackFrame|.
817
    mozilla::Vector<InterruptFrame> mCxxStackFrames;
818
819
    // Did we process an Interrupt out-call during this stack?  Only meaningful in
820
    // ExitedCxxStack(), from which this variable is reset.
821
    bool mSawInterruptOutMsg;
822
823
    // Are we waiting on this channel for an incoming message? This is used
824
    // to implement WaitForIncomingMessage(). Must only be accessed while owning
825
    // mMonitor.
826
    bool mIsWaitingForIncoming;
827
828
    // Map of replies received "out of turn", because of Interrupt
829
    // in-calls racing with replies to outstanding in-calls.  See
830
    // https://bugzilla.mozilla.org/show_bug.cgi?id=521929.
831
    MessageMap mOutOfTurnReplies;
832
833
    // Map of async Callbacks that are still waiting replies.
834
    CallbackMap mPendingResponses;
835
836
    // Stack of Interrupt in-calls that were deferred because of race
837
    // conditions.
838
    std::stack<Message> mDeferred;
839
840
#ifdef OS_WIN
841
    HANDLE mEvent;
842
#endif
843
844
    // Should the channel abort the process from the I/O thread when
845
    // a channel error occurs?
846
    bool mAbortOnError;
847
848
    // True if the listener has already been notified of a channel close or
849
    // error.
850
    bool mNotifiedChannelDone;
851
852
    // See SetChannelFlags
853
    ChannelFlags mFlags;
854
855
    // Task and state used to asynchronously notify channel has been connected
856
    // safely.  This is necessary to be able to cancel notification if we are
857
    // closed at the same time.
858
    RefPtr<CancelableRunnable> mOnChannelConnectedTask;
859
    bool mPeerPidSet;
860
    int32_t mPeerPid;
861
862
    // Channels can enter messages are not sent immediately; instead, they are
863
    // held in a queue until another thread deems it is safe to send them.
864
    bool mIsPostponingSends;
865
    std::vector<UniquePtr<Message>> mPostponedSends;
866
867
    bool mInKillHardShutdown;
868
869
    bool mBuildIDsConfirmedMatch;
870
};
871
872
void
873
CancelCPOWs();
874
875
} // namespace ipc
876
} // namespace mozilla
877
878
namespace IPC {
879
template <>
880
struct ParamTraits<mozilla::ipc::ResponseRejectReason>
881
    : public ContiguousEnumSerializer<mozilla::ipc::ResponseRejectReason,
882
                                      mozilla::ipc::ResponseRejectReason::SendError,
883
                                      mozilla::ipc::ResponseRejectReason::EndGuard_>
884
{ };
885
} // namespace IPC
886
887
#endif  // ifndef ipc_glue_MessageChannel_h