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/atomicops.h"
6 #include "base/basictypes.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/memory/shared_memory.h"
9 #include "base/process/kill.h"
10 #include "base/rand_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/sys_info.h"
13 #include "base/test/multiprocess_test.h"
14 #include "base/threading/platform_thread.h"
15 #include "base/time/time.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "testing/multiprocess_func_list.h"
19 #if defined(OS_MACOSX)
20 #include "base/mac/scoped_nsautorelease_pool.h"
28 #include <sys/types.h>
33 #include "base/win/scoped_handle.h"
36 static const int kNumThreads
= 5;
37 #if !defined(OS_IOS) && !defined(OS_ANDROID)
38 static const int kNumTasks
= 5;
45 // Each thread will open the shared memory. Each thread will take a different 4
46 // byte int pointer, and keep changing it, with some small pauses in between.
47 // Verify that each thread's value in the shared memory is always correct.
48 class MultipleThreadMain
: public PlatformThread::Delegate
{
50 explicit MultipleThreadMain(int16 id
) : id_(id
) {}
51 ~MultipleThreadMain() override
{}
53 static void CleanUp() {
55 memory
.Delete(s_test_name_
);
58 // PlatformThread::Delegate interface.
59 void ThreadMain() override
{
60 #if defined(OS_MACOSX)
61 mac::ScopedNSAutoreleasePool pool
;
63 const uint32 kDataSize
= 1024;
65 bool rv
= memory
.CreateNamedDeprecated(s_test_name_
, true, kDataSize
);
67 rv
= memory
.Map(kDataSize
);
69 int *ptr
= static_cast<int*>(memory
.memory()) + id_
;
72 for (int idx
= 0; idx
< 100; idx
++) {
74 PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
77 // Reset back to 0 for the next test that uses the same name.
86 static const char* const s_test_name_
;
88 DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain
);
91 const char* const MultipleThreadMain::s_test_name_
=
92 "SharedMemoryOpenThreadTest";
96 // Android doesn't support SharedMemory::Open/Delete/
97 // CreateNamedDeprecated(openExisting=true)
98 #if !defined(OS_ANDROID)
99 TEST(SharedMemoryTest
, OpenClose
) {
100 const uint32 kDataSize
= 1024;
101 std::string test_name
= "SharedMemoryOpenCloseTest";
103 // Open two handles to a memory segment, confirm that they are mapped
104 // separately yet point to the same space.
105 SharedMemory memory1
;
106 bool rv
= memory1
.Delete(test_name
);
108 rv
= memory1
.Delete(test_name
);
110 rv
= memory1
.Open(test_name
, false);
112 rv
= memory1
.CreateNamedDeprecated(test_name
, false, kDataSize
);
114 rv
= memory1
.Map(kDataSize
);
116 SharedMemory memory2
;
117 rv
= memory2
.Open(test_name
, false);
119 rv
= memory2
.Map(kDataSize
);
121 EXPECT_NE(memory1
.memory(), memory2
.memory()); // Compare the pointers.
123 // Make sure we don't segfault. (it actually happened!)
124 ASSERT_NE(memory1
.memory(), static_cast<void*>(NULL
));
125 ASSERT_NE(memory2
.memory(), static_cast<void*>(NULL
));
127 // Write data to the first memory segment, verify contents of second.
128 memset(memory1
.memory(), '1', kDataSize
);
129 EXPECT_EQ(memcmp(memory1
.memory(), memory2
.memory(), kDataSize
), 0);
131 // Close the first memory segment, and verify the second has the right data.
133 char *start_ptr
= static_cast<char *>(memory2
.memory());
134 char *end_ptr
= start_ptr
+ kDataSize
;
135 for (char* ptr
= start_ptr
; ptr
< end_ptr
; ptr
++)
136 EXPECT_EQ(*ptr
, '1');
138 // Close the second memory segment.
141 rv
= memory1
.Delete(test_name
);
143 rv
= memory2
.Delete(test_name
);
147 TEST(SharedMemoryTest
, OpenExclusive
) {
148 const uint32 kDataSize
= 1024;
149 const uint32 kDataSize2
= 2048;
150 std::ostringstream test_name_stream
;
151 test_name_stream
<< "SharedMemoryOpenExclusiveTest."
152 << Time::Now().ToDoubleT();
153 std::string test_name
= test_name_stream
.str();
155 // Open two handles to a memory segment and check that
156 // open_existing_deprecated works as expected.
157 SharedMemory memory1
;
158 bool rv
= memory1
.CreateNamedDeprecated(test_name
, false, kDataSize
);
161 // Memory1 knows it's size because it created it.
162 EXPECT_EQ(memory1
.requested_size(), kDataSize
);
164 rv
= memory1
.Map(kDataSize
);
167 // The mapped memory1 must be at least the size we asked for.
168 EXPECT_GE(memory1
.mapped_size(), kDataSize
);
170 // The mapped memory1 shouldn't exceed rounding for allocation granularity.
171 EXPECT_LT(memory1
.mapped_size(),
172 kDataSize
+ base::SysInfo::VMAllocationGranularity());
174 memset(memory1
.memory(), 'G', kDataSize
);
176 SharedMemory memory2
;
177 // Should not be able to create if openExisting is false.
178 rv
= memory2
.CreateNamedDeprecated(test_name
, false, kDataSize2
);
181 // Should be able to create with openExisting true.
182 rv
= memory2
.CreateNamedDeprecated(test_name
, true, kDataSize2
);
185 // Memory2 shouldn't know the size because we didn't create it.
186 EXPECT_EQ(memory2
.requested_size(), 0U);
188 // We should be able to map the original size.
189 rv
= memory2
.Map(kDataSize
);
192 // The mapped memory2 must be at least the size of the original.
193 EXPECT_GE(memory2
.mapped_size(), kDataSize
);
195 // The mapped memory2 shouldn't exceed rounding for allocation granularity.
196 EXPECT_LT(memory2
.mapped_size(),
197 kDataSize2
+ base::SysInfo::VMAllocationGranularity());
199 // Verify that opening memory2 didn't truncate or delete memory 1.
200 char *start_ptr
= static_cast<char *>(memory2
.memory());
201 char *end_ptr
= start_ptr
+ kDataSize
;
202 for (char* ptr
= start_ptr
; ptr
< end_ptr
; ptr
++) {
203 EXPECT_EQ(*ptr
, 'G');
209 rv
= memory1
.Delete(test_name
);
214 // Check that memory is still mapped after its closed.
215 TEST(SharedMemoryTest
, CloseNoUnmap
) {
216 const size_t kDataSize
= 4096;
219 ASSERT_TRUE(memory
.CreateAndMapAnonymous(kDataSize
));
220 char* ptr
= static_cast<char*>(memory
.memory());
221 ASSERT_NE(ptr
, static_cast<void*>(NULL
));
222 memset(ptr
, 'G', kDataSize
);
226 EXPECT_EQ(ptr
, memory
.memory());
227 EXPECT_EQ(SharedMemory::NULLHandle(), memory
.handle());
229 for (size_t i
= 0; i
< kDataSize
; i
++) {
230 EXPECT_EQ('G', ptr
[i
]);
234 EXPECT_EQ(nullptr, memory
.memory());
237 // Create a set of N threads to each open a shared memory segment and write to
238 // it. Verify that they are always reading/writing consistent data.
239 TEST(SharedMemoryTest
, MultipleThreads
) {
240 MultipleThreadMain::CleanUp();
241 // On POSIX we have a problem when 2 threads try to create the shmem
242 // (a file) at exactly the same time, since create both creates the
243 // file and zerofills it. We solve the problem for this unit test
244 // (make it not flaky) by starting with 1 thread, then
245 // intentionally don't clean up its shmem before running with
248 int threadcounts
[] = { 1, kNumThreads
};
249 for (size_t i
= 0; i
< arraysize(threadcounts
); i
++) {
250 int numthreads
= threadcounts
[i
];
251 scoped_ptr
<PlatformThreadHandle
[]> thread_handles
;
252 scoped_ptr
<MultipleThreadMain
*[]> thread_delegates
;
254 thread_handles
.reset(new PlatformThreadHandle
[numthreads
]);
255 thread_delegates
.reset(new MultipleThreadMain
*[numthreads
]);
257 // Spawn the threads.
258 for (int16 index
= 0; index
< numthreads
; index
++) {
259 PlatformThreadHandle pth
;
260 thread_delegates
[index
] = new MultipleThreadMain(index
);
261 EXPECT_TRUE(PlatformThread::Create(0, thread_delegates
[index
], &pth
));
262 thread_handles
[index
] = pth
;
265 // Wait for the threads to finish.
266 for (int index
= 0; index
< numthreads
; index
++) {
267 PlatformThread::Join(thread_handles
[index
]);
268 delete thread_delegates
[index
];
271 MultipleThreadMain::CleanUp();
274 // Allocate private (unique) shared memory with an empty string for a
275 // name. Make sure several of them don't point to the same thing as
276 // we might expect if the names are equal.
277 TEST(SharedMemoryTest
, AnonymousPrivate
) {
281 const uint32 kDataSize
= 8192;
283 scoped_ptr
<SharedMemory
[]> memories(new SharedMemory
[count
]);
284 scoped_ptr
<int*[]> pointers(new int*[count
]);
285 ASSERT_TRUE(memories
.get());
286 ASSERT_TRUE(pointers
.get());
288 for (i
= 0; i
< count
; i
++) {
289 rv
= memories
[i
].CreateAndMapAnonymous(kDataSize
);
291 int *ptr
= static_cast<int*>(memories
[i
].memory());
296 for (i
= 0; i
< count
; i
++) {
297 // zero out the first int in each except for i; for that one, make it 100.
298 for (j
= 0; j
< count
; j
++) {
300 pointers
[j
][0] = 100;
304 // make sure there is no bleeding of the 100 into the other pointers
305 for (j
= 0; j
< count
; j
++) {
307 EXPECT_EQ(100, pointers
[j
][0]);
309 EXPECT_EQ(0, pointers
[j
][0]);
313 for (int i
= 0; i
< count
; i
++) {
318 TEST(SharedMemoryTest
, ShareReadOnly
) {
319 StringPiece contents
= "Hello World";
321 SharedMemory writable_shmem
;
322 SharedMemoryCreateOptions options
;
323 options
.size
= contents
.size();
324 options
.share_read_only
= true;
325 ASSERT_TRUE(writable_shmem
.Create(options
));
326 ASSERT_TRUE(writable_shmem
.Map(options
.size
));
327 memcpy(writable_shmem
.memory(), contents
.data(), contents
.size());
328 EXPECT_TRUE(writable_shmem
.Unmap());
330 SharedMemoryHandle readonly_handle
;
331 ASSERT_TRUE(writable_shmem
.ShareReadOnlyToProcess(GetCurrentProcessHandle(),
333 SharedMemory
readonly_shmem(readonly_handle
, /*readonly=*/true);
335 ASSERT_TRUE(readonly_shmem
.Map(contents
.size()));
337 StringPiece(static_cast<const char*>(readonly_shmem
.memory()),
339 EXPECT_TRUE(readonly_shmem
.Unmap());
341 // Make sure the writable instance is still writable.
342 ASSERT_TRUE(writable_shmem
.Map(contents
.size()));
343 StringPiece new_contents
= "Goodbye";
344 memcpy(writable_shmem
.memory(), new_contents
.data(), new_contents
.size());
345 EXPECT_EQ(new_contents
,
346 StringPiece(static_cast<const char*>(writable_shmem
.memory()),
347 new_contents
.size()));
349 // We'd like to check that if we send the read-only segment to another
350 // process, then that other process can't reopen it read/write. (Since that
351 // would be a security hole.) Setting up multiple processes is hard in a
352 // unittest, so this test checks that the *current* process can't reopen the
353 // segment read/write. I think the test here is stronger than we actually
354 // care about, but there's a remote possibility that sending a file over a
355 // pipe would transform it into read/write.
356 SharedMemoryHandle handle
= readonly_shmem
.handle();
358 #if defined(OS_ANDROID)
359 // The "read-only" handle is still writable on Android:
360 // http://crbug.com/320865
362 #elif defined(OS_POSIX)
363 EXPECT_EQ(O_RDONLY
, fcntl(handle
.fd
, F_GETFL
) & O_ACCMODE
)
364 << "The descriptor itself should be read-only.";
367 void* writable
= mmap(
368 NULL
, contents
.size(), PROT_READ
| PROT_WRITE
, MAP_SHARED
, handle
.fd
, 0);
369 int mmap_errno
= errno
;
370 EXPECT_EQ(MAP_FAILED
, writable
)
371 << "It shouldn't be possible to re-mmap the descriptor writable.";
372 EXPECT_EQ(EACCES
, mmap_errno
) << strerror(mmap_errno
);
373 if (writable
!= MAP_FAILED
)
374 EXPECT_EQ(0, munmap(writable
, readonly_shmem
.mapped_size()));
376 #elif defined(OS_WIN)
377 EXPECT_EQ(NULL
, MapViewOfFile(handle
, FILE_MAP_WRITE
, 0, 0, 0))
378 << "Shouldn't be able to map memory writable.";
381 BOOL rv
= ::DuplicateHandle(GetCurrentProcess(),
389 << "Shouldn't be able to duplicate the handle into a writable one.";
391 base::win::ScopedHandle
writable_handle(temp_handle
);
392 rv
= ::DuplicateHandle(GetCurrentProcess(),
400 << "Should be able to duplicate the handle into a readable one.";
402 base::win::ScopedHandle
writable_handle(temp_handle
);
404 #error Unexpected platform; write a test that tries to make 'handle' writable.
405 #endif // defined(OS_POSIX) || defined(OS_WIN)
408 TEST(SharedMemoryTest
, ShareToSelf
) {
409 StringPiece contents
= "Hello World";
412 ASSERT_TRUE(shmem
.CreateAndMapAnonymous(contents
.size()));
413 memcpy(shmem
.memory(), contents
.data(), contents
.size());
414 EXPECT_TRUE(shmem
.Unmap());
416 SharedMemoryHandle shared_handle
;
417 ASSERT_TRUE(shmem
.ShareToProcess(GetCurrentProcessHandle(), &shared_handle
));
418 SharedMemory
shared(shared_handle
, /*readonly=*/false);
420 ASSERT_TRUE(shared
.Map(contents
.size()));
423 StringPiece(static_cast<const char*>(shared
.memory()), contents
.size()));
425 ASSERT_TRUE(shmem
.ShareToProcess(GetCurrentProcessHandle(), &shared_handle
));
426 SharedMemory
readonly(shared_handle
, /*readonly=*/true);
428 ASSERT_TRUE(readonly
.Map(contents
.size()));
430 StringPiece(static_cast<const char*>(readonly
.memory()),
434 TEST(SharedMemoryTest
, MapAt
) {
435 ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32
));
436 const size_t kCount
= SysInfo::VMAllocationGranularity();
437 const size_t kDataSize
= kCount
* sizeof(uint32
);
440 ASSERT_TRUE(memory
.CreateAndMapAnonymous(kDataSize
));
441 uint32
* ptr
= static_cast<uint32
*>(memory
.memory());
442 ASSERT_NE(ptr
, static_cast<void*>(NULL
));
444 for (size_t i
= 0; i
< kCount
; ++i
) {
450 off_t offset
= SysInfo::VMAllocationGranularity();
451 ASSERT_TRUE(memory
.MapAt(offset
, kDataSize
- offset
));
452 offset
/= sizeof(uint32
);
453 ptr
= static_cast<uint32
*>(memory
.memory());
454 ASSERT_NE(ptr
, static_cast<void*>(NULL
));
455 for (size_t i
= offset
; i
< kCount
; ++i
) {
456 EXPECT_EQ(ptr
[i
- offset
], i
);
460 TEST(SharedMemoryTest
, MapTwice
) {
461 const uint32 kDataSize
= 1024;
463 bool rv
= memory
.CreateAndMapAnonymous(kDataSize
);
466 void* old_address
= memory
.memory();
468 rv
= memory
.Map(kDataSize
);
470 EXPECT_EQ(old_address
, memory
.memory());
473 #if defined(OS_POSIX)
474 // This test is not applicable for iOS (crbug.com/399384).
476 // Create a shared memory object, mmap it, and mprotect it to PROT_EXEC.
477 TEST(SharedMemoryTest
, AnonymousExecutable
) {
478 const uint32 kTestSize
= 1 << 16;
480 SharedMemory shared_memory
;
481 SharedMemoryCreateOptions options
;
482 options
.size
= kTestSize
;
483 options
.executable
= true;
485 EXPECT_TRUE(shared_memory
.Create(options
));
486 EXPECT_TRUE(shared_memory
.Map(shared_memory
.requested_size()));
488 EXPECT_EQ(0, mprotect(shared_memory
.memory(), shared_memory
.requested_size(),
489 PROT_READ
| PROT_EXEC
));
491 #endif // !defined(OS_IOS)
493 // Android supports a different permission model than POSIX for its "ashmem"
494 // shared memory implementation. So the tests about file permissions are not
495 // included on Android.
496 #if !defined(OS_ANDROID)
498 // Set a umask and restore the old mask on destruction.
499 class ScopedUmaskSetter
{
501 explicit ScopedUmaskSetter(mode_t target_mask
) {
502 old_umask_
= umask(target_mask
);
504 ~ScopedUmaskSetter() { umask(old_umask_
); }
507 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter
);
510 // Create a shared memory object, check its permissions.
511 TEST(SharedMemoryTest
, FilePermissionsAnonymous
) {
512 const uint32 kTestSize
= 1 << 8;
514 SharedMemory shared_memory
;
515 SharedMemoryCreateOptions options
;
516 options
.size
= kTestSize
;
517 // Set a file mode creation mask that gives all permissions.
518 ScopedUmaskSetter
permissive_mask(S_IWGRP
| S_IWOTH
);
520 EXPECT_TRUE(shared_memory
.Create(options
));
522 int shm_fd
= shared_memory
.handle().fd
;
523 struct stat shm_stat
;
524 EXPECT_EQ(0, fstat(shm_fd
, &shm_stat
));
525 // Neither the group, nor others should be able to read the shared memory
527 EXPECT_FALSE(shm_stat
.st_mode
& S_IRWXO
);
528 EXPECT_FALSE(shm_stat
.st_mode
& S_IRWXG
);
531 // Create a shared memory object, check its permissions.
532 TEST(SharedMemoryTest
, FilePermissionsNamed
) {
533 const uint32 kTestSize
= 1 << 8;
535 SharedMemory shared_memory
;
536 SharedMemoryCreateOptions options
;
537 options
.size
= kTestSize
;
538 std::string shared_mem_name
= "shared_perm_test-" + IntToString(getpid()) +
539 "-" + Uint64ToString(RandUint64());
540 options
.name_deprecated
= &shared_mem_name
;
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
));
545 // Clean-up the backing file name immediately, we don't need it.
546 EXPECT_TRUE(shared_memory
.Delete(shared_mem_name
));
548 int shm_fd
= shared_memory
.handle().fd
;
549 struct stat shm_stat
;
550 EXPECT_EQ(0, fstat(shm_fd
, &shm_stat
));
551 // Neither the group, nor others should have been able to open the shared
552 // memory file while its name existed.
553 EXPECT_FALSE(shm_stat
.st_mode
& S_IRWXO
);
554 EXPECT_FALSE(shm_stat
.st_mode
& S_IRWXG
);
556 #endif // !defined(OS_ANDROID)
558 #endif // defined(OS_POSIX)
560 // Map() will return addresses which are aligned to the platform page size, this
561 // varies from platform to platform though. Since we'd like to advertise a
562 // minimum alignment that callers can count on, test for it here.
563 TEST(SharedMemoryTest
, MapMinimumAlignment
) {
564 static const int kDataSize
= 8192;
566 SharedMemory shared_memory
;
567 ASSERT_TRUE(shared_memory
.CreateAndMapAnonymous(kDataSize
));
568 EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(
569 shared_memory
.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT
- 1));
570 shared_memory
.Close();
573 // iOS does not allow multiple processes.
574 // Android ashmem doesn't support named shared memory.
575 #if !defined(OS_IOS) && !defined(OS_ANDROID)
577 // On POSIX it is especially important we test shmem across processes,
578 // not just across threads. But the test is enabled on all platforms.
579 class SharedMemoryProcessTest
: public MultiProcessTest
{
582 static void CleanUp() {
584 memory
.Delete(s_test_name_
);
587 static int TaskTestMain() {
589 #if defined(OS_MACOSX)
590 mac::ScopedNSAutoreleasePool pool
;
593 bool rv
= memory
.CreateNamedDeprecated(s_test_name_
, true, s_data_size_
);
597 rv
= memory
.Map(s_data_size_
);
601 int *ptr
= static_cast<int*>(memory
.memory());
603 // This runs concurrently in multiple processes. Writes need to be atomic.
604 base::subtle::Barrier_AtomicIncrement(ptr
, 1);
609 static const char* const s_test_name_
;
610 static const uint32 s_data_size_
;
613 const char* const SharedMemoryProcessTest::s_test_name_
= "MPMem";
614 const uint32
SharedMemoryProcessTest::s_data_size_
= 1024;
616 TEST_F(SharedMemoryProcessTest
, SharedMemoryAcrossProcesses
) {
617 SharedMemoryProcessTest::CleanUp();
619 // Create a shared memory region. Set the first word to 0.
621 bool rv
= memory
.CreateNamedDeprecated(s_test_name_
, true, s_data_size_
);
623 rv
= memory
.Map(s_data_size_
);
625 int* ptr
= static_cast<int*>(memory
.memory());
628 // Start |kNumTasks| processes, each of which atomically increments the first
630 Process processes
[kNumTasks
];
631 for (int index
= 0; index
< kNumTasks
; ++index
) {
632 processes
[index
] = SpawnChild("SharedMemoryTestMain");
633 ASSERT_TRUE(processes
[index
].IsValid());
636 // Check that each process exited correctly.
638 for (int index
= 0; index
< kNumTasks
; ++index
) {
639 EXPECT_TRUE(processes
[index
].WaitForExit(&exit_code
));
640 EXPECT_EQ(0, exit_code
);
643 // Check that the shared memory region reflects |kNumTasks| increments.
644 ASSERT_EQ(kNumTasks
, *ptr
);
647 SharedMemoryProcessTest::CleanUp();
650 MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain
) {
651 return SharedMemoryProcessTest::TaskTestMain();
654 #endif // !defined(OS_IOS) && !defined(OS_ANDROID)