1 // Copyright 2014 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 "mojo/core/shared_buffer_dispatcher.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <limits>
11
12 #include "base/macros.h"
13 #include "base/memory/platform_shared_memory_region.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/writable_shared_memory_region.h"
16 #include "mojo/core/dispatcher.h"
17 #include "mojo/core/platform_shared_memory_mapping.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace mojo {
21 namespace core {
22 namespace {
23
24 // NOTE(vtl): There's currently not much to test for in
25 // |SharedBufferDispatcher::ValidateCreateOptions()|, but the tests should be
26 // expanded if/when options are added, so I've kept the general form of the
27 // tests from data_pipe_unittest.cc.
28
29 const uint32_t kSizeOfCreateOptions = sizeof(MojoCreateSharedBufferOptions);
30
31 // Does a cursory sanity check of |validated_options|. Calls
32 // |ValidateCreateOptions()| on already-validated options. The validated options
33 // should be valid, and the revalidated copy should be the same.
RevalidateCreateOptions(const MojoCreateSharedBufferOptions & validated_options)34 void RevalidateCreateOptions(
35 const MojoCreateSharedBufferOptions& validated_options) {
36 EXPECT_EQ(kSizeOfCreateOptions, validated_options.struct_size);
37 // Nothing to check for flags.
38
39 MojoCreateSharedBufferOptions revalidated_options = {};
40 EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::ValidateCreateOptions(
41 &validated_options, &revalidated_options));
42 EXPECT_EQ(validated_options.struct_size, revalidated_options.struct_size);
43 EXPECT_EQ(validated_options.flags, revalidated_options.flags);
44 }
45
46 class SharedBufferDispatcherTest : public testing::Test {
47 public:
SharedBufferDispatcherTest()48 SharedBufferDispatcherTest() {}
~SharedBufferDispatcherTest()49 ~SharedBufferDispatcherTest() override {}
50
51 private:
52 DISALLOW_COPY_AND_ASSIGN(SharedBufferDispatcherTest);
53 };
54
55 // Tests valid inputs to |ValidateCreateOptions()|.
TEST_F(SharedBufferDispatcherTest,ValidateCreateOptionsValid)56 TEST_F(SharedBufferDispatcherTest, ValidateCreateOptionsValid) {
57 // Default options.
58 {
59 MojoCreateSharedBufferOptions validated_options = {};
60 EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::ValidateCreateOptions(
61 nullptr, &validated_options));
62 RevalidateCreateOptions(validated_options);
63 }
64
65 // Different flags.
66 MojoCreateSharedBufferFlags flags_values[] = {
67 MOJO_CREATE_SHARED_BUFFER_FLAG_NONE};
68 for (size_t i = 0; i < arraysize(flags_values); i++) {
69 const MojoCreateSharedBufferFlags flags = flags_values[i];
70
71 // Different capacities (size 1).
72 for (uint32_t capacity = 1; capacity <= 100 * 1000 * 1000; capacity *= 10) {
73 MojoCreateSharedBufferOptions options = {
74 kSizeOfCreateOptions, // |struct_size|.
75 flags // |flags|.
76 };
77 MojoCreateSharedBufferOptions validated_options = {};
78 EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::ValidateCreateOptions(
79 &options, &validated_options))
80 << capacity;
81 RevalidateCreateOptions(validated_options);
82 EXPECT_EQ(options.flags, validated_options.flags);
83 }
84 }
85 }
86
TEST_F(SharedBufferDispatcherTest,ValidateCreateOptionsInvalid)87 TEST_F(SharedBufferDispatcherTest, ValidateCreateOptionsInvalid) {
88 // Invalid |struct_size|.
89 {
90 MojoCreateSharedBufferOptions options = {
91 1, // |struct_size|.
92 MOJO_CREATE_SHARED_BUFFER_FLAG_NONE // |flags|.
93 };
94 MojoCreateSharedBufferOptions unused;
95 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
96 SharedBufferDispatcher::ValidateCreateOptions(&options, &unused));
97 }
98
99 // Unknown |flags|.
100 {
101 MojoCreateSharedBufferOptions options = {
102 kSizeOfCreateOptions, // |struct_size|.
103 ~0u // |flags|.
104 };
105 MojoCreateSharedBufferOptions unused;
106 EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
107 SharedBufferDispatcher::ValidateCreateOptions(&options, &unused));
108 }
109 }
110
TEST_F(SharedBufferDispatcherTest,CreateAndMapBuffer)111 TEST_F(SharedBufferDispatcherTest, CreateAndMapBuffer) {
112 scoped_refptr<SharedBufferDispatcher> dispatcher;
113 EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::Create(
114 SharedBufferDispatcher::kDefaultCreateOptions,
115 nullptr, 100, &dispatcher));
116 ASSERT_TRUE(dispatcher);
117 EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER, dispatcher->GetType());
118
119 // Make a couple of mappings.
120 std::unique_ptr<PlatformSharedMemoryMapping> mapping1;
121 EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer(0, 100, &mapping1));
122 ASSERT_TRUE(mapping1);
123 ASSERT_TRUE(mapping1->GetBase());
124 EXPECT_EQ(100u, mapping1->GetLength());
125 // Write something.
126 static_cast<char*>(mapping1->GetBase())[50] = 'x';
127
128 std::unique_ptr<PlatformSharedMemoryMapping> mapping2;
129 EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer(50, 50, &mapping2));
130 ASSERT_TRUE(mapping2);
131 ASSERT_TRUE(mapping2->GetBase());
132 EXPECT_EQ(50u, mapping2->GetLength());
133 EXPECT_EQ('x', static_cast<char*>(mapping2->GetBase())[0]);
134
135 EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close());
136
137 // Check that we can still read/write to mappings after the dispatcher has
138 // gone away.
139 static_cast<char*>(mapping2->GetBase())[1] = 'y';
140 EXPECT_EQ('y', static_cast<char*>(mapping1->GetBase())[51]);
141 }
142
TEST_F(SharedBufferDispatcherTest,CreateAndMapBufferFromPlatformBuffer)143 TEST_F(SharedBufferDispatcherTest, CreateAndMapBufferFromPlatformBuffer) {
144 base::WritableSharedMemoryRegion region =
145 base::WritableSharedMemoryRegion::Create(100);
146 ASSERT_TRUE(region.IsValid());
147 scoped_refptr<SharedBufferDispatcher> dispatcher;
148 EXPECT_EQ(MOJO_RESULT_OK,
149 SharedBufferDispatcher::CreateFromPlatformSharedMemoryRegion(
150 base::WritableSharedMemoryRegion::TakeHandleForSerialization(
151 std::move(region)),
152 &dispatcher));
153 ASSERT_TRUE(dispatcher);
154 EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER, dispatcher->GetType());
155
156 // Make a couple of mappings.
157 std::unique_ptr<PlatformSharedMemoryMapping> mapping1;
158 EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer(0, 100, &mapping1));
159 ASSERT_TRUE(mapping1);
160 ASSERT_TRUE(mapping1->GetBase());
161 EXPECT_EQ(100u, mapping1->GetLength());
162 // Write something.
163 static_cast<char*>(mapping1->GetBase())[50] = 'x';
164
165 std::unique_ptr<PlatformSharedMemoryMapping> mapping2;
166 EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer(50, 50, &mapping2));
167 ASSERT_TRUE(mapping2);
168 ASSERT_TRUE(mapping2->GetBase());
169 EXPECT_EQ(50u, mapping2->GetLength());
170 EXPECT_EQ('x', static_cast<char*>(mapping2->GetBase())[0]);
171
172 EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close());
173
174 // Check that we can still read/write to mappings after the dispatcher has
175 // gone away.
176 static_cast<char*>(mapping2->GetBase())[1] = 'y';
177 EXPECT_EQ('y', static_cast<char*>(mapping1->GetBase())[51]);
178 }
179
TEST_F(SharedBufferDispatcherTest,DuplicateBufferHandle)180 TEST_F(SharedBufferDispatcherTest, DuplicateBufferHandle) {
181 scoped_refptr<SharedBufferDispatcher> dispatcher1;
182 EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::Create(
183 SharedBufferDispatcher::kDefaultCreateOptions,
184 nullptr, 100, &dispatcher1));
185
186 // Map and write something.
187 std::unique_ptr<PlatformSharedMemoryMapping> mapping;
188 EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->MapBuffer(0, 100, &mapping));
189 static_cast<char*>(mapping->GetBase())[0] = 'x';
190 mapping.reset();
191
192 // Duplicate |dispatcher1| and then close it.
193 scoped_refptr<Dispatcher> dispatcher2;
194 EXPECT_EQ(MOJO_RESULT_OK,
195 dispatcher1->DuplicateBufferHandle(nullptr, &dispatcher2));
196 ASSERT_TRUE(dispatcher2);
197 EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER, dispatcher2->GetType());
198
199 EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->Close());
200
201 // Map |dispatcher2| and read something.
202 EXPECT_EQ(MOJO_RESULT_OK, dispatcher2->MapBuffer(0, 100, &mapping));
203 EXPECT_EQ('x', static_cast<char*>(mapping->GetBase())[0]);
204
205 EXPECT_EQ(MOJO_RESULT_OK, dispatcher2->Close());
206 }
207
TEST_F(SharedBufferDispatcherTest,DuplicateBufferHandleOptionsValid)208 TEST_F(SharedBufferDispatcherTest, DuplicateBufferHandleOptionsValid) {
209 scoped_refptr<SharedBufferDispatcher> dispatcher1;
210 EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::Create(
211 SharedBufferDispatcher::kDefaultCreateOptions,
212 nullptr, 100, &dispatcher1));
213
214 scoped_refptr<SharedBufferDispatcher> dispatcher2;
215 EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::Create(
216 SharedBufferDispatcher::kDefaultCreateOptions,
217 nullptr, 100, &dispatcher2));
218
219 MojoDuplicateBufferHandleOptions kReadOnlyOptions = {
220 sizeof(MojoCreateSharedBufferOptions),
221 MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_READ_ONLY};
222
223 // NOTE: We forbid handles from being duplicated read-only after they've been
224 // duplicated non-read-only; conversely we also forbid handles from being
225 // duplicated non-read-only after they've been duplicated read-only.
226 scoped_refptr<Dispatcher> writable_duped_dispatcher1;
227 scoped_refptr<Dispatcher> read_only_duped_dispatcher1;
228 EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->DuplicateBufferHandle(
229 nullptr, &writable_duped_dispatcher1));
230 EXPECT_TRUE(writable_duped_dispatcher1);
231 EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER,
232 writable_duped_dispatcher1->GetType());
233 {
234 std::unique_ptr<PlatformSharedMemoryMapping> mapping;
235 EXPECT_EQ(MOJO_RESULT_OK,
236 writable_duped_dispatcher1->MapBuffer(0, 100, &mapping));
237 }
238 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
239 dispatcher1->DuplicateBufferHandle(&kReadOnlyOptions,
240 &read_only_duped_dispatcher1));
241 EXPECT_FALSE(read_only_duped_dispatcher1);
242
243 scoped_refptr<Dispatcher> read_only_duped_dispatcher2;
244 scoped_refptr<Dispatcher> writable_duped_dispatcher2;
245 EXPECT_EQ(MOJO_RESULT_OK,
246 dispatcher2->DuplicateBufferHandle(&kReadOnlyOptions,
247 &read_only_duped_dispatcher2));
248 EXPECT_TRUE(read_only_duped_dispatcher2);
249 EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER,
250 read_only_duped_dispatcher2->GetType());
251 {
252 std::unique_ptr<PlatformSharedMemoryMapping> mapping;
253 EXPECT_EQ(MOJO_RESULT_OK,
254 read_only_duped_dispatcher2->MapBuffer(0, 100, &mapping));
255 }
256 EXPECT_EQ(
257 MOJO_RESULT_FAILED_PRECONDITION,
258 dispatcher2->DuplicateBufferHandle(nullptr, &writable_duped_dispatcher2));
259 EXPECT_FALSE(writable_duped_dispatcher2);
260
261 EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->Close());
262 EXPECT_EQ(MOJO_RESULT_OK, writable_duped_dispatcher1->Close());
263 EXPECT_EQ(MOJO_RESULT_OK, dispatcher2->Close());
264 EXPECT_EQ(MOJO_RESULT_OK, read_only_duped_dispatcher2->Close());
265 }
266
TEST_F(SharedBufferDispatcherTest,DuplicateBufferHandleOptionsInvalid)267 TEST_F(SharedBufferDispatcherTest, DuplicateBufferHandleOptionsInvalid) {
268 scoped_refptr<SharedBufferDispatcher> dispatcher1;
269 EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::Create(
270 SharedBufferDispatcher::kDefaultCreateOptions,
271 nullptr, 100, &dispatcher1));
272
273 // Invalid |struct_size|.
274 {
275 MojoDuplicateBufferHandleOptions options = {
276 1u, MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_NONE};
277 scoped_refptr<Dispatcher> dispatcher2;
278 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
279 dispatcher1->DuplicateBufferHandle(&options, &dispatcher2));
280 EXPECT_FALSE(dispatcher2);
281 }
282
283 // Unknown |flags|.
284 {
285 MojoDuplicateBufferHandleOptions options = {
286 sizeof(MojoDuplicateBufferHandleOptions), ~0u};
287 scoped_refptr<Dispatcher> dispatcher2;
288 EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
289 dispatcher1->DuplicateBufferHandle(&options, &dispatcher2));
290 EXPECT_FALSE(dispatcher2);
291 }
292
293 EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->Close());
294 }
295
TEST_F(SharedBufferDispatcherTest,CreateInvalidNumBytes)296 TEST_F(SharedBufferDispatcherTest, CreateInvalidNumBytes) {
297 // Size too big.
298 scoped_refptr<SharedBufferDispatcher> dispatcher;
299 EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
300 SharedBufferDispatcher::Create(
301 SharedBufferDispatcher::kDefaultCreateOptions, nullptr,
302 std::numeric_limits<uint64_t>::max(), &dispatcher));
303 EXPECT_FALSE(dispatcher);
304
305 // Zero size.
306 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
307 SharedBufferDispatcher::Create(
308 SharedBufferDispatcher::kDefaultCreateOptions, nullptr, 0,
309 &dispatcher));
310 EXPECT_FALSE(dispatcher);
311 }
312
TEST_F(SharedBufferDispatcherTest,MapBufferInvalidArguments)313 TEST_F(SharedBufferDispatcherTest, MapBufferInvalidArguments) {
314 scoped_refptr<SharedBufferDispatcher> dispatcher;
315 EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::Create(
316 SharedBufferDispatcher::kDefaultCreateOptions,
317 nullptr, 100, &dispatcher));
318
319 MojoSharedBufferInfo info = {sizeof(info), 0u};
320 EXPECT_EQ(MOJO_RESULT_OK, dispatcher->GetBufferInfo(&info));
321
322 std::unique_ptr<PlatformSharedMemoryMapping> mapping;
323 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
324 dispatcher->MapBuffer(0, info.size + 1, &mapping));
325 EXPECT_FALSE(mapping);
326
327 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
328 dispatcher->MapBuffer(1, info.size, &mapping));
329 EXPECT_FALSE(mapping);
330
331 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
332 dispatcher->MapBuffer(0, 0, &mapping));
333 EXPECT_FALSE(mapping);
334
335 EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close());
336 }
337
338 } // namespace
339 } // namespace core
340 } // namespace mojo
341