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