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
.CreateNamed(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
.CreateNamed("SharedMemoryMultipleLockThreadTest",
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
++) {
126 int i
= (id_
<< 16) + idx
;
128 PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
139 DISALLOW_COPY_AND_ASSIGN(MultipleLockThread
);
145 // Android doesn't support SharedMemory::Open/Delete/
146 // CreateNamed(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
.CreateNamed(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 open_existing works
206 SharedMemory memory1
;
207 bool rv
= memory1
.CreateNamed(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
.CreateNamed(test_name
, false, kDataSize2
);
230 // Should be able to create with openExisting true.
231 rv
= memory2
.CreateNamed(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 ASSERT_TRUE(writable_shmem
.CreateAndMapAnonymous(contents
.size()));
377 memcpy(writable_shmem
.memory(), contents
.data(), contents
.size());
378 EXPECT_TRUE(writable_shmem
.Unmap());
380 SharedMemoryHandle readonly_handle
;
381 ASSERT_TRUE(writable_shmem
.ShareReadOnlyToProcess(GetCurrentProcessHandle(),
383 SharedMemory
readonly_shmem(readonly_handle
, /*readonly=*/true);
385 ASSERT_TRUE(readonly_shmem
.Map(contents
.size()));
387 StringPiece(static_cast<const char*>(readonly_shmem
.memory()),
389 EXPECT_TRUE(readonly_shmem
.Unmap());
391 // Make sure the writable instance is still writable.
392 ASSERT_TRUE(writable_shmem
.Map(contents
.size()));
393 StringPiece new_contents
= "Goodbye";
394 memcpy(writable_shmem
.memory(), new_contents
.data(), new_contents
.size());
395 EXPECT_EQ(new_contents
,
396 StringPiece(static_cast<const char*>(writable_shmem
.memory()),
397 new_contents
.size()));
399 // We'd like to check that if we send the read-only segment to another
400 // process, then that other process can't reopen it read/write. (Since that
401 // would be a security hole.) Setting up multiple processes is hard in a
402 // unittest, so this test checks that the *current* process can't reopen the
403 // segment read/write. I think the test here is stronger than we actually
404 // care about, but there's a remote possibility that sending a file over a
405 // pipe would transform it into read/write.
406 SharedMemoryHandle handle
= readonly_shmem
.handle();
408 #if defined(OS_ANDROID)
409 // The "read-only" handle is still writable on Android:
410 // http://crbug.com/320865
412 #elif defined(OS_POSIX)
413 EXPECT_EQ(O_RDONLY
, fcntl(handle
.fd
, F_GETFL
) & O_ACCMODE
)
414 << "The descriptor itself should be read-only.";
417 void* writable
= mmap(
418 NULL
, contents
.size(), PROT_READ
| PROT_WRITE
, MAP_SHARED
, handle
.fd
, 0);
419 int mmap_errno
= errno
;
420 EXPECT_EQ(MAP_FAILED
, writable
)
421 << "It shouldn't be possible to re-mmap the descriptor writable.";
422 EXPECT_EQ(EACCES
, mmap_errno
) << strerror(mmap_errno
);
423 if (writable
!= MAP_FAILED
)
424 EXPECT_EQ(0, munmap(writable
, readonly_shmem
.mapped_size()));
426 #elif defined(OS_WIN)
427 EXPECT_EQ(NULL
, MapViewOfFile(handle
, FILE_MAP_WRITE
, 0, 0, 0))
428 << "Shouldn't be able to map memory writable.";
431 BOOL rv
= ::DuplicateHandle(GetCurrentProcess(),
439 << "Shouldn't be able to duplicate the handle into a writable one.";
441 base::win::ScopedHandle
writable_handle(temp_handle
);
443 #error Unexpected platform; write a test that tries to make 'handle' writable.
444 #endif // defined(OS_POSIX) || defined(OS_WIN)
447 TEST(SharedMemoryTest
, ShareToSelf
) {
448 StringPiece contents
= "Hello World";
451 ASSERT_TRUE(shmem
.CreateAndMapAnonymous(contents
.size()));
452 memcpy(shmem
.memory(), contents
.data(), contents
.size());
453 EXPECT_TRUE(shmem
.Unmap());
455 SharedMemoryHandle shared_handle
;
456 ASSERT_TRUE(shmem
.ShareToProcess(GetCurrentProcessHandle(), &shared_handle
));
457 SharedMemory
shared(shared_handle
, /*readonly=*/false);
459 ASSERT_TRUE(shared
.Map(contents
.size()));
462 StringPiece(static_cast<const char*>(shared
.memory()), contents
.size()));
464 ASSERT_TRUE(shmem
.ShareToProcess(GetCurrentProcessHandle(), &shared_handle
));
465 SharedMemory
readonly(shared_handle
, /*readonly=*/true);
467 ASSERT_TRUE(readonly
.Map(contents
.size()));
469 StringPiece(static_cast<const char*>(readonly
.memory()),
473 TEST(SharedMemoryTest
, MapAt
) {
474 ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32
));
475 const size_t kCount
= SysInfo::VMAllocationGranularity();
476 const size_t kDataSize
= kCount
* sizeof(uint32
);
479 ASSERT_TRUE(memory
.CreateAndMapAnonymous(kDataSize
));
480 ASSERT_TRUE(memory
.Map(kDataSize
));
481 uint32
* ptr
= static_cast<uint32
*>(memory
.memory());
482 ASSERT_NE(ptr
, static_cast<void*>(NULL
));
484 for (size_t i
= 0; i
< kCount
; ++i
) {
490 off_t offset
= SysInfo::VMAllocationGranularity();
491 ASSERT_TRUE(memory
.MapAt(offset
, kDataSize
- offset
));
492 offset
/= sizeof(uint32
);
493 ptr
= static_cast<uint32
*>(memory
.memory());
494 ASSERT_NE(ptr
, static_cast<void*>(NULL
));
495 for (size_t i
= offset
; i
< kCount
; ++i
) {
496 EXPECT_EQ(ptr
[i
- offset
], i
);
500 #if defined(OS_POSIX)
501 // Create a shared memory object, mmap it, and mprotect it to PROT_EXEC.
502 TEST(SharedMemoryTest
, AnonymousExecutable
) {
503 const uint32 kTestSize
= 1 << 16;
505 SharedMemory shared_memory
;
506 SharedMemoryCreateOptions options
;
507 options
.size
= kTestSize
;
508 options
.executable
= true;
510 EXPECT_TRUE(shared_memory
.Create(options
));
511 EXPECT_TRUE(shared_memory
.Map(shared_memory
.requested_size()));
513 EXPECT_EQ(0, mprotect(shared_memory
.memory(), shared_memory
.requested_size(),
514 PROT_READ
| PROT_EXEC
));
517 // Android supports a different permission model than POSIX for its "ashmem"
518 // shared memory implementation. So the tests about file permissions are not
519 // included on Android.
520 #if !defined(OS_ANDROID)
522 // Set a umask and restore the old mask on destruction.
523 class ScopedUmaskSetter
{
525 explicit ScopedUmaskSetter(mode_t target_mask
) {
526 old_umask_
= umask(target_mask
);
528 ~ScopedUmaskSetter() { umask(old_umask_
); }
531 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter
);
534 // Create a shared memory object, check its permissions.
535 TEST(SharedMemoryTest
, FilePermissionsAnonymous
) {
536 const uint32 kTestSize
= 1 << 8;
538 SharedMemory shared_memory
;
539 SharedMemoryCreateOptions options
;
540 options
.size
= kTestSize
;
541 // Set a file mode creation mask that gives all permissions.
542 ScopedUmaskSetter
permissive_mask(S_IWGRP
| S_IWOTH
);
544 EXPECT_TRUE(shared_memory
.Create(options
));
546 int shm_fd
= shared_memory
.handle().fd
;
547 struct stat shm_stat
;
548 EXPECT_EQ(0, fstat(shm_fd
, &shm_stat
));
549 // Neither the group, nor others should be able to read the shared memory
551 EXPECT_FALSE(shm_stat
.st_mode
& S_IRWXO
);
552 EXPECT_FALSE(shm_stat
.st_mode
& S_IRWXG
);
555 // Create a shared memory object, check its permissions.
556 TEST(SharedMemoryTest
, FilePermissionsNamed
) {
557 const uint32 kTestSize
= 1 << 8;
559 SharedMemory shared_memory
;
560 SharedMemoryCreateOptions options
;
561 options
.size
= kTestSize
;
562 std::string shared_mem_name
= "shared_perm_test-" + IntToString(getpid()) +
563 "-" + Uint64ToString(RandUint64());
564 options
.name
= &shared_mem_name
;
565 // Set a file mode creation mask that gives all permissions.
566 ScopedUmaskSetter
permissive_mask(S_IWGRP
| S_IWOTH
);
568 EXPECT_TRUE(shared_memory
.Create(options
));
569 // Clean-up the backing file name immediately, we don't need it.
570 EXPECT_TRUE(shared_memory
.Delete(shared_mem_name
));
572 int shm_fd
= shared_memory
.handle().fd
;
573 struct stat shm_stat
;
574 EXPECT_EQ(0, fstat(shm_fd
, &shm_stat
));
575 // Neither the group, nor others should have been able to open the shared
576 // memory file while its name existed.
577 EXPECT_FALSE(shm_stat
.st_mode
& S_IRWXO
);
578 EXPECT_FALSE(shm_stat
.st_mode
& S_IRWXG
);
580 #endif // !defined(OS_ANDROID)
582 #endif // defined(OS_POSIX)
584 // Map() will return addresses which are aligned to the platform page size, this
585 // varies from platform to platform though. Since we'd like to advertise a
586 // minimum alignment that callers can count on, test for it here.
587 TEST(SharedMemoryTest
, MapMinimumAlignment
) {
588 static const int kDataSize
= 8192;
590 SharedMemory shared_memory
;
591 ASSERT_TRUE(shared_memory
.CreateAndMapAnonymous(kDataSize
));
592 EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(
593 shared_memory
.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT
- 1));
594 shared_memory
.Close();
597 #if !defined(OS_IOS) // iOS does not allow multiple processes.
599 // On POSIX it is especially important we test shmem across processes,
600 // not just across threads. But the test is enabled on all platforms.
601 class SharedMemoryProcessTest
: public MultiProcessTest
{
604 static void CleanUp() {
606 memory
.Delete(s_test_name_
);
609 static int TaskTestMain() {
611 #if defined(OS_MACOSX)
612 mac::ScopedNSAutoreleasePool pool
;
614 const uint32 kDataSize
= 1024;
616 bool rv
= memory
.CreateNamed(s_test_name_
, true, kDataSize
);
620 rv
= memory
.Map(kDataSize
);
624 int *ptr
= static_cast<int*>(memory
.memory());
626 for (int idx
= 0; idx
< 20; idx
++) {
628 int i
= (1 << 16) + idx
;
630 PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
641 static const char* const s_test_name_
;
644 const char* const SharedMemoryProcessTest::s_test_name_
= "MPMem";
646 TEST_F(SharedMemoryProcessTest
, Tasks
) {
647 SharedMemoryProcessTest::CleanUp();
649 ProcessHandle handles
[kNumTasks
];
650 for (int index
= 0; index
< kNumTasks
; ++index
) {
651 handles
[index
] = SpawnChild("SharedMemoryTestMain", false);
652 ASSERT_TRUE(handles
[index
]);
656 for (int index
= 0; index
< kNumTasks
; ++index
) {
657 EXPECT_TRUE(WaitForExitCode(handles
[index
], &exit_code
));
658 EXPECT_EQ(0, exit_code
);
661 SharedMemoryProcessTest::CleanUp();
664 MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain
) {
665 return SharedMemoryProcessTest::TaskTestMain();