Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: base/memory/shared_memory_mac_unittest.cc

Issue 1418113003: mac: Add auto-close and share-read-only functionality to SharedMemory. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comments from mark. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/memory/shared_memory_mac.cc ('k') | ipc/attachment_broker_mac_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <mach/mach.h> 5 #include <mach/mach.h>
6 #include <mach/mach_vm.h> 6 #include <mach/mach_vm.h>
7 #include <servers/bootstrap.h> 7 #include <servers/bootstrap.h>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/mac/mac_util.h"
10 #include "base/mac/mach_logging.h" 11 #include "base/mac/mach_logging.h"
11 #include "base/mac/scoped_mach_port.h" 12 #include "base/mac/scoped_mach_port.h"
12 #include "base/memory/shared_memory.h" 13 #include "base/memory/shared_memory.h"
13 #include "base/process/process_handle.h" 14 #include "base/process/process_handle.h"
14 #include "base/rand_util.h" 15 #include "base/rand_util.h"
15 #include "base/strings/stringprintf.h" 16 #include "base/strings/stringprintf.h"
16 #include "base/sys_info.h" 17 #include "base/sys_info.h"
17 #include "base/test/multiprocess_test.h" 18 #include "base/test/multiprocess_test.h"
18 #include "base/test/test_timeouts.h" 19 #include "base/test/test_timeouts.h"
19 #include "testing/multiprocess_func_list.h" 20 #include "testing/multiprocess_func_list.h"
20 21
21 namespace base { 22 namespace base {
22 23
23 namespace { 24 namespace {
24 25
26 // Gets the current and maximum protection levels of the memory region.
27 // Returns whether the operation was successful.
28 // |current| and |max| are output variables only populated on success.
29 bool GetProtections(void* address, size_t size, int* current, int* max) {
30 vm_region_info_t region_info;
31 mach_vm_address_t mem_address = reinterpret_cast<mach_vm_address_t>(address);
32 mach_vm_size_t mem_size = size;
33 vm_region_basic_info_64 basic_info;
34
35 region_info = reinterpret_cast<vm_region_recurse_info_t>(&basic_info);
36 vm_region_flavor_t flavor = VM_REGION_BASIC_INFO_64;
37 memory_object_name_t memory_object;
38 mach_port_t ctype;
39
40 kern_return_t kr =
41 mach_vm_region(mach_task_self(), &mem_address, &mem_size, flavor,
42 region_info, &memory_object, &ctype);
43 if (kr != KERN_SUCCESS) {
44 LOG(ERROR) << "Failed to get region info.";
45 return false;
46 }
47
48 *current = basic_info.protection;
49 *max = basic_info.max_protection;
50 return true;
51 }
52
53 // Creates a new SharedMemory with the given |size|, filled with 'a'.
54 scoped_ptr<SharedMemory> CreateSharedMemory(int size) {
55 SharedMemoryHandle shm(size);
56 if (!shm.IsValid()) {
57 LOG(ERROR) << "Failed to make SharedMemoryHandle";
58 return nullptr;
59 }
60 scoped_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false));
61 shared_memory->Map(size);
62 memset(shared_memory->memory(), 'a', size);
63 return shared_memory;
64 }
65
25 static const std::string g_service_switch_name = "service_name"; 66 static const std::string g_service_switch_name = "service_name";
26 67
27 // Structs used to pass a mach port from client to server. 68 // Structs used to pass a mach port from client to server.
28 struct MachSendPortMessage { 69 struct MachSendPortMessage {
29 mach_msg_header_t header; 70 mach_msg_header_t header;
30 mach_msg_body_t body; 71 mach_msg_body_t body;
31 mach_msg_port_descriptor_t data; 72 mach_msg_port_descriptor_t data;
32 }; 73 };
33 struct MachReceivePortMessage { 74 struct MachReceivePortMessage {
34 mach_msg_header_t header; 75 mach_msg_header_t header;
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 // process. 218 // process.
178 mac::ScopedMachSendRight client_port_; 219 mac::ScopedMachSendRight client_port_;
179 220
180 base::Process child_process_; 221 base::Process child_process_;
181 DISALLOW_COPY_AND_ASSIGN(SharedMemoryMacMultiProcessTest); 222 DISALLOW_COPY_AND_ASSIGN(SharedMemoryMacMultiProcessTest);
182 }; 223 };
183 224
184 // Tests that content written to shared memory in the server process can be read 225 // Tests that content written to shared memory in the server process can be read
185 // by the child process. 226 // by the child process.
186 TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemory) { 227 TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemory) {
228 // Mach-based SharedMemory isn't support on OSX 10.6.
229 if (mac::IsOSSnowLeopard())
230 return;
231
187 SetUpChild("MachBasedSharedMemoryClient"); 232 SetUpChild("MachBasedSharedMemoryClient");
188 233
189 SharedMemoryHandle shm(s_memory_size); 234 scoped_ptr<SharedMemory> shared_memory(
190 ASSERT_TRUE(shm.IsValid()); 235 CreateSharedMemory(s_memory_size).Pass());
191 SharedMemory shared_memory(shm, false);
192 shared_memory.Map(s_memory_size);
193 memset(shared_memory.memory(), 'a', s_memory_size);
194 236
195 // Send the underlying memory object to the client process. 237 // Send the underlying memory object to the client process.
196 SendMachPort( 238 SendMachPort(client_port_.get(), shared_memory->handle().GetMemoryObject(),
197 client_port_.get(), shm.GetMemoryObject(), MACH_MSG_TYPE_COPY_SEND); 239 MACH_MSG_TYPE_COPY_SEND);
198 int rv = -1; 240 int rv = -1;
199 ASSERT_TRUE(child_process_.WaitForExitWithTimeout( 241 ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
200 TestTimeouts::action_timeout(), &rv)); 242 TestTimeouts::action_timeout(), &rv));
201 EXPECT_EQ(0, rv); 243 EXPECT_EQ(0, rv);
202 } 244 }
203 245
204 MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryClient) { 246 MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryClient) {
205 mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp()); 247 mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp());
206 // The next mach port should be for a memory object. 248 // The next mach port should be for a memory object.
207 mach_port_t memory_object = ReceiveMachPort(client_port.get()); 249 mach_port_t memory_object = ReceiveMachPort(client_port.get());
208 SharedMemoryHandle shm(memory_object, 250 SharedMemoryHandle shm(memory_object,
209 SharedMemoryMacMultiProcessTest::s_memory_size, 251 SharedMemoryMacMultiProcessTest::s_memory_size,
210 GetCurrentProcId()); 252 GetCurrentProcId());
211 SharedMemory shared_memory(shm, false); 253 SharedMemory shared_memory(shm, false);
212 shared_memory.Map(SharedMemoryMacMultiProcessTest::s_memory_size); 254 shared_memory.Map(SharedMemoryMacMultiProcessTest::s_memory_size);
213 const char* start = static_cast<const char*>(shared_memory.memory()); 255 const char* start = static_cast<const char*>(shared_memory.memory());
214 for (int i = 0; i < SharedMemoryMacMultiProcessTest::s_memory_size; ++i) { 256 for (int i = 0; i < SharedMemoryMacMultiProcessTest::s_memory_size; ++i) {
215 DCHECK_EQ(start[i], 'a'); 257 DCHECK_EQ(start[i], 'a');
216 } 258 }
217 return 0; 259 return 0;
218 } 260 }
219 261
220 // Tests that mapping shared memory with an offset works correctly. 262 // Tests that mapping shared memory with an offset works correctly.
221 TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemoryWithOffset) { 263 TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemoryWithOffset) {
264 // Mach-based SharedMemory isn't support on OSX 10.6.
265 if (mac::IsOSSnowLeopard())
266 return;
267
222 SetUpChild("MachBasedSharedMemoryWithOffsetClient"); 268 SetUpChild("MachBasedSharedMemoryWithOffsetClient");
223 269
224 SharedMemoryHandle shm(s_memory_size); 270 SharedMemoryHandle shm(s_memory_size);
225 ASSERT_TRUE(shm.IsValid()); 271 ASSERT_TRUE(shm.IsValid());
226 SharedMemory shared_memory(shm, false); 272 SharedMemory shared_memory(shm, false);
227 shared_memory.Map(s_memory_size); 273 shared_memory.Map(s_memory_size);
228 274
229 size_t page_size = SysInfo::VMAllocationGranularity(); 275 size_t page_size = SysInfo::VMAllocationGranularity();
230 char* start = static_cast<char*>(shared_memory.memory()); 276 char* start = static_cast<char*>(shared_memory.memory());
231 memset(start, 'a', page_size); 277 memset(start, 'a', page_size);
(...skipping 25 matching lines...) Expand all
257 } 303 }
258 for (size_t i = page_size; i < 2 * page_size; ++i) { 304 for (size_t i = page_size; i < 2 * page_size; ++i) {
259 DCHECK_EQ(start[i], 'c'); 305 DCHECK_EQ(start[i], 'c');
260 } 306 }
261 return 0; 307 return 0;
262 } 308 }
263 309
264 // Tests that duplication and closing has the right effect on Mach reference 310 // Tests that duplication and closing has the right effect on Mach reference
265 // counts. 311 // counts.
266 TEST_F(SharedMemoryMacMultiProcessTest, MachDuplicateAndClose) { 312 TEST_F(SharedMemoryMacMultiProcessTest, MachDuplicateAndClose) {
313 // Mach-based SharedMemory isn't support on OSX 10.6.
314 if (mac::IsOSSnowLeopard())
315 return;
316
267 mach_msg_type_number_t active_name_count = GetActiveNameCount(); 317 mach_msg_type_number_t active_name_count = GetActiveNameCount();
268 318
269 // Making a new SharedMemoryHandle increments the name count. 319 // Making a new SharedMemoryHandle increments the name count.
270 SharedMemoryHandle shm(s_memory_size); 320 SharedMemoryHandle shm(s_memory_size);
271 ASSERT_TRUE(shm.IsValid()); 321 ASSERT_TRUE(shm.IsValid());
272 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); 322 EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
273 323
274 // Duplicating the SharedMemoryHandle increments the ref count, but doesn't 324 // Duplicating the SharedMemoryHandle increments the ref count, but doesn't
275 // make a new name. 325 // make a new name.
276 shm.Duplicate(); 326 shm.Duplicate();
277 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); 327 EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
278 328
279 // Closing the SharedMemoryHandle decrements the ref count. The first time has 329 // Closing the SharedMemoryHandle decrements the ref count. The first time has
280 // no effect. 330 // no effect.
281 shm.Close(); 331 shm.Close();
282 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); 332 EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
283 333
284 // Closing the SharedMemoryHandle decrements the ref count. The second time 334 // Closing the SharedMemoryHandle decrements the ref count. The second time
285 // destroys the port. 335 // destroys the port.
286 shm.Close(); 336 shm.Close();
287 EXPECT_EQ(active_name_count, GetActiveNameCount()); 337 EXPECT_EQ(active_name_count, GetActiveNameCount());
288 } 338 }
289 339
290 // Tests that passing a SharedMemoryHandle to a SharedMemory object also passes 340 // Tests that passing a SharedMemoryHandle to a SharedMemory object also passes
291 // ownership, and that destroying the SharedMemory closes the SharedMemoryHandle 341 // ownership, and that destroying the SharedMemory closes the SharedMemoryHandle
292 // as well. 342 // as well.
293 TEST_F(SharedMemoryMacMultiProcessTest, MachSharedMemoryTakesOwnership) { 343 TEST_F(SharedMemoryMacMultiProcessTest, MachSharedMemoryTakesOwnership) {
344 // Mach-based SharedMemory isn't support on OSX 10.6.
345 if (mac::IsOSSnowLeopard())
346 return;
347
294 mach_msg_type_number_t active_name_count = GetActiveNameCount(); 348 mach_msg_type_number_t active_name_count = GetActiveNameCount();
295 349
296 // Making a new SharedMemoryHandle increments the name count. 350 // Making a new SharedMemoryHandle increments the name count.
297 SharedMemoryHandle shm(s_memory_size); 351 SharedMemoryHandle shm(s_memory_size);
298 ASSERT_TRUE(shm.IsValid()); 352 ASSERT_TRUE(shm.IsValid());
299 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); 353 EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
300 354
301 // Name count doesn't change when mapping the memory. 355 // Name count doesn't change when mapping the memory.
302 scoped_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false)); 356 scoped_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false));
303 shared_memory->Map(s_memory_size); 357 shared_memory->Map(s_memory_size);
304 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); 358 EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
305 359
306 // Destroying the SharedMemory object frees the resource. 360 // Destroying the SharedMemory object frees the resource.
307 shared_memory.reset(); 361 shared_memory.reset();
308 EXPECT_EQ(active_name_count, GetActiveNameCount()); 362 EXPECT_EQ(active_name_count, GetActiveNameCount());
309 } 363 }
310 364
311 // Tests that the read-only flag works. 365 // Tests that the read-only flag works.
312 TEST_F(SharedMemoryMacMultiProcessTest, MachReadOnly) { 366 TEST_F(SharedMemoryMacMultiProcessTest, MachReadOnly) {
313 SharedMemoryHandle shm(s_memory_size); 367 // Mach-based SharedMemory isn't support on OSX 10.6.
314 ASSERT_TRUE(shm.IsValid()); 368 if (mac::IsOSSnowLeopard())
315 SharedMemory shared_memory(shm, false); 369 return;
316 shared_memory.Map(s_memory_size);
317 memset(shared_memory.memory(), 'a', s_memory_size);
318 370
319 SharedMemoryHandle shm2 = shm.Duplicate(); 371 scoped_ptr<SharedMemory> shared_memory(
372 CreateSharedMemory(s_memory_size).Pass());
373
374 SharedMemoryHandle shm2 = shared_memory->handle().Duplicate();
320 ASSERT_TRUE(shm2.IsValid()); 375 ASSERT_TRUE(shm2.IsValid());
321 SharedMemory shared_memory2(shm, true); 376 SharedMemory shared_memory2(shm2, true);
322 shared_memory2.Map(s_memory_size); 377 shared_memory2.Map(s_memory_size);
323 ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), ""); 378 ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), "");
324 } 379 }
325 380
381 // Tests that the method ShareToProcess() works.
382 TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcess) {
383 // Mach-based SharedMemory isn't support on OSX 10.6.
384 if (mac::IsOSSnowLeopard())
385 return;
386
387 mach_msg_type_number_t active_name_count = GetActiveNameCount();
388
389 {
390 scoped_ptr<SharedMemory> shared_memory(
391 CreateSharedMemory(s_memory_size).Pass());
392
393 SharedMemoryHandle shm2;
394 ASSERT_TRUE(shared_memory->ShareToProcess(GetCurrentProcId(), &shm2));
395 ASSERT_TRUE(shm2.IsValid());
396 SharedMemory shared_memory2(shm2, true);
397 shared_memory2.Map(s_memory_size);
398
399 ASSERT_EQ(0, memcmp(shared_memory->memory(), shared_memory2.memory(),
400 s_memory_size));
401 }
402
403 EXPECT_EQ(active_name_count, GetActiveNameCount());
404 }
405
406 // Tests that the method ShareReadOnlyToProcess() creates a memory object that
407 // is read only.
408 TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcessReadonly) {
409 // Mach-based SharedMemory isn't support on OSX 10.6.
410 if (mac::IsOSSnowLeopard())
411 return;
412
413 scoped_ptr<SharedMemory> shared_memory(
414 CreateSharedMemory(s_memory_size).Pass());
415
416 // Check the protection levels.
417 int current_prot, max_prot;
418 ASSERT_TRUE(GetProtections(shared_memory->memory(),
419 shared_memory->mapped_size(), &current_prot,
420 &max_prot));
421 ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, current_prot);
422 ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, max_prot);
423
424 // Make a new memory object.
425 SharedMemoryHandle shm2;
426 ASSERT_TRUE(shared_memory->ShareReadOnlyToProcess(GetCurrentProcId(), &shm2));
427 ASSERT_TRUE(shm2.IsValid());
428
429 // Mapping with |readonly| set to |false| should fail.
430 SharedMemory shared_memory2(shm2, false);
431 shared_memory2.Map(s_memory_size);
432 ASSERT_EQ(nullptr, shared_memory2.memory());
433
434 // Now trying mapping with |readonly| set to |true|.
435 SharedMemory shared_memory3(shm2.Duplicate(), true);
436 shared_memory3.Map(s_memory_size);
437 ASSERT_NE(nullptr, shared_memory3.memory());
438
439 // Check the protection levels.
440 ASSERT_TRUE(GetProtections(shared_memory3.memory(),
441 shared_memory3.mapped_size(), &current_prot,
442 &max_prot));
443 ASSERT_EQ(VM_PROT_READ, current_prot);
444 ASSERT_EQ(VM_PROT_READ, max_prot);
445
446 // The memory should still be readonly, since the underlying memory object
447 // is readonly.
448 ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), "");
449 }
450
451 // Tests that the method ShareReadOnlyToProcess() doesn't leak.
452 TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcessReadonlyLeak) {
453 // Mach-based SharedMemory isn't support on OSX 10.6.
454 if (mac::IsOSSnowLeopard())
455 return;
456
457 mach_msg_type_number_t active_name_count = GetActiveNameCount();
458
459 {
460 scoped_ptr<SharedMemory> shared_memory(
461 CreateSharedMemory(s_memory_size).Pass());
462
463 SharedMemoryHandle shm2;
464 ASSERT_TRUE(
465 shared_memory->ShareReadOnlyToProcess(GetCurrentProcId(), &shm2));
466 ASSERT_TRUE(shm2.IsValid());
467
468 // Intentionally map with |readonly| set to |false|.
469 SharedMemory shared_memory2(shm2, false);
470 shared_memory2.Map(s_memory_size);
471 }
472
473 EXPECT_EQ(active_name_count, GetActiveNameCount());
474 }
475
326 } // namespace base 476 } // namespace base
OLDNEW
« no previous file with comments | « base/memory/shared_memory_mac.cc ('k') | ipc/attachment_broker_mac_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698