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. 4 5 #include "base/memory/shared_memory.h" 6 7 #include <stddef.h> 8 #include <stdint.h> 9 10 #include <memory> 11 12 #include "base/atomicops.h" 13 #include "base/macros.h" 14 #include "base/memory/shared_memory_handle.h" 15 #include "base/process/kill.h" 16 #include "base/rand_util.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "base/sys_info.h" 19 #include "base/test/multiprocess_test.h" 20 #include "base/threading/platform_thread.h" 21 #include "base/time/time.h" 22 #include "build/build_config.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 #include "testing/multiprocess_func_list.h" 25 26 #if defined(OS_POSIX) 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <sys/mman.h> 30 #include <sys/stat.h> 31 #include <sys/types.h> 32 #include <unistd.h> 33 #endif 34 35 #if defined(OS_WIN) 36 #include "base/win/scoped_handle.h" 37 #endif 38 39 namespace base { 40 41 namespace { 42 43 #if !defined(OS_MACOSX) 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 { 48 public: 49 explicit MultipleThreadMain(int16_t id) : id_(id) {} 50 ~MultipleThreadMain() override {} 51 52 static void CleanUp() { 53 SharedMemory memory; 54 memory.Delete(s_test_name_); 55 } 56 57 // PlatformThread::Delegate interface. 58 void ThreadMain() override { 59 const uint32_t kDataSize = 1024; 60 SharedMemory memory; 61 bool rv = memory.CreateNamedDeprecated(s_test_name_, true, kDataSize); 62 EXPECT_TRUE(rv); 63 rv = memory.Map(kDataSize); 64 EXPECT_TRUE(rv); 65 int* ptr = static_cast<int*>(memory.memory()) + id_; 66 EXPECT_EQ(0, *ptr); 67 68 for (int idx = 0; idx < 100; idx++) { 69 *ptr = idx; 70 PlatformThread::Sleep(TimeDelta::FromMilliseconds(1)); 71 EXPECT_EQ(*ptr, idx); 72 } 73 // Reset back to 0 for the next test that uses the same name. 74 *ptr = 0; 75 76 memory.Close(); 77 } 78 79 private: 80 int16_t id_; 81 82 static const char s_test_name_[]; 83 84 DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain); 85 }; 86 87 const char MultipleThreadMain::s_test_name_[] = 88 "SharedMemoryOpenThreadTest"; 89 #endif // !defined(OS_MACOSX) 90 91 } // namespace 92 93 // Android/Mac doesn't support SharedMemory::Open/Delete/ 94 // CreateNamedDeprecated(openExisting=true) 95 #if !defined(OS_ANDROID) && !defined(OS_MACOSX) 96 TEST(SharedMemoryTest, OpenClose) { 97 const uint32_t kDataSize = 1024; 98 std::string test_name = "SharedMemoryOpenCloseTest"; 99 100 // Open two handles to a memory segment, confirm that they are mapped 101 // separately yet point to the same space. 102 SharedMemory memory1; 103 bool rv = memory1.Delete(test_name); 104 EXPECT_TRUE(rv); 105 rv = memory1.Delete(test_name); 106 EXPECT_TRUE(rv); 107 rv = memory1.Open(test_name, false); 108 EXPECT_FALSE(rv); 109 rv = memory1.CreateNamedDeprecated(test_name, false, kDataSize); 110 EXPECT_TRUE(rv); 111 rv = memory1.Map(kDataSize); 112 EXPECT_TRUE(rv); 113 SharedMemory memory2; 114 rv = memory2.Open(test_name, false); 115 EXPECT_TRUE(rv); 116 rv = memory2.Map(kDataSize); 117 EXPECT_TRUE(rv); 118 EXPECT_NE(memory1.memory(), memory2.memory()); // Compare the pointers. 119 120 // Make sure we don't segfault. (it actually happened!) 121 ASSERT_NE(memory1.memory(), static_cast<void*>(NULL)); 122 ASSERT_NE(memory2.memory(), static_cast<void*>(NULL)); 123 124 // Write data to the first memory segment, verify contents of second. 125 memset(memory1.memory(), '1', kDataSize); 126 EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0); 127 128 // Close the first memory segment, and verify the second has the right data. 129 memory1.Close(); 130 char* start_ptr = static_cast<char*>(memory2.memory()); 131 char* end_ptr = start_ptr + kDataSize; 132 for (char* ptr = start_ptr; ptr < end_ptr; ptr++) 133 EXPECT_EQ(*ptr, '1'); 134 135 // Close the second memory segment. 136 memory2.Close(); 137 138 rv = memory1.Delete(test_name); 139 EXPECT_TRUE(rv); 140 rv = memory2.Delete(test_name); 141 EXPECT_TRUE(rv); 142 } 143 144 TEST(SharedMemoryTest, OpenExclusive) { 145 const uint32_t kDataSize = 1024; 146 const uint32_t kDataSize2 = 2048; 147 std::ostringstream test_name_stream; 148 test_name_stream << "SharedMemoryOpenExclusiveTest." 149 << Time::Now().ToDoubleT(); 150 std::string test_name = test_name_stream.str(); 151 152 // Open two handles to a memory segment and check that 153 // open_existing_deprecated works as expected. 154 SharedMemory memory1; 155 bool rv = memory1.CreateNamedDeprecated(test_name, false, kDataSize); 156 EXPECT_TRUE(rv); 157 158 // Memory1 knows it's size because it created it. 159 EXPECT_EQ(memory1.requested_size(), kDataSize); 160 161 rv = memory1.Map(kDataSize); 162 EXPECT_TRUE(rv); 163 164 // The mapped memory1 must be at least the size we asked for. 165 EXPECT_GE(memory1.mapped_size(), kDataSize); 166 167 // The mapped memory1 shouldn't exceed rounding for allocation granularity. 168 EXPECT_LT(memory1.mapped_size(), 169 kDataSize + SysInfo::VMAllocationGranularity()); 170 171 memset(memory1.memory(), 'G', kDataSize); 172 173 SharedMemory memory2; 174 // Should not be able to create if openExisting is false. 175 rv = memory2.CreateNamedDeprecated(test_name, false, kDataSize2); 176 EXPECT_FALSE(rv); 177 178 // Should be able to create with openExisting true. 179 rv = memory2.CreateNamedDeprecated(test_name, true, kDataSize2); 180 EXPECT_TRUE(rv); 181 182 // Memory2 shouldn't know the size because we didn't create it. 183 EXPECT_EQ(memory2.requested_size(), 0U); 184 185 // We should be able to map the original size. 186 rv = memory2.Map(kDataSize); 187 EXPECT_TRUE(rv); 188 189 // The mapped memory2 must be at least the size of the original. 190 EXPECT_GE(memory2.mapped_size(), kDataSize); 191 192 // The mapped memory2 shouldn't exceed rounding for allocation granularity. 193 EXPECT_LT(memory2.mapped_size(), 194 kDataSize2 + SysInfo::VMAllocationGranularity()); 195 196 // Verify that opening memory2 didn't truncate or delete memory 1. 197 char* start_ptr = static_cast<char*>(memory2.memory()); 198 char* end_ptr = start_ptr + kDataSize; 199 for (char* ptr = start_ptr; ptr < end_ptr; ptr++) { 200 EXPECT_EQ(*ptr, 'G'); 201 } 202 203 memory1.Close(); 204 memory2.Close(); 205 206 rv = memory1.Delete(test_name); 207 EXPECT_TRUE(rv); 208 } 209 #endif // !defined(OS_ANDROID) && !defined(OS_MACOSX) 210 211 // Check that memory is still mapped after its closed. 212 TEST(SharedMemoryTest, CloseNoUnmap) { 213 const size_t kDataSize = 4096; 214 215 SharedMemory memory; 216 ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize)); 217 char* ptr = static_cast<char*>(memory.memory()); 218 ASSERT_NE(ptr, static_cast<void*>(NULL)); 219 memset(ptr, 'G', kDataSize); 220 221 memory.Close(); 222 223 EXPECT_EQ(ptr, memory.memory()); 224 EXPECT_EQ(SharedMemory::NULLHandle(), memory.handle()); 225 226 for (size_t i = 0; i < kDataSize; i++) { 227 EXPECT_EQ('G', ptr[i]); 228 } 229 230 memory.Unmap(); 231 EXPECT_EQ(nullptr, memory.memory()); 232 } 233 234 #if !defined(OS_MACOSX) 235 // Create a set of N threads to each open a shared memory segment and write to 236 // it. Verify that they are always reading/writing consistent data. 237 TEST(SharedMemoryTest, MultipleThreads) { 238 const int kNumThreads = 5; 239 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 246 // kNumThreads. 247 248 int threadcounts[] = { 1, kNumThreads }; 249 for (size_t i = 0; i < arraysize(threadcounts); i++) { 250 int numthreads = threadcounts[i]; 251 std::unique_ptr<PlatformThreadHandle[]> thread_handles; 252 std::unique_ptr<MultipleThreadMain* []> thread_delegates; 253 254 thread_handles.reset(new PlatformThreadHandle[numthreads]); 255 thread_delegates.reset(new MultipleThreadMain*[numthreads]); 256 257 // Spawn the threads. 258 for (int16_t 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; 263 } 264 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]; 269 } 270 } 271 MultipleThreadMain::CleanUp(); 272 } 273 #endif 274 275 // Allocate private (unique) shared memory with an empty string for a 276 // name. Make sure several of them don't point to the same thing as 277 // we might expect if the names are equal. 278 TEST(SharedMemoryTest, AnonymousPrivate) { 279 int i, j; 280 int count = 4; 281 bool rv; 282 const uint32_t kDataSize = 8192; 283 284 std::unique_ptr<SharedMemory[]> memories(new SharedMemory[count]); 285 std::unique_ptr<int* []> pointers(new int*[count]); 286 ASSERT_TRUE(memories.get()); 287 ASSERT_TRUE(pointers.get()); 288 289 for (i = 0; i < count; i++) { 290 rv = memories[i].CreateAndMapAnonymous(kDataSize); 291 EXPECT_TRUE(rv); 292 int* ptr = static_cast<int*>(memories[i].memory()); 293 EXPECT_TRUE(ptr); 294 pointers[i] = ptr; 295 } 296 297 for (i = 0; i < count; i++) { 298 // zero out the first int in each except for i; for that one, make it 100. 299 for (j = 0; j < count; j++) { 300 if (i == j) 301 pointers[j][0] = 100; 302 else 303 pointers[j][0] = 0; 304 } 305 // make sure there is no bleeding of the 100 into the other pointers 306 for (j = 0; j < count; j++) { 307 if (i == j) 308 EXPECT_EQ(100, pointers[j][0]); 309 else 310 EXPECT_EQ(0, pointers[j][0]); 311 } 312 } 313 314 for (int i = 0; i < count; i++) { 315 memories[i].Close(); 316 } 317 } 318 319 // The Mach functionality is tested in shared_memory_mac_unittest.cc. 320 #if !(defined(OS_MACOSX) && !defined(OS_IOS)) 321 TEST(SharedMemoryTest, ShareReadOnly) { 322 StringPiece contents = "Hello World"; 323 324 SharedMemory writable_shmem; 325 SharedMemoryCreateOptions options; 326 options.size = contents.size(); 327 options.share_read_only = true; 328 ASSERT_TRUE(writable_shmem.Create(options)); 329 ASSERT_TRUE(writable_shmem.Map(options.size)); 330 memcpy(writable_shmem.memory(), contents.data(), contents.size()); 331 EXPECT_TRUE(writable_shmem.Unmap()); 332 333 SharedMemoryHandle readonly_handle; 334 ASSERT_TRUE(writable_shmem.ShareReadOnlyToProcess(GetCurrentProcessHandle(), 335 &readonly_handle)); 336 SharedMemory readonly_shmem(readonly_handle, /*readonly=*/true); 337 338 ASSERT_TRUE(readonly_shmem.Map(contents.size())); 339 EXPECT_EQ(contents, 340 StringPiece(static_cast<const char*>(readonly_shmem.memory()), 341 contents.size())); 342 EXPECT_TRUE(readonly_shmem.Unmap()); 343 344 // Make sure the writable instance is still writable. 345 ASSERT_TRUE(writable_shmem.Map(contents.size())); 346 StringPiece new_contents = "Goodbye"; 347 memcpy(writable_shmem.memory(), new_contents.data(), new_contents.size()); 348 EXPECT_EQ(new_contents, 349 StringPiece(static_cast<const char*>(writable_shmem.memory()), 350 new_contents.size())); 351 352 // We'd like to check that if we send the read-only segment to another 353 // process, then that other process can't reopen it read/write. (Since that 354 // would be a security hole.) Setting up multiple processes is hard in a 355 // unittest, so this test checks that the *current* process can't reopen the 356 // segment read/write. I think the test here is stronger than we actually 357 // care about, but there's a remote possibility that sending a file over a 358 // pipe would transform it into read/write. 359 SharedMemoryHandle handle = readonly_shmem.handle(); 360 361 #if defined(OS_ANDROID) 362 // The "read-only" handle is still writable on Android: 363 // http://crbug.com/320865 364 (void)handle; 365 #elif defined(OS_POSIX) 366 int handle_fd = SharedMemory::GetFdFromSharedMemoryHandle(handle); 367 EXPECT_EQ(O_RDONLY, fcntl(handle_fd, F_GETFL) & O_ACCMODE) 368 << "The descriptor itself should be read-only."; 369 370 errno = 0; 371 void* writable = mmap(NULL, contents.size(), PROT_READ | PROT_WRITE, 372 MAP_SHARED, handle_fd, 0); 373 int mmap_errno = errno; 374 EXPECT_EQ(MAP_FAILED, writable) 375 << "It shouldn't be possible to re-mmap the descriptor writable."; 376 EXPECT_EQ(EACCES, mmap_errno) << strerror(mmap_errno); 377 if (writable != MAP_FAILED) 378 EXPECT_EQ(0, munmap(writable, readonly_shmem.mapped_size())); 379 380 #elif defined(OS_WIN) 381 EXPECT_EQ(NULL, MapViewOfFile(handle.GetHandle(), FILE_MAP_WRITE, 0, 0, 0)) 382 << "Shouldn't be able to map memory writable."; 383 384 HANDLE temp_handle; 385 BOOL rv = ::DuplicateHandle(GetCurrentProcess(), handle.GetHandle(), 386 GetCurrentProcess(), &temp_handle, 387 FILE_MAP_ALL_ACCESS, false, 0); 388 EXPECT_EQ(FALSE, rv) 389 << "Shouldn't be able to duplicate the handle into a writable one."; 390 if (rv) 391 win::ScopedHandle writable_handle(temp_handle); 392 rv = ::DuplicateHandle(GetCurrentProcess(), handle.GetHandle(), 393 GetCurrentProcess(), &temp_handle, FILE_MAP_READ, 394 false, 0); 395 EXPECT_EQ(TRUE, rv) 396 << "Should be able to duplicate the handle into a readable one."; 397 if (rv) 398 win::ScopedHandle writable_handle(temp_handle); 399 #else 400 #error Unexpected platform; write a test that tries to make 'handle' writable. 401 #endif // defined(OS_POSIX) || defined(OS_WIN) 402 } 403 #endif // !(defined(OS_MACOSX) && !defined(OS_IOS)) 404 405 TEST(SharedMemoryTest, ShareToSelf) { 406 StringPiece contents = "Hello World"; 407 408 SharedMemory shmem; 409 ASSERT_TRUE(shmem.CreateAndMapAnonymous(contents.size())); 410 memcpy(shmem.memory(), contents.data(), contents.size()); 411 EXPECT_TRUE(shmem.Unmap()); 412 413 SharedMemoryHandle shared_handle; 414 ASSERT_TRUE(shmem.ShareToProcess(GetCurrentProcessHandle(), &shared_handle)); 415 #if defined(OS_WIN) 416 ASSERT_TRUE(shared_handle.OwnershipPassesToIPC()); 417 #endif 418 SharedMemory shared(shared_handle, /*readonly=*/false); 419 420 ASSERT_TRUE(shared.Map(contents.size())); 421 EXPECT_EQ( 422 contents, 423 StringPiece(static_cast<const char*>(shared.memory()), contents.size())); 424 425 shared_handle = SharedMemoryHandle(); 426 ASSERT_TRUE(shmem.ShareToProcess(GetCurrentProcessHandle(), &shared_handle)); 427 #if defined(OS_WIN) 428 ASSERT_TRUE(shared_handle.OwnershipPassesToIPC()); 429 #endif 430 SharedMemory readonly(shared_handle, /*readonly=*/true); 431 432 ASSERT_TRUE(readonly.Map(contents.size())); 433 EXPECT_EQ(contents, 434 StringPiece(static_cast<const char*>(readonly.memory()), 435 contents.size())); 436 } 437 438 TEST(SharedMemoryTest, MapAt) { 439 ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32_t)); 440 const size_t kCount = SysInfo::VMAllocationGranularity(); 441 const size_t kDataSize = kCount * sizeof(uint32_t); 442 443 SharedMemory memory; 444 ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize)); 445 uint32_t* ptr = static_cast<uint32_t*>(memory.memory()); 446 ASSERT_NE(ptr, static_cast<void*>(NULL)); 447 448 for (size_t i = 0; i < kCount; ++i) { 449 ptr[i] = i; 450 } 451 452 memory.Unmap(); 453 454 off_t offset = SysInfo::VMAllocationGranularity(); 455 ASSERT_TRUE(memory.MapAt(offset, kDataSize - offset)); 456 offset /= sizeof(uint32_t); 457 ptr = static_cast<uint32_t*>(memory.memory()); 458 ASSERT_NE(ptr, static_cast<void*>(NULL)); 459 for (size_t i = offset; i < kCount; ++i) { 460 EXPECT_EQ(ptr[i - offset], i); 461 } 462 } 463 464 TEST(SharedMemoryTest, MapTwice) { 465 const uint32_t kDataSize = 1024; 466 SharedMemory memory; 467 bool rv = memory.CreateAndMapAnonymous(kDataSize); 468 EXPECT_TRUE(rv); 469 470 void* old_address = memory.memory(); 471 472 rv = memory.Map(kDataSize); 473 EXPECT_FALSE(rv); 474 EXPECT_EQ(old_address, memory.memory()); 475 } 476 477 #if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS)) 478 // This test is not applicable for iOS (crbug.com/399384). 479 #if !defined(OS_IOS) 480 // Create a shared memory object, mmap it, and mprotect it to PROT_EXEC. 481 TEST(SharedMemoryTest, AnonymousExecutable) { 482 const uint32_t kTestSize = 1 << 16; 483 484 SharedMemory shared_memory; 485 SharedMemoryCreateOptions options; 486 options.size = kTestSize; 487 options.executable = true; 488 489 EXPECT_TRUE(shared_memory.Create(options)); 490 EXPECT_TRUE(shared_memory.Map(shared_memory.requested_size())); 491 492 EXPECT_EQ(0, mprotect(shared_memory.memory(), shared_memory.requested_size(), 493 PROT_READ | PROT_EXEC)); 494 } 495 #endif // !defined(OS_IOS) 496 497 // Android supports a different permission model than POSIX for its "ashmem" 498 // shared memory implementation. So the tests about file permissions are not 499 // included on Android. 500 #if !defined(OS_ANDROID) 501 502 // Set a umask and restore the old mask on destruction. 503 class ScopedUmaskSetter { 504 public: 505 explicit ScopedUmaskSetter(mode_t target_mask) { 506 old_umask_ = umask(target_mask); 507 } 508 ~ScopedUmaskSetter() { umask(old_umask_); } 509 private: 510 mode_t old_umask_; 511 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter); 512 }; 513 514 // Create a shared memory object, check its permissions. 515 TEST(SharedMemoryTest, FilePermissionsAnonymous) { 516 const uint32_t kTestSize = 1 << 8; 517 518 SharedMemory shared_memory; 519 SharedMemoryCreateOptions options; 520 options.size = kTestSize; 521 // Set a file mode creation mask that gives all permissions. 522 ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH); 523 524 EXPECT_TRUE(shared_memory.Create(options)); 525 526 int shm_fd = 527 SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle()); 528 struct stat shm_stat; 529 EXPECT_EQ(0, fstat(shm_fd, &shm_stat)); 530 // Neither the group, nor others should be able to read the shared memory 531 // file. 532 EXPECT_FALSE(shm_stat.st_mode & S_IRWXO); 533 EXPECT_FALSE(shm_stat.st_mode & S_IRWXG); 534 } 535 536 // Create a shared memory object, check its permissions. 537 TEST(SharedMemoryTest, FilePermissionsNamed) { 538 const uint32_t kTestSize = 1 << 8; 539 540 SharedMemory shared_memory; 541 SharedMemoryCreateOptions options; 542 options.size = kTestSize; 543 544 // Set a file mode creation mask that gives all permissions. 545 ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH); 546 547 EXPECT_TRUE(shared_memory.Create(options)); 548 549 int fd = SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle()); 550 struct stat shm_stat; 551 EXPECT_EQ(0, fstat(fd, &shm_stat)); 552 // Neither the group, nor others should have been able to open the shared 553 // memory file while its name existed. 554 EXPECT_FALSE(shm_stat.st_mode & S_IRWXO); 555 EXPECT_FALSE(shm_stat.st_mode & S_IRWXG); 556 } 557 #endif // !defined(OS_ANDROID) 558 559 #endif // defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS)) 560 561 // Map() will return addresses which are aligned to the platform page size, this 562 // varies from platform to platform though. Since we'd like to advertise a 563 // minimum alignment that callers can count on, test for it here. 564 TEST(SharedMemoryTest, MapMinimumAlignment) { 565 static const int kDataSize = 8192; 566 567 SharedMemory shared_memory; 568 ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(kDataSize)); 569 EXPECT_EQ(0U, reinterpret_cast<uintptr_t>( 570 shared_memory.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); 571 shared_memory.Close(); 572 } 573 574 #if defined(OS_WIN) 575 TEST(SharedMemoryTest, UnsafeImageSection) { 576 const char kTestSectionName[] = "UnsafeImageSection"; 577 wchar_t path[MAX_PATH]; 578 EXPECT_GT(::GetModuleFileName(nullptr, path, arraysize(path)), 0U); 579 580 // Map the current executable image to save us creating a new PE file on disk. 581 base::win::ScopedHandle file_handle(::CreateFile( 582 path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr)); 583 EXPECT_TRUE(file_handle.IsValid()); 584 base::win::ScopedHandle section_handle( 585 ::CreateFileMappingA(file_handle.Get(), nullptr, 586 PAGE_READONLY | SEC_IMAGE, 0, 0, kTestSectionName)); 587 EXPECT_TRUE(section_handle.IsValid()); 588 589 // Check direct opening by name, from handle and duplicated from handle. 590 SharedMemory shared_memory_open; 591 EXPECT_TRUE(shared_memory_open.Open(kTestSectionName, true)); 592 EXPECT_FALSE(shared_memory_open.Map(1)); 593 EXPECT_EQ(nullptr, shared_memory_open.memory()); 594 595 SharedMemory shared_memory_handle_local( 596 SharedMemoryHandle(section_handle.Take(), ::GetCurrentProcessId()), true); 597 EXPECT_FALSE(shared_memory_handle_local.Map(1)); 598 EXPECT_EQ(nullptr, shared_memory_handle_local.memory()); 599 600 // Check that a handle without SECTION_QUERY also can't be mapped as it can't 601 // be checked. 602 SharedMemory shared_memory_handle_dummy; 603 SharedMemoryCreateOptions options; 604 options.size = 0x1000; 605 EXPECT_TRUE(shared_memory_handle_dummy.Create(options)); 606 HANDLE handle_no_query; 607 EXPECT_TRUE(::DuplicateHandle( 608 ::GetCurrentProcess(), shared_memory_handle_dummy.handle().GetHandle(), 609 ::GetCurrentProcess(), &handle_no_query, FILE_MAP_READ, FALSE, 0)); 610 SharedMemory shared_memory_handle_no_query( 611 SharedMemoryHandle(handle_no_query, ::GetCurrentProcessId()), true); 612 EXPECT_FALSE(shared_memory_handle_no_query.Map(1)); 613 EXPECT_EQ(nullptr, shared_memory_handle_no_query.memory()); 614 } 615 #endif // defined(OS_WIN) 616 617 // iOS does not allow multiple processes. 618 // Android ashmem does not support named shared memory. 619 // Mac SharedMemory does not support named shared memory. crbug.com/345734 620 #if !defined(OS_IOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX) 621 // On POSIX it is especially important we test shmem across processes, 622 // not just across threads. But the test is enabled on all platforms. 623 class SharedMemoryProcessTest : public MultiProcessTest { 624 public: 625 static void CleanUp() { 626 SharedMemory memory; 627 memory.Delete(s_test_name_); 628 } 629 630 static int TaskTestMain() { 631 int errors = 0; 632 SharedMemory memory; 633 bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_); 634 EXPECT_TRUE(rv); 635 if (rv != true) 636 errors++; 637 rv = memory.Map(s_data_size_); 638 EXPECT_TRUE(rv); 639 if (rv != true) 640 errors++; 641 int* ptr = static_cast<int*>(memory.memory()); 642 643 // This runs concurrently in multiple processes. Writes need to be atomic. 644 subtle::Barrier_AtomicIncrement(ptr, 1); 645 memory.Close(); 646 return errors; 647 } 648 649 static const char s_test_name_[]; 650 static const uint32_t s_data_size_; 651 }; 652 653 const char SharedMemoryProcessTest::s_test_name_[] = "MPMem"; 654 const uint32_t SharedMemoryProcessTest::s_data_size_ = 1024; 655 656 TEST_F(SharedMemoryProcessTest, SharedMemoryAcrossProcesses) { 657 const int kNumTasks = 5; 658 659 SharedMemoryProcessTest::CleanUp(); 660 661 // Create a shared memory region. Set the first word to 0. 662 SharedMemory memory; 663 bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_); 664 ASSERT_TRUE(rv); 665 rv = memory.Map(s_data_size_); 666 ASSERT_TRUE(rv); 667 int* ptr = static_cast<int*>(memory.memory()); 668 *ptr = 0; 669 670 // Start |kNumTasks| processes, each of which atomically increments the first 671 // word by 1. 672 Process processes[kNumTasks]; 673 for (int index = 0; index < kNumTasks; ++index) { 674 processes[index] = SpawnChild("SharedMemoryTestMain"); 675 ASSERT_TRUE(processes[index].IsValid()); 676 } 677 678 // Check that each process exited correctly. 679 int exit_code = 0; 680 for (int index = 0; index < kNumTasks; ++index) { 681 EXPECT_TRUE(processes[index].WaitForExit(&exit_code)); 682 EXPECT_EQ(0, exit_code); 683 } 684 685 // Check that the shared memory region reflects |kNumTasks| increments. 686 ASSERT_EQ(kNumTasks, *ptr); 687 688 memory.Close(); 689 SharedMemoryProcessTest::CleanUp(); 690 } 691 692 MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) { 693 return SharedMemoryProcessTest::TaskTestMain(); 694 } 695 #endif // !defined(OS_IOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX) 696 697 } // namespace base 698