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 |