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