OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 "base/memory/shared_memory_allocator.h" | |
6 | |
7 #include "base/memory/scoped_ptr.h" | |
8 #include "base/rand_util.h" | |
9 #include "base/threading/simple_thread.h" | |
10 #include "testing/gmock/include/gmock/gmock.h" | |
11 | |
12 namespace { | |
13 | |
14 const uint32_t TEST_MEMORY_SIZE = 1 << 20; // 1 MiB | |
15 const uint32_t TEST_MEMORY_PAGE = 64 << 10; // 64 KiB | |
16 | |
17 } // namespace | |
18 | |
19 namespace base { | |
20 | |
Alexander Potapenko
2015/11/09 18:03:46
You're missing the tests for:
-- using the alloca
bcwhite
2015/11/09 19:21:16
The ParallelismTest and CorruptionTest are intra-p
| |
21 typedef SharedMemoryAllocator::Reference Reference; | |
22 | |
23 class SharedMemoryAllocatorTest : public testing::Test { | |
24 public: | |
25 struct TestObject1 { | |
26 int32_t onething; | |
27 char oranother; | |
28 }; | |
29 | |
30 struct TestObject2 { | |
31 int thiis; | |
32 long that; | |
33 float andthe; | |
34 char other; | |
35 double thing; | |
36 }; | |
37 | |
38 SharedMemoryAllocatorTest() { | |
39 mem_segment_.reset(new char[TEST_MEMORY_SIZE]); | |
40 } | |
41 | |
42 void SetUp() override { | |
43 allocator_.reset(); | |
44 memset(mem_segment_.get(), 0, TEST_MEMORY_SIZE); | |
45 allocator_.reset(new SharedMemoryAllocator( | |
46 mem_segment_.get(), TEST_MEMORY_SIZE, TEST_MEMORY_PAGE)); | |
47 } | |
48 | |
49 void TearDown() override { | |
50 allocator_.reset(); | |
51 } | |
52 | |
53 int CountIterables() { | |
54 SharedMemoryAllocator::Iterator iter; | |
55 uint32_t type; | |
56 int count = 0; | |
57 for (allocator_->CreateIterator(&iter); | |
58 allocator_->GetNextIterable(&iter, &type) != 0;) { | |
59 count++; | |
60 } | |
61 return count; | |
62 } | |
63 | |
64 scoped_ptr<char[]> mem_segment_; | |
65 scoped_ptr<SharedMemoryAllocator> allocator_; | |
66 }; | |
67 | |
68 TEST_F(SharedMemoryAllocatorTest, AllocateAndIterate) { | |
69 SharedMemoryAllocator::MemoryInfo meminfo0; | |
70 allocator_->GetMemoryInfo(&meminfo0); | |
71 EXPECT_EQ(TEST_MEMORY_SIZE, meminfo0.total); | |
72 EXPECT_GT(meminfo0.total, meminfo0.free); | |
73 | |
74 Reference block1 = allocator_->Allocate(sizeof(TestObject1), 1); | |
75 EXPECT_NE(0, block1); | |
76 EXPECT_NE(nullptr, allocator_->GetAsObject<TestObject1>(block1, 1)); | |
77 EXPECT_EQ(nullptr, allocator_->GetAsObject<TestObject2>(block1, 1)); | |
78 EXPECT_LE(sizeof(TestObject1), allocator_->GetAllocSize(block1)); | |
79 EXPECT_GE(sizeof(TestObject1) + 7, allocator_->GetAllocSize(block1)); | |
80 SharedMemoryAllocator::MemoryInfo meminfo1; | |
81 allocator_->GetMemoryInfo(&meminfo1); | |
82 EXPECT_EQ(meminfo0.total, meminfo1.total); | |
83 EXPECT_GT(meminfo0.free, meminfo1.free); | |
84 | |
85 SharedMemoryAllocator::Iterator iter; | |
86 uint32_t type; | |
87 allocator_->CreateIterator(&iter); | |
88 EXPECT_EQ(0, allocator_->GetNextIterable(&iter, &type)); | |
89 allocator_->MakeIterable(block1); | |
90 EXPECT_EQ(block1, allocator_->GetNextIterable(&iter, &type)); | |
91 EXPECT_EQ(1U, type); | |
92 EXPECT_EQ(0, allocator_->GetNextIterable(&iter, &type)); | |
93 | |
94 Reference block2 = allocator_->Allocate(sizeof(TestObject2), 2); | |
95 EXPECT_NE(0, block2); | |
96 EXPECT_NE(nullptr, allocator_->GetAsObject<TestObject2>(block2, 2)); | |
97 EXPECT_EQ(nullptr, allocator_->GetAsObject<TestObject2>(block2, 1)); | |
98 EXPECT_LE(sizeof(TestObject2), allocator_->GetAllocSize(block2)); | |
99 EXPECT_GE(sizeof(TestObject2) + 7, allocator_->GetAllocSize(block2)); | |
100 SharedMemoryAllocator::MemoryInfo meminfo2; | |
101 allocator_->GetMemoryInfo(&meminfo2); | |
102 EXPECT_EQ(meminfo1.total, meminfo2.total); | |
103 EXPECT_GT(meminfo1.free, meminfo2.free); | |
104 | |
105 allocator_->MakeIterable(block2); | |
106 EXPECT_EQ(block2, allocator_->GetNextIterable(&iter, &type)); | |
107 EXPECT_EQ(2U, type); | |
108 EXPECT_EQ(0, allocator_->GetNextIterable(&iter, &type)); | |
109 | |
110 EXPECT_FALSE(allocator_->IsFull()); | |
111 EXPECT_FALSE(allocator_->IsCorrupt()); | |
112 } | |
113 | |
114 TEST_F(SharedMemoryAllocatorTest, PageTest) { | |
115 Reference block1 = allocator_->Allocate(TEST_MEMORY_PAGE / 2, 1); | |
116 EXPECT_LT(0, block1); | |
117 EXPECT_GT((int)TEST_MEMORY_PAGE, block1); | |
118 | |
119 Reference block2 = allocator_->Allocate(TEST_MEMORY_PAGE - 16, 2); | |
120 EXPECT_EQ((int)TEST_MEMORY_PAGE, block2); | |
121 | |
122 Reference block3 = allocator_->Allocate(99, 3); | |
123 EXPECT_EQ(2 * (int)TEST_MEMORY_PAGE, block3); | |
124 } | |
125 | |
126 class AllocatorThread : public SimpleThread { | |
127 public: | |
128 AllocatorThread(const std::string& name, | |
129 void* base, | |
130 int32_t size, | |
131 int32_t page_size) | |
132 : SimpleThread(name, Options()), | |
133 count_(0), | |
134 iterable_(0), | |
135 allocator_(base, size, page_size) {} | |
136 | |
137 void Run() override { | |
138 for (;;) { | |
139 int32_t size = (int32_t)base::RandInt(1, 99); | |
140 uint32_t type = (int32_t)base::RandInt(100, 999); | |
141 Reference block = allocator_.Allocate(size, type); | |
142 if (!block) | |
143 break; | |
144 | |
145 count_++; | |
146 if (base::RandInt(0, 1)) { | |
147 allocator_.MakeIterable(block); | |
148 iterable_++; | |
149 } | |
150 } | |
151 } | |
152 | |
153 int count_; | |
154 int iterable_; | |
155 | |
156 private: | |
157 SharedMemoryAllocator allocator_; | |
158 }; | |
159 | |
160 TEST_F(SharedMemoryAllocatorTest, ParallelismTest) { | |
161 void* memory = mem_segment_.get(); | |
162 AllocatorThread t1("t1", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
163 AllocatorThread t2("t2", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
164 AllocatorThread t3("t3", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
165 AllocatorThread t4("t4", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
166 AllocatorThread t5("t5", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
167 | |
168 t1.Start(); | |
169 t2.Start(); | |
170 t3.Start(); | |
171 t4.Start(); | |
172 t5.Start(); | |
173 | |
174 int last_count = 0; | |
175 do { | |
176 int count = CountIterables(); | |
177 EXPECT_LE(last_count, count); | |
178 } while (!allocator_->IsCorrupt() && !allocator_->IsFull()); | |
179 | |
180 t1.Join(); | |
181 t2.Join(); | |
182 t3.Join(); | |
183 t4.Join(); | |
184 t5.Join(); | |
185 | |
186 EXPECT_FALSE(allocator_->IsCorrupt()); | |
187 EXPECT_EQ(CountIterables(), | |
188 t1.iterable_ + t2.iterable_ + t3.iterable_ + t4.iterable_ + | |
189 t5.iterable_); | |
190 } | |
191 | |
192 // This test doesn't verify anything other than it doesn't crash. | |
193 TEST_F(SharedMemoryAllocatorTest, CorruptionTest) { | |
194 char* memory = mem_segment_.get(); | |
195 AllocatorThread t1("t1", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
196 AllocatorThread t2("t2", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
197 AllocatorThread t3("t3", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
198 AllocatorThread t4("t4", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
199 AllocatorThread t5("t5", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE); | |
200 | |
201 t1.Start(); | |
202 t2.Start(); | |
203 t3.Start(); | |
204 t4.Start(); | |
205 t5.Start(); | |
206 | |
207 do { | |
208 size_t offset = base::RandInt(0, TEST_MEMORY_SIZE - 1); | |
209 char value = base::RandInt(0, 255); | |
210 memory[offset] = value; | |
211 } while (!allocator_->IsCorrupt() && !allocator_->IsFull()); | |
212 | |
213 t1.Join(); | |
214 t2.Join(); | |
215 t3.Join(); | |
216 t4.Join(); | |
217 t5.Join(); | |
218 | |
219 CountIterables(); | |
220 } | |
221 | |
222 // Attempt to cause crashes or loops by expressly creating dangerous coditions. | |
223 TEST_F(SharedMemoryAllocatorTest, MaliciousTest) { | |
224 Reference block1 = allocator_->Allocate(sizeof(TestObject1), 1); | |
225 Reference block2 = allocator_->Allocate(sizeof(TestObject1), 2); | |
226 Reference block3 = allocator_->Allocate(sizeof(TestObject1), 3); | |
227 Reference block4 = allocator_->Allocate(sizeof(TestObject1), 3); | |
228 Reference block5 = allocator_->Allocate(sizeof(TestObject1), 3); | |
229 allocator_->MakeIterable(block1); | |
230 allocator_->MakeIterable(block2); | |
231 allocator_->MakeIterable(block3); | |
232 allocator_->MakeIterable(block4); | |
233 allocator_->MakeIterable(block5); | |
234 EXPECT_EQ(5, CountIterables()); | |
235 EXPECT_FALSE(allocator_->IsCorrupt()); | |
236 | |
237 // Create loop in iterable list and ensure it doesn't hang. | |
238 int32_t* header4 = (int32_t*)(mem_segment_.get() + block4); | |
239 EXPECT_EQ(block5, header4[3]); | |
240 header4[3] = block3; | |
241 CountIterables(); // loop: 1-2-3-4-3 | |
242 header4[3] = block2; | |
243 CountIterables(); // loop: 1-2-3-4-2 | |
244 header4[3] = block1; | |
245 CountIterables(); // loop: 1-2-3-4-1 | |
246 EXPECT_TRUE(allocator_->IsCorrupt()); | |
247 } | |
248 | |
249 } // namespace base | |
OLD | NEW |