summaryrefslogtreecommitdiff
path: root/base/memory/shared_memory_handle.h
blob: dd3d47aa0cf6abc003a63cd12a5fbe9f10cf27e5 (plain)
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
#define BASE_MEMORY_SHARED_MEMORY_HANDLE_H_

#include <stddef.h>

#include "base/unguessable_token.h"
#include "build/build_config.h"

#if defined(OS_WIN)
#include "base/process/process_handle.h"
#include "base/win/windows_types.h"
#elif defined(OS_MACOSX) && !defined(OS_IOS)
#include <mach/mach.h>
#include "base/base_export.h"
#include "base/file_descriptor_posix.h"
#include "base/macros.h"
#include "base/process/process_handle.h"
#elif defined(OS_POSIX)
#include <sys/types.h>
#include "base/file_descriptor_posix.h"
#elif defined(OS_FUCHSIA)
#include <zircon/types.h>
#endif

namespace base {

// SharedMemoryHandle is the smallest possible IPC-transportable "reference" to
// a shared memory OS resource. A "reference" can be consumed exactly once [by
// base::SharedMemory] to map the shared memory OS resource into the virtual
// address space of the current process.
// TODO(erikchen): This class should have strong ownership semantics to prevent
// leaks of the underlying OS resource. https://crbug.com/640840.
class BASE_EXPORT SharedMemoryHandle {
 public:
  // The default constructor returns an invalid SharedMemoryHandle.
  SharedMemoryHandle();

  // Standard copy constructor. The new instance shares the underlying OS
  // primitives.
  SharedMemoryHandle(const SharedMemoryHandle& handle);

  // Standard assignment operator. The updated instance shares the underlying
  // OS primitives.
  SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);

  // Closes the underlying OS resource.
  // The fact that this method needs to be "const" is an artifact of the
  // original interface for base::SharedMemory::CloseHandle.
  // TODO(erikchen): This doesn't clear the underlying reference, which seems
  // like a bug, but is how this class has always worked. Fix this:
  // https://crbug.com/716072.
  void Close() const;

  // Whether ownership of the underlying OS resource is implicitly passed to
  // the IPC subsystem during serialization.
  void SetOwnershipPassesToIPC(bool ownership_passes);
  bool OwnershipPassesToIPC() const;

  // Whether the underlying OS resource is valid.
  bool IsValid() const;

  // Duplicates the underlying OS resource. Using the return value as a
  // parameter to an IPC message will cause the IPC subsystem to consume the OS
  // resource.
  SharedMemoryHandle Duplicate() const;

  // Uniques identifies the shared memory region that the underlying OS resource
  // points to. Multiple SharedMemoryHandles that point to the same shared
  // memory region will have the same GUID. Preserved across IPC.
  base::UnguessableToken GetGUID() const;

  // Returns the size of the memory region that SharedMemoryHandle points to.
  size_t GetSize() const;

#if defined(OS_WIN)
  // Takes implicit ownership of |h|.
  // |guid| uniquely identifies the shared memory region pointed to by the
  // underlying OS resource. If the HANDLE is associated with another
  // SharedMemoryHandle, the caller must pass the |guid| of that
  // SharedMemoryHandle. Otherwise, the caller should generate a new
  // UnguessableToken.
  // Passing the wrong |size| has no immediate consequence, but may cause errors
  // when trying to map the SharedMemoryHandle at a later point in time.
  SharedMemoryHandle(HANDLE h, size_t size, const base::UnguessableToken& guid);
  HANDLE GetHandle() const;
#elif defined(OS_FUCHSIA)
  // Takes implicit ownership of |h|.
  // |guid| uniquely identifies the shared memory region pointed to by the
  // underlying OS resource. If the zx_handle_t is associated with another
  // SharedMemoryHandle, the caller must pass the |guid| of that
  // SharedMemoryHandle. Otherwise, the caller should generate a new
  // UnguessableToken.
  // Passing the wrong |size| has no immediate consequence, but may cause errors
  // when trying to map the SharedMemoryHandle at a later point in time.
  SharedMemoryHandle(zx_handle_t h,
                     size_t size,
                     const base::UnguessableToken& guid);
  zx_handle_t GetHandle() const;
#elif defined(OS_MACOSX) && !defined(OS_IOS)
  enum Type {
    // The SharedMemoryHandle is backed by a POSIX fd.
    POSIX,
    // The SharedMemoryHandle is backed by the Mach primitive "memory object".
    MACH,
  };

  // Makes a Mach-based SharedMemoryHandle of the given size. On error,
  // subsequent calls to IsValid() return false.
  // Passing the wrong |size| has no immediate consequence, but may cause errors
  // when trying to map the SharedMemoryHandle at a later point in time.
  SharedMemoryHandle(mach_vm_size_t size, const base::UnguessableToken& guid);

  // Makes a Mach-based SharedMemoryHandle from |memory_object|, a named entry
  // in the current task. The memory region has size |size|.
  // Passing the wrong |size| has no immediate consequence, but may cause errors
  // when trying to map the SharedMemoryHandle at a later point in time.
  SharedMemoryHandle(mach_port_t memory_object,
                     mach_vm_size_t size,
                     const base::UnguessableToken& guid);

  // Exposed so that the SharedMemoryHandle can be transported between
  // processes.
  mach_port_t GetMemoryObject() const;

  // The SharedMemoryHandle must be valid.
  // Returns whether the SharedMemoryHandle was successfully mapped into memory.
  // On success, |memory| is an output variable that contains the start of the
  // mapped memory.
  bool MapAt(off_t offset, size_t bytes, void** memory, bool read_only);
#elif defined(OS_POSIX)
  // Creates a SharedMemoryHandle from an |fd| supplied from an external
  // service.
  // Passing the wrong |size| has no immediate consequence, but may cause errors
  // when trying to map the SharedMemoryHandle at a later point in time.
  static SharedMemoryHandle ImportHandle(int fd, size_t size);

  // Returns the underlying OS resource.
  int GetHandle() const;

  // Invalidates [but doesn't close] the underlying OS resource. This will leak
  // unless the caller is careful.
  int Release();
#endif

#if defined(OS_ANDROID)
  // Marks the current file descriptor as read-only, for the purpose of
  // mapping. This is independent of the region's read-only status.
  void SetReadOnly() { read_only_ = true; }

  // Returns true iff the descriptor is to be used for read-only
  // mappings.
  bool IsReadOnly() const { return read_only_; }

  // Returns true iff the corresponding region is read-only.
  bool IsRegionReadOnly() const;

  // Try to set the region read-only. This will fail any future attempt
  // at read-write mapping.
  bool SetRegionReadOnly() const;
#endif

#if defined(OS_POSIX)
  // Constructs a SharedMemoryHandle backed by a FileDescriptor. The newly
  // created instance has the same ownership semantics as base::FileDescriptor.
  // This typically means that the SharedMemoryHandle takes ownership of the
  // |fd| if |auto_close| is true. Unfortunately, it's common for existing code
  // to make shallow copies of SharedMemoryHandle, and the one that is finally
  // passed into a base::SharedMemory is the one that "consumes" the fd.
  //
  // |guid| uniquely identifies the shared memory region pointed to by the
  // underlying OS resource. If |file_descriptor| is associated with another
  // SharedMemoryHandle, the caller must pass the |guid| of that
  // SharedMemoryHandle. Otherwise, the caller should generate a new
  // UnguessableToken.
  // Passing the wrong |size| has no immediate consequence, but may cause errors
  // when trying to map the SharedMemoryHandle at a later point in time.
  SharedMemoryHandle(const base::FileDescriptor& file_descriptor,
                     size_t size,
                     const base::UnguessableToken& guid);
#endif

 private:
#if defined(OS_WIN)
  HANDLE handle_ = nullptr;

  // Whether passing this object as a parameter to an IPC message passes
  // ownership of |handle_| to the IPC stack. This is meant to mimic the
  // behavior of the |auto_close| parameter of FileDescriptor. This member only
  // affects attachment-brokered SharedMemoryHandles.
  // Defaults to |false|.
  bool ownership_passes_to_ipc_ = false;
#elif defined(OS_FUCHSIA)
  zx_handle_t handle_ = ZX_HANDLE_INVALID;
  bool ownership_passes_to_ipc_ = false;
#elif defined(OS_MACOSX) && !defined(OS_IOS)
  friend class SharedMemory;
  friend bool CheckReadOnlySharedMemoryHandleForTesting(
      SharedMemoryHandle handle);

  Type type_ = MACH;

  // Each instance of a SharedMemoryHandle is backed either by a POSIX fd or a
  // mach port. |type_| determines the backing member.
  union {
    FileDescriptor file_descriptor_;

    struct {
      mach_port_t memory_object_ = MACH_PORT_NULL;

      // Whether passing this object as a parameter to an IPC message passes
      // ownership of |memory_object_| to the IPC stack. This is meant to mimic
      // the behavior of the |auto_close| parameter of FileDescriptor.
      // Defaults to |false|.
      bool ownership_passes_to_ipc_ = false;
    };
  };
#elif defined(OS_ANDROID)
  friend class SharedMemory;

  FileDescriptor file_descriptor_;
  bool read_only_ = false;
#elif defined(OS_POSIX)
  FileDescriptor file_descriptor_;
#endif

  base::UnguessableToken guid_;

  // The size of the region referenced by the SharedMemoryHandle.
  size_t size_ = 0;
};

}  // namespace base

#endif  // BASE_MEMORY_SHARED_MEMORY_HANDLE_H_