1 // Copyright 2024 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/structured_shared_memory.h"
6
7 #include <atomic>
8 #include <optional>
9 #include <utility>
10
11 #include "base/containers/span.h"
12 #include "base/memory/platform_shared_memory_handle.h"
13 #include "base/memory/read_only_shared_memory_region.h"
14 #include "base/memory/shared_memory_mapper.h"
15 #include "base/test/gtest_util.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace base {
19
20 namespace {
21
22 // A SharedMemoryMapper that always fails to map memory.
23 class FailingSharedMemoryMapper final : public SharedMemoryMapper {
24 public:
Map(subtle::PlatformSharedMemoryHandle handle,bool write_allowed,uint64_t offset,size_t size)25 std::optional<span<uint8_t>> Map(subtle::PlatformSharedMemoryHandle handle,
26 bool write_allowed,
27 uint64_t offset,
28 size_t size) final {
29 return std::nullopt;
30 }
31
Unmap(span<uint8_t> mapping)32 void Unmap(span<uint8_t> mapping) final {}
33 };
34
TEST(StructuredSharedMemoryTest,ReadWrite)35 TEST(StructuredSharedMemoryTest, ReadWrite) {
36 auto writable_memory = StructuredSharedMemory<double>::Create();
37 ASSERT_TRUE(writable_memory.has_value());
38 EXPECT_EQ(writable_memory->WritablePtr(), &writable_memory->WritableRef());
39 EXPECT_EQ(writable_memory->WritablePtr(), writable_memory->ReadOnlyPtr());
40 EXPECT_EQ(writable_memory->ReadOnlyPtr(), &writable_memory->ReadOnlyRef());
41 EXPECT_EQ(writable_memory->ReadOnlyRef(), 0.0);
42
43 auto read_only_memory = StructuredSharedMemory<double>::MapReadOnlyRegion(
44 writable_memory->TakeReadOnlyRegion());
45 ASSERT_TRUE(read_only_memory.has_value());
46 EXPECT_EQ(read_only_memory->ReadOnlyPtr(), &read_only_memory->ReadOnlyRef());
47 EXPECT_EQ(read_only_memory->ReadOnlyRef(), 0.0);
48
49 writable_memory->WritableRef() += 0.5;
50 EXPECT_EQ(read_only_memory->ReadOnlyRef(), 0.5);
51 }
52
TEST(StructuredSharedMemoryTest,Initialize)53 TEST(StructuredSharedMemoryTest, Initialize) {
54 // Default initialize.
55 auto writable_memory = StructuredSharedMemory<double>::Create();
56 ASSERT_TRUE(writable_memory.has_value());
57 EXPECT_EQ(writable_memory->ReadOnlyRef(), 0.0);
58
59 // Initialize from same type.
60 writable_memory = StructuredSharedMemory<double>::Create(1.2);
61 ASSERT_TRUE(writable_memory.has_value());
62 EXPECT_EQ(writable_memory->ReadOnlyRef(), 1.2);
63
64 // Initialize from compatible type.
65 writable_memory = StructuredSharedMemory<double>::Create(3);
66 ASSERT_TRUE(writable_memory.has_value());
67 EXPECT_EQ(writable_memory->ReadOnlyRef(), 3);
68 }
69
TEST(StructuredSharedMemoryTest,MapFailure)70 TEST(StructuredSharedMemoryTest, MapFailure) {
71 // Fail to map writable memory.
72 FailingSharedMemoryMapper failing_mapper;
73 auto writable_memory =
74 StructuredSharedMemory<double>::CreateWithCustomMapper(&failing_mapper);
75 EXPECT_FALSE(writable_memory.has_value());
76
77 // Initialize from same type, but fail.
78 writable_memory = StructuredSharedMemory<double>::CreateWithCustomMapper(
79 1.2, &failing_mapper);
80 EXPECT_FALSE(writable_memory.has_value());
81
82 // Initialize from compatible type, but fail.
83 writable_memory = StructuredSharedMemory<double>::CreateWithCustomMapper(
84 3, &failing_mapper);
85 EXPECT_FALSE(writable_memory.has_value());
86
87 // Fail to create read-only region (bad handle).
88 ReadOnlySharedMemoryRegion region;
89 EXPECT_FALSE(region.IsValid());
90 auto read_only_memory =
91 StructuredSharedMemory<double>::MapReadOnlyRegion(std::move(region));
92 EXPECT_FALSE(read_only_memory.has_value());
93
94 // Valid handle for read-only region, but fail to map memory.
95 writable_memory = StructuredSharedMemory<double>::Create();
96 ASSERT_TRUE(writable_memory.has_value());
97 region = writable_memory->TakeReadOnlyRegion();
98 EXPECT_TRUE(region.IsValid());
99 read_only_memory = StructuredSharedMemory<double>::MapReadOnlyRegion(
100 std::move(region), &failing_mapper);
101 EXPECT_FALSE(read_only_memory.has_value());
102 }
103
TEST(StructuredSharedMemoryDeathTest,DuplicateRegion)104 TEST(StructuredSharedMemoryDeathTest, DuplicateRegion) {
105 auto writable_memory = StructuredSharedMemory<double>::Create();
106 ASSERT_TRUE(writable_memory.has_value());
107 ReadOnlySharedMemoryRegion region =
108 writable_memory->DuplicateReadOnlyRegion();
109 ReadOnlySharedMemoryRegion region2 =
110 writable_memory->DuplicateReadOnlyRegion();
111 EXPECT_EQ(region.GetGUID(), region2.GetGUID());
112 ReadOnlySharedMemoryRegion region3 = writable_memory->TakeReadOnlyRegion();
113 EXPECT_EQ(region.GetGUID(), region3.GetGUID());
114 // Region is no longer valid.
115 EXPECT_CHECK_DEATH(writable_memory->DuplicateReadOnlyRegion());
116 EXPECT_CHECK_DEATH(writable_memory->TakeReadOnlyRegion());
117 }
118
TEST(StructuredSharedMemoryTest,AtomicReadWrite)119 TEST(StructuredSharedMemoryTest, AtomicReadWrite) {
120 auto writable_memory = AtomicSharedMemory<int>::Create();
121 ASSERT_TRUE(writable_memory.has_value());
122 EXPECT_EQ(writable_memory->WritablePtr(), &writable_memory->WritableRef());
123 EXPECT_EQ(writable_memory->WritablePtr(), writable_memory->ReadOnlyPtr());
124 EXPECT_EQ(writable_memory->ReadOnlyPtr(), &writable_memory->ReadOnlyRef());
125 EXPECT_EQ(writable_memory->ReadOnlyRef().load(std::memory_order_relaxed), 0);
126
127 auto read_only_memory = AtomicSharedMemory<int>::MapReadOnlyRegion(
128 writable_memory->TakeReadOnlyRegion());
129 ASSERT_TRUE(read_only_memory.has_value());
130 EXPECT_EQ(read_only_memory->ReadOnlyPtr(), &read_only_memory->ReadOnlyRef());
131 EXPECT_EQ(read_only_memory->ReadOnlyRef().load(std::memory_order_relaxed), 0);
132
133 writable_memory->WritableRef().store(1, std::memory_order_relaxed);
134 EXPECT_EQ(read_only_memory->ReadOnlyRef().load(std::memory_order_relaxed), 1);
135 }
136
TEST(StructuredSharedMemoryTest,AtomicInitialize)137 TEST(StructuredSharedMemoryTest, AtomicInitialize) {
138 auto writable_memory = AtomicSharedMemory<int>::Create();
139 ASSERT_TRUE(writable_memory.has_value());
140 EXPECT_EQ(writable_memory->ReadOnlyRef().load(std::memory_order_relaxed), 0);
141
142 writable_memory = AtomicSharedMemory<int>::Create(1);
143 ASSERT_TRUE(writable_memory.has_value());
144 EXPECT_EQ(writable_memory->ReadOnlyRef().load(std::memory_order_relaxed), 1);
145 }
146
147 } // namespace
148
149 } // namespace base
150