shared_memory_unittest.cc revision 58e6fbe4ee35d65e14b626c557d37565bf8ad179
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/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"
17
18#if defined(OS_MACOSX)
19#include "base/mac/scoped_nsautorelease_pool.h"
20#endif
21
22#if defined(OS_POSIX)
23#include <sys/mman.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <unistd.h>
27#endif
28
29static const int kNumThreads = 5;
30static const int kNumTasks = 5;
31
32namespace base {
33
34namespace {
35
36// Each thread will open the shared memory.  Each thread will take a different 4
37// byte int pointer, and keep changing it, with some small pauses in between.
38// Verify that each thread's value in the shared memory is always correct.
39class MultipleThreadMain : public PlatformThread::Delegate {
40 public:
41  explicit MultipleThreadMain(int16 id) : id_(id) {}
42  virtual ~MultipleThreadMain() {}
43
44  static void CleanUp() {
45    SharedMemory memory;
46    memory.Delete(s_test_name_);
47  }
48
49  // PlatformThread::Delegate interface.
50  virtual void ThreadMain() OVERRIDE {
51#if defined(OS_MACOSX)
52    mac::ScopedNSAutoreleasePool pool;
53#endif
54    const uint32 kDataSize = 1024;
55    SharedMemory memory;
56    bool rv = memory.CreateNamed(s_test_name_, true, kDataSize);
57    EXPECT_TRUE(rv);
58    rv = memory.Map(kDataSize);
59    EXPECT_TRUE(rv);
60    int *ptr = static_cast<int*>(memory.memory()) + id_;
61    EXPECT_EQ(0, *ptr);
62
63    for (int idx = 0; idx < 100; idx++) {
64      *ptr = idx;
65      PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
66      EXPECT_EQ(*ptr, idx);
67    }
68    // Reset back to 0 for the next test that uses the same name.
69    *ptr = 0;
70
71    memory.Close();
72  }
73
74 private:
75  int16 id_;
76
77  static const char* const s_test_name_;
78
79  DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain);
80};
81
82const char* const MultipleThreadMain::s_test_name_ =
83    "SharedMemoryOpenThreadTest";
84
85// TODO(port):
86// This test requires the ability to pass file descriptors between processes.
87// We haven't done that yet in Chrome for POSIX.
88#if defined(OS_WIN)
89// Each thread will open the shared memory.  Each thread will take the memory,
90// and keep changing it while trying to lock it, with some small pauses in
91// between. Verify that each thread's value in the shared memory is always
92// correct.
93class MultipleLockThread : public PlatformThread::Delegate {
94 public:
95  explicit MultipleLockThread(int id) : id_(id) {}
96  virtual ~MultipleLockThread() {}
97
98  // PlatformThread::Delegate interface.
99  virtual void ThreadMain() OVERRIDE {
100    const uint32 kDataSize = sizeof(int);
101    SharedMemoryHandle handle = NULL;
102    {
103      SharedMemory memory1;
104      EXPECT_TRUE(memory1.CreateNamed("SharedMemoryMultipleLockThreadTest",
105                                 true, kDataSize));
106      EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle));
107      // TODO(paulg): Implement this once we have a posix version of
108      // SharedMemory::ShareToProcess.
109      EXPECT_TRUE(true);
110    }
111
112    SharedMemory memory2(handle, false);
113    EXPECT_TRUE(memory2.Map(kDataSize));
114    volatile int* const ptr = static_cast<int*>(memory2.memory());
115
116    for (int idx = 0; idx < 20; idx++) {
117      memory2.Lock();
118      int i = (id_ << 16) + idx;
119      *ptr = i;
120      PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
121      EXPECT_EQ(*ptr, i);
122      memory2.Unlock();
123    }
124
125    memory2.Close();
126  }
127
128 private:
129  int id_;
130
131  DISALLOW_COPY_AND_ASSIGN(MultipleLockThread);
132};
133#endif
134
135}  // namespace
136
137// Android doesn't support SharedMemory::Open/Delete/
138// CreateNamed(openExisting=true)
139#if !defined(OS_ANDROID)
140TEST(SharedMemoryTest, OpenClose) {
141  const uint32 kDataSize = 1024;
142  std::string test_name = "SharedMemoryOpenCloseTest";
143
144  // Open two handles to a memory segment, confirm that they are mapped
145  // separately yet point to the same space.
146  SharedMemory memory1;
147  bool rv = memory1.Delete(test_name);
148  EXPECT_TRUE(rv);
149  rv = memory1.Delete(test_name);
150  EXPECT_TRUE(rv);
151  rv = memory1.Open(test_name, false);
152  EXPECT_FALSE(rv);
153  rv = memory1.CreateNamed(test_name, false, kDataSize);
154  EXPECT_TRUE(rv);
155  rv = memory1.Map(kDataSize);
156  EXPECT_TRUE(rv);
157  SharedMemory memory2;
158  rv = memory2.Open(test_name, false);
159  EXPECT_TRUE(rv);
160  rv = memory2.Map(kDataSize);
161  EXPECT_TRUE(rv);
162  EXPECT_NE(memory1.memory(), memory2.memory());  // Compare the pointers.
163
164  // Make sure we don't segfault. (it actually happened!)
165  ASSERT_NE(memory1.memory(), static_cast<void*>(NULL));
166  ASSERT_NE(memory2.memory(), static_cast<void*>(NULL));
167
168  // Write data to the first memory segment, verify contents of second.
169  memset(memory1.memory(), '1', kDataSize);
170  EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0);
171
172  // Close the first memory segment, and verify the second has the right data.
173  memory1.Close();
174  char *start_ptr = static_cast<char *>(memory2.memory());
175  char *end_ptr = start_ptr + kDataSize;
176  for (char* ptr = start_ptr; ptr < end_ptr; ptr++)
177    EXPECT_EQ(*ptr, '1');
178
179  // Close the second memory segment.
180  memory2.Close();
181
182  rv = memory1.Delete(test_name);
183  EXPECT_TRUE(rv);
184  rv = memory2.Delete(test_name);
185  EXPECT_TRUE(rv);
186}
187
188TEST(SharedMemoryTest, OpenExclusive) {
189  const uint32 kDataSize = 1024;
190  const uint32 kDataSize2 = 2048;
191  std::ostringstream test_name_stream;
192  test_name_stream << "SharedMemoryOpenExclusiveTest."
193                   << Time::Now().ToDoubleT();
194  std::string test_name = test_name_stream.str();
195
196  // Open two handles to a memory segment and check that open_existing works
197  // as expected.
198  SharedMemory memory1;
199  bool rv = memory1.CreateNamed(test_name, false, kDataSize);
200  EXPECT_TRUE(rv);
201
202  // Memory1 knows it's size because it created it.
203  EXPECT_EQ(memory1.requested_size(), kDataSize);
204
205  rv = memory1.Map(kDataSize);
206  EXPECT_TRUE(rv);
207
208  // The mapped memory1 must be at least the size we asked for.
209  EXPECT_GE(memory1.mapped_size(), kDataSize);
210
211  // The mapped memory1 shouldn't exceed rounding for allocation granularity.
212  EXPECT_LT(memory1.mapped_size(),
213            kDataSize + base::SysInfo::VMAllocationGranularity());
214
215  memset(memory1.memory(), 'G', kDataSize);
216
217  SharedMemory memory2;
218  // Should not be able to create if openExisting is false.
219  rv = memory2.CreateNamed(test_name, false, kDataSize2);
220  EXPECT_FALSE(rv);
221
222  // Should be able to create with openExisting true.
223  rv = memory2.CreateNamed(test_name, true, kDataSize2);
224  EXPECT_TRUE(rv);
225
226  // Memory2 shouldn't know the size because we didn't create it.
227  EXPECT_EQ(memory2.requested_size(), 0U);
228
229  // We should be able to map the original size.
230  rv = memory2.Map(kDataSize);
231  EXPECT_TRUE(rv);
232
233  // The mapped memory2 must be at least the size of the original.
234  EXPECT_GE(memory2.mapped_size(), kDataSize);
235
236  // The mapped memory2 shouldn't exceed rounding for allocation granularity.
237  EXPECT_LT(memory2.mapped_size(),
238            kDataSize2 + base::SysInfo::VMAllocationGranularity());
239
240  // Verify that opening memory2 didn't truncate or delete memory 1.
241  char *start_ptr = static_cast<char *>(memory2.memory());
242  char *end_ptr = start_ptr + kDataSize;
243  for (char* ptr = start_ptr; ptr < end_ptr; ptr++) {
244    EXPECT_EQ(*ptr, 'G');
245  }
246
247  memory1.Close();
248  memory2.Close();
249
250  rv = memory1.Delete(test_name);
251  EXPECT_TRUE(rv);
252}
253#endif
254
255// Create a set of N threads to each open a shared memory segment and write to
256// it. Verify that they are always reading/writing consistent data.
257TEST(SharedMemoryTest, MultipleThreads) {
258  MultipleThreadMain::CleanUp();
259  // On POSIX we have a problem when 2 threads try to create the shmem
260  // (a file) at exactly the same time, since create both creates the
261  // file and zerofills it.  We solve the problem for this unit test
262  // (make it not flaky) by starting with 1 thread, then
263  // intentionally don't clean up its shmem before running with
264  // kNumThreads.
265
266  int threadcounts[] = { 1, kNumThreads };
267  for (size_t i = 0; i < arraysize(threadcounts); i++) {
268    int numthreads = threadcounts[i];
269    scoped_ptr<PlatformThreadHandle[]> thread_handles;
270    scoped_ptr<MultipleThreadMain*[]> thread_delegates;
271
272    thread_handles.reset(new PlatformThreadHandle[numthreads]);
273    thread_delegates.reset(new MultipleThreadMain*[numthreads]);
274
275    // Spawn the threads.
276    for (int16 index = 0; index < numthreads; index++) {
277      PlatformThreadHandle pth;
278      thread_delegates[index] = new MultipleThreadMain(index);
279      EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
280      thread_handles[index] = pth;
281    }
282
283    // Wait for the threads to finish.
284    for (int index = 0; index < numthreads; index++) {
285      PlatformThread::Join(thread_handles[index]);
286      delete thread_delegates[index];
287    }
288  }
289  MultipleThreadMain::CleanUp();
290}
291
292// TODO(port): this test requires the MultipleLockThread class
293// (defined above), which requires the ability to pass file
294// descriptors between processes.  We haven't done that yet in Chrome
295// for POSIX.
296#if defined(OS_WIN)
297// Create a set of threads to each open a shared memory segment and write to it
298// with the lock held. Verify that they are always reading/writing consistent
299// data.
300TEST(SharedMemoryTest, Lock) {
301  PlatformThreadHandle thread_handles[kNumThreads];
302  MultipleLockThread* thread_delegates[kNumThreads];
303
304  // Spawn the threads.
305  for (int index = 0; index < kNumThreads; ++index) {
306    PlatformThreadHandle pth;
307    thread_delegates[index] = new MultipleLockThread(index);
308    EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
309    thread_handles[index] = pth;
310  }
311
312  // Wait for the threads to finish.
313  for (int index = 0; index < kNumThreads; ++index) {
314    PlatformThread::Join(thread_handles[index]);
315    delete thread_delegates[index];
316  }
317}
318#endif
319
320// Allocate private (unique) shared memory with an empty string for a
321// name.  Make sure several of them don't point to the same thing as
322// we might expect if the names are equal.
323TEST(SharedMemoryTest, AnonymousPrivate) {
324  int i, j;
325  int count = 4;
326  bool rv;
327  const uint32 kDataSize = 8192;
328
329  scoped_ptr<SharedMemory[]> memories(new SharedMemory[count]);
330  scoped_ptr<int*[]> pointers(new int*[count]);
331  ASSERT_TRUE(memories.get());
332  ASSERT_TRUE(pointers.get());
333
334  for (i = 0; i < count; i++) {
335    rv = memories[i].CreateAndMapAnonymous(kDataSize);
336    EXPECT_TRUE(rv);
337    int *ptr = static_cast<int*>(memories[i].memory());
338    EXPECT_TRUE(ptr);
339    pointers[i] = ptr;
340  }
341
342  for (i = 0; i < count; i++) {
343    // zero out the first int in each except for i; for that one, make it 100.
344    for (j = 0; j < count; j++) {
345      if (i == j)
346        pointers[j][0] = 100;
347      else
348        pointers[j][0] = 0;
349    }
350    // make sure there is no bleeding of the 100 into the other pointers
351    for (j = 0; j < count; j++) {
352      if (i == j)
353        EXPECT_EQ(100, pointers[j][0]);
354      else
355        EXPECT_EQ(0, pointers[j][0]);
356    }
357  }
358
359  for (int i = 0; i < count; i++) {
360    memories[i].Close();
361  }
362}
363
364TEST(SharedMemoryTest, MapAt) {
365  ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32));
366  const size_t kCount = SysInfo::VMAllocationGranularity();
367  const size_t kDataSize = kCount * sizeof(uint32);
368
369  SharedMemory memory;
370  ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize));
371  ASSERT_TRUE(memory.Map(kDataSize));
372  uint32* ptr = static_cast<uint32*>(memory.memory());
373  ASSERT_NE(ptr, static_cast<void*>(NULL));
374
375  for (size_t i = 0; i < kCount; ++i) {
376    ptr[i] = i;
377  }
378
379  memory.Unmap();
380
381  off_t offset = SysInfo::VMAllocationGranularity();
382  ASSERT_TRUE(memory.MapAt(offset, kDataSize - offset));
383  offset /= sizeof(uint32);
384  ptr = static_cast<uint32*>(memory.memory());
385  ASSERT_NE(ptr, static_cast<void*>(NULL));
386  for (size_t i = offset; i < kCount; ++i) {
387    EXPECT_EQ(ptr[i - offset], i);
388  }
389}
390
391#if defined(OS_POSIX)
392// Create a shared memory object, mmap it, and mprotect it to PROT_EXEC.
393TEST(SharedMemoryTest, AnonymousExecutable) {
394  const uint32 kTestSize = 1 << 16;
395
396  SharedMemory shared_memory;
397  SharedMemoryCreateOptions options;
398  options.size = kTestSize;
399  options.executable = true;
400
401  EXPECT_TRUE(shared_memory.Create(options));
402  EXPECT_TRUE(shared_memory.Map(shared_memory.requested_size()));
403
404  EXPECT_EQ(0, mprotect(shared_memory.memory(), shared_memory.requested_size(),
405                        PROT_READ | PROT_EXEC));
406}
407
408// Android supports a different permission model than POSIX for its "ashmem"
409// shared memory implementation. So the tests about file permissions are not
410// included on Android.
411#if !defined(OS_ANDROID)
412
413// Set a umask and restore the old mask on destruction.
414class ScopedUmaskSetter {
415 public:
416  explicit ScopedUmaskSetter(mode_t target_mask) {
417    old_umask_ = umask(target_mask);
418  }
419  ~ScopedUmaskSetter() { umask(old_umask_); }
420 private:
421  mode_t old_umask_;
422  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter);
423};
424
425// Create a shared memory object, check its permissions.
426TEST(SharedMemoryTest, FilePermissionsAnonymous) {
427  const uint32 kTestSize = 1 << 8;
428
429  SharedMemory shared_memory;
430  SharedMemoryCreateOptions options;
431  options.size = kTestSize;
432  // Set a file mode creation mask that gives all permissions.
433  ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH);
434
435  EXPECT_TRUE(shared_memory.Create(options));
436
437  int shm_fd = shared_memory.handle().fd;
438  struct stat shm_stat;
439  EXPECT_EQ(0, fstat(shm_fd, &shm_stat));
440  // Neither the group, nor others should be able to read the shared memory
441  // file.
442  EXPECT_FALSE(shm_stat.st_mode & S_IRWXO);
443  EXPECT_FALSE(shm_stat.st_mode & S_IRWXG);
444}
445
446// Create a shared memory object, check its permissions.
447TEST(SharedMemoryTest, FilePermissionsNamed) {
448  const uint32 kTestSize = 1 << 8;
449
450  SharedMemory shared_memory;
451  SharedMemoryCreateOptions options;
452  options.size = kTestSize;
453  std::string shared_mem_name = "shared_perm_test-" + IntToString(getpid()) +
454      "-" + Uint64ToString(RandUint64());
455  options.name = &shared_mem_name;
456  // Set a file mode creation mask that gives all permissions.
457  ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH);
458
459  EXPECT_TRUE(shared_memory.Create(options));
460  // Clean-up the backing file name immediately, we don't need it.
461  EXPECT_TRUE(shared_memory.Delete(shared_mem_name));
462
463  int shm_fd = shared_memory.handle().fd;
464  struct stat shm_stat;
465  EXPECT_EQ(0, fstat(shm_fd, &shm_stat));
466  // Neither the group, nor others should have been able to open the shared
467  // memory file while its name existed.
468  EXPECT_FALSE(shm_stat.st_mode & S_IRWXO);
469  EXPECT_FALSE(shm_stat.st_mode & S_IRWXG);
470}
471#endif  // !defined(OS_ANDROID)
472
473#endif  // defined(OS_POSIX)
474
475// Map() will return addresses which are aligned to the platform page size, this
476// varies from platform to platform though.  Since we'd like to advertise a
477// minimum alignment that callers can count on, test for it here.
478TEST(SharedMemoryTest, MapMinimumAlignment) {
479  static const int kDataSize = 8192;
480
481  SharedMemory shared_memory;
482  ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(kDataSize));
483  EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(
484      shared_memory.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
485  shared_memory.Close();
486}
487
488#if !defined(OS_IOS)  // iOS does not allow multiple processes.
489
490// On POSIX it is especially important we test shmem across processes,
491// not just across threads.  But the test is enabled on all platforms.
492class SharedMemoryProcessTest : public MultiProcessTest {
493 public:
494
495  static void CleanUp() {
496    SharedMemory memory;
497    memory.Delete(s_test_name_);
498  }
499
500  static int TaskTestMain() {
501    int errors = 0;
502#if defined(OS_MACOSX)
503    mac::ScopedNSAutoreleasePool pool;
504#endif
505    const uint32 kDataSize = 1024;
506    SharedMemory memory;
507    bool rv = memory.CreateNamed(s_test_name_, true, kDataSize);
508    EXPECT_TRUE(rv);
509    if (rv != true)
510      errors++;
511    rv = memory.Map(kDataSize);
512    EXPECT_TRUE(rv);
513    if (rv != true)
514      errors++;
515    int *ptr = static_cast<int*>(memory.memory());
516
517    for (int idx = 0; idx < 20; idx++) {
518      memory.Lock();
519      int i = (1 << 16) + idx;
520      *ptr = i;
521      PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
522      if (*ptr != i)
523        errors++;
524      memory.Unlock();
525    }
526
527    memory.Close();
528    return errors;
529  }
530
531 private:
532  static const char* const s_test_name_;
533};
534
535const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem";
536
537TEST_F(SharedMemoryProcessTest, Tasks) {
538  SharedMemoryProcessTest::CleanUp();
539
540  ProcessHandle handles[kNumTasks];
541  for (int index = 0; index < kNumTasks; ++index) {
542    handles[index] = SpawnChild("SharedMemoryTestMain", false);
543    ASSERT_TRUE(handles[index]);
544  }
545
546  int exit_code = 0;
547  for (int index = 0; index < kNumTasks; ++index) {
548    EXPECT_TRUE(WaitForExitCode(handles[index], &exit_code));
549    EXPECT_EQ(0, exit_code);
550  }
551
552  SharedMemoryProcessTest::CleanUp();
553}
554
555MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) {
556  return SharedMemoryProcessTest::TaskTestMain();
557}
558
559#endif  // !OS_IOS
560
561}  // namespace base
562