1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <sys/mman.h>
19 #include <time.h>
20
21 #include <memory>
22 #include <string>
23
24 #include <android-base/file.h>
25 #include <android-base/properties.h>
26 #include <gmock/gmock.h>
27 #include <gtest/gtest.h>
28
29 #include "libdebuggerd/utility.h"
30
31 #include "UnwinderMock.h"
32 #include "host_signal_fixup.h"
33 #include "log_fake.h"
34
35 // Include tombstone.cpp to define log_tag before GWP-ASan includes log.
36 #include "tombstone.cpp"
37
38 #include "gwp_asan.cpp"
39
40 using ::testing::MatchesRegex;
41
42 class TombstoneTest : public ::testing::Test {
43 protected:
SetUp()44 virtual void SetUp() {
45 unwinder_mock_.reset(new UnwinderMock());
46
47 char tmp_file[256];
48 const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
49 memcpy(tmp_file, data_template, sizeof(data_template));
50 int tombstone_fd = mkstemp(tmp_file);
51 if (tombstone_fd == -1) {
52 const char tmp_template[] = "/tmp/debuggerd_memory_testXXXXXX";
53 memcpy(tmp_file, tmp_template, sizeof(tmp_template));
54 tombstone_fd = mkstemp(tmp_file);
55 if (tombstone_fd == -1) {
56 abort();
57 }
58 }
59 if (unlink(tmp_file) == -1) {
60 abort();
61 }
62
63 log_.tfd = tombstone_fd;
64 amfd_data_.clear();
65 log_.amfd_data = &amfd_data_;
66 log_.crashed_tid = 12;
67 log_.current_tid = 12;
68 log_.should_retrieve_logcat = false;
69
70 resetLogs();
71 }
72
TearDown()73 virtual void TearDown() {
74 if (log_.tfd >= 0) {
75 close(log_.tfd);
76 }
77 }
78
79 std::unique_ptr<UnwinderMock> unwinder_mock_;
80
81 log_t log_;
82 std::string amfd_data_;
83 };
84
TEST_F(TombstoneTest,single_map)85 TEST_F(TombstoneTest, single_map) {
86 #if defined(__LP64__)
87 unwinder_mock_->MockAddMap(0x123456789abcd000UL, 0x123456789abdf000UL, 0, 0, "", 0);
88 #else
89 unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, 0, "", 0);
90 #endif
91
92 dump_all_maps(&log_, unwinder_mock_.get(), 0);
93
94 std::string tombstone_contents;
95 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
96 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
97 const char* expected_dump = \
98 "\nmemory map (1 entry):\n"
99 #if defined(__LP64__)
100 " 12345678'9abcd000-12345678'9abdefff --- 0 12000\n";
101 #else
102 " 01234000-01234fff --- 0 1000\n";
103 #endif
104 ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
105
106 ASSERT_STREQ("", amfd_data_.c_str());
107
108 // Verify that the log buf is empty, and no error messages.
109 ASSERT_STREQ("", getFakeLogBuf().c_str());
110 ASSERT_STREQ("", getFakeLogPrint().c_str());
111 }
112
TEST_F(TombstoneTest,single_map_elf_build_id)113 TEST_F(TombstoneTest, single_map_elf_build_id) {
114 uint64_t build_id_offset;
115 #if defined(__LP64__)
116 build_id_offset = 0x123456789abcd000UL;
117 unwinder_mock_->MockAddMap(build_id_offset, 0x123456789abdf000UL, 0, PROT_READ,
118 "/system/lib/libfake.so", 0);
119 #else
120 build_id_offset = 0x1234000;
121 unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, PROT_READ, "/system/lib/libfake.so", 0);
122 #endif
123
124 unwinder_mock_->MockSetBuildID(
125 build_id_offset,
126 std::string{static_cast<char>(0xab), static_cast<char>(0xcd), static_cast<char>(0xef),
127 static_cast<char>(0x12), static_cast<char>(0x34), static_cast<char>(0x56),
128 static_cast<char>(0x78), static_cast<char>(0x90), static_cast<char>(0xab),
129 static_cast<char>(0xcd), static_cast<char>(0xef), static_cast<char>(0x12),
130 static_cast<char>(0x34), static_cast<char>(0x56), static_cast<char>(0x78),
131 static_cast<char>(0x90)});
132 dump_all_maps(&log_, unwinder_mock_.get(), 0);
133
134 std::string tombstone_contents;
135 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
136 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
137 const char* expected_dump = \
138 "\nmemory map (1 entry):\n"
139 #if defined(__LP64__)
140 " 12345678'9abcd000-12345678'9abdefff r-- 0 12000 /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
141 #else
142 " 01234000-01234fff r-- 0 1000 /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
143 #endif
144 ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
145
146 ASSERT_STREQ("", amfd_data_.c_str());
147
148 // Verify that the log buf is empty, and no error messages.
149 ASSERT_STREQ("", getFakeLogBuf().c_str());
150 ASSERT_STREQ("", getFakeLogPrint().c_str());
151 }
152
TEST_F(TombstoneTest,multiple_maps)153 TEST_F(TombstoneTest, multiple_maps) {
154 unwinder_mock_->MockAddMap(0xa234000, 0xa235000, 0, 0, "", 0);
155 unwinder_mock_->MockAddMap(0xa334000, 0xa335000, 0xf000, PROT_READ, "", 0);
156 unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
157 unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
158 unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
159 "/system/lib/fake.so", 0);
160
161 dump_all_maps(&log_, unwinder_mock_.get(), 0);
162
163 std::string tombstone_contents;
164 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
165 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
166 const char* expected_dump =
167 "\nmemory map (5 entries):\n"
168 #if defined(__LP64__)
169 " 00000000'0a234000-00000000'0a234fff --- 0 1000\n"
170 " 00000000'0a334000-00000000'0a334fff r-- f000 1000\n"
171 " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
172 " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
173 " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
174 #else
175 " 0a234000-0a234fff --- 0 1000\n"
176 " 0a334000-0a334fff r-- f000 1000\n"
177 " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
178 " 0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
179 " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
180 #endif
181 ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
182
183 ASSERT_STREQ("", amfd_data_.c_str());
184
185 // Verify that the log buf is empty, and no error messages.
186 ASSERT_STREQ("", getFakeLogBuf().c_str());
187 ASSERT_STREQ("", getFakeLogPrint().c_str());
188 }
189
TEST_F(TombstoneTest,multiple_maps_fault_address_before)190 TEST_F(TombstoneTest, multiple_maps_fault_address_before) {
191 unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
192 unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
193 unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
194 "/system/lib/fake.so", 0);
195
196 dump_all_maps(&log_, unwinder_mock_.get(), 0x1000);
197
198 std::string tombstone_contents;
199 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
200 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
201 const char* expected_dump =
202 "\nmemory map (3 entries):\n"
203 #if defined(__LP64__)
204 "--->Fault address falls at 00000000'00001000 before any mapped regions\n"
205 " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
206 " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
207 " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
208 #else
209 "--->Fault address falls at 00001000 before any mapped regions\n"
210 " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
211 " 0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
212 " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
213 #endif
214 ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
215
216 ASSERT_STREQ("", amfd_data_.c_str());
217
218 // Verify that the log buf is empty, and no error messages.
219 ASSERT_STREQ("", getFakeLogBuf().c_str());
220 ASSERT_STREQ("", getFakeLogPrint().c_str());
221 }
222
TEST_F(TombstoneTest,multiple_maps_fault_address_between)223 TEST_F(TombstoneTest, multiple_maps_fault_address_between) {
224 unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
225 unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
226 unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
227 "/system/lib/fake.so", 0);
228
229 dump_all_maps(&log_, unwinder_mock_.get(), 0xa533000);
230
231 std::string tombstone_contents;
232 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
233 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
234 const char* expected_dump =
235 "\nmemory map (3 entries): (fault address prefixed with --->)\n"
236 #if defined(__LP64__)
237 " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
238 "--->Fault address falls at 00000000'0a533000 between mapped regions\n"
239 " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
240 " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
241 #else
242 " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
243 "--->Fault address falls at 0a533000 between mapped regions\n"
244 " 0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
245 " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
246 #endif
247 ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
248
249 ASSERT_STREQ("", amfd_data_.c_str());
250
251 // Verify that the log buf is empty, and no error messages.
252 ASSERT_STREQ("", getFakeLogBuf().c_str());
253 ASSERT_STREQ("", getFakeLogPrint().c_str());
254 }
255
TEST_F(TombstoneTest,multiple_maps_fault_address_in_map)256 TEST_F(TombstoneTest, multiple_maps_fault_address_in_map) {
257 unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
258 unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
259 unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
260 "/system/lib/fake.so", 0);
261
262 dump_all_maps(&log_, unwinder_mock_.get(), 0xa534040);
263
264 std::string tombstone_contents;
265 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
266 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
267 const char* expected_dump =
268 "\nmemory map (3 entries): (fault address prefixed with --->)\n"
269 #if defined(__LP64__)
270 " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
271 "--->00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
272 " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
273 #else
274 " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
275 "--->0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
276 " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
277 #endif
278 ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
279
280 ASSERT_STREQ("", amfd_data_.c_str());
281
282 // Verify that the log buf is empty, and no error messages.
283 ASSERT_STREQ("", getFakeLogBuf().c_str());
284 ASSERT_STREQ("", getFakeLogPrint().c_str());
285 }
286
TEST_F(TombstoneTest,multiple_maps_fault_address_after)287 TEST_F(TombstoneTest, multiple_maps_fault_address_after) {
288 unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
289 unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
290 unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
291 "/system/lib/fake.so", 0);
292
293 #if defined(__LP64__)
294 uint64_t addr = 0x12345a534040UL;
295 #else
296 uint64_t addr = 0xf534040UL;
297 #endif
298 dump_all_maps(&log_, unwinder_mock_.get(), addr);
299
300 std::string tombstone_contents;
301 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
302 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
303 const char* expected_dump =
304 "\nmemory map (3 entries): (fault address prefixed with --->)\n"
305 #if defined(__LP64__)
306 " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
307 " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
308 " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n"
309 "--->Fault address falls at 00001234'5a534040 after any mapped regions\n";
310 #else
311 " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
312 " 0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
313 " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n"
314 "--->Fault address falls at 0f534040 after any mapped regions\n";
315 #endif
316 ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
317
318 ASSERT_STREQ("", amfd_data_.c_str());
319
320 // Verify that the log buf is empty, and no error messages.
321 ASSERT_STREQ("", getFakeLogBuf().c_str());
322 ASSERT_STREQ("", getFakeLogPrint().c_str());
323 }
324
TEST_F(TombstoneTest,dump_log_file_error)325 TEST_F(TombstoneTest, dump_log_file_error) {
326 log_.should_retrieve_logcat = true;
327 dump_log_file(&log_, 123, "/fake/filename", 10);
328
329 std::string tombstone_contents;
330 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
331 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
332 ASSERT_STREQ("", tombstone_contents.c_str());
333
334 ASSERT_STREQ("", getFakeLogBuf().c_str());
335 ASSERT_STREQ("6 DEBUG Unable to open /fake/filename: Permission denied\n\n",
336 getFakeLogPrint().c_str());
337
338 ASSERT_STREQ("", amfd_data_.c_str());
339 }
340
TEST_F(TombstoneTest,dump_header_info)341 TEST_F(TombstoneTest, dump_header_info) {
342 dump_header_info(&log_);
343
344 std::string expected = android::base::StringPrintf(
345 "Build fingerprint: '%s'\nRevision: '%s'\n",
346 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
347 android::base::GetProperty("ro.revision", "unknown").c_str());
348 expected += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
349 ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
350 }
351
TEST_F(TombstoneTest,dump_thread_info_uid)352 TEST_F(TombstoneTest, dump_thread_info_uid) {
353 std::vector<std::string> cmdline = {"some_process"};
354 dump_thread_info(
355 &log_,
356 ThreadInfo{
357 .uid = 1, .tid = 3, .thread_name = "some_thread", .pid = 2, .command_line = cmdline});
358 std::string expected = "pid: 2, tid: 3, name: some_thread >>> some_process <<<\nuid: 1\n";
359 ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
360 }
361
362 class GwpAsanCrashDataTest : public GwpAsanCrashData {
363 public:
GwpAsanCrashDataTest(gwp_asan::Error error,const gwp_asan::AllocationMetadata * responsible_allocation)364 GwpAsanCrashDataTest(
365 gwp_asan::Error error,
366 const gwp_asan::AllocationMetadata *responsible_allocation) :
367 GwpAsanCrashData(nullptr, ProcessInfo{}, ThreadInfo{}) {
368 is_gwp_asan_responsible_ = true;
369 error_ = error;
370 responsible_allocation_ = responsible_allocation;
371 error_string_ = gwp_asan::ErrorToString(error_);
372 }
373
SetCrashAddress(uintptr_t crash_address)374 void SetCrashAddress(uintptr_t crash_address) {
375 crash_address_ = crash_address;
376 }
377 };
378
TEST_F(TombstoneTest,gwp_asan_cause_uaf_exact)379 TEST_F(TombstoneTest, gwp_asan_cause_uaf_exact) {
380 gwp_asan::AllocationMetadata meta;
381 meta.Addr = 0x1000;
382 meta.RequestedSize = 32;
383
384 GwpAsanCrashDataTest crash_data(gwp_asan::Error::USE_AFTER_FREE, &meta);
385 crash_data.SetCrashAddress(0x1000);
386
387 crash_data.DumpCause(&log_);
388 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
389 std::string tombstone_contents;
390 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
391 ASSERT_THAT(tombstone_contents, MatchesRegex("Cause: \\[GWP-ASan\\]: Use After Free, 0 bytes "
392 "into a 32-byte allocation at 0x[a-fA-F0-9]+\n"));
393 }
394
TEST_F(TombstoneTest,gwp_asan_cause_double_free)395 TEST_F(TombstoneTest, gwp_asan_cause_double_free) {
396 gwp_asan::AllocationMetadata meta;
397 meta.Addr = 0x1000;
398 meta.RequestedSize = 32;
399
400 GwpAsanCrashDataTest crash_data(gwp_asan::Error::DOUBLE_FREE, &meta);
401 crash_data.SetCrashAddress(0x1000);
402
403 crash_data.DumpCause(&log_);
404 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
405 std::string tombstone_contents;
406 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
407 ASSERT_THAT(tombstone_contents, MatchesRegex("Cause: \\[GWP-ASan\\]: Double Free, 0 bytes into a "
408 "32-byte allocation at 0x[a-fA-F0-9]+\n"));
409 }
410
TEST_F(TombstoneTest,gwp_asan_cause_overflow)411 TEST_F(TombstoneTest, gwp_asan_cause_overflow) {
412 gwp_asan::AllocationMetadata meta;
413 meta.Addr = 0x1000;
414 meta.RequestedSize = 32;
415
416 GwpAsanCrashDataTest crash_data(gwp_asan::Error::BUFFER_OVERFLOW, &meta);
417 crash_data.SetCrashAddress(0x1025);
418
419 crash_data.DumpCause(&log_);
420 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
421 std::string tombstone_contents;
422 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
423 ASSERT_THAT(
424 tombstone_contents,
425 MatchesRegex(
426 "Cause: \\[GWP-ASan\\]: Buffer Overflow, 5 bytes right of a 32-byte "
427 "allocation at 0x[a-fA-F0-9]+\n"));
428 }
429
TEST_F(TombstoneTest,gwp_asan_cause_underflow)430 TEST_F(TombstoneTest, gwp_asan_cause_underflow) {
431 gwp_asan::AllocationMetadata meta;
432 meta.Addr = 0x1000;
433 meta.RequestedSize = 32;
434
435 GwpAsanCrashDataTest crash_data(gwp_asan::Error::BUFFER_UNDERFLOW, &meta);
436 crash_data.SetCrashAddress(0xffe);
437
438 crash_data.DumpCause(&log_);
439 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
440 std::string tombstone_contents;
441 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
442 ASSERT_THAT(
443 tombstone_contents,
444 MatchesRegex(
445 "Cause: \\[GWP-ASan\\]: Buffer Underflow, 2 bytes left of a 32-byte "
446 "allocation at 0x[a-fA-F0-9]+\n"));
447 }
448
TEST_F(TombstoneTest,gwp_asan_cause_invalid_free_inside)449 TEST_F(TombstoneTest, gwp_asan_cause_invalid_free_inside) {
450 gwp_asan::AllocationMetadata meta;
451 meta.Addr = 0x1000;
452 meta.RequestedSize = 32;
453
454 GwpAsanCrashDataTest crash_data(gwp_asan::Error::INVALID_FREE, &meta);
455 crash_data.SetCrashAddress(0x1001);
456
457 crash_data.DumpCause(&log_);
458 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
459 std::string tombstone_contents;
460 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
461 ASSERT_THAT(
462 tombstone_contents,
463 MatchesRegex(
464 "Cause: \\[GWP-ASan\\]: Invalid \\(Wild\\) Free, 1 byte into a 32-byte "
465 "allocation at 0x[a-fA-F0-9]+\n"));
466 }
467
TEST_F(TombstoneTest,gwp_asan_cause_invalid_free_outside)468 TEST_F(TombstoneTest, gwp_asan_cause_invalid_free_outside) {
469 gwp_asan::AllocationMetadata meta;
470 meta.Addr = 0x1000;
471 meta.RequestedSize = 32;
472
473 GwpAsanCrashDataTest crash_data(gwp_asan::Error::INVALID_FREE, &meta);
474 crash_data.SetCrashAddress(0x1021);
475
476 crash_data.DumpCause(&log_);
477 ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
478 std::string tombstone_contents;
479 ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
480 ASSERT_THAT(
481 tombstone_contents,
482 MatchesRegex(
483 "Cause: \\[GWP-ASan\\]: Invalid \\(Wild\\) Free, 33 bytes right of a 32-byte "
484 "allocation at 0x[a-fA-F0-9]+\n"));
485 }
486
487