File: Shmem.cpp

package info (click to toggle)
firefox 147.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,683,324 kB
  • sloc: cpp: 7,607,156; javascript: 6,532,492; ansic: 3,775,158; python: 1,415,368; xml: 634,556; asm: 438,949; java: 186,241; sh: 62,751; makefile: 18,079; objc: 13,092; perl: 12,808; yacc: 4,583; cs: 3,846; pascal: 3,448; lex: 1,720; ruby: 1,003; php: 436; lisp: 258; awk: 247; sql: 66; sed: 54; csh: 10; exp: 6
file content (217 lines) | stat: -rw-r--r-- 6,140 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "Shmem.h"

#include "ProtocolUtils.h"
#include "ShmemMessageUtils.h"
#include "chrome/common/ipc_message_utils.h"
#include "mozilla/ipc/SharedMemoryHandle.h"

namespace mozilla {
namespace ipc {

class ShmemCreated : public IPC::Message {
 private:
  typedef Shmem::id_t id_t;

 public:
  ShmemCreated(routeid_t routingId, id_t aIPDLId,
               MutableSharedMemoryHandle&& aHandle)
      : IPC::Message(
            routingId, SHMEM_CREATED_MESSAGE_TYPE, 0,
            HeaderFlags(NESTED_INSIDE_CPOW, CONTROL_PRIORITY, COMPRESSION_NONE,
                        LAZY_SEND, NOT_CONSTRUCTOR, ASYNC, NOT_REPLY)) {
    IPC::MessageWriter writer(*this);
    IPC::WriteParam(&writer, aIPDLId);
    IPC::WriteParam(&writer, std::move(aHandle));
  }

  static bool ReadInfo(IPC::MessageReader* aReader, id_t* aIPDLId,
                       MutableSharedMemoryHandle* aHandle) {
    return IPC::ReadParam(aReader, aIPDLId) && IPC::ReadParam(aReader, aHandle);
  }

  void Log(const std::string& aPrefix, FILE* aOutf) const {
    fputs("(special ShmemCreated msg)", aOutf);
  }
};

class ShmemDestroyed : public IPC::Message {
 private:
  typedef Shmem::id_t id_t;

 public:
  ShmemDestroyed(routeid_t routingId, id_t aIPDLId)
      : IPC::Message(
            routingId, SHMEM_DESTROYED_MESSAGE_TYPE, 0,
            HeaderFlags(NOT_NESTED, NORMAL_PRIORITY, COMPRESSION_NONE,
                        LAZY_SEND, NOT_CONSTRUCTOR, ASYNC, NOT_REPLY)) {
    IPC::MessageWriter writer(*this);
    IPC::WriteParam(&writer, aIPDLId);
  }
};

#if defined(DEBUG)

static void Protect(const Shmem::Segment* aSegment) {
  MOZ_ASSERT(aSegment && *aSegment, "null segment");
  shared_memory::LocalProtect(aSegment->DataAs<char>(), aSegment->Size(),
                              shared_memory::AccessNone);
}

static void Unprotect(const Shmem::Segment* aSegment) {
  MOZ_ASSERT(aSegment && *aSegment, "null segment");
  shared_memory::LocalProtect(aSegment->DataAs<char>(), aSegment->Size(),
                              shared_memory::AccessReadWrite);
}

void Shmem::AssertInvariants() const {
  MOZ_ASSERT(mSegment, "null segment");
  MOZ_ASSERT(mData, "null data pointer");
  MOZ_ASSERT(mSize > 0, "invalid size");
  // if the segment isn't owned by the current process, these will
  // trigger SIGSEGV
  char checkMappingFront = *reinterpret_cast<char*>(mData);
  char checkMappingBack = *(reinterpret_cast<char*>(mData) + mSize - 1);

  // avoid "unused" warnings for these variables:
  (void)checkMappingFront;
  (void)checkMappingBack;
}

void Shmem::RevokeRights() {
  AssertInvariants();

  // When sending a non-unsafe shmem, remove read/write rights from the local
  // mapping of the segment.
  if (!mUnsafe) {
    Protect(mSegment);
  }
}

#endif  // if defined(DEBUG)

Shmem::Shmem(RefPtr<Segment>&& aSegment, id_t aId, size_t aSize, bool aUnsafe)
    : mSegment(std::move(aSegment)),
      mData(mSegment->Address()),
      mSize(aSize),
      mId(aId) {
#ifdef DEBUG
  mUnsafe = aUnsafe;
  Unprotect(mSegment);
#endif

  MOZ_RELEASE_ASSERT(mSegment->Size() >= mSize,
                     "illegal size in shared memory segment");
}

Shmem::Builder::Builder(size_t aSize) : mSize(aSize) {
  if (!aSize) {
    return;
  }
  size_t pageAlignedSize = shared_memory::PageAlignedSize(aSize);
  mHandle = shared_memory::Create(pageAlignedSize);
  if (!mHandle) {
    return;
  }
  auto mapping = mHandle.Map();
  if (!mapping) {
    return;
  }
  mSegment = MakeAndAddRef<Segment>(std::move(mapping));
}

std::tuple<UniquePtr<IPC::Message>, Shmem> Shmem::Builder::Build(
    id_t aId, bool aUnsafe, IPC::Message::routeid_t aRoutingId) {
  Shmem shmem(std::move(mSegment), aId, mSize, aUnsafe);
  shmem.AssertInvariants();
  MOZ_ASSERT(mHandle, "null shmem handle");

  auto msg = MakeUnique<ShmemCreated>(aRoutingId, aId, std::move(mHandle));
  return std::make_tuple(std::move(msg), std::move(shmem));
}

// static
already_AddRefed<Shmem::Segment> Shmem::OpenExisting(
    const IPC::Message& aDescriptor, id_t* aId, bool /*unused*/) {
  if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) {
    NS_ERROR("expected 'shmem created' message");
    return nullptr;
  }
  MutableSharedMemoryHandle handle;
  IPC::MessageReader reader(aDescriptor);
  if (!ShmemCreated::ReadInfo(&reader, aId, &handle)) {
    return nullptr;
  }
  reader.EndRead();
  if (!handle) {
    return nullptr;
  }

  auto mapping = handle.Map();
  if (!mapping) {
    return nullptr;
  }
  return MakeAndAddRef<Shmem::Segment>(std::move(mapping));
}

UniquePtr<IPC::Message> Shmem::MkDestroyedMessage(
    IPC::Message::routeid_t routingId) {
  AssertInvariants();
  return MakeUnique<ShmemDestroyed>(routingId, mId);
}

}  // namespace ipc
}  // namespace mozilla

namespace IPC {

void ParamTraits<mozilla::ipc::Shmem>::Write(IPC::MessageWriter* aWriter,
                                             paramType&& aParam) {
  WriteParam(aWriter, aParam.mId);
  WriteParam(aWriter, uint32_t(aParam.mSize));
#ifdef DEBUG
  WriteParam(aWriter, aParam.mUnsafe);
#endif

  aParam.RevokeRights();
  aParam.forget();
}

bool ParamTraits<mozilla::ipc::Shmem>::Read(IPC::MessageReader* aReader,
                                            paramType* aResult) {
  if (!aReader->GetActor()) {
    return false;
  }

  paramType::id_t id;
  uint32_t size;
  if (!ReadParam(aReader, &id) || !ReadParam(aReader, &size)) {
    return false;
  }

  bool unsafe = false;
#ifdef DEBUG
  if (!ReadParam(aReader, &unsafe)) {
    return false;
  }
#endif

  auto* segment = aReader->GetActor()->LookupSharedMemory(id);
  if (segment) {
    if (size > segment->Size()) {
      return false;
    }

    *aResult = mozilla::ipc::Shmem(segment, id, size, unsafe);
    return true;
  }
  *aResult = mozilla::ipc::Shmem();
  return true;
}

}  // namespace IPC