• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors
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_mapping.h"
6 
7 #include <stdint.h>
8 
9 #include <atomic>
10 #include <limits>
11 
12 #include "base/containers/span.h"
13 #include "base/memory/read_only_shared_memory_region.h"
14 #include "base/memory/writable_shared_memory_region.h"
15 #include "base/ranges/algorithm.h"
16 #include "build/build_config.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 
20 namespace base {
21 
22 class SharedMemoryMappingTest : public ::testing::Test {
23  protected:
CreateMapping(size_t size)24   void CreateMapping(size_t size) {
25     auto result = ReadOnlySharedMemoryRegion::Create(size);
26     ASSERT_TRUE(result.IsValid());
27     write_mapping_ = std::move(result.mapping);
28     read_mapping_ = result.region.Map();
29     ASSERT_TRUE(read_mapping_.IsValid());
30   }
31 
32   WritableSharedMemoryMapping write_mapping_;
33   ReadOnlySharedMemoryMapping read_mapping_;
34 };
35 
TEST_F(SharedMemoryMappingTest,Invalid)36 TEST_F(SharedMemoryMappingTest, Invalid) {
37   EXPECT_EQ(nullptr, write_mapping_.GetMemoryAs<uint8_t>());
38   EXPECT_EQ(nullptr, read_mapping_.GetMemoryAs<uint8_t>());
39   EXPECT_TRUE(write_mapping_.GetMemoryAsSpan<uint8_t>().empty());
40   EXPECT_TRUE(read_mapping_.GetMemoryAsSpan<uint8_t>().empty());
41   EXPECT_TRUE(write_mapping_.GetMemoryAsSpan<uint8_t>(1).empty());
42   EXPECT_TRUE(read_mapping_.GetMemoryAsSpan<uint8_t>(1).empty());
43 }
44 
TEST_F(SharedMemoryMappingTest,Scalar)45 TEST_F(SharedMemoryMappingTest, Scalar) {
46   CreateMapping(sizeof(uint32_t));
47 
48   uint32_t* write_ptr = write_mapping_.GetMemoryAs<uint32_t>();
49   ASSERT_NE(nullptr, write_ptr);
50 
51   const uint32_t* read_ptr = read_mapping_.GetMemoryAs<uint32_t>();
52   ASSERT_NE(nullptr, read_ptr);
53 
54   *write_ptr = 0u;
55   EXPECT_EQ(0u, *read_ptr);
56 
57   *write_ptr = 0x12345678u;
58   EXPECT_EQ(0x12345678u, *read_ptr);
59 }
60 
TEST_F(SharedMemoryMappingTest,SpanWithAutoDeducedElementCount)61 TEST_F(SharedMemoryMappingTest, SpanWithAutoDeducedElementCount) {
62   CreateMapping(sizeof(uint8_t) * 8);
63 
64   span<uint8_t> write_span = write_mapping_.GetMemoryAsSpan<uint8_t>();
65   ASSERT_EQ(8u, write_span.size());
66 
67   span<const uint32_t> read_span = read_mapping_.GetMemoryAsSpan<uint32_t>();
68   ASSERT_EQ(2u, read_span.size());
69 
70   ranges::fill(write_span, 0);
71   EXPECT_EQ(0u, read_span[0]);
72   EXPECT_EQ(0u, read_span[1]);
73 
74   for (size_t i = 0; i < write_span.size(); ++i)
75     write_span[i] = i + 1;
76   EXPECT_EQ(0x04030201u, read_span[0]);
77   EXPECT_EQ(0x08070605u, read_span[1]);
78 }
79 
TEST_F(SharedMemoryMappingTest,SpanWithExplicitElementCount)80 TEST_F(SharedMemoryMappingTest, SpanWithExplicitElementCount) {
81   CreateMapping(sizeof(uint8_t) * 8);
82 
83   span<uint8_t> write_span = write_mapping_.GetMemoryAsSpan<uint8_t>(8);
84   ASSERT_EQ(8u, write_span.size());
85 
86   span<uint8_t> write_span_2 = write_mapping_.GetMemoryAsSpan<uint8_t>(4);
87   ASSERT_EQ(4u, write_span_2.size());
88 
89   span<const uint32_t> read_span = read_mapping_.GetMemoryAsSpan<uint32_t>(2);
90   ASSERT_EQ(2u, read_span.size());
91 
92   span<const uint32_t> read_span_2 = read_mapping_.GetMemoryAsSpan<uint32_t>(1);
93   ASSERT_EQ(1u, read_span_2.size());
94 
95   ranges::fill(write_span, 0);
96   EXPECT_EQ(0u, read_span[0]);
97   EXPECT_EQ(0u, read_span[1]);
98   EXPECT_EQ(0u, read_span_2[0]);
99 
100   for (size_t i = 0; i < write_span.size(); ++i)
101     write_span[i] = i + 1;
102   EXPECT_EQ(0x04030201u, read_span[0]);
103   EXPECT_EQ(0x08070605u, read_span[1]);
104   EXPECT_EQ(0x04030201u, read_span_2[0]);
105 
106   ranges::fill(write_span_2, 0);
107   EXPECT_EQ(0u, read_span[0]);
108   EXPECT_EQ(0x08070605u, read_span[1]);
109   EXPECT_EQ(0u, read_span_2[0]);
110 }
111 
TEST_F(SharedMemoryMappingTest,SpanWithZeroElementCount)112 TEST_F(SharedMemoryMappingTest, SpanWithZeroElementCount) {
113   CreateMapping(sizeof(uint8_t) * 8);
114 
115   EXPECT_TRUE(write_mapping_.GetMemoryAsSpan<uint8_t>(0).empty());
116 
117   EXPECT_TRUE(read_mapping_.GetMemoryAsSpan<uint8_t>(0).empty());
118 }
119 
TEST_F(SharedMemoryMappingTest,TooBigScalar)120 TEST_F(SharedMemoryMappingTest, TooBigScalar) {
121   CreateMapping(sizeof(uint8_t));
122 
123   EXPECT_EQ(nullptr, write_mapping_.GetMemoryAs<uint32_t>());
124 
125   EXPECT_EQ(nullptr, read_mapping_.GetMemoryAs<uint32_t>());
126 }
127 
TEST_F(SharedMemoryMappingTest,TooBigSpanWithAutoDeducedElementCount)128 TEST_F(SharedMemoryMappingTest, TooBigSpanWithAutoDeducedElementCount) {
129   CreateMapping(sizeof(uint8_t));
130 
131   EXPECT_TRUE(write_mapping_.GetMemoryAsSpan<uint32_t>().empty());
132 
133   EXPECT_TRUE(read_mapping_.GetMemoryAsSpan<uint32_t>().empty());
134 }
135 
TEST_F(SharedMemoryMappingTest,TooBigSpanWithExplicitElementCount)136 TEST_F(SharedMemoryMappingTest, TooBigSpanWithExplicitElementCount) {
137   CreateMapping(sizeof(uint8_t));
138 
139   // Deliberately pick element counts such that a naive bounds calculation would
140   // overflow.
141   EXPECT_TRUE(write_mapping_
142                   .GetMemoryAsSpan<uint32_t>(std::numeric_limits<size_t>::max())
143                   .empty());
144 
145   EXPECT_TRUE(read_mapping_
146                   .GetMemoryAsSpan<uint32_t>(std::numeric_limits<size_t>::max())
147                   .empty());
148 }
149 
TEST_F(SharedMemoryMappingTest,Atomic)150 TEST_F(SharedMemoryMappingTest, Atomic) {
151   CreateMapping(sizeof(std::atomic<uint32_t>));
152 
153   auto* write_ptr = write_mapping_.GetMemoryAs<std::atomic<uint32_t>>();
154   ASSERT_NE(nullptr, write_ptr);
155 
156   // Placement new to initialize the std::atomic in place.
157   new (write_ptr) std::atomic<uint32_t>;
158 
159   const auto* read_ptr = read_mapping_.GetMemoryAs<std::atomic<uint32_t>>();
160   ASSERT_NE(nullptr, read_ptr);
161 
162   write_ptr->store(0u, std::memory_order_relaxed);
163   EXPECT_EQ(0u, read_ptr->load(std::memory_order_relaxed));
164 
165   write_ptr->store(0x12345678u, std::memory_order_relaxed);
166   EXPECT_EQ(0x12345678u, read_ptr->load(std::memory_order_relaxed));
167 }
168 
TEST_F(SharedMemoryMappingTest,TooBigAtomic)169 TEST_F(SharedMemoryMappingTest, TooBigAtomic) {
170   CreateMapping(sizeof(std::atomic<uint8_t>));
171 
172   EXPECT_EQ(nullptr, write_mapping_.GetMemoryAs<std::atomic<uint32_t>>());
173 
174   EXPECT_EQ(nullptr, read_mapping_.GetMemoryAs<std::atomic<uint32_t>>());
175 }
176 
177 // TODO(dcheng): This test is temporarily disabled on iOS. iOS devices allow
178 // the creation of a 1GB shared memory region, but don't allow the region to be
179 // mapped.
180 #if !BUILDFLAG(IS_IOS)
181 // TODO(crbug.com/40846204) Fix flakiness and re-enable on Linux and ChromeOS.
182 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
183 #define MAYBE_TotalMappedSizeLimit DISABLED_TotalMappedSizeLimit
184 #else
185 #define MAYBE_TotalMappedSizeLimit TotalMappedSizeLimit
186 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
TEST_F(SharedMemoryMappingTest,MAYBE_TotalMappedSizeLimit)187 TEST_F(SharedMemoryMappingTest, MAYBE_TotalMappedSizeLimit) {
188   // Nothing interesting to test if the address space isn't 64 bits, since
189   // there's no real limit enforced on 32 bits other than complete address
190   // space exhaustion.
191   // Also exclude NaCl since pointers are 32 bits on all architectures:
192   // https://bugs.chromium.org/p/nativeclient/issues/detail?id=1162
193 #if defined(ARCH_CPU_64_BITS) && !BUILDFLAG(IS_NACL)
194   auto region = WritableSharedMemoryRegion::Create(1024 * 1024 * 1024);
195   ASSERT_TRUE(region.IsValid());
196   // The limit is 32GB of mappings on 64-bit platforms, so the final mapping
197   // should fail.
198   std::vector<WritableSharedMemoryMapping> mappings(32);
199   for (size_t i = 0; i < mappings.size(); ++i) {
200     SCOPED_TRACE(i);
201     auto& mapping = mappings[i];
202     mapping = region.Map();
203     EXPECT_EQ(&mapping != &mappings.back(), mapping.IsValid());
204   }
205 #endif  // defined(ARCH_CPU_64_BITS)
206 }
207 #endif  // !BUILDFLAG(IS_IOS)
208 
209 }  // namespace base
210