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 |