Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/ipc/StructuredCloneData.cpp
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
#include "StructuredCloneData.h"
8
9
#include "nsIMutable.h"
10
#include "nsIXPConnect.h"
11
12
#include "ipc/IPCMessageUtils.h"
13
#include "mozilla/dom/BindingUtils.h"
14
#include "mozilla/dom/BlobBinding.h"
15
#include "mozilla/dom/DOMTypes.h"
16
#include "mozilla/dom/File.h"
17
#include "mozilla/dom/IPCBlobUtils.h"
18
#include "mozilla/ipc/BackgroundParent.h"
19
#include "mozilla/ipc/IPCStreamUtils.h"
20
#include "nsContentUtils.h"
21
#include "nsJSEnvironment.h"
22
#include "MainThreadUtils.h"
23
#include "StructuredCloneTags.h"
24
#include "jsapi.h"
25
26
using namespace mozilla::ipc;
27
28
namespace mozilla {
29
namespace dom {
30
namespace ipc {
31
32
using mozilla::ipc::AutoIPCStream;
33
using mozilla::ipc::IPCStream;
34
using mozilla::ipc::PBackgroundChild;
35
using mozilla::ipc::PBackgroundParent;
36
37
StructuredCloneData::StructuredCloneData()
38
  : StructuredCloneData(StructuredCloneHolder::TransferringSupported)
39
0
{}
40
41
StructuredCloneData::StructuredCloneData(StructuredCloneData&& aOther)
42
  : StructuredCloneData(StructuredCloneHolder::TransferringSupported)
43
0
{
44
0
  *this = std::move(aOther);
45
0
}
46
47
StructuredCloneData::StructuredCloneData(TransferringSupport aSupportsTransferring)
48
  : StructuredCloneHolder(StructuredCloneHolder::CloningSupported,
49
                          aSupportsTransferring,
50
                          StructuredCloneHolder::StructuredCloneScope::DifferentProcess)
51
  , mExternalData(JS::StructuredCloneScope::DifferentProcess)
52
  , mInitialized(false)
53
0
{}
54
55
StructuredCloneData::~StructuredCloneData()
56
0
{}
57
58
StructuredCloneData&
59
StructuredCloneData::operator=(StructuredCloneData&& aOther)
60
0
{
61
0
  mBlobImplArray = std::move(aOther.mBlobImplArray);
62
0
  mExternalData = std::move(aOther.mExternalData);
63
0
  mSharedData = std::move(aOther.mSharedData);
64
0
  mIPCStreams = std::move(aOther.mIPCStreams);
65
0
  mInitialized = aOther.mInitialized;
66
0
67
0
  return *this;
68
0
}
69
70
bool
71
StructuredCloneData::Copy(const StructuredCloneData& aData)
72
0
{
73
0
  if (!aData.mInitialized) {
74
0
    return true;
75
0
  }
76
0
77
0
  if (aData.SharedData()) {
78
0
    mSharedData = aData.SharedData();
79
0
  } else {
80
0
    mSharedData =
81
0
      SharedJSAllocatedData::CreateFromExternalData(aData.Data());
82
0
    NS_ENSURE_TRUE(mSharedData, false);
83
0
  }
84
0
85
0
  if (mSupportsTransferring) {
86
0
    PortIdentifiers().AppendElements(aData.PortIdentifiers());
87
0
  }
88
0
89
0
  MOZ_ASSERT(BlobImpls().IsEmpty());
90
0
  BlobImpls().AppendElements(aData.BlobImpls());
91
0
92
0
  MOZ_ASSERT(GetSurfaces().IsEmpty());
93
0
  MOZ_ASSERT(WasmModules().IsEmpty());
94
0
95
0
  MOZ_ASSERT(InputStreams().IsEmpty());
96
0
  InputStreams().AppendElements(aData.InputStreams());
97
0
98
0
  mInitialized = true;
99
0
100
0
  return true;
101
0
}
102
103
void
104
StructuredCloneData::Read(JSContext* aCx,
105
                          JS::MutableHandle<JS::Value> aValue,
106
                          ErrorResult &aRv)
107
0
{
108
0
  MOZ_ASSERT(mInitialized);
109
0
110
0
  nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
111
0
  MOZ_ASSERT(global);
112
0
113
0
  ReadFromBuffer(global, aCx, Data(), aValue, aRv);
114
0
}
115
116
void
117
StructuredCloneData::Write(JSContext* aCx,
118
                           JS::Handle<JS::Value> aValue,
119
                           ErrorResult &aRv)
120
0
{
121
0
  Write(aCx, aValue, JS::UndefinedHandleValue, aRv);
122
0
}
123
124
void
125
StructuredCloneData::Write(JSContext* aCx,
126
                           JS::Handle<JS::Value> aValue,
127
                           JS::Handle<JS::Value> aTransfer,
128
                           ErrorResult &aRv)
129
0
{
130
0
  MOZ_ASSERT(!mInitialized);
131
0
132
0
  StructuredCloneHolder::Write(aCx, aValue, aTransfer,
133
0
                               JS::CloneDataPolicy().denySharedArrayBuffer(), aRv);
134
0
  if (NS_WARN_IF(aRv.Failed())) {
135
0
    return;
136
0
  }
137
0
138
0
  JSStructuredCloneData data(mBuffer->scope());
139
0
  mBuffer->abandon();
140
0
  mBuffer->steal(&data);
141
0
  mBuffer = nullptr;
142
0
  mSharedData = new SharedJSAllocatedData(std::move(data));
143
0
  mInitialized = true;
144
0
}
145
146
enum ActorFlavorEnum {
147
  Parent = 0,
148
  Child,
149
};
150
151
enum ManagerFlavorEnum {
152
  ContentProtocol = 0,
153
  BackgroundProtocol
154
};
155
156
template<typename M>
157
bool
158
BuildClonedMessageData(M* aManager, StructuredCloneData& aData,
159
                       ClonedMessageData& aClonedData)
160
0
{
161
0
  SerializedStructuredCloneBuffer& buffer = aClonedData.data();
162
0
  auto iter = aData.Data().Start();
163
0
  size_t size = aData.Data().Size();
164
0
  bool success;
165
0
  buffer.data = aData.Data().Borrow(iter, size, &success);
166
0
  if (NS_WARN_IF(!success)) {
167
0
    return false;
168
0
  }
169
0
  if (aData.SupportsTransferring()) {
170
0
    aClonedData.identfiers().AppendElements(aData.PortIdentifiers());
171
0
  }
172
0
173
0
  const nsTArray<RefPtr<BlobImpl>>& blobImpls = aData.BlobImpls();
174
0
175
0
  if (!blobImpls.IsEmpty()) {
176
0
    if (NS_WARN_IF(!aClonedData.blobs().SetLength(blobImpls.Length(), fallible))) {
177
0
      return false;
178
0
    }
179
0
180
0
    for (uint32_t i = 0; i < blobImpls.Length(); ++i) {
181
0
      nsresult rv = IPCBlobUtils::Serialize(blobImpls[i], aManager,
182
0
                                            aClonedData.blobs()[i]);
183
0
      if (NS_WARN_IF(NS_FAILED(rv))) {
184
0
        return false;
185
0
      }
186
0
    }
187
0
  }
188
0
189
0
  const nsTArray<nsCOMPtr<nsIInputStream>>& inputStreams = aData.InputStreams();
190
0
  if (!inputStreams.IsEmpty()) {
191
0
    if (NS_WARN_IF(!aData.IPCStreams().SetCapacity(inputStreams.Length(),
192
0
                                                   fallible))) {
193
0
      return false;
194
0
    }
195
0
196
0
    InfallibleTArray<IPCStream>& streams = aClonedData.inputStreams();
197
0
    uint32_t length = inputStreams.Length();
198
0
    streams.SetCapacity(length);
199
0
    for (uint32_t i = 0; i < length; ++i) {
200
0
      AutoIPCStream* stream = aData.IPCStreams().AppendElement(fallible);
201
0
      if (NS_WARN_IF(!stream)) {
202
0
        return false;
203
0
      }
204
0
205
0
      if (!stream->Serialize(inputStreams[i], aManager)) {
206
0
        return false;
207
0
      }
208
0
      streams.AppendElement(stream->TakeValue());
209
0
    }
210
0
  }
211
0
212
0
  return true;
213
0
}
Unexecuted instantiation: bool mozilla::dom::ipc::BuildClonedMessageData<mozilla::dom::nsIContentParent>(mozilla::dom::nsIContentParent*, mozilla::dom::ipc::StructuredCloneData&, mozilla::dom::ClonedMessageData&)
Unexecuted instantiation: bool mozilla::dom::ipc::BuildClonedMessageData<mozilla::dom::nsIContentChild>(mozilla::dom::nsIContentChild*, mozilla::dom::ipc::StructuredCloneData&, mozilla::dom::ClonedMessageData&)
Unexecuted instantiation: bool mozilla::dom::ipc::BuildClonedMessageData<mozilla::ipc::PBackgroundParent>(mozilla::ipc::PBackgroundParent*, mozilla::dom::ipc::StructuredCloneData&, mozilla::dom::ClonedMessageData&)
Unexecuted instantiation: bool mozilla::dom::ipc::BuildClonedMessageData<mozilla::ipc::PBackgroundChild>(mozilla::ipc::PBackgroundChild*, mozilla::dom::ipc::StructuredCloneData&, mozilla::dom::ClonedMessageData&)
214
215
bool
216
StructuredCloneData::BuildClonedMessageDataForParent(
217
  nsIContentParent* aParent,
218
  ClonedMessageData& aClonedData)
219
0
{
220
0
  return BuildClonedMessageData(aParent, *this, aClonedData);
221
0
}
222
223
bool
224
StructuredCloneData::BuildClonedMessageDataForChild(
225
  nsIContentChild* aChild,
226
  ClonedMessageData& aClonedData)
227
0
{
228
0
  return BuildClonedMessageData(aChild, *this, aClonedData);
229
0
}
230
231
bool
232
StructuredCloneData::BuildClonedMessageDataForBackgroundParent(
233
  PBackgroundParent* aParent,
234
  ClonedMessageData& aClonedData)
235
0
{
236
0
  return BuildClonedMessageData(aParent, *this, aClonedData);
237
0
}
238
239
bool
240
StructuredCloneData::BuildClonedMessageDataForBackgroundChild(
241
  PBackgroundChild* aChild,
242
  ClonedMessageData& aClonedData)
243
0
{
244
0
  return BuildClonedMessageData(aChild, *this, aClonedData);
245
0
}
246
247
// See the StructuredCloneData class block comment for the meanings of each val.
248
enum MemoryFlavorEnum {
249
  BorrowMemory = 0,
250
  CopyMemory,
251
  StealMemory
252
};
253
254
template<MemoryFlavorEnum>
255
struct MemoryTraits
256
{ };
257
258
template<>
259
struct MemoryTraits<BorrowMemory>
260
{
261
  typedef const mozilla::dom::ClonedMessageData ClonedMessageType;
262
263
  static void ProvideBuffer(const ClonedMessageData& aClonedData,
264
                            StructuredCloneData& aData)
265
0
  {
266
0
    const SerializedStructuredCloneBuffer& buffer = aClonedData.data();
267
0
    aData.UseExternalData(buffer.data);
268
0
  }
269
};
270
271
template<>
272
struct MemoryTraits<CopyMemory>
273
{
274
  typedef const mozilla::dom::ClonedMessageData ClonedMessageType;
275
276
  static void ProvideBuffer(const ClonedMessageData& aClonedData,
277
                            StructuredCloneData& aData)
278
0
  {
279
0
    const SerializedStructuredCloneBuffer& buffer = aClonedData.data();
280
0
    aData.CopyExternalData(buffer.data);
281
0
  }
282
};
283
284
template<>
285
struct MemoryTraits<StealMemory>
286
{
287
  // note: not const!
288
  typedef mozilla::dom::ClonedMessageData ClonedMessageType;
289
290
  static void ProvideBuffer(ClonedMessageData& aClonedData,
291
                            StructuredCloneData& aData)
292
0
  {
293
0
    SerializedStructuredCloneBuffer& buffer = aClonedData.data();
294
0
    aData.StealExternalData(buffer.data);
295
0
  }
296
};
297
298
// Note that there isn't actually a difference between Parent/BackgroundParent
299
// and Child/BackgroundChild in this implementation.  The calling methods,
300
// however, do maintain the distinction for code-reading purposes and are backed
301
// by assertions to enforce there is no misuse.
302
template<MemoryFlavorEnum MemoryFlavor, ActorFlavorEnum Flavor>
303
static void
304
UnpackClonedMessageData(typename MemoryTraits<MemoryFlavor>::ClonedMessageType& aClonedData,
305
                        StructuredCloneData& aData)
306
0
{
307
0
  const InfallibleTArray<MessagePortIdentifier>& identifiers = aClonedData.identfiers();
308
0
309
0
  MemoryTraits<MemoryFlavor>::ProvideBuffer(aClonedData, aData);
310
0
311
0
  if (aData.SupportsTransferring()) {
312
0
    aData.PortIdentifiers().AppendElements(identifiers);
313
0
  }
314
0
315
0
  const nsTArray<IPCBlob>& blobs = aClonedData.blobs();
316
0
  if (!blobs.IsEmpty()) {
317
0
    uint32_t length = blobs.Length();
318
0
    aData.BlobImpls().SetCapacity(length);
319
0
    for (uint32_t i = 0; i < length; ++i) {
320
0
      RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(blobs[i]);
321
0
      MOZ_ASSERT(blobImpl);
322
0
323
0
      aData.BlobImpls().AppendElement(blobImpl);
324
0
    }
325
0
  }
326
0
327
0
  const InfallibleTArray<IPCStream>& streams = aClonedData.inputStreams();
328
0
  if (!streams.IsEmpty()) {
329
0
    uint32_t length = streams.Length();
330
0
    aData.InputStreams().SetCapacity(length);
331
0
    for (uint32_t i = 0; i < length; ++i) {
332
0
      nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(streams[i]);
333
0
      aData.InputStreams().AppendElement(stream);
334
0
    }
335
0
  }
336
0
}
Unexecuted instantiation: Unified_cpp_dom_ipc1.cpp:void mozilla::dom::ipc::UnpackClonedMessageData<(mozilla::dom::ipc::MemoryFlavorEnum)0, (mozilla::dom::ipc::ActorFlavorEnum)0>(mozilla::dom::ipc::MemoryTraits<(mozilla::dom::ipc::MemoryFlavorEnum)0>::ClonedMessageType&, mozilla::dom::ipc::StructuredCloneData&)
Unexecuted instantiation: Unified_cpp_dom_ipc1.cpp:void mozilla::dom::ipc::UnpackClonedMessageData<(mozilla::dom::ipc::MemoryFlavorEnum)0, (mozilla::dom::ipc::ActorFlavorEnum)1>(mozilla::dom::ipc::MemoryTraits<(mozilla::dom::ipc::MemoryFlavorEnum)0>::ClonedMessageType&, mozilla::dom::ipc::StructuredCloneData&)
Unexecuted instantiation: Unified_cpp_dom_ipc1.cpp:void mozilla::dom::ipc::UnpackClonedMessageData<(mozilla::dom::ipc::MemoryFlavorEnum)1, (mozilla::dom::ipc::ActorFlavorEnum)0>(mozilla::dom::ipc::MemoryTraits<(mozilla::dom::ipc::MemoryFlavorEnum)1>::ClonedMessageType&, mozilla::dom::ipc::StructuredCloneData&)
Unexecuted instantiation: Unified_cpp_dom_ipc1.cpp:void mozilla::dom::ipc::UnpackClonedMessageData<(mozilla::dom::ipc::MemoryFlavorEnum)1, (mozilla::dom::ipc::ActorFlavorEnum)1>(mozilla::dom::ipc::MemoryTraits<(mozilla::dom::ipc::MemoryFlavorEnum)1>::ClonedMessageType&, mozilla::dom::ipc::StructuredCloneData&)
Unexecuted instantiation: Unified_cpp_dom_ipc1.cpp:void mozilla::dom::ipc::UnpackClonedMessageData<(mozilla::dom::ipc::MemoryFlavorEnum)2, (mozilla::dom::ipc::ActorFlavorEnum)0>(mozilla::dom::ipc::MemoryTraits<(mozilla::dom::ipc::MemoryFlavorEnum)2>::ClonedMessageType&, mozilla::dom::ipc::StructuredCloneData&)
Unexecuted instantiation: Unified_cpp_dom_ipc1.cpp:void mozilla::dom::ipc::UnpackClonedMessageData<(mozilla::dom::ipc::MemoryFlavorEnum)2, (mozilla::dom::ipc::ActorFlavorEnum)1>(mozilla::dom::ipc::MemoryTraits<(mozilla::dom::ipc::MemoryFlavorEnum)2>::ClonedMessageType&, mozilla::dom::ipc::StructuredCloneData&)
337
338
void
339
StructuredCloneData::BorrowFromClonedMessageDataForParent(const ClonedMessageData& aClonedData)
340
0
{
341
0
  // PContent parent is always main thread and actor constraints demand we're
342
0
  // likewise on that thread.
343
0
  MOZ_ASSERT(NS_IsMainThread());
344
0
  UnpackClonedMessageData<BorrowMemory, Parent>(aClonedData, *this);
345
0
}
346
347
void
348
StructuredCloneData::BorrowFromClonedMessageDataForChild(const ClonedMessageData& aClonedData)
349
0
{
350
0
  // PContent child is always main thread and actor constraints demand we're
351
0
  // likewise on that thread.
352
0
  MOZ_ASSERT(NS_IsMainThread());
353
0
  UnpackClonedMessageData<BorrowMemory, Child>(aClonedData, *this);
354
0
}
355
356
void
357
StructuredCloneData::BorrowFromClonedMessageDataForBackgroundParent(const ClonedMessageData& aClonedData)
358
0
{
359
0
  MOZ_ASSERT(IsOnBackgroundThread());
360
0
  UnpackClonedMessageData<BorrowMemory, Parent>(aClonedData, *this);
361
0
}
362
363
void
364
StructuredCloneData::BorrowFromClonedMessageDataForBackgroundChild(const ClonedMessageData& aClonedData)
365
0
{
366
0
  // No thread assertion; BackgroundChild can happen on any thread.
367
0
  UnpackClonedMessageData<BorrowMemory, Child>(aClonedData, *this);
368
0
}
369
370
void
371
StructuredCloneData::CopyFromClonedMessageDataForParent(const ClonedMessageData& aClonedData)
372
0
{
373
0
  MOZ_ASSERT(NS_IsMainThread());
374
0
  UnpackClonedMessageData<CopyMemory, Parent>(aClonedData, *this);
375
0
}
376
377
void
378
StructuredCloneData::CopyFromClonedMessageDataForChild(const ClonedMessageData& aClonedData)
379
0
{
380
0
  MOZ_ASSERT(NS_IsMainThread());
381
0
  UnpackClonedMessageData<CopyMemory, Child>(aClonedData, *this);
382
0
}
383
384
void
385
StructuredCloneData::CopyFromClonedMessageDataForBackgroundParent(const ClonedMessageData& aClonedData)
386
0
{
387
0
  MOZ_ASSERT(IsOnBackgroundThread());
388
0
  UnpackClonedMessageData<CopyMemory, Parent>(aClonedData, *this);
389
0
}
390
391
void
392
StructuredCloneData::CopyFromClonedMessageDataForBackgroundChild(const ClonedMessageData& aClonedData)
393
0
{
394
0
  UnpackClonedMessageData<CopyMemory, Child>(aClonedData, *this);
395
0
}
396
397
void
398
StructuredCloneData::StealFromClonedMessageDataForParent(ClonedMessageData& aClonedData)
399
0
{
400
0
  MOZ_ASSERT(NS_IsMainThread());
401
0
  UnpackClonedMessageData<StealMemory, Parent>(aClonedData, *this);
402
0
}
403
404
void
405
StructuredCloneData::StealFromClonedMessageDataForChild(ClonedMessageData& aClonedData)
406
0
{
407
0
  MOZ_ASSERT(NS_IsMainThread());
408
0
  UnpackClonedMessageData<StealMemory, Child>(aClonedData, *this);
409
0
}
410
411
void
412
StructuredCloneData::StealFromClonedMessageDataForBackgroundParent(ClonedMessageData& aClonedData)
413
0
{
414
0
  MOZ_ASSERT(IsOnBackgroundThread());
415
0
  UnpackClonedMessageData<StealMemory, Parent>(aClonedData, *this);
416
0
}
417
418
void
419
StructuredCloneData::StealFromClonedMessageDataForBackgroundChild(ClonedMessageData& aClonedData)
420
0
{
421
0
  UnpackClonedMessageData<StealMemory, Child>(aClonedData, *this);
422
0
}
423
424
425
void
426
StructuredCloneData::WriteIPCParams(IPC::Message* aMsg) const
427
0
{
428
0
  WriteParam(aMsg, Data());
429
0
}
430
431
bool
432
StructuredCloneData::ReadIPCParams(const IPC::Message* aMsg,
433
                                   PickleIterator* aIter)
434
0
{
435
0
  MOZ_ASSERT(!mInitialized);
436
0
  JSStructuredCloneData data(JS::StructuredCloneScope::DifferentProcess);
437
0
  if (!ReadParam(aMsg, aIter, &data)) {
438
0
    return false;
439
0
  }
440
0
  mSharedData = new SharedJSAllocatedData(std::move(data));
441
0
  mInitialized = true;
442
0
  return true;
443
0
}
444
445
bool
446
StructuredCloneData::CopyExternalData(const char* aData,
447
                                      size_t aDataLength)
448
0
{
449
0
  MOZ_ASSERT(!mInitialized);
450
0
  mSharedData = SharedJSAllocatedData::CreateFromExternalData(aData,
451
0
                                                              aDataLength);
452
0
  NS_ENSURE_TRUE(mSharedData, false);
453
0
  mInitialized = true;
454
0
  return true;
455
0
}
456
457
bool
458
StructuredCloneData::CopyExternalData(const JSStructuredCloneData& aData)
459
0
{
460
0
  MOZ_ASSERT(!mInitialized);
461
0
  mSharedData = SharedJSAllocatedData::CreateFromExternalData(aData);
462
0
  NS_ENSURE_TRUE(mSharedData, false);
463
0
  mInitialized = true;
464
0
  return true;
465
0
}
466
467
bool
468
StructuredCloneData::StealExternalData(JSStructuredCloneData& aData)
469
0
{
470
0
  MOZ_ASSERT(!mInitialized);
471
0
  mSharedData = new SharedJSAllocatedData(std::move(aData));
472
0
  mInitialized = true;
473
0
  return true;
474
0
}
475
476
already_AddRefed<SharedJSAllocatedData>
477
StructuredCloneData::TakeSharedData()
478
0
{
479
0
  return mSharedData.forget();
480
0
}
481
482
} // namespace ipc
483
} // namespace dom
484
} // namespace mozilla