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

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: 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
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/mach_logging.h" 10 #include "base/mac/mach_logging.h"
11 #include "base/mac/scoped_mach_port.h" 11 #include "base/mac/scoped_mach_port.h"
12 #include "base/memory/shared_memory.h" 12 #include "base/memory/shared_memory.h"
13 #include "base/process/process_handle.h" 13 #include "base/process/process_handle.h"
14 #include "base/rand_util.h" 14 #include "base/rand_util.h"
15 #include "base/strings/stringprintf.h" 15 #include "base/strings/stringprintf.h"
16 #include "base/sys_info.h" 16 #include "base/sys_info.h"
17 #include "base/test/multiprocess_test.h" 17 #include "base/test/multiprocess_test.h"
18 #include "base/test/test_timeouts.h" 18 #include "base/test/test_timeouts.h"
19 #include "testing/multiprocess_func_list.h" 19 #include "testing/multiprocess_func_list.h"
20 20
21 namespace base { 21 namespace base {
22 22
23 namespace { 23 namespace {
24 24
25 // Gets the current and maximum protection levels of the memory region.
26 // Returns whether the operation was successful.
27 // |current| and |max| are output variables only populated on success.
28 bool GetProtections(void* address, size_t size, int* current, int* max) {
29 vm_region_info_t region_info;
30 mach_vm_address_t mem_address = reinterpret_cast<mach_vm_address_t>(address);
31 mach_vm_size_t mem_size = size;
32 vm_region_basic_info_64 basic_info;
33
34 region_info = reinterpret_cast<vm_region_recurse_info_t>(&basic_info);
35 vm_region_flavor_t flavor = VM_REGION_BASIC_INFO_64;
36 memory_object_name_t memory_object;
37 mach_port_t ctype;
38
39 kern_return_t kr =
40 mach_vm_region(mach_task_self(), &mem_address, &mem_size, flavor,
41 region_info, &memory_object, &ctype);
42 if (kr != KERN_SUCCESS) {
43 LOG(ERROR) << "Failed to get region info.";
44 return false;
45 }
46
47 *current = basic_info.protection;
48 *max = basic_info.max_protection;
49 return true;
50 }
51
52 // Creates a new SharedMemory with the given |size|, filled with 'a'.
53 scoped_ptr<SharedMemory> CreateSharedMemory(int size) {
54 SharedMemoryHandle shm(size);
55 if (!shm.IsValid()) {
56 LOG(ERROR) << "Failed to make SharedMemoryHandle";
57 return nullptr;
58 }
59 scoped_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false));
60 shared_memory->Map(size);
61 memset(shared_memory->memory(), 'a', size);
62 return shared_memory;
63 }
64
25 static const std::string g_service_switch_name = "service_name"; 65 static const std::string g_service_switch_name = "service_name";
26 66
27 // Structs used to pass a mach port from client to server. 67 // Structs used to pass a mach port from client to server.
28 struct MachSendPortMessage { 68 struct MachSendPortMessage {
29 mach_msg_header_t header; 69 mach_msg_header_t header;
30 mach_msg_body_t body; 70 mach_msg_body_t body;
31 mach_msg_port_descriptor_t data; 71 mach_msg_port_descriptor_t data;
32 }; 72 };
33 struct MachReceivePortMessage { 73 struct MachReceivePortMessage {
34 mach_msg_header_t header; 74 mach_msg_header_t header;
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 219
180 base::Process child_process_; 220 base::Process child_process_;
181 DISALLOW_COPY_AND_ASSIGN(SharedMemoryMacMultiProcessTest); 221 DISALLOW_COPY_AND_ASSIGN(SharedMemoryMacMultiProcessTest);
182 }; 222 };
183 223
184 // Tests that content written to shared memory in the server process can be read 224 // Tests that content written to shared memory in the server process can be read
185 // by the child process. 225 // by the child process.
186 TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemory) { 226 TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemory) {
187 SetUpChild("MachBasedSharedMemoryClient"); 227 SetUpChild("MachBasedSharedMemoryClient");
188 228
189 SharedMemoryHandle shm(s_memory_size); 229 scoped_ptr<SharedMemory> shared_memory(
190 ASSERT_TRUE(shm.IsValid()); 230 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 231
195 // Send the underlying memory object to the client process. 232 // Send the underlying memory object to the client process.
196 SendMachPort( 233 SendMachPort(client_port_.get(), shared_memory->handle().GetMemoryObject(),
197 client_port_.get(), shm.GetMemoryObject(), MACH_MSG_TYPE_COPY_SEND); 234 MACH_MSG_TYPE_COPY_SEND);
198 int rv = -1; 235 int rv = -1;
199 ASSERT_TRUE(child_process_.WaitForExitWithTimeout( 236 ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
200 TestTimeouts::action_timeout(), &rv)); 237 TestTimeouts::action_timeout(), &rv));
201 EXPECT_EQ(0, rv); 238 EXPECT_EQ(0, rv);
202 } 239 }
203 240
204 MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryClient) { 241 MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryClient) {
205 mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp()); 242 mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp());
206 // The next mach port should be for a memory object. 243 // The next mach port should be for a memory object.
207 mach_port_t memory_object = ReceiveMachPort(client_port.get()); 244 mach_port_t memory_object = ReceiveMachPort(client_port.get());
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 shared_memory->Map(s_memory_size); 340 shared_memory->Map(s_memory_size);
304 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); 341 EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
305 342
306 // Destroying the SharedMemory object frees the resource. 343 // Destroying the SharedMemory object frees the resource.
307 shared_memory.reset(); 344 shared_memory.reset();
308 EXPECT_EQ(active_name_count, GetActiveNameCount()); 345 EXPECT_EQ(active_name_count, GetActiveNameCount());
309 } 346 }
310 347
311 // Tests that the read-only flag works. 348 // Tests that the read-only flag works.
312 TEST_F(SharedMemoryMacMultiProcessTest, MachReadOnly) { 349 TEST_F(SharedMemoryMacMultiProcessTest, MachReadOnly) {
313 SharedMemoryHandle shm(s_memory_size); 350 scoped_ptr<SharedMemory> shared_memory(
314 ASSERT_TRUE(shm.IsValid()); 351 CreateSharedMemory(s_memory_size).Pass());
315 SharedMemory shared_memory(shm, false);
316 shared_memory.Map(s_memory_size);
317 memset(shared_memory.memory(), 'a', s_memory_size);
318 352
319 SharedMemoryHandle shm2 = shm.Duplicate(); 353 SharedMemoryHandle shm2 = shared_memory->handle().Duplicate();
320 ASSERT_TRUE(shm2.IsValid()); 354 ASSERT_TRUE(shm2.IsValid());
321 SharedMemory shared_memory2(shm, true); 355 SharedMemory shared_memory2(shm2, true);
322 shared_memory2.Map(s_memory_size); 356 shared_memory2.Map(s_memory_size);
323 ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), ""); 357 ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), "");
324 } 358 }
325 359
360 // Tests that the method ShareToProcess() works.
361 TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcess) {
362 mach_msg_type_number_t active_name_count = GetActiveNameCount();
363
364 {
365 scoped_ptr<SharedMemory> shared_memory(
366 CreateSharedMemory(s_memory_size).Pass());
367
368 SharedMemoryHandle shm2;
369 ASSERT_TRUE(shared_memory->ShareToProcess(GetCurrentProcId(), &shm2));
370 ASSERT_TRUE(shm2.IsValid());
371 SharedMemory shared_memory2(shm2, true);
372 shared_memory2.Map(s_memory_size);
373
374 ASSERT_EQ(0, memcmp(shared_memory->memory(), shared_memory2.memory(),
375 s_memory_size));
376 }
377
378 EXPECT_EQ(active_name_count, GetActiveNameCount());
379 }
380
381 // Tests that the method ShareReadOnlyToProcess() creates a memory object that
382 // is read only.
383 TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcessReadonly) {
384 scoped_ptr<SharedMemory> shared_memory(
385 CreateSharedMemory(s_memory_size).Pass());
386
387 // Check the protection levels.
388 int current_prot, max_prot;
389 ASSERT_TRUE(GetProtections(shared_memory->memory(),
390 shared_memory->mapped_size(), &current_prot,
391 &max_prot));
392 ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, current_prot);
393 ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, max_prot);
394
395 // Make a new memory object.
396 SharedMemoryHandle shm2;
397 ASSERT_TRUE(shared_memory->ShareReadOnlyToProcess(GetCurrentProcId(), &shm2));
398 ASSERT_TRUE(shm2.IsValid());
399
400 // Mapping with |readonly| set to |false| should fail.
401 SharedMemory shared_memory2(shm2, false);
402 shared_memory2.Map(s_memory_size);
403 ASSERT_EQ(nullptr, shared_memory2.memory());
404
405 // Now trying mapping with |readonly| set to |true|.
406 SharedMemory shared_memory3(shm2.Duplicate(), true);
407 shared_memory3.Map(s_memory_size);
408 ASSERT_NE(nullptr, shared_memory3.memory());
409
410 // Check the protection levels.
411 ASSERT_TRUE(GetProtections(shared_memory3.memory(),
412 shared_memory3.mapped_size(), &current_prot,
413 &max_prot));
414 ASSERT_EQ(VM_PROT_READ, current_prot);
415 ASSERT_EQ(VM_PROT_READ, max_prot);
416
417 // The memory should still be readonly, since the underlying memory object
418 // is readonly.
419 ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), "");
420 }
421
422 // Tests that the method ShareReadOnlyToProcess() doesn't leak.
423 TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcessReadonlyLeak) {
424 mach_msg_type_number_t active_name_count = GetActiveNameCount();
425
426 {
427 scoped_ptr<SharedMemory> shared_memory(
428 CreateSharedMemory(s_memory_size).Pass());
429
430 SharedMemoryHandle shm2;
431 ASSERT_TRUE(
432 shared_memory->ShareReadOnlyToProcess(GetCurrentProcId(), &shm2));
433 ASSERT_TRUE(shm2.IsValid());
434
435 // Intentionally map with |readonly| set to |false|.
436 SharedMemory shared_memory2(shm2, false);
437 shared_memory2.Map(s_memory_size);
438 }
439
440 EXPECT_EQ(active_name_count, GetActiveNameCount());
441 }
442
326 } // namespace base 443 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698