| Index: base/memory/shared_memory_mac_unittest.cc
|
| diff --git a/base/memory/shared_memory_mac_unittest.cc b/base/memory/shared_memory_mac_unittest.cc
|
| index e4c5e8b19b8d0dd6b426a77c895b16324ee9b5e1..097d1b32e6e5ae5fe7eaf95db2f457cf80885e01 100644
|
| --- a/base/memory/shared_memory_mac_unittest.cc
|
| +++ b/base/memory/shared_memory_mac_unittest.cc
|
| @@ -7,6 +7,7 @@
|
| #include <servers/bootstrap.h>
|
|
|
| #include "base/command_line.h"
|
| +#include "base/mac/mac_util.h"
|
| #include "base/mac/mach_logging.h"
|
| #include "base/mac/scoped_mach_port.h"
|
| #include "base/memory/shared_memory.h"
|
| @@ -22,6 +23,46 @@ namespace base {
|
|
|
| namespace {
|
|
|
| +// Gets the current and maximum protection levels of the memory region.
|
| +// Returns whether the operation was successful.
|
| +// |current| and |max| are output variables only populated on success.
|
| +bool GetProtections(void* address, size_t size, int* current, int* max) {
|
| + vm_region_info_t region_info;
|
| + mach_vm_address_t mem_address = reinterpret_cast<mach_vm_address_t>(address);
|
| + mach_vm_size_t mem_size = size;
|
| + vm_region_basic_info_64 basic_info;
|
| +
|
| + region_info = reinterpret_cast<vm_region_recurse_info_t>(&basic_info);
|
| + vm_region_flavor_t flavor = VM_REGION_BASIC_INFO_64;
|
| + memory_object_name_t memory_object;
|
| + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
|
| +
|
| + kern_return_t kr =
|
| + mach_vm_region(mach_task_self(), &mem_address, &mem_size, flavor,
|
| + region_info, &count, &memory_object);
|
| + if (kr != KERN_SUCCESS) {
|
| + MACH_LOG(ERROR, kr) << "Failed to get region info.";
|
| + return false;
|
| + }
|
| +
|
| + *current = basic_info.protection;
|
| + *max = basic_info.max_protection;
|
| + return true;
|
| +}
|
| +
|
| +// Creates a new SharedMemory with the given |size|, filled with 'a'.
|
| +scoped_ptr<SharedMemory> CreateSharedMemory(int size) {
|
| + SharedMemoryHandle shm(size);
|
| + if (!shm.IsValid()) {
|
| + LOG(ERROR) << "Failed to make SharedMemoryHandle";
|
| + return nullptr;
|
| + }
|
| + scoped_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false));
|
| + shared_memory->Map(size);
|
| + memset(shared_memory->memory(), 'a', size);
|
| + return shared_memory;
|
| +}
|
| +
|
| static const std::string g_service_switch_name = "service_name";
|
|
|
| // Structs used to pass a mach port from client to server.
|
| @@ -184,17 +225,18 @@ class SharedMemoryMacMultiProcessTest : public MultiProcessTest {
|
| // Tests that content written to shared memory in the server process can be read
|
| // by the child process.
|
| TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemory) {
|
| + // Mach-based SharedMemory isn't support on OSX 10.6.
|
| + if (mac::IsOSSnowLeopard())
|
| + return;
|
| +
|
| SetUpChild("MachBasedSharedMemoryClient");
|
|
|
| - SharedMemoryHandle shm(s_memory_size);
|
| - ASSERT_TRUE(shm.IsValid());
|
| - SharedMemory shared_memory(shm, false);
|
| - shared_memory.Map(s_memory_size);
|
| - memset(shared_memory.memory(), 'a', s_memory_size);
|
| + scoped_ptr<SharedMemory> shared_memory(
|
| + CreateSharedMemory(s_memory_size).Pass());
|
|
|
| // Send the underlying memory object to the client process.
|
| - SendMachPort(
|
| - client_port_.get(), shm.GetMemoryObject(), MACH_MSG_TYPE_COPY_SEND);
|
| + SendMachPort(client_port_.get(), shared_memory->handle().GetMemoryObject(),
|
| + MACH_MSG_TYPE_COPY_SEND);
|
| int rv = -1;
|
| ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
|
| TestTimeouts::action_timeout(), &rv));
|
| @@ -219,6 +261,10 @@ MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryClient) {
|
|
|
| // Tests that mapping shared memory with an offset works correctly.
|
| TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemoryWithOffset) {
|
| + // Mach-based SharedMemory isn't support on OSX 10.6.
|
| + if (mac::IsOSSnowLeopard())
|
| + return;
|
| +
|
| SetUpChild("MachBasedSharedMemoryWithOffsetClient");
|
|
|
| SharedMemoryHandle shm(s_memory_size);
|
| @@ -264,6 +310,10 @@ MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryWithOffsetClient) {
|
| // Tests that duplication and closing has the right effect on Mach reference
|
| // counts.
|
| TEST_F(SharedMemoryMacMultiProcessTest, MachDuplicateAndClose) {
|
| + // Mach-based SharedMemory isn't support on OSX 10.6.
|
| + if (mac::IsOSSnowLeopard())
|
| + return;
|
| +
|
| mach_msg_type_number_t active_name_count = GetActiveNameCount();
|
|
|
| // Making a new SharedMemoryHandle increments the name count.
|
| @@ -291,6 +341,10 @@ TEST_F(SharedMemoryMacMultiProcessTest, MachDuplicateAndClose) {
|
| // ownership, and that destroying the SharedMemory closes the SharedMemoryHandle
|
| // as well.
|
| TEST_F(SharedMemoryMacMultiProcessTest, MachSharedMemoryTakesOwnership) {
|
| + // Mach-based SharedMemory isn't support on OSX 10.6.
|
| + if (mac::IsOSSnowLeopard())
|
| + return;
|
| +
|
| mach_msg_type_number_t active_name_count = GetActiveNameCount();
|
|
|
| // Making a new SharedMemoryHandle increments the name count.
|
| @@ -310,17 +364,113 @@ TEST_F(SharedMemoryMacMultiProcessTest, MachSharedMemoryTakesOwnership) {
|
|
|
| // Tests that the read-only flag works.
|
| TEST_F(SharedMemoryMacMultiProcessTest, MachReadOnly) {
|
| - SharedMemoryHandle shm(s_memory_size);
|
| - ASSERT_TRUE(shm.IsValid());
|
| - SharedMemory shared_memory(shm, false);
|
| - shared_memory.Map(s_memory_size);
|
| - memset(shared_memory.memory(), 'a', s_memory_size);
|
| + // Mach-based SharedMemory isn't support on OSX 10.6.
|
| + if (mac::IsOSSnowLeopard())
|
| + return;
|
| +
|
| + scoped_ptr<SharedMemory> shared_memory(
|
| + CreateSharedMemory(s_memory_size).Pass());
|
|
|
| - SharedMemoryHandle shm2 = shm.Duplicate();
|
| + SharedMemoryHandle shm2 = shared_memory->handle().Duplicate();
|
| ASSERT_TRUE(shm2.IsValid());
|
| - SharedMemory shared_memory2(shm, true);
|
| + SharedMemory shared_memory2(shm2, true);
|
| shared_memory2.Map(s_memory_size);
|
| ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), "");
|
| }
|
|
|
| +// Tests that the method ShareToProcess() works.
|
| +TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcess) {
|
| + // Mach-based SharedMemory isn't support on OSX 10.6.
|
| + if (mac::IsOSSnowLeopard())
|
| + return;
|
| +
|
| + mach_msg_type_number_t active_name_count = GetActiveNameCount();
|
| +
|
| + {
|
| + scoped_ptr<SharedMemory> shared_memory(
|
| + CreateSharedMemory(s_memory_size).Pass());
|
| +
|
| + SharedMemoryHandle shm2;
|
| + ASSERT_TRUE(shared_memory->ShareToProcess(GetCurrentProcId(), &shm2));
|
| + ASSERT_TRUE(shm2.IsValid());
|
| + SharedMemory shared_memory2(shm2, true);
|
| + shared_memory2.Map(s_memory_size);
|
| +
|
| + ASSERT_EQ(0, memcmp(shared_memory->memory(), shared_memory2.memory(),
|
| + s_memory_size));
|
| + }
|
| +
|
| + EXPECT_EQ(active_name_count, GetActiveNameCount());
|
| +}
|
| +
|
| +// Tests that the method ShareReadOnlyToProcess() creates a memory object that
|
| +// is read only.
|
| +TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcessReadonly) {
|
| + // Mach-based SharedMemory isn't support on OSX 10.6.
|
| + if (mac::IsOSSnowLeopard())
|
| + return;
|
| +
|
| + scoped_ptr<SharedMemory> shared_memory(
|
| + CreateSharedMemory(s_memory_size).Pass());
|
| +
|
| + // Check the protection levels.
|
| + int current_prot, max_prot;
|
| + ASSERT_TRUE(GetProtections(shared_memory->memory(),
|
| + shared_memory->mapped_size(), ¤t_prot,
|
| + &max_prot));
|
| + ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, current_prot);
|
| + ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, max_prot);
|
| +
|
| + // Make a new memory object.
|
| + SharedMemoryHandle shm2;
|
| + ASSERT_TRUE(shared_memory->ShareReadOnlyToProcess(GetCurrentProcId(), &shm2));
|
| + ASSERT_TRUE(shm2.IsValid());
|
| +
|
| + // Mapping with |readonly| set to |false| should fail.
|
| + SharedMemory shared_memory2(shm2, false);
|
| + shared_memory2.Map(s_memory_size);
|
| + ASSERT_EQ(nullptr, shared_memory2.memory());
|
| +
|
| + // Now trying mapping with |readonly| set to |true|.
|
| + SharedMemory shared_memory3(shm2.Duplicate(), true);
|
| + shared_memory3.Map(s_memory_size);
|
| + ASSERT_NE(nullptr, shared_memory3.memory());
|
| +
|
| + // Check the protection levels.
|
| + ASSERT_TRUE(GetProtections(shared_memory3.memory(),
|
| + shared_memory3.mapped_size(), ¤t_prot,
|
| + &max_prot));
|
| + ASSERT_EQ(VM_PROT_READ, current_prot);
|
| + ASSERT_EQ(VM_PROT_READ, max_prot);
|
| +
|
| + // The memory should still be readonly, since the underlying memory object
|
| + // is readonly.
|
| + ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), "");
|
| +}
|
| +
|
| +// Tests that the method ShareReadOnlyToProcess() doesn't leak.
|
| +TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcessReadonlyLeak) {
|
| + // Mach-based SharedMemory isn't support on OSX 10.6.
|
| + if (mac::IsOSSnowLeopard())
|
| + return;
|
| +
|
| + mach_msg_type_number_t active_name_count = GetActiveNameCount();
|
| +
|
| + {
|
| + scoped_ptr<SharedMemory> shared_memory(
|
| + CreateSharedMemory(s_memory_size).Pass());
|
| +
|
| + SharedMemoryHandle shm2;
|
| + ASSERT_TRUE(
|
| + shared_memory->ShareReadOnlyToProcess(GetCurrentProcId(), &shm2));
|
| + ASSERT_TRUE(shm2.IsValid());
|
| +
|
| + // Intentionally map with |readonly| set to |false|.
|
| + SharedMemory shared_memory2(shm2, false);
|
| + shared_memory2.Map(s_memory_size);
|
| + }
|
| +
|
| + EXPECT_EQ(active_name_count, GetActiveNameCount());
|
| +}
|
| +
|
| } // namespace base
|
|
|