1 // Copyright (c) 2012 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.
5 #include "base/basictypes.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/memory/shared_memory.h"
8 #include "base/process/kill.h"
9 #include "base/rand_util.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/sys_info.h"
12 #include "base/test/multiprocess_test.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/time/time.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "testing/multiprocess_func_list.h"
18 #if defined(OS_MACOSX)
19 #include "base/mac/scoped_nsautorelease_pool.h"
27 #include <sys/types.h>
32 #include "base/win/scoped_handle.h"
35 static const int kNumThreads
= 5;
36 #if !defined(OS_IOS) // iOS does not allow multiple processes.
37 static const int kNumTasks
= 5;
44 // Each thread will open the shared memory. Each thread will take a different 4
45 // byte int pointer, and keep changing it, with some small pauses in between.
46 // Verify that each thread's value in the shared memory is always correct.
47 class MultipleThreadMain
: public PlatformThread::Delegate
{
49 explicit MultipleThreadMain(int16 id
) : id_(id
) {}
50 virtual ~MultipleThreadMain() {}
52 static void CleanUp() {
54 memory
.Delete(s_test_name_
);
57 // PlatformThread::Delegate interface.
58 virtual void ThreadMain() OVERRIDE
{
59 #if defined(OS_MACOSX)
60 mac::ScopedNSAutoreleasePool pool
;
62 const uint32 kDataSize
= 1024;
64 bool rv
= memory
.CreateNamedDeprecated(s_test_name_
, true, kDataSize
);
66 rv
= memory
.Map(kDataSize
);
68 int *ptr
= static_cast<int*>(memory
.memory()) + id_
;
71 for (int idx
= 0; idx
< 100; idx
++) {
73 PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
76 // Reset back to 0 for the next test that uses the same name.
85 static const char* const s_test_name_
;
87 DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain
);
90 const char* const MultipleThreadMain::s_test_name_
=
91 "SharedMemoryOpenThreadTest";
94 // This test requires the ability to pass file descriptors between processes.
95 // We haven't done that yet in Chrome for POSIX.
97 // Each thread will open the shared memory. Each thread will take the memory,
98 // and keep changing it while trying to lock it, with some small pauses in
99 // between. Verify that each thread's value in the shared memory is always
101 class MultipleLockThread
: public PlatformThread::Delegate
{
103 explicit MultipleLockThread(int id
) : id_(id
) {}
104 virtual ~MultipleLockThread() {}
106 // PlatformThread::Delegate interface.
107 virtual void ThreadMain() OVERRIDE
{
108 const uint32 kDataSize
= sizeof(int);
109 SharedMemoryHandle handle
= NULL
;
111 SharedMemory memory1
;
112 EXPECT_TRUE(memory1
.CreateNamedDeprecated(
113 "SharedMemoryMultipleLockThreadTest", true, kDataSize
));
114 EXPECT_TRUE(memory1
.ShareToProcess(GetCurrentProcess(), &handle
));
115 // TODO(paulg): Implement this once we have a posix version of
116 // SharedMemory::ShareToProcess.
120 SharedMemory
memory2(handle
, false);
121 EXPECT_TRUE(memory2
.Map(kDataSize
));
122 volatile int* const ptr
= static_cast<int*>(memory2
.memory());
124 for (int idx
= 0; idx
< 20; idx
++) {
125 memory2
.LockDeprecated();
126 int i
= (id_
<< 16) + idx
;
128 PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
130 memory2
.UnlockDeprecated();
139 DISALLOW_COPY_AND_ASSIGN(MultipleLockThread
);
145 // Android doesn't support SharedMemory::Open/Delete/
146 // CreateNamedDeprecated(openExisting=true)
147 #if !defined(OS_ANDROID)
148 TEST(SharedMemoryTest
, OpenClose
) {
149 const uint32 kDataSize
= 1024;
150 std::string test_name
= "SharedMemoryOpenCloseTest";
152 // Open two handles to a memory segment, confirm that they are mapped
153 // separately yet point to the same space.
154 SharedMemory memory1
;
155 bool rv
= memory1
.Delete(test_name
);
157 rv
= memory1
.Delete(test_name
);
159 rv
= memory1
.Open(test_name
, false);
161 rv
= memory1
.CreateNamedDeprecated(test_name
, false, kDataSize
);
163 rv
= memory1
.Map(kDataSize
);
165 SharedMemory memory2
;
166 rv
= memory2
.Open(test_name
, false);
168 rv
= memory2
.Map(kDataSize
);
170 EXPECT_NE(memory1
.memory(), memory2
.memory()); // Compare the pointers.
172 // Make sure we don't segfault. (it actually happened!)
173 ASSERT_NE(memory1
.memory(), static_cast<void*>(NULL
));
174 ASSERT_NE(memory2
.memory(), static_cast<void*>(NULL
));
176 // Write data to the first memory segment, verify contents of second.
177 memset(memory1
.memory(), '1', kDataSize
);
178 EXPECT_EQ(memcmp(memory1
.memory(), memory2
.memory(), kDataSize
), 0);
180 // Close the first memory segment, and verify the second has the right data.
182 char *start_ptr
= static_cast<char *>(memory2
.memory());
183 char *end_ptr
= start_ptr
+ kDataSize
;
184 for (char* ptr
= start_ptr
; ptr
< end_ptr
; ptr
++)
185 EXPECT_EQ(*ptr
, '1');
187 // Close the second memory segment.
190 rv
= memory1
.Delete(test_name
);
192 rv
= memory2
.Delete(test_name
);
196 TEST(SharedMemoryTest
, OpenExclusive
) {
197 const uint32 kDataSize
= 1024;
198 const uint32 kDataSize2
= 2048;
199 std::ostringstream test_name_stream
;
200 test_name_stream
<< "SharedMemoryOpenExclusiveTest."
201 << Time::Now().ToDoubleT();
202 std::string test_name
= test_name_stream
.str();
204 // Open two handles to a memory segment and check that
205 // open_existing_deprecated works as expected.
206 SharedMemory memory1
;
207 bool rv
= memory1
.CreateNamedDeprecated(test_name
, false, kDataSize
);
210 // Memory1 knows it's size because it created it.
211 EXPECT_EQ(memory1
.requested_size(), kDataSize
);
213 rv
= memory1
.Map(kDataSize
);
216 // The mapped memory1 must be at least the size we asked for.
217 EXPECT_GE(memory1
.mapped_size(), kDataSize
);
219 // The mapped memory1 shouldn't exceed rounding for allocation granularity.
220 EXPECT_LT(memory1
.mapped_size(),
221 kDataSize
+ base::SysInfo::VMAllocationGranularity());
223 memset(memory1
.memory(), 'G', kDataSize
);
225 SharedMemory memory2
;
226 // Should not be able to create if openExisting is false.
227 rv
= memory2
.CreateNamedDeprecated(test_name
, false, kDataSize2
);
230 // Should be able to create with openExisting true.
231 rv
= memory2
.CreateNamedDeprecated(test_name
, true, kDataSize2
);
234 // Memory2 shouldn't know the size because we didn't create it.
235 EXPECT_EQ(memory2
.requested_size(), 0U);
237 // We should be able to map the original size.
238 rv
= memory2
.Map(kDataSize
);
241 // The mapped memory2 must be at least the size of the original.
242 EXPECT_GE(memory2
.mapped_size(), kDataSize
);
244 // The mapped memory2 shouldn't exceed rounding for allocation granularity.
245 EXPECT_LT(memory2
.mapped_size(),
246 kDataSize2
+ base::SysInfo::VMAllocationGranularity());
248 // Verify that opening memory2 didn't truncate or delete memory 1.
249 char *start_ptr
= static_cast<char *>(memory2
.memory());
250 char *end_ptr
= start_ptr
+ kDataSize
;
251 for (char* ptr
= start_ptr
; ptr
< end_ptr
; ptr
++) {
252 EXPECT_EQ(*ptr
, 'G');
258 rv
= memory1
.Delete(test_name
);
263 // Create a set of N threads to each open a shared memory segment and write to
264 // it. Verify that they are always reading/writing consistent data.
265 TEST(SharedMemoryTest
, MultipleThreads
) {
266 MultipleThreadMain::CleanUp();
267 // On POSIX we have a problem when 2 threads try to create the shmem
268 // (a file) at exactly the same time, since create both creates the
269 // file and zerofills it. We solve the problem for this unit test
270 // (make it not flaky) by starting with 1 thread, then
271 // intentionally don't clean up its shmem before running with
274 int threadcounts
[] = { 1, kNumThreads
};
275 for (size_t i
= 0; i
< arraysize(threadcounts
); i
++) {
276 int numthreads
= threadcounts
[i
];
277 scoped_ptr
<PlatformThreadHandle
[]> thread_handles
;
278 scoped_ptr
<MultipleThreadMain
*[]> thread_delegates
;
280 thread_handles
.reset(new PlatformThreadHandle
[numthreads
]);
281 thread_delegates
.reset(new MultipleThreadMain
*[numthreads
]);
283 // Spawn the threads.
284 for (int16 index
= 0; index
< numthreads
; index
++) {
285 PlatformThreadHandle pth
;
286 thread_delegates
[index
] = new MultipleThreadMain(index
);
287 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates
[index
], &pth
));
288 thread_handles
[index
] = pth
;
291 // Wait for the threads to finish.
292 for (int index
= 0; index
< numthreads
; index
++) {
293 PlatformThread::Join(thread_handles
[index
]);
294 delete thread_delegates
[index
];
297 MultipleThreadMain::CleanUp();
300 // TODO(port): this test requires the MultipleLockThread class
301 // (defined above), which requires the ability to pass file
302 // descriptors between processes. We haven't done that yet in Chrome
305 // Create a set of threads to each open a shared memory segment and write to it
306 // with the lock held. Verify that they are always reading/writing consistent
308 TEST(SharedMemoryTest
, Lock
) {
309 PlatformThreadHandle thread_handles
[kNumThreads
];
310 MultipleLockThread
* thread_delegates
[kNumThreads
];
312 // Spawn the threads.
313 for (int index
= 0; index
< kNumThreads
; ++index
) {
314 PlatformThreadHandle pth
;
315 thread_delegates
[index
] = new MultipleLockThread(index
);
316 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates
[index
], &pth
));
317 thread_handles
[index
] = pth
;
320 // Wait for the threads to finish.
321 for (int index
= 0; index
< kNumThreads
; ++index
) {
322 PlatformThread::Join(thread_handles
[index
]);
323 delete thread_delegates
[index
];
328 // Allocate private (unique) shared memory with an empty string for a
329 // name. Make sure several of them don't point to the same thing as
330 // we might expect if the names are equal.
331 TEST(SharedMemoryTest
, AnonymousPrivate
) {
335 const uint32 kDataSize
= 8192;
337 scoped_ptr
<SharedMemory
[]> memories(new SharedMemory
[count
]);
338 scoped_ptr
<int*[]> pointers(new int*[count
]);
339 ASSERT_TRUE(memories
.get());
340 ASSERT_TRUE(pointers
.get());
342 for (i
= 0; i
< count
; i
++) {
343 rv
= memories
[i
].CreateAndMapAnonymous(kDataSize
);
345 int *ptr
= static_cast<int*>(memories
[i
].memory());
350 for (i
= 0; i
< count
; i
++) {
351 // zero out the first int in each except for i; for that one, make it 100.
352 for (j
= 0; j
< count
; j
++) {
354 pointers
[j
][0] = 100;
358 // make sure there is no bleeding of the 100 into the other pointers
359 for (j
= 0; j
< count
; j
++) {
361 EXPECT_EQ(100, pointers
[j
][0]);
363 EXPECT_EQ(0, pointers
[j
][0]);
367 for (int i
= 0; i
< count
; i
++) {
372 TEST(SharedMemoryTest
, ShareReadOnly
) {
373 StringPiece contents
= "Hello World";
375 SharedMemory writable_shmem
;
376 SharedMemoryCreateOptions options
;
377 options
.size
= contents
.size();
378 options
.share_read_only
= true;
379 ASSERT_TRUE(writable_shmem
.Create(options
));
380 ASSERT_TRUE(writable_shmem
.Map(options
.size
));
381 memcpy(writable_shmem
.memory(), contents
.data(), contents
.size());
382 EXPECT_TRUE(writable_shmem
.Unmap());
384 SharedMemoryHandle readonly_handle
;
385 ASSERT_TRUE(writable_shmem
.ShareReadOnlyToProcess(GetCurrentProcessHandle(),
387 SharedMemory
readonly_shmem(readonly_handle
, /*readonly=*/true);
389 ASSERT_TRUE(readonly_shmem
.Map(contents
.size()));
391 StringPiece(static_cast<const char*>(readonly_shmem
.memory()),
393 EXPECT_TRUE(readonly_shmem
.Unmap());
395 // Make sure the writable instance is still writable.
396 ASSERT_TRUE(writable_shmem
.Map(contents
.size()));
397 StringPiece new_contents
= "Goodbye";
398 memcpy(writable_shmem
.memory(), new_contents
.data(), new_contents
.size());
399 EXPECT_EQ(new_contents
,
400 StringPiece(static_cast<const char*>(writable_shmem
.memory()),
401 new_contents
.size()));
403 // We'd like to check that if we send the read-only segment to another
404 // process, then that other process can't reopen it read/write. (Since that
405 // would be a security hole.) Setting up multiple processes is hard in a
406 // unittest, so this test checks that the *current* process can't reopen the
407 // segment read/write. I think the test here is stronger than we actually
408 // care about, but there's a remote possibility that sending a file over a
409 // pipe would transform it into read/write.
410 SharedMemoryHandle handle
= readonly_shmem
.handle();
412 #if defined(OS_ANDROID)
413 // The "read-only" handle is still writable on Android:
414 // http://crbug.com/320865
416 #elif defined(OS_POSIX)
417 EXPECT_EQ(O_RDONLY
, fcntl(handle
.fd
, F_GETFL
) & O_ACCMODE
)
418 << "The descriptor itself should be read-only.";
421 void* writable
= mmap(
422 NULL
, contents
.size(), PROT_READ
| PROT_WRITE
, MAP_SHARED
, handle
.fd
, 0);
423 int mmap_errno
= errno
;
424 EXPECT_EQ(MAP_FAILED
, writable
)
425 << "It shouldn't be possible to re-mmap the descriptor writable.";
426 EXPECT_EQ(EACCES
, mmap_errno
) << strerror(mmap_errno
);
427 if (writable
!= MAP_FAILED
)
428 EXPECT_EQ(0, munmap(writable
, readonly_shmem
.mapped_size()));
430 #elif defined(OS_WIN)
431 EXPECT_EQ(NULL
, MapViewOfFile(handle
, FILE_MAP_WRITE
, 0, 0, 0))
432 << "Shouldn't be able to map memory writable.";
435 BOOL rv
= ::DuplicateHandle(GetCurrentProcess(),
443 << "Shouldn't be able to duplicate the handle into a writable one.";
445 base::win::ScopedHandle
writable_handle(temp_handle
);
447 #error Unexpected platform; write a test that tries to make 'handle' writable.
448 #endif // defined(OS_POSIX) || defined(OS_WIN)
451 TEST(SharedMemoryTest
, ShareToSelf
) {
452 StringPiece contents
= "Hello World";
455 ASSERT_TRUE(shmem
.CreateAndMapAnonymous(contents
.size()));
456 memcpy(shmem
.memory(), contents
.data(), contents
.size());
457 EXPECT_TRUE(shmem
.Unmap());
459 SharedMemoryHandle shared_handle
;
460 ASSERT_TRUE(shmem
.ShareToProcess(GetCurrentProcessHandle(), &shared_handle
));
461 SharedMemory
shared(shared_handle
, /*readonly=*/false);
463 ASSERT_TRUE(shared
.Map(contents
.size()));
466 StringPiece(static_cast<const char*>(shared
.memory()), contents
.size()));
468 ASSERT_TRUE(shmem
.ShareToProcess(GetCurrentProcessHandle(), &shared_handle
));
469 SharedMemory
readonly(shared_handle
, /*readonly=*/true);
471 ASSERT_TRUE(readonly
.Map(contents
.size()));
473 StringPiece(static_cast<const char*>(readonly
.memory()),
477 TEST(SharedMemoryTest
, MapAt
) {
478 ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32
));
479 const size_t kCount
= SysInfo::VMAllocationGranularity();
480 const size_t kDataSize
= kCount
* sizeof(uint32
);
483 ASSERT_TRUE(memory
.CreateAndMapAnonymous(kDataSize
));
484 uint32
* ptr
= static_cast<uint32
*>(memory
.memory());
485 ASSERT_NE(ptr
, static_cast<void*>(NULL
));
487 for (size_t i
= 0; i
< kCount
; ++i
) {
493 off_t offset
= SysInfo::VMAllocationGranularity();
494 ASSERT_TRUE(memory
.MapAt(offset
, kDataSize
- offset
));
495 offset
/= sizeof(uint32
);
496 ptr
= static_cast<uint32
*>(memory
.memory());
497 ASSERT_NE(ptr
, static_cast<void*>(NULL
));
498 for (size_t i
= offset
; i
< kCount
; ++i
) {
499 EXPECT_EQ(ptr
[i
- offset
], i
);
503 TEST(SharedMemoryTest
, MapTwice
) {
504 const uint32 kDataSize
= 1024;
506 bool rv
= memory
.CreateAndMapAnonymous(kDataSize
);
509 void* old_address
= memory
.memory();
511 rv
= memory
.Map(kDataSize
);
513 EXPECT_EQ(old_address
, memory
.memory());
516 #if defined(OS_POSIX)
517 // Create a shared memory object, mmap it, and mprotect it to PROT_EXEC.
518 TEST(SharedMemoryTest
, AnonymousExecutable
) {
519 const uint32 kTestSize
= 1 << 16;
521 SharedMemory shared_memory
;
522 SharedMemoryCreateOptions options
;
523 options
.size
= kTestSize
;
524 options
.executable
= true;
526 EXPECT_TRUE(shared_memory
.Create(options
));
527 EXPECT_TRUE(shared_memory
.Map(shared_memory
.requested_size()));
529 EXPECT_EQ(0, mprotect(shared_memory
.memory(), shared_memory
.requested_size(),
530 PROT_READ
| PROT_EXEC
));
533 // Android supports a different permission model than POSIX for its "ashmem"
534 // shared memory implementation. So the tests about file permissions are not
535 // included on Android.
536 #if !defined(OS_ANDROID)
538 // Set a umask and restore the old mask on destruction.
539 class ScopedUmaskSetter
{
541 explicit ScopedUmaskSetter(mode_t target_mask
) {
542 old_umask_
= umask(target_mask
);
544 ~ScopedUmaskSetter() { umask(old_umask_
); }
547 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter
);
550 // Create a shared memory object, check its permissions.
551 TEST(SharedMemoryTest
, FilePermissionsAnonymous
) {
552 const uint32 kTestSize
= 1 << 8;
554 SharedMemory shared_memory
;
555 SharedMemoryCreateOptions options
;
556 options
.size
= kTestSize
;
557 // Set a file mode creation mask that gives all permissions.
558 ScopedUmaskSetter
permissive_mask(S_IWGRP
| S_IWOTH
);
560 EXPECT_TRUE(shared_memory
.Create(options
));
562 int shm_fd
= shared_memory
.handle().fd
;
563 struct stat shm_stat
;
564 EXPECT_EQ(0, fstat(shm_fd
, &shm_stat
));
565 // Neither the group, nor others should be able to read the shared memory
567 EXPECT_FALSE(shm_stat
.st_mode
& S_IRWXO
);
568 EXPECT_FALSE(shm_stat
.st_mode
& S_IRWXG
);
571 // Create a shared memory object, check its permissions.
572 TEST(SharedMemoryTest
, FilePermissionsNamed
) {
573 const uint32 kTestSize
= 1 << 8;
575 SharedMemory shared_memory
;
576 SharedMemoryCreateOptions options
;
577 options
.size
= kTestSize
;
578 std::string shared_mem_name
= "shared_perm_test-" + IntToString(getpid()) +
579 "-" + Uint64ToString(RandUint64());
580 options
.name_deprecated
= &shared_mem_name
;
581 // Set a file mode creation mask that gives all permissions.
582 ScopedUmaskSetter
permissive_mask(S_IWGRP
| S_IWOTH
);
584 EXPECT_TRUE(shared_memory
.Create(options
));
585 // Clean-up the backing file name immediately, we don't need it.
586 EXPECT_TRUE(shared_memory
.Delete(shared_mem_name
));
588 int shm_fd
= shared_memory
.handle().fd
;
589 struct stat shm_stat
;
590 EXPECT_EQ(0, fstat(shm_fd
, &shm_stat
));
591 // Neither the group, nor others should have been able to open the shared
592 // memory file while its name existed.
593 EXPECT_FALSE(shm_stat
.st_mode
& S_IRWXO
);
594 EXPECT_FALSE(shm_stat
.st_mode
& S_IRWXG
);
596 #endif // !defined(OS_ANDROID)
598 #endif // defined(OS_POSIX)
600 // Map() will return addresses which are aligned to the platform page size, this
601 // varies from platform to platform though. Since we'd like to advertise a
602 // minimum alignment that callers can count on, test for it here.
603 TEST(SharedMemoryTest
, MapMinimumAlignment
) {
604 static const int kDataSize
= 8192;
606 SharedMemory shared_memory
;
607 ASSERT_TRUE(shared_memory
.CreateAndMapAnonymous(kDataSize
));
608 EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(
609 shared_memory
.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT
- 1));
610 shared_memory
.Close();
613 #if !defined(OS_IOS) // iOS does not allow multiple processes.
615 // On POSIX it is especially important we test shmem across processes,
616 // not just across threads. But the test is enabled on all platforms.
617 class SharedMemoryProcessTest
: public MultiProcessTest
{
620 static void CleanUp() {
622 memory
.Delete(s_test_name_
);
625 static int TaskTestMain() {
627 #if defined(OS_MACOSX)
628 mac::ScopedNSAutoreleasePool pool
;
630 const uint32 kDataSize
= 1024;
632 bool rv
= memory
.CreateNamedDeprecated(s_test_name_
, true, kDataSize
);
636 rv
= memory
.Map(kDataSize
);
640 int *ptr
= static_cast<int*>(memory
.memory());
642 for (int idx
= 0; idx
< 20; idx
++) {
643 memory
.LockDeprecated();
644 int i
= (1 << 16) + idx
;
646 PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
649 memory
.UnlockDeprecated();
657 static const char* const s_test_name_
;
660 const char* const SharedMemoryProcessTest::s_test_name_
= "MPMem";
662 TEST_F(SharedMemoryProcessTest
, Tasks
) {
663 SharedMemoryProcessTest::CleanUp();
665 ProcessHandle handles
[kNumTasks
];
666 for (int index
= 0; index
< kNumTasks
; ++index
) {
667 handles
[index
] = SpawnChild("SharedMemoryTestMain");
668 ASSERT_TRUE(handles
[index
]);
672 for (int index
= 0; index
< kNumTasks
; ++index
) {
673 EXPECT_TRUE(WaitForExitCode(handles
[index
], &exit_code
));
674 EXPECT_EQ(0, exit_code
);
677 SharedMemoryProcessTest::CleanUp();
680 MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain
) {
681 return SharedMemoryProcessTest::TaskTestMain();