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|. 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 72 SharedMemoryCreateOptions::SharedMemoryCreateOptions() 73 : size(0), 74 executable(false), 75 share_read_only(false) {} 76 77 SharedMemory::SharedMemory() 78 : mapped_size_(0), memory_(NULL), read_only_(false), requested_size_(0) {} 79 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 87 SharedMemory::~SharedMemory() { 88 Unmap(); 89 Close(); 90 } 91 92 // static 93 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { 94 return handle.IsValid(); 95 } 96 97 // static 98 SharedMemoryHandle SharedMemory::NULLHandle() { 99 return SharedMemoryHandle(); 100 } 101 102 // static 103 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) { 104 handle.Close(); 105 } 106 107 // static 108 size_t SharedMemory::GetHandleLimit() { 109 // This should be effectively unlimited on OS X. 110 return 10000; 111 } 112 113 // static 114 SharedMemoryHandle SharedMemory::DuplicateHandle( 115 const SharedMemoryHandle& handle) { 116 return handle.Duplicate(); 117 } 118 119 bool SharedMemory::CreateAndMapAnonymous(size_t size) { 120 return CreateAnonymous(size) && Map(size); 121 } 122 123 // static 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. 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 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 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 181 SharedMemoryHandle SharedMemory::handle() const { 182 return shm_; 183 } 184 185 void SharedMemory::Close() { 186 shm_.Close(); 187 shm_ = SharedMemoryHandle(); 188 } 189 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