| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 <aclapi.h> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "base/memory/scoped_ptr.h" | |
| 11 #include "base/rand_util.h" | |
| 12 #include "base/strings/stringprintf.h" | |
| 13 #include "base/strings/utf_string_conversions.h" | |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 // Returns the length of the memory section starting at the supplied address. | |
| 18 size_t GetMemorySectionSize(void* address) { | |
| 19 MEMORY_BASIC_INFORMATION memory_info; | |
| 20 if (!::VirtualQuery(address, &memory_info, sizeof(memory_info))) | |
| 21 return 0; | |
| 22 return memory_info.RegionSize - (static_cast<char*>(address) - | |
| 23 static_cast<char*>(memory_info.AllocationBase)); | |
| 24 } | |
| 25 | |
| 26 } // namespace. | |
| 27 | |
| 28 namespace base { | |
| 29 | |
| 30 SharedMemory::SharedMemory() | |
| 31 : mapped_file_(NULL), | |
| 32 memory_(NULL), | |
| 33 read_only_(false), | |
| 34 mapped_size_(0), | |
| 35 requested_size_(0), | |
| 36 lock_(NULL) { | |
| 37 } | |
| 38 | |
| 39 SharedMemory::SharedMemory(const std::wstring& name) | |
| 40 : mapped_file_(NULL), | |
| 41 memory_(NULL), | |
| 42 read_only_(false), | |
| 43 requested_size_(0), | |
| 44 mapped_size_(0), | |
| 45 lock_(NULL), | |
| 46 name_(name) { | |
| 47 } | |
| 48 | |
| 49 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) | |
| 50 : mapped_file_(handle), | |
| 51 memory_(NULL), | |
| 52 read_only_(read_only), | |
| 53 requested_size_(0), | |
| 54 mapped_size_(0), | |
| 55 lock_(NULL) { | |
| 56 } | |
| 57 | |
| 58 SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, | |
| 59 ProcessHandle process) | |
| 60 : mapped_file_(NULL), | |
| 61 memory_(NULL), | |
| 62 read_only_(read_only), | |
| 63 requested_size_(0), | |
| 64 mapped_size_(0), | |
| 65 lock_(NULL) { | |
| 66 ::DuplicateHandle(process, handle, | |
| 67 GetCurrentProcess(), &mapped_file_, | |
| 68 read_only_ ? FILE_MAP_READ : FILE_MAP_READ | | |
| 69 FILE_MAP_WRITE, | |
| 70 FALSE, 0); | |
| 71 } | |
| 72 | |
| 73 SharedMemory::~SharedMemory() { | |
| 74 Unmap(); | |
| 75 Close(); | |
| 76 if (lock_ != NULL) | |
| 77 CloseHandle(lock_); | |
| 78 } | |
| 79 | |
| 80 // static | |
| 81 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { | |
| 82 return handle != NULL; | |
| 83 } | |
| 84 | |
| 85 // static | |
| 86 SharedMemoryHandle SharedMemory::NULLHandle() { | |
| 87 return NULL; | |
| 88 } | |
| 89 | |
| 90 // static | |
| 91 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) { | |
| 92 DCHECK(handle != NULL); | |
| 93 ::CloseHandle(handle); | |
| 94 } | |
| 95 | |
| 96 // static | |
| 97 size_t SharedMemory::GetHandleLimit() { | |
| 98 // Rounded down from value reported here: | |
| 99 // http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx | |
| 100 return static_cast<size_t>(1 << 23); | |
| 101 } | |
| 102 | |
| 103 // static | |
| 104 SharedMemoryHandle SharedMemory::DuplicateHandle( | |
| 105 const SharedMemoryHandle& handle) { | |
| 106 ProcessHandle process = GetCurrentProcess(); | |
| 107 SharedMemoryHandle duped_handle; | |
| 108 BOOL success = ::DuplicateHandle(process, handle, process, &duped_handle, 0, | |
| 109 FALSE, DUPLICATE_SAME_ACCESS); | |
| 110 if (success) | |
| 111 return duped_handle; | |
| 112 return NULLHandle(); | |
| 113 } | |
| 114 | |
| 115 bool SharedMemory::CreateAndMapAnonymous(size_t size) { | |
| 116 return CreateAnonymous(size) && Map(size); | |
| 117 } | |
| 118 | |
| 119 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { | |
| 120 // TODO(bsy,sehr): crbug.com/210609 NaCl forces us to round up 64k here, | |
| 121 // wasting 32k per mapping on average. | |
| 122 static const size_t kSectionMask = 65536 - 1; | |
| 123 DCHECK(!options.executable); | |
| 124 DCHECK(!mapped_file_); | |
| 125 if (options.size == 0) | |
| 126 return false; | |
| 127 | |
| 128 // Check maximum accounting for overflow. | |
| 129 if (options.size > | |
| 130 static_cast<size_t>(std::numeric_limits<int>::max()) - kSectionMask) | |
| 131 return false; | |
| 132 | |
| 133 size_t rounded_size = (options.size + kSectionMask) & ~kSectionMask; | |
| 134 name_ = options.name_deprecated ? | |
| 135 ASCIIToUTF16(*options.name_deprecated) : L""; | |
| 136 SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, FALSE }; | |
| 137 SECURITY_DESCRIPTOR sd; | |
| 138 ACL dacl; | |
| 139 | |
| 140 if (options.share_read_only && name_.empty()) { | |
| 141 // Add an empty DACL to enforce anonymous read-only sections. | |
| 142 sa.lpSecurityDescriptor = &sd; | |
| 143 if (!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) | |
| 144 return false; | |
| 145 if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) | |
| 146 return false; | |
| 147 if (!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE)) | |
| 148 return false; | |
| 149 | |
| 150 // Windows ignores DACLs on certain unnamed objects (like shared sections). | |
| 151 // So, we generate a random name when we need to enforce read-only. | |
| 152 uint64_t rand_values[4]; | |
| 153 RandBytes(&rand_values, sizeof(rand_values)); | |
| 154 name_ = StringPrintf(L"CrSharedMem_%016x%016x%016x%016x", | |
| 155 rand_values[0], rand_values[1], | |
| 156 rand_values[2], rand_values[3]); | |
| 157 } | |
| 158 mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, | |
| 159 PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size), | |
| 160 name_.empty() ? nullptr : name_.c_str()); | |
| 161 if (!mapped_file_) | |
| 162 return false; | |
| 163 | |
| 164 requested_size_ = options.size; | |
| 165 | |
| 166 // Check if the shared memory pre-exists. | |
| 167 if (GetLastError() == ERROR_ALREADY_EXISTS) { | |
| 168 // If the file already existed, set requested_size_ to 0 to show that | |
| 169 // we don't know the size. | |
| 170 requested_size_ = 0; | |
| 171 if (!options.open_existing_deprecated) { | |
| 172 Close(); | |
| 173 return false; | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 return true; | |
| 178 } | |
| 179 | |
| 180 bool SharedMemory::Delete(const std::string& name) { | |
| 181 // intentionally empty -- there is nothing for us to do on Windows. | |
| 182 return true; | |
| 183 } | |
| 184 | |
| 185 bool SharedMemory::Open(const std::string& name, bool read_only) { | |
| 186 DCHECK(!mapped_file_); | |
| 187 | |
| 188 name_ = ASCIIToUTF16(name); | |
| 189 read_only_ = read_only; | |
| 190 mapped_file_ = OpenFileMapping( | |
| 191 read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, | |
| 192 false, name_.empty() ? NULL : name_.c_str()); | |
| 193 if (mapped_file_ != NULL) { | |
| 194 // Note: size_ is not set in this case. | |
| 195 return true; | |
| 196 } | |
| 197 return false; | |
| 198 } | |
| 199 | |
| 200 bool SharedMemory::MapAt(off_t offset, size_t bytes) { | |
| 201 if (mapped_file_ == NULL) | |
| 202 return false; | |
| 203 | |
| 204 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) | |
| 205 return false; | |
| 206 | |
| 207 if (memory_) | |
| 208 return false; | |
| 209 | |
| 210 memory_ = MapViewOfFile(mapped_file_, | |
| 211 read_only_ ? FILE_MAP_READ : FILE_MAP_READ | | |
| 212 FILE_MAP_WRITE, | |
| 213 static_cast<uint64>(offset) >> 32, | |
| 214 static_cast<DWORD>(offset), | |
| 215 bytes); | |
| 216 if (memory_ != NULL) { | |
| 217 DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) & | |
| 218 (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); | |
| 219 mapped_size_ = GetMemorySectionSize(memory_); | |
| 220 return true; | |
| 221 } | |
| 222 return false; | |
| 223 } | |
| 224 | |
| 225 bool SharedMemory::Unmap() { | |
| 226 if (memory_ == NULL) | |
| 227 return false; | |
| 228 | |
| 229 UnmapViewOfFile(memory_); | |
| 230 memory_ = NULL; | |
| 231 return true; | |
| 232 } | |
| 233 | |
| 234 bool SharedMemory::ShareToProcessCommon(ProcessHandle process, | |
| 235 SharedMemoryHandle* new_handle, | |
| 236 bool close_self, | |
| 237 ShareMode share_mode) { | |
| 238 *new_handle = 0; | |
| 239 DWORD access = FILE_MAP_READ; | |
| 240 DWORD options = 0; | |
| 241 HANDLE mapped_file = mapped_file_; | |
| 242 HANDLE result; | |
| 243 if (share_mode == SHARE_CURRENT_MODE && !read_only_) | |
| 244 access |= FILE_MAP_WRITE; | |
| 245 if (close_self) { | |
| 246 // DUPLICATE_CLOSE_SOURCE causes DuplicateHandle to close mapped_file. | |
| 247 options = DUPLICATE_CLOSE_SOURCE; | |
| 248 mapped_file_ = NULL; | |
| 249 Unmap(); | |
| 250 } | |
| 251 | |
| 252 if (process == GetCurrentProcess() && close_self) { | |
| 253 *new_handle = mapped_file; | |
| 254 return true; | |
| 255 } | |
| 256 | |
| 257 if (!::DuplicateHandle(GetCurrentProcess(), mapped_file, process, &result, | |
| 258 access, FALSE, options)) { | |
| 259 return false; | |
| 260 } | |
| 261 *new_handle = result; | |
| 262 return true; | |
| 263 } | |
| 264 | |
| 265 | |
| 266 void SharedMemory::Close() { | |
| 267 if (mapped_file_ != NULL) { | |
| 268 CloseHandle(mapped_file_); | |
| 269 mapped_file_ = NULL; | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 void SharedMemory::LockDeprecated() { | |
| 274 if (lock_ == NULL) { | |
| 275 std::wstring name = name_; | |
| 276 name.append(L"lock"); | |
| 277 lock_ = CreateMutex(NULL, FALSE, name.c_str()); | |
| 278 if (lock_ == NULL) { | |
| 279 DPLOG(ERROR) << "Could not create mutex."; | |
| 280 NOTREACHED(); | |
| 281 return; // There is nothing good we can do here. | |
| 282 } | |
| 283 } | |
| 284 DWORD result = WaitForSingleObject(lock_, INFINITE); | |
| 285 DCHECK_EQ(result, WAIT_OBJECT_0); | |
| 286 } | |
| 287 | |
| 288 void SharedMemory::UnlockDeprecated() { | |
| 289 DCHECK(lock_ != NULL); | |
| 290 ReleaseMutex(lock_); | |
| 291 } | |
| 292 | |
| 293 SharedMemoryHandle SharedMemory::handle() const { | |
| 294 return mapped_file_; | |
| 295 } | |
| 296 | |
| 297 } // namespace base | |
| OLD | NEW |