• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/memory/shared_memory.h"
6 
7 #include <mach/mach_vm.h>
8 
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_file.h"
11 #include "base/logging.h"
12 #include "base/mac/foundation_util.h"
13 #include "base/mac/mac_util.h"
14 #include "base/mac/scoped_mach_vm.h"
15 #include "base/metrics/field_trial.h"
16 #include "base/metrics/histogram_macros.h"
17 #include "base/process/process_metrics.h"
18 #include "base/profiler/scoped_tracker.h"
19 #include "base/scoped_generic.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "build/build_config.h"
22 
23 namespace base {
24 
25 namespace {
26 
27 // Returns whether the operation succeeded.
28 // |new_handle| is an output variable, populated on success. The caller takes
29 // ownership of the underlying memory object.
30 // |handle| is the handle to copy.
31 // If |handle| is already mapped, |mapped_addr| is its mapped location.
32 // Otherwise, |mapped_addr| should be |nullptr|.
MakeMachSharedMemoryHandleReadOnly(SharedMemoryHandle * new_handle,SharedMemoryHandle handle,void * mapped_addr)33 bool MakeMachSharedMemoryHandleReadOnly(SharedMemoryHandle* new_handle,
34                                         SharedMemoryHandle handle,
35                                         void* mapped_addr) {
36   if (!handle.IsValid())
37     return false;
38 
39   size_t size;
40   CHECK(handle.GetSize(&size));
41 
42   // Map if necessary.
43   void* temp_addr = mapped_addr;
44   base::mac::ScopedMachVM scoper;
45   if (!temp_addr) {
46     // Intentionally lower current prot and max prot to |VM_PROT_READ|.
47     kern_return_t kr = mach_vm_map(
48         mach_task_self(), reinterpret_cast<mach_vm_address_t*>(&temp_addr),
49         size, 0, VM_FLAGS_ANYWHERE, handle.GetMemoryObject(), 0, FALSE,
50         VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE);
51     if (kr != KERN_SUCCESS)
52       return false;
53     scoper.reset(reinterpret_cast<vm_address_t>(temp_addr),
54                  mach_vm_round_page(size));
55   }
56 
57   // Make new memory object.
58   mach_port_t named_right;
59   kern_return_t kr = mach_make_memory_entry_64(
60       mach_task_self(), reinterpret_cast<memory_object_size_t*>(&size),
61       reinterpret_cast<memory_object_offset_t>(temp_addr), VM_PROT_READ,
62       &named_right, MACH_PORT_NULL);
63   if (kr != KERN_SUCCESS)
64     return false;
65 
66   *new_handle = SharedMemoryHandle(named_right, size, base::GetCurrentProcId());
67   return true;
68 }
69 
70 }  // namespace
71 
SharedMemoryCreateOptions()72 SharedMemoryCreateOptions::SharedMemoryCreateOptions()
73     : size(0),
74       executable(false),
75       share_read_only(false) {}
76 
SharedMemory()77 SharedMemory::SharedMemory()
78     : mapped_size_(0), memory_(NULL), read_only_(false), requested_size_(0) {}
79 
SharedMemory(const SharedMemoryHandle & handle,bool read_only)80 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
81     : shm_(handle),
82       mapped_size_(0),
83       memory_(NULL),
84       read_only_(read_only),
85       requested_size_(0) {}
86 
~SharedMemory()87 SharedMemory::~SharedMemory() {
88   Unmap();
89   Close();
90 }
91 
92 // static
IsHandleValid(const SharedMemoryHandle & handle)93 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
94   return handle.IsValid();
95 }
96 
97 // static
NULLHandle()98 SharedMemoryHandle SharedMemory::NULLHandle() {
99   return SharedMemoryHandle();
100 }
101 
102 // static
CloseHandle(const SharedMemoryHandle & handle)103 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
104   handle.Close();
105 }
106 
107 // static
GetHandleLimit()108 size_t SharedMemory::GetHandleLimit() {
109   // This should be effectively unlimited on OS X.
110   return 10000;
111 }
112 
113 // static
DuplicateHandle(const SharedMemoryHandle & handle)114 SharedMemoryHandle SharedMemory::DuplicateHandle(
115     const SharedMemoryHandle& handle) {
116   return handle.Duplicate();
117 }
118 
CreateAndMapAnonymous(size_t size)119 bool SharedMemory::CreateAndMapAnonymous(size_t size) {
120   return CreateAnonymous(size) && Map(size);
121 }
122 
123 // static
GetSizeFromSharedMemoryHandle(const SharedMemoryHandle & handle,size_t * size)124 bool SharedMemory::GetSizeFromSharedMemoryHandle(
125     const SharedMemoryHandle& handle,
126     size_t* size) {
127   return handle.GetSize(size);
128 }
129 
130 // Chromium mostly only uses the unique/private shmem as specified by
131 // "name == L"". The exception is in the StatsTable.
Create(const SharedMemoryCreateOptions & options)132 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
133   // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
134   // is fixed.
135   tracked_objects::ScopedTracker tracking_profile1(
136       FROM_HERE_WITH_EXPLICIT_FUNCTION(
137           "466437 SharedMemory::Create::Start"));
138   DCHECK(!shm_.IsValid());
139   if (options.size == 0) return false;
140 
141   if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
142     return false;
143 
144   shm_ = SharedMemoryHandle(options.size);
145   requested_size_ = options.size;
146   return shm_.IsValid();
147 }
148 
MapAt(off_t offset,size_t bytes)149 bool SharedMemory::MapAt(off_t offset, size_t bytes) {
150   if (!shm_.IsValid())
151     return false;
152   if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
153     return false;
154   if (memory_)
155     return false;
156 
157   bool success = shm_.MapAt(offset, bytes, &memory_, read_only_);
158   if (success) {
159     mapped_size_ = bytes;
160     DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
161                       (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
162   } else {
163     memory_ = NULL;
164   }
165 
166   return success;
167 }
168 
Unmap()169 bool SharedMemory::Unmap() {
170   if (memory_ == NULL)
171     return false;
172 
173   mach_vm_deallocate(mach_task_self(),
174                      reinterpret_cast<mach_vm_address_t>(memory_),
175                      mapped_size_);
176   memory_ = NULL;
177   mapped_size_ = 0;
178   return true;
179 }
180 
handle() const181 SharedMemoryHandle SharedMemory::handle() const {
182   return shm_;
183 }
184 
Close()185 void SharedMemory::Close() {
186   shm_.Close();
187   shm_ = SharedMemoryHandle();
188 }
189 
ShareToProcessCommon(ProcessHandle,SharedMemoryHandle * new_handle,bool close_self,ShareMode share_mode)190 bool SharedMemory::ShareToProcessCommon(ProcessHandle /*process*/,
191                                         SharedMemoryHandle* new_handle,
192                                         bool close_self,
193                                         ShareMode share_mode) {
194   DCHECK(shm_.IsValid());
195 
196   bool success = false;
197   switch (share_mode) {
198     case SHARE_CURRENT_MODE:
199       *new_handle = shm_.Duplicate();
200       success = true;
201       break;
202     case SHARE_READONLY:
203       success = MakeMachSharedMemoryHandleReadOnly(new_handle, shm_, memory_);
204       break;
205   }
206 
207   if (success)
208     new_handle->SetOwnershipPassesToIPC(true);
209 
210   if (close_self) {
211     Unmap();
212     Close();
213   }
214 
215   return success;
216 }
217 
218 }  // namespace base
219