Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/ipc/Shmem.h
Line
Count
Source (jump to first uncovered line)
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 http://mozilla.org/MPL/2.0/. */
6
7
#ifndef mozilla_ipc_Shmem_h
8
#define mozilla_ipc_Shmem_h
9
10
#include "mozilla/Attributes.h"
11
12
#include "base/basictypes.h"
13
#include "base/process.h"
14
15
#include "nscore.h"
16
#include "nsDebug.h"
17
18
#include "ipc/IPCMessageUtils.h"
19
#include "mozilla/ipc/SharedMemory.h"
20
#include "mozilla/ipc/IPDLParamTraits.h"
21
22
/**
23
 * |Shmem| is one agent in the IPDL shared memory scheme.  The way it
24
    works is essentially
25
 *
26
 *  (1) C++ code calls, say, |parentActor->AllocShmem(size)|
27
28
 *  (2) IPDL-generated code creates a |mozilla::ipc::SharedMemory|
29
 *  wrapping the bare OS shmem primitives.  The code then adds the new
30
 *  SharedMemory to the set of shmem segments being managed by IPDL.
31
 *
32
 *  (3) IPDL-generated code "shares" the new SharedMemory to the child
33
 *  process, and then sends a special asynchronous IPC message to the
34
 *  child notifying it of the creation of the segment.  (What this
35
 *  means is OS specific.)
36
 *
37
 *  (4a) The child receives the special IPC message, and using the
38
 *  |SharedMemory{Basic}::Handle| it was passed, creates a
39
 *  |mozilla::ipc::SharedMemory| in the child
40
 *  process.
41
 *
42
 *  (4b) After sending the "shmem-created" IPC message, IPDL-generated
43
 *  code in the parent returns a |mozilla::ipc::Shmem| back to the C++
44
 *  caller of |parentActor->AllocShmem()|.  The |Shmem| is a "weak
45
 *  reference" to the underlying |SharedMemory|, which is managed by
46
 *  IPDL-generated code.  C++ consumers of |Shmem| can't get at the
47
 *  underlying |SharedMemory|.
48
 *
49
 * If parent code wants to give access rights to the Shmem to the
50
 * child, it does so by sending its |Shmem| to the child, in an IPDL
51
 * message.  The parent's |Shmem| then "dies", i.e. becomes
52
 * inaccessible.  This process could be compared to passing a
53
 * "shmem-access baton" between parent and child.
54
 */
55
56
namespace mozilla {
57
namespace layers {
58
class ShadowLayerForwarder;
59
} // namespace layers
60
61
namespace ipc {
62
63
class Shmem final
64
{
65
  friend struct IPDLParamTraits<mozilla::ipc::Shmem>;
66
#ifdef DEBUG
67
  // For ShadowLayerForwarder::CheckSurfaceDescriptor
68
  friend class mozilla::layers::ShadowLayerForwarder;
69
#endif
70
71
public:
72
  typedef int32_t id_t;
73
  // Low-level wrapper around platform shmem primitives.
74
  typedef mozilla::ipc::SharedMemory SharedMemory;
75
  typedef SharedMemory::SharedMemoryType SharedMemoryType;
76
  // Shmem objects should only be constructed directly from SharedMemory
77
  // objects by the Shmem implementation itself, or by a select few functions
78
  // in ProtocolUtils.{h,cpp}.  You should not need to add new instances of
79
  // this token.
80
  struct PrivateIPDLCaller {};
81
82
  Shmem() :
83
    mSegment(nullptr),
84
    mData(nullptr),
85
    mSize(0),
86
    mId(0)
87
0
  {
88
0
  }
89
90
  Shmem(const Shmem& aOther) :
91
    mSegment(aOther.mSegment),
92
    mData(aOther.mData),
93
    mSize(aOther.mSize),
94
    mId(aOther.mId)
95
0
  {
96
0
  }
97
98
#if !defined(DEBUG)
99
  Shmem(PrivateIPDLCaller,
100
        SharedMemory* aSegment, id_t aId) :
101
    mSegment(aSegment),
102
    mData(aSegment->memory()),
103
    mSize(0),
104
    mId(aId)
105
  {
106
    mSize = static_cast<size_t>(*PtrToSize(mSegment));
107
  }
108
#else
109
  Shmem(PrivateIPDLCaller,
110
        SharedMemory* aSegment, id_t aId);
111
#endif
112
113
  ~Shmem()
114
0
  {
115
0
    // Shmem only holds a "weak ref" to the actual segment, which is
116
0
    // owned by IPDL. So there's nothing interesting to be done here
117
0
    forget(PrivateIPDLCaller());
118
0
  }
119
120
  Shmem& operator=(const Shmem& aRhs)
121
  {
122
    mSegment = aRhs.mSegment;
123
    mData = aRhs.mData;
124
    mSize = aRhs.mSize;
125
    mId = aRhs.mId;
126
    return *this;
127
  }
128
129
  bool operator==(const Shmem& aRhs) const
130
0
  {
131
0
    return mSegment == aRhs.mSegment;
132
0
  }
133
134
  // Returns whether this Shmem is writable by you, and thus whether you can
135
  // transfer writability to another actor.
136
  bool
137
  IsWritable() const
138
0
  {
139
0
    return mSegment != nullptr;
140
0
  }
141
142
  // Returns whether this Shmem is readable by you, and thus whether you can
143
  // transfer readability to another actor.
144
  bool
145
  IsReadable() const
146
0
  {
147
0
    return mSegment != nullptr;
148
0
  }
149
150
  // Return a pointer to the user-visible data segment.
151
  template<typename T>
152
  T*
153
  get() const
154
0
  {
155
0
    AssertInvariants();
156
0
    AssertAligned<T>();
157
0
158
0
    return reinterpret_cast<T*>(mData);
159
0
  }
Unexecuted instantiation: unsigned char* mozilla::ipc::Shmem::get<unsigned char>() const
Unexecuted instantiation: char* mozilla::ipc::Shmem::get<char>() const
Unexecuted instantiation: mozilla::layers::FixedSizeSmallShmemSectionAllocator::ShmemSectionHeapHeader* mozilla::ipc::Shmem::get<mozilla::layers::FixedSizeSmallShmemSectionAllocator::ShmemSectionHeapHeader>() const
Unexecuted instantiation: mozilla::Atomic<int, (mozilla::MemoryOrdering)2, (mozilla::recordreplay::Behavior)1, void>* mozilla::ipc::Shmem::get<mozilla::Atomic<int, (mozilla::MemoryOrdering)2, (mozilla::recordreplay::Behavior)1, void> >() const
160
161
  // Return the size of the segment as requested when this shmem
162
  // segment was allocated, in units of T.  The underlying mapping may
163
  // actually be larger because of page alignment and private data,
164
  // but this isn't exposed to clients.
165
  template<typename T>
166
  size_t
167
  Size() const
168
0
  {
169
0
    AssertInvariants();
170
0
    AssertAligned<T>();
171
0
172
0
    return mSize / sizeof(T);
173
0
  }
Unexecuted instantiation: unsigned long mozilla::ipc::Shmem::Size<unsigned char>() const
Unexecuted instantiation: unsigned long mozilla::ipc::Shmem::Size<char>() const
174
175
  // These shouldn't be used directly, use the IPDL interface instead.
176
  id_t Id(PrivateIPDLCaller) const {
177
    return mId;
178
  }
179
180
0
  SharedMemory* Segment(PrivateIPDLCaller) const {
181
0
    return mSegment;
182
0
  }
183
184
#ifndef DEBUG
185
  void RevokeRights(PrivateIPDLCaller)
186
  {
187
  }
188
#else
189
  void RevokeRights(PrivateIPDLCaller);
190
#endif
191
192
  void forget(PrivateIPDLCaller)
193
0
  {
194
0
    mSegment = nullptr;
195
0
    mData = nullptr;
196
0
    mSize = 0;
197
0
    mId = 0;
198
0
  }
199
200
  static already_AddRefed<Shmem::SharedMemory>
201
  Alloc(PrivateIPDLCaller,
202
        size_t aNBytes,
203
        SharedMemoryType aType,
204
        bool aUnsafe,
205
        bool aProtect=false);
206
207
  // Prepare this to be shared with |aProcess|.  Return an IPC message
208
  // that contains enough information for the other process to map
209
  // this segment in OpenExisting() below.  Return a new message if
210
  // successful (owned by the caller), nullptr if not.
211
  IPC::Message*
212
  ShareTo(PrivateIPDLCaller,
213
          base::ProcessId aTargetPid,
214
          int32_t routingId);
215
216
  // Stop sharing this with |aTargetPid|.  Return an IPC message that
217
  // contains enough information for the other process to unmap this
218
  // segment.  Return a new message if successful (owned by the
219
  // caller), nullptr if not.
220
  IPC::Message*
221
  UnshareFrom(PrivateIPDLCaller,
222
              int32_t routingId);
223
224
  // Return a SharedMemory instance in this process using the
225
  // descriptor shared to us by the process that created the
226
  // underlying OS shmem resource.  The contents of the descriptor
227
  // depend on the type of SharedMemory that was passed to us.
228
  static already_AddRefed<SharedMemory>
229
  OpenExisting(PrivateIPDLCaller,
230
               const IPC::Message& aDescriptor,
231
               id_t* aId,
232
               bool aProtect=false);
233
234
  static void
235
  Dealloc(PrivateIPDLCaller,
236
          SharedMemory* aSegment);
237
238
private:
239
  template<typename T>
240
  void AssertAligned() const
241
0
  {
242
0
    if (0 != (mSize % sizeof(T)))
243
0
      MOZ_CRASH("shmem is not T-aligned");
244
0
  }
Unexecuted instantiation: void mozilla::ipc::Shmem::AssertAligned<unsigned char>() const
Unexecuted instantiation: void mozilla::ipc::Shmem::AssertAligned<char>() const
Unexecuted instantiation: void mozilla::ipc::Shmem::AssertAligned<mozilla::layers::FixedSizeSmallShmemSectionAllocator::ShmemSectionHeapHeader>() const
Unexecuted instantiation: void mozilla::ipc::Shmem::AssertAligned<mozilla::Atomic<int, (mozilla::MemoryOrdering)2, (mozilla::recordreplay::Behavior)1, void> >() const
245
246
#if !defined(DEBUG)
247
  void AssertInvariants() const
248
0
  { }
249
250
  static uint32_t*
251
  PtrToSize(SharedMemory* aSegment)
252
  {
253
    char* endOfSegment =
254
      reinterpret_cast<char*>(aSegment->memory()) + aSegment->Size();
255
    return reinterpret_cast<uint32_t*>(endOfSegment - sizeof(uint32_t));
256
  }
257
258
#else
259
  void AssertInvariants() const;
260
#endif
261
262
  RefPtr<SharedMemory> mSegment;
263
  void* mData;
264
  size_t mSize;
265
  id_t mId;
266
};
267
268
template<>
269
struct IPDLParamTraits<Shmem>
270
{
271
  typedef Shmem paramType;
272
273
  static void Write(IPC::Message* aMsg, IProtocol* aActor, paramType& aParam);
274
  static bool Read(const IPC::Message* aMsg, PickleIterator* aIter, IProtocol* aActor, paramType* aResult);
275
276
  static void Log(const paramType& aParam, std::wstring* aLog)
277
0
  {
278
0
    aLog->append(L"(shmem segment)");
279
0
  }
280
};
281
282
} // namespace ipc
283
} // namespace mozilla
284
285
#endif // ifndef mozilla_ipc_Shmem_h