Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1675)

Side by Side Diff: util/mach/task_memory_test.cc

Issue 438993002: Add TaskMemory, which can read another Mach task’s memory, and its test (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Improvements Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util/mach/task_memory.h"
16
17 #include <mach/mach.h>
18
19 #include <algorithm>
20 #include <string>
21
22 #include "base/mac/scoped_mach_vm.h"
23 #include "gtest/gtest.h"
24 #include "util/test/mac/mach_errors.h"
25
26 namespace {
27
28 using namespace crashpad;
29 using namespace crashpad::test;
30
31 TEST(TaskMemory, ReadSelf) {
32 vm_address_t address = 0;
33 const vm_size_t kSize = 4 * PAGE_SIZE;
34 kern_return_t kr =
35 vm_allocate(mach_task_self(), &address, kSize, VM_FLAGS_ANYWHERE);
36 ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_allocate");
37 base::mac::ScopedMachVM vm_owner(address, mach_vm_round_page(kSize));
38
39 char* region = reinterpret_cast<char*>(address);
40 for (size_t index = 0; index < kSize; ++index) {
41 region[index] = (index % 256) ^ ((index >> 8) % 256);
42 }
43
44 TaskMemory memory(mach_task_self());
45 std::string result(kSize, '\0');
46
47 // Ensure that the entire region can be read.
48 ASSERT_TRUE(memory.Read(address, kSize, &result[0]));
49 EXPECT_EQ(0, memcmp(region, &result[0], kSize));
50
51 // Ensure that a read of length 0 succeeds and doesn’t touch the result.
52 result.assign(kSize, '\0');
53 std::string zeroes = result;
54 ASSERT_TRUE(memory.Read(address, 0, &result[0]));
55 EXPECT_EQ(zeroes, result);
56
57 // Ensure that a read starting at an unaligned address works.
58 ASSERT_TRUE(memory.Read(address + 1, kSize - 1, &result[0]));
59 EXPECT_EQ(0, memcmp(region + 1, &result[0], kSize - 1));
60
61 // Ensure that a read ending at an unaligned address works.
62 ASSERT_TRUE(memory.Read(address, kSize - 1, &result[0]));
63 EXPECT_EQ(0, memcmp(region, &result[0], kSize - 1));
64
65 // Ensure that a read starting and ending at unaligned addresses works.
66 ASSERT_TRUE(memory.Read(address + 1, kSize - 2, &result[0]));
67 EXPECT_EQ(0, memcmp(region + 1, &result[0], kSize - 2));
68
69 // Ensure that a read of exactly one page works.
70 ASSERT_TRUE(memory.Read(address + PAGE_SIZE, PAGE_SIZE, &result[0]));
71 EXPECT_EQ(0, memcmp(region + PAGE_SIZE, &result[0], PAGE_SIZE));
72
73 // Ensure that a read of a single byte works.
74 ASSERT_TRUE(memory.Read(address + 2, 1, &result[0]));
75 EXPECT_EQ(region[2], result[0]);
76
77 // Ensure that a read of length zero works and doesn’t touch the data.
78 result[0] = 'M';
79 ASSERT_TRUE(memory.Read(address + 3, 0, &result[0]));
80 EXPECT_EQ('M', result[0]);
81 }
82
83 TEST(TaskMemory, ReadSelfUnmapped) {
84 vm_address_t address = 0;
85 const vm_size_t kSize = 2 * PAGE_SIZE;
86 kern_return_t kr =
87 vm_allocate(mach_task_self(), &address, kSize, VM_FLAGS_ANYWHERE);
88 ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_allocate");
89 base::mac::ScopedMachVM vm_owner(address, mach_vm_round_page(kSize));
90
91 char* region = reinterpret_cast<char*>(address);
92 for (size_t index = 0; index < kSize; ++index) {
93 // Don’t include any NUL bytes, because ReadCString stops when it encounters
94 // a NUL.
95 region[index] = (index % 255) + 1;
96 }
97
98 kr = vm_protect(
99 mach_task_self(), address + PAGE_SIZE, PAGE_SIZE, FALSE, VM_PROT_NONE);
100 ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_protect");
101
102 TaskMemory memory(mach_task_self());
103 std::string result(kSize, '\0');
104
105 EXPECT_FALSE(memory.Read(address, kSize, &result[0]));
106 EXPECT_FALSE(memory.Read(address + 1, kSize - 1, &result[0]));
107 EXPECT_FALSE(memory.Read(address + PAGE_SIZE, 1, &result[0]));
108 EXPECT_FALSE(memory.Read(address + PAGE_SIZE - 1, 2, &result[0]));
109 EXPECT_TRUE(memory.Read(address, PAGE_SIZE, &result[0]));
110 EXPECT_TRUE(memory.Read(address + PAGE_SIZE - 1, 1, &result[0]));
111
112 // Repeat the test with an unmapped page instead of an unreadable one. This
113 // portion of the test may be flaky in the presence of other threads, if
114 // another thread maps something in the region that is deallocated here.
115 kr = vm_deallocate(mach_task_self(), address + PAGE_SIZE, PAGE_SIZE);
116 ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_deallocate");
117 vm_owner.reset(address, PAGE_SIZE);
118
119 EXPECT_FALSE(memory.Read(address, kSize, &result[0]));
120 EXPECT_FALSE(memory.Read(address + 1, kSize - 1, &result[0]));
121 EXPECT_FALSE(memory.Read(address + PAGE_SIZE, 1, &result[0]));
122 EXPECT_FALSE(memory.Read(address + PAGE_SIZE - 1, 2, &result[0]));
123 EXPECT_TRUE(memory.Read(address, PAGE_SIZE, &result[0]));
124 EXPECT_TRUE(memory.Read(address + PAGE_SIZE - 1, 1, &result[0]));
125 }
126
127 // This function consolidates the cast from a char* to mach_vm_address_t in one
128 // location when reading from the current task.
129 bool ReadCStringSelf(TaskMemory* memory,
130 const char* pointer,
131 std::string* result) {
132 return memory->ReadCString(reinterpret_cast<mach_vm_address_t>(pointer),
133 result);
134 }
135
136 TEST(TaskMemory, ReadCStringSelf) {
137 TaskMemory memory(mach_task_self());
138 std::string result;
139
140 const char kConstCharEmpty[] = "";
141 ASSERT_TRUE(ReadCStringSelf(&memory, kConstCharEmpty, &result));
142 EXPECT_TRUE(result.empty());
143 EXPECT_EQ(kConstCharEmpty, result);
144
145 const char kConstCharShort[] = "A short const char[]";
146 ASSERT_TRUE(ReadCStringSelf(&memory, kConstCharShort, &result));
147 EXPECT_FALSE(result.empty());
148 EXPECT_EQ(kConstCharShort, result);
149
150 static const char kStaticConstCharEmpty[] = "";
151 ASSERT_TRUE(ReadCStringSelf(&memory, kStaticConstCharEmpty, &result));
152 EXPECT_TRUE(result.empty());
153 EXPECT_EQ(kStaticConstCharEmpty, result);
154
155 static const char kStaticConstCharShort[] = "A short static const char[]";
156 ASSERT_TRUE(ReadCStringSelf(&memory, kStaticConstCharShort, &result));
157 EXPECT_FALSE(result.empty());
158 EXPECT_EQ(kStaticConstCharShort, result);
159
160 std::string string_short("A short std::string in a function");
161 ASSERT_TRUE(ReadCStringSelf(&memory, &string_short[0], &result));
162 EXPECT_FALSE(result.empty());
163 EXPECT_EQ(string_short, result);
164
165 std::string string_long;
166 const size_t kStringLongSize = 4 * PAGE_SIZE;
167 for (size_t index = 0; index < kStringLongSize; ++index) {
168 // Don’t include any NUL bytes, because ReadCString stops when it encounters
169 // a NUL.
170 string_long.append(1, (index % 255) + 1);
171 }
172 ASSERT_EQ(kStringLongSize, string_long.size());
173 ASSERT_TRUE(ReadCStringSelf(&memory, &string_long[0], &result));
174 EXPECT_FALSE(result.empty());
175 EXPECT_EQ(kStringLongSize, result.size());
176 EXPECT_EQ(string_long, result);
177 }
178
179 TEST(TaskMemory, ReadCStringSelfUnmapped) {
180 vm_address_t address = 0;
181 const vm_size_t kSize = 2 * PAGE_SIZE;
182 kern_return_t kr =
183 vm_allocate(mach_task_self(), &address, kSize, VM_FLAGS_ANYWHERE);
184 ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_allocate");
185 base::mac::ScopedMachVM vm_owner(address, mach_vm_round_page(kSize));
186
187 char* region = reinterpret_cast<char*>(address);
188 for (size_t index = 0; index < kSize; ++index) {
189 // Don’t include any NUL bytes, because ReadCString stops when it encounters
190 // a NUL.
191 region[index] = (index % 255) + 1;
192 }
193
194 kr = vm_protect(
195 mach_task_self(), address + PAGE_SIZE, PAGE_SIZE, FALSE, VM_PROT_NONE);
196 ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_protect");
197
198 TaskMemory memory(mach_task_self());
199 std::string result;
200 EXPECT_FALSE(memory.ReadCString(address, &result));
201
202 // Make sure that if the string is NUL-terminated within the mapped memory
203 // region, it can be read properly.
204 char terminator_or_not = '\0';
205 std::swap(region[PAGE_SIZE - 1], terminator_or_not);
206 ASSERT_TRUE(memory.ReadCString(address, &result));
207 EXPECT_FALSE(result.empty());
208 EXPECT_EQ(PAGE_SIZE - 1u, result.size());
209 EXPECT_EQ(region, result);
210
211 // Repeat the test with an unmapped page instead of an unreadable one. This
212 // portion of the test may be flaky in the presence of other threads, if
213 // another thread maps something in the region that is deallocated here.
214 std::swap(region[PAGE_SIZE - 1], terminator_or_not);
215 kr = vm_deallocate(mach_task_self(), address + PAGE_SIZE, PAGE_SIZE);
216 ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_deallocate");
217 vm_owner.reset(address, PAGE_SIZE);
218
219 EXPECT_FALSE(memory.ReadCString(address, &result));
220
221 // Clear the result before testing that the string can be read. This makes
222 // sure that the result is actually filled in, because it already contains the
223 // expected value from the tests above.
224 result.clear();
225 std::swap(region[PAGE_SIZE - 1], terminator_or_not);
226 ASSERT_TRUE(memory.ReadCString(address, &result));
227 EXPECT_FALSE(result.empty());
228 EXPECT_EQ(PAGE_SIZE - 1u, result.size());
229 EXPECT_EQ(region, result);
230 }
231
232 // This function consolidates the cast from a char* to mach_vm_address_t in one
233 // location when reading from the current task.
234 bool ReadCStringSizeLimitedSelf(TaskMemory* memory,
235 const char* pointer,
236 size_t size,
237 std::string* result) {
238 return memory->ReadCStringSizeLimited(
239 reinterpret_cast<mach_vm_address_t>(pointer), size, result);
240 }
241
242 TEST(TaskMemory, ReadCStringSizeLimited) {
Robert Sesek 2014/08/03 14:56:43 This test is rather large, and failures in it may
243 TaskMemory memory(mach_task_self());
244 std::string result;
245
246 const char kConstCharEmpty[] = "";
247 ASSERT_TRUE(ReadCStringSizeLimitedSelf(
248 &memory, kConstCharEmpty, arraysize(kConstCharEmpty), &result));
249 EXPECT_TRUE(result.empty());
250 EXPECT_EQ(kConstCharEmpty, result);
251 result.clear();
252 ASSERT_TRUE(ReadCStringSizeLimitedSelf(
253 &memory, kConstCharEmpty, arraysize(kConstCharEmpty) + 1, &result));
254 EXPECT_TRUE(result.empty());
255 EXPECT_EQ(kConstCharEmpty, result);
256 result.clear();
257 ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory, kConstCharEmpty, 0, &result));
258 EXPECT_TRUE(result.empty());
259 EXPECT_EQ(kConstCharEmpty, result);
260
261 const char kConstCharShort[] = "A short const char[]";
262 ASSERT_TRUE(ReadCStringSizeLimitedSelf(
263 &memory, kConstCharShort, arraysize(kConstCharShort), &result));
264 EXPECT_FALSE(result.empty());
265 EXPECT_EQ(kConstCharShort, result);
266 result.clear();
267 ASSERT_TRUE(ReadCStringSizeLimitedSelf(
268 &memory, kConstCharShort, arraysize(kConstCharShort) + 1, &result));
269 EXPECT_FALSE(result.empty());
270 EXPECT_EQ(kConstCharShort, result);
271 result.clear();
272 ASSERT_FALSE(ReadCStringSizeLimitedSelf(
273 &memory, kConstCharShort, arraysize(kConstCharShort) - 1, &result));
274
275 static const char kStaticConstCharEmpty[] = "";
276 ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory,
277 kStaticConstCharEmpty,
278 arraysize(kStaticConstCharEmpty),
279 &result));
280 EXPECT_TRUE(result.empty());
281 EXPECT_EQ(kStaticConstCharEmpty, result);
282 result.clear();
283 ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory,
284 kStaticConstCharEmpty,
285 arraysize(kStaticConstCharEmpty) + 1,
286 &result));
287 EXPECT_TRUE(result.empty());
288 EXPECT_EQ(kStaticConstCharEmpty, result);
289 result.clear();
290 ASSERT_TRUE(
291 ReadCStringSizeLimitedSelf(&memory, kStaticConstCharEmpty, 0, &result));
292 EXPECT_TRUE(result.empty());
293 EXPECT_EQ(kStaticConstCharEmpty, result);
294
295 static const char kStaticConstCharShort[] = "A short static const char[]";
296 ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory,
297 kStaticConstCharShort,
298 arraysize(kStaticConstCharShort),
299 &result));
300 EXPECT_FALSE(result.empty());
301 EXPECT_EQ(kStaticConstCharShort, result);
302 result.clear();
303 ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory,
304 kStaticConstCharShort,
305 arraysize(kStaticConstCharShort) + 1,
306 &result));
307 EXPECT_FALSE(result.empty());
308 EXPECT_EQ(kStaticConstCharShort, result);
309 result.clear();
310 ASSERT_FALSE(ReadCStringSizeLimitedSelf(&memory,
311 kStaticConstCharShort,
312 arraysize(kStaticConstCharShort) - 1,
313 &result));
314
315 std::string string_short("A short std::string in a function");
316 ASSERT_TRUE(ReadCStringSizeLimitedSelf(
317 &memory, &string_short[0], string_short.size() + 1, &result));
318 EXPECT_FALSE(result.empty());
319 EXPECT_EQ(string_short, result);
320 result.clear();
321 ASSERT_TRUE(ReadCStringSizeLimitedSelf(
322 &memory, &string_short[0], string_short.size() + 2, &result));
323 EXPECT_FALSE(result.empty());
324 EXPECT_EQ(string_short, result);
325 result.clear();
326 ASSERT_FALSE(ReadCStringSizeLimitedSelf(
327 &memory, &string_short[0], string_short.size(), &result));
328
329 std::string string_long;
330 const size_t kStringLongSize = 4 * PAGE_SIZE;
331 for (size_t index = 0; index < kStringLongSize; ++index) {
332 // Don’t include any NUL bytes, because ReadCString stops when it encounters
333 // a NUL.
334 string_long.append(1, (index % 255) + 1);
335 }
336 ASSERT_EQ(kStringLongSize, string_long.size());
337 ASSERT_TRUE(ReadCStringSizeLimitedSelf(
338 &memory, &string_long[0], string_long.size() + 1, &result));
339 EXPECT_FALSE(result.empty());
340 EXPECT_EQ(kStringLongSize, result.size());
341 EXPECT_EQ(string_long, result);
342 result.clear();
343 ASSERT_TRUE(ReadCStringSizeLimitedSelf(
344 &memory, &string_long[0], string_long.size() + 2, &result));
345 EXPECT_FALSE(result.empty());
346 EXPECT_EQ(kStringLongSize, result.size());
347 EXPECT_EQ(string_long, result);
348 result.clear();
349 ASSERT_FALSE(ReadCStringSizeLimitedSelf(
350 &memory, &string_long[0], string_long.size(), &result));
351 }
352
353 } // namespace
OLDNEW
« no previous file with comments | « util/mach/task_memory.cc ('k') | util/test/errors.h » ('j') | util/test/errors.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698